sortable_table.class.php 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * @package chamilo.library
  5. */
  6. /**
  7. * Code
  8. */
  9. require_once 'pear/HTML/Table.php';
  10. require_once 'pear/Pager/Pager.php';
  11. //require_once 'tablesort.lib.php'; moved to autoload table_sort.class.php
  12. /**
  13. * This class allows you to display a sortable data-table. It is possible to
  14. * split the data in several pages.
  15. * Using this class you can:
  16. * - automatically create checkboxes of the first table column
  17. * - a "select all" and "deselect all" link is added
  18. * - only if you provide a list of actions for the selected items
  19. * - click on the table header to sort the data
  20. * - choose how many items you see per page
  21. * - navigate through all data-pages
  22. * @package chamilo.library
  23. */
  24. class SortableTable extends HTML_Table {
  25. /**
  26. * A name for this table
  27. */
  28. public $table_name;
  29. /**
  30. * The page to display
  31. */
  32. public $page_nr;
  33. /**
  34. * The column to sort the data
  35. */
  36. public $column;
  37. /**
  38. * The sorting direction (ASC or DESC)
  39. */
  40. public $direction;
  41. /**
  42. * Number of items to display per page
  43. */
  44. public $per_page;
  45. /**
  46. * The default number of items to display per page
  47. */
  48. public $default_items_per_page;
  49. /**
  50. * A prefix for the URL-parameters, can be used on pages with multiple
  51. * SortableTables
  52. */
  53. public $param_prefix;
  54. /**
  55. * The pager object to split the data in several pages
  56. */
  57. public $pager;
  58. /**
  59. * The total number of items in the table
  60. */
  61. public $total_number_of_items;
  62. /**
  63. * The function to get the total number of items
  64. */
  65. public $get_total_number_function;
  66. /**
  67. * The function to the the data to display
  68. */
  69. public $get_data_function;
  70. /**
  71. * An array with defined column-filters
  72. */
  73. public $column_filters;
  74. /**
  75. * A list of actions which will be available through a select list
  76. */
  77. public $form_actions;
  78. /**
  79. * Additional parameters to pass in the URL
  80. */
  81. public $additional_parameters;
  82. /**
  83. * Additional attributes for the th-tags
  84. */
  85. public $th_attributes;
  86. /**
  87. * Additional attributes for the td-tags
  88. */
  89. public $td_attributes;
  90. /**
  91. * Array with names of the other tables defined on the same page of this
  92. * table
  93. */
  94. public $other_tables;
  95. /**
  96. * Activates the odd even rows
  97. * **/
  98. public $odd_even_rows_enabled = true;
  99. /**
  100. * Create a new SortableTable
  101. * @param string $table_name A name for the table (default = 'table')
  102. * @param string $get_total_number_function A user defined function to get
  103. * the total number of items in the table
  104. * @param string $get_data_function A function to get the data to display on
  105. * the current page
  106. * @param int $default_column The default column on which the data should be
  107. * sorted
  108. * @param int $default_items_per_page The default number of items to show
  109. * on one page
  110. * @param string $default_order_direction The default order direction;
  111. * either the constant 'ASC' or 'DESC'
  112. */
  113. public function __construct($table_name = 'table', $get_total_number_function = null, $get_data_function = null, $default_column = 1, $default_items_per_page = 20, $default_order_direction = 'ASC') {
  114. parent :: __construct (array ('class' => 'data_table'));
  115. $this->table_name = $table_name;
  116. $this->additional_parameters = array ();
  117. $this->param_prefix = $table_name.'_';
  118. $this->page_nr = isset ($_SESSION[$this->param_prefix.'page_nr']) ? intval($_SESSION[$this->param_prefix.'page_nr']) : 1;
  119. $this->page_nr = isset ($_GET[$this->param_prefix.'page_nr']) ? intval($_GET[$this->param_prefix.'page_nr']) : $this->page_nr;
  120. $this->column = isset ($_SESSION[$this->param_prefix.'column']) ? intval($_SESSION[$this->param_prefix.'column']) : $default_column;
  121. $this->column = isset ($_GET[$this->param_prefix.'column']) ? intval($_GET[$this->param_prefix.'column']) : $this->column;
  122. //$this->direction = isset ($_SESSION[$this->param_prefix.'direction']) ? $_SESSION[$this->param_prefix.'direction'] : $default_order_direction;
  123. if (isset($_SESSION[$this->param_prefix.'direction'])) {
  124. $my_session_direction = $_SESSION[$this->param_prefix.'direction'];
  125. if (!in_array($my_session_direction, array('ASC', 'DESC'))) {
  126. $this->direction = 'ASC';
  127. } else {
  128. if ($my_session_direction == 'ASC') {
  129. $this->direction = 'ASC';
  130. } elseif ($my_session_direction == 'DESC') {
  131. $this->direction = 'DESC';
  132. }
  133. }
  134. }
  135. if (isset($_GET[$this->param_prefix.'direction'])) {
  136. $my_get_direction = $_GET[$this->param_prefix.'direction'];
  137. if (!in_array($my_get_direction, array('ASC', 'DESC'))){
  138. $this->direction = 'ASC';
  139. } else {
  140. if ($my_get_direction == 'ASC') {
  141. $this->direction = 'ASC';
  142. } elseif ($my_get_direction == 'DESC') {
  143. $this->direction = 'DESC';
  144. }
  145. }
  146. }
  147. // Allow to change paginate in multiples tabs
  148. unset($_SESSION[$this->param_prefix.'per_page']);
  149. $this->per_page = isset ($_SESSION[$this->param_prefix.'per_page']) ? intval($_SESSION[$this->param_prefix.'per_page']) : $default_items_per_page;
  150. $this->per_page = isset ($_GET[$this->param_prefix.'per_page']) ? intval($_GET[$this->param_prefix.'per_page']) : $this->per_page;
  151. $_SESSION[$this->param_prefix.'per_page'] = $this->per_page;
  152. $_SESSION[$this->param_prefix.'direction'] = $this->direction ;
  153. $_SESSION[$this->param_prefix.'page_nr'] = $this->page_nr;
  154. $_SESSION[$this->param_prefix.'column'] = $this->column;
  155. $this->pager = null;
  156. $this->default_items_per_page = $default_items_per_page;
  157. $this->total_number_of_items = -1;
  158. $this->get_total_number_function = $get_total_number_function;
  159. $this->get_data_function = $get_data_function;
  160. $this->column_filters = array();
  161. $this->form_actions = array();
  162. $this->checkbox_name = null;
  163. $this->td_attributes = array();
  164. $this->th_attributes = array();
  165. $this->other_tables = array();
  166. }
  167. /**
  168. * Get the Pager object to split the showed data in several pages
  169. */
  170. public function get_pager() {
  171. if (is_null($this->pager)) {
  172. $total_number_of_items = $this->get_total_number_of_items();
  173. $params['mode'] = 'Sliding';
  174. $params['perPage'] = $this->per_page;
  175. $params['totalItems'] = $total_number_of_items;
  176. $params['urlVar'] = $this->param_prefix.'page_nr';
  177. $params['currentPage'] = $this->page_nr;
  178. $icon_attributes = array('style' => 'vertical-align: middle;');
  179. $params['prevImg'] = Display :: return_icon('action_prev.png', get_lang('PreviousPage'), $icon_attributes);
  180. $params['nextImg'] = Display :: return_icon('action_next.png', get_lang('NextPage'), $icon_attributes);
  181. $params['firstPageText'] = Display :: return_icon('action_first.png', get_lang('FirstPage'), $icon_attributes);
  182. $params['lastPageText'] = Display :: return_icon('action_last.png', get_lang('LastPage'), $icon_attributes);
  183. $params['firstPagePre'] = '';
  184. $params['lastPagePre'] = '';
  185. $params['firstPagePost'] = '';
  186. $params['lastPagePost'] = '';
  187. $params['spacesBeforeSeparator'] = '';
  188. $params['spacesAfterSeparator'] = '';
  189. $query_vars = array_keys($_GET);
  190. $query_vars_needed = array ($this->param_prefix.'column', $this->param_prefix.'direction', $this->param_prefix.'per_page');
  191. if (count($this->additional_parameters) > 0) {
  192. $query_vars_needed = array_merge($query_vars_needed, array_keys($this->additional_parameters));
  193. }
  194. $query_vars_exclude = array_diff($query_vars, $query_vars_needed);
  195. $params['excludeVars'] = $query_vars_exclude;
  196. $this->pager = & Pager::factory($params);
  197. }
  198. return $this->pager;
  199. }
  200. public function display() {
  201. echo $this->return_table();
  202. }
  203. /**
  204. * Displays the table, complete with navigation buttons to browse through
  205. * the data-pages.
  206. */
  207. public function return_table() {
  208. $empty_table = false;
  209. $content = $this->get_table_html();
  210. if ($this->get_total_number_of_items() == 0) {
  211. $cols = $this->getColCount();
  212. $this->setCellAttributes(1, 0, 'style="font-style: italic;text-align:center;" colspan='.$cols);
  213. $message_empty = api_xml_http_response_encode(get_lang('TheListIsEmpty'));
  214. $this->setCellContents(1, 0, $message_empty);
  215. $empty_table = true;
  216. }
  217. $html = '';
  218. if (!$empty_table) {
  219. $form = $this->get_page_select_form();
  220. $nav = $this->get_navigation_html();
  221. //Only show pagination info when there are items to paginate
  222. if ($this->get_total_number_of_items() > $this->default_items_per_page) {
  223. $html = '<table class="data_table_pagination">';
  224. $html .= '<tr>';
  225. $html .= '<td style="width:25%;">';
  226. $html .= $form;
  227. $html .= '</td>';
  228. $html .= '<td style="text-align:center;">';
  229. $html .= $this->get_table_title();
  230. $html .= '</td>';
  231. $html .= '<td style="text-align:right;width:25%;">';
  232. $html .= $nav;
  233. $html .= '</td>';
  234. $html .= '</tr>';
  235. $html .= '</table>';
  236. }
  237. if (count($this->form_actions) > 0) {
  238. $html .= '<script type="text/javascript">
  239. function setCheckbox(value) {
  240. d = document.form_'.$this->table_name.';
  241. for (i = 0; i < d.elements.length; i++) {
  242. if (d.elements[i].type == "checkbox") {
  243. d.elements[i].checked = value;
  244. if (value) {
  245. $(d.elements[i]).parentsUntil("tr").parent().addClass("row_selected");
  246. } else {
  247. $(d.elements[i]).parentsUntil("tr").parent().removeClass("row_selected");
  248. }
  249. }
  250. }
  251. }
  252. function action_click(element) {
  253. if (!confirm('."'".addslashes(get_lang("ConfirmYourChoice"))."'".')) {
  254. return false;
  255. } else {
  256. var action =$(element).attr("data-action");
  257. $(\' #form_'.$this->table_name.'_id input[name="action"] \').attr("value", action);
  258. $("#form_'.$this->table_name.'_id").submit();
  259. return false;
  260. }
  261. }
  262. </script>';
  263. $params = $this->get_sortable_table_param_string().'&amp;'.$this->get_additional_url_paramstring();
  264. $html .= '<form id ="form_'.$this->table_name.'_id" class="form-search" method="post" action="'.api_get_self().'?'.$params.'" name="form_'.$this->table_name.'">';
  265. }
  266. }
  267. $html .= $content;
  268. if (!$empty_table) {
  269. if (!empty($this->additional_parameters)) {
  270. foreach($this->additional_parameters as $key => $value) {
  271. $html .= '<input type="hidden" name ="'.Security::remove_XSS($key).'" value ="'.Security::remove_XSS($value).'" />';
  272. }
  273. }
  274. $html .= '<input type="hidden" name="action">';
  275. $html .= '<table style="width:100%;">';
  276. $html .= '<tr>';
  277. $html .= '<td>';
  278. if (count($this->form_actions) > 0) {
  279. $html .= '<div class="btn-toolbar">';
  280. $html .= '<div class="btn-group">';
  281. $html .= '<a class="btn" href="?'.$params.'&amp;'.$this->param_prefix.'selectall=1" onclick="javascript: setCheckbox(true); return false;">'.get_lang('SelectAll').'</a>';
  282. $html .= '<a class="btn" href="?'.$params.'" onclick="javascript: setCheckbox(false); return false;">'.get_lang('UnSelectAll').'</a> ';
  283. $html .= '</div>';
  284. $html .= '<div class="btn-group">
  285. <button class="btn" onclick="javascript:return false;">'.get_lang('Actions').'</button>
  286. <button class="btn dropdown-toggle" data-toggle="dropdown">
  287. <span class="caret"></span>
  288. </button>';
  289. $html .= '<ul class="dropdown-menu">';
  290. foreach ($this->form_actions as $action => & $label) {
  291. $html .= '<li><a data-action ="'.$action.'" href="#" onclick="javascript:action_click(this);">'.$label.'</a></li>';
  292. }
  293. $html .= '</ul>';
  294. $html .= '</div>';//btn-group
  295. $html .= '</div>'; //toolbar
  296. } else {
  297. $html .= $form;
  298. }
  299. $html .= '</td>';
  300. if ($this->get_total_number_of_items() > $this->default_items_per_page) {
  301. $html .= '<td style="text-align:right;">';
  302. $html .= $nav;
  303. $html .= '</td>';
  304. }else{
  305. $html .= '<td> ';
  306. $html .= '</td>';
  307. }
  308. $html .= '</tr>';
  309. $html .= '</table>';
  310. if (count($this->form_actions) > 0) {
  311. $html .= '</form>';
  312. }
  313. }
  314. return $html;
  315. }
  316. /**
  317. * This function shows the content of a table in a grid.
  318. * Should not be use to edit information (edit/delete rows) only.
  319. * */
  320. public function display_grid() {
  321. $empty_table = false;
  322. if ($this->get_total_number_of_items() == 0) {
  323. $cols = $this->getColCount();
  324. //$this->setCellAttributes(1, 0, 'style="font-style: italic;text-align:center;" colspan='.$cols);
  325. $message_empty = api_xml_http_response_encode(get_lang('TheListIsEmpty'));
  326. $this->setCellContents(1, 0, $message_empty);
  327. $empty_table = true;
  328. }
  329. $html = '';
  330. if (!$empty_table) {
  331. $form = $this->get_page_select_form();
  332. $nav = $this->get_navigation_html();
  333. // @todo This style css must be moved to default.css only for dev
  334. echo '<style>
  335. .main-grid { width:100%;}
  336. .sub-header { width:100%; padding-top: 10px; padding-right: 10px; padding-left: 10px; height:30px;}
  337. .grid_container { width:100%;}
  338. .grid_item { height: 120px; width:98px; float:left; padding:5px; margin:8px;}
  339. .grid_element_0 { width:100px; height: 100px; float:left; text-align:center; margin-bottom:5px;}
  340. .grid_element_1 { width:100px; float:left; text-align:center;margin-bottom:5px;}
  341. .grid_element_2 { width:150px; float:left;}
  342. .grid_selectbox { width:30%; float:left;}
  343. .grid_title { width:30%; float:left;}
  344. .grid_nav { }
  345. </style>';
  346. // @todo This also must be moved
  347. // Show only navigations if there are more than 1 page
  348. $my_pager = $this->get_pager();
  349. $html .= '<div class="main-grid">';
  350. if ($my_pager->numPages() > 1) {
  351. $html .= '<div class="sub-header">';
  352. $html .= '<div class="grid_selectbox">'.$form.'</div>';
  353. $html .= '<div class="grid_title">'.$this->get_table_title().'</div>';
  354. $html .= '<div class="grid_nav">'.$nav.'</div>';
  355. $html .= '</div>';
  356. }
  357. $html .= '<div class="clear"></div>';
  358. if (count($this->form_actions) > 0) {
  359. $script= '<script language="JavaScript" type="text/javascript">
  360. /*<![CDATA[*/
  361. function setCheckbox(value) {
  362. d = document.form_'.$this->table_name.';
  363. for (i = 0; i < d.elements.length; i++) {
  364. if (d.elements[i].type == "checkbox") {
  365. d.elements[i].checked = value;
  366. }
  367. if (value) {
  368. $(d.elements[i]).parentsUntil("tr").parent().addClass("row_selected");
  369. } else {
  370. $(d.elements[i]).parentsUntil("tr").parent().removeClass("row_selected");
  371. }
  372. }
  373. }
  374. /*]]>*/
  375. </script>';
  376. $params = $this->get_sortable_table_param_string().'&amp;'.$this->get_additional_url_paramstring();
  377. $html .= '<form method="post" action="'.api_get_self().'?'.$params.'" name="form_'.$this->table_name.'">';
  378. }
  379. }
  380. // Getting the items of the table
  381. $items = $this->get_clean_html(false); //no sort
  382. // Generation of style classes must be improved. Maybe we need a a table name to create style on the fly:
  383. // i.e: .whoisonline_table_grid_container instead of .grid_container
  384. // where whoisonline is the table's name like drupal's template engine
  385. $html .= '<div class="grid_container">';
  386. if (is_array($items) && count($items) > 0) {
  387. foreach ($items as & $row) {
  388. $html .= '<div class="grid_item">';
  389. $i = 0;
  390. foreach ($row as & $element) {
  391. $html .= '<div class="grid_element_'.$i.'">'.$element.'</div>';
  392. $i++;
  393. }
  394. $html .= '</div>';
  395. }
  396. }
  397. $html .= '</div>'; //close grid_container
  398. $html .= '</div>'; //close main grid
  399. $html .= '<div class="clear"></div>';
  400. /*
  401. if (!$empty_table) {
  402. $html .= '<table style="width:100%;">';
  403. $html .= '<tr>';
  404. $html .= '<td colspan="2">';
  405. if (count($this->form_actions) > 0) {
  406. $html .= '<br />';
  407. $html .= '<a href="?'.$params.'&amp;'.$this->param_prefix.'selectall=1" onclick="javascript:setCheckbox(true);return false;">'.get_lang('SelectAll').'</a> - ';
  408. $html .= '<a href="?'.$params.'" onclick="javascript:setCheckbox(false);return false;">'.get_lang('UnSelectAll').'</a> ';
  409. $html .= '<select name="action">';
  410. foreach ($this->form_actions as $action => $label) {
  411. $html .= '<option value="'.$action.'">'.$label.'</option>';
  412. }
  413. $html .= '</select>';
  414. $html .= '&nbsp;&nbsp;<button type="submit" class="save" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"),ENT_QUOTES))."'".')) return false;">'.get_lang('Select').'</button>';
  415. } else {
  416. $html .= $form;
  417. }
  418. $html .= '</td>';
  419. $html .= '<td style="text-align:right;">';
  420. $html .= $nav;
  421. $html .= '</td>';
  422. $html .= '</tr>';
  423. $html .= '</div>';
  424. if (count($this->form_actions) > 0) {
  425. $html .= '</form>';
  426. }
  427. }
  428. */
  429. echo $html;
  430. }
  431. /**
  432. * This function returns the content of a table in a grid
  433. * Should not be use to edit information (edit/delete rows) only.
  434. * @param array options of visibility
  435. * @param bool hide navigation optionally
  436. * @param int content per page when show navigation (optional)
  437. * @param bool sort data optionally
  438. * @return string grid html
  439. */
  440. public function display_simple_grid($visibility_options, $hide_navigation = true, $per_page = 20, $sort_data = true, $grid_class = array()) {
  441. $empty_table = false;
  442. if ($this->get_total_number_of_items() == 0) {
  443. $cols = $this->getColCount();
  444. //$this->setCellAttributes(1, 0, 'style="font-style: italic;text-align:center;" colspan='.$cols);
  445. $message_empty = api_xml_http_response_encode(get_lang('TheListIsEmpty'));
  446. $this->setCellContents(1, 0, $message_empty);
  447. $empty_table = true;
  448. }
  449. $html = '';
  450. if (!$empty_table) {
  451. // If we show the pagination
  452. if (!$hide_navigation) {
  453. $form = '&nbsp;';
  454. if ($this->get_total_number_of_items() > $per_page) {
  455. if ($per_page > 10) {
  456. $form = $this->get_page_select_form();
  457. }
  458. $nav = $this->get_navigation_html();
  459. // This also must be moved
  460. $html = '<div class="sub-header">';
  461. $html .= '<div class="grid_selectbox">'.$form.'</div>';
  462. $html .= '<div class="grid_title">'.$this->get_table_title().'</div>';
  463. $html .= '<div class="grid_nav">'.$nav.'</div>';
  464. $html .= '</div>';
  465. }
  466. }
  467. $html .= '<div class="clear"></div>';
  468. if (count($this->form_actions) > 0) {
  469. $script= '<script language="javaScript" type="text/javascript">
  470. /*<![CDATA[*/
  471. function setCheckbox(value) {
  472. d = document.form_'.$this->table_name.';
  473. for (i = 0; i < d.elements.length; i++) {
  474. if (d.elements[i].type == "checkbox") {
  475. d.elements[i].checked = value;
  476. }
  477. if (value) {
  478. $(d.elements[i]).parentsUntil("tr").parent().addClass("row_selected");
  479. } else {
  480. $(d.elements[i]).parentsUntil("tr").parent().removeClass("row_selected");
  481. }
  482. }
  483. }
  484. /*]]>*/
  485. </script>';
  486. $params = $this->get_sortable_table_param_string().'&amp;'.$this->get_additional_url_paramstring();
  487. $html .= '<form method="post" action="'.api_get_self().'?'.$params.'" name="form_'.$this->table_name.'">';
  488. }
  489. }
  490. if ($hide_navigation) {
  491. $items = $this->table_data; // This is a faster way to get what we want
  492. } else {
  493. // The normal way
  494. $items = $this->get_clean_html($sort_data); // Getting the items of the table
  495. }
  496. // Generation of style classes must be improved. Maybe we need a a table name to create style on the fly:
  497. // i.e: .whoisonline_table_grid_container instead of .grid_container
  498. // where whoisonline is the table's name like drupal's template engine
  499. if (is_array($visibility_options)) {
  500. $filter = false; // The 2nd condition of the if will be loaded
  501. } else {
  502. $filter = $visibility_options !== false;
  503. }
  504. $item_css_class = $item_css_style = $grid_css_class = $grid_css_style = '';
  505. if (!empty($grid_class)) {
  506. $grid_css_class = $grid_class['main']['class'];
  507. $item_css_class = $grid_class['item']['class'];
  508. $grid_css_style = isset($grid_class['main']['style']) ? $grid_class['main']['style'] : null;
  509. $item_css_style = isset($grid_class['item']['style']) ? $grid_class['item']['style'] : null;
  510. }
  511. $div = '';
  512. if (is_array($items) && count($items) > 0) {
  513. foreach ($items as & $row) {
  514. $i = 0;
  515. $rows = '';
  516. foreach ($row as & $element) {
  517. if ($filter || $visibility_options[$i]) {
  518. $rows .= '<div class="'.$this->table_name.'_grid_element_'.$i.'">'.$element.'</div>';
  519. }
  520. $i++;
  521. }
  522. $div .= Display::div($rows, array('class'=>$item_css_class.' '.$this->table_name.'_grid_item', 'style' => $item_css_style));
  523. }
  524. }
  525. $html .= Display::div($div, array('class'=>$grid_css_class.' '.$this->table_name.'_grid_container', 'style' => $grid_css_style));
  526. $html .= '<div class="clear"></div>';
  527. return $html;
  528. }
  529. /**
  530. * Get the HTML-code with the navigational buttons to browse through the
  531. * data-pages.
  532. */
  533. public function get_navigation_html () {
  534. $pager = $this->get_pager();
  535. $pager_links = $pager->getLinks();
  536. $nav = $pager_links['first'].' '.$pager_links['back'];
  537. $nav .= ' '.$pager->getCurrentPageId().' / '.$pager->numPages().' ';
  538. $nav .= $pager_links['next'].' '.$pager_links['last'];
  539. return $nav;
  540. }
  541. /**
  542. * Get the HTML-code with the data-table.
  543. */
  544. public function get_table_html() {
  545. $pager = $this->get_pager();
  546. $offset = $pager->getOffsetByPageId();
  547. $from = $offset[0] - 1;
  548. $table_data = $this->get_table_data($from);
  549. if (is_array($table_data)) {
  550. $count = 1;
  551. foreach ($table_data as $index => & $row) {
  552. $row = $this->filter_data($row);
  553. $this->addRow($row);
  554. if (isset($row['child_of'])) {
  555. $this->setRowAttributes($count, array('class' => 'hidden hidden_'.$row['child_of']), true);
  556. }
  557. $count++;
  558. }
  559. }
  560. if ($this->odd_even_rows_enabled == true) {
  561. $this->altRowAttributes(0, array ('class' => 'row_odd'), array ('class' => 'row_even'), true);
  562. }
  563. foreach ($this->th_attributes as $column => $attributes) {
  564. $this->setCellAttributes(0, $column, $attributes);
  565. }
  566. foreach ($this->td_attributes as $column => $attributes) {
  567. $this->setColAttributes($column, $attributes);
  568. }
  569. return $this->toHTML();
  570. }
  571. /**
  572. * This function return the items of the table
  573. * @param bool true for sorting table data or false otherwise
  574. * @return array table row items
  575. */
  576. public function get_clean_html($sort = true) {
  577. $pager = $this->get_pager();
  578. $offset = $pager->getOffsetByPageId();
  579. $from = $offset[0] - 1;
  580. $table_data = $this->get_table_data($from, null, null, null, $sort);
  581. $new_table_data = array();
  582. if (is_array($table_data)) {
  583. foreach ($table_data as $index => & $row) {
  584. $row = $this->filter_data($row);
  585. $new_table_data[] = $row;
  586. }
  587. }
  588. return $new_table_data;
  589. }
  590. /**
  591. * Get the HTML-code wich represents a form to select how many items a page
  592. * should contain.
  593. */
  594. public function get_page_select_form () {
  595. $total_number_of_items = $this->get_total_number_of_items();
  596. if ($total_number_of_items <= $this->default_items_per_page) {
  597. return '';
  598. }
  599. $result[] = '<form method="GET" action="'.api_get_self().'" style="display:inline;">';
  600. $param[$this->param_prefix.'direction'] = $this->direction;
  601. $param[$this->param_prefix.'page_nr'] = $this->page_nr;
  602. $param[$this->param_prefix.'column'] = $this->column;
  603. if (is_array($this->additional_parameters)) {
  604. $param = array_merge($param, $this->additional_parameters);
  605. }
  606. foreach ($param as $key => & $value) {
  607. $result[] = '<input type="hidden" name="'.$key.'" value="'.$value.'"/>';
  608. }
  609. $result[] = '<select name="'.$this->param_prefix.'per_page" onchange="javascript: this.form.submit();">';
  610. for ($nr = 10; $nr <= min(50, $total_number_of_items); $nr += 10) {
  611. $result[] = '<option value="'.$nr.'" '. ($nr == $this->per_page ? 'selected="selected"' : '').'>'.$nr.'</option>';
  612. }
  613. // @todo no limits
  614. //if ($total_number_of_items < 500) {
  615. $result[] = '<option value="'.$total_number_of_items.'" '. ($total_number_of_items == $this->per_page ? 'selected="selected"' : '').'>'.api_ucfirst(get_lang('All')).'</option>';
  616. //}
  617. $result[] = '</select>';
  618. $result[] = '<noscript>';
  619. $result[] = '<button class="btn save" type="submit">'.get_lang('Save').'</button>';
  620. $result[] = '</noscript>';
  621. $result[] = '</form>';
  622. $result = implode("\n", $result);
  623. return $result;
  624. }
  625. /**
  626. * Get the table title.
  627. */
  628. public function get_table_title () {
  629. $pager = $this->get_pager();
  630. $showed_items = $pager->getOffsetByPageId();
  631. return $showed_items[0].' - '.$showed_items[1].' / '.$this->get_total_number_of_items();
  632. }
  633. /**
  634. * Set the header-label
  635. * @param int $column The column number
  636. * @param string $label The label
  637. * @param boolean $sortable Is the table sortable by this column? (defatult
  638. * = true)
  639. * @param string $th_attributes Additional attributes for the th-tag of the
  640. * table header
  641. * @param string $td_attributes Additional attributes for the td-tags of the
  642. * column
  643. */
  644. public function set_header ($column, $label, $sortable = true, $th_attributes = null, $td_attributes = null) {
  645. $param['direction'] = 'ASC';
  646. if ($this->column == $column && $this->direction == 'ASC') {
  647. $param['direction'] = 'DESC';
  648. }
  649. $param['page_nr'] = $this->page_nr;
  650. $param['per_page'] = $this->per_page;
  651. $param['column'] = $column;
  652. if ($sortable) {
  653. $link = '<a href="'.api_get_self().'?'.api_get_cidreq().'&amp;';
  654. foreach ($param as $key => & $value) {
  655. $link .= $this->param_prefix.$key.'='.urlencode($value).'&amp;';
  656. }
  657. $link .= $this->get_additional_url_paramstring();
  658. $link .= '">'.$label.'</a>';
  659. if ($this->column == $column) {
  660. $link .= $this->direction == 'ASC' ? ' &#8595;' : ' &#8593;';
  661. }
  662. } else {
  663. $link = $label;
  664. }
  665. $this->setHeaderContents(0, $column, $link);
  666. if (!is_null($td_attributes)) {
  667. $this->td_attributes[$column] = $td_attributes;
  668. }
  669. if (!is_null($th_attributes)) {
  670. $this->th_attributes[$column] = $th_attributes;
  671. }
  672. }
  673. /**
  674. * Get the parameter-string with additional parameters to use in the URLs
  675. * generated by this SortableTable
  676. */
  677. public function get_additional_url_paramstring () {
  678. $param_string_parts = array ();
  679. if (is_array($this->additional_parameters) && count($this->additional_parameters) > 0) {
  680. foreach ($this->additional_parameters as $key => & $value) {
  681. $param_string_parts[] = urlencode($key).'='.urlencode($value);
  682. }
  683. }
  684. $result = implode('&amp;', $param_string_parts);
  685. foreach ($this->other_tables as $index => & $tablename) {
  686. $param = array();
  687. if (isset($_GET[$tablename.'_direction'])) {
  688. //$param[$tablename.'_direction'] = $_GET[$tablename.'_direction'];
  689. $my_get_direction = $_GET[$tablename.'_direction'];
  690. if (!in_array($my_get_direction, array('ASC', 'DESC'))) {
  691. $param[$tablename.'_direction'] = 'ASC';
  692. } else {
  693. $param[$tablename.'_direction'] = $my_get_direction;
  694. }
  695. }
  696. if (isset($_GET[$tablename.'_page_nr'])) {
  697. $param[$tablename.'_page_nr'] = intval($_GET[$tablename.'_page_nr']);
  698. }
  699. if (isset($_GET[$tablename.'_per_page'])) {
  700. $param[$tablename.'_per_page'] = intval($_GET[$tablename.'_per_page']);
  701. }
  702. if (isset($_GET[$tablename.'_column'])) {
  703. $param[$tablename.'_column'] = intval($_GET[$tablename.'_column']);
  704. }
  705. $param_string_parts = array ();
  706. foreach ($param as $key => & $value) {
  707. $param_string_parts[] = urlencode($key).'='.urlencode($value);
  708. }
  709. if (count($param_string_parts) > 0)
  710. $result .= '&amp;'.implode('&amp;', $param_string_parts);
  711. }
  712. return $result;
  713. }
  714. /**
  715. * Get the parameter-string with the SortableTable-related parameters to use
  716. * in URLs
  717. */
  718. public function get_sortable_table_param_string () {
  719. $param[$this->param_prefix.'direction'] = $this->direction;
  720. $param[$this->param_prefix.'page_nr'] = $this->page_nr;
  721. $param[$this->param_prefix.'per_page'] = $this->per_page;
  722. $param[$this->param_prefix.'column'] = $this->column;
  723. $param_string_parts = array ();
  724. foreach ($param as $key => & $value) {
  725. $param_string_parts[] = urlencode($key).'='.urlencode($value);
  726. }
  727. $res = implode('&amp;', $param_string_parts);
  728. return $res;
  729. }
  730. /**
  731. * Add a filter to a column. If another filter was allready defined for the
  732. * given column, it will be overwritten.
  733. * @param int $column The number of the column
  734. * @param string $function The name of the filter-function. This should be a
  735. * function wich requires 1 parameter and returns the filtered value.
  736. */
  737. public function set_column_filter ($column, $function) {
  738. $this->column_filters[$column] = $function;
  739. }
  740. /**
  741. * Define a list of actions which can be performed on the table-date.
  742. * If you define a list of actions, the first column of the table will be
  743. * converted into checkboxes.
  744. * @param array $actions A list of actions. The key is the name of the
  745. * action. The value is the label to show in the select-box
  746. * @param string $checkbox_name The name of the generated checkboxes. The
  747. * value of the checkbox will be the value of the first column.
  748. */
  749. public function set_form_actions ($actions, $checkbox_name = 'id') {
  750. $this->form_actions = $actions;
  751. $this->checkbox_name = $checkbox_name;
  752. }
  753. /**
  754. * Define a list of additional parameters to use in the generated URLs
  755. * <code>$parameters['action'] = 'test'; will be convert in <input type="hidden" name="action" value="test"></code>
  756. * @param array $parameters
  757. */
  758. public function set_additional_parameters ($parameters) {
  759. $this->additional_parameters = $parameters;
  760. }
  761. /**
  762. * Set other tables on the same page.
  763. * If you have other sortable tables on the page displaying this sortable
  764. * tables, you can define those other tables with this function. If you
  765. * don't define the other tables, there sorting and pagination will return
  766. * to their default state when sorting this table.
  767. * @param array $tablenames An array of table names.
  768. */
  769. public function set_other_tables ($tablenames) {
  770. $this->other_tables = $tablenames;
  771. }
  772. /**
  773. * Transform all data in a table-row, using the filters defined by the
  774. * function set_column_filter(...) defined elsewhere in this class.
  775. * If you've defined actions, the first element of the given row will be
  776. * converted into a checkbox
  777. * @param array $row A row from the table.
  778. */
  779. public function filter_data ($row) {
  780. $url_params = $this->get_sortable_table_param_string().'&amp;'.$this->get_additional_url_paramstring();
  781. foreach ($this->column_filters as $column => & $function) {
  782. $row[$column] = call_user_func($function, $row[$column], $url_params, $row);
  783. }
  784. if (count($this->form_actions) > 0) {
  785. if (strlen($row[0]) > 0) {
  786. $row[0] = '<input type="checkbox" name="'.$this->checkbox_name.'[]" value="'.$row[0].'"';
  787. if (isset($_GET[$this->param_prefix.'selectall'])) {
  788. $row[0] .= ' checked="checked"';
  789. }
  790. $row[0] .= '/>';
  791. }
  792. }
  793. foreach ($row as $index => & $value) {
  794. if (empty($value)) {
  795. $value = '-';
  796. }
  797. }
  798. return $row;
  799. }
  800. /**
  801. * Get the total number of items. This function calls the function given as
  802. * 2nd argument in the constructor of a SortableTable. Make sure your
  803. * function has the same parameters as defined here.
  804. */
  805. public function get_total_number_of_items () {
  806. if ($this->total_number_of_items == -1 && !is_null($this->get_total_number_function)) {
  807. $this->total_number_of_items = call_user_func($this->get_total_number_function);
  808. }
  809. return $this->total_number_of_items;
  810. }
  811. /**
  812. * Get the data to display. This function calls the function given as
  813. * 2nd argument in the constructor of a SortableTable. Make sure your
  814. * function has the same parameters as defined here.
  815. * @param int $from Index of the first item to return.
  816. * @param int $per_page The number of items to return
  817. * @param int $column The number of the column on which the data should be
  818. * @param bool $sort Whether to sort or not
  819. * sorted
  820. * @param string $direction In which order should the data be sorted (ASC
  821. * or DESC)
  822. */
  823. public function get_table_data ($from = null, $per_page = null, $column = null, $direction = null, $sort = null) {
  824. if (!is_null($this->get_data_function)) {
  825. return call_user_func($this->get_data_function, $from, $this->per_page, $this->column, $this->direction);
  826. }
  827. return array ();
  828. }
  829. }
  830. /**
  831. * Sortable table which can be used for data available in an array
  832. * @package chamilo.library
  833. */
  834. class SortableTableFromArray extends SortableTable {
  835. /**
  836. * The array containing all data for this table
  837. */
  838. public $table_data;
  839. /**
  840. * Constructor
  841. * @param array $table_data
  842. * @param int $default_column
  843. * @param int $default_items_per_page
  844. */
  845. public function __construct($table_data, $default_column = 1, $default_items_per_page = 20, $tablename = 'tablename') {
  846. parent :: __construct ($tablename, null, null, $default_column, $default_items_per_page);
  847. $this->table_data = $table_data;
  848. }
  849. /**
  850. * Get table data to show on current page
  851. * @see SortableTable#get_table_data
  852. */
  853. public function get_table_data($from = 1, $per_page = null, $column = null, $direction = null, $sort = true) {
  854. if ($sort) {
  855. $content = TableSort :: sort_table($this->table_data, $this->column, $this->direction == 'ASC' ? SORT_ASC : SORT_DESC);
  856. } else {
  857. $content = $this->table_data;
  858. }
  859. return array_slice($content, $from, $this->per_page);
  860. }
  861. /**
  862. * Get total number of items
  863. * @see SortableTable#get_total_number_of_items
  864. */
  865. public function get_total_number_of_items() {
  866. return count($this->table_data);
  867. }
  868. }
  869. /**
  870. * Sortable table which can be used for data available in an array
  871. *
  872. * Is a variation of SortableTableFromArray because we add 2 new arrays $column_show and $column_order
  873. * $column_show is an array that lets us decide which are going to be the columns to show
  874. * $column_order is an array that lets us decide the ordering of the columns
  875. * i.e: $column_header=array('a','b','c','d','e'); $column_order=array(1,2,5,4,5);
  876. * These means that the 3th column (letter "c") will be sort like the order we use in the 5th column
  877. * @package chamilo.library
  878. */
  879. class SortableTableFromArrayConfig extends SortableTable {
  880. /**
  881. * The array containing the columns that will be show i.e $column_show=array('1','0','0'); we will show only the 1st column
  882. */
  883. private $column_show;
  884. /**
  885. *The array containing the real sort column $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
  886. */
  887. private $column_order;
  888. /**
  889. * The array containing all data for this table
  890. */
  891. private $table_data;
  892. private $doc_filter;
  893. /**
  894. * Constructor
  895. * @param array $table_data All the information of the table
  896. * @param int $default_column Default column that will be use in the sorts functions
  897. * @param int $default_items_per_page quantity of pages that we are going to see
  898. * @param int $tablename Name of the table
  899. * @param array $column_show An array with binary values 1: we show the column 2: we don't show it
  900. * @param array $column_order An array of integers that let us decide how the columns are going to be sort.
  901. * @param bool special modification to fix the document name order
  902. */
  903. public function __construct ($table_data, $default_column = 1, $default_items_per_page = 20, $tablename = 'tablename', $column_show = null, $column_order = null, $direction = 'ASC', $doc_filter = false) {
  904. $this->column_show = $column_show;
  905. $this->column_order = $column_order;
  906. $this->doc_filter = $doc_filter;
  907. parent :: __construct ($tablename, null, null, $default_column, $default_items_per_page, $direction);
  908. $this->table_data = $table_data;
  909. }
  910. /**
  911. * Get table data to show on current page
  912. * @see SortableTable#get_table_data
  913. */
  914. public function get_table_data($from = 1, $per_page = null, $column = null, $direction = null, $sort = true) {
  915. $content = TableSort :: sort_table_config($this->table_data, $this->column, $this->direction == 'ASC' ? SORT_ASC : SORT_DESC, $this->column_show, $this->column_order, SORT_REGULAR, $this->doc_filter);
  916. return array_slice($content, $from, $this->per_page);
  917. }
  918. /**
  919. * Get total number of items
  920. * @see SortableTable#get_total_number_of_items
  921. */
  922. public function get_total_number_of_items() {
  923. return count($this->table_data);
  924. }
  925. }