PageRenderTime 60ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/include/MVC/View/SugarView.php

https://github.com/mikmagic/sugarcrm_dev
PHP | 1243 lines | 833 code | 163 blank | 247 comment | 191 complexity | 3ba5c97ad3a5c2173544fdfede2a672e MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause, AGPL-3.0
  1. <?php
  2. /*********************************************************************************
  3. * SugarCRM Community Edition is a customer relationship management program developed by
  4. * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
  5. *
  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.
  12. *
  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
  16. * details.
  17. *
  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
  21. * 02110-1301 USA.
  22. *
  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.
  25. *
  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.
  29. *
  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. ********************************************************************************/
  36. class SugarView
  37. {
  38. /**
  39. * This array is meant to hold an objects/data that we would like to pass between
  40. * the controller and the view. The bean will automatically be set for us, but this
  41. * is meant to hold anything else.
  42. */
  43. var $view_object_map = array();
  44. /**
  45. * The name of the current module.
  46. */
  47. var $module = '';
  48. /**
  49. * The name of the current action.
  50. */
  51. var $action = '';
  52. /**
  53. */
  54. var $bean = null;
  55. /**
  56. * Sugar_Smarty. This is useful if you have a view and a subview you can
  57. * share the same smarty object.
  58. */
  59. var $ss = null;
  60. /**
  61. * Any errors that occured this can either be set by the view or the controller or the model
  62. */
  63. var $errors = array();
  64. /**
  65. * Set to true if you do not want to display errors from SugarView::displayErrors(); instead they will be returned
  66. */
  67. var $suppressDisplayErrors = false;
  68. /**
  69. * Options for what UI elements to hide/show/
  70. */
  71. var $options = array('show_header' => true, 'show_title' => true, 'show_subpanels' => false, 'show_search' => true, 'show_footer' => true, 'show_javascript' => true, 'view_print' => false,);
  72. var $type = null;
  73. var $responseTime;
  74. var $fileResources;
  75. /**
  76. * Constructor which will peform the setup.
  77. */
  78. public function SugarView(
  79. $bean = null,
  80. $view_object_map = array()
  81. )
  82. {
  83. }
  84. public function init(
  85. $bean = null,
  86. $view_object_map = array()
  87. )
  88. {
  89. $this->bean = $bean;
  90. $this->view_object_map = $view_object_map;
  91. $this->action = $GLOBALS['action'];
  92. $this->module = $GLOBALS['module'];
  93. $this->_initSmarty();
  94. }
  95. protected function _initSmarty()
  96. {
  97. $this->ss = new Sugar_Smarty();
  98. $this->ss->assign('MOD', $GLOBALS['mod_strings']);
  99. $this->ss->assign('APP', $GLOBALS['app_strings']);
  100. }
  101. /**
  102. * This method will be called from the controller and is not meant to be overridden.
  103. */
  104. public function process()
  105. {
  106. LogicHook::initialize();
  107. $this->_checkModule();
  108. //trackView has to be here in order to track for breadcrumbs
  109. $this->_trackView();
  110. if ($this->_getOption('show_header')) {
  111. $this->displayHeader();
  112. } else {
  113. $this->renderJavascript();
  114. }
  115. $this->_buildModuleList();
  116. $this->preDisplay();
  117. $this->displayErrors();
  118. $this->display();
  119. if ( !empty($this->module) ) {
  120. $GLOBALS['logic_hook']->call_custom_logic($this->module, 'after_ui_frame');
  121. } else {
  122. $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_frame');
  123. }
  124. if ($this->_getOption('show_subpanels')) $this->_displaySubPanels();
  125. if ($this->action === 'Login') {
  126. //this is needed for a faster loading login page ie won't render unless the tables are closed
  127. ob_flush();
  128. }
  129. if ($this->_getOption('show_footer')) $this->displayFooter();
  130. $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_footer');
  131. //Do not track if there is no module or if module is not a String
  132. $this->_track();
  133. }
  134. /**
  135. * This method will display the errors on the page.
  136. */
  137. public function displayErrors()
  138. {
  139. $errors = '';
  140. foreach($this->errors as $error) {
  141. $errors .= '<span class="error">' . $error . '</span><br>';
  142. }
  143. if ( !$this->suppressDisplayErrors ) {
  144. echo $errors;
  145. }
  146. else {
  147. return $errors;
  148. }
  149. }
  150. /**
  151. * [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is
  152. * to allow a view to do some preprocessing before the display method is called. This becomes
  153. * useful when you have a view defined at the application level and then within a module
  154. * have a sub-view that extends from this application level view. The application level
  155. * view can do the setup in preDisplay() that is common to itself and any subviews
  156. * and then the subview can just override display(). If it so desires, can also override
  157. * preDisplay().
  158. */
  159. public function preDisplay()
  160. {
  161. }
  162. /**
  163. * [OVERRIDE] - This method is meant to overidden in a subclass. This method
  164. * will handle the actual display logic of the view.
  165. */
  166. public function display()
  167. {
  168. }
  169. /**
  170. * trackView
  171. */
  172. protected function _trackView()
  173. {
  174. $action = strtolower($this->action);
  175. //Skip save, tracked in SugarBean instead
  176. if($action == 'save') {
  177. return;
  178. }
  179. $trackerManager = TrackerManager::getInstance();
  180. $timeStamp = TimeDate::getInstance()->nowDb();
  181. if($monitor = $trackerManager->getMonitor('tracker')){
  182. $monitor->setValue('action', $action);
  183. $monitor->setValue('user_id', $GLOBALS['current_user']->id);
  184. $monitor->setValue('module_name', $this->module);
  185. $monitor->setValue('date_modified', $timeStamp);
  186. $monitor->setValue('visible', (($monitor->action == 'detailview') || ($monitor->action == 'editview')
  187. ) ? 1 : 0);
  188. if (!empty($this->bean->id)) {
  189. $monitor->setValue('item_id', $this->bean->id);
  190. $monitor->setValue('item_summary', $this->bean->get_summary_text());
  191. }
  192. //If visible is true, but there is no bean, do not track (invalid/unauthorized reference)
  193. //Also, do not track save actions where there is no bean id
  194. if($monitor->visible && empty($this->bean->id)) {
  195. $trackerManager->unsetMonitor($monitor);
  196. return;
  197. }
  198. $trackerManager->saveMonitor($monitor, true, true);
  199. }
  200. }
  201. /**
  202. * Displays the header on section of the page; basically everything before the content
  203. */
  204. public function displayHeader()
  205. {
  206. global $theme;
  207. global $max_tabs;
  208. global $app_strings;
  209. global $current_user;
  210. global $sugar_config;
  211. global $app_list_strings;
  212. global $mod_strings;
  213. global $current_language;
  214. $GLOBALS['app']->headerDisplayed = true;
  215. $themeObject = SugarThemeRegistry::current();
  216. $theme = $themeObject->__toString();
  217. $ss = new Sugar_Smarty();
  218. $ss->assign("APP", $app_strings);
  219. $ss->assign("THEME", $theme);
  220. $ss->assign("THEME_IE6COMPAT", $themeObject->ie6compat ? 'true':'false');
  221. $ss->assign("MODULE_NAME", $this->module);
  222. // get browser title
  223. $ss->assign("SYSTEM_NAME", $this->getBrowserTitle());
  224. // get css
  225. $css = $themeObject->getCSS();
  226. if ($this->_getOption('view_print')) {
  227. $css .= '<link rel="stylesheet" type="text/css" href="'.$themeObject->getCSSURL('print.css').'" media="all" />';
  228. }
  229. $ss->assign("SUGAR_CSS",$css);
  230. // get javascript
  231. ob_start();
  232. $this->renderJavascript();
  233. $ss->assign("SUGAR_JS",ob_get_contents().$themeObject->getJS());
  234. ob_end_clean();
  235. // get favicon
  236. if(isset($GLOBALS['sugar_config']['default_module_favicon']))
  237. $module_favicon = $GLOBALS['sugar_config']['default_module_favicon'];
  238. else
  239. $module_favicon = false;
  240. $favicon = '';
  241. if ( $module_favicon )
  242. $favicon = $themeObject->getImageURL($this->module.'.gif',false);
  243. if ( !sugar_is_file($favicon) || !$module_favicon )
  244. $favicon = $themeObject->getImageURL('sugar_icon.ico',false);
  245. $ss->assign('FAVICON_URL',getJSPath($favicon));
  246. // build the shortcut menu
  247. $shortcut_menu = array();
  248. foreach ( $this->getMenu() as $key => $menu_item )
  249. $shortcut_menu[$key] = array(
  250. "URL" => $menu_item[0],
  251. "LABEL" => $menu_item[1],
  252. "MODULE_NAME" => $menu_item[2],
  253. "IMAGE" => $themeObject
  254. ->getImage($menu_item[2],"alt='".$menu_item[1]."' border='0' align='absmiddle'"),
  255. );
  256. $ss->assign("SHORTCUT_MENU",$shortcut_menu);
  257. // handle rtl text direction
  258. if(isset($_REQUEST['RTL']) && $_REQUEST['RTL'] == 'RTL'){
  259. $_SESSION['RTL'] = true;
  260. }
  261. if(isset($_REQUEST['LTR']) && $_REQUEST['LTR'] == 'LTR'){
  262. unset($_SESSION['RTL']);
  263. }
  264. if(isset($_SESSION['RTL']) && $_SESSION['RTL']){
  265. $ss->assign("DIR", 'dir="RTL"');
  266. }
  267. // handle resizing of the company logo correctly on the fly
  268. $companyLogoURL = $themeObject->getImageURL('company_logo.png');
  269. $companyLogoURL_arr = explode('?', $companyLogoURL);
  270. $companyLogoURL = $companyLogoURL_arr[0];
  271. $company_logo_attributes = sugar_cache_retrieve('company_logo_attributes');
  272. if(!empty($company_logo_attributes)) {
  273. $ss->assign("COMPANY_LOGO_MD5", $company_logo_attributes[0]);
  274. $ss->assign("COMPANY_LOGO_WIDTH", $company_logo_attributes[1]);
  275. $ss->assign("COMPANY_LOGO_HEIGHT", $company_logo_attributes[2]);
  276. }
  277. else {
  278. // Always need to md5 the file
  279. $ss->assign("COMPANY_LOGO_MD5", md5_file($companyLogoURL));
  280. list($width,$height) = getimagesize($companyLogoURL);
  281. if ( $width > 212 || $height > 40 ) {
  282. $resizePctWidth = ($width - 212)/212;
  283. $resizePctHeight = ($height - 40)/40;
  284. if ( $resizePctWidth > $resizePctHeight )
  285. $resizeAmount = $width / 212;
  286. else
  287. $resizeAmount = $height / 40;
  288. $ss->assign("COMPANY_LOGO_WIDTH", round($width * (1/$resizeAmount)));
  289. $ss->assign("COMPANY_LOGO_HEIGHT", round($height * (1/$resizeAmount)));
  290. }
  291. else {
  292. $ss->assign("COMPANY_LOGO_WIDTH", $width);
  293. $ss->assign("COMPANY_LOGO_HEIGHT", $height);
  294. }
  295. // Let's cache the results
  296. sugar_cache_put('company_logo_attributes',
  297. array(
  298. $ss->get_template_vars("COMPANY_LOGO_MD5"),
  299. $ss->get_template_vars("COMPANY_LOGO_WIDTH"),
  300. $ss->get_template_vars("COMPANY_LOGO_HEIGHT")
  301. )
  302. );
  303. }
  304. $ss->assign("COMPANY_LOGO_URL",getJSPath($companyLogoURL)."&logo_md5=".$ss->get_template_vars("COMPANY_LOGO_MD5"));
  305. // get the global links
  306. $gcls = array();
  307. $global_control_links = array();
  308. require("include/globalControlLinks.php");
  309. foreach($global_control_links as $key => $value) {
  310. if ($key == 'users') { //represents logout link.
  311. $ss->assign("LOGOUT_LINK", $value['linkinfo'][key($value['linkinfo'])]);
  312. $ss->assign("LOGOUT_LABEL", key($value['linkinfo']));//key value for first element.
  313. continue;
  314. }
  315. foreach ($value as $linkattribute => $attributevalue) {
  316. // get the main link info
  317. if ( $linkattribute == 'linkinfo' ) {
  318. $gcls[$key] = array(
  319. "LABEL" => key($attributevalue),
  320. "URL" => current($attributevalue),
  321. "SUBMENU" => array(),
  322. );
  323. if(substr($gcls[$key]["URL"], 0, 11) == "javascript:") {
  324. $gcls[$key]["ONCLICK"] = substr($gcls[$key]["URL"],11);
  325. $gcls[$key]["URL"] = "#";
  326. }
  327. }
  328. // and now the sublinks
  329. if ( $linkattribute == 'submenu' && is_array($attributevalue) ) {
  330. foreach ($attributevalue as $submenulinkkey => $submenulinkinfo)
  331. $gcls[$key]['SUBMENU'][$submenulinkkey] = array(
  332. "LABEL" => key($submenulinkinfo),
  333. "URL" => current($submenulinkinfo),
  334. );
  335. if(substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"], 0, 11) == "javascript:") {
  336. $gcls[$key]['SUBMENU'][$submenulinkkey]["ONCLICK"] = substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"],11);
  337. $gcls[$key]['SUBMENU'][$submenulinkkey]["URL"] = "#";
  338. }
  339. }
  340. }
  341. }
  342. $ss->assign("GCLS",$gcls);
  343. $ss->assign("SEARCH", isset($_REQUEST['query_string']) ? $_REQUEST['query_string'] : '');
  344. if ($this->action == "EditView" || $this->action == "Login")
  345. $ss->assign("ONLOAD", 'onload="set_focus()"');
  346. $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
  347. // get other things needed for page style popup
  348. if (isset($_SESSION["authenticated_user_id"])) {
  349. // get the current user name and id
  350. $ss->assign("CURRENT_USER", $current_user->full_name == '' || !showFullName()
  351. ? $current_user->user_name : $current_user->full_name );
  352. $ss->assign("CURRENT_USER_ID", $current_user->id);
  353. // get the last viewed records
  354. $tracker = new Tracker();
  355. $history = $tracker->get_recently_viewed($current_user->id);
  356. foreach ( $history as $key => $row ) {
  357. $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']);
  358. $history[$key]['image'] = SugarThemeRegistry::current()
  359. ->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"');
  360. }
  361. $ss->assign("recentRecords",$history);
  362. }
  363. $bakModStrings = $mod_strings;
  364. if (isset($_SESSION["authenticated_user_id"]) ) {
  365. // get the module list
  366. $moduleTopMenu = array();
  367. $max_tabs = $current_user->getPreference('max_tabs');
  368. // Attempt to correct if max tabs count is waaay too high.
  369. if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10 ) {
  370. $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
  371. $current_user->setPreference('max_tabs', $max_tabs, 0, 'global');
  372. }
  373. $moduleTab = $this->_getModuleTab();
  374. $ss->assign('MODULE_TAB',$moduleTab);
  375. // See if they are using grouped tabs or not (removed in 6.0, returned in 6.1)
  376. $user_navigation_paradigm = $current_user->getPreference('navigation_paradigm');
  377. if ( !isset($user_navigation_paradigm) ) {
  378. $user_navigation_paradigm = $GLOBALS['sugar_config']['default_navigation_paradigm'];
  379. }
  380. // Get the full module list for later use
  381. foreach ( query_module_access_list($current_user) as $module ) {
  382. // Bug 25948 - Check for the module being in the moduleList
  383. if ( isset($app_list_strings['moduleList'][$module]) ) {
  384. $fullModuleList[$module] = $app_list_strings['moduleList'][$module];
  385. }
  386. }
  387. if(!should_hide_iframes()) {
  388. $iFrame = new iFrame();
  389. $frames = $iFrame->lookup_frames('tab');
  390. foreach($frames as $key => $values){
  391. $fullModuleList[$key] = $values;
  392. }
  393. }
  394. elseif (isset($fullModuleList['iFrames'])) {
  395. unset($fullModuleList['iFrames']);
  396. }
  397. if ( $user_navigation_paradigm == 'gm' && isset($themeObject->group_tabs) && $themeObject->group_tabs) {
  398. // We are using grouped tabs
  399. require_once('include/GroupedTabs/GroupedTabStructure.php');
  400. $groupedTabsClass = new GroupedTabStructure();
  401. $modules = query_module_access_list($current_user);
  402. //handle with submoremodules
  403. $max_tabs = $current_user->getPreference('max_tabs');
  404. // If the max_tabs isn't set incorrectly, set it within the range, to the default max sub tabs size
  405. if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10){
  406. // We have a default value. Use it
  407. if(isset($GLOBALS['sugar_config']['default_max_tabs'])){
  408. $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
  409. }
  410. else{
  411. $max_tabs = 8;
  412. }
  413. }
  414. $subMoreModules = false;
  415. $groupTabs = $groupedTabsClass->get_tab_structure(get_val_array($modules));
  416. // We need to put this here, so the "All" group is valid for the user's preference.
  417. $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
  418. // Setup the default group tab.
  419. $allGroup = $app_strings['LBL_TABGROUP_ALL'];
  420. $ss->assign('currentGroupTab',$allGroup);
  421. $currentGroupTab = $allGroup;
  422. $usersGroup = $current_user->getPreference('theme_current_group');
  423. // Figure out which tab they currently have selected (stored as a user preference)
  424. if ( !empty($usersGroup) && isset($groupTabs[$usersGroup]) ) {
  425. $currentGroupTab = $usersGroup;
  426. } else {
  427. $current_user->setPreference('theme_current_group',$currentGroupTab);
  428. }
  429. $ss->assign('currentGroupTab',$currentGroupTab);
  430. $usingGroupTabs = true;
  431. } else {
  432. // Setup the default group tab.
  433. $ss->assign('currentGroupTab',$app_strings['LBL_TABGROUP_ALL']);
  434. $usingGroupTabs = false;
  435. $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
  436. }
  437. $topTabList = array();
  438. // Now time to go through each of the tab sets and fix them up.
  439. foreach ( $groupTabs as $tabIdx => $tabData ) {
  440. $topTabs = $tabData['modules'];
  441. if ( ! is_array($topTabs) ) {
  442. $topTabs = array();
  443. }
  444. $extraTabs = array();
  445. // Split it in to the tabs that go across the top, and the ones that are on the extra menu.
  446. if ( count($topTabs) > $max_tabs ) {
  447. $extraTabs = array_splice($topTabs,$max_tabs);
  448. }
  449. // Make sure the current module is accessable through one of the top tabs
  450. if ( !isset($topTabs[$moduleTab]) ) {
  451. // Nope, we need to add it.
  452. // First, take it out of the extra menu, if it's there
  453. if ( isset($extraTabs[$moduleTab]) ) {
  454. unset($extraTabs[$moduleTab]);
  455. }
  456. if ( count($topTabs) >= $max_tabs - 1 ) {
  457. // We already have the maximum number of tabs, so we need to shuffle the last one
  458. // from the top to the first one of the extras
  459. $lastElem = array_splice($topTabs,$max_tabs-1);
  460. $extraTabs = $lastElem + $extraTabs;
  461. }
  462. if ( !empty($moduleTab) ) {
  463. $topTabs[$moduleTab] = $app_list_strings['moduleList'][$moduleTab];
  464. }
  465. }
  466. /*
  467. // This was removed, but I like the idea, so I left the code in here in case we decide to turn it back on
  468. // If we are using group tabs, add all the "hidden" tabs to the end of the extra menu
  469. if ( $usingGroupTabs ) {
  470. foreach($fullModuleList as $moduleKey => $module ) {
  471. if ( !isset($topTabs[$moduleKey]) && !isset($extraTabs[$moduleKey]) ) {
  472. $extraTabs[$moduleKey] = $module;
  473. }
  474. }
  475. }
  476. */
  477. // Get a unique list of the top tabs so we can build the popup menus for them
  478. foreach ( $topTabs as $moduleKey => $module ) {
  479. $topTabList[$moduleKey] = $module;
  480. }
  481. $groupTabs[$tabIdx]['modules'] = $topTabs;
  482. $groupTabs[$tabIdx]['extra'] = $extraTabs;
  483. }
  484. }
  485. if ( isset($topTabList) && is_array($topTabList) ) {
  486. // Adding shortcuts array to menu array for displaying shortcuts associated with each module
  487. $shortcutTopMenu = array();
  488. foreach($topTabList as $module_key => $label) {
  489. global $mod_strings;
  490. $mod_strings = return_module_language($current_language, $module_key);
  491. foreach ( $this->getMenu($module_key) as $key => $menu_item ) {
  492. $shortcutTopMenu[$module_key][$key] = array(
  493. "URL" => $menu_item[0],
  494. "LABEL" => $menu_item[1],
  495. "MODULE_NAME" => $menu_item[2],
  496. "IMAGE" => $themeObject
  497. ->getImage($menu_item[2],"alt='".$menu_item[1]."' border='0' align='absmiddle'"),
  498. );
  499. }
  500. }
  501. $ss->assign("groupTabs",$groupTabs);
  502. $ss->assign("shortcutTopMenu",$shortcutTopMenu);
  503. $ss->assign('USE_GROUP_TABS',$usingGroupTabs);
  504. // This is here for backwards compatibility, someday, somewhere, it will be able to be removed
  505. $ss->assign("moduleTopMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules']);
  506. $ss->assign("moduleExtraMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['extra']);
  507. }
  508. global $mod_strings;
  509. $mod_strings = $bakModStrings;
  510. $headerTpl = $themeObject->getTemplate('header.tpl');
  511. if ( isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'] )
  512. $ss->clear_compiled_tpl($headerTpl);
  513. $ss->display($headerTpl);
  514. $this->includeClassicFile('modules/Administration/DisplayWarnings.php');
  515. $errorMessages = SugarApplication::getErrorMessages();
  516. if ( !empty($errorMessages)) {
  517. foreach ( $errorMessages as $error_message ) {
  518. echo('<p class="error">' . $error_message.'</p>');
  519. }
  520. }
  521. }
  522. /**
  523. * If the view is classic then this method will include the file and
  524. * setup any global variables.
  525. *
  526. * @param string $file
  527. */
  528. public function includeClassicFile(
  529. $file
  530. )
  531. {
  532. global $sugar_config, $theme, $current_user, $sugar_version, $sugar_flavor, $mod_strings, $app_strings, $app_list_strings, $action, $timezones;
  533. global $gridline, $request_string, $modListHeader, $dashletData, $authController, $locale, $currentModule, $import_bean_map, $image_path, $license;
  534. global $user_unique_key, $server_unique_key, $barChartColors, $modules_exempt_from_availability_check, $dictionary, $current_language, $beanList, $beanFiles, $sugar_build, $sugar_codename;
  535. global $timedate, $login_error; // cn: bug 13855 - timedate not available to classic views.
  536. $currentModule = $this->module;
  537. require_once ($file);
  538. }
  539. protected function _displayLoginJS()
  540. {
  541. global $sugar_config, $timedate;
  542. if(isset($this->bean->module_dir)){
  543. echo "<script>var module_sugar_grp1 = '{$this->bean->module_dir}';</script>";
  544. }
  545. if(isset($_REQUEST['action'])){
  546. echo "<script>var action_sugar_grp1 = '{$_REQUEST['action']}';</script>";
  547. }
  548. echo '<script>jscal_today = ' . (1000*$timedate->asUserTs($timedate->getNow())) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
  549. if (!is_file("include/javascript/sugar_grp1.js")) {
  550. $_REQUEST['root_directory'] = ".";
  551. require_once("jssource/minify_utils.php");
  552. ConcatenateFiles(".");
  553. }
  554. echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1_yui.js') . '"></script>';
  555. echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1.js') . '"></script>';
  556. echo '<script type="text/javascript" src="' . getJSPath('include/javascript/calendar.js') . '"></script>';
  557. echo <<<EOQ
  558. <script>
  559. if ( typeof(SUGAR) == 'undefined' ) {SUGAR = {}};
  560. if ( typeof(SUGAR.themes) == 'undefined' ) SUGAR.themes = {};
  561. </script>
  562. EOQ;
  563. if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
  564. echo '<script type="text/javascript" src="' . getJSPath('modules/Sync/headersync.js') . '"></script>';
  565. }
  566. /**
  567. * Get JS validation code for views
  568. */
  569. public static function getJavascriptValidation()
  570. {
  571. global $timedate;
  572. $cal_date_format = $timedate->get_cal_date_format();
  573. $timereg = $timedate->get_regular_expression($timedate->get_time_format());
  574. $datereg = $timedate->get_regular_expression($timedate->get_date_format());
  575. $date_pos = '';
  576. foreach ($datereg['positions'] as $type => $pos) {
  577. if (empty($date_pos)) {
  578. $date_pos .= "'$type': $pos";
  579. } else {
  580. $date_pos .= ",'$type': $pos";
  581. }
  582. }
  583. $time_separator = $timedate->timeSeparator();
  584. $hour_offset = $timedate->getUserUTCOffset() * 60;
  585. // Add in the number formatting styles here as well, we have been handling this with individual modules.
  586. require_once ('modules/Currencies/Currency.php');
  587. list ($num_grp_sep, $dec_sep) = get_number_seperators();
  588. $the_script = "<script type=\"text/javascript\">\n" . "\tvar time_reg_format = '" .
  589. $timereg['format'] . "';\n" . "\tvar date_reg_format = '" .
  590. $datereg['format'] . "';\n" . "\tvar date_reg_positions = { $date_pos };\n" .
  591. "\tvar time_separator = '$time_separator';\n" .
  592. "\tvar cal_date_format = '$cal_date_format';\n" .
  593. "\tvar time_offset = $hour_offset;\n" . "\tvar num_grp_sep = '$num_grp_sep';\n" .
  594. "\tvar dec_sep = '$dec_sep';\n" . "</script>";
  595. return $the_script;
  596. }
  597. /**
  598. * Called from process(). This method will display the correct javascript.
  599. */
  600. protected function _displayJavascript()
  601. {
  602. global $locale, $sugar_config, $timedate;
  603. if ($this->_getOption('show_javascript')) {
  604. if (!$this->_getOption('show_header'))
  605. echo <<<EOHTML
  606. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  607. <html>
  608. <head>
  609. EOHTML;
  610. echo "<script>var sugar_cache_dir = '{$GLOBALS['sugar_config']['cache_dir']}';</script>";
  611. echo "<script>var sugar_upload_dir = '{$GLOBALS['sugar_config']['upload_dir']}';</script>";
  612. if(isset($this->bean->module_dir)){
  613. echo "<script>var module_sugar_grp1 = '{$this->bean->module_dir}';</script>";
  614. }
  615. if(isset($_REQUEST['action'])){
  616. echo "<script>var action_sugar_grp1 = '{$_REQUEST['action']}';</script>";
  617. }
  618. echo '<script>jscal_today = ' . (1000*$timedate->asUserTs($timedate->getNow())) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
  619. if (!is_file("include/javascript/sugar_grp1.js") || !is_file("include/javascript/sugar_grp1_yui.js")) {
  620. $_REQUEST['root_directory'] = ".";
  621. require_once("jssource/minify_utils.php");
  622. ConcatenateFiles(".");
  623. }
  624. echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1_yui.js') . '"></script>';
  625. echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1.js') . '"></script>';
  626. echo '<script type="text/javascript" src="' . getJSPath('include/javascript/calendar.js') . '"></script>';
  627. if ( isset($sugar_config['quicksearch_querydelay']) ) {
  628. echo "<script>SUGAR.config.quicksearch_querydelay = {$GLOBALS['sugar_config']['quicksearch_querydelay']};</script>";
  629. }
  630. if ( isset($sugar_config['email_sugarclient_listviewmaxselect']) ) {
  631. echo "<script>SUGAR.config.email_sugarclient_listviewmaxselect = {$GLOBALS['sugar_config']['email_sugarclient_listviewmaxselect']};</script>";
  632. }
  633. $image_server = (defined('TEMPLATE_URL'))?TEMPLATE_URL . '/':'';
  634. echo '<script type="text/javascript">SUGAR.themes.image_server="' . $image_server . '";</script>'; // cn: bug 12274 - create session-stored key to defend against CSRF
  635. echo '<script type="text/javascript">var name_format = "' . $locale->getLocaleFormatMacro() . '";</script>';
  636. echo self::getJavascriptValidation();
  637. if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $GLOBALS['current_language'] . '.js')) {
  638. require_once ('include/language/jsLanguage.php');
  639. jsLanguage::createAppStringsCache($GLOBALS['current_language']);
  640. }
  641. echo '<script type="text/javascript" src="' . $GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $GLOBALS['current_language'] . '.js?s=' . $GLOBALS['js_version_key'] . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] . '&j=' . $GLOBALS['sugar_config']['js_lang_version'] . '"></script>';
  642. if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $this->module . '/' . $GLOBALS['current_language'] . '.js')) {
  643. require_once ('include/language/jsLanguage.php');
  644. jsLanguage::createModuleStringsCache($this->module, $GLOBALS['current_language']);
  645. }
  646. echo '<script type="text/javascript" src="' . $GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $this->module . '/' . $GLOBALS['current_language'] . '.js?s=' . $GLOBALS['js_version_key'] . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] . '&j=' . $GLOBALS['sugar_config']['js_lang_version'] . '"></script>';
  647. if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
  648. echo '<script type="text/javascript" src="' . getJSPath('modules/Sync/headersync.js') . '"></script>';
  649. }
  650. }
  651. /**
  652. * Called from process(). This method will display the footer on the page.
  653. */
  654. public function displayFooter()
  655. {
  656. if (empty($this->responseTime)) {
  657. $this->_calculateFooterMetrics();
  658. }
  659. global $sugar_config;
  660. global $app_strings;
  661. //decide whether or not to show themepicker, default is to show
  662. $showThemePicker = true;
  663. if (isset($sugar_config['showThemePicker'])) {
  664. $showThemePicker = $sugar_config['showThemePicker'];
  665. }
  666. echo "<!-- crmprint -->";
  667. $jsalerts = new jsAlerts();
  668. if ( !isset($_SESSION['isMobile']) )
  669. echo $jsalerts->getScript();
  670. $ss = new Sugar_Smarty();
  671. $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
  672. $ss->assign('MOD',return_module_language($GLOBALS['current_language'], 'Users'));
  673. $bottomLinkList = array();
  674. if (isset($this->action) && $this->action != "EditView") {
  675. $bottomLinkList['print'] =
  676. array($app_strings['LNK_PRINT'] => 'javascript:void window.open(\'index.php?'.$GLOBALS['request_string'].'\',\'printwin\',\'menubar=1,status=0,resizable=1,scrollbars=1,toolbar=0,location=1\')');
  677. }
  678. $bottomLinkList['backtotop'] = array($app_strings['LNK_BACKTOTOP'] => '#top');
  679. $bottomLinksStr = "";
  680. foreach($bottomLinkList as $key => $value) {
  681. foreach($value as $text => $link) {
  682. $href = $link;
  683. if(substr($link, 0, 11) == "javascript:") {
  684. $onclick = " onclick=\"".substr($link,11)."\"";
  685. $href = "#";
  686. } else {
  687. $onclick = "";
  688. }
  689. $imageURL = SugarThemeRegistry::current()->getImageURL($key.'.gif');
  690. $bottomLinksStr .= "<a href=\"{$href}\"";
  691. $bottomLinksStr .= (isset($onclick)) ? $onclick : "";
  692. $bottomLinksStr .= "><img src='{$imageURL}' alt='{$text}'></a>";
  693. $bottomLinksStr .= " <a href=\"{$href}\" class=\"bottomLink\"";
  694. $bottomLinksStr .= (isset($onclick)) ? $onclick : "";
  695. $bottomLinksStr .= ">".$text."</a>";
  696. }
  697. }
  698. $ss->assign("BOTTOMLINKS",$bottomLinksStr);
  699. if (SugarConfig::getInstance()->get('calculate_response_time', false))
  700. $ss->assign('STATISTICS',$this->_getStatistics());
  701. // Under the License referenced above, you are required to leave in all copyright statements in both
  702. // the code and end-user application.
  703. $copyright = '&copy; 2004-2011 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>';
  704. // The interactive user interfaces in modified source and object code
  705. // versions of this program must display Appropriate Legal Notices, as
  706. // required under Section 5 of the GNU General Public License version
  707. // 3. In accordance with Section 7(b) of the GNU General Public License
  708. // version 3, these Appropriate Legal Notices must retain the display
  709. // of the "Powered by SugarCRM" logo. If the display of the logo is
  710. // not reasonably feasible for technical reasons, the Appropriate
  711. // Legal Notices must display the words "Powered by SugarCRM".
  712. $attribLinkImg = "<img style='margin-top: 2px' border='0' width='106' height='23' src='include/images/poweredby_sugarcrm.png' alt='Powered By SugarCRM'>\n";
  713. // Bug 38594 - Add in Trademark wording
  714. $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 />';
  715. //rrs bug: 20923 - if this image does not exist as per the license, then the proper image will be displaye regardless, so no need
  716. //to display an empty image here.
  717. if(file_exists('include/images/poweredby_sugarcrm.png')){
  718. $copyright .= $attribLinkImg;
  719. }
  720. // End Required Image
  721. $ss->assign('COPYRIGHT',$copyright);
  722. $ss->display(SugarThemeRegistry::current()->getTemplate('footer.tpl'));
  723. }
  724. /**
  725. * Called from process(). This method will display subpanels.
  726. */
  727. protected function _displaySubPanels()
  728. {
  729. 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'))) {
  730. $GLOBALS['focus'] = $this->bean;
  731. require_once ('include/SubPanel/SubPanelTiles.php');
  732. $subpanel = new SubPanelTiles($this->bean, $this->module);
  733. echo $subpanel->display();
  734. }
  735. }
  736. protected function _buildModuleList()
  737. {
  738. if (!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader']))
  739. $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
  740. }
  741. /**
  742. * private method used in process() to determine the value of a passed in option
  743. *
  744. * @param string option - the option that we want to know the valye of
  745. * @param bool default - what the default value should be if we do not find the option
  746. *
  747. * @return bool - the value of the option
  748. */
  749. protected function _getOption(
  750. $option,
  751. $default = false
  752. )
  753. {
  754. if (!empty($this->options) && isset($this->options['show_all'])) {
  755. return $this->options['show_all'];
  756. } elseif (!empty($this->options) && isset($this->options[$option])) {
  757. return $this->options[$option];
  758. } else return $default;
  759. }
  760. /**
  761. * track
  762. * Private function to track information about the view request
  763. */
  764. private function _track()
  765. {
  766. if (empty($this->responseTime)) {
  767. $this->_calculateFooterMetrics();
  768. }
  769. if (empty($GLOBALS['current_user']->id)) {
  770. return;
  771. }
  772. $trackerManager = TrackerManager::getInstance();
  773. $trackerManager->save();
  774. }
  775. /**
  776. * Checks to see if the module name passed is valid; dies if it is not
  777. */
  778. protected function _checkModule()
  779. {
  780. if(!empty($this->module) && !file_exists('modules/'.$this->module)){
  781. $error = str_replace("[module]", "$this->module", $GLOBALS['app_strings']['ERR_CANNOT_FIND_MODULE']);
  782. $GLOBALS['log']->fatal($error);
  783. echo $error;
  784. die();
  785. }
  786. }
  787. public function renderJavascript()
  788. {
  789. if ($this->action !== 'Login')
  790. $this->_displayJavascript();
  791. else
  792. $this->_displayLoginJS();
  793. }
  794. private function _calculateFooterMetrics()
  795. {
  796. $endTime = microtime(true);
  797. $deltaTime = $endTime - $GLOBALS['startTime'];
  798. $this->responseTime = number_format(round($deltaTime, 2), 2);
  799. // Print out the resources used in constructing the page.
  800. $this->fileResources = count(get_included_files());
  801. }
  802. private function _getStatistics()
  803. {
  804. $endTime = microtime(true);
  805. $deltaTime = $endTime - $GLOBALS['startTime'];
  806. $response_time_string = $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME'] . " " . number_format(round($deltaTime, 2), 2) . " " . $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME_SECONDS'];
  807. $return = $response_time_string;
  808. $return .= '<br />';
  809. if (!empty($GLOBALS['sugar_config']['show_page_resources'])) {
  810. // Print out the resources used in constructing the page.
  811. $included_files = get_included_files();
  812. // take all of the included files and make a list that does not allow for duplicates based on case
  813. // I believe the full get_include_files result set appears to have one entry for each file in real
  814. // case, and one entry in all lower case.
  815. $list_of_files_case_insensitive = array();
  816. foreach($included_files as $key => $name) {
  817. // preserve the first capitalization encountered.
  818. $list_of_files_case_insensitive[mb_strtolower($name) ] = $name;
  819. }
  820. $return .= $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_RESOURCES'] . '(' . DBManager::getQueryCount() . ',' . sizeof($list_of_files_case_insensitive) . ')<br>';
  821. // Display performance of the internal and external caches....
  822. $cacheStats = SugarCache::instance()->getCacheStats();
  823. $return .= "External cache (hits/total=ratio) local ({$cacheStats['localHits']}/{$cacheStats['requests']}=" . round($cacheStats['localHits']*100/$cacheStats['requests'], 0) . "%)";
  824. $return .= " external ({$cacheStats['externalHits']}/{$cacheStats['requests']}=" . round($cacheStats['externalHits']*100/$cacheStats['requests'], 0) . "%)<br />";
  825. $return .= " misses ({$cacheStats['misses']}/{$cacheStats['requests']}=" . round($cacheStats['misses']*100/$cacheStats['requests'], 0) . "%)<br />";
  826. }
  827. return $return;
  828. }
  829. /**
  830. * Loads the module shortcuts menu
  831. *
  832. * @param $module string optional, can specify module to retrieve menu for if not the current one
  833. * @return array module menu
  834. */
  835. public function getMenu(
  836. $module = null
  837. )
  838. {
  839. global $current_language, $current_user, $mod_strings, $app_strings, $module_menu;
  840. if ( empty($module) )
  841. $module = $this->module;
  842. $module_menu = array();
  843. if (file_exists('modules/' . $module . '/Menu.php')) {
  844. require('modules/' . $module . '/Menu.php');
  845. }
  846. if (file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php')) {
  847. require('custom/modules/' . $module . '/Ext/Menus/menu.ext.php');
  848. }
  849. if (!file_exists('modules/' . $module . '/Menu.php')
  850. && !file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php')
  851. && !empty($GLOBALS['mod_strings']['LNK_NEW_RECORD'])) {
  852. $module_menu[] = array("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView",
  853. $GLOBALS['mod_strings']['LNK_NEW_RECORD'],"{$GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']}$module" ,$module );
  854. $module_menu[] = array("index.php?module=$module&action=index", $GLOBALS['mod_strings']['LNK_LIST'],
  855. $module, $module);
  856. if ( ($this->bean instanceOf SugarBean) && !empty($this->bean->importable) )
  857. if ( !empty($mod_strings['LNK_IMPORT_'.strtoupper($module)]) )
  858. $module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index",
  859. $mod_strings['LNK_IMPORT_'.strtoupper($module)], "Import", $module);
  860. else
  861. $module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index",
  862. $app_strings['LBL_IMPORT'], "Import", $module);
  863. }
  864. if (file_exists('custom/application/Ext/Menus/menu.ext.php')) {
  865. require('custom/application/Ext/Menus/menu.ext.php');
  866. }
  867. $builtModuleMenu = $module_menu;
  868. unset($module_menu);
  869. return $builtModuleMenu;
  870. }
  871. /**
  872. * Returns the module name which should be highlighted in the module menu
  873. */
  874. protected function _getModuleTab()
  875. {
  876. global $app_list_strings, $moduleTabMap;
  877. // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions.
  878. if ( !empty($_REQUEST['module_tab']) )
  879. return $_REQUEST['module_tab'];
  880. elseif ( isset($moduleTabMap[$this->module]) )
  881. return $moduleTabMap[$this->module];
  882. // Special cases
  883. elseif ( $this->module == 'MergeRecords' )
  884. return !empty($_REQUEST['merge_module']) ? $_REQUEST['merge_module'] : $_REQUEST['return_module'];
  885. elseif ( $this->module == 'Users' && $this->action == 'SetTimezone' )
  886. return 'Home';
  887. // Default anonymous pages to be under Home
  888. elseif ( !isset($app_list_strings['moduleList'][$this->module]) )
  889. return 'Home';
  890. else
  891. return $this->module;
  892. }
  893. /**
  894. * Return the "breadcrumbs" to display at the top of the page
  895. *
  896. * @param bool $show_help optional, true if we show the help links
  897. * @return HTML string containing breadcrumb title
  898. */
  899. public function getModuleTitle(
  900. $show_help = true
  901. )
  902. {
  903. global $sugar_version, $sugar_flavor, $server_unique_key, $current_language, $action;
  904. $theTitle = "<div class='moduleTitle'>\n<h2>";
  905. $module = preg_replace("/ /","",$this->module);
  906. $params = $this->_getModuleTitleParams();
  907. $count = count($params);
  908. $index = 0;
  909. if(SugarThemeRegistry::current()->directionality == "rtl") {
  910. $params = array_reverse($params);
  911. }
  912. foreach($params as $parm){
  913. $index++;
  914. $theTitle .= $parm;
  915. if($index < $count){
  916. $theTitle .= $this->getBreadCrumbSymbol();
  917. }
  918. }
  919. $theTitle .= "</h2>\n";
  920. if ($show_help) {
  921. $theTitle .= "<span class='utils'>";
  922. $createImageURL = SugarThemeRegistry::current()->getImageURL('create-record.gif');
  923. $theTitle .= <<<EOHTML
  924. &nbsp;
  925. <a href="index.php?module={$module}&action=EditView&return_module={$module}&return_action=DetailView" class="utilsLink">
  926. <img src='{$createImageURL}' alt='{$GLOBALS['app_strings']['LNK_CREATE']}'></a>
  927. <a href="index.php?module={$module}&action=EditView&return_module={$module}&return_action=DetailView" class="utilsLink">
  928. {$GLOBALS['app_strings']['LNK_CREATE']}
  929. </a>
  930. EOHTML;
  931. }
  932. $theTitle .= "</span></div>\n";
  933. return $theTitle;
  934. }
  935. /**
  936. * Return the metadata file that will be used by this view.
  937. *
  938. * @return string File location of the metadata file.
  939. */
  940. public function getMetaDataFile()
  941. {
  942. $metadataFile = null;
  943. $foundViewDefs = false;
  944. $viewDef = strtolower($this->type) . 'viewdefs';
  945. $coreMetaPath = 'modules/'.$this->module.'/metadata/' . $viewDef . '.php';
  946. if(file_exists('custom/' .$coreMetaPath )){
  947. $metadataFile = 'custom/' . $coreMetaPath;
  948. $foundViewDefs = true;
  949. }else{
  950. if(file_exists('custom/modules/'.$this->module.'/metadata/metafiles.php')){
  951. require_once('custom/modules/'.$this->module.'/metadata/metafiles.php');
  952. if(!empty($metafiles[$this->module][$viewDef])){
  953. $metadataFile = $metafiles[$this->module][$viewDef];
  954. $foundViewDefs = true;
  955. }
  956. }elseif(file_exists('modules/'.$this->module.'/metadata/metafiles.php')){
  957. require_once('modules/'.$this->module.'/metadata/metafiles.php');
  958. if(!empty($metafiles[$this->module][$viewDef])){
  959. $metadataFile = $metafiles[$this->module][$viewDef];
  960. $foundViewDefs = true;
  961. }
  962. }
  963. }
  964. if(!$foundViewDefs && file_exists($coreMetaPath)){
  965. $metadataFile = $coreMetaPath;
  966. }
  967. $GLOBALS['log']->debug("metadatafile=". $metadataFile);
  968. return $metadataFile;
  969. }
  970. /**
  971. * Returns an array composing of the breadcrumbs to use for the module title
  972. *
  973. * @param bool $browserTitle true if the returned string is being used for the browser title, meaning
  974. * there should be no HTML in the string
  975. * @return array
  976. */
  977. protected function _getModuleTitleParams($browserTitle = false)
  978. {
  979. $params = array($this->_getModuleTitleListParam($browserTitle));
  980. if (isset($this->action)){
  981. switch ($this->action) {
  982. case 'EditView':
  983. if(!empty($this->bean->id)) {
  984. $params[] = "<a href='index.php?module={$this->module}&action=DetailView&record={$this->bean->id}'>".$this->bean->get_summary_text()."</a>";
  985. $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL'];
  986. }
  987. else
  988. $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL'];
  989. break;
  990. case 'DetailView':
  991. $beanName = $this->bean->get_summary_text();
  992. $params[] = $beanName;
  993. break;
  994. }
  995. }
  996. return $params;
  997. }
  998. /**
  999. * Returns the portion of the array that will represent the listview in the breadcrumb
  1000. *
  1001. * @param bool $browserTitle true if the returned string is being used for the browser title, meaning
  1002. * there should be no HTML in the string
  1003. * @return string
  1004. */
  1005. protected function _getModuleTitleListParam( $browserTitle = false )
  1006. {
  1007. global $current_user;
  1008. global $app_strings;
  1009. if(!empty($GLOBALS['app_list_strings']['moduleList'][$this->module]))
  1010. $firstParam = $GLOBALS['app_list_strings']['moduleList'][$this->module];
  1011. else
  1012. $firstParam = $this->module;
  1013. $iconPath = $this->getModuleTitleIconPath($this->module);
  1014. if($this->action == "ListView" || $this->action == "index") {
  1015. if (!empty($iconPath) && !$browserTitle) {
  1016. if (SugarThemeRegistry::current()->directionality == "ltr") {
  1017. return "<a href='index.php?module={$this->module}&action=index'>"
  1018. . "<img src='{$iconPath}' alt='".$this->module."' title='".$this->module."' align='absmiddle'></a>"
  1019. . $this->getBreadCrumbSymbol().$app_strings['LBL_SEARCH'];
  1020. } else {
  1021. return $app_strings['LBL_SEARCH'].$this->getBreadCrumbSymbol()
  1022. . "<a href='index.php?module={$this->module}&action=index'>"
  1023. . "<img src='{$iconPath}' alt='".$this->module."' title='".$this->module."' align='absmiddle'></a>";
  1024. }
  1025. } else {
  1026. return $firstParam;
  1027. }
  1028. }
  1029. else {
  1030. if (!empty($iconPath) && !$browserTitle) {
  1031. return "<a href='index.php?module={$this->module}&action=index'>"
  1032. . "<img src='{$iconPath}' alt='".$this->module."' title='".$this->module."' align='absmiddle'></a>";
  1033. } else {
  1034. return "{$firstParam}";
  1035. }
  1036. }
  1037. }
  1038. protected function getModuleTitleIconPath($module)
  1039. {
  1040. $iconPath = "";
  1041. if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) {
  1042. $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png');
  1043. }
  1044. else if (is_file(SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png',false))) {
  1045. $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png');
  1046. }
  1047. return $iconPath;
  1048. }
  1049. /**
  1050. * Returns the string which will be shown in the browser's title; defaults to using the same breadcrumb
  1051. * as in the module title
  1052. *
  1053. * @return string
  1054. */
  1055. public function getBrowserTitle()
  1056. {
  1057. global $app_strings;
  1058. $browserTitle = $app_strings['LBL_BROWSER_TITLE'];
  1059. if ( $this->module == 'Users' && ($this->action == 'SetTimezone' || $this->action == 'Login') )
  1060. return $browserTitle;
  1061. $params = $this->_getModuleTitleParams(true);
  1062. foreach ($params as $value )
  1063. $browserTitle = strip_tags($value) . ' &raquo; ' . $browserTitle;
  1064. return $browserTitle;
  1065. }
  1066. /**
  1067. * Returns the correct breadcrumb symbol according to theme's directionality setting
  1068. *
  1069. * @return string
  1070. */
  1071. public function getBreadCrumbSymbol()
  1072. {
  1073. if(SugarThemeRegistry::current()->directionality == "ltr") {
  1074. return "<span class='pointer'>&raquo;</span>";
  1075. }
  1076. else {
  1077. return "<span class='pointer'>&laquo;</span>";
  1078. }
  1079. }
  1080. }