rewrite in 12/2006 * @author Pim Snel author of the idots template set * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package api * @subpackage framework * @access public * @version $Id$ */ /** * eGW API - framework: virtual base class for all template sets * * This class creates / renders the eGW framework: * a) html header * b) navbar * c) sidebox menu * d) main application area * e) footer * It replaces several methods in the common class and the diverse templates. * * Existing apps either set $GLOBALS['egw_info']['flags']['noheader'] and call common::egw_header() and * (if $GLOBALS['egw_info']['flags']['nonavbar'] is true) parse_navbar() or it's done by the header.inc.php include. * The app's hook_sidebox then calls the public function display_sidebox(). * And the app calls common::egw_footer(). * * This are the authors (and their copyrights) of the original egw_header, egw_footer methods of the common class: * This file written by Dan Kuykendall * and Joseph Engo * and Mark Peters * and Lars Kneschke * Copyright (C) 2000, 2001 Dan Kuykendall * Copyright (C) 2003 Lars Kneschke */ abstract class egw_framework { /** * Name of the template set, eg. 'idots' * * @var string */ var $template; /** * true if $this->header() was called * * @var boolean */ static $header_done = false; /** * true if $this->navbar() was called * * @var boolean */ static $navbar_done = false; /** * Constructor * * The constructor instanciates the class in $GLOBALS['egw']->framework, from where it should be used * * @return egw_framework */ function egw_framework($template) { $this->template = $template; if (!isset($GLOBALS['egw']->framework)) { $GLOBALS['egw']->framework = $this; } } /** * Renders an applicaton page with the complete eGW framework (header, navigation and menu) * * This is the (new) prefered way to render a page in eGW! * * @param string $content html of the main application area * @param string $app_header=null application header, default what's set in $GLOBALS['egw_info']['flags']['app_header'] * @param string $navbar=null show the navigation, default !$GLOBALS['egw_info']['flags']['nonavbar'], false gives a typical popu * */ function render($content,$app_header=null,$navbar=null) { if (!is_null($app_header)) $GLOBALS['egw_info']['flags']['app_header'] = $app_header; if (!is_null($navbar)) $GLOBALS['egw_info']['flags']['nonavbar'] = !$navbar; echo $this->header(); if (!isset($GLOBALS['egw_info']['flags']['nonavbar']) || !$GLOBALS['egw_info']['flags']['nonavbar']) { echo $this->navbar(); } echo $content; echo $this->footer(); } /** * Returns the html-header incl. the opening body tag * * @return string with html */ abstract function header(); /** * Returns the html from the body-tag til the main application area (incl. opening div tag) * * @return string with html */ abstract function navbar(); /** * Returns the content of one sidebox * * @param string $appname * @param string $menu_title * @param array $file */ abstract function sidebox($appname,$menu_title,$file); /** * Returns the html from the closing div of the main application area to the closing html-tag * * @return string */ abstract function footer(); /** * displays a login screen * * @string $extra_vars for login url * @return string */ abstract function login_screen($extra_vars); /** * displays a login denied message * * @return string */ abstract function denylogin_screen(); /** * Get footer as array to eg. set as vars for a template (from idots' head.inc.php) * * @return array */ protected function _get_footer() { $var = Array( 'img_root' => $GLOBALS['egw_info']['server']['webserver_url'] . '/phpgwapi/templates/'.$this->template.'/images', 'version' => $GLOBALS['egw_info']['server']['versions']['phpgwapi'] ); if($GLOBALS['egw_info']['user']['preferences']['common']['show_generation_time']) { $totaltime = sprintf('%4.2lf',microtime(true) - $GLOBALS['egw_info']['flags']['page_start_time']); $var['page_generation_time'] = '

'.lang('Page was generated in %1 seconds',$totaltime); if ($GLOBALS['egw_info']['flags']['session_restore_time']) { $var['page_generation_time'] .= ' '.lang('(session restored in %1 seconds)', sprintf('%4.2lf',$GLOBALS['egw_info']['flags']['session_restore_time'])); } $var['page_generation_time'] .= '
'; } $var['powered_by'] = lang('Powered by').' Stylite\'s'. ' EGroupware'. ' Community Version '.$GLOBALS['egw_info']['server']['versions']['phpgwapi']; return $var; } /** * Get the (depricated) application footer * * @return string html */ protected static function _get_app_footer() { ob_start(); // Include the apps footer files if it exists if (EGW_APP_INC != EGW_API_INC && // this prevents an endless inclusion on the homepage // (some apps set currentapp in hook_home => it's not releyable) (file_exists (EGW_APP_INC . '/footer.inc.php') || isset($_GET['menuaction'])) && $GLOBALS['egw_info']['flags']['currentapp'] != 'home' && $GLOBALS['egw_info']['flags']['currentapp'] != 'login' && $GLOBALS['egw_info']['flags']['currentapp'] != 'logout' && !@$GLOBALS['egw_info']['flags']['noappfooter']) { list($app,$class,$method) = explode('.',(string)$_GET['menuaction']); if ($class && is_object($GLOBALS[$class]) && is_array($GLOBALS[$class]->public_functions) && isset($GLOBALS[$class]->public_functions['footer'])) { $GLOBALS[$class]->footer(); } elseif(file_exists(EGW_APP_INC.'/footer.inc.php')) { include(EGW_APP_INC . '/footer.inc.php'); } } $content = ob_get_contents(); ob_end_clean(); return $content; } /** * Get header as array to eg. set as vars for a template (from idots' head.inc.php) * * @return array */ protected function _get_header() { // get used language code (with a little xss check, if someone tries to sneak something in) if (preg_match('/^[a-z]{2}(-[a-z]{2})?$/',$GLOBALS['egw_info']['user']['preferences']['common']['lang'])) { $lang_code = $GLOBALS['egw_info']['user']['preferences']['common']['lang']; } // IE specific fixes if (html::$user_agent == 'msie') { // tell IE to use it's own mode, not old compatibility modes (set eg. via group policy for all intranet sites) // has to be before any other header tags, but meta and title!!! $pngfix = ''."\n"; // pngfix for IE6 defaults to yes if(!$GLOBALS['egw_info']['user']['preferences']['common']['disable_pngfix'] && html::$ua_version < 7) { $pngfix_src = $GLOBALS['egw_info']['server']['webserver_url'] . '/phpgwapi/templates/idots/js/pngfix.js'; $pngfix .= ' '; } } if(!$GLOBALS['egw_info']['user']['preferences']['common']['disable_slider_effects']) { $slider_effects_src = $GLOBALS['egw_info']['server']['webserver_url'] . '/phpgwapi/templates/idots/js/slidereffects.js'; $slider_effects = ''; } else { $simple_show_hide_src = $GLOBALS['egw_info']['server']['webserver_url'] . '/phpgwapi/templates/idots/js/simple_show_hide.js'; $simple_show_hide = ''; } if ($GLOBALS['egw_info']['flags']['app_header']) { $app = $GLOBALS['egw_info']['flags']['app_header']; } else { $app = $GLOBALS['egw_info']['flags']['currentapp']; $app = isset($GLOBALS['egw_info']['apps'][$app]) ? $GLOBALS['egw_info']['apps'][$app]['title'] : lang($app); } if($app!='wiki') $robots =''; if (substr($GLOBALS['egw_info']['server']['favicon_file'],0,4) == 'http') { $var['favicon_file'] = $GLOBALS['egw_info']['server']['favicon_file']; } else { $var['favicon_file'] = common::image('phpgwapi',$GLOBALS['egw_info']['server']['favicon_file']?$GLOBALS['egw_info']['server']['favicon_file']:'favicon.ico'); } if ($GLOBALS['egw_info']['flags']['include_wz_tooltip'] && file_exists(EGW_SERVER_ROOT.($wz_tooltip = '/phpgwapi/js/wz_tooltip/wz_tooltip.js'))) { $include_wz_tooltip = ''; } return $this->_get_css()+array( 'img_icon' => $var['favicon_file'], 'img_shortcut' => $var['favicon_file'], 'pngfix' => $pngfix, 'slider_effects' => $slider_effects, 'simple_show_hide' => $simple_show_hide, 'lang_code' => $lang_code, 'charset' => translation::charset(), 'website_title' => strip_tags($GLOBALS['egw_info']['server']['site_title']. ($app ? " [$app]" : '')), 'body_tags' => self::_get_body_attribs(), 'java_script' => self::_get_js(), 'meta_robots' => $robots, 'dir_code' => lang('language_direction_rtl') != 'rtl' ? '' : ' dir="rtl"', 'include_wz_tooltip'=> $include_wz_tooltip, ); } /** * Get navbar as array to eg. set as vars for a template (from idots' navbar.inc.php) * * @param array $apps navbar apps from _get_navbar_apps * @return array */ protected function _get_navbar($apps) { $var['img_root'] = $GLOBALS['egw_info']['server']['webserver_url'] . '/phpgwapi/templates/'.$this->template.'/images'; if(isset($GLOBALS['egw_info']['flags']['app_header'])) { $var['current_app_title'] = $GLOBALS['egw_info']['flags']['app_header']; } else { $var['current_app_title']=$apps[$GLOBALS['egw_info']['flags']['currentapp']]['title']; } $var['currentapp'] = $GLOBALS['egw_info']['flags']['currentapp']; // current users for admins $var['current_users'] = $this->_current_users(); // quick add selectbox $var['quick_add'] = $this->_get_quick_add(); $var['user_info'] = $this->_user_time_info(); if($GLOBALS['egw_info']['user']['lastpasswd_change'] == 0) { $api_messages = lang('You are required to change your password during your first login').'
'. lang('Click this image on the navbar: %1',''); } elseif($GLOBALS['egw_info']['user']['lastpasswd_change'] < time() - (86400*30)) { $api_messages = lang('it has been more then %1 days since you changed your password',30); } // This is gonna change if(isset($cd)) { $var['messages'] = $api_messages . '
' . checkcode($cd); } if (substr($GLOBALS['egw_info']['server']['login_logo_file'],0,4) == 'http') { $var['logo_file'] = $GLOBALS['egw_info']['server']['login_logo_file']; } else { $var['logo_file'] = common::image('phpgwapi',$GLOBALS['egw_info']['server']['login_logo_file']?$GLOBALS['egw_info']['server']['login_logo_file']:'logo'); } $var['logo_url'] = $GLOBALS['egw_info']['server']['login_logo_url']?$GLOBALS['egw_info']['server']['login_logo_url']:'http://www.eGroupWare.org'; if (substr($var['logo_url'],0,4) != 'http') { $var['logo_url'] = 'http://'.$var['logo_url']; } $var['logo_title'] = $GLOBALS['egw_info']['server']['login_logo_title']?$GLOBALS['egw_info']['server']['login_logo_title']:'www.eGroupWare.org'; return $var; } /** * Returns html with user and time * * @return void */ protected static function _user_time_info() { $now = new egw_time(); $user_info = ''.common::display_fullname() .''. ' - ' . lang($now->format('l')) . ' ' . $now->format(true); $user_tzs = egw_time::getUserTimezones(); if (count($user_tzs) > 1) { $tz = $GLOBALS['egw_info']['user']['preferences']['common']['tz']; $user_info .= html::form(html::select('tz',$tz,$user_tzs,true,' onchange="this.form.submit();"'),array(), '/index.php','','tz_selection',' style="display: inline;"','GET'); } return $user_info; } /** * Prepare the current users * * @return string */ protected static function _current_users() { if( $GLOBALS['egw_info']['user']['apps']['admin'] && $GLOBALS['egw_info']['user']['preferences']['common']['show_currentusers']) { $current_users = '' . lang('Current users') . ': ' . $GLOBALS['egw']->session->session_count() . ''; return $current_users; } } /** * Prepare the quick add selectbox * * @return string */ protected static function _get_quick_add() { $apps = egw_link::app_list('add'); asort($apps); // sort them alphabetic $options = array(lang('Add').' ...'); foreach($apps as $app => $label) { $link = egw::link('/index.php',egw_link::add($app,$GLOBALS['egw_info']['flags']['currentapp'],$GLOBALS['egw_info']['flags']['currentid'])+ (is_array($GLOBALS['egw_info']['flags']['quick_add']) ? $GLOBALS['egw_info']['flags']['quick_add'] : array())); if (($popup = egw_link::is_popup($app,'add'))) { list($w,$h) = explode('x',$popup); $action = "window.open('$link','_blank','width='+$w+',height='+$h+',location=no,menubar=no,toolbar=no,scrollbars=yes,status=yes');"; } else { $action = "location.href = '$link';"; } $options[$action] = $label; } return html::select('quick_add','',$options,true,$options=' onchange="eval(this.value); this.value=0; return false;"'); } /** * Prepare notification signal (blinking bell) * * @return string */ protected static function _get_notification_bell() { return html::div( html::a_href( html::image('notifications','notificationbell',lang('notifications')), 'javascript: egwpopup_display();' ), 'id="notificationbell"', // options '', // class 'display: none' //style ); } /** * Get the link to an application's index page * * @param string $app * @return string */ public static function index($app) { $data =& $GLOBALS['egw_info']['user']['apps'][$app]; if (!isset($data)) { throw new egw_exception_wrong_parameter("'$app' not a valid app for this user!"); } $index = '/'.$app.'/index.php'; if (isset($data['index'])) { if ($data['index'][0] == '/') { $index = $data['index']; } else { $index = '/index.php?menuaction='.$data['index']; } } return egw::link($index,$GLOBALS['egw_info']['flags']['params'][$app]); } /** * Prepare an array with apps used to render the navbar * * This is similar to the former common::navbar() method - though it returns the vars and does not place them in global scope. * * @return array */ protected static function _get_navbar_apps() { list($first) = each($GLOBALS['egw_info']['user']['apps']); if(is_array($GLOBALS['egw_info']['user']['apps']['admin']) && $first != 'admin') { $newarray['admin'] = $GLOBALS['egw_info']['user']['apps']['admin']; foreach($GLOBALS['egw_info']['user']['apps'] as $index => $value) { if($index != 'admin') { $newarray[$index] = $value; } } $GLOBALS['egw_info']['user']['apps'] = $newarray; reset($GLOBALS['egw_info']['user']['apps']); } unset($index); unset($value); unset($newarray); $apps = array(); foreach($GLOBALS['egw_info']['user']['apps'] as $app => $data) { if (is_long($app)) { continue; } if ($app == 'preferences' || $GLOBALS['egw_info']['apps'][$app]['status'] != 2 && $GLOBALS['egw_info']['apps'][$app]['status'] != 3) { $apps[$app]['title'] = $GLOBALS['egw_info']['apps'][$app]['title']; $apps[$app]['url'] = self::index($app); $apps[$app]['name'] = $app; // create popup target if ($data['status'] == 4) { $apps[$app]['target'] = ' target="'.$app.'" onClick="'."if (this != '') { window.open(this+'". (strpos($apps[$app]['url'],'?') !== false ? '&' : '?'). "referer='+encodeURIComponent(location),this.target,'width=800,height=600,scrollbars=yes,resizable=yes'); return false; } else { return true; }".'"'; } elseif(isset($GLOBALS['egw_info']['flags']['navbar_target']) && $GLOBALS['egw_info']['flags']['navbar_target']) { $apps[$app]['target'] = 'target="' . $GLOBALS['egw_info']['flags']['navbar_target'] . '"'; } else { $apps[$app]['target'] = ''; } $icon = isset($data['icon']) ? $data['icon'] : 'navbar'; $icon_app = isset($data['icon_app']) ? $data['icon_app'] : $app; if ($app != $GLOBALS['egw_info']['flags']['currentapp']) { $apps[$app]['icon'] = common::image($icon_app,Array($icon,'nonav')); $apps[$app]['icon_hover'] = common::image_on($icon_app,Array($icon,'nonav'),'-over'); } else { $apps[$app]['icon'] = common::image_on($icon_app,Array($icon,'nonav'),'-over'); $apps[$app]['icon_hover'] = common::image($icon_app,Array($icon,'nonav')); } } } if ($GLOBALS['egw_info']['flags']['currentapp'] == 'preferences' || $GLOBALS['egw_info']['flags']['currentapp'] == 'about') { $app = $app_title = 'eGroupWare'; } else { $app = $GLOBALS['egw_info']['flags']['currentapp']; $app_title = $GLOBALS['egw_info']['apps'][$app]['title']; } if ($GLOBALS['egw_info']['user']['apps']['preferences']) // preferences last { $prefs = $apps['preferences']; unset($apps['preferences']); $apps['preferences'] = $prefs; } // We handle this here becuase its special $apps['about']['title'] = lang('About %1',$app_title); $apps['about']['url'] = egw::link('/about.php','app='.$app); $apps['about']['icon'] = common::image('phpgwapi',Array('about','nonav')); $apps['about']['icon_hover'] = common::image_on('phpgwapi',Array('about','nonav'),'-over'); $apps['logout']['title'] = lang('Logout'); $apps['logout']['url'] = egw::link('/logout.php'); $apps['logout']['icon'] = common::image('phpgwapi',Array('logout','nonav')); $apps['logout']['icon_hover'] = common::image_on('phpgwapi',Array('logout','nonav'),'-over'); return $apps; } /** * Used by template headers for including CSS in the header * * 'app_css' - css styles from a) the menuaction's css-method and b) the $GLOBALS['egw_info']['flags']['css'] * 'file_css' - link tag of the app.css file of the current app * 'theme_css' - url of the theme css file * 'print_css' - url of the print css file * * @author Dave Hall (*based* on verdilak? css inclusion code) * @return array with keys 'app_css' from the css method of the menuaction-class and 'file_css' (app.css file of the application) */ public function _get_css() { $app_css = ''; if(isset($_GET['menuaction'])) { list($app,$class,$method) = explode('.',$_GET['menuaction']); if(is_array($GLOBALS[$class]->public_functions) && $GLOBALS[$class]->public_functions['css']) { error_log("Deprecated functionality in $app class $class: using of public_function css, use \$GLOBALS['egw_info']['flags']['css'] or an app.css file!"); $app_css .= $GLOBALS[$class]->css(); } } if (isset($GLOBALS['egw_info']['flags']['css'])) { $app_css .= $GLOBALS['egw_info']['flags']['css']; } // search for app specific css file if(@isset($GLOBALS['egw_info']['flags']['currentapp'])) { $appname = $GLOBALS['egw_info']['flags']['currentapp']; $css_file = '/'.$appname.'/templates/'.$GLOBALS['egw_info']['server']['template_set'].'/app.css'; if (!file_exists(EGW_SERVER_ROOT.$css_file)) { $css_file = '/'.$appname.'/templates/default/app.css'; if (!file_exists(EGW_SERVER_ROOT.$css_file)) $css_file = ''; } if($css_file) { $css_file = ''; } } #_debug_array($GLOBALS['egw_info']['user']['preferences']['common']); $theme_css = '/phpgwapi/templates/'.$this->template.'/css/'.$GLOBALS['egw_info']['user']['preferences']['common']['theme'].'.css'; if(!file_exists(EGW_SERVER_ROOT.$theme_css)) { $theme_css = '/phpgwapi/templates/'.$this->template.'/css/'.$this->template.'.css'; } $theme_css = $GLOBALS['egw_info']['server']['webserver_url'] . $theme_css .'?'.filemtime(EGW_SERVER_ROOT.$theme_css); $print_css = '/phpgwapi/templates/'.$this->template.'/print.css'; if(!file_exists(EGW_SERVER_ROOT.$print_css)) { $print_css = '/phpgwapi/templates/idots/print.css'; } $print_css = $GLOBALS['egw_info']['server']['webserver_url'] . $print_css .'?'.filemtime(EGW_SERVER_ROOT.$print_css); return array( 'app_css' => $app_css, 'css_file' => $css_file, 'theme_css' => $theme_css, 'print_css' => $print_css, ); } /** * Used by the template headers for including javascript in the header * * The method is included here to make it easier to change the js support * in eGW. One change then all templates will support it (as long as they * include a call to this method). * * @author Dave Hall (*vaguely based* on verdilak? css inclusion code) * @return string the javascript to be included */ public static function _get_js() { $java_script = ''; // always include javascript helper functions $GLOBALS['egw']->js->validate_file('jsapi','jsapi'); // GLOBAL var to tell egroupware wether or not to enable the IE selectBox resize hack if($GLOBALS['egw_info']['user']['preferences']['common']['enable_ie_dropdownmenuhack'] && html::$user_agent == 'msie' && html::$ua_version < 9) { $java_script .= "\n"; } //viniciuscb: in Concisus this condition is inexistent, and in all //pages the javascript globals are inserted. Today, because //filescenter needs these javascript globals, this //include_jsbackend is a must to the javascript globals be //included. if ($GLOBALS['egw_info']['flags']['include_jsbackend']) { if (!$GLOBALS['egw_info']['flags']['nojsapi']) { $GLOBALS['egw']->js->validate_jsapi(); } if(@is_object($GLOBALS['egw']->js)) { $java_script .= $GLOBALS['egw']->js->get_javascript_globals(); } } if ($GLOBALS['egw']->acl->check('run',1,'notifications') && !$GLOBALS['egw_info']['user']['preferences']['notifications']['disable_ajaxpopup']) { $GLOBALS['egw_info']['flags']['include_xajax'] = true; } if ($GLOBALS['egw_info']['flags']['include_xajax']) { require_once(EGW_API_INC.'/xajax/xajax_core/xajax.inc.php'); $xajax = new xajax(); $xajax->configure('requestURI', egw::link('/xajax.php')); $xajax->configure('javascript URI',$GLOBALS['egw_info']['server']['webserver_url'] . '/phpgwapi/inc/xajax'); $xajax->configure('waitCursor',false); $xajax->register(XAJAX_FUNCTION,'doXMLHTTP'); $xajax->register(XAJAX_FUNCTION,'doXMLHTTP',array('mode' => "'synchronous'",'alias' => 'doXMLHTTPsync')); $java_script .= $xajax->getJavascript(); } /* this flag is for all javascript code that has to be put before other jscode. Think of conf vars etc... (pim@lingewoud.nl) */ if (isset($GLOBALS['egw_info']['flags']['java_script_thirst'])) { $java_script .= $GLOBALS['egw_info']['flags']['java_script_thirst'] . "\n"; } if(@is_object($GLOBALS['egw']->js)) { $java_script .= $GLOBALS['egw']->js->get_script_links(); } if(@isset($_GET['menuaction'])) { list($app,$class,$method) = explode('.',$_GET['menuaction']); if(is_array($GLOBALS[$class]->public_functions) && $GLOBALS[$class]->public_functions['java_script']) { $java_script .= $GLOBALS[$class]->java_script(); } } if (isset($GLOBALS['egw_info']['flags']['java_script'])) { $java_script .= $GLOBALS['egw_info']['flags']['java_script'] . "\n"; } return $java_script; } /** * Returns on(Un)Load attributes from js class * * @author Dave Hall - skwashd at egroupware.org * @returns string body attributes */ public static function _get_body_attribs() { if(@is_object($GLOBALS['egw']->js)) { return $GLOBALS['egw']->js->get_body_attribs(); } else { return ''; } } } /** * Public functions to be compatible with the exiting eGW framework */ if (!function_exists('parse_navbar')) { /** * echo's out the navbar * * @deprecated use $GLOBALS['egw']->framework::navbar() or $GLOBALS['egw']->framework::render() */ function parse_navbar() { echo $GLOBALS['egw']->framework->navbar(); } } if (!function_exists('display_sidebox')) { /** * echo's out a sidebox menu * * @deprecated use $GLOBALS['egw']->framework::sidebox() */ function display_sidebox($appname,$menu_title,$file) { $GLOBALS['egw']->framework->sidebox($appname,$menu_title,$file); } }