mirror of
https://github.com/salesagility/SuiteCRM.git
synced 2024-11-21 23:47:57 +00:00
481 lines
22 KiB
PHP
Executable File
481 lines
22 KiB
PHP
Executable File
<?php
|
|
if (!defined('sugarEntry') || !sugarEntry) {
|
|
die('Not A Valid Entry Point');
|
|
}
|
|
/**
|
|
*
|
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
|
*
|
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
|
* Free Software Foundation with the addition of the following permission added
|
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License along with
|
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA.
|
|
*
|
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of this program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU Affero General Public License version 3.
|
|
*
|
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
|
*/
|
|
|
|
require_once('include/SubPanel/SubPanel.php');
|
|
require_once('include/SubPanel/SubPanelTilesTabs.php');
|
|
require_once('include/SubPanel/SubPanelDefinitions.php');
|
|
|
|
/**
|
|
* Subpanel tiles
|
|
* @api
|
|
*/
|
|
#[\AllowDynamicProperties]
|
|
class SubPanelTiles
|
|
{
|
|
public $id;
|
|
public $module;
|
|
public $focus;
|
|
public $start_on_field;
|
|
public $layout_manager;
|
|
public $layout_def_key;
|
|
public $show_tabs = false;
|
|
|
|
/**
|
|
* @var \SuiteCRM\SubPanel\SubPanelRowCounter
|
|
*/
|
|
protected $rowCounter;
|
|
|
|
public $subpanel_definitions;
|
|
|
|
public $hidden_tabs=array(); //consumer of this class can array of tabs that should be hidden. the tab name
|
|
//should be the array.
|
|
|
|
public function __construct(&$focus, $layout_def_key='', $layout_def_override = '')
|
|
{
|
|
$this->focus = $focus;
|
|
$this->id = $focus->id;
|
|
$this->module = $focus->module_dir;
|
|
$this->layout_def_key = $layout_def_key;
|
|
$this->subpanel_definitions=new SubPanelDefinitions($focus, $layout_def_key, $layout_def_override);
|
|
$this->rowCounter = new \SuiteCRM\SubPanel\SubPanelRowCounter($focus);
|
|
}
|
|
|
|
/*
|
|
* Return the current selected or requested subpanel tab
|
|
* @return string The identifier for the selected subpanel tab (e.g., 'Other')
|
|
*/
|
|
public function getSelectedGroup()
|
|
{
|
|
global $current_user;
|
|
|
|
if (isset($_REQUEST['subpanelTabs'])) {
|
|
$_SESSION['subpanelTabs'] = $_REQUEST['subpanelTabs'];
|
|
}
|
|
|
|
// include/tabConfig.php in turn includes the customized file at custom/include/tabConfig.php
|
|
require 'include/tabConfig.php';
|
|
|
|
$subpanelTabsPref = $current_user->getPreference('subpanel_tabs');
|
|
if (!isset($subpanelTabsPref)) {
|
|
$subpanelTabsPref = $GLOBALS['sugar_config']['default_subpanel_tabs'];
|
|
}
|
|
if (!empty($GLOBALS['tabStructure']) && (!empty($_SESSION['subpanelTabs']) || !empty($sugar_config['subpanelTabs']) || !empty($subpanelTabsPref))) {
|
|
// Determine selected group
|
|
if (!empty($_REQUEST['subpanel'])) {
|
|
$selected_group = $_REQUEST['subpanel'];
|
|
} elseif (!empty($_COOKIE[$this->module.'_sp_tab'])) {
|
|
$selected_group = $_COOKIE[$this->module.'_sp_tab'];
|
|
} elseif (!empty($_SESSION['parentTab']) && !empty($GLOBALS['tabStructure'][$_SESSION['parentTab']]) && in_array($this->module, $GLOBALS['tabStructure'][$_SESSION['parentTab']]['modules'])) {
|
|
$selected_group = $_SESSION['parentTab'];
|
|
} else {
|
|
$selected_group = '';
|
|
foreach ($GLOBALS['tabStructure'] as $mainTab => $group) {
|
|
if (in_array($this->module, $group['modules'])) {
|
|
$selected_group = $mainTab;
|
|
break;
|
|
}
|
|
}
|
|
if (!$selected_group) {
|
|
$selected_group = 'All';
|
|
}
|
|
}
|
|
} else {
|
|
$selected_group = '';
|
|
}
|
|
return $selected_group;
|
|
}
|
|
|
|
/*
|
|
* Determine which subpanels should be shown within the selected tab group (e.g., 'Other');
|
|
* @param boolean $showTabs True if we should call the code to render each visible tab
|
|
* @param string $selectedGroup The requested tab group
|
|
* @return array Visible tabs
|
|
*/
|
|
public function getTabs($showTabs = true, $selectedGroup='')
|
|
{
|
|
global $current_user;
|
|
|
|
//get all the "tabs" - this actually means all the subpanels available for display within a tab
|
|
$tabs = $this->subpanel_definitions->get_available_tabs();
|
|
|
|
if (!empty($selectedGroup)) {
|
|
// Bug #44344 : Custom relationships under same module only show once in subpanel tabs
|
|
// use object property instead new object to have ability run unit test (can override subpanel_definitions)
|
|
$objSubPanelTilesTabs = new SubPanelTilesTabs($this->focus);
|
|
$tabs = $objSubPanelTilesTabs->getTabs($tabs, $showTabs, $selectedGroup);
|
|
unset($objSubPanelTilesTabs);
|
|
return $tabs;
|
|
} else {
|
|
// see if user current user has custom subpanel layout
|
|
$objSubPanelTilesTabs = new SubPanelTilesTabs($this->focus);
|
|
$tabs = $objSubPanelTilesTabs->applyUserCustomLayoutToTabs($tabs);
|
|
|
|
/* Check if the preference is set now,
|
|
* because there's no point in executing this code if
|
|
* we aren't going to render anything.
|
|
*/
|
|
$subpanelLinksPref = $current_user->getPreference('subpanel_links');
|
|
if (!isset($subpanelLinksPref)) {
|
|
$subpanelLinksPref = $GLOBALS['sugar_config']['default_subpanel_links'];
|
|
}
|
|
|
|
if ($showTabs && $subpanelLinksPref) {
|
|
require_once('include/SubPanel/SugarTab.php');
|
|
$sugarTab = new SugarTab();
|
|
|
|
$displayTabs = array();
|
|
|
|
foreach ($tabs as $tab) {
|
|
$displayTabs []= array('key'=>$tab, 'label'=>translate($this->subpanel_definitions->layout_defs['subpanel_setup'][$tab]['title_key']));
|
|
}
|
|
$sugarTab->setup(array(), array(), $displayTabs);
|
|
$sugarTab->display();
|
|
}
|
|
}
|
|
return $tabs;
|
|
}
|
|
public function display($showContainer = true, $forceTabless = false)
|
|
{
|
|
global $layout_edit_mode, $sugar_version, $sugar_config, $current_user, $app_strings, $modListHeader;
|
|
|
|
if (isset($layout_edit_mode) && $layout_edit_mode) {
|
|
return;
|
|
}
|
|
|
|
$template = new Sugar_Smarty();
|
|
$template_header = "";
|
|
$template_body = "";
|
|
$template_footer = "";
|
|
|
|
$tabs = array();
|
|
$tabs_properties = array();
|
|
$tab_names = array();
|
|
|
|
$module_sub_panels = [];
|
|
|
|
$default_div_display = 'inline';
|
|
if (!empty($sugar_config['hide_subpanels_on_login'])) {
|
|
if (!isset($_SESSION['visited_details'][$this->focus->module_dir])) {
|
|
SugarApplication::setCookie($this->focus->module_dir . '_divs', '', 0, null, null, isSSL(), true);
|
|
unset($_COOKIE[$this->focus->module_dir . '_divs']);
|
|
$_SESSION['visited_details'][$this->focus->module_dir] = true;
|
|
}
|
|
$default_div_display = 'none';
|
|
}
|
|
$div_cookies = get_sub_cookies($this->focus->module_dir . '_divs');
|
|
|
|
|
|
if (empty($_REQUEST['subpanels'])) {
|
|
$selected_group = $forceTabless?'':$this->getSelectedGroup();
|
|
$usersLayout = $current_user->getPreference('subpanelLayout', $this->focus->module_dir);
|
|
|
|
// 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
|
|
// this means that we can't just restore the old layout verbatim as the new subpanels would then go walkabout
|
|
// so we need to do a merge while attempting as best we can to preserve the sense of the specified order
|
|
// 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
|
|
// 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...
|
|
// we also now check for tabs that have been removed since the user saved their preferences.
|
|
|
|
$tabs = $this->getTabs($showContainer, $selected_group) ;
|
|
|
|
if (!empty($usersLayout)) {
|
|
$availableTabs = $tabs ;
|
|
$tabs = array_intersect($usersLayout, $availableTabs) ; // remove any tabs that have been removed since the user's layout was saved
|
|
foreach (array_diff($availableTabs, $usersLayout) as $tab) {
|
|
$tabs [] = $tab;
|
|
}
|
|
}
|
|
} else {
|
|
$tabs = explode(',', $_REQUEST['subpanels']);
|
|
}
|
|
|
|
// Display the group header. this section is executed only if the tabbed interface is being used.
|
|
$current_key = '';
|
|
if (! empty($this->show_tabs)) {
|
|
require_once('include/tabs.php');
|
|
$tab_panel = new SugarWidgetTabs($tabs, $current_key, 'showSubPanel');
|
|
$template_header .= get_form_header('Related', '', false);
|
|
$template_header .= $tab_panel->display();
|
|
}
|
|
|
|
if (empty($GLOBALS['relationships'])) {
|
|
if (!class_exists('Relationship')) {
|
|
require('modules/Relationships/Relationship.php');
|
|
}
|
|
$rel= BeanFactory::newBean('Relationships');
|
|
$rel->load_relationship_meta();
|
|
}
|
|
|
|
foreach ($tabs as $t => $tab) {
|
|
// load meta definition of the sub-panel.
|
|
$thisPanel = $this->subpanel_definitions->load_subpanel($tab);
|
|
if ($thisPanel === false) {
|
|
continue;
|
|
}
|
|
// this if-block will try to skip over ophaned subpanels. Studio/MB are being delete unloaded modules completely.
|
|
// this check will ignore subpanels that are collections (activities, history, etc)
|
|
if (!isset($thisPanel->_instance_properties['collection_list']) and isset($thisPanel->_instance_properties['get_subpanel_data'])) {
|
|
// ignore when data source is a function
|
|
|
|
if (!isset($this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']])) {
|
|
if (stripos($thisPanel->_instance_properties['get_subpanel_data'], 'function:') === false) {
|
|
$GLOBALS['log']->fatal("Bad subpanel definition, it has incorrect value for get_subpanel_data property " .$tab);
|
|
continue;
|
|
}
|
|
} else {
|
|
$rel_name='';
|
|
if (isset($this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']]['relationship'])) {
|
|
$rel_name=$this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']]['relationship'];
|
|
}
|
|
|
|
if (empty($rel_name) or !isset($GLOBALS['relationships'][$rel_name])) {
|
|
$GLOBALS['log']->fatal("Missing relationship definition " .$rel_name. ". skipping " .$tab ." subpanel");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($thisPanel->isCollection()) {
|
|
// collect names of sub-panels that may contain items of each module
|
|
$collection_list = $thisPanel->get_inst_prop_value('collection_list');
|
|
if (is_array($collection_list)) {
|
|
foreach ($collection_list as $data) {
|
|
if (!empty($data['module'])) {
|
|
$module_sub_panels[$data['module']][$tab] = true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
$module = $thisPanel->get_module_name();
|
|
if (!empty($module)) {
|
|
$module_sub_panels[$module][$tab] = true;
|
|
}
|
|
}
|
|
|
|
$div_display = $default_div_display;
|
|
|
|
if (isset($thisPanel->_instance_properties['collapsed'])
|
|
&& $thisPanel->_instance_properties['collapsed']) {
|
|
$div_display = 'none';
|
|
}
|
|
|
|
if (!empty($sugar_config['hide_subpanels']) || $thisPanel->isDefaultHidden()) {
|
|
$div_display = 'none';
|
|
}
|
|
|
|
$cookie_name = $this->module . '_' . $tab . '_v';
|
|
if (isset($div_cookies[$cookie_name])) {
|
|
$div_display = $div_cookies[$cookie_name] === 'false' ? 'none' : '';
|
|
}
|
|
|
|
if ($div_display == 'none') {
|
|
$opp_display = 'inline';
|
|
$tabs_properties[$t]['expanded_subpanels'] = false;
|
|
} else {
|
|
$opp_display = 'none';
|
|
$tabs_properties[$t]['expanded_subpanels'] = true;
|
|
}
|
|
|
|
if (!empty($this->layout_def_key)) {
|
|
$layout_def_key = $this->layout_def_key;
|
|
} else {
|
|
$layout_def_key = '';
|
|
}
|
|
|
|
if (empty($this->show_tabs)) {
|
|
///
|
|
/// Legacy Support for subpanels
|
|
$show_icon_html = SugarThemeRegistry::current()->getImage('advanced_search', 'border="0" align="absmiddle"', null, null, '.gif', translate('LBL_SHOW'));
|
|
$hide_icon_html = SugarThemeRegistry::current()->getImage('basic_search', 'border="0" align="absmiddle"', null, null, '.gif', translate('LBL_HIDE'));
|
|
|
|
$tabs_properties[$t]['show_icon_html'] = $show_icon_html;
|
|
$tabs_properties[$t]['hide_icon_html'] = $hide_icon_html;
|
|
|
|
$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,true,'".$layout_def_key."');document.getElementById('show_link_".$tab."').style.display='none';document.getElementById('hide_link_".$tab."').style.display='';return false;\">"
|
|
. "" . $show_icon_html . "</a></span>";
|
|
$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;\">"
|
|
. "" . $hide_icon_html . "</a></span>";
|
|
$tabs_properties[$t]['title'] = $thisPanel->get_title();
|
|
$tabs_properties[$t]['module_name'] = $thisPanel->get_module_name();
|
|
$tabs_properties[$t]['get_form_header'] = get_form_header($thisPanel->get_title(), $max_min, false, false);
|
|
}
|
|
|
|
$tabs_properties[$t]['cookie_name'] = $cookie_name;
|
|
$tabs_properties[$t]['div_display'] = $div_display;
|
|
$tabs_properties[$t]['opp_display'] = $opp_display;
|
|
|
|
$tabs_properties[$t]['subpanel_body'] = '';
|
|
$tabs_properties[$t]['buttons'] = '';
|
|
|
|
// We only preload this subpanel's contents if it's expanded
|
|
if ($tabs_properties[$t]['expanded_subpanels']) {
|
|
// Get Subpanel
|
|
include_once('include/SubPanel/SubPanel.php');
|
|
$subpanel_object = new SubPanel($this->module, $_REQUEST['record'], $tab, $thisPanel, $layout_def_key);
|
|
|
|
$arr = array();
|
|
// TODO: Remove x-template:
|
|
$tabs_properties[$t]['subpanel_body'] = $subpanel_object->ProcessSubPanelListView(
|
|
'include/SubPanel/tpls/SubPanelDynamic.tpl',
|
|
$arr
|
|
);
|
|
|
|
// Get subpanel buttons
|
|
$tabs_properties[$t]['buttons'] = $this->get_buttons($thisPanel, $subpanel_object->subpanel_query);
|
|
} elseif ($current_user->getPreference('count_collapsed_subpanels')) {
|
|
$subPanelDef = $this->subpanel_definitions->layout_defs['subpanel_setup'][$tab];
|
|
$count = (int)$this->rowCounter->getSubPanelRowCount($subPanelDef);
|
|
|
|
$extraClass = '';
|
|
if ($count === 0) {
|
|
$countStr = $count.'';
|
|
} elseif ($count > 0) {
|
|
$countStr = $count.'';
|
|
$tabs_properties[$t]['collapsed_override'] = 1;
|
|
} else {
|
|
$countStr = '...';
|
|
$extraClass = ' incomplete';
|
|
}
|
|
|
|
$tabs_properties[$t]['title'] .= ' (<span class="subPanelCountHint' . $extraClass . '" data-subpanel="' . $tab . '" data-module="' . $layout_def_key . '" data-record="' . $_REQUEST['record'] . '">' . $countStr . '</span>)';
|
|
}
|
|
|
|
|
|
array_push($tab_names, $tab);
|
|
}
|
|
|
|
$tab_names = '["' . implode('","', $tab_names) . '"]';
|
|
|
|
if (!isset($module_sub_panels)) {
|
|
$module_sub_panels = [];
|
|
}
|
|
$module_sub_panels = array_map('array_keys', $module_sub_panels);
|
|
$module_sub_panels = json_encode($module_sub_panels);
|
|
|
|
$template->assign('layout_def_key', $this->layout_def_key);
|
|
$template->assign('show_subpanel_tabs', $this->show_tabs);
|
|
$template->assign('subpanel_tabs', $tabs);
|
|
$template->assign('subpanel_tabs_properties', $tabs_properties);
|
|
$template->assign('module_sub_panels', $module_sub_panels);
|
|
$template->assign('sugar_config', $sugar_config);
|
|
$template->assign('REQUEST', $_REQUEST);
|
|
$template->assign('GLOBALS', $GLOBALS);
|
|
$template->assign('selected_group', $selected_group);
|
|
$template->assign('tab_names', $tab_names);
|
|
$template->assign('module_sub_panels', $module_sub_panels);
|
|
$template->assign('module', $this->module);
|
|
$template->assign('APP', $app_strings);
|
|
|
|
$template_body = $template->fetch('include/SubPanel/tpls/SubPanelTiles.tpl');
|
|
|
|
return $template_header . $template_body . $template_footer;
|
|
}
|
|
|
|
public function getLayoutManager()
|
|
{
|
|
require_once('include/generic/LayoutManager.php');
|
|
if ($this->layout_manager == null) {
|
|
$this->layout_manager = new LayoutManager();
|
|
}
|
|
return $this->layout_manager;
|
|
}
|
|
|
|
/**
|
|
* @param aSubPanel $thisPanel
|
|
* @param $panel_query
|
|
* @return string
|
|
*/
|
|
public function get_buttons($thisPanel, $panel_query=null)
|
|
{
|
|
$subpanel_def = $thisPanel->get_buttons();
|
|
$layout_manager = $this->getLayoutManager();
|
|
|
|
//for action button at the top of each subpanel
|
|
// bug#51275: smarty widget to help provide the action menu functionality as it is currently sprinkled throughout the app with html
|
|
$buttons = array();
|
|
$widget_contents = '';
|
|
foreach ($subpanel_def as $widget_data) {
|
|
$widget_data['action'] = $_REQUEST['action'];
|
|
$widget_data['module'] = $thisPanel->get_inst_prop_value('module');
|
|
$widget_data['focus'] = $this->focus;
|
|
$widget_data['subpanel_definition'] = $thisPanel;
|
|
$widget_contents .= '<td class="buttons">' . "\n";
|
|
|
|
if (empty($widget_data['widget_class'])) {
|
|
$buttons[] = "widget_class not defined for top subpanel buttons";
|
|
} else {
|
|
$button = $layout_manager->widgetDisplay($widget_data);
|
|
if ($button) {
|
|
$buttons[] = $button;
|
|
}
|
|
}
|
|
}
|
|
require_once('include/Smarty/plugins/function.sugar_action_menu.php');
|
|
$widget_contents = smarty_function_sugar_action_menu(
|
|
[
|
|
'buttons' => $buttons,
|
|
'class' => 'clickMenu fancymenu',
|
|
'flat' => $thisPanel->get_inst_prop_value('flat')
|
|
],
|
|
$this->xTemplate
|
|
);
|
|
return $widget_contents;
|
|
}
|
|
|
|
/**
|
|
* @param string $html_text
|
|
* @param aSubPanel $thisPanel
|
|
* @return string
|
|
*/
|
|
public function getCheckbox($html_text, $thisPanel)
|
|
{
|
|
$template = new Sugar_Smarty();
|
|
|
|
if ($thisPanel->get_inst_prop_value('select_link_top')) {
|
|
$html_text .= $template->fetch('include/SubPanel/tpls/SubPanelCheckbox.tpl');
|
|
}
|
|
|
|
return $html_text;
|
|
}
|
|
}
|