Author: ralfbecker
New Revision: 55974
URL: http://svn.stylite.de/viewvc/egroupware?rev=55974&view=rev
Log:
change Pixelegg template to no longer depend on jdots
Added:
trunk/egroupware/api/src/Framework/Ajax.php
- copied, changed from r55973, trunk/jdots/inc/class.jdots_framework.inc.php
trunk/pixelegg/print.less
- copied, changed from r55973, trunk/pixelegg/print.css
Modified:
trunk/egroupware/Gruntfile.js
trunk/egroupware/api/src/Framework.php
trunk/jdots/inc/class.jdots_framework.inc.php
trunk/jdots/print.css
trunk/jdots/setup/setup.inc.php
trunk/pixelegg/inc/class.pixelegg_framework.inc.php
trunk/pixelegg/print.css
trunk/pixelegg/setup/setup.inc.php
— trunk/egroupware/Gruntfile.js (original)
+++ trunk/egroupware/Gruntfile.js Mon May 2 16:19:34 2016
@@ -286,7 +286,6 @@
“api/templates/default/etemplate2.css”,
“pixelegg/css/pixelegg.css”,
“api/templates/default/print.css”,
@@ -302,7 +301,6 @@
“api/templates/default/etemplate2.css”,
“pixelegg/css/mobile.css”,
“api/templates/default/print.css”,
@@ -318,7 +316,6 @@
“api/templates/default/etemplate2.css”,
“pixelegg/mobile/fw_mobile.css”,
“api/templates/default/print.css”,
— trunk/egroupware/api/src/Framework.php (original)
+++ trunk/egroupware/api/src/Framework.php Mon May 2 16:19:34 2016
@@ -13,9 +13,6 @@
*/
namespace EGroupware\Api;
-// import not yet ported non-namespaced classes
-use jdots_framework;
/**
- Framework: virtual base class for all template sets
@@ -210,7 +207,7 @@
{
throw new Exception\AssertionFailed(METHOD."(’".htmlspecialchars($url)."’) can NOT redirect, output already started at $file line $line!");
}
-
if ($GLOBALS['egw']->framework instanceof Framework\Ajax && !empty($link_app))
{
self::set_extra('egw', 'redirect', array($url, $link_app));
$GLOBALS['egw']->framework->render('');
— trunk/jdots/inc/class.jdots_framework.inc.php (original)
+++ trunk/egroupware/api/src/Framework/Ajax.php Mon May 2 16:19:34 2016
@@ -1,9 +1,10 @@
<?php
/**
- * Stylite: jdots template
+ * EGroupware - Framework for Ajax based templates: jdots & Pixelegg
*
* @link http://www.stylite.de
- * @package jdots
+ * @package api
+ * @subpackage framework
* @author Andreas Stöckel
* @author Ralf Becker
* @author Nathan Gray
@@ -11,21 +12,24 @@
* @version $Id$
*/
+namespace EGroupware\Api\Framework;
+
use EGroupware\Api;
+use EGroupware\Api\Egw;
/**
* Stylite jdots template
*/
-class jdots_framework extends Api\Framework
+abstract class Ajax extends Api\Framework
{
/**
* Appname used to include javascript code
*/
- const JS_INCLUDE_APP = 'jdots';
+ const JS_INCLUDE_APP = '';
/**
* Appname used for everything else
*/
- const APP = 'jdots';
+ const APP = '';
/**
* Minimum width of sidebar eg. from German 2-letter daynames in Calendar
@@ -51,7 +55,7 @@
/**
* Constructor
*
- * @param string $template = 'idots' name of the template
+ * @param string $template = '' name of the template
*/
function __construct($template=self::APP)
{
@@ -170,54 +174,6 @@
}
/**
- * Overwrite to add our customizable colors
- *
- * @see Api\Framework::_get_css()
- * @return array
- */
- public function _get_css()
- {
- $ret = parent::_get_css();
-
- // color to use
- $color = str_replace('custom',$GLOBALS['egw_info']['user']['preferences']['common']['template_custom_color'],
- $GLOBALS['egw_info']['user']['preferences']['common']['template_color']);
- // use active tab or header, beside sidebox
- if (($use_active_tab = $color[0] == '@')) $color = substr($color,1);
-
- if (preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i',$color)) // a little xss check
- {
- $ret['app_css'] .= "
-/**
- * theme changes to color jdots for color: $color
- */
-.egw_fw_ui_sidemenu_entry_header_active, .egw_fw_ui_sidemenu_entry_content, .egw_fw_ui_sidemenu_entry_header:hover {
- background-color: $color;
- border-color: $color;
-}
-.egw_fw_ui_sidemenu_entry_header_active, .egw_fw_ui_sidemenu_entry_header:hover {
- background-image: url(jdots/images/gradient30transparent.png);
-}
-.egw_fw_ui_sidemenu_entry_content {
- background-image: url(jdots/images/gradient10transparent.png);
-}
-div .egw_fw_ui_sidemenu_entry_content > div {
- background-color: #ffffff;
-}".($use_active_tab ? "
-.egw_fw_ui_tab_header_active {
- background-image: url(jdots/images/gradient30transparent.png);
- background-color: $color;
-}
-" : "
-.egw_fw_ui_tabs_header {
- background-image: url(jdots/images/gradient22transparent.png);
- background-color: $color;
-}");
- }
- return $ret;
- }
-
- /**
* Query additional CSP frame-src from current app
*
* We have to query all apps, as we dont reload frameset!
@@ -254,9 +210,9 @@
//error_log(__METHOD__.'('.array2string($extra).') called from:'.function_backtrace());
// the instanciation of the template has to be here and not in the constructor,
- // as the old Template class has problems if restored from the session (php-restore)
+ // as the old template class has problems if restored from the session (php-restore)
// todo: check if this is still true
- $this->tpl = new Api\Framework\Template(EGW_SERVER_ROOT.$this->template_dir);
+ $this->tpl = new Template(EGW_SERVER_ROOT.$this->template_dir);
if (Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile')
{
$this->tpl->set_file(array('_head' => 'head_mobile.tpl'));
@@ -285,7 +241,7 @@
// framework javascript classes only need for framework
if (Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile')
{
- self::includeJS('.', 'fw_mobile', self::JS_INCLUDE_APP);
+ self::includeJS('.', 'fw_mobile', static::JS_INCLUDE_APP);
}
else
{
@@ -337,7 +293,7 @@
{
// logout button
$this->tpl->set_var('title_logout', lang("Logout"));
- $this->tpl->set_var('link_logout', egw::link('/logout.php'));
+ $this->tpl->set_var('link_logout', Egw::link('/logout.php'));
//Print button title
$this->tpl->set_var('title_print', lang("Print current view"));
}
@@ -502,14 +458,14 @@
if (!$this->sidebox_done && self::$header_done)
{
$this->do_sidebox();
- return $header.'
';
+ return $header.'';
}
return $header;
}
/**
- * Set sidebox content in Api\Framework::$data['setSidebox']
+ * Set sidebox content in self::$data['setSidebox']
*
* We store in the session the md5 of each sidebox menu already send to client.
* If the framework get reloaded, that list gets cleared in header();
@@ -538,9 +494,9 @@
if ($md5_session[$app] !== $md5)
{
- //error_log(__METHOD__."() header changed md5_session[$app]!=='$md5' --> setting it on Api\Framework::\$extra[setSidebox]");
+ //error_log(__METHOD__."() header changed md5_session[$app]!=='$md5' --> setting it on self::\$extra[setSidebox]");
$md5_session[$app] = $md5; // update md5 in session
- Api\Framework::$extra['setSidebox'] = array($app, $sidebox, $md5);
+ self::$extra['setSidebox'] = array($app, $sidebox, $md5);
}
//else error_log(__METHOD__."() md5_session[$app]==='$md5' --> nothing to do");
}
@@ -564,14 +520,14 @@
*
* @var array
*/
- private $sideboxes;
+ protected $sideboxes;
/**
* Should calls the first call to self::sidebox create an opened menu
*
* @var boolean
*/
- private $sidebox_menu_opened = true;
+ protected $sidebox_menu_opened = true;
/**
* Callback for sideboxes hooks, collects the data in a private var
@@ -782,7 +738,7 @@
}
/**
- * Stores the user defined sorting of the applications inside the Api\Preferences
+ * Stores the user defined sorting of the applications inside the preferences
*
* @param array $apps
*/
@@ -806,35 +762,6 @@
$GLOBALS['egw']->preferences->read_repository();
$GLOBALS['egw']->preferences->add('common', 'user_apporder', serialize($order));
$GLOBALS['egw']->preferences->save_repository(true);
- }
-
- /**
- * Reads all available remote applications (currently there may only be one)
- * and returns them as an array.
- */
- public function jdots_remote_apps()
- {
- $result = array();
-
- /*if ($GLOBALS['egw_info']['user']['preferences']['common']['remote_application_enabled'])
- {
- $name = $GLOBALS['egw_info']['user']['preferences']['common']['remote_application_name'];
- $title = $GLOBALS['egw_info']['user']['preferences']['common']['remote_application_title'];
- $url = $GLOBALS['egw_info']['user']['preferences']['common']['remote_application_url'];
-
- $result[$name.'_remote'] = array(
- 'name' => $name.'_remote',
- 'sideboxwidth' => false,
- 'target' => false,
- 'title' => $title,
- 'icon' => "/egroupware/trunk/egroupware/".$name."/templates/default/images/navbar.png", //TODO: Check whether icon exists
- 'baseUrl' => $url,
- 'url' => $url.$name.'/index.php',
- 'internalName' => $name,
- );
- }*/
-
- return $result;
}
/**
@@ -853,7 +780,6 @@
public function navbar_apps()
{
$apps = parent::_get_navbar_apps(Api\Image::svg_usable()); // use svg if usable in browser
- //$apps += $this->jdots_remote_apps(); currently not used/usable
//Add its sidebox width to each app
foreach ($apps as $app => &$data)
Modified: trunk/jdots/inc/class.jdots_framework.inc.php
URL: http://svn.stylite.de/viewvc/egroupware/trunk/jdots/inc/class.jdots_framework.inc.php?rev=55974&r1=55973&r2=55974&view=diff
==============================================================================
--- trunk/jdots/inc/class.jdots_framework.inc.php (original)
+++ trunk/jdots/inc/class.jdots_framework.inc.php Mon May 2 16:19:34 2016
@@ -16,7 +16,7 @@
/**
* Stylite jdots template
*/
-class jdots_framework extends Api\Framework
+class jdots_framework extends Api\Framework\Ajax
{
/**
* Appname used to include javascript code
@@ -28,145 +28,17 @@
const APP = 'jdots';
/**
- * Minimum width of sidebar eg. from German 2-letter daynames in Calendar
- * or Calendar's navigation buttons need to be seen
- *
- * Need to be changed in js/fw_[template].js.
- */
- const MIN_SIDEBAR_WIDTH = 245;
- /**
- * Default width need to be tested with English 3-letter day-names and Pixelegg template in Calendar
- *
- * Need to be changed in js/egw_fw.js around line 1536 too!
- */
- const DEFAULT_SIDEBAR_WIDTH = 255;
- /**
- * Whether javascript:egw_link_handler calls (including given app) should be returned by the "link" function
- * or just the link
- *
- * @var string
- */
- private static $link_app;
-
- /**
* Constructor
*
- * @param string $template = 'idots' name of the template
+ * Overwritten to set own app/template name (parent can NOT use static::APP!)
+ *
+ * @param string $template ='pixelegg' name of the template
*/
function __construct($template=self::APP)
{
parent::__construct($template); // call the constructor of the extended class
$this->template_dir = '/'.$template; // we are packaged as an application
- }
-
- /**
- * Check if current user agent is supported
- *
- * Currently we do NOT support:
- * - iPhone, iPad, Android, SymbianOS due to iframe scrolling problems of Webkit
- * - IE < 7
- *
- * @return boolean
- */
- public static function is_supported_user_agent()
- {
- if (Api\Header\UserAgent::type() == 'msie' && Api\Header\UserAgent::version() < 7)
- {
- return false;
- }
- return true;
- }
-
- /**
- * Reads an returns the width of the sidebox or false if the width is not set
- */
- private static function get_sidebar_width($app)
- {
- $width = self::DEFAULT_SIDEBAR_WIDTH;
-
- //Check whether the width had been stored explicitly for the jdots template, use that value
- if ($GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth'])
- {
- $width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth'];
-// error_log(__METHOD__.__LINE__."($app):$width --> reading jdotssideboxwidth");
- }
- //Otherwise use the legacy "idotssideboxwidth" value
- else if ($GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth'])
- {
- $width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth'];
-// error_log(__METHOD__.__LINE__."($app):$width --> reading idotssideboxwidth");
- }
-
- //Width may not be smaller than MIN_SIDEBAR_WIDTH
- if ($width < self::MIN_SIDEBAR_WIDTH)
- $width = self::MIN_SIDEBAR_WIDTH;
-
- return $width;
- }
-
- /**
- * Returns the global width of the sidebox. If the app_specific_sidebar_width had been switched
- * on, the default width will be returned
- */
- private static function get_global_sidebar_width()
- {
- return self::DEFAULT_SIDEBAR_WIDTH;
- }
-
-
-
- /**
- * Extract applicaton name from given url (incl. GET parameters)
- *
- * @param string $url
- * @return string appname or NULL if it could not be detected (eg. constructing javascript urls)
- */
- public static function app_from_url($url)
- {
- $matches = null;
- if (preg_match('/menuaction=([a-z0-9_-]+)\./i',$url,$matches))
- {
- return $matches[1];
- }
- if ($GLOBALS['egw_info']['server']['webserver_url'] &&
- ($webserver_path = parse_url($GLOBALS['egw_info']['server']['webserver_url'],PHP_URL_PATH)))
- {
- list(,$url) = explode($webserver_path, parse_url($url,PHP_URL_PATH),2);
- }
- if (preg_match('/\/([^\/]+)\/([^\/]+\.php)?(\?|\/|$)/',$url,$matches))
- {
- return $matches[1];
- }
- //error_log(__METHOD__."('$url') could NOT detect application!");
- return null;
- }
-
- /**
- * Link url generator
- *
- * @param string $url The url the link is for
- * @param string|array $extravars Extra params to be passed to the url
- * @param string $link_app = null if appname or true, some templates generate a special link-handler url
- * @return string The full url after processing
- */
- static function link($url = '', $extravars = '', $link_app=null)
- {
- if (is_null($link_app)) $link_app = self::$link_app;
- $link = parent::link($url, $extravars);
-
- // $link_app === true --> detect application, otherwise use given application
- if ($link_app && (is_string($link_app) || ($link_app = self::app_from_url($link))))
- {
- // Link gets handled in JS, so quotes need slashes as well as url-encoded
- // encoded ampersands in get parameters (%26) need to be encoded twise,
- // so they are still encoded when assigned to window.location
- $link_with_slashes = str_replace(array('%27','%26'), array('\%27','%2526'), $link);
-
- //$link = "javascript:window.egw_link_handler?egw_link_handler('$link','$link_app'):parent.egw_link_handler('$link','$link_app');";
- $link = "javascript:egw_link_handler('$link_with_slashes','$link_app')";
- }
- return $link;
}
/**
@@ -216,883 +88,4 @@
}
return $ret;
}
-
- /**
- * Query additional CSP frame-src from current app
- *
- * We have to query all apps, as we dont reload frameset!
- *
- * @return array
- */
- protected function _get_csp_frame_src()
- {
- $srcs = array();
- foreach(Api\Hooks::process('csp-frame-src') as $src)
- {
- if ($src) $srcs = array_merge($srcs, $src);
- }
- return $srcs;
- }
-
- /**
- * Returns the html-header incl. the opening body tag
- *
- * @param array $extra = array() extra attributes passed as data-attribute to egw.js
- * @return string with Api\Html
- */
- function header(array $extra=array())
- {
- // make sure header is output only once
- if (self::$header_done) return '';
- self::$header_done = true;
-
- $this->send_headers();
-
- // catch error echo'ed before the header, ob_start'ed in the header.inc.php
- $content = ob_get_contents();
- ob_end_clean();
- //error_log(__METHOD__.'('.array2string($extra).') called from:'.function_backtrace());
-
- // the instanciation of the template has to be here and not in the constructor,
- // as the old Template class has problems if restored from the session (php-restore)
- // todo: check if this is still true
- $this->tpl = new Api\Framework\Template(EGW_SERVER_ROOT.$this->template_dir);
- if (Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile')
- {
- $this->tpl->set_file(array('_head' => 'head_mobile.tpl'));
- }
- else
- {
- $this->tpl->set_file(array('_head' => 'head.tpl'));
- }
- $this->tpl->set_block('_head','head');
- $this->tpl->set_block('_head','framework');
-
- // should we draw the framework, or just a header
- $do_framework = isset($_GET['cd']) && $_GET['cd'] === 'yes';
-
- // load clientside link registry to framework only
- if (!isset($GLOBALS['egw_info']['flags']['js_link_registry']))
- {
- $GLOBALS['egw_info']['flags']['js_link_registry'] = $do_framework;
- }
- // Loader
- $this->tpl->set_var('loader_text', lang('please wait...'));
-
- if ($do_framework)
- {
- //echo __METHOD__.__LINE__.' do framework ...'.'
';
- // framework javascript classes only need for framework
- if (Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile')
- {
- self::includeJS('.', 'fw_mobile', self::JS_INCLUDE_APP);
- }
- else
- {
- self::includeJS('.', 'fw_'.static::APP, static::JS_INCLUDE_APP);
- }
- Api\Cache::unsetSession(__CLASS__,'sidebox_md5'); // sideboxes need to be send again
-
- $extra['navbar-apps'] = $this->get_navbar_apps($_SERVER['REQUEST_URI']);
- }
- // for an url WITHOUT cd=yes --> load framework if not yet loaded:
- // - if top has framework object, we are all right
- // - if not we need to check if we have an opener (are a popup window)
- // - as popups can open further popups, we need to decend all the way down until we find a framework
- // - only if we cant find a framework in all openers, we redirect to create a new framework
- if(!$do_framework)
- {
- // fetch sidebox from application and set it in extra data, if we are no popup
- if (!$GLOBALS['egw_info']['flags']['nonavbar'])
- {
- $this->do_sidebox();
- }
- // for remote manual never check/create framework
- if (!in_array($GLOBALS['egw_info']['flags']['currentapp'], array('manual', 'login', 'logout', 'sitemgr')))
- {
- if (empty($GLOBALS['egw_info']['flags']['java_script'])) $GLOBALS['egw_info']['flags']['java_script']='';
- $extra['check-framework'] = $_GET['cd'] !== 'no';
- }
- }
- $this->tpl->set_var($this->_get_header($extra));
- $content = $this->tpl->fp('out','head').$content;
-
- if (!$do_framework)
- {
- return $content;
- }
-
- // topmenu
- $vars = $this->_get_navbar($apps = $this->_get_navbar_apps());
- $this->tpl->set_var($this->topmenu($vars,$apps));
-
- // hook after_navbar (eg. notifications)
- $this->tpl->set_var('hook_after_navbar',$this->_get_after_navbar());
-
- //Global sidebar width
- $this->tpl->set_var('sidebox_width', self::get_global_sidebar_width());
- $this->tpl->set_var('sidebox_min_width', self::MIN_SIDEBAR_WIDTH);
-
- if (!(Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile'))
- {
- // logout button
- $this->tpl->set_var('title_logout', lang("Logout"));
- $this->tpl->set_var('link_logout', egw::link('/logout.php'));
- //Print button title
- $this->tpl->set_var('title_print', lang("Print current view"));
- }
-
- // add framework div's
- $this->tpl->set_var($this->_get_footer());
- $content .= $this->tpl->fp('out','framework');
- $content .= self::footer(false);
-
- echo $content;
- exit();
- }
-
- private $topmenu_items;
- private $topmenu_info_items;
-
- /**
- * Compile entries for topmenu:
- * - regular items: links
- * - info items
- *
- * @param array $vars
- * @param array $apps
- * @return array
- */
- function topmenu(array $vars,array $apps)
- {
- $this->topmenu_items = $this->topmenu_info_items = array();
-
- parent::topmenu($vars,$apps);
- $vars['topmenu_items'] = "\n- ".implode("
\n- ",$this->topmenu_items)."
\n
";
- $vars['topmenu_info_items'] = '';
- foreach($this->topmenu_info_items as $id => $item)
- {
- $vars['topmenu_info_items'] .= ''.$item."
\n";
- }
- $this->topmenu_items = $this->topmenu_info_items = null;
-
- return $vars;
- }
-
- /**
- * called by hooks to add an icon in the topmenu info location
- *
- * @param string $id unique element id
- * @param string $icon_src src of the icon image. Make sure this nog height then 18pixels
- * @param string $iconlink where the icon links to
- * @param booleon $blink set true to make the icon blink
- * @param mixed $tooltip string containing the tooltip Api\Html, or null of no tooltip
- * @todo implement in a reasonable way for jdots
- * @return void
- */
- function topmenu_info_icon($id,$icon_src,$iconlink,$blink=false,$tooltip=null)
- {
- unset($id,$icon_src,$iconlink,$blink,$tooltip); // not used
- // not yet implemented, only used in admin/inc/hook_topmenu_info.inc.php to notify about pending updates
- }
-
- /**
- * Add menu items to the topmenu template class to be displayed
- *
- * @param array $app application data
- * @param mixed $alt_label string with alternative menu item label default value = null
- * @param string $urlextra string with alternate additional code inside -tag
- * @access protected
- * @return void
- */
- function _add_topmenu_item(array $app_data,$alt_label=null)
- {
- switch($app_data['name'])
- {
- case 'logout':
- if (Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile')
- {
-
- }
- else
- {
- return; // no need for logout in topmenu on jdots
- }
- break;
-
- case 'manual':
- $app_data['url'] = "javascript:callManual();";
- break;
-
- default:
- if (strpos($app_data['url'],'logout.php') === false && substr($app_data['url'], 0, 11) != 'javascript:')
- {
- $app_data['url'] = "javascript:egw_link_handler('".$app_data['url']."','".
- (isset($GLOBALS['egw_info']['user']['apps'][$app_data['name']]) ?
- $app_data['name'] : 'about')."')";
- }
- }
- $id = $app_data['id'] ? $app_data['id'] : ($app_data['name'] ? $app_data['name'] : $app_data['title']);
- $title = htmlspecialchars($alt_label ? $alt_label : $app_data['title']);
- $this->topmenu_items[] = ''.$title.'';
- }
-
- /**
- * Add info items to the topmenu template class to be displayed
- *
- * @param string $content Api\Html of item
- * @param string $id = null
- * @access protected
- * @return void
- */
- function _add_topmenu_info_item($content, $id=null)
- {
- if(strpos($content,'menuaction=admin.admin_accesslog.sessions') !== false)
- {
- $content = preg_replace('/href="([^"]+)"/',"href=\"javascript:egw_link_handler('\\1','admin')\"",$content);
- }
- if ($id)
- {
- $this->topmenu_info_items[$id] = $content;
- }
- else
- {
- $this->topmenu_info_items[] = $content;
- }
- }
-
- /**
- * Change timezone
- *
- * @param string $tz
- */
- function ajax_tz_selection($tz)
- {
- Api\DateTime::setUserPrefs($tz); // throws exception, if tz is invalid
-
- $GLOBALS['egw']->preferences->read_repository();
- $GLOBALS['egw']->preferences->add('common','tz',$tz);
- $GLOBALS['egw']->preferences->save_repository();
- }
-
- /**
- * Flag if do_sidebox() was called
- *
- * @var boolean
- */
- protected $sidebox_done = false;
-
- /**
- * Returns the Api\Html from the body-tag til the main application area (incl. opening div tag)
- *
- * jDots does NOT use a navbar, but it tells us that application might want a sidebox!
- *
- * @return string
- */
- function navbar()
- {
- $header = '';
- if (!self::$header_done)
- {
- $header = $this->header();
- }
- $GLOBALS['egw_info']['flags']['nonavbar'] = false;
-
- if (!$this->sidebox_done && self::$header_done)
- {
- $this->do_sidebox();
- return $header.'';
- }
-
- return $header;
- }
-
- /**
- * Set sidebox content in Api\Framework::$data['setSidebox']
- *
- * We store in the session the md5 of each sidebox menu already send to client.
- * If the framework get reloaded, that list gets cleared in header();
- * Most apps never change sidebox, so we not even need to generate it more then once.
- */
- function do_sidebox()
- {
- $this->sidebox_done = true;
-
- $app = $GLOBALS['egw_info']['flags']['currentapp'];
-
- // only send admin sidebox, for admin index url (when clicked on admin),
- // not for other admin pages, called eg. from sidebox menu of other apps
- // --> that way we always stay in the app, and NOT open admin sidebox for an app tab!!!
- if ($app == 'admin' && substr($_SERVER['PHP_SELF'],-16) != '/admin/index.php' &&
- $_GET['menuaction'] != 'admin.admin_ui.index')
- {
- //error_log(__METHOD__."() app=$app, menuaction=$_GET[menuaction], PHP_SELF=$_SERVER[PHP_SELF] --> sidebox request ignored");
- return;
- }
- $md5_session =& Api\Cache::getSession(__CLASS__,'sidebox_md5');
-
- //Set the sidebox content
- $sidebox = $this->get_sidebox($app);
- $md5 = md5(json_encode($sidebox));
-
- if ($md5_session[$app] !== $md5)
- {
- //error_log(__METHOD__."() header changed md5_session[$app]!=='$md5' --> setting it on Api\Framework::\$extra[setSidebox]");
- $md5_session[$app] = $md5; // update md5 in session
- Api\Framework::$extra['setSidebox'] = array($app, $sidebox, $md5);
- }
- //else error_log(__METHOD__."() md5_session[$app]==='$md5' --> nothing to do");
- }
-
- /**
- * Return true if we are rendering the top-level EGroupware window
- *
- * A top-level EGroupware window has a navbar: eg. no popup and for a framed template (jdots) only frameset itself
- *
- * @return boolean $consider_navbar_not_yet_called_as_true=true ignored by jdots, we only care for cd=yes GET param
- * @return boolean
- */
- public function isTop($consider_navbar_not_yet_called_as_true=true)
- {
- unset($consider_navbar_not_yet_called_as_true); // not used
- return isset($_GET['cd']) && $_GET['cd'] === 'yes';
- }
-
- /**
- * Array containing sidebox menus by applications and menu-name
- *
- * @var array
- */
- private $sideboxes;
-
- /**
- * Should calls the first call to self::sidebox create an opened menu
- *
- * @var boolean
- */
- private $sidebox_menu_opened = true;
-
- /**
- * Callback for sideboxes hooks, collects the data in a private var
- *
- * @param string $appname
- * @param string $menu_title
- * @param array $file
- * @param string $type = null 'admin', 'preferences', 'favorites', ...
- */
- public function sidebox($appname,$menu_title,$file,$type=null)
- {
- if (!isset($file['menuOpened'])) $file['menuOpened'] = (boolean)$this->sidebox_menu_opened;
- //error_log(__METHOD__."('$appname', '$menu_title', file[menuOpened]=$file[menuOpened], ...) this->sidebox_menu_opened=$this->sidebox_menu_opened");
- $this->sidebox_menu_opened = false;
-
- // fix app admin menus to use admin.admin_ui.index loader
- if (($type == 'admin' || $menu_title == lang('Admin')) && $appname != 'admin')
- {
- $file = preg_replace("/^(javascript:egw_link_handler\(')(.*)menuaction=([^&]+)(.*)(','[^']+'\))$/",
- '$1$2menuaction=admin.admin_ui.index&load=$3$4&ajax=true\',\'admin\')', $file_was=$file);
- }
-
- $this->sideboxes[$appname][$menu_title] = $file;
- }
-
- /**
- * Return sidebox data for an application
- *
- * @param $appname
- * @return array of array(
- * 'menu_name' => (string), // menu name, currently md5(title)
- * 'title' => (string), // translated title to display
- * 'opened' => (boolean), // menu opend or closed
- * 'entries' => array(
- * array(
- * 'lang_item' => translated menu item or Api\Html, i item_link === false
- * 'icon_or_star' => url of bullet images, or false for none
- * 'item_link' => url or false (lang_item contains complete html)
- * 'target' => target attribute fragment, ' target="..."'
- * ),
- * // more entries
- * ),
- * ),
- * array (
- * // next menu
- * )
- */
- public function get_sidebox($appname)
- {
- if (!isset($this->sideboxes[$appname]))
- {
- self::$link_app = $appname;
- // allow other apps to hook into sidebox menu of an app, hook-name: sidebox_$appname
- $this->sidebox_menu_opened = true;
- Api\Hooks::process('sidebox_'.$appname,array($appname),true); // true = call independent of app-permissions
-
- // calling the old hook
- $this->sidebox_menu_opened = true;
- Api\Hooks::single('sidebox_menu',$appname);
- self::$link_app = null;
-
- // allow other apps to hook into sidebox menu of every app: sidebox_all
- Api\Hooks::process('sidebox_all',array($GLOBALS['egw_info']['flags']['currentapp']),true);
- }
- //If there still is no sidebox content, return null here
- if (!isset($this->sideboxes[$appname]))
- {
- return null;
- }
-
- $data = array();
- foreach($this->sideboxes[$appname] as $menu_name => &$file)
- {
- $current_menu = array(
- 'menu_name' => md5($menu_name), // can contain Api\Html tags and javascript!
- 'title' => $menu_name,
- 'entries' => array(),
- 'opened' => (boolean)$file['menuOpened'],
- );
- foreach($file as $item_text => $item_link)
- {
- if ($item_text === 'menuOpened' || // flag, not menu entry
- $item_text === '_NewLine_' || $item_link === '_NewLine_')
- {
- continue;
- }
- if (strtolower($item_text) == 'grant access' && $GLOBALS['egw_info']['server']['deny_user_grants_access'])
- {
- continue;
- }
-
- $var = array();
- $var['icon_or_star'] = $GLOBALS['egw_info']['server']['webserver_url'] . $this->template_dir.'/images/bullet.png';
- $var['target'] = '';
- if(is_array($item_link))
- {
- if(isset($item_link['icon']))
- {
- $app = isset($item_link['app']) ? $item_link['app'] : $appname;
- $var['icon_or_star'] = $item_link['icon'] ? Api\Image::find($app,$item_link['icon']) : False;
- }
- $var['lang_item'] = isset($item_link['no_lang']) && $item_link['no_lang'] ? $item_link['text'] : lang($item_link['text']);
- $var['item_link'] = $item_link['link'];
- if ($item_link['target'])
- {
- // we only support real targets not Api\Html markup with target in it
- if (strpos($item_link['target'], 'target=') === false &&
- strpos($item_link['target'], '"') === false)
- {
- $var['target'] = $item_link['target'];
- }
- }
- }
- else
- {
- $var['lang_item'] = lang($item_text);
- $var['item_link'] = $item_link;
- }
- $current_menu['entries'][] = $var;
- }
- $data[] = $current_menu;
- }
- return $data;
- }
-
- /**
- * Ajax callback which is called whenever a previously opened tab is closed or
- * opened.
- *
- * @param $tablist is an array which contains each tab as an associative array
- * with the keys 'appName' and 'active'
- */
- public function ajax_tab_changed_state($tablist)
- {
- $tabs = array();
- foreach($tablist as $data)
- {
- $tabs[] = $data['appName'];
- if ($data['active']) $active = $data['appName'];
- }
- // send app a notification, that it's tab got closed
- // used eg. in phpFreeChat to leave the chat
- if (($old_tabs = Api\Cache::getSession(__CLASS__, 'open_tabs')))
- {
- foreach(array_diff(explode(',',$old_tabs),$tabs) as $app)
- {
- //error_log("Tab '$app' closed, old_tabs=$old_tabs");
- Api\Hooks::single(array(
- 'location' => 'tab_closed',
- 'app' => $app,
- ), $app);
- }
- }
- $open = implode(',',$tabs);
-
- if ($open != $GLOBALS['egw_info']['user']['preferences']['common']['open_tabs'] ||
- $active != $GLOBALS['egw_info']['user']['preferences']['common']['active_tab'])
- {
- //error_log(__METHOD__.'('.array2string($tablist).") storing common prefs: open_tabs='$tabs', active_tab='$active'");
- Api\Cache::setSession(__CLASS__, 'open_tabs', $open);
- $GLOBALS['egw']->preferences->read_repository();
- $GLOBALS['egw']->preferences->add('common', 'open_tabs', $open);
- $GLOBALS['egw']->preferences->add('common', 'active_tab', $active);
- $GLOBALS['egw']->preferences->save_repository(true);
- }
- }
-
- /**
- * Return sidebox data for an application
- *
- * Format see get_sidebox()
- *
- * @param $appname
- */
- public function ajax_sidebox($appname, $md5)
- {
- $response = Api\Json\Response::get();
- $sidebox = $this->get_sidebox($appname);
- $encoded = json_encode($sidebox);
- $n