uiwizard.class.inc.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. class UIWizard
  3. {
  4. protected $m_oPage;
  5. protected $m_sClass;
  6. protected $m_sTargetState;
  7. protected $m_aWizardSteps;
  8. public function __construct($oPage, $sClass, $sTargetState = '')
  9. {
  10. $this->m_oPage = $oPage;
  11. $this->m_sClass = $sClass;
  12. if (empty($sTargetState))
  13. {
  14. $sTargetState = MetaModel::GetDefaultState($sClass);
  15. }
  16. $this->m_sTargetState = $sTargetState;
  17. $this->m_aWizardSteps = $this->ComputeWizardStructure();
  18. }
  19. public function GetObjectClass() { return $this->m_sClass; }
  20. public function GetTargetState() { return $this->m_sTargetState; }
  21. public function GetWizardStructure() { return $this->m_aWizardSteps; }
  22. /**
  23. * Displays one step of the wizard
  24. */
  25. public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false)
  26. {
  27. $this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
  28. $this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
  29. $aStates = MetaModel::EnumStates($this->m_sClass);
  30. $aDetails = array();
  31. $sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
  32. foreach($aStep as $sAttCode)
  33. {
  34. if ($sAttCode != 'finalclass') // Do not displa the attribute that stores the actual class name
  35. {
  36. $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
  37. $sAttLabel = $oAttDef->GetLabel();
  38. $iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
  39. $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
  40. if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
  41. {
  42. $aFields[$sAttCode] = array();
  43. foreach($aPrerequisites as $sCode)
  44. {
  45. $aFields[$sAttCode][$sCode] = '';
  46. }
  47. }
  48. if (count($aPrerequisites) > 0)
  49. {
  50. $aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
  51. }
  52. $sFieldFlag = ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) ? ' <span class="hilite">*</span>' : '';
  53. $oDefaultValuesSet = $oAttDef->GetDefaultValue(); // @@@ TO DO: get the object's current value if the object exists
  54. $sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions);
  55. $aFieldsMap[$iMaxInputId] = $sAttCode;
  56. $aDetails[] = array('label' => $oAttDef->GetLabel().$sFieldFlag, 'value' => "<div id=\"field_$iMaxInputId\">$sHTMLValue</div>");
  57. if ($oAttDef->GetValuesDef() != null)
  58. {
  59. $sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
  60. }
  61. if ($oAttDef->GetDefaultValue() != null)
  62. {
  63. $sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
  64. }
  65. if ($oAttDef->IsLinkSet())
  66. {
  67. $sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
  68. }
  69. $iMaxInputId++;
  70. }
  71. }
  72. //$aDetails[] = array('label' => '', 'value' => '<input type="button" value="Next &gt;&gt;">');
  73. $this->m_oPage->details($aDetails);
  74. $sBackButtonDisabled = ($iStepIndex <= 1) ? 'disabled' : '';
  75. $sDisabled = $bFinishEnabled ? '' : 'disabled';
  76. $nbSteps = count($this->m_aWizardSteps['mandatory']) + count($this->m_aWizardSteps['optional']);
  77. $this->m_oPage->add("<div style=\"text-align:center\">
  78. <input type=\"button\" value=\"&lt;&lt; Back \" $sBackButtonDisabled onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\">
  79. <input type=\"button\" value=\" Next &gt;&gt;\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\">
  80. <input type=\"button\" value=\" Finish \" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\">
  81. </div>\n");
  82. $this->m_oPage->add("
  83. <script>
  84. function OnEnterStep{$iStepIndex}()
  85. {
  86. oWizardHelper.ResetQuery();
  87. oWizardHelper.UpdateWizard();
  88. $sJSHandlerCode
  89. oWizardHelper.AjaxQueryServer();
  90. }
  91. </script>\n");
  92. $this->m_oPage->add("</div>\n\n");
  93. }
  94. /**
  95. * Display the final step of the wizard: a confirmation screen
  96. */
  97. public function DisplayFinalStep($iStepIndex, $aFieldsMap)
  98. {
  99. $this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
  100. $this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
  101. $this->m_oPage->P("Final step: confirmation");
  102. $this->m_oPage->add("<form method=\"post\" action=\"../pages/UI.php\">\n");
  103. $this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\">\n");
  104. $this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">\n");
  105. $this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\">\n");
  106. $this->m_oPage->add("<script>\n");
  107. $this->m_oPage->add("function OnEnterStep$iStepIndex() {\n");
  108. foreach($aFieldsMap as $iInputId => $sAttCode)
  109. {
  110. $this->m_oPage->add("\toWizardHelper.UpdateCurrentValue('$sAttCode');\n");
  111. }
  112. $this->m_oPage->add("\toWizardHelper.Preview('object_preview');\n");
  113. $this->m_oPage->add("\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n");
  114. $this->m_oPage->add("}\n");
  115. $this->m_oPage->add("</script>\n");
  116. $this->m_oPage->add("<div id=\"object_preview\">\n");
  117. $this->m_oPage->add("</div>\n");
  118. $this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\">\n");
  119. $this->m_oPage->add("</form>\n");
  120. $this->m_oPage->add("</div>\n");
  121. }
  122. /**
  123. * Compute the order of the fields & pages in the wizard
  124. * @param $oPage iTopWebPage The current page (used to display error messages)
  125. * @param $sClass string Name of the class
  126. * @param $sStateCode string Code of the target state of the object
  127. * @return hash Two dimensional array: each element represents the list of fields for a given page
  128. */
  129. protected function ComputeWizardStructure()
  130. {
  131. $aWizardSteps = array( 'mandatory' => array(), 'optional' => array());
  132. $aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
  133. $aStates = MetaModel::EnumStates($this->m_sClass);
  134. if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
  135. {
  136. // Check all the fields that *must* be included in the wizard for this
  137. // particular target state
  138. $aFields = array();
  139. foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
  140. {
  141. $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
  142. $sAttLabel = $oAttDef->GetLabel();
  143. if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
  144. {
  145. $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
  146. $aFields[$sAttCode] = array();
  147. foreach($aPrerequisites as $sCode)
  148. {
  149. $aFields[$sAttCode][$sCode] = '';
  150. }
  151. }
  152. }
  153. // Now use the dependencies between the fields to order them
  154. while(count($aFields) > 0)
  155. {
  156. $aCurrentStep = array();
  157. foreach($aFields as $sAttCode => $aDependencies)
  158. {
  159. // All fields with no remaining dependencies can be entered at this
  160. // step of the wizard
  161. if (count($aDependencies) == 0)
  162. {
  163. $aCurrentStep[] = $sAttCode;
  164. $aFieldsDone[$sAttCode] = '';
  165. unset($aFields[$sAttCode]);
  166. // Remove this field from the dependencies of the other fields
  167. foreach($aFields as $sUpdatedCode => $aDummy)
  168. {
  169. // remove the dependency
  170. unset($aFields[$sUpdatedCode][$sAttCode]);
  171. }
  172. }
  173. }
  174. if (count($aCurrentStep) == 0)
  175. {
  176. // This step of the wizard would contain NO field !
  177. echo "<strong>Error:</strong> Circular reference in the dependencies between the fields.";
  178. print_r($aFields);
  179. break;
  180. }
  181. $aWizardSteps['mandatory'][] = $aCurrentStep;
  182. }
  183. }
  184. // Now computes the steps to fill the optional fields
  185. $sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
  186. $aFields = array(); // reset
  187. foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
  188. {
  189. $iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
  190. if ( ($sStateAttCode != $sAttCode) &&
  191. (!$oAttDef->IsExternalField()) &&
  192. (($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0) &&
  193. (!isset($aFieldsDone[$sAttCode])) )
  194. {
  195. // 'State', external fields, read-only and hidden fields
  196. // and fields that are already listed in the wizard
  197. // are removed from the 'optional' part of the wizard
  198. $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
  199. $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
  200. $aFields[$sAttCode] = array();
  201. foreach($aPrerequisites as $sCode)
  202. {
  203. if (!isset($aFieldsDone[$sCode]))
  204. {
  205. // retain only the dependencies that were not covered
  206. // in the 'mandatory' part of the wizard
  207. $aFields[$sAttCode][$sCode] = '';
  208. }
  209. }
  210. }
  211. }
  212. // Now use the dependencies between the fields to order them
  213. while(count($aFields) > 0)
  214. {
  215. $aCurrentStep = array();
  216. foreach($aFields as $sAttCode => $aDependencies)
  217. {
  218. // All fields with no remaining dependencies can be entered at this
  219. // step of the wizard
  220. if (count($aDependencies) == 0)
  221. {
  222. $aCurrentStep[] = $sAttCode;
  223. $aFieldsDone[$sAttCode] = '';
  224. unset($aFields[$sAttCode]);
  225. // Remove this field from the dependencies of the other fields
  226. foreach($aFields as $sUpdatedCode => $aDummy)
  227. {
  228. // remove the dependency
  229. unset($aFields[$sUpdatedCode][$sAttCode]);
  230. }
  231. }
  232. }
  233. if (count($aCurrentStep) == 0)
  234. {
  235. // This step of the wizard would contain NO field !
  236. $oPage->add("<strong>Error:</strong> Circular reference in the dependencies between the fields.");
  237. print_r($aFields);
  238. break;
  239. }
  240. $aWizardSteps['optional'][] = $aCurrentStep;
  241. }
  242. return $aWizardSteps;
  243. }
  244. }
  245. ?>