PageRenderTime 99ms CodeModel.GetById 32ms RepoModel.GetById 5ms app.codeStats 0ms

/library/Adapto/Recordlist.php

http://github.com/egeniq/adapto
PHP | 836 lines | 565 code | 101 blank | 170 comment | 165 complexity | 329a7094bf90846c12c147bf860ae632 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Adapto Toolkit.
  4. * Detailed copyright and licensing information can be found
  5. * in the doc/COPYRIGHT and doc/LICENSE files which should be
  6. * included in the distribution.
  7. *
  8. * @package adapto
  9. * @subpackage recordlist
  10. *
  11. * @copyright (c)2000-2004 Ibuildings.nl BV
  12. * @license http://www.achievo.org/atk/licensing ATK Open Source License
  13. *
  14. */
  15. /** recordlist flags */
  16. define("RL_NO_SORT", 1); // recordlist is not sortable
  17. define("RL_NO_SEARCH", 2); // recordlist is not searchable
  18. define("RL_NO_EXTENDED_SEARCH", 4); // recordlist is not searchable
  19. define("RL_EMBED", 8); // recordlist is embedded
  20. define("RL_MRA", 16); // multi-record-actions enabled
  21. define("RL_MRPA", 32); // multi-record-priority-actions enabled
  22. define("RL_LOCK", 64); // records can be locked
  23. define("RL_EXT_SORT", 128); // extended sort feature
  24. /**
  25. * The recordlist class is used to render tables containing records.
  26. *
  27. * @author ijansch
  28. * @package adapto
  29. * @subpackage recordlist
  30. *
  31. */
  32. class Adapto_Recordlist
  33. {
  34. public $m_entity=NULL; // defaulted to public
  35. public $m_flags=0; // defaulted to public
  36. public $m_actionloader; // defaulted to public
  37. public $m_masterentity=NULL; // defaulted to public
  38. public $m_hasActionColumn=0; // defaulted to public
  39. public $m_actionSessionStatus = SESSION_NESTED; // defaulted to public
  40. /**
  41. * @access private
  42. * @param atkEntity $entity
  43. */
  44. function setEntity(&$entity)
  45. {
  46. $this->m_entity = &$entity;
  47. }
  48. /**
  49. * Sets the action session status for actions in the recordlist.
  50. * (Defaults to SESSION_NESTED).
  51. *
  52. * @param int $sessionStatus The session status (one of the SESSION_* constants)
  53. */
  54. function setActionSessionStatus($sessionStatus)
  55. {
  56. $this->m_actionSessionStatus = $sessionStatus;
  57. }
  58. /**
  59. * Make the recordlist use a different masterentity than the entity than it is rendering.
  60. *
  61. * @param atkEntity $masterentity
  62. */
  63. function setMasterEntity(&$masterentity)
  64. {
  65. $this->m_masterentity = &$masterentity;
  66. }
  67. /**
  68. * Converts the given entity flags to recordlist flags where possible.
  69. *
  70. * @param int $flags
  71. * @static
  72. */
  73. function convertFlags($flags)
  74. {
  75. $result = hasFlag($flags, EF_MRA) ? RL_MRA : 0;
  76. $result |= hasFlag($flags, EF_MRPA) ? RL_MRPA : 0;
  77. $result |= hasFlag($flags, EF_LOCK) ? RL_LOCK : 0;
  78. $result |= hasFlag($flags, EF_NO_SEARCH) ? RL_NO_SEARCH : 0;
  79. $result |= hasFlag($flags, EF_NO_EXTENDED_SEARCH) ? RL_NO_EXTENDED_SEARCH : 0;
  80. $result |= hasFlag($flags, EF_EXT_SORT) ? RL_EXT_SORT : 0;
  81. return $result;
  82. }
  83. /**
  84. * Render the recordlist
  85. *
  86. * @param atkEntity $entity the entity
  87. * @param Array $recordset the list of records
  88. * @param Array $actions the default actions array
  89. * @param Integer $flags recordlist flags (see the top of this file)
  90. * @param Array $suppressList fields we don't display
  91. * @param String $formName if embedded the form name in which we are embedded
  92. * @param Array $navigation Navigation links
  93. * @param String $embedprefix The prefix for embeded fields
  94. * @return String The rendered recordlist
  95. */
  96. function render(&$entity, $recordset, $actions, $flags=0, $suppressList="", $formName="", $navigation=array(),$embedprefix="")
  97. {
  98. $data = $this->getRecordlistData($entity, $recordset, $actions, $flags, $suppressList, $formName, $navigation,$embedprefix);
  99. $ui = &$this->m_entity->getUi();
  100. $res = $ui->render($entity->getTemplate("admin"), array("vorientation"=>$data["vorientation"],
  101. "rows"=>$data["rows"],
  102. "header"=>$data["header"],
  103. "search"=>$data["search"],
  104. "sort"=>$data["sort"],
  105. "total"=>$data["total"],
  106. "searchstart"=>$data["searchstart"],
  107. "searchend"=>$data["searchend"],
  108. "sortstart"=>$data["sortstart"],
  109. "sortend"=>$data["sortend"],
  110. "liststart"=>$data["liststart"],
  111. "listend"=>$data["listend"],
  112. "listid"=>$data["listid"],
  113. "mra"=>$data["mra"]),$this->m_entity->m_module);
  114. return $res;
  115. }
  116. /**
  117. * Get records for a recordlist without actually rendering the recordlist.
  118. * @param atkEntity $entity the entity
  119. * @param Array $recordset the list of records
  120. * @param Array $actions the default actions array
  121. * @param Integer $flags recordlist flags (see the top of this file)
  122. * @param Array $suppressList fields we don't display
  123. * @param String $formName if embedded the form name in which we are embedded
  124. * @param Array $navigation Navigation links
  125. * @param String $embedprefix The prefix for embeded fields
  126. * @return String The rendered recordlist
  127. */
  128. function getRecordlistData(&$entity, $recordset, $actions, $flags=0, $suppressList="", $formName="", $navigation=array(),$embedprefix="")
  129. {
  130. $this->setEntity($entity);
  131. $this->m_flags = $flags;
  132. $theme = Adapto_ClassLoader::getInstance("Adapto_Ui_Theme");
  133. $page = &atkPage::getInstance();
  134. $page->register_style($theme->stylePath("recordlist.css",$this->m_entity->m_module));
  135. $listName = "rl_".getUniqueId("normalRecordList");
  136. $page->register_script(Adapto_Config::getGlobal("atkroot")."atk/javascript/recordlist.js");
  137. $defaulthighlight = $theme->getAttribute("highlight");
  138. $selectcolor = $theme->getAttribute("select");
  139. /* retrieve list array */
  140. $list = $this->listArray($recordset, $flags, "", $actions, $suppressList, $embedprefix);
  141. /* Check if some flags are still valid or not... */
  142. if (hasFlag($flags, RL_MRA) && (count($list["mra"]) == 0 || count($list["rows"]) == 0)) $flags ^= RL_MRA;
  143. if (!hasFlag($flags, RL_NO_SEARCH) && count($list["search"]) == 0) $flags |= RL_NO_SEARCH;
  144. if (hasFlag($flags, RL_MRPA) && (count($this->m_entity->m_priority_actions) == 0 || count($list["rows"]) == 0)) $flags ^= RL_MRPA;
  145. elseif (hasFlag($flags, RL_MRPA))
  146. {
  147. $flags = ($flags | RL_MRA | RL_MRPA ) ^ RL_MRA;
  148. if ($this->m_entity->m_priority_max == 0)
  149. $this->m_entity->m_priority_max = $this->m_entity->m_priority_min + count($list["rows"]) - 1;
  150. }
  151. $orientation = Adapto_Config::getGlobal('recordlist_orientation', $theme->getAttribute("recordlist_orientation"));
  152. $vorientation = trim(Adapto_Config::getGlobal('recordlist_vorientation', $theme->getAttribute("recordlist_vorientation")));
  153. $ui = &$this->m_entity->getUi();
  154. if (is_object($ui) && is_object($page))
  155. {
  156. /**************/
  157. /* HEADER ROW */
  158. /**************/
  159. $headercols = array();
  160. if ($this->_hasActionColumn($list) && count($list["rows"]) == 0)
  161. {
  162. if ($orientation == "left" || $orientation == "both")
  163. {
  164. // empty cell above search button, if zero rows
  165. // if $orientation is empty, no search button is shown, so no empty cell is needed
  166. $headercols[] = array("content"=>"&nbsp;");
  167. }
  168. }
  169. if (hasFlag($flags, RL_MRA) || hasFlag($flags, RL_MRPA))
  170. {
  171. $headercols[] = array("content"=>""); // Empty leader on top of mra action list.
  172. }
  173. if (hasFlag($flags, RL_LOCK))
  174. {
  175. $headercols[] = array("content"=>'<img src="'.Adapto_Config::getGlobal("atkroot").'atk/images/lock_head.gif">');
  176. }
  177. if (($orientation == "left" || $orientation == "both") && ($this->_hasActionColumn($list) && count($list["rows"]) > 0))
  178. {
  179. $headercols[] = array("content"=>"");
  180. }
  181. //Todo: For speedup we must move hasFlag($this->m_flags, RL_EMBED out of cycle or to listArray()
  182. foreach (array_values($list["heading"]) as $head)
  183. {
  184. // make old recordlist compatible with new order specification
  185. if (!empty($head["order"]))
  186. {
  187. global $Adapto_VARS;
  188. $head["url"] = session_url(atkSelf().'?atkentitytype='.$Adapto_VARS["atkentitytype"].'&atkaction='.$Adapto_VARS["atkaction"].'&atkorderby='.rawurlencode($head["order"]));
  189. }
  190. if (hasFlag($this->m_flags, RL_EMBED) && !empty($head["url"]))
  191. {
  192. $head["url"] = str_replace("atkorderby=","atkorderby{$embedprefix}=",$head["url"]);
  193. }
  194. if (empty($head["url"]))
  195. {
  196. $headercols[] = array("content"=>$head["title"]);
  197. }
  198. else
  199. {
  200. $headercols[] = array("content"=>href($head["url"], $head["title"]));
  201. }
  202. }
  203. if (($orientation == "right" || $orientation == "both") && ($this->_hasActionColumn($list) && count($list["rows"]) > 0))
  204. {
  205. $headercols[] = array("content"=>"");
  206. }
  207. if ($this->_hasActionColumn($list) && count($list["rows"]) == 0)
  208. {
  209. if ($orientation == "right" || $orientation == "both")
  210. {
  211. // empty cell above search button, if zero rows
  212. // if $orientation is empty, no search button is shown, so no empty cell is needed
  213. $headercols[] = array("content"=>"&nbsp;");
  214. }
  215. }
  216. /**************/
  217. /* SORT ROW */
  218. /**************/
  219. $sortcols = array();
  220. $sortstart=""; $sortend="";
  221. if (hasFlag($flags, RL_EXT_SORT))
  222. {
  223. $button = '<input type="submit" value="'.atktext("sort").'">';
  224. if (hasFlag($flags, RL_MRA) || hasFlag($flags, RL_MRPA))
  225. {
  226. $sortcols[] = array("content"=>""); // Empty leader on top of mra action list.
  227. }
  228. if (hasFlag($flags, RL_LOCK))
  229. {
  230. $sortcols[] = array("content"=>"");
  231. }
  232. if ($orientation == "left" || $orientation == "both")
  233. {
  234. $sortcols[] = array("content"=>$button);
  235. }
  236. $sortstart = '<a name="sortform"></a>'.
  237. '<form action="'.atkSelf().'?'.SID.'" method="get">'.
  238. session_form().
  239. '<input type="hidden" name="atkstartat" value="0">'; // reset atkstartat to first page after a new sort
  240. foreach (array_keys($list["heading"]) as $key)
  241. {
  242. if (isset($list["sort"][$key])) $sortcols[] = array("content"=>$list["sort"][$key]);
  243. }
  244. $sortend = '</form>';
  245. if ($orientation == "right" || $orientation == "both")
  246. {
  247. $sortcols[] = array("content"=>$button);
  248. }
  249. }
  250. /**************/
  251. /* SEARCH ROW */
  252. /**************/
  253. $searchcols = array();
  254. $searchstart=""; $searchend="";
  255. if (!hasFlag($flags, RL_NO_SEARCH))
  256. {
  257. $button = '<input type="submit" class="btn_search" value="'.atktext("search").'">';
  258. if (!hasFlag($flags, RL_NO_EXTENDED_SEARCH)&&!$this->m_entity->hasFlag(EF_NO_EXTENDED_SEARCH))
  259. {
  260. $button .= '<br>'.href(atkSelf()."?atkentitytype=".$this->getMasterEntityType()."&atkaction=".$entity->getExtendedSearchAction(),"(".atktext("search_extended").")",SESSION_NESTED);
  261. }
  262. $searchstart = '<a name="searchform"></a>';
  263. if (!hasFlag($this->m_flags, RL_EMBED))
  264. {
  265. $searchstart.='<form action="'.atkSelf().'?'.SID.'" method="get">'.session_form();
  266. $searchstart.= '<input type="hidden" name="atkentitytype" value="'.$this->getMasterEntityType().'">'.
  267. '<input type="hidden" name="atkaction" value="'.$this->m_entity->m_action.'">'. '<input type="hidden" name="atksmartsearch" value="clear">'.
  268. '<input type="hidden" name="atkstartat" value="0">'; // reset atkstartat to first page after a new search;
  269. }
  270. if (hasFlag($flags, RL_MRA) || hasFlag($flags, RL_MRPA))
  271. {
  272. $searchcols[] = array("content"=>"");
  273. }
  274. if (hasFlag($flags, RL_LOCK))
  275. {
  276. $searchcols[] = array("content"=>"");
  277. }
  278. if ($orientation == "left" || $orientation == "both")
  279. {
  280. $searchcols[] = array("content"=>$button);
  281. }
  282. foreach (array_keys($list["heading"]) as $key)
  283. {
  284. if (isset($list["search"][$key]))
  285. {
  286. $searchcols[] = array("content"=>$list["search"][$key]);
  287. }
  288. else
  289. {
  290. $searchcols[] = array("content"=>"");
  291. }
  292. }
  293. if ($orientation == "right" || $orientation == "both")
  294. {
  295. $searchcols[] = array("content"=>$button);
  296. }
  297. $searchend = "";
  298. if (!hasFlag($this->m_flags, RL_EMBED)) $searchend = '</form>';
  299. }
  300. /*******************************************/
  301. /* MULTI-RECORD-(PRIORITY-)ACTIONS FORM DATA */
  302. /*******************************************/
  303. $liststart = "";
  304. $listend = "";
  305. if (hasFlag($flags, RL_MRA) || hasFlag($flags, RL_MRPA))
  306. {
  307. $page->register_script(Adapto_Config::getGlobal("atkroot")."atk/javascript/formselect.js");
  308. if (!hasFlag($flags, RL_EMBED))
  309. {
  310. if (empty($formName)) $formName = $listName;
  311. $liststart = '<form id="'.$formName.'" name="'.$formName.'" method="post">'.
  312. session_form(SESSION_DEFAULT).
  313. '<input type="hidden" name="atkentitytype" value="'.$this->getMasterEntityType().'">'.
  314. '<input type="hidden" name="atkaction" value="'.$this->m_entity->m_action.'">';
  315. $listend = '</form>';
  316. }
  317. if (hasFlag($flags, RL_MRA))
  318. {
  319. $liststart.= '<script language="javascript" type="text/javascript">var '.$listName.' = new Object();</script>';
  320. }
  321. }
  322. /********/
  323. /* ROWS */
  324. /********/
  325. $records = array();
  326. $keys = array_keys($actions);
  327. $actionurl = (count($actions)>0) ? $actions[$keys[0]] : '';
  328. $actionloader = "rl_a['".$listName."'] = {};";
  329. $actionloader.= "\nrl_a['".$listName."']['base'] = '".session_vars($this->m_actionSessionStatus,1,$actionurl)."';";
  330. $actionloader.= "\nrl_a['".$listName."']['embed'] = ".(hasFlag($flags, RL_EMBED)?'true':'false').";";
  331. if (isset($navigation["next"]) && isset($navigation["next"]["url"]))
  332. {
  333. $actionloader.="\nrl_a['".$listName."']['next'] = '".$navigation["next"]["url"]."';";
  334. }
  335. if (isset($navigation["previous"]) && isset($navigation["previous"]["url"]))
  336. {
  337. $actionloader.="\nrl_a['".$listName."']['previous'] = '".$navigation["previous"]["url"]."';";
  338. }
  339. for ($i = 0, $_i = count($list["rows"]); $i < $_i; $i++)
  340. {
  341. $record = array();
  342. /* Special rowColor method makes it possible to change the row color based on the record data.
  343. * the method can return a simple value (which will be used for the normal row color), or can be
  344. * an array, in which case the first element will be the normal row color, and the second the mouseover
  345. * row color, example: function rowColor(&$record, $num) { return array('red', 'blue'); }
  346. */
  347. $method = "rowColor";
  348. $bgn="";
  349. $bgh = $defaulthighlight;
  350. if (method_exists($this->m_entity, $method))
  351. {
  352. $bgn = $this->m_entity->$method($recordset[$i], $i);
  353. if (is_array($bgn)) list($bgn, $bgh) = $bgn;
  354. }
  355. /* alternate colors of rows */
  356. $record["background"] = $bgn;
  357. $record["highlight"] = $bgh;
  358. $record["rownum"] = $i;
  359. $record["id"] = $listName.'_'.$i;
  360. $record["type"] = $list["rows"][$i]["type"];
  361. /* multi-record-priority-actions -> priority selection */
  362. if (hasFlag($flags, RL_MRPA))
  363. {
  364. $select = '<select name="'.$listName.'_atkselector[]">'.
  365. '<option value="'.rawurlencode($list["rows"][$i]["selector"]).'"></option>';
  366. for ($j = $this->m_entity->m_priority_min; $j <= $this->m_entity->m_priority_max; $j++)
  367. $select .= '<option value="'.$j.'">'.$j.'</option>';
  368. $select .= '</select>';
  369. $record["cols"][] = array("content" => $select, "type" => "mrpa");
  370. }
  371. /* multi-record-actions -> checkbox */
  372. elseif (hasFlag($flags, RL_MRA))
  373. {
  374. if (count($list["rows"][$i]["mra"]) > 0)
  375. $record["cols"][] = array(
  376. "content"=>'<input type="checkbox" name="'.$listName.'_atkselector[]" value="'.Adapto_htmlentities($list["rows"][$i]["selector"]).'" class="atkcheckbox" onclick="if (this.disabled) this.checked = false">'.
  377. '<script language="javascript" type="text/javascript">'.$listName.'["'.Adapto_htmlentities($list["rows"][$i]["selector"]).'"] = new Array("'.implode($list["rows"][$i]["mra"], '","').'");</script>',
  378. "type" => "mra");
  379. else $record["cols"][] = array("content"=>"");
  380. }
  381. /* locked? */
  382. if (hasFlag($flags, RL_LOCK))
  383. {
  384. if (is_array($list["rows"][$i]["lock"]))
  385. {
  386. $alt = $list["rows"][$i]["lock"]["user_id"]." / ".$list["rows"][$i]["lock"]["user_ip"];
  387. $record["cols"][] = array("content"=>'<img src="'.Adapto_Config::getGlobal("atkroot").'atk/images/lock.gif" alt="'.$alt.'" title="'.$alt.'" border="0">', "type" => "lock");
  388. }
  389. else $record["cols"][] = array("content"=>"");
  390. }
  391. $str_actions = "<span class=\"actions\">";
  392. $actionloader.="\nrl_a['".$listName."'][".$i."] = {};";
  393. $icons = (Adapto_Config::getGlobal('recordlist_icons', $theme->getAttribute("recordlist_icons"))===false ||
  394. Adapto_Config::getGlobal('recordlist_icons', $theme->getAttribute("recordlist_icons"))==='false'?false:true);
  395. foreach ($list["rows"][$i]["actions"] as $name => $url)
  396. {
  397. if (substr($url, 0, 11) == 'javascript:')
  398. {
  399. $call = substr($url, 11);
  400. $actionloader.="\nrl_a['{$listName}'][{$i}]['{$name}'] = function() { $call; };";
  401. }
  402. else
  403. {
  404. $actionloader.="\nrl_a['{$listName}'][{$i}]['{$name}'] = '$url';";
  405. }
  406. $link = $name;
  407. if($icons == true)
  408. {
  409. $icon = $theme->iconPath(strtolower($name),"recordlist", $this->m_entity->m_module);
  410. $link = sprintf('<img class="recordlist" border="0" src="%1$s" alt="%2$s" title="%2$s">', $icon, atktext($name, $this->m_entity->m_module, $this->m_entity->m_type));
  411. }
  412. else
  413. {
  414. $link = atktext($name, $this->m_entity->m_module, $this->m_entity->m_type);
  415. }
  416. $confirmtext= "false";
  417. if (Adapto_Config::getGlobal("recordlist_javascript_delete") && $name=="delete")
  418. $confirmtext = "'".$this->m_entity->confirmActionText($name)."'";
  419. $str_actions.='<a href="'."javascript:rl_do('$listName',$i,'$name',$confirmtext);".'">'.$link.'</a>&nbsp;';
  420. }
  421. $str_actions.="</span>";
  422. /* actions (left) */
  423. if ($orientation == "left" || $orientation == "both")
  424. {
  425. if (!empty($list["rows"][$i]["actions"]))
  426. {
  427. $record["cols"][] = array("content"=>$str_actions, "type" => "actions");
  428. }
  429. else if ($this->_hasActionColumn($list))
  430. {
  431. $record["cols"][] = array("content"=>"");
  432. }
  433. }
  434. /* columns */
  435. foreach ($list["rows"][$i]["data"] as $html)
  436. $record["cols"][] = array("content"=>$html, "type" => "data");
  437. /* actions (right) */
  438. if ($orientation=="right"||$orientation=="both")
  439. {
  440. if (!empty($list["rows"][$i]["actions"])) $record["cols"][] = array("content"=>$str_actions, "type" => "actions");
  441. else if ($this->_hasActionColumn($list))
  442. {
  443. $record["cols"][] = array("content"=>"");
  444. }
  445. }
  446. $records[] = $record;
  447. }
  448. $page->register_loadscript($actionloader);
  449. $this->m_actionloader = $actionloader;
  450. /*************/
  451. /* TOTAL ROW */
  452. /*************/
  453. $totalcols = array();
  454. if (count($list["total"]) > 0)
  455. {
  456. if (hasFlag($flags, RL_MRA) || hasFlag($flags, RL_MRPA)) $totalcols[] = array("content"=>"");
  457. if (hasFlag($flags, RL_LOCK)) $totalcols[] = array("content"=>"");
  458. if (($orientation == "left" || $orientation == "both") && ($this->_hasActionColumn($list) && count($list["rows"]) > 0))
  459. $totalcols[] = array("content"=>"");
  460. foreach (array_keys($list["heading"]) as $key)
  461. {
  462. $totalcols[] = array("content"=>(isset($list["total"][$key])?$list["total"][$key]:""));
  463. }
  464. if (($orientation == "right" || $orientation == "both") && ($this->_hasActionColumn($list) && count($list["rows"]) > 0))
  465. $totalcols[] = array("content"=>"");
  466. }
  467. /*************************************************/
  468. /* MULTI-RECORD-PRIORITY-ACTION FORM (CONTINUED) */
  469. /*************************************************/
  470. $mra = "";
  471. if (hasFlag($flags, RL_MRPA))
  472. {
  473. $target = session_url(atkSelf().'?atkentitytype='.$this->getMasterEntityType(), SESSION_NESTED);
  474. /* multiple actions -> dropdown */
  475. if (count($this->m_entity->m_priority_actions) > 1)
  476. {
  477. $mra = '<select name="'.$listName.'_atkaction">'.
  478. '<option value="">'.atktext("with_selected").':</option>';
  479. foreach ($this->m_entity->m_priority_actions as $name)
  480. $mra .= '<option value="'.$name.'">'.atktext($name).'</option>';
  481. $mra .= '</select>&nbsp;'.$this->getCustomMraHtml().
  482. '<input type="button" class="btn" value="'.atktext("submit").'" onclick="atkSubmitMRPA(\''.$listName.'\', this.form, \''.$target.'\')">';
  483. }
  484. /* one action -> only the submit button */
  485. else
  486. {
  487. $mra= $this->getCustomMraHtml().'<input type="hidden" name="'.$listName.'_atkaction" value="'.$this->m_entity->m_priority_actions[0].'">'.
  488. '<input type="button" class="btn" value="'.atktext($this->m_entity->m_priority_actions[0]).'" onclick="atkSubmitMRPA(\''.$listName.'\', this.form, \''.$target.'\')">';
  489. }
  490. }
  491. /****************************************/
  492. /* MULTI-RECORD-ACTION FORM (CONTINUED) */
  493. /****************************************/
  494. elseif (hasFlag($flags, RL_MRA))
  495. {
  496. $target = session_url(atkSelf().'?atkentitytype='.$this->m_entity->atkEntityType().'&atktarget='.$this->m_entity->m_postvars['atktarget'].'&atktargetvar='.$this->m_entity->m_postvars['atktargetvar'].'&atktargetvartpl='.$this->m_entity->m_postvars['atktargetvartpl'], SESSION_NESTED);
  497. $mra = (count($list["rows"]) > 1 ?
  498. '<a href="javascript:updateSelection(\''.$listName.'\', document.forms[\''.$formName.'\'], \'all\')">'.atktext("select_all").'</a> / '.
  499. '<a href="javascript:updateSelection(\''.$listName.'\', document.forms[\''.$formName.'\'], \'none\')">'.atktext("deselect_all").'</a> / '.
  500. '<a href="javascript:updateSelection(\''.$listName.'\', document.forms[\''.$formName.'\'], \'invert\')">'.atktext("select_invert").'</a> '
  501. :
  502. '');
  503. /* multiple actions -> dropdown */
  504. if (count($list["mra"]) > 1)
  505. {
  506. $mra .= '<select name="'.$listName.'_atkaction" onchange="javascript:updateSelectable(\''.$listName.'\', this.form)">'.
  507. '<option value="">'.atktext("with_selected").':</option>';
  508. foreach ($list["mra"] as $name)
  509. {
  510. if ($this->m_entity->allowed($name))
  511. {
  512. $mra .= '<option value="'.$name.'">'.atktext($name, $this->m_entity->m_module, $this->m_entity->m_type).'</option>';
  513. }
  514. }
  515. $mra .= '</select>&nbsp;'.$this->getCustomMraHtml().
  516. '<input type="button" class="btn" value="'.atktext("submit").'" onclick="atkSubmitMRA(\''.$listName.'\', this.form, \''.$target.'\')">';
  517. }
  518. /* one action -> only the submit button */
  519. else
  520. {
  521. if ($this->m_entity->allowed($list["mra"][0]))
  522. {
  523. $mra .= '&nbsp; <input type="hidden" name="'.$listName.'_atkaction" value="'.$list["mra"][0].'">'.
  524. $this->getCustomMraHtml().
  525. '<input type="button" class="btn" value="'.atktext($list["mra"][0],$this->m_entity->m_module, $this->m_entity->m_type).'" onclick="atkSubmitMRA(\''.$listName.'\', this.form, \''.$target.'\')">';
  526. }
  527. }
  528. }
  529. if (Adapto_Config::getGlobal("use_keyboard_handler"))
  530. {
  531. $kb = &atkKeyboard::getInstance();
  532. $kb->addRecordListHandler($listName, $selectcolor, count($records));
  533. }
  534. $recordListData = array("vorientation"=>$vorientation,
  535. "rows"=>$records,
  536. "header"=>$headercols,
  537. "search"=>$searchcols,
  538. "sort"=>$sortcols,
  539. "total"=>$totalcols,
  540. "searchstart"=>$searchstart,
  541. "searchend"=>$searchend,
  542. "sortstart"=>$sortstart,
  543. "sortend"=>$sortend,
  544. "liststart"=>$liststart,
  545. "listend"=>$listend,
  546. "listid"=>$listName,
  547. "mra"=>$mra);
  548. return $recordListData;
  549. }
  550. }
  551. /**
  552. * Checks wether the recordlist should display a column which holds the actions.
  553. *
  554. * @access private
  555. * @param Array $list The recordlist data
  556. * @return bool Wether the list should display an extra column to hold the actions
  557. */
  558. function _hasActionColumn($list)
  559. {
  560. if($this->m_hasActionColumn == 0)
  561. {
  562. // when there's a search bar, we always need an extra column (for the button)
  563. if (!hasFlag($this->m_flags, RL_NO_SEARCH))
  564. {
  565. $this->m_hasActionColumn = true;
  566. }
  567. // when there's an extended sort bar, we also need the column (for the sort button)
  568. else if (hasFlag($this->m_flags, RL_EXT_SORT))
  569. {
  570. $this->m_hasActionColumn = true;
  571. }
  572. else
  573. {
  574. // otherwise, it depends on whether one of the records has actions defined.
  575. $this->m_hasActionColumn = false;
  576. foreach ($list["rows"] as $record)
  577. {
  578. if (!empty($record['actions']))
  579. {
  580. $this->m_hasActionColumn = true;
  581. break;
  582. }
  583. }
  584. }
  585. }
  586. return $this->m_hasActionColumn;
  587. }
  588. /**
  589. * Get custom mra HTML code
  590. *
  591. * @return string The custom HTML
  592. */
  593. function getCustomMraHtml()
  594. {
  595. if (method_exists($this->m_entity, "getcustommrahtml"))
  596. {
  597. $output = $this->m_entity->getCustomMraHtml();
  598. return $output;
  599. }
  600. }
  601. /**
  602. * Function outputs an array with all information necessary to output a recordlist.
  603. *
  604. * @param Array $recordset List of records that need to be displayed
  605. * @param Integer $flags Recordlist flags
  606. * @param String $prefix Prefix for each column name (used for subcalls)
  607. * @param Array $actions List of default actions for each record
  608. * @param Array $suppress An array of fields that you want to hide
  609. * @param String $embedprefix The prefix for embeded fields
  610. *
  611. * The result array contains the following information:
  612. * "heading" => for each visible column an array containing: "title" {, "url"}
  613. * "search" => for each visible column HTML input field(s) for searching
  614. * "rows" => list of rows, per row: "data", "actions", "mra", "record"
  615. * "totalraw" => for each totalisable column the sum value field(s) (raw)
  616. * "total" => for each totalisable column the sum value (display)
  617. * "mra" => list of all multi-record actions
  618. *
  619. * @return see above
  620. */
  621. function listArray(&$recordset, $flags=0, $prefix="", $actions=array(), $suppress=array(), $embedprefix="")
  622. {
  623. if (!is_array($suppress)) $suppress = array();
  624. $result = array("heading" => array(), "search" => array(), "rows" => array(),
  625. "totalraw" => array(), "total" => array(), "mra" => array());
  626. if (hasFlag($this->m_flags, RL_EMBED) && $embedprefix)
  627. {
  628. $prefix = $embedprefix."][";
  629. }
  630. $columnConfig = &$this->m_entity->getColumnConfig();
  631. /* get the heading and search columns */
  632. $atksearchpostvar = isset($this->m_entity->m_postvars["atksearch"]) ? $this->m_entity->m_postvars["atksearch"] : null;
  633. if (!hasFlag($flags, RL_NO_SEARCH)) $this->m_entity->setAttribSizes();
  634. foreach (array_keys($this->m_entity->m_attribIndexList) as $r)
  635. {
  636. $name = $this->m_entity->m_attribIndexList[$r]["name"];
  637. if (!in_array($name, $suppress))
  638. {
  639. $attribute = &$this->m_entity->m_attribList[$name];
  640. $attribute->addToListArrayHeader($this->m_entity->m_action, $result, $prefix, $flags, $atksearchpostvar, $columnConfig);
  641. }
  642. }
  643. /* actions array can contain multi-record-actions */
  644. if (count($actions) == 2 && count(array_diff(array_keys($actions), array("actions", "mra"))) == 0)
  645. {
  646. $mra = $actions["mra"];
  647. $actions = $actions["actions"];
  648. }
  649. else
  650. $mra = $this->m_entity->hasFlag(EF_NO_DELETE) ? array() : array("delete");
  651. /* get the rows */
  652. for ($i = 0, $_i = count($recordset); $i < $_i; $i++)
  653. {
  654. $result["rows"][$i] = array("columns" => array(), "actions" => $actions, "mra" => $mra, "record" => &$recordset[$i], "data" => array());
  655. $result["rows"][$i]["selector"] = $this->m_entity->primaryKey($recordset[$i]);
  656. $result["rows"][$i]["type"]="data";
  657. $row = &$result["rows"][$i];
  658. /* locked */
  659. if (hasFlag($flags, RL_LOCK))
  660. {
  661. $result["rows"][$i]["lock"] = $this->m_entity->m_lock->isLocked($result["rows"][$i]["selector"], $this->m_entity->m_table);
  662. if (is_array($result["rows"][$i]["lock"]))
  663. {
  664. unset($row["actions"]["edit"]);
  665. unset($row["actions"]["delete"]);
  666. $row["mra"] = array();
  667. }
  668. }
  669. /* actions / mra */
  670. $this->m_entity->collectRecordActions($row["record"], $row["actions"], $row["mra"]);
  671. $result["mra"] = array_merge($result["mra"], $row["mra"]);
  672. foreach($row["actions"] as $name => $url)
  673. {
  674. if (!empty($url) && $this->m_entity->allowed($name, $row["record"]))
  675. {
  676. /* dirty hack */
  677. $atkencoded = strpos($url, "_15B") > 0;
  678. $url = str_replace("%5B","[", $url);
  679. $url = str_replace("%5D","]", $url);
  680. $url = str_replace("_1"."5B","[", $url);
  681. $url = str_replace("_1"."5D","]", $url);
  682. if ($atkencoded) $url = str_replace('[pk]', atkurlencode(rawurlencode($row["selector"]), false), $url);
  683. else $url = str_replace('[pk]', rawurlencode($row["selector"]), $url);
  684. $parser = new Adapto_StringParser($url);
  685. $url = $parser->parse($row["record"],true);
  686. $row["actions"][$name] = $url;
  687. }
  688. else
  689. {
  690. unset($row["actions"][$name]);
  691. }
  692. }
  693. /* columns */
  694. foreach (array_keys($this->m_entity->m_attribIndexList) as $r)
  695. {
  696. $name = $this->m_entity->m_attribIndexList[$r]["name"];
  697. if (!in_array($name, $suppress))
  698. {
  699. $attribute = &$this->m_entity->m_attribList[$name];
  700. $attribute->addToListArrayRow($this->m_entity->m_action, $result, $i, $prefix, $flags);
  701. }
  702. }
  703. }
  704. if (hasFlag($flags, RL_EXT_SORT) && $columnConfig->hasSubTotals())
  705. {
  706. $totalizer = new Adapto_Totalizer($this->m_entity, $columnConfig);
  707. $result["rows"] = $totalizer->totalize($result["rows"]);
  708. }
  709. if (hasFlag($flags, RL_MRA))
  710. $result["mra"] = array_values(array_unique($result["mra"]));
  711. return $result;
  712. }
  713. /**
  714. * Get the masterentity
  715. *
  716. * @return atkEntity The master entity
  717. */
  718. function getMasterEntity()
  719. {
  720. if (is_object($this->m_masterentity)) return $this->m_masterentity;
  721. return $this->m_entity; // treat rendered entity as master
  722. }
  723. /**
  724. * Get the entitytype of the master entity
  725. *
  726. * @return string Modulename.entityname of the master entity
  727. */
  728. function getMasterEntityType()
  729. {
  730. $entity = &$this->getMasterEntity();
  731. return $entity->atkEntityType();
  732. }
  733. }