]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SubPanel/SubPanelTiles.php
Release 6.5.13
[Github/sugarcrm.git] / include / SubPanel / SubPanelTiles.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38
39 require_once('include/SubPanel/SubPanel.php');
40 require_once('include/SubPanel/SubPanelTilesTabs.php');
41 require_once('include/SubPanel/SubPanelDefinitions.php');
42
43 /**
44  * Subpanel tiles
45  * @api
46  */
47 class SubPanelTiles
48 {
49         var $id;
50         var $module;
51         var $focus;
52         var $start_on_field;
53         var $layout_manager;
54         var $layout_def_key;
55         var $show_tabs = false;
56
57         var $subpanel_definitions;
58
59         var $hidden_tabs=array(); //consumer of this class can array of tabs that should be hidden. the tab name
60                                                         //should be the array.
61
62         function SubPanelTiles(&$focus, $layout_def_key='', $layout_def_override = '')
63         {
64                 $this->focus = $focus;
65                 $this->id = $focus->id;
66                 $this->module = $focus->module_dir;
67                 $this->layout_def_key = $layout_def_key;
68                 $this->subpanel_definitions=new SubPanelDefinitions($focus, $layout_def_key, $layout_def_override);
69         }
70
71         /*
72          * Return the current selected or requested subpanel tab
73          * @return      string  The identifier for the selected subpanel tab (e.g., 'Other')
74          */
75     function getSelectedGroup()
76     {
77         global $current_user;
78
79         if(isset($_REQUEST['subpanelTabs']))
80             $_SESSION['subpanelTabs'] = $_REQUEST['subpanelTabs'];
81
82         require_once 'include/tabConfig.php' ; // include/tabConfig.php in turn includes the customized file at custom/include/tabConfig.php...
83
84         $subpanelTabsPref = $current_user->getPreference('subpanel_tabs');
85         if(!isset($subpanelTabsPref)) $subpanelTabsPref = $GLOBALS['sugar_config']['default_subpanel_tabs'];
86         if(!empty($GLOBALS['tabStructure']) && (!empty($_SESSION['subpanelTabs']) || !empty($sugar_config['subpanelTabs']) || !empty($subpanelTabsPref)))
87         {
88             // Determine selected group
89             if(!empty($_REQUEST['subpanel']))
90             {
91                 $selected_group = $_REQUEST['subpanel'];
92             }
93             elseif(!empty($_COOKIE[$this->module.'_sp_tab']))
94             {
95                 $selected_group = $_COOKIE[$this->module.'_sp_tab'];
96             }
97             elseif(!empty($_SESSION['parentTab']) && !empty($GLOBALS['tabStructure'][$_SESSION['parentTab']]) && in_array($this->module, $GLOBALS['tabStructure'][$_SESSION['parentTab']]['modules']))
98             {
99                 $selected_group = $_SESSION['parentTab'];
100             }
101             else
102             {
103                 $selected_group = '';
104                 foreach($GLOBALS['tabStructure'] as $mainTab => $group)
105                 {
106                     if(in_array($this->module, $group['modules']))
107                     {
108                         $selected_group = $mainTab;
109                         break;
110                     }
111                 }
112                 if(!$selected_group)
113                 {
114                     $selected_group = 'All';
115                 }
116             }
117         }
118         else
119         {
120                 $selected_group = '';
121         }
122         return $selected_group;
123     }
124
125     /*
126      * Determine which subpanels should be shown within the selected tab group (e.g., 'Other');
127      * @param boolean $showTabs         True if we should call the code to render each visible tab
128      * @param string $selectedGroup     The requested tab group
129      * @return array Visible tabs
130      */
131     function getTabs($showTabs = true, $selectedGroup='')
132     {
133         global $current_user;
134
135         //get all the "tabs" - this actually means all the subpanels available for display within a tab
136         $tabs = $this->subpanel_definitions->get_available_tabs();
137
138         if(!empty($selectedGroup))
139         {
140             // Bug #44344 : Custom relationships under same module only show once in subpanel tabs
141             // use object property instead new object to have ability run unit test (can override subpanel_definitions)
142             $objSubPanelTilesTabs = new SubPanelTilesTabs($this->focus);
143             $tabs = $objSubPanelTilesTabs->getTabs($tabs, $showTabs, $selectedGroup);
144             unset($objSubPanelTilesTabs);
145             return $tabs;
146             }
147         else
148         {
149             // see if user current user has custom subpanel layout
150             $tabs = SubPanelTilesTabs::applyUserCustomLayoutToTabs($tabs);
151
152             /* Check if the preference is set now,
153              * because there's no point in executing this code if
154              * we aren't going to render anything.
155              */
156             $subpanelLinksPref = $current_user->getPreference('subpanel_links');
157             if(!isset($subpanelLinksPref)) $subpanelLinksPref = $GLOBALS['sugar_config']['default_subpanel_links'];
158
159             if($showTabs && $subpanelLinksPref){
160                require_once('include/SubPanel/SugarTab.php');
161                $sugarTab = new SugarTab();
162
163                $displayTabs = array();
164
165                foreach($tabs as $tab){
166                    $displayTabs []= array('key'=>$tab, 'label'=>translate($this->subpanel_definitions->layout_defs['subpanel_setup'][$tab]['title_key']));
167                    //echo '<td nowrap="nowrap"><a class="subTabLink" href="#' . $tab . '">' .  translate($this->subpanel_definitions->layout_defs['subpanel_setup'][$tab]['title_key']) .  '</a></td><td> | </td>';
168                }
169                $sugarTab->setup(array(),array(),$displayTabs);
170                $sugarTab->display();
171             }
172             //echo '<td width="100%">&nbsp;</td></tr></table>';
173         }
174             return $tabs;
175
176         }
177         function display($showContainer = true, $forceTabless = false)
178         {
179                 global $layout_edit_mode, $sugar_version, $sugar_config, $current_user, $app_strings;
180                 if(isset($layout_edit_mode) && $layout_edit_mode){
181                         return;
182                 }
183
184                 global $modListHeader;
185
186                 ob_start();
187     echo '<script type="text/javascript" src="'. getJSPath('include/SubPanel/SubPanelTiles.js') . '"></script>';
188 ?>
189 <script>
190 if(document.DetailView != null &&
191    document.DetailView.elements != null &&
192    document.DetailView.elements.layout_def_key != null &&
193    typeof document.DetailView.elements['layout_def_key'] != 'undefined'){
194     document.DetailView.elements['layout_def_key'].value = '<?php echo $this->layout_def_key; ?>';
195 }
196 </script>
197 <?php
198
199                 $tabs = array();
200                 $default_div_display = 'inline';
201                 if(!empty($sugar_config['hide_subpanels_on_login'])){
202                         if(!isset($_SESSION['visited_details'][$this->focus->module_dir])){
203                                 setcookie($this->focus->module_dir . '_divs', '');
204                                 unset($_COOKIE[$this->focus->module_dir . '_divs']);
205                                 $_SESSION['visited_details'][$this->focus->module_dir] = true;
206
207                         }
208                         $default_div_display = 'none';
209                 }
210                 $div_cookies = get_sub_cookies($this->focus->module_dir . '_divs');
211
212
213                 //Display the group header. this section is executed only if the tabbed interface is being used.
214                 $current_key = '';
215                 if (! empty($this->show_tabs))
216                 {
217                         require_once('include/tabs.php');
218                 $tab_panel = new SugarWidgetTabs($tabs, $current_key, 'showSubPanel');
219                         echo get_form_header('Related', '', false);
220                         echo "<br />" . $tab_panel->display();
221                 }
222
223         if(empty($_REQUEST['subpanels']))
224         {
225             $selected_group = $forceTabless?'':$this->getSelectedGroup();
226             $usersLayout = $current_user->getPreference('subpanelLayout', $this->focus->module_dir);
227
228             // we need to use some intelligence here when restoring the user's layout, as new modules with new subpanels might have been installed since the user's layout was recorded
229             // this means that we can't just restore the old layout verbatim as the new subpanels would then go walkabout
230             // so we need to do a merge while attempting as best we can to preserve the sense of the specified order
231             // this is complicated by the different ordering schemes used in the two sources for the panels: the user's layout uses an ordinal layout, the panels from getTabs have an explicit ordering driven by the 'order' parameter
232             // it's not clear how to best reconcile these two schemes; so we punt on it, and add all new panels to the end of the user's layout. At least this will give them a clue that something has changed...
233             // we also now check for tabs that have been removed since the user saved his or her preferences.
234
235             $tabs = $this->getTabs($showContainer, $selected_group) ;
236
237             if(!empty($usersLayout))
238             {
239                 $availableTabs = $tabs ;
240                 $tabs = array_intersect ( $usersLayout , $availableTabs ) ; // remove any tabs that have been removed since the user's layout was saved
241                 foreach (array_diff ( $availableTabs , $usersLayout ) as $tab)
242                     $tabs [] = $tab ;
243             }
244         }
245         else
246         {
247                 $tabs = explode(',', $_REQUEST['subpanels']);
248         }
249
250         $tab_names = array();
251
252         if($showContainer)
253         {
254             echo '<ul class="noBullet" id="subpanel_list">';
255         }
256         //echo "<li id='hidden_0' style='height: 5px' class='noBullet'>&nbsp;&nbsp;&nbsp;</li>";
257         if (empty($GLOBALS['relationships'])) {
258                 if (!class_exists('Relationship')) {
259                         require('modules/Relationships/Relationship.php');
260                 }
261                 $rel= new Relationship();
262                 $rel->load_relationship_meta();
263         }
264
265         // this array will store names of sub-panels that can contain items
266         // of each module
267         $module_sub_panels = array();
268
269         foreach ($tabs as $tab)
270                 {
271                         //load meta definition of the sub-panel.
272                         $thisPanel=$this->subpanel_definitions->load_subpanel($tab);
273             if ($thisPanel === false)
274                 continue;
275                         //this if-block will try to skip over ophaned subpanels. Studio/MB are being delete unloaded modules completely.
276                         //this check will ignore subpanels that are collections (activities, history, etc)
277                         if (!isset($thisPanel->_instance_properties['collection_list']) and isset($thisPanel->_instance_properties['get_subpanel_data']) ) {
278                                 //ignore when data source is a function
279
280                                 if (!isset($this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']])) {
281                                         if (stripos($thisPanel->_instance_properties['get_subpanel_data'],'function:') === false) {
282                                                 $GLOBALS['log']->fatal("Bad subpanel definition, it has incorrect value for get_subpanel_data property " .$tab);
283                                                 continue;
284                                         }
285                                 } else {
286                                         $rel_name='';
287                                         if (isset($this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']]['relationship'])) {
288                                                 $rel_name=$this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']]['relationship'];
289                                         }
290
291                                         if (empty($rel_name) or !isset($GLOBALS['relationships'][$rel_name])) {
292                                                 $GLOBALS['log']->fatal("Missing relationship definition " .$rel_name. ". skipping " .$tab ." subpanel");
293                                                 continue;
294                                         }
295                                 }
296                         }
297
298             if ($thisPanel->isCollection()) {
299                 // collect names of sub-panels that may contain items of each module
300                 $collection_list = $thisPanel->get_inst_prop_value('collection_list');
301                 if (is_array($collection_list)) {
302                     foreach ($collection_list as $data) {
303                         if (!empty($data['module'])) {
304                             $module_sub_panels[$data['module']][$tab] = true;
305                         }
306                     }
307                 }
308             } else {
309                 $module = $thisPanel->get_module_name();
310                 if (!empty($module)) {
311                     $module_sub_panels[$module][$tab] = true;
312                 }
313             }
314
315                         echo '<li class="noBullet" id="whole_subpanel_' . $tab . '">';
316
317                         $display= 'none';
318                         $div_display = $default_div_display;
319                         $cookie_name =   $tab . '_v';
320
321                         if (isset($thisPanel->_instance_properties['collapsed']) && $thisPanel->_instance_properties['collapsed'])
322                         {
323                                 $div_display = 'none';
324                         }
325                                 
326                         if(isset($div_cookies[$cookie_name])){
327                                 //If defaultSubPanelExpandCollapse is set, ignore the cookie that remembers whether the panel is expanded or collapsed.
328                                 //To be used with the above 'collapsed' metadata setting so they will always be set the same when the page is loaded.
329                                 if(!isset($sugar_config['defaultSubPanelExpandCollapse']) || $sugar_config['defaultSubPanelExpandCollapse'] == false)
330                                         $div_display =  $div_cookies[$cookie_name];
331                         }
332                         if(!empty($sugar_config['hide_subpanels'])){
333                                 $div_display = 'none';
334                         }
335             if($thisPanel->isDefaultHidden()) {
336                 $div_display = 'none';
337             }
338                         if($div_display == 'none'){
339                                 $opp_display  = 'inline';
340                         }else{
341                                 $opp_display  = 'none';
342                         }
343
344             if (!empty($this->layout_def_key) ) {
345                 $layout_def_key = $this->layout_def_key;
346             } else {
347                 $layout_def_key = '';
348             }
349
350                         if (empty($this->show_tabs))
351                         {
352                                 $show_icon_html = SugarThemeRegistry::current()->getImage( 'advanced_search', 'border="0" align="absmiddle"',null,null,'.gif',translate('LBL_SHOW'));
353                                 $hide_icon_html = SugarThemeRegistry::current()->getImage( 'basic_search', 'border="0" align="absmiddle"',null,null,'.gif',translate('LBL_HIDE'));
354
355                                 $max_min = "<a name=\"$tab\"> </a><span id=\"show_link_".$tab."\" style=\"display: $opp_display\"><a href='#' class='utilsLink' onclick=\"current_child_field = '".$tab."';showSubPanel('".$tab."',null,null,'".$layout_def_key."');document.getElementById('show_link_".$tab."').style.display='none';document.getElementById('hide_link_".$tab."').style.display='';return false;\">"
356                                         . "" . $show_icon_html . "</a></span>";
357                                 $max_min .= "<span id=\"hide_link_".$tab."\" style=\"display: $div_display\"><a href='#' class='utilsLink' onclick=\"hideSubPanel('".$tab."');document.getElementById('hide_link_".$tab."').style.display='none';document.getElementById('show_link_".$tab."').style.display='';return false;\">"
358                                  . "" . $hide_icon_html . "</a></span>";
359                                 echo '<div id="subpanel_title_' . $tab . '"';
360                 if(empty($sugar_config['lock_subpanels']) || $sugar_config['lock_subpanels'] == false) echo ' onmouseover="this.style.cursor = \'move\';"';
361                 echo '>' . get_form_header( $thisPanel->get_title(), $max_min, false) . '</div>';
362                         }
363
364             echo <<<EOQ
365 <div cookie_name="$cookie_name" id="subpanel_$tab" style="display:$div_display">
366     <script>document.getElementById("subpanel_$tab" ).cookie_name="$cookie_name";</script>
367 EOQ;
368             $display_spd = '';
369             if($div_display != 'none'){
370                 echo "<script>SUGAR.util.doWhen(\"typeof(markSubPanelLoaded) != 'undefined'\", function() {markSubPanelLoaded('$tab');});</script>";
371                 $old_contents = ob_get_contents();
372                 @ob_end_clean();
373
374                 ob_start();
375                 include_once('include/SubPanel/SubPanel.php');
376                 $subpanel_object = new SubPanel($this->module, $_REQUEST['record'], $tab,$thisPanel,$layout_def_key);
377                 $subpanel_object->setTemplateFile('include/SubPanel/SubPanelDynamic.html');
378                 $subpanel_object->display();
379                 $subpanel_data = ob_get_contents();
380                 @ob_end_clean();
381
382                 ob_start();
383                 echo $this->get_buttons($thisPanel,$subpanel_object->subpanel_query);
384                 $buttons = ob_get_contents();
385                 @ob_end_clean();
386
387                 ob_start();
388                 echo $old_contents;
389                 //echo $buttons;
390                 $display_spd = $subpanel_data;
391             }
392             echo <<<EOQ
393     <div id="list_subpanel_$tab">$display_spd</div>
394 </div>
395 EOQ;
396                 array_push($tab_names, $tab);
397                 echo '</li>';
398         } // end $tabs foreach
399         if($showContainer)
400         {
401                 echo '</ul>';
402
403
404             if(!empty($selected_group))
405             {
406                 // closing table from tpls/singletabmenu.tpl
407                 echo '</td></tr></table>';
408             }
409         }
410         // drag/drop code
411         $tab_names = '["' . join($tab_names, '","') . '"]';
412         global $sugar_config;
413
414         if(empty($sugar_config['lock_subpanels']) || $sugar_config['lock_subpanels'] == false) {
415             echo <<<EOQ
416     <script>
417         var SubpanelInit = function() {
418                 SubpanelInitTabNames({$tab_names});
419         }
420         var SubpanelInitTabNames = function(tabNames) {
421                 subpanel_dd = new Array();
422                 j = 0;
423                 for(i in tabNames) {
424                         subpanel_dd[j] = new ygDDList('whole_subpanel_' + tabNames[i]);
425                         subpanel_dd[j].setHandleElId('subpanel_title_' + tabNames[i]);
426                         subpanel_dd[j].onMouseDown = SUGAR.subpanelUtils.onDrag;
427                         subpanel_dd[j].afterEndDrag = SUGAR.subpanelUtils.onDrop;
428                         j++;
429                 }
430
431                 YAHOO.util.DDM.mode = 1;
432         }
433         currentModule = '{$this->module}';
434         SUGAR.util.doWhen(
435             "typeof(SUGAR.subpanelUtils) == 'object' && typeof(SUGAR.subpanelUtils.onDrag) == 'function'" +
436                 " && document.getElementById('subpanel_list')",
437             SubpanelInit
438         );
439     </script>
440 EOQ;
441         }
442
443         $module_sub_panels = array_map('array_keys', $module_sub_panels);
444         $module_sub_panels = json_encode($module_sub_panels);
445         echo <<<EOQ
446 <script>
447 var ModuleSubPanels = $module_sub_panels;
448 </script>
449 EOQ;
450
451                 $ob_contents = ob_get_contents();
452                 ob_end_clean();
453                 return $ob_contents;
454         }
455
456
457         function getLayoutManager()
458         {
459                 require_once('include/generic/LayoutManager.php');
460                 if ( $this->layout_manager == null) {
461                 $this->layout_manager = new LayoutManager();
462                 }
463                 return $this->layout_manager;
464         }
465
466         function get_buttons($thisPanel,$panel_query=null)
467         {
468                 $subpanel_def = $thisPanel->get_buttons();
469         $layout_manager = $this->getLayoutManager();
470
471         //for action button at the top of each subpanel
472         // bug#51275: smarty widget to help provide the action menu functionality as it is currently sprinkled throughout the app with html
473         $buttons = array();
474         $widget_contents = '';
475                 foreach($subpanel_def as $widget_data)
476                 {
477
478                         $widget_data['action'] = $_REQUEST['action'];
479                         $widget_data['module'] =  $thisPanel->get_inst_prop_value('module');
480                         $widget_data['focus'] = $this->focus;
481                         $widget_data['subpanel_definition'] = $thisPanel;
482                         $widget_contents .= '<td class="buttons">' . "\n";
483
484                         if(empty($widget_data['widget_class']))
485                         {
486                                 $buttons[] = "widget_class not defined for top subpanel buttons";
487                         }
488                         else
489                         {
490                 $button = $layout_manager->widgetDisplay($widget_data);
491                 if ($button) {
492                     $buttons[] = $button;
493                 }
494                         }
495
496         }
497         require_once('include/Smarty/plugins/function.sugar_action_menu.php');
498         $widget_contents = smarty_function_sugar_action_menu(array(
499             'buttons' => $buttons,
500             'class' => 'clickMenu fancymenu',
501         ), $this->xTemplate);
502         return $widget_contents;
503         }
504 }
505 ?>