ui.autocompletewidget.class.inc.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <?php
  2. // Copyright (C) 2010 Combodo SARL
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; version 3 of the License.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. /**
  17. * Class UIAutoCompleteWidget
  18. * UI wdiget for displaying and editing external keys when
  19. * A simple drop-down list is not enough...
  20. *
  21. * The layout is the following
  22. *
  23. * +-- #label_<id> (input)-------+ +-----------+
  24. * | | | Browse... |
  25. * +-----------------------------+ +-----------+
  26. *
  27. * And the popup dialog has the following layout:
  28. *
  29. * +------------------- ac_dlg_<id> (div)-----------+
  30. * + +--- ds_<id> (div)---------------------------+ |
  31. * | | +------------- fs_<id> (form)------------+ | |
  32. * | | | +--------+---+ | | |
  33. * | | | | Class | V | | | |
  34. * | | | +--------+---+ | | |
  35. * | | | | | |
  36. * | | | S e a r c h F o r m | | |
  37. * | | | +--------+ | | |
  38. * | | | | Search | | | |
  39. * | | | +--------+ | | |
  40. * | | +----------------------------------------+ | |
  41. * | +--------------+-dh_<id>-+--------------------+ |
  42. * | \ Search / |
  43. * | +------+ |
  44. * | +--- fr_<id> (form)--------------------------+ |
  45. * | | +------------ dr_<id> (div)--------------+ | |
  46. * | | | | | |
  47. * | | | S e a r c h R e s u l t s | | |
  48. * | | | | | |
  49. * | | +----------------------------------------+ | |
  50. * | | +--------+ +-----+ | |
  51. * | | | Cancel | | Add | | |
  52. * | | +--------+ +-----+ | |
  53. * | +--------------------------------------------+ |
  54. * +------------------------------------------------+
  55. * @author Erwan Taloc <erwan.taloc@combodo.com>
  56. * @author Romain Quetiez <romain.quetiez@combodo.com>
  57. * @author Denis Flaven <denis.flaven@combodo.com>
  58. * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
  59. */
  60. require_once('../application/webpage.class.inc.php');
  61. require_once('../application/displayblock.class.inc.php');
  62. class UIAutoCompleteWidget
  63. {
  64. protected static $iWidgetIndex = 0;
  65. protected $sAttCode;
  66. protected $sNameSuffix;
  67. protected $iId;
  68. protected $sTitle;
  69. public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
  70. {
  71. self::$iWidgetIndex++;
  72. $this->sAttCode = $sAttCode;
  73. $this->sClass = $sClass;
  74. $this->oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
  75. $this->sNameSuffix = $sNameSuffix;
  76. $this->iId = $iInputId;
  77. $this->aAllowedValues = $aAllowedValues;
  78. $this->value = $value;
  79. $this->sFieldPrefix = $sFieldPrefix;
  80. $this->sTargetClass = $this->oAttDef->GetTargetClass();
  81. $this->sTitle = $sTitle;
  82. $this->sFormPrefix = $sFormPrefix;
  83. }
  84. /**
  85. * Get the HTML fragment corresponding to the linkset editing widget
  86. * @param WebPage $oP The web page used for all the output
  87. * @param Hash $aArgs Extra context arguments
  88. * @return string The HTML fragment to be inserted into the page
  89. */
  90. public function Display(WebPage $oPage, $aArgs = array())
  91. {
  92. if ($this->oAttDef->IsNull($this->value)) // Null values are displayed as ''
  93. {
  94. $sDisplayValue = '';
  95. }
  96. else
  97. {
  98. $sDisplayValue = $this->GetObjectName($this->value);
  99. }
  100. $bCreate = UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY);
  101. $sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
  102. $sFormPrefix = $this->sFormPrefix;
  103. $oPage->add_ready_script(
  104. <<<EOF
  105. oACWidget_{$this->iId} = new AutocompleteWidget('$this->iId', '$this->sClass', '$this->sAttCode', '$this->sNameSuffix', oWizardHelper$sFormPrefix);
  106. oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
  107. EOF
  108. );
  109. $iMinChars = $this->oAttDef->GetMinAutoCompleteChars();
  110. // the input for the auto-complete
  111. $sHTMLValue = "<input count=\"".count($this->aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/>&nbsp;";
  112. $sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.Search();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_search.gif\" /></a>&nbsp;";
  113. if ($bCreate)
  114. {
  115. $sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.CreateObject();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_add.gif\" /></a>&nbsp;";
  116. }
  117. $sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
  118. // another hidden input to store & pass the object's Id
  119. $sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"attr_{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" value=\"$this->value\" />\n";
  120. // Scripts to start the autocomplete and bind some events to it
  121. $oPage->add_ready_script("\$('#label_$this->iId').autocomplete('./ajax.render.php', { scroll:true, minChars:{$iMinChars}, formatItem:formatItem, autoFill:false, matchContains:true, keyHolder:'#{$this->iId}', extraParams:{operation:'autocomplete', sclass:'$this->sClass',attCode:'".$this->sAttCode."'}});");
  122. $oPage->add_ready_script("\$('#label_$this->iId').blur(function() { $(this).search(); } );");
  123. $oPage->add_ready_script("\$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('$this->iId', event, data, formatted); } );");
  124. $oPage->add_ready_script("\$('#ac_dlg_$this->iId').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$this->sTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });\n");
  125. $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$this->sTitle'});\n");
  126. $oPage->add_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form
  127. if ($bCreate)
  128. {
  129. $oPage->add_at_the_end($this->GetCreationDialog($oPage)); // To prevent adding forms inside the main form
  130. }
  131. return $sHTMLValue;
  132. }
  133. protected function GetSearchDialog(WebPage $oPage)
  134. {
  135. $sHTML = '<div id="ac_dlg_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
  136. $oFilter = new DBObjectSearch($this->sTargetClass);
  137. $oSet = new CMDBObjectSet($oFilter);
  138. $oBlock = new DisplayBlock($oFilter, 'search', false);
  139. $sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $this->iId));
  140. $sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
  141. $sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
  142. $sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
  143. $sHTML .= "</div>\n";
  144. $sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\">&nbsp;&nbsp;";
  145. $sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
  146. $sHTML .= "</div>\n";
  147. $sHTML .= "</form>\n";
  148. $sHTML .= '</div></div></div>';
  149. $oPage->add_ready_script("$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);");
  150. $oPage->add_ready_script("$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);");
  151. return $sHTML;
  152. }
  153. protected function GetCreationDialog(WebPage $oPage)
  154. {
  155. $sHTML = '<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">';
  156. //$sHTML .= "<form id=\"fcr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoCreate();\">\n";
  157. //cmdbAbstractObject::DisplayCreationForm($oPage, 'Person', null, array());
  158. //$sHTML .= "<input type=\"button\" id=\"btn_create_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_create_{$this->iId}').dialog('close');\">&nbsp;&nbsp;";
  159. //$sHTML .= "<input type=\"button\" id=\"btn_create_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:New')."\" onClick=\"oACWidget_{$this->iId}.DoCreate();\">";
  160. //$sHTML .= "</form>\n";
  161. $sHTML .= '</div></div></div>';
  162. //$oPage->add_ready_script("$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);");
  163. return $sHTML;
  164. }
  165. /**
  166. * Search for objects to be selected
  167. * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
  168. * @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
  169. * @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
  170. */
  171. public function SearchObjectsToSelect(WebPage $oP, $sTargetClass = '')
  172. {
  173. if ($sTargetClass != '')
  174. {
  175. // assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
  176. $oFilter = new DBObjectSearch($sTargetClass);
  177. }
  178. else
  179. {
  180. // No remote class specified use the one defined in the linkedset
  181. $oFilter = new DBObjectSearch($this->sTargetClass);
  182. }
  183. $oFilter->AddCondition('id', array_keys($this->aAllowedValues), 'IN');
  184. $oSet = new CMDBObjectSet($oFilter);
  185. $oBlock = new DisplayBlock($oFilter, 'list', false);
  186. $oBlock->Display($oP, $this->iId, array('menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'display_limit' => false)); // Don't display the 'Actions' menu on the results
  187. }
  188. /**
  189. * Get the display name of the selected object, to fill back the autocomplete
  190. */
  191. public function GetObjectName($iObjId)
  192. {
  193. $oObj = MetaModel::GetObject($this->sTargetClass, $iObjId);
  194. return $oObj->GetName();
  195. }
  196. /**
  197. * Get the form to create a new object of the 'target' class
  198. */
  199. public function GetObjectCreationForm(WebPage $oPage)
  200. {
  201. $oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
  202. cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, null, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
  203. $oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");
  204. $oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);");
  205. }
  206. /**
  207. * Get the form to create a new object of the 'target' class
  208. */
  209. public function DoCreateObject($oPage)
  210. {
  211. $oObj = MetaModel::NewObject($this->sTargetClass);
  212. $oObj->UpdateObject($this->sFormPrefix.$this->iId);
  213. $oMyChange = MetaModel::NewObject("CMDBChange");
  214. $oMyChange->Set("date", time());
  215. if (UserRights::IsImpersonated())
  216. {
  217. $sUserString = Dict::Format('UI:Archive_User_OnBehalfOf_User', UserRights::GetRealUser(), UserRights::GetUser());
  218. }
  219. else
  220. {
  221. $sUserString = UserRights::GetUser();
  222. }
  223. $oMyChange->Set("userinfo", $sUserString);
  224. $iChangeId = $oMyChange->DBInsert();
  225. $oObj->DBInsertTracked($oMyChange);
  226. return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
  227. //return array('name' => 'test', 'id' => '42');
  228. }
  229. }
  230. ?>