dialogstack.class.inc.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. /**
  3. * Helper class to allow modal-style dialog box in an html form
  4. *
  5. * Possible improvement: do not use _SESSION for the caller's data,
  6. * instead set a member variable with caller information
  7. * and take the opportunity of the first edit button to place the information
  8. * into a hidden field
  9. *
  10. * Usage:
  11. */
  12. define('DLGSTACK_OK', 1);
  13. define('DLGSTACK_CANCEL', 2);
  14. //session_name("dialogstack");
  15. session_start();
  16. class dialogstack
  17. {
  18. private static $m_bCurrPageDeclared = false;
  19. /**
  20. * Declare the current page as being a dialog issuer, potentially pop...
  21. */
  22. static public function DeclareCaller($sTitle)
  23. {
  24. self::$m_bCurrPageDeclared = false;
  25. $_SESSION['dialogstack_calleruri'] = $_SERVER["REQUEST_URI"];
  26. $_SESSION['dialogstack_callertitle'] = $sTitle;
  27. if (isset($_POST["dialogstackpop"]) && ($_POST["dialogstackpop"] == count($_SESSION['dialogstack_currdlg'])))
  28. {
  29. // Pop !
  30. array_pop($_SESSION['dialogstack_currdlg']);
  31. }
  32. }
  33. /**
  34. * True if the current page has been loaded from an "dialog startup button"
  35. */
  36. static private function GetRetArgName()
  37. {
  38. foreach($_REQUEST as $sArgName=>$sArgValue)
  39. {
  40. if (strstr($sArgName, "dlgstack_go,"))
  41. {
  42. $aTokens = explode(",", $sArgName);
  43. return self::ArgNameDecode($aTokens[1]);
  44. }
  45. }
  46. return "";
  47. }
  48. /**
  49. * Protect against weird effects of PHP interpreting brackets...
  50. */
  51. static private function ArgNameEncode($sArgName)
  52. {
  53. return str_replace(array('[', ']'), array('_bracket_open_', '_bracket_close_'), $sArgName);
  54. }
  55. static private function ArgNameDecode($sCodedArgName)
  56. {
  57. return str_replace(array('_bracket_open_', '_bracket_close_'), array('[', ']'), $sCodedArgName);
  58. }
  59. /**
  60. * True if the current page has been loaded from an "dialog startup button"
  61. */
  62. static public function IsDialogStartup()
  63. {
  64. return (strlen(self::GetRetArgName()) > 0);
  65. }
  66. /**
  67. * Helper to
  68. */
  69. static private function RemoveArg(&$aValues, $sKey, &$retval = null)
  70. {
  71. if (isset($aValues[$sKey]))
  72. {
  73. if (empty($retval))
  74. {
  75. $retval = $aValues[$sKey];
  76. }
  77. unset($aValues[$sKey]);
  78. }
  79. }
  80. /**
  81. * Record current page args, and returns the initial value for the dialog
  82. */
  83. static public function StartDialog()
  84. {
  85. if (!isset($_SESSION['dialogstack_currdlg']))
  86. {
  87. // Init stack
  88. $_SESSION['dialogstack_currdlg'] = array();
  89. }
  90. $sRetArgName = self::GetRetArgName();
  91. $sCodedArgName = self::ArgNameEncode($sRetArgName);
  92. $sArgForRetArgName = "dlgstack_init_".$sCodedArgName;
  93. $sButtonName = "dlgstack_go,".$sCodedArgName;
  94. // Do not record utility arguments, neither the current value (stored separately)
  95. //
  96. $initValue = null;
  97. $aPost = $_POST;
  98. self::RemoveArg($aPost, $sArgForRetArgName, $initValue);
  99. self::RemoveArg($aPost, $sButtonName);
  100. self::RemoveArg($aPost, 'dlgstack_onok_page', $sOnOKPage);
  101. self::RemoveArg($aPost, 'dlgstack_onok_args', $aOnOKArgs);
  102. $aGet = $_GET;
  103. self::RemoveArg($aGet, $sArgForRetArgName, $initValue);
  104. self::RemoveArg($aGet, $sButtonName);
  105. self::RemoveArg($aGet, 'dlgstack_onok_page', $sOnOKPage);
  106. self::RemoveArg($aGet, 'dlgstack_onok_args', $aOnOKArgs);
  107. if (self::$m_bCurrPageDeclared)
  108. {
  109. throw new Exception("DeclareCaller() must not be called before StartDialog()");
  110. }
  111. $aCall = array(
  112. "title"=>$_SESSION['dialogstack_callertitle'],
  113. "uri"=>$_SESSION['dialogstack_calleruri'],
  114. "post"=>$aPost,
  115. "get"=>$aGet,
  116. "retarg"=>$sRetArgName,
  117. "initval"=>$initValue,
  118. );
  119. if (isset($sOnOKPage)) $aCall["onok_page"] = $sOnOKPage;
  120. if (isset($aOnOKArgs)) $aCall["onok_args"] = $aOnOKArgs;
  121. array_push($_SESSION['dialogstack_currdlg'], $aCall);
  122. return $initValue;
  123. }
  124. /**
  125. * Render a button to launch a new dialog
  126. */
  127. static public function RenderEditableField($sTitle, $sArgName, $sCurrValue, $bAddFieldValue, $sOnOKPage = "", $aOnOKArgs = array())
  128. {
  129. $sRet = "";
  130. $sCodedArgName = self::ArgNameEncode($sArgName);
  131. if ($bAddFieldValue)
  132. {
  133. $sRet .= "<input type=\"hidden\" name=\"$sArgName\" value=\"$sCurrValue\">\n";
  134. }
  135. $sRet .= "<input type=\"hidden\" name=\"dlgstack_init_$sCodedArgName\" value=\"$sCurrValue\">\n";
  136. $sRet .= "<input type=\"submit\" name=\"dlgstack_go,$sCodedArgName\" value=\"$sTitle\">\n";
  137. if (!empty($sOnOKPage))
  138. {
  139. $sRet .= "<input type=\"hidden\" name=\"dlgstack_onok_page\" value=\"$sCurrValue\">\n";
  140. }
  141. foreach($aOnOKArgs as $sArgName=>$value)
  142. {
  143. $sRet .= "<input type=\"hidden\" name=\"dlgstack_onok_args[$sArgName]\" value=\"$value\">\n";
  144. }
  145. return $sRet;
  146. }
  147. /**
  148. * Render a [set of] hidden field, from a value that may be an array
  149. */
  150. static private function RenderHiddenField($sName, $value)
  151. {
  152. $sRet = "";
  153. if (is_array($value))
  154. {
  155. foreach($value as $sKey=>$subvalue)
  156. {
  157. $sRet .= self::RenderHiddenField($sName.'['.$sKey.']', $subvalue);
  158. }
  159. }
  160. else
  161. {
  162. $sRet .= "<input type=\"hidden\" name=\"$sName\" value=\"$value\">\n";
  163. }
  164. return $sRet;
  165. }
  166. /**
  167. * Render a form to end the current dialog and return to the caller
  168. */
  169. static public function RenderEndDialogForm($iButtonStyle, $sTitle, $sRetValue = null)
  170. {
  171. $aCall = end($_SESSION['dialogstack_currdlg']);
  172. if (!$aCall) return;
  173. return self::privRenderEndDialogForm($aCall, $iButtonStyle, $sTitle, $sRetValue);
  174. }
  175. /**
  176. * Returns an array of buttons to get back to upper dialog levels
  177. */
  178. static public function GetCurrentStack()
  179. {
  180. $aRet = array();
  181. if (isset($_SESSION['dialogstack_currdlg']))
  182. {
  183. foreach ($_SESSION['dialogstack_currdlg'] as $aCall)
  184. {
  185. $aRet[] = self::privRenderEndDialogForm($aCall, DLGSTACK_CANCEL, $aCall["title"]);
  186. }
  187. }
  188. return $aRet;
  189. }
  190. /**
  191. * Render a form to end the current dialog and return to the caller
  192. */
  193. static private function privRenderEndDialogForm($aCall, $iButtonStyle, $sTitle, $sRetValue = null)
  194. {
  195. if (($iButtonStyle == DLGSTACK_OK) && isset($aCall["onok_page"])) $sFormAction = $aCall["onok_page"];
  196. else $sFormAction = $aCall["uri"];
  197. $sRet = "<form method=\"post\" action=\"$sFormAction\">\n";
  198. foreach ($aCall["post"] as $sName=>$value)
  199. {
  200. $sRet .= self::RenderHiddenField($sName, $value);
  201. }
  202. if ($iButtonStyle == DLGSTACK_OK)
  203. {
  204. if (isset($aCall["onok_args"]))
  205. {
  206. foreach($aCall["onok_args"] as $sArgName=>$value)
  207. {
  208. $sRet .= "<input type=\"hidden\" name=\"$sArgName\" value=\"$value\">\n";
  209. }
  210. }
  211. $sRet .= "<input type=\"hidden\" name=\"".$aCall["retarg"]."\" value=\"$sRetValue\">\n";
  212. $sRet .= "<input type=\"submit\" name=\"dlgstackOK\" value=\"$sTitle, (OK) Back to ".$aCall["title"]."\">\n";
  213. }
  214. elseif ($iButtonStyle == DLGSTACK_CANCEL)
  215. {
  216. if (!is_null($aCall["initval"]))
  217. {
  218. $sRet .= "<input type=\"hidden\" name=\"".$aCall["retarg"]."\" value=\"".$aCall["initval"]."\">\n";
  219. }
  220. $sRet .= "<input type=\"submit\" name=\"dlgstackCANCEL\" value=\"$sTitle\">\n";
  221. }
  222. else
  223. {
  224. throw new Exception("Wrong value for button style ($iButtonStyle)");
  225. }
  226. $sRet .= "<input type=\"hidden\" name=\"dialogstackpop\" value=\"".count($_SESSION['dialogstack_currdlg'])."\">\n";
  227. $sRet .= "</form>\n";
  228. return $sRet;
  229. }
  230. }
  231. ?>