2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
44 * This array is meant to hold an objects/data that we would like to pass between
45 * the controller and the view. The bean will automatically be set for us, but this
46 * is meant to hold anything else.
48 var $view_object_map = array();
50 * The name of the current module.
54 * The name of the current action.
61 * Sugar_Smarty. This is useful if you have a view and a subview you can
62 * share the same smarty object.
66 * Any errors that occured this can either be set by the view or the controller or the model
68 var $errors = array();
70 * Set to true if you do not want to display errors from SugarView::displayErrors(); instead they will be returned
72 var $suppressDisplayErrors = false;
75 * Options for what UI elements to hide/show/
77 var $options = array('show_header' => true, 'show_title' => true, 'show_subpanels' => false, 'show_search' => true, 'show_footer' => true, 'show_javascript' => true, 'view_print' => false,);
83 * Constructor which will peform the setup.
85 public function SugarView(
87 $view_object_map = array()
94 $view_object_map = array()
98 $this->view_object_map = $view_object_map;
99 $this->action = $GLOBALS['action'];
100 $this->module = $GLOBALS['module'];
101 $this->_initSmarty();
104 protected function _initSmarty()
106 $this->ss = new Sugar_Smarty();
107 $this->ss->assign('MOD', $GLOBALS['mod_strings']);
108 $this->ss->assign('APP', $GLOBALS['app_strings']);
112 * This method will be called from the controller and is not meant to be overridden.
114 public function process()
116 LogicHook::initialize();
117 $this->_checkModule();
119 //trackView has to be here in order to track for breadcrumbs
122 //For the ajaxUI, we need to use output buffering to return the page in an ajax friendly format
123 if ($this->_getOption('json_output')){
125 if(!empty($_REQUEST['ajax_load']) && !empty($_REQUEST['loadLanguageJS'])) {
126 echo $this->_getModLanguageJS();
130 if ($this->_getOption('show_header')) {
131 $this->displayHeader();
133 $this->renderJavascript();
136 $this->_buildModuleList();
138 $this->displayErrors();
140 if ( !empty($this->module) ) {
141 $GLOBALS['logic_hook']->call_custom_logic($this->module, 'after_ui_frame');
143 $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_frame');
146 if ($this->_getOption('show_subpanels') && !empty($_REQUEST['record'])) $this->_displaySubPanels();
148 if ($this->action === 'Login') {
149 //this is needed for a faster loading login page ie won't render unless the tables are closed
152 if ($this->_getOption('show_footer')) $this->displayFooter();
153 $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_footer');
154 if ($this->_getOption('json_output'))
156 $content = ob_get_clean();
157 $module = $this->module;
159 'content' => mb_detect_encoding($content) == "UTF-8" ? $content : utf8_encode($content),
162 'label' => translate($module),
163 $this->getMenu($module),
165 'title' => $this->getBrowserTitle(),
166 'action' => isset($_REQUEST['action']) ? $_REQUEST['action'] : "",
167 'record' => isset($_REQUEST['record']) ? $_REQUEST['record'] : "",
168 'favicon' => $this->getFavicon(),
171 if(SugarThemeRegistry::current()->name == 'Classic')
172 $ajax_ret['moduleList'] = $this->displayHeader(true);
174 if(empty($this->responseTime))
175 $this->_calculateFooterMetrics();
176 $ajax_ret['responseTime'] = $this->responseTime;
177 $json = getJSONobj();
178 echo $json->encode($ajax_ret);
179 $GLOBALS['app']->headerDisplayed = false;
182 //Do not track if there is no module or if module is not a String
187 * This method will display the errors on the page.
189 public function displayErrors()
193 foreach($this->errors as $error) {
194 $errors .= '<span class="error">' . $error . '</span><br>';
197 if ( !$this->suppressDisplayErrors ) {
206 * [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is
207 * to allow a view to do some preprocessing before the display method is called. This becomes
208 * useful when you have a view defined at the application level and then within a module
209 * have a sub-view that extends from this application level view. The application level
210 * view can do the setup in preDisplay() that is common to itself and any subviews
211 * and then the subview can just override display(). If it so desires, can also override
214 public function preDisplay()
219 * [OVERRIDE] - This method is meant to overidden in a subclass. This method
220 * will handle the actual display logic of the view.
222 public function display()
230 protected function _trackView()
232 $action = strtolower($this->action);
233 //Skip save, tracked in SugarBean instead
234 if($action == 'save') {
239 $trackerManager = TrackerManager::getInstance();
240 $timeStamp = TimeDate::getInstance()->nowDb();
241 if($monitor = $trackerManager->getMonitor('tracker')){
242 $monitor->setValue('action', $action);
243 $monitor->setValue('user_id', $GLOBALS['current_user']->id);
244 $monitor->setValue('module_name', $this->module);
245 $monitor->setValue('date_modified', $timeStamp);
246 $monitor->setValue('visible', (($monitor->action == 'detailview') || ($monitor->action == 'editview')
249 if (!empty($this->bean->id)) {
250 $monitor->setValue('item_id', $this->bean->id);
251 $monitor->setValue('item_summary', $this->bean->get_summary_text());
254 //If visible is true, but there is no bean, do not track (invalid/unauthorized reference)
255 //Also, do not track save actions where there is no bean id
256 if($monitor->visible && empty($this->bean->id)) {
257 $trackerManager->unsetMonitor($monitor);
260 $trackerManager->saveMonitor($monitor, true, true);
266 * Displays the header on section of the page; basically everything before the content
268 public function displayHeader($retModTabs=false)
273 global $current_user;
274 global $sugar_config;
275 global $app_list_strings;
277 global $current_language;
279 $GLOBALS['app']->headerDisplayed = true;
281 $themeObject = SugarThemeRegistry::current();
282 $theme = $themeObject->__toString();
284 $ss = new Sugar_Smarty();
285 $ss->assign("APP", $app_strings);
286 $ss->assign("THEME", $theme);
287 $ss->assign("THEME_IE6COMPAT", $themeObject->ie6compat ? 'true':'false');
288 $ss->assign("MODULE_NAME", $this->module);
289 $ss->assign("langHeader", get_language_header());
291 // set ab testing if exists
292 $testing = (isset($_REQUEST["testing"]) ? $_REQUEST['testing'] : "a");
293 $ss->assign("ABTESTING", $testing);
296 $ss->assign("SYSTEM_NAME", $this->getBrowserTitle());
299 $css = $themeObject->getCSS();
300 if ($this->_getOption('view_print')) {
301 $css .= '<link rel="stylesheet" type="text/css" href="'.$themeObject->getCSSURL('print.css').'" media="all" />';
303 $ss->assign("SUGAR_CSS",$css);
307 $this->renderJavascript();
309 $ss->assign("SUGAR_JS",ob_get_contents().$themeObject->getJS());
313 if(isset($GLOBALS['sugar_config']['default_module_favicon']))
314 $module_favicon = $GLOBALS['sugar_config']['default_module_favicon'];
316 $module_favicon = false;
318 $favicon = $this->getFavicon();
319 $ss->assign('FAVICON_URL', $favicon['url']);
321 // build the shortcut menu
322 $shortcut_menu = array();
323 foreach ( $this->getMenu() as $key => $menu_item )
324 $shortcut_menu[$key] = array(
325 "URL" => $menu_item[0],
326 "LABEL" => $menu_item[1],
327 "MODULE_NAME" => $menu_item[2],
328 "IMAGE" => $themeObject
329 ->getImage($menu_item[2],"border='0' align='absmiddle'",null,null,'.gif',$menu_item[1]),
331 $ss->assign("SHORTCUT_MENU",$shortcut_menu);
333 // handle rtl text direction
334 if(isset($_REQUEST['RTL']) && $_REQUEST['RTL'] == 'RTL'){
335 $_SESSION['RTL'] = true;
337 if(isset($_REQUEST['LTR']) && $_REQUEST['LTR'] == 'LTR'){
338 unset($_SESSION['RTL']);
340 if(isset($_SESSION['RTL']) && $_SESSION['RTL']){
341 $ss->assign("DIR", 'dir="RTL"');
344 // handle resizing of the company logo correctly on the fly
345 $companyLogoURL = $themeObject->getImageURL('company_logo.png');
346 $companyLogoURL_arr = explode('?', $companyLogoURL);
347 $companyLogoURL = $companyLogoURL_arr[0];
349 $company_logo_attributes = sugar_cache_retrieve('company_logo_attributes');
350 if(!empty($company_logo_attributes)) {
351 $ss->assign("COMPANY_LOGO_MD5", $company_logo_attributes[0]);
352 $ss->assign("COMPANY_LOGO_WIDTH", $company_logo_attributes[1]);
353 $ss->assign("COMPANY_LOGO_HEIGHT", $company_logo_attributes[2]);
356 // Always need to md5 the file
357 $ss->assign("COMPANY_LOGO_MD5", md5_file($companyLogoURL));
359 list($width,$height) = getimagesize($companyLogoURL);
360 if ( $width > 212 || $height > 40 ) {
361 $resizePctWidth = ($width - 212)/212;
362 $resizePctHeight = ($height - 40)/40;
363 if ( $resizePctWidth > $resizePctHeight )
364 $resizeAmount = $width / 212;
366 $resizeAmount = $height / 40;
367 $ss->assign("COMPANY_LOGO_WIDTH", round($width * (1/$resizeAmount)));
368 $ss->assign("COMPANY_LOGO_HEIGHT", round($height * (1/$resizeAmount)));
371 $ss->assign("COMPANY_LOGO_WIDTH", $width);
372 $ss->assign("COMPANY_LOGO_HEIGHT", $height);
375 // Let's cache the results
376 sugar_cache_put('company_logo_attributes',
378 $ss->get_template_vars("COMPANY_LOGO_MD5"),
379 $ss->get_template_vars("COMPANY_LOGO_WIDTH"),
380 $ss->get_template_vars("COMPANY_LOGO_HEIGHT")
384 $ss->assign("COMPANY_LOGO_URL",getJSPath($companyLogoURL)."&logo_md5=".$ss->get_template_vars("COMPANY_LOGO_MD5"));
386 // get the global links
388 $global_control_links = array();
389 require("include/globalControlLinks.php");
391 foreach($global_control_links as $key => $value) {
392 if ($key == 'users') { //represents logout link.
393 $ss->assign("LOGOUT_LINK", $value['linkinfo'][key($value['linkinfo'])]);
394 $ss->assign("LOGOUT_LABEL", key($value['linkinfo']));//key value for first element.
398 foreach ($value as $linkattribute => $attributevalue) {
399 // get the main link info
400 if ( $linkattribute == 'linkinfo' ) {
402 "LABEL" => key($attributevalue),
403 "URL" => current($attributevalue),
404 "SUBMENU" => array(),
406 if(substr($gcls[$key]["URL"], 0, 11) == "javascript:") {
407 $gcls[$key]["ONCLICK"] = substr($gcls[$key]["URL"],11);
408 $gcls[$key]["URL"] = "javascript:void(0)";
411 // and now the sublinks
412 if ( $linkattribute == 'submenu' && is_array($attributevalue) ) {
413 foreach ($attributevalue as $submenulinkkey => $submenulinkinfo)
414 $gcls[$key]['SUBMENU'][$submenulinkkey] = array(
415 "LABEL" => key($submenulinkinfo),
416 "URL" => current($submenulinkinfo),
418 if(substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"], 0, 11) == "javascript:") {
419 $gcls[$key]['SUBMENU'][$submenulinkkey]["ONCLICK"] = substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"],11);
420 $gcls[$key]['SUBMENU'][$submenulinkkey]["URL"] = "javascript:void(0)";
425 $ss->assign("GCLS",$gcls);
427 $ss->assign("SEARCH", isset($_REQUEST['query_string']) ? $_REQUEST['query_string'] : '');
429 if ($this->action == "EditView" || $this->action == "Login")
430 $ss->assign("ONLOAD", 'onload="set_focus()"');
432 $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
434 // get other things needed for page style popup
435 if (isset($_SESSION["authenticated_user_id"])) {
436 // get the current user name and id
437 $ss->assign("CURRENT_USER", $current_user->full_name == '' || !showFullName()
438 ? $current_user->user_name : $current_user->full_name );
439 $ss->assign("CURRENT_USER_ID", $current_user->id);
441 // get the last viewed records
442 $tracker = new Tracker();
443 $history = $tracker->get_recently_viewed($current_user->id);
444 foreach ( $history as $key => $row ) {
445 $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']);
446 $history[$key]['image'] = SugarThemeRegistry::current()
447 ->getImage($row['module_name'],'border="0" align="absmiddle"',null,null,'.gif',$row['item_summary']);
449 $ss->assign("recentRecords",$history);
452 $bakModStrings = $mod_strings;
453 if (isset($_SESSION["authenticated_user_id"]) ) {
454 // get the module list
455 $moduleTopMenu = array();
457 $max_tabs = $current_user->getPreference('max_tabs');
458 // Attempt to correct if max tabs count is extremely high.
459 if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10 ) {
460 $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
461 $current_user->setPreference('max_tabs', $max_tabs, 0, 'global');
464 $moduleTab = $this->_getModuleTab();
465 $ss->assign('MODULE_TAB',$moduleTab);
468 // See if they are using grouped tabs or not (removed in 6.0, returned in 6.1)
469 $user_navigation_paradigm = $current_user->getPreference('navigation_paradigm');
470 if ( !isset($user_navigation_paradigm) ) {
471 $user_navigation_paradigm = $GLOBALS['sugar_config']['default_navigation_paradigm'];
475 // Get the full module list for later use
476 foreach ( query_module_access_list($current_user) as $module ) {
477 // Bug 25948 - Check for the module being in the moduleList
478 if ( isset($app_list_strings['moduleList'][$module]) ) {
479 $fullModuleList[$module] = $app_list_strings['moduleList'][$module];
484 if(!should_hide_iframes()) {
485 $iFrame = new iFrame();
486 $frames = $iFrame->lookup_frames('tab');
487 foreach($frames as $key => $values){
488 $fullModuleList[$key] = $values;
491 elseif (isset($fullModuleList['iFrames'])) {
492 unset($fullModuleList['iFrames']);
495 if ( $user_navigation_paradigm == 'gm' && isset($themeObject->group_tabs) && $themeObject->group_tabs) {
496 // We are using grouped tabs
497 require_once('include/GroupedTabs/GroupedTabStructure.php');
498 $groupedTabsClass = new GroupedTabStructure();
499 $modules = query_module_access_list($current_user);
500 //handle with submoremodules
501 $max_tabs = $current_user->getPreference('max_tabs');
502 // If the max_tabs isn't set incorrectly, set it within the range, to the default max sub tabs size
503 if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10){
504 // We have a default value. Use it
505 if(isset($GLOBALS['sugar_config']['default_max_tabs'])){
506 $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
513 $subMoreModules = false;
514 $groupTabs = $groupedTabsClass->get_tab_structure(get_val_array($modules));
515 // We need to put this here, so the "All" group is valid for the user's preference.
516 $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
519 // Setup the default group tab.
520 $allGroup = $app_strings['LBL_TABGROUP_ALL'];
521 $ss->assign('currentGroupTab',$allGroup);
522 $currentGroupTab = $allGroup;
523 $usersGroup = $current_user->getPreference('theme_current_group');
524 // Figure out which tab they currently have selected (stored as a user preference)
525 if ( !empty($usersGroup) && isset($groupTabs[$usersGroup]) ) {
526 $currentGroupTab = $usersGroup;
528 $current_user->setPreference('theme_current_group',$currentGroupTab);
531 $ss->assign('currentGroupTab',$currentGroupTab);
532 $usingGroupTabs = true;
535 // Setup the default group tab.
536 $ss->assign('currentGroupTab',$app_strings['LBL_TABGROUP_ALL']);
538 $usingGroupTabs = false;
540 $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
545 $topTabList = array();
547 // Now time to go through each of the tab sets and fix them up.
548 foreach ( $groupTabs as $tabIdx => $tabData ) {
549 $topTabs = $tabData['modules'];
550 if ( ! is_array($topTabs) ) {
553 $extraTabs = array();
555 // Split it in to the tabs that go across the top, and the ones that are on the extra menu.
556 if ( count($topTabs) > $max_tabs ) {
557 $extraTabs = array_splice($topTabs,$max_tabs);
559 // Make sure the current module is accessable through one of the top tabs
560 if ( !isset($topTabs[$moduleTab]) ) {
561 // Nope, we need to add it.
562 // First, take it out of the extra menu, if it's there
563 if ( isset($extraTabs[$moduleTab]) ) {
564 unset($extraTabs[$moduleTab]);
566 if ( count($topTabs) >= $max_tabs - 1 ) {
567 // We already have the maximum number of tabs, so we need to shuffle the last one
568 // from the top to the first one of the extras
569 $lastElem = array_splice($topTabs,$max_tabs-1);
570 $extraTabs = $lastElem + $extraTabs;
572 if ( !empty($moduleTab) ) {
573 $topTabs[$moduleTab] = $app_list_strings['moduleList'][$moduleTab];
579 // This was removed, but I like the idea, so I left the code in here in case we decide to turn it back on
580 // If we are using group tabs, add all the "hidden" tabs to the end of the extra menu
581 if ( $usingGroupTabs ) {
582 foreach($fullModuleList as $moduleKey => $module ) {
583 if ( !isset($topTabs[$moduleKey]) && !isset($extraTabs[$moduleKey]) ) {
584 $extraTabs[$moduleKey] = $module;
590 // Get a unique list of the top tabs so we can build the popup menus for them
591 foreach ( $topTabs as $moduleKey => $module ) {
592 $topTabList[$moduleKey] = $module;
595 $groupTabs[$tabIdx]['modules'] = $topTabs;
596 $groupTabs[$tabIdx]['extra'] = $extraTabs;
600 if ( isset($topTabList) && is_array($topTabList) ) {
601 // Adding shortcuts array to menu array for displaying shortcuts associated with each module
602 $shortcutTopMenu = array();
603 foreach($topTabList as $module_key => $label) {
605 $mod_strings = return_module_language($current_language, $module_key);
606 foreach ( $this->getMenu($module_key) as $key => $menu_item ) {
607 $shortcutTopMenu[$module_key][$key] = array(
608 "URL" => $menu_item[0],
609 "LABEL" => $menu_item[1],
610 "MODULE_NAME" => $menu_item[2],
611 "IMAGE" => $themeObject
612 ->getImage($menu_item[2],"border='0' align='absmiddle'",null,null,'.gif',$menu_item[1]),
613 "ID" => $menu_item[2]."_link",
617 $ss->assign("groupTabs",$groupTabs);
618 $ss->assign("shortcutTopMenu",$shortcutTopMenu);
619 $ss->assign('USE_GROUP_TABS',$usingGroupTabs);
621 // This is here for backwards compatibility, someday, somewhere, it will be able to be removed
622 $ss->assign("moduleTopMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules']);
623 $ss->assign("moduleExtraMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['extra']);
628 if ( isset($extraTabs) && is_array($extraTabs) ) {
629 // Adding shortcuts array to extra menu array for displaying shortcuts associated with each module
630 $shortcutExtraMenu = array();
631 foreach($extraTabs as $module_key => $label) {
633 $mod_strings = return_module_language($current_language, $module_key);
634 foreach ( $this->getMenu($module_key) as $key => $menu_item ) {
635 $shortcutExtraMenu[$module_key][$key] = array(
636 "URL" => $menu_item[0],
637 "LABEL" => $menu_item[1],
638 "MODULE_NAME" => $menu_item[2],
639 "IMAGE" => $themeObject
640 ->getImage($menu_item[2],"border='0' align='absmiddle'",null,null,'.gif',$menu_item[1]),
641 "ID" => $menu_item[2]."_link",
645 $ss->assign("shortcutExtraMenu",$shortcutExtraMenu);
648 if(!empty($current_user)){
649 $ss->assign("max_tabs", $current_user->getPreference("max_tabs"));
653 $imageURL = SugarThemeRegistry::current()->getImageURL("dashboard.png");
654 $homeImage = "<img src='$imageURL'>";
655 $ss->assign("homeImage",$homeImage);
657 $mod_strings = $bakModStrings;
658 $headerTpl = $themeObject->getTemplate('header.tpl');
659 if (inDeveloperMode() )
660 $ss->clear_compiled_tpl($headerTpl);
664 return $ss->fetch($themeObject->getTemplate('_headerModuleList.tpl'));
666 $ss->display($headerTpl);
668 $this->includeClassicFile('modules/Administration/DisplayWarnings.php');
670 $errorMessages = SugarApplication::getErrorMessages();
671 if ( !empty($errorMessages)) {
672 foreach ( $errorMessages as $error_message ) {
673 echo('<p class="error">' . $error_message.'</p>');
680 function getModuleMenuHTML()
686 * If the view is classic then this method will include the file and
687 * setup any global variables.
689 * @param string $file
691 public function includeClassicFile(
695 global $sugar_config, $theme, $current_user, $sugar_version, $sugar_flavor, $mod_strings, $app_strings, $app_list_strings, $action;
696 global $gridline, $request_string, $modListHeader, $dashletData, $authController, $locale, $currentModule, $import_bean_map, $image_path, $license;
697 global $user_unique_key, $server_unique_key, $barChartColors, $modules_exempt_from_availability_check, $dictionary, $current_language, $beanList, $beanFiles, $sugar_build, $sugar_codename;
698 global $timedate, $login_error; // cn: bug 13855 - timedate not available to classic views.
699 if (!empty($this->module))
700 $currentModule = $this->module;
701 require_once ($file);
704 protected function _displayLoginJS()
706 global $sugar_config, $timedate;
708 if(isset($this->bean->module_dir)){
709 echo "<script>var module_sugar_grp1 = '{$this->bean->module_dir}';</script>";
711 if(isset($_REQUEST['action'])){
712 echo "<script>var action_sugar_grp1 = '{$_REQUEST['action']}';</script>";
714 echo '<script>jscal_today = 1000*' . $timedate->asUserTs($timedate->getNow()) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
715 if (!is_file(sugar_cached("include/javascript/sugar_grp1.js"))) {
716 $_REQUEST['root_directory'] = ".";
717 require_once("jssource/minify_utils.php");
718 ConcatenateFiles(".");
720 echo getVersionedScript('cache/include/javascript/sugar_grp1_jquery.js');
721 echo getVersionedScript('cache/include/javascript/sugar_grp1_yui.js');
722 echo getVersionedScript('cache/include/javascript/sugar_grp1.js');
723 echo getVersionedScript('include/javascript/calendar.js');
726 if ( typeof(SUGAR) == 'undefined' ) {SUGAR = {}};
727 if ( typeof(SUGAR.themes) == 'undefined' ) SUGAR.themes = {};
730 if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
731 echo getVersionedScript('modules/Sync/headersync.js');
735 * Get JS validation code for views
737 public static function getJavascriptValidation()
740 $cal_date_format = $timedate->get_cal_date_format();
741 $timereg = $timedate->get_regular_expression($timedate->get_time_format());
742 $datereg = $timedate->get_regular_expression($timedate->get_date_format());
744 foreach ($datereg['positions'] as $type => $pos) {
745 if (empty($date_pos)) {
746 $date_pos .= "'$type': $pos";
748 $date_pos .= ",'$type': $pos";
752 $time_separator = $timedate->timeSeparator();
753 $hour_offset = $timedate->getUserUTCOffset() * 60;
755 // Add in the number formatting styles here as well, we have been handling this with individual modules.
756 require_once ('modules/Currencies/Currency.php');
757 list ($num_grp_sep, $dec_sep) = get_number_seperators();
759 $the_script = "<script type=\"text/javascript\">\n" . "\tvar time_reg_format = '" .
760 $timereg['format'] . "';\n" . "\tvar date_reg_format = '" .
761 $datereg['format'] . "';\n" . "\tvar date_reg_positions = { $date_pos };\n" .
762 "\tvar time_separator = '$time_separator';\n" .
763 "\tvar cal_date_format = '$cal_date_format';\n" .
764 "\tvar time_offset = $hour_offset;\n" . "\tvar num_grp_sep = '$num_grp_sep';\n" .
765 "\tvar dec_sep = '$dec_sep';\n" . "</script>";
771 * Called from process(). This method will display the correct javascript.
773 protected function _displayJavascript()
775 global $locale, $sugar_config, $timedate;
778 if ($this->_getOption('show_javascript')) {
779 if (!$this->_getOption('show_header')) {
780 $langHeader = get_language_header();
783 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
790 "sugar_cache_dir" => "cache/",
793 if(isset($this->bean->module_dir)){
794 $js_vars['module_sugar_grp1'] = $this->bean->module_dir;
796 if(isset($_REQUEST['action'])){
797 $js_vars['action_sugar_grp1'] = $_REQUEST['action'];
799 echo '<script>jscal_today = 1000*' . $timedate->asUserTs($timedate->getNow()) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
800 if (!is_file(sugar_cached("include/javascript/sugar_grp1.js")) || !is_file(sugar_cached("include/javascript/sugar_grp1_yui.js")) || !is_file(sugar_cached("include/javascript/sugar_grp1_jquery.js"))) {
801 $_REQUEST['root_directory'] = ".";
802 require_once("jssource/minify_utils.php");
803 ConcatenateFiles(".");
805 echo getVersionedScript('cache/include/javascript/sugar_grp1_jquery.js');
806 echo getVersionedScript('cache/include/javascript/sugar_grp1_yui.js');
807 echo getVersionedScript('cache/include/javascript/sugar_grp1.js');
808 echo getVersionedScript('include/javascript/calendar.js');
810 // output necessary config js in the top of the page
811 $config_js = $this->getSugarConfigJS();
812 if(!empty($config_js)){
813 echo "<script>\n".implode("\n", $config_js)."</script>\n";
816 if ( isset($sugar_config['email_sugarclient_listviewmaxselect']) ) {
817 echo "<script>SUGAR.config.email_sugarclient_listviewmaxselect = {$GLOBALS['sugar_config']['email_sugarclient_listviewmaxselect']};</script>";
820 $image_server = (defined('TEMPLATE_URL'))?TEMPLATE_URL . '/':'';
821 echo '<script type="text/javascript">SUGAR.themes.image_server="' . $image_server . '";</script>'; // cn: bug 12274 - create session-stored key to defend against CSRF
822 echo '<script type="text/javascript">var name_format = "' . $locale->getLocaleFormatMacro() . '";</script>';
823 echo self::getJavascriptValidation();
824 if (!is_file(sugar_cached('jsLanguage/') . $GLOBALS['current_language'] . '.js')) {
825 require_once ('include/language/jsLanguage.php');
826 jsLanguage::createAppStringsCache($GLOBALS['current_language']);
828 echo getVersionedScript('cache/jsLanguage/'. $GLOBALS['current_language'] . '.js', $GLOBALS['sugar_config']['js_lang_version']);
830 echo $this->_getModLanguageJS();
832 if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
833 echo getVersionedScript('modules/Sync/headersync.js');
836 //echo out the $js_vars variables as javascript variables
837 echo "<script type='text/javascript'>\n";
838 foreach($js_vars as $var=>$value)
840 echo "var {$var} = '{$value}';\n";
846 protected function _getModLanguageJS(){
847 if (!is_file(sugar_cached('jsLanguage/') . $this->module . '/' . $GLOBALS['current_language'] . '.js')) {
848 require_once ('include/language/jsLanguage.php');
849 jsLanguage::createModuleStringsCache($this->module, $GLOBALS['current_language']);
851 return getVersionedScript("cache/jsLanguage/{$this->module}/". $GLOBALS['current_language'] . '.js', $GLOBALS['sugar_config']['js_lang_version']);
855 * Called from process(). This method will display the footer on the page.
857 public function displayFooter()
859 if (empty($this->responseTime)) {
860 $this->_calculateFooterMetrics();
862 global $sugar_config;
865 $themeObject = SugarThemeRegistry::current();
866 //decide whether or not to show themepicker, default is to show
867 $showThemePicker = true;
868 if (isset($sugar_config['showThemePicker'])) {
869 $showThemePicker = $sugar_config['showThemePicker'];
872 echo "<!-- crmprint -->";
873 $jsalerts = new jsAlerts();
874 if ( !isset($_SESSION['isMobile']) )
875 echo $jsalerts->getScript();
877 $ss = new Sugar_Smarty();
878 $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
879 $ss->assign('MOD',return_module_language($GLOBALS['current_language'], 'Users'));
881 $bottomLinkList = array();
882 if (isset($this->action) && $this->action != "EditView") {
883 $bottomLinkList['print'] = array($app_strings['LNK_PRINT'] => getPrintLink());
885 $bottomLinkList['backtotop'] = array($app_strings['LNK_BACKTOTOP'] => 'javascript:SUGAR.util.top();');
887 $bottomLinksStr = "";
888 foreach($bottomLinkList as $key => $value) {
889 foreach($value as $text => $link) {
891 if(substr($link, 0, 11) == "javascript:") {
892 $onclick = " onclick=\"".substr($link,11)."\"";
893 $href = "javascript:void(0)";
897 $imageURL = SugarThemeRegistry::current()->getImageURL($key.'.gif');
898 $bottomLinksStr .= "<a href=\"{$href}\"";
899 $bottomLinksStr .= (isset($onclick)) ? $onclick : "";
900 $bottomLinksStr .= "><img src='{$imageURL}' alt=''>"; //keeping alt blank on purpose for 508 (text will be read instead)
901 $bottomLinksStr .= " ".$text."</a>";
904 $ss->assign("BOTTOMLINKS",$bottomLinksStr);
905 if (SugarConfig::getInstance()->get('calculate_response_time', false))
906 $ss->assign('STATISTICS',$this->_getStatistics());
908 // Under the License referenced above, you are required to leave in all copyright statements in both
909 // the code and end-user application.
912 $copyright = '© 2004-2012 SugarCRM Inc. The Program is provided AS IS, without warranty. Licensed under <a href="LICENSE.txt" target="_blank" class="copyRightLink">AGPLv3</a>.<br>This program is free software; you can redistribute it and/or modify it under the terms of the <br><a href="LICENSE.txt" target="_blank" class="copyRightLink"> GNU Affero General Public License version 3</a> as published by the Free Software Foundation, including the additional permission set forth in the source code header.<br>';
924 // The interactive user interfaces in modified source and object code
925 // versions of this program must display Appropriate Legal Notices, as
926 // required under Section 5 of the GNU General Public License version
927 // 3. In accordance with Section 7(b) of the GNU General Public License
928 // version 3, these Appropriate Legal Notices must retain the display
929 // of the "Powered by SugarCRM" logo. If the display of the logo is
930 // not reasonably feasible for technical reasons, the Appropriate
931 // Legal Notices must display the words "Powered by SugarCRM".
932 $attribLinkImg = "<img style='margin-top: 2px' border='0' width='120' height='34' src='include/images/poweredby_sugarcrm_65.png' alt='Powered By SugarCRM'>\n";
935 // handle resizing of the company logo correctly on the fly
936 $companyLogoURL = $themeObject->getImageURL('company_logo.png');
937 $companyLogoURL_arr = explode('?', $companyLogoURL);
938 $companyLogoURL = $companyLogoURL_arr[0];
940 $company_logo_attributes = sugar_cache_retrieve('company_logo_attributes');
941 if(!empty($company_logo_attributes)) {
942 $ss->assign("COMPANY_LOGO_MD5", $company_logo_attributes[0]);
943 $ss->assign("COMPANY_LOGO_WIDTH", $company_logo_attributes[1]);
944 $ss->assign("COMPANY_LOGO_HEIGHT", $company_logo_attributes[2]);
947 // Always need to md5 the file
948 $ss->assign("COMPANY_LOGO_MD5", md5_file($companyLogoURL));
950 list($width,$height) = getimagesize($companyLogoURL);
951 if ( $width > 212 || $height > 40 ) {
952 $resizePctWidth = ($width - 212)/212;
953 $resizePctHeight = ($height - 40)/40;
954 if ( $resizePctWidth > $resizePctHeight )
955 $resizeAmount = $width / 212;
957 $resizeAmount = $height / 40;
958 $ss->assign("COMPANY_LOGO_WIDTH", round($width * (1/$resizeAmount)));
959 $ss->assign("COMPANY_LOGO_HEIGHT", round($height * (1/$resizeAmount)));
962 $ss->assign("COMPANY_LOGO_WIDTH", $width);
963 $ss->assign("COMPANY_LOGO_HEIGHT", $height);
966 // Let's cache the results
967 sugar_cache_put('company_logo_attributes',
969 $ss->get_template_vars("COMPANY_LOGO_MD5"),
970 $ss->get_template_vars("COMPANY_LOGO_WIDTH"),
971 $ss->get_template_vars("COMPANY_LOGO_HEIGHT")
975 $ss->assign("COMPANY_LOGO_URL",getJSPath($companyLogoURL)."&logo_md5=".$ss->get_template_vars("COMPANY_LOGO_MD5"));
977 // Bug 38594 - Add in Trademark wording
978 $copyright .= 'SugarCRM is a trademark of SugarCRM, Inc. All other company and product names may be trademarks of the respective companies with which they are associated.<br />';
980 //rrs bug: 20923 - if this image does not exist as per the license, then the proper image will be displayed regardless, so no need
981 //to display an empty image here.
982 if(file_exists('include/images/poweredby_sugarcrm_65.png')){
983 $copyright .= $attribLinkImg;
985 // End Required Image
986 $ss->assign('COPYRIGHT',$copyright);
989 $ss->display(SugarThemeRegistry::current()->getTemplate('footer.tpl'));
993 * Called from process(). This method will display subpanels.
995 protected function _displaySubPanels()
997 if (isset($this->bean) && !empty($this->bean->id) && (file_exists('modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/Ext/Layoutdefs/layoutdefs.ext.php'))) {
998 $GLOBALS['focus'] = $this->bean;
999 require_once ('include/SubPanel/SubPanelTiles.php');
1000 $subpanel = new SubPanelTiles($this->bean, $this->module);
1001 echo $subpanel->display();
1005 protected function _buildModuleList()
1007 if (!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader']))
1008 $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
1012 * private method used in process() to determine the value of a passed in option
1014 * @param string option - the option that we want to know the valye of
1015 * @param bool default - what the default value should be if we do not find the option
1017 * @return bool - the value of the option
1019 protected function _getOption(
1024 if (!empty($this->options) && isset($this->options['show_all'])) {
1025 return $this->options['show_all'];
1026 } elseif (!empty($this->options) && isset($this->options[$option])) {
1027 return $this->options[$option];
1028 } else return $default;
1033 * Private function to track information about the view request
1035 private function _track()
1037 if (empty($this->responseTime)) {
1038 $this->_calculateFooterMetrics();
1040 if (empty($GLOBALS['current_user']->id)) {
1045 $trackerManager = TrackerManager::getInstance();
1046 $trackerManager->save();
1051 * Checks to see if the module name passed is valid; dies if it is not
1053 protected function _checkModule()
1055 if(!empty($this->module) && !file_exists('modules/'.$this->module)){
1056 $error = str_replace("[module]", "$this->module", $GLOBALS['app_strings']['ERR_CANNOT_FIND_MODULE']);
1057 $GLOBALS['log']->fatal($error);
1063 public function renderJavascript()
1065 if ($this->action !== 'Login')
1066 $this->_displayJavascript();
1068 $this->_displayLoginJS();
1071 private function _calculateFooterMetrics()
1073 $endTime = microtime(true);
1074 $deltaTime = $endTime - $GLOBALS['startTime'];
1075 $this->responseTime = number_format(round($deltaTime, 2), 2);
1076 // Print out the resources used in constructing the page.
1077 $this->fileResources = count(get_included_files());
1080 private function _getStatistics()
1082 $endTime = microtime(true);
1083 $deltaTime = $endTime - $GLOBALS['startTime'];
1084 $response_time_string = $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME'] . ' ' . number_format(round($deltaTime, 2), 2) . ' ' . $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME_SECONDS'];
1085 $return = $response_time_string;
1086 // $return .= '<br />';
1087 if (!empty($GLOBALS['sugar_config']['show_page_resources'])) {
1088 // Print out the resources used in constructing the page.
1089 $included_files = get_included_files();
1091 // take all of the included files and make a list that does not allow for duplicates based on case
1092 // I believe the full get_include_files result set appears to have one entry for each file in real
1093 // case, and one entry in all lower case.
1094 $list_of_files_case_insensitive = array();
1095 foreach($included_files as $key => $name) {
1096 // preserve the first capitalization encountered.
1097 $list_of_files_case_insensitive[mb_strtolower($name) ] = $name;
1099 $return .= $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_RESOURCES'] . '(' . DBManager::getQueryCount() . ',' . sizeof($list_of_files_case_insensitive) . ')<br>';
1100 // Display performance of the internal and external caches....
1101 $cacheStats = SugarCache::instance()->getCacheStats();
1102 $return .= "External cache (hits/total=ratio) local ({$cacheStats['localHits']}/{$cacheStats['requests']}=" . round($cacheStats['localHits']*100/$cacheStats['requests'], 0) . "%)";
1103 $return .= " external ({$cacheStats['externalHits']}/{$cacheStats['requests']}=" . round($cacheStats['externalHits']*100/$cacheStats['requests'], 0) . "%)<br />";
1104 $return .= " misses ({$cacheStats['misses']}/{$cacheStats['requests']}=" . round($cacheStats['misses']*100/$cacheStats['requests'], 0) . "%)<br />";
1107 $return .= $this->logMemoryStatistics();
1113 * logMemoryStatistics
1115 * This function returns a string message containing the memory statistics as well as writes to the memory_usage.log
1116 * file the memory statistics for the SugarView invocation.
1118 * @param $newline String of newline character to use (defaults to </ br>)
1119 * @return $message String formatted message about memory statistics
1121 protected function logMemoryStatistics($newline='<br>')
1125 if(!empty($GLOBALS['sugar_config']['log_memory_usage']))
1127 if(function_exists('memory_get_usage'))
1129 $memory_usage = memory_get_usage();
1130 $bytes = $GLOBALS['app_strings']['LBL_SERVER_MEMORY_BYTES'];
1131 $data = array($memory_usage, $bytes);
1132 $log_message = string_format($GLOBALS['app_strings']['LBL_SERVER_MEMORY_USAGE'], $data) . $newline;
1135 if(function_exists('memory_get_peak_usage'))
1137 $memory_peak_usage = memory_get_peak_usage();
1138 $bytes = $GLOBALS['app_strings']['LBL_SERVER_MEMORY_BYTES'];
1139 $data = array($memory_peak_usage, $bytes);
1140 $log_message .= string_format($GLOBALS['app_strings']['LBL_SERVER_PEAK_MEMORY_USAGE'], $data) . $newline;
1143 if(!empty($log_message))
1147 !empty($this->module) ? $this->module : $GLOBALS['app_strings']['LBL_LINK_NONE'],
1148 !empty($this->action) ? $this->action : $GLOBALS['app_strings']['LBL_LINK_NONE'],
1151 $output = string_format($GLOBALS['app_strings']['LBL_SERVER_MEMORY_LOG_MESSAGE'], $data) . $newline;
1152 $output .= $log_message;
1153 $fp = fopen("memory_usage.log", "ab");
1154 fwrite($fp, $output);
1159 return $log_message;
1164 * Loads the module shortcuts menu
1166 * @param $module string optional, can specify module to retrieve menu for if not the current one
1167 * @return array module menu
1169 public function getMenu(
1173 global $current_language, $current_user, $mod_strings, $app_strings, $module_menu;
1175 if ( empty($module) )
1176 $module = $this->module;
1178 //Need to make sure the mod_strings match the requested module or Menus may fail
1179 $curr_mod_strings = $mod_strings;
1180 $mod_strings = return_module_language ( $current_language, $module ) ;
1182 $module_menu = array();
1184 if (file_exists('modules/' . $module . '/Menu.php')) {
1185 require('modules/' . $module . '/Menu.php');
1187 if (file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php')) {
1188 require('custom/modules/' . $module . '/Ext/Menus/menu.ext.php');
1190 if (!file_exists('modules/' . $module . '/Menu.php')
1191 && !file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php')
1192 && !empty($GLOBALS['mod_strings']['LNK_NEW_RECORD'])) {
1193 $module_menu[] = array("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView",
1194 $GLOBALS['mod_strings']['LNK_NEW_RECORD'],"{$GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']}$module" ,$module );
1195 $module_menu[] = array("index.php?module=$module&action=index", $GLOBALS['mod_strings']['LNK_LIST'],
1197 if ( ($this->bean instanceOf SugarBean) && !empty($this->bean->importable) )
1198 if ( !empty($mod_strings['LNK_IMPORT_'.strtoupper($module)]) )
1199 $module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index",
1200 $mod_strings['LNK_IMPORT_'.strtoupper($module)], "Import", $module);
1202 $module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index",
1203 $app_strings['LBL_IMPORT'], "Import", $module);
1205 if (file_exists('custom/application/Ext/Menus/menu.ext.php')) {
1206 require('custom/application/Ext/Menus/menu.ext.php');
1209 $mod_strings = $curr_mod_strings;
1210 $builtModuleMenu = $module_menu;
1211 unset($module_menu);
1213 return $builtModuleMenu;
1217 * Returns the module name which should be highlighted in the module menu
1219 protected function _getModuleTab()
1221 global $app_list_strings, $moduleTabMap, $current_user;
1223 $userTabs = query_module_access_list($current_user);
1224 //If the home tab is in the user array use it as the default tab, otherwise use the first element in the tab array
1225 $defaultTab = (in_array("Home",$userTabs)) ? "Home" : key($userTabs);
1227 // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions.
1228 if ( !empty($_REQUEST['module_tab']) )
1229 return $_REQUEST['module_tab'];
1230 elseif ( isset($moduleTabMap[$this->module]) )
1231 return $moduleTabMap[$this->module];
1233 elseif ( $this->module == 'MergeRecords' )
1234 return !empty($_REQUEST['merge_module']) ? $_REQUEST['merge_module'] : $_REQUEST['return_module'];
1235 elseif ( $this->module == 'Users' && $this->action == 'SetTimezone' )
1237 // Default anonymous pages to be under Home
1238 elseif ( !isset($app_list_strings['moduleList'][$this->module]) )
1240 elseif ( isset($_REQUEST['action']) && $_REQUEST['action'] == "ajaxui" )
1243 return $this->module;
1247 * Return the "breadcrumbs" to display at the top of the page
1249 * @param bool $show_help optional, true if we show the help links
1250 * @return HTML string containing breadcrumb title
1252 public function getModuleTitle(
1256 global $sugar_version, $sugar_flavor, $server_unique_key, $current_language, $action;
1258 $theTitle = "<div class='moduleTitle'>\n";
1260 $module = preg_replace("/ /","",$this->module);
1262 $params = $this->_getModuleTitleParams();
1265 if(SugarThemeRegistry::current()->directionality == "rtl") {
1266 $params = array_reverse($params);
1268 if(count($params) > 1) {
1269 array_shift($params);
1271 $count = count($params);
1273 foreach($params as $parm){
1275 $paramString .= $parm;
1276 if($index < $count){
1277 $paramString .= $this->getBreadCrumbSymbol();
1281 if(!empty($paramString)){
1282 $theTitle .= "<h2> $paramString </h2>\n";
1284 $theTitle .= "<span class='utils'>";
1285 $createImageURL = SugarThemeRegistry::current()->getImageURL('create-record.gif');
1286 $url = ajaxLink("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView");
1287 $theTitle .= <<<EOHTML
1289 <a id="create_image" href="{$url}" class="utilsLink">
1290 <img src='{$createImageURL}' alt='{$GLOBALS['app_strings']['LNK_CREATE']}'></a>
1291 <a id="create_link" href="{$url}" class="utilsLink">
1292 {$GLOBALS['app_strings']['LNK_CREATE']}
1296 $theTitle .= "</span><div class='clear'></div></div>\n";
1301 * Return the metadata file that will be used by this view.
1303 * @return string File location of the metadata file.
1305 public function getMetaDataFile()
1307 $metadataFile = null;
1308 $foundViewDefs = false;
1309 $viewDef = strtolower($this->type) . 'viewdefs';
1310 $coreMetaPath = 'modules/'.$this->module.'/metadata/' . $viewDef . '.php';
1311 if(file_exists('custom/' .$coreMetaPath )){
1312 $metadataFile = 'custom/' . $coreMetaPath;
1313 $foundViewDefs = true;
1315 if(file_exists('custom/modules/'.$this->module.'/metadata/metafiles.php')){
1316 require_once('custom/modules/'.$this->module.'/metadata/metafiles.php');
1317 if(!empty($metafiles[$this->module][$viewDef])){
1318 $metadataFile = $metafiles[$this->module][$viewDef];
1319 $foundViewDefs = true;
1321 }elseif(file_exists('modules/'.$this->module.'/metadata/metafiles.php')){
1322 require_once('modules/'.$this->module.'/metadata/metafiles.php');
1323 if(!empty($metafiles[$this->module][$viewDef])){
1324 $metadataFile = $metafiles[$this->module][$viewDef];
1325 $foundViewDefs = true;
1330 if(!$foundViewDefs && file_exists($coreMetaPath)){
1331 $metadataFile = $coreMetaPath;
1333 $GLOBALS['log']->debug("metadatafile=". $metadataFile);
1335 return $metadataFile;
1340 * Returns an array composing of the breadcrumbs to use for the module title
1342 * @param bool $browserTitle true if the returned string is being used for the browser title, meaning
1343 * there should be no HTML in the string
1346 protected function _getModuleTitleParams($browserTitle = false)
1348 $params = array($this->_getModuleTitleListParam($browserTitle));
1349 //$params = array();
1350 if (isset($this->action)){
1351 switch ($this->action) {
1353 if(!empty($this->bean->id)) {
1354 $params[] = $this->bean->get_summary_text();
1355 //$params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL'];
1358 $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL'];
1361 $beanName = $this->bean->get_summary_text();
1362 $params[] = $beanName;
1371 * Returns the portion of the array that will represent the listview in the breadcrumb
1373 * @param bool $browserTitle true if the returned string is being used for the browser title, meaning
1374 * there should be no HTML in the string
1377 protected function _getModuleTitleListParam( $browserTitle = false )
1379 global $current_user;
1380 global $app_strings;
1382 if(!empty($GLOBALS['app_list_strings']['moduleList'][$this->module]))
1383 $firstParam = $GLOBALS['app_list_strings']['moduleList'][$this->module];
1385 $firstParam = $this->module;
1387 $iconPath = $this->getModuleTitleIconPath($this->module);
1388 if($this->action == "ListView" || $this->action == "index") {
1389 if (!empty($iconPath) && !$browserTitle) {
1390 if (SugarThemeRegistry::current()->directionality == "ltr") {
1391 return $app_strings['LBL_SEARCH']." "
1395 return "$firstParam"
1396 . " ".$app_strings['LBL_SEARCH'];
1403 if (!empty($iconPath) && !$browserTitle) {
1404 //return "<a href='index.php?module={$this->module}&action=index'>$this->module</a>";
1411 protected function getModuleTitleIconPath($module)
1414 if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) {
1415 $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png');
1417 else if (is_file(SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png',false))) {
1418 $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png');
1424 * Returns the string which will be shown in the browser's title; defaults to using the same breadcrumb
1425 * as in the module title
1429 public function getBrowserTitle()
1431 global $app_strings;
1433 $browserTitle = $app_strings['LBL_BROWSER_TITLE'];
1434 if ( $this->module == 'Users' && ($this->action == 'SetTimezone' || $this->action == 'Login') )
1435 return $browserTitle;
1436 $params = $this->_getModuleTitleParams(true);
1437 foreach ($params as $value )
1438 $browserTitle = strip_tags($value) . ' » ' . $browserTitle;
1440 return $browserTitle;
1444 * Returns the correct breadcrumb symbol according to theme's directionality setting
1448 public function getBreadCrumbSymbol()
1450 if(SugarThemeRegistry::current()->directionality == "ltr") {
1451 return "<span class='pointer'>»</span>";
1454 return "<span class='pointer'>«</span>";
1459 * Fetch config values to be put into an array for JavaScript
1463 protected function getSugarConfigJS(){
1464 global $sugar_config;
1466 // Set all the config parameters in the JS config as necessary
1467 $config_js = array();
1468 // AjaxUI stock banned modules
1469 $config_js[] = "SUGAR.config.stockAjaxBannedModules = ".json_encode(ajaxBannedModules()).";";
1470 if ( isset($sugar_config['quicksearch_querydelay']) ) {
1471 $config_js[] = $this->prepareConfigVarForJs('quicksearch_querydelay', $sugar_config['quicksearch_querydelay']);
1473 if ( empty($sugar_config['disableAjaxUI']) ) {
1474 $config_js[] = "SUGAR.config.disableAjaxUI = false;";
1477 $config_js[] = "SUGAR.config.disableAjaxUI = true;";
1479 if ( !empty($sugar_config['addAjaxBannedModules']) ){
1480 $config_js[] = $this->prepareConfigVarForJs('addAjaxBannedModules', $sugar_config['addAjaxBannedModules']);
1482 if ( !empty($sugar_config['overrideAjaxBannedModules']) ){
1483 $config_js[] = $this->prepareConfigVarForJs('overrideAjaxBannedModules', $sugar_config['overrideAjaxBannedModules']);
1485 if (!empty($sugar_config['js_available']) && is_array ($sugar_config['js_available']))
1487 foreach ($sugar_config['js_available'] as $configKey)
1489 if (isset($sugar_config[$configKey]))
1491 $jsVariableStatement = $this->prepareConfigVarForJs($configKey, $sugar_config[$configKey]);
1492 if (!array_search($jsVariableStatement, $config_js))
1494 $config_js[] = $jsVariableStatement;
1504 * Utility method to convert sugar_config values into a JS acceptable format.
1506 * @param string $key Config Variable Name
1507 * @param string $value Config Variable Value
1510 protected function prepareConfigVarForJs($key, $value)
1512 $value = json_encode($value);
1513 return "SUGAR.config.{$key} = {$value};";
1519 * This is a protected function that returns the help text portion. It is called from getModuleTitle.
1521 * @param $module String the formatted module name
1522 * @return $theTitle String the HTML for the help text
1524 protected function getHelpText($module)
1526 $createImageURL = SugarThemeRegistry::current()->getImageURL('create-record.gif');
1527 $url = ajaxLink("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView");
1528 $theTitle = <<<EOHTML
1530 <img src='{$createImageURL}' alt='{$GLOBALS['app_strings']['LNK_CREATE']}'>
1531 <a href="{$url}" class="utilsLink">
1532 {$GLOBALS['app_strings']['LNK_CREATE']}
1539 * Retrieves favicon corresponding to currently requested module
1543 protected function getFavicon()
1546 if(isset($GLOBALS['sugar_config']['default_module_favicon']))
1547 $module_favicon = $GLOBALS['sugar_config']['default_module_favicon'];
1549 $module_favicon = false;
1551 $themeObject = SugarThemeRegistry::current();
1554 if ( $module_favicon )
1555 $favicon = $themeObject->getImageURL($this->module.'.gif',false);
1556 if ( !sugar_is_file($favicon) || !$module_favicon )
1557 $favicon = $themeObject->getImageURL('sugar_icon.ico',false);
1559 $extension = pathinfo($favicon, PATHINFO_EXTENSION);
1563 $type = 'image/png';
1568 $type = 'image/x-icon';
1573 'url' => getJSPath($favicon),
1580 * getCustomFilePathIfExists
1582 * This function wraps a call to get_custom_file_if_exists from include/utils.php
1584 * @param $file String of filename to check
1585 * @return $file String of filename including custom directory if found
1587 protected function getCustomFilePathIfExists($file)
1589 return get_custom_file_if_exists($file);
1596 * This function wraps the call to the fetch function of the Smarty variable for the view
1598 * @param $file String path of the file to fetch
1599 * @return $content String content from resulting Smarty fetch operation on template
1601 protected function fetchTemplate($file)
1603 return $this->ss->fetch($file);
1607 * Determines whether the state of the post global array indicates there was an error uploading a
1608 * file that exceeds the post_max_size setting. Such an error can be detected if:
1609 * 1. The Server['REQUEST_METHOD'] will still point to POST
1610 * 2. POST and FILES global arrays will be returned empty despite the request method
1611 * This also results in a redirect to the home page (due to lack of module and action in POST)
1613 * @return boolean indicating true or false
1615 public function checkPostMaxSizeError(){
1616 //if the referrer is post, and the post array is empty, then an error has occurred, most likely
1617 //while uploading a file that exceeds the post_max_size.
1618 if(empty($_FILES) && empty($_POST) && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) == 'post'){
1619 $GLOBALS['log']->fatal($GLOBALS['app_strings']['UPLOAD_ERROR_HOME_TEXT']);