move egw_framework to api and refactor it

This commit is contained in:
Ralf Becker 2016-04-07 20:42:06 +00:00
parent d48a968674
commit 8c87cf9dfc
29 changed files with 2815 additions and 2649 deletions

View File

@ -14,22 +14,23 @@ $GLOBALS['egw_info'] = array(
);
include('../../../header.inc.php');
egw_framework::validate_file('.','etemplate2','etemplate');
egw_framework::validate_file('jquery','jquery.tools.min','phpgwapi'); // Not needed once JS require works for files like this
egw_framework::validate_file('jquery','jquery.html5_upload','phpgwapi'); // Not needed once JS require works for files like this
egw_framework::includeCSS('/etemplate/js/test/test.css');
use EGroupware\Api;
Api\Framework::includeJS('.','etemplate2','etemplate');
Api\Framework::includeJS('jquery','jquery.tools.min','phpgwapi'); // Not needed once JS require works for files like this
Api\Framework::includeJS('jquery','jquery.html5_upload','phpgwapi'); // Not needed once JS require works for files like this
Api\Framework::includeCSS('/api/js/etemplate/test/test.css');
/*
* Test using any actual template
*/
$template = 'etemplate.et2_test_file_upload';
if($template) {
$etemplate = new etemplate_new('etemplate.et2_test_file_upload');
$etemplate = new Api\Etemplate('etemplate.et2_test_file_upload');
$etemplate->exec('',array());
return;
}
common::egw_header();
// parse_navbar();
echo $GLOBALS['egw']->framework->header();
?>
<script src="et2_test_timesheet_edit.json"></script>
<script src="et2_test_input_validator.json"></script>
@ -58,6 +59,4 @@ Testing from inside framework, so JS includes work
}
</script>
<?php
common::egw_footer();
?>
echo $GLOBALS['egw']->framework->footer();

View File

@ -19,7 +19,7 @@
namespace EGroupware\Api;
// explicitly reference classes still in phpgwapi of old structure
use egw;
use egw; // invalidate_session_cache
/**
* API - accounts

View File

@ -15,9 +15,6 @@ namespace EGroupware\Api\CalDAV;
use EGroupware\Api;
// explicit import old non-namespaced api classes
use egw; // link
/**
* GroupDAV hooks: eg. preferences
*/
@ -40,7 +37,7 @@ class Hooks
if ($location == 'preferences')
{
$file = array(
'Preferences' => egw::link('/index.php','menuaction=preferences.preference_settings.index&appname='.$appname),
'Preferences' => Api\Framework::link('/index.php','menuaction=preferences.preference_settings.index&appname='.$appname),
);
if ($location == 'preferences')
{
@ -121,7 +118,7 @@ class Hooks
}
}
}
$link = egw::link('/index.php',array(
$link = Api\Framework::link('/index.php',array(
'menuaction' => 'api.'.__CLASS__.'.log',
'filename' => '',
));

View File

@ -19,8 +19,6 @@
namespace EGroupware\Api;
use egw_framework; // includeCSS
/**
* class to manage categories in eGroupWare
*
@ -1040,7 +1038,7 @@ class Categories
$last_mod = $cats->return_array('all',0,1,'','DESC','last_mod', $appname == self::GLOBAL_APPNAME);
$time = count($last_mod) ? $last_mod[0]['last_mod'] : time();
$path = '/api/categories.php?app='.$appname.'&'.$time;
egw_framework::includeCSS($path);
Framework::includeCSS($path);
return $path;
}

View File

@ -13,10 +13,6 @@
namespace EGroupware\Api;
// explicitly import old not yet ported classes
use egw;
use egw_framework;
/**
* New eTemplate serverside contains:
* - main server methods like read, exec
@ -71,7 +67,7 @@ class Etemplate extends Etemplate\Widget\Template
*/
static function location($params='')
{
egw::redirect_link(is_array($params) ? '/index.php' : $params,
Framework::redirect_link(is_array($params) ? '/index.php' : $params,
is_array($params) ? $params : '');
}
@ -138,7 +134,7 @@ class Etemplate extends Etemplate\Widget\Template
unset($hook_data);
// Include the etemplate2 javascript code
egw_framework::validate_file('etemplate', 'etemplate2', 'api');
Framework::includeJS('etemplate', 'etemplate2', 'api');
if (!$this->rel_path) throw new Exception\AssertionFailed("No (valid) template '$this->name' found!");
@ -210,25 +206,25 @@ class Etemplate extends Etemplate\Widget\Template
if (self::$response) // call is within an ajax event / form submit
{
//error_log("Ajax " . __LINE__);
self::$response->generic('et2_load', $load_array+egw_framework::get_extra());
egw_framework::clear_extra(); // to not send/set it twice for multiple etemplates (eg. CRM view)
self::$response->generic('et2_load', $load_array+Framework::get_extra());
Framework::clear_extra(); // to not send/set it twice for multiple etemplates (eg. CRM view)
}
else // first call
{
// missing dependency, thought egw:uses jquery.jquery.tools does NOT work, maybe we should rename it to jquery-tools
// egw_framework::validate_file('jquery','jquery.tools.min');
// Framework::includeJS('jquery','jquery.tools.min');
// Include the jQuery-UI CSS - many more complex widgets use it
$theme = 'redmond';
egw_framework::includeCSS("/api/js/jquery/jquery-ui/$theme/jquery-ui-1.10.3.custom.css");
Framework::includeCSS("/api/js/jquery/jquery-ui/$theme/jquery-ui-1.10.3.custom.css");
// Load our CSS after jQuery-UI, so we can override it
egw_framework::includeCSS('/api/templates/default/etemplate2.css');
Framework::includeCSS('/api/templates/default/etemplate2.css');
// check if application of template has a app.js file --> load it
list($app) = explode('.',$this->name);
if (file_exists(EGW_SERVER_ROOT.'/'.$app.'/js/app.js'))
{
egw_framework::validate_file('.','app',$app,false);
Framework::includeJS('.','app',$app,false);
}
// Category styles
Categories::css($app);
@ -252,8 +248,8 @@ class Etemplate extends Etemplate\Widget\Template
$content .= "\n".$vars['page_generation_time'];
}
$GLOBALS['egw']->framework->response->generic("data", array($content));
$GLOBALS['egw']->framework->response->generic('et2_load',$load_array+egw_framework::get_extra());
egw_framework::clear_extra(); // to not send/set it twice for multiple etemplates (eg. CRM view)
$GLOBALS['egw']->framework->response->generic('et2_load',$load_array+Framework::get_extra());
Framework::clear_extra(); // to not send/set it twice for multiple etemplates (eg. CRM view)
self::$request = null;
return;
}

View File

@ -15,9 +15,6 @@ namespace EGroupware\Api\Etemplate;
use EGroupware\Api;
// explicitly import old not yet ported classes
use egw_framework;
/**
* Class to represent the persitent information of an eTemplate request
*
@ -212,7 +209,7 @@ class Request
}
else
{
egw_framework::redirect_link($index_url);
Api\Framework::redirect_link($index_url);
}
}
return $request;

View File

@ -16,10 +16,6 @@ namespace EGroupware\Api\Etemplate\Widget;
use EGroupware\Api\Etemplate;
use EGroupware\Api;
// explicitly import old not yet ported classes
use egw;
use egw_framework; // includeCSS
/**
* eTemplate serverside implementation of the nextmatch widget
*
@ -95,7 +91,7 @@ class Nextmatch extends Etemplate\Widget
parent::__construct($xml);
// TODO: probably a better way to do this
egw_framework::includeCSS('/api/js/egw_action/test/skins/dhtmlxmenu_egw.css');
Api\Framework::includeCSS('/api/js/egw_action/test/skins/dhtmlxmenu_egw.css');
}
}
@ -863,7 +859,7 @@ class Nextmatch extends Etemplate\Widget
// link or popup action
if ($action['url'])
{
$action['url'] = egw::link('/index.php',str_replace('$action',$id,$action['url']));
$action['url'] = Api\Framework::link('/index.php',str_replace('$action',$id,$action['url']));
if ($action['popup'])
{
list($action['data']['width'],$action['data']['height']) = explode('x',$action['popup']);

View File

@ -17,9 +17,6 @@ use EGroupware\Api\Etemplate;
use EGroupware\Api;
use XMLReader;
// explicitly import old not yet ported classes
use egw; // link
/* allow to call direct for tests (see end of class)
if (!isset($GLOBALS['egw_info']))
{
@ -211,7 +208,7 @@ class Template extends Etemplate\Widget
{
$url = Api\Vfs::download_url($path);
if ($url[0] == '/') $url = egw::link($url);
if ($url[0] == '/') $url = Api\Framework::link($url);
// mtime postfix has to use '?download=', as our WebDAV treats everything else literal and not ignore them like Apache for static files!
$url .= '?download='.filemtime($path);

View File

@ -16,10 +16,7 @@ namespace EGroupware\Api\Etemplate\Widget;
use EGroupware\Api\Etemplate;
use EGroupware\Api;
// explicitly import old not yet ported classes
use egw_framework;
egw_framework::includeCSS('/api/js/dhtmlxtree/codebase/dhtmlXTree.css');
Api\Framework::includeCSS('/api/js/dhtmlxtree/codebase/dhtmlXTree.css');
/**
* eTemplate tree widget

View File

@ -16,9 +16,6 @@ namespace EGroupware\Api\Etemplate\Widget;
use EGroupware\Api\Etemplate;
use EGroupware\Api;
// explicitly import old not yet ported classes
use egw; // link
/**
* eTemplate VFS widget
* Deals with the Virtual File System
@ -165,7 +162,7 @@ class Vfs extends File
$file = array(
"uploaded" => (int)empty($error),
"fileName" => Api\Html::htmlspecialchars($_FILES['upload']['name']),
"url" => egw::link(Api\Vfs::download_url($path)),
"url" => Api\Framework::link(Api\Vfs::download_url($path)),
"error" => array(
"message" => $error,
)

View File

@ -15,9 +15,6 @@ namespace EGroupware\Api\Etemplate;
use EGroupware\Api;
// explicitly list not yet ported api classes
use egw_framework;
/**
* eTemplate2 widget browser
*
@ -38,18 +35,18 @@ class WidgetBrowser
//'js_link_registry' => True,
// Widget browser code
egw_framework::validate_file('/api/js/etemplate/widget_browser.js');
Api\Framework::includeJS('/api/js/etemplate/widget_browser.js');
// Include the etemplate2 javascript code
egw_framework::validate_file('.', 'etemplate2', 'etemplate');
Api\Framework::includeJS('.', 'etemplate2', 'etemplate');
// Include the jQuery-UI CSS - many more complex widgets use it
$theme = 'redmond';
egw_framework::includeCSS("/api/js/jquery/jquery-ui/$theme/jquery-ui-1.10.3.custom.css");
Api\Framework::includeCSS("/api/js/jquery/jquery-ui/$theme/jquery-ui-1.10.3.custom.css");
egw_framework::includeCSS('/api/templates/default/etemplate2.css');
Api\Framework::includeCSS('/api/templates/default/etemplate2.css');
egw_framework::includeCSS('api','widget_browser',false);
Api\Framework::includeCSS('api','widget_browser',false);
// load translations
Api\Translation::add_app('etemplate');

1418
api/src/Framework.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,279 @@
<?php
/**
* EGroupware API - Bundle JS includes
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage framework
* @access public
* @version $Id$
*/
namespace EGroupware\Api\Framework;
use EGroupware\Api\Cache;
use EGroupware\Api\Header\UserAgent;
/**
* Bundle JS includes
*/
class Bundle
{
/**
* Url of minified version of bundle
*
* @var array
*/
static $bundle2minurl = array(
'api' => '/api/js/jsapi.min.js',
'et2' => '/api/js/etemplate/etemplate2.min.js',
'et21'=> '/api/js/etemplate/etemplate2.min.js',
'pixelegg' => '/pixelegg/js/fw_pixelegg.min.js',
'jdots' => '/jdots/js/fw_jdots.min.js',
'mobile' => '/jdots/js/fw_mobile.min.js',
);
/**
* Devide js-includes in bundles of javascript files to include eg. api or etemplate2, if minifying is enabled
*
* @param array $js_includes files to include with egw relative url
* @return array egw relative urls to include incl. bundels/minify urls, if enabled
*/
public static function js_includes(array $js_includes)
{
$file2bundle = array();
if ($GLOBALS['egw_info']['server']['debug_minify'] !== 'True')
{
// get used bundles and cache them on tree-level for 2h
//$bundles = self::all(); Cache::setTree(__CLASS__, 'bundles', $bundles, 7200);
$bundles = Cache::getTree(__CLASS__, 'bundles', array(__CLASS__, 'all'), array(), 7200);
$bundles_ts = $bundles['.ts'];
unset($bundles['.ts']);
foreach($bundles as $name => $files)
{
// to facilitate move to new et2 location, can be removed after 16.1 release
if ($name == 'et21' && !in_array('/api/js/etemplate/etemplate2.js', $files))
{
Cache::unsetTree(__CLASS__, 'bundles');
return self::js_includes($js_includes);
}
// ignore bundles of not used templates, as they can contain identical files
if (in_array($name, array('api', 'et2', 'et21')) ||
$name == (UserAgent::mobile() ? 'mobile' : $GLOBALS['egw_info']['server']['template_set']) ||
isset($GLOBALS['egw_info']['apps'][$name]))
{
$file2bundle += array_combine($files, array_fill(0, count($files), $name));
}
}
//error_log(__METHOD__."() file2bundle=".array2string($file2bundle));
}
$to_include = $included_bundles = array();
$query = null;
foreach($js_includes as $file)
{
if (!isset($to_include[$file]))
{
if (($bundle = $file2bundle[$file]))
{
//error_log(__METHOD__."() requiring bundle $bundle for $file");
if (!in_array($bundle, $included_bundles))
{
$included_bundles[] = $bundle;
$minurl = self::$bundle2minurl[$bundle];
if (!isset($minurl) && isset($GLOBALS['egw_info']['apps'][$bundle]))
{
$minurl = '/'.$bundle.'/js/app.min.js';
}
$max_modified = 0;
$to_include = array_merge($to_include, self::urls($bundles[$bundle], $max_modified, $minurl));
// check if bundle-config is more recent then
if ($max_modified > $bundles_ts)
{
// force new bundle Config by deleting cached one and call ourself again
Cache::unsetTree(__CLASS__, 'bundles');
return self::js_includes($js_includes);
}
}
}
else
{
unset($query);
list($path, $query) = explode('?', $file, 2);
$mod = filemtime(EGW_SERVER_ROOT.$path);
// check if we have a more recent minified version of the file and use it
if ($GLOBALS['egw_info']['server']['debug_minify'] !== 'True' &&
substr($path, -3) == '.js' && file_exists(EGW_SERVER_ROOT.($min_path = substr($path, 0, -3).'.min.js')) &&
(($min_mod = filemtime(EGW_SERVER_ROOT.$min_path)) >= $mod))
{
$path = $min_path;
$mod = $min_mod;
}
$to_include[$file] = $path.'?'.$mod.($query ? '&'.$query : '');
}
}
}
//error_log(__METHOD__."(".array2string($js_includes).') debug_minify='.array2string($GLOBALS['egw_info']['server']['debug_minify']).', include_bundels='.array2string($included_bundles).' returning '.array2string(array_values(array_unique($to_include))));
return array_values(array_unique($to_include));
}
/**
* Generate bundle url(s) for given js files
*
* @param array $js_includes
* @param int& $max_modified =null on return maximum modification time of bundle
* @param string $minurl =null url of minified bundle, to be used, if existing and recent
* @return array js-files (can be more then one, if one of given files can not be bundeled)
*/
protected static function urls(array $js_includes, &$max_modified=null, $minurl=null)
{
$debug_minify = $GLOBALS['egw_info']['server']['debug_minify'] === 'True';
// ignore not existing minurl
$to_include_first = $to_include = $to_minify = array();
$max_modified = 0;
$query = null;
foreach($js_includes as $path)
{
if ($path == '/api/js/jsapi/egw.js') continue; // loaded via own tag, and we must not load it twice!
unset($query);
list($path,$query) = explode('?',$path,2);
$mod = filemtime(EGW_SERVER_ROOT.$path);
// ckeditor must be included before bundled files, as they depend on it!
if (strpos($path,'/ckeditor/ckeditor.js') !== false)
{
$to_include_first[] = $path . '?' . $mod;
}
// for now minify does NOT support query parameters, nor php files generating javascript
elseif ($debug_minify || $query || substr($path, -3) != '.js')
{
$path .= '?'. $mod.($query ? '&'.$query : '');
$to_include[] = $path;
}
else
{
if ($mod > $max_modified) $max_modified = $mod;
$to_minify[] = substr($path,1);
}
}
if (!$debug_minify && $to_minify)
{
if (!empty($minurl) && file_exists(EGW_SERVER_ROOT.$minurl) &&
($mod=filemtime(EGW_SERVER_ROOT.$minurl)) >= $max_modified)
{
$path = $minurl.'?'.$mod;
}
else
{
$base_path = $GLOBALS['egw_info']['server']['webserver_url'];
if ($base_path[0] != '/') $base_path = parse_url($base_path, PHP_URL_PATH);
$path = '/phpgwapi/inc/min/?'.($base_path && $base_path != '/' ? 'b='.substr($base_path, 1).'&' : '').
'f='.implode(',', $to_minify) .
($GLOBALS['egw_info']['server']['debug_minify'] === 'debug' ? '&debug' : '').
'&'.$max_modified;
}
// need to include minified javascript before not minified stuff like jscalendar-setup, as it might depend on it
array_unshift($to_include, $path);
}
if ($to_include_first) $to_include = array_merge($to_include_first, $to_include);
//error_log(__METHOD__."("./*array2string($js_includes).*/", $max_modified, $minurl) returning ".array2string($to_include));
return $to_include;
}
/**
* Maximum number of files in a bundle
*
* We split bundles, if they contain more then these number of files,
* because IE silently stops caching them, if Content-Length get's too big.
*
* IE11 cached 142kb compressed api bundle, but not 190kb et2 bundle.
* Splitting et2 bundle in max 50 files chunks, got IE11 to cache both bundles.
*/
const MAX_BUNDLE_FILES = 50;
/**
* Return all bundels we use:
* - api stuff phpgwapi/js/jsapi/* and it's dependencies incl. jquery
* - etemplate2 stuff not including api bundle, but jquery-ui
*
* @return array bundle-url => array of contained files
*/
public static function all()
{
$inc_mgr = new IncludeMgr();
$bundles = array();
$max_mod = array();
// generate api bundle
$inc_mgr->include_js_file('/api/js/jquery/jquery.js');
$inc_mgr->include_js_file('/api/js/jquery/jquery-ui.js');
$inc_mgr->include_js_file('/api/js/jsapi/jsapi.js');
$inc_mgr->include_js_file('/api/js/egw_json.js');
$inc_mgr->include_js_file('/api/js/jsapi/egw.js');
// dhtmlxTree (dhtmlxMenu get loaded via dependency in egw_menu_dhtmlx.js)
$inc_mgr->include_js_file('/api/js/dhtmlxtree/codebase/dhtmlxcommon.js');
$inc_mgr->include_js_file('/api/js/dhtmlxtree/sources/dhtmlxtree.js');
$inc_mgr->include_js_file('/api/js/dhtmlxtree/sources/ext/dhtmlxtree_json.js');
// actions
$inc_mgr->include_js_file('/api/js/egw_action/egw_action.js');
$inc_mgr->include_js_file('/api/js/egw_action/egw_keymanager.js');
$inc_mgr->include_js_file('/api/js/egw_action/egw_action_popup.js');
$inc_mgr->include_js_file('/api/js/egw_action/egw_action_dragdrop.js');
$inc_mgr->include_js_file('/api/js/egw_action/egw_dragdrop_dhtmlx_tree.js');
$inc_mgr->include_js_file('/api/js/egw_action/egw_menu.js');
$inc_mgr->include_js_file('/api/js/egw_action/egw_menu_dhtmlx.js');
// include choosen in api, as old eTemplate uses it and fail if it pulls in half of et2
$inc_mgr->include_js_file('/api/js/jquery/chosen/chosen.jquery.js');
// include CKEditor in api, as old eTemplate uses it too
$inc_mgr->include_js_file('/api/js/ckeditor/ckeditor.js');
$inc_mgr->include_js_file('/api/js/ckeditor/config.js');
$bundles['api'] = $inc_mgr->get_included_files();
self::urls($bundles['api'], $max_mod['api']);
// generate et2 bundle (excluding files in api bundle)
$inc_mgr->include_js_file('/api/js/etemplate/etemplate2.js');
$bundles['et2'] = array_diff($inc_mgr->get_included_files(), $bundles['api']);
self::urls($bundles['et2'], $max_mod['et2']);
$stock_files = call_user_func_array('array_merge', $bundles);
// generate template and app bundles, if installed
foreach(array(
'jdots' => '/jdots/js/fw_jdots.js',
'mobile' => '/jdots/js/fw_mobile.js',
'pixelegg' => '/pixelegg/js/fw_pixelegg.js',
'calendar' => '/calendar/js/app.js',
'mail' => '/mail/js/app.js',
'projectmanager' => '/projectmanager/js/app.js',
) as $bundle => $file)
{
if (@file_exists(EGW_SERVER_ROOT.$file))
{
$inc_mgr = new IncludeMgr($stock_files); // reset loaded files to stock files
$inc_mgr->include_js_file($file);
$bundles[$bundle] = array_diff($inc_mgr->get_included_files(), $stock_files);
self::urls($bundles[$bundle], $max_mod[$bundle]);
}
}
// automatic split bundles with more then MAX_BUNDLE_FILES (=50) files
foreach($bundles as $name => $files)
{
$n = '';
while (count($files) > self::MAX_BUNDLE_FILES*(int)$n)
{
$files80 = array_slice($files, self::MAX_BUNDLE_FILES*(int)$n, self::MAX_BUNDLE_FILES, true);
$bundles[$name.$n++] = $files80;
}
}
// store max modification time of all files in all bundles
$bundles['.ts'] = max($max_mod);
//error_log(__METHOD__."() returning ".array2string($bundles));
return $bundles;
}
}

View File

@ -0,0 +1,163 @@
<?php
/**
* EGroupware API - CSS Includes
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> rewrite in 12/2006
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage framework
* @access public
* @version $Id$
*/
namespace EGroupware\Api\Framework;
/**
* CSS includes
*/
class CssIncludes
{
/**
* Content from add calls
*
* @var array
*/
protected static $files = array();
/**
* Include a css file, either speicified by it's path (relative to EGW_SERVER_ROOT) or appname and css file name
*
* @param string $app path (relative to EGW_SERVER_ROOT) or appname (if !is_null($name))
* @param string $name =null name of css file in $app/templates/{default|$this->template}/$name.css
* @param boolean $append =true true append file, false prepend (add as first) file used eg. for template itself
* @param boolean $clear_includes =false true: clear all previous includes
* @return boolean false: css file not found, true: file found
*/
public static function add($app, $name=null, $append=true, $clear_includes=false)
{
if ($clear_includes)
{
self::$files = array();
}
if (!is_null($name))
{
foreach($GLOBALS['egw']->framework->template_dirs as $dir)
{
if (file_exists(EGW_SERVER_ROOT.($path = '/'.$app.'/templates/'.$dir.'/'.$name.'.css')))
{
break;
}
}
}
else
{
$path = $app;
}
if (!file_exists(EGW_SERVER_ROOT.$path) && !file_exists(EGW_SERVER_ROOT . parse_url($path,PHP_URL_PATH)))
{
//error_log(__METHOD__."($app,$name) $path NOT found!");
return false;
}
if (!in_array($path,self::$files))
{
if ($append)
{
self::$files[] = $path;
}
else
{
self::$files = array_merge(array($path), self::$files);
}
}
return true;
}
/**
* Get all css files included with add
*
* @return string
*/
public static function get()
{
return self::$files;
}
/**
* Return link tags for all included css files incl. minifying
*
* @return string
*/
public static function tags()
{
// add all css files from self::includeCSS
$max_modified = 0;
$debug_minify = $GLOBALS['egw_info']['server']['debug_minify'] === 'True';
$base_path = $GLOBALS['egw_info']['server']['webserver_url'];
if ($base_path[0] != '/') $base_path = parse_url($base_path, PHP_URL_PATH);
$css_files = '';
foreach(self::$files as $path)
{
foreach(self::resolve_css_includes($path) as $path)
{
list($file,$query) = explode('?',$path,2);
if (($mod = filemtime(EGW_SERVER_ROOT.$file)) > $max_modified) $max_modified = $mod;
// do NOT include app.css or categories.php, as it changes from app to app
if ($debug_minify || substr($path, -8) == '/app.css' || substr($file,-14) == 'categories.php')
{
$css_files .= '<link href="'.$GLOBALS['egw_info']['server']['webserver_url'].$path.($query ? '&' : '?').$mod.'" type="text/css" rel="StyleSheet" />'."\n";
}
else
{
$css_file .= ($css_file ? ',' : '').substr($path, 1);
}
}
}
if (!$debug_minify)
{
$css = $GLOBALS['egw_info']['server']['webserver_url'].'/phpgwapi/inc/min/?';
if ($base_path && $base_path != '/') $css .= 'b='.substr($base_path, 1).'&';
$css .= 'f='.$css_file .
($GLOBALS['egw_info']['server']['debug_minify'] === 'debug' ? '&debug' : '').
'&'.$max_modified;
$css_files = '<link href="'.$css.'" type="text/css" rel="StyleSheet" />'."\n".$css_files;
}
return $css_files;
}
/**
* Parse beginning of given CSS file for /*@import url("...") statements
*
* @param string $path EGroupware relative path eg. /phpgwapi/templates/default/some.css
* @return array parsed pathes (EGroupware relative) including $path itself
*/
protected static function resolve_css_includes($path, &$pathes=array())
{
$matches = null;
list($file) = explode('?',$path,2);
if (($to_check = file_get_contents (EGW_SERVER_ROOT.$file, false, null, -1, 1024)) &&
stripos($to_check, '/*@import') !== false && preg_match_all('|/\*@import url\("([^"]+)"|i', $to_check, $matches))
{
foreach($matches[1] as $import_path)
{
if ($import_path[0] != '/')
{
$dir = dirname($path);
while(substr($import_path,0,3) == '../')
{
$dir = dirname($dir);
$import_path = substr($import_path, 3);
}
$import_path = ($dir != '/' ? $dir : '').'/'.$import_path;
}
self::resolve_css_includes($import_path, $pathes);
}
}
$pathes[] = $path;
return $pathes;
}
}

183
api/src/Framework/Extra.php Normal file
View File

@ -0,0 +1,183 @@
<?php
/**
* EGroupware API - Framework extra
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage framework
* @access public
* @version $Id$
*/
namespace EGroupware\Api\Framework;
use EGroupware\Api\Link;
use EGroupware\Api\Json;
/**
* Framework extra - handling of server-responses either send via data attribute
*/
abstract class Extra
{
/**
* Extra values send as data attributes to script tag of egw.js
*
* @var array
*/
protected static $extra = array();
/**
* Refresh given application $targetapp display of entry $app $id, incl. outputting $msg
*
* Calling egw_refresh and egw_message on opener in a content security save way
*
* To provide more information about necessary refresh an automatic 9th parameter is added
* containing an object with application-name as attributes containing an array of linked ids
* (adding happens in get_extras to give apps time to link new entries!).
*
* @param string $msg message (already translated) to show, eg. 'Entry deleted'
* @param string $app application name
* @param string|int $id =null id of entry to refresh
* @param string $type =null either 'update', 'edit', 'delete', 'add' or null
* - update: request just modified data from given rows.
* Sorting and filtering are not considered, so if the sort field is changed,
* the row will not be moved. If the current filtering could include or exclude
* the record, use edit.
* - edit: rows changed, but sorting or filtering may be affected. Requires full reload.
* - delete: just delete the given rows clientside (no server interaction neccessary)
* - add: requires full reload for proper sorting
* - null: full reload
* @param string $targetapp =null which app's window should be refreshed, default current
* @param string|RegExp $replace =null regular expression to replace in url
* @param string $with =null
* @param string $msg_type =null 'error', 'warning' or 'success' (default)
*/
public static function refresh_opener($msg, $app, $id=null, $type=null, $targetapp=null, $replace=null, $with=null, $msg_type=null)
{
//error_log(__METHOD__.'('.array2string(func_get_args()).')');
self::$extra['refresh-opener'] = func_get_args();
unset($msg, $app, $id, $type, $targetapp, $replace, $with, $msg_type); // used only via func_get_args();
}
/**
* Display an error or regular message
*
* Calls egw_message on client-side in a content security save way
*
* @param string $msg message to show
* @param string $type ='success' 'error', 'warning' or 'success' (default)
*/
public static function message($msg, $type='success')
{
self::$extra['message'] = func_get_args();
unset($msg, $type); // used only via func_get_args();
}
/**
* Open a popup independent if we run as json or regular request
*
* @param string $link
* @param string $target
* @param string $popup
*/
public static function popup($link, $target='_blank', $popup='640x480')
{
// default params are not returned by func_get_args!
$args = func_get_args()+array(null, '_blank', '640x480');
unset($link, $target, $popup); // used only via func_get_args()
if (Json\Request::isJSONRequest())
{
Json\Response::get()->apply('egw.open_link', $args);
}
else
{
self::$extra['popup'] = $args;
}
}
/**
* Close (popup) window, use to replace egw_framework::onload('window.close()') in a content security save way
*
* @param string $alert_msg ='' optional message to display as alert, before closing the window
*/
public static function window_close($alert_msg='')
{
//error_log(__METHOD__."()");
self::$extra['window-close'] = $alert_msg ? $alert_msg : true;
// are we in ajax_process_content -> just return extra data, with close instructions
if (preg_match('/etemplate(_new)?(::|\.)ajax_process_content/', $_GET['menuaction']))
{
$response = Json\Response::get();
$response->generic('et2_load', self::get_extra());
}
else
{
$GLOBALS['egw']->framework->render('', false, false);
}
exit;
}
/**
* Close (popup) window, use to replace egw_framework::onload('window.close()') in a content security save way
*/
public static function window_focus()
{
//error_log(__METHOD__."()");
self::$extra['window-focus'] = true;
}
/**
* Allow app to store arbitray values in egw script tag
*
* Attribute name will be "data-$app-$name" and value will be json serialized, if not scalar.
*
* @param string $app
* @param string $name
* @param mixed $value
*/
public static function set_extra($app, $name, $value)
{
self::$extra[$app.'-'.$name] = $value;
}
/**
* Clear all extra data
*/
public static function clear_extra()
{
self::$extra = array();
}
/**
* Allow eg. ajax to query content set via refresh_opener or window_close
*
* @return array content of egw_framework::$extra
*/
public static function get_extra()
{
// adding links of refreshed entry, to give others apps more information about necessity to refresh
if (isset(self::$extra['refresh-opener']) && count(self::$extra['refresh-opener']) <= 8 && // do not run twice
!empty(self::$extra['refresh-opener'][1]) && !empty(self::$extra['refresh-opener'][2])) // app/id given
{
$links = Link::get_links(self::$extra['refresh-opener'][1], self::$extra['refresh-opener'][2]);
$apps = array();
foreach($links as $link)
{
$apps[$link['app']][] = $link['id'];
}
while (count(self::$extra['refresh-opener']) < 8)
{
self::$extra['refresh-opener'][] = null;
}
self::$extra['refresh-opener'][] = $apps;
}
return self::$extra;
}
}

View File

@ -0,0 +1,260 @@
<?php
/**
* EGroupware API - Favorites server-side
*
* @link http://www.egroupware.org
* @author Nathan Gray <ng@stylite.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage framework
* @access public
* @version $Id$
*/
namespace EGroupware\Api\Framework;
use EGroupware\Api;
/**
* Favorites service-side:
*
* Favorites are generated on serverside by following code in apps sidebox hook:
*
* display_sidebox($appname, lang('Favorites'), Api\Framework\Favorites::favorite_list($appname));
*
* Clientside code resides in:
* - api/js/jsapi/app_base.js
* - api/js/etemplate/et2_widget_favorites.js
*
* Favorites are stored with prefix "favorite_" in app preferences.
*/
class Favorites
{
/**
* Include favorites when generating the page server-side
*
* Use this function in your sidebox (or anywhere else, I suppose) to
* get the favorite list when a nextmatch is _not_ on the page. If
* a nextmatch is on the page, it will update / replace this list.
*
* @param string $app application, needed to find preferences
* @param string $default preference name for default favorite, default "nextmatch-$app.index.rows-favorite"
*
* @return array with a single sidebox menu item (array) containing html for favorites
*/
public static function list_favorites($app, $default=null)
{
if (!$app)
{
return '';
}
if (!$default)
{
$default = "nextmatch-$app.index.rows-favorite";
}
// This target is used client-side to find & enable adding new favorites
$target = 'favorite_sidebox_'.$app;
/* @var $filters array an array of favorites*/
$filters = self::get_favorites($app);
$is_admin = $GLOBALS['egw_info']['user']['apps']['admin'];
$html = "<span id='$target' class='ui-helper-clearfix sidebox-favorites'><ul class='ui-menu ui-widget-content ui-corner-all favorites' role='listbox'>\n";
$default_filter = $GLOBALS['egw_info']['user']['preferences'][$app][$default];
if (!isset($default_filter) || !isset($filters[$default_filter]))
{
$default_filter = "blank";
}
// Get link for if there is no nextmatch - this is the fallback
$registry = Api\Link::get_registry($app,'list');
if (!$registry)
{
$registry = Api\Link::get_registry($app, 'index');
}
foreach($filters as $name => $filter)
{
//filter must not be empty if there's one, ignore it at the moment but it need to be checked how it got there in database
if (!$filter)
{
error_log(__METHOD__.'Favorite filter "'.$name.'" is not supposed to be empty, it should be an array. Skipping, more investigation needed. filter = '. array2string($filters[$name]));
continue;
}
$li = "<li data-id='$name' data-group='{$filter['group']}' class='ui-menu-item' role='menuitem'>\n";
$li .= '<a href="#" class="ui-corner-all" tabindex="-1">';
$li .= "<div class='" . ((string)$name === (string)$default_filter ? 'ui-icon ui-icon-heart' : 'sideboxstar') . "'></div>".
$filter['name'];
$li .= ($filter['group'] != false && !$is_admin || $name === 'blank' ? "" :
"<div class='ui-icon ui-icon-trash' title='" . lang('Delete') . "'></div>");
$li .= "</a></li>\n";
//error_log(__METHOD__."() $name, filter=".array2string($filter)." --> ".$li);
$html .= $li;
}
// If were're here, the app supports favorites, so add a 'Add' link too
$html .= "<li data-id='add' class='ui-menu-item' role='menuitem'><a href='javascript:app.$app.add_favorite()' class='ui-corner-all'>";
$html .= Api\Html::image($app, 'new') . lang('Add current'). '</a></li>';
$html .= '</ul></span>';
return array(
array(
'no_lang' => true,
'text' => $html,
'link' => false,
'icon' => false,
),
);
}
/**
* Get preferenced favorites sorted list
*
* @param string $app Application name as string
*
* @return (array|boolean) An array of sorted favorites or False if there's no preferenced sorted list
*
*/
public static function get_fav_sort_pref ($app)
{
$fav_sorted_list = array();
if (($fav_sorted_list = $GLOBALS['egw_info']['user']['preferences'][$app]['fav_sort_pref']))
{
return $fav_sorted_list;
}
else
{
return false;
}
}
/**
* Get a list of actual user favorites
* The default 'Blank' favorite is not included here
*
* @param string $app Current application
*
* @return array Favorite information
*/
public static function get_favorites($app)
{
$favorites = array(
'blank' => array(
'name' => lang('No filters'),
// Old
'filter' => array(),
// New
'state' => array(),
'group' => true
)
);
$pref_prefix = 'favorite_';
$sorted_list = array();
$fav_sort_pref = self::get_fav_sort_pref($app);
// Look through all preferences & pull out favorites
foreach((array)$GLOBALS['egw_info']['user']['preferences'][$app] as $pref_name => $pref)
{
if(strpos($pref_name, $pref_prefix) === 0)
{
if(!is_array($pref)) continue; // old favorite
$favorites[(string)substr($pref_name,strlen($pref_prefix))] = $pref;
}
}
if (is_array($fav_sort_pref))
{
foreach ($fav_sort_pref as $key)
{
$sorted_list[$key] = $favorites[$key];
}
$favorites = array_merge($sorted_list,$favorites);
}
return $favorites;
}
/**
* Create or delete a favorite for multiple users
*
* Current user needs to be an admin or it will just do nothing quietly
*
* @param string $app Current application, needed to save preference
* @param string $_name Name of the favorite
* @param string $action "add" or "delete"
* @param boolean|int|String $group ID of the group to create the favorite for, or 'all' for all users
* @param array $filters key => value pairs for the filter
* @return boolean Success
*/
public static function set_favorite($app, $_name, $action, $group, $filters = array())
{
// Only use alphanumeric for preference name, so it can be used directly as DOM ID
$name = strip_tags($_name);
$pref_name = "favorite_".$name;
// older group-favorites have just true as their group and are not deletable, if we dont find correct group
if ($group === true || $group === '1')
{
if (isset($GLOBALS['egw']->preferences->default[$app][$pref_name]))
{
$group = 'all';
}
else
{
foreach($GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'], true) as $gid)
{
$prefs = new Api\Preferences($gid);
$prefs->read_repository();
if (isset($prefs->user[$app][$pref_name]))
{
$group = $gid;
break;
}
}
}
}
if($group && $GLOBALS['egw_info']['apps']['admin'] && $group !== 'all')
{
$prefs = new Api\Preferences(is_numeric($group) ? $group : $GLOBALS['egw_info']['user']['account_id']);
}
else
{
$prefs = $GLOBALS['egw']->preferences;
}
$prefs->read_repository();
$type = $group === "all" ? "default" : "user";
//error_log(__METHOD__."('$app', '$name', '$action', ".array2string($group).", ...) pref_name=$pref_name, type=$type");
if($action == "add")
{
$filters = array(
// This is the name as user entered it, minus tags
'name' => $name,
'group' => $group ? $group : false,
'state' => $filters
);
$pref_name = "favorite_".preg_replace('/[^A-Za-z0-9-_]/','_',$name);
$result = $prefs->add($app,$pref_name,$filters,$type);
$pref = $prefs->save_repository(false,$type);
// Update preferences client side, or it could disappear
Api\Json\Responseget()->call('egw.set_preferences', (array)$pref[$app], $app);
Api\Json\Responseget()->data(isset($result[$app][$pref_name]));
return isset($result[$app][$pref_name]);
}
else if ($action == "delete")
{
$result = $prefs->delete($app,$pref_name, $type);
$pref = $prefs->save_repository(false,$type);
// Update preferences client side, or it could come back
Api\Json\Responseget()->call('egw.set_preferences', (array)$pref[$app], $app);
Api\Json\Responseget()->data(!isset($result[$app][$pref_name]));
return !isset($result[$app][$pref_name]);
}
}
}

View File

@ -6,7 +6,7 @@
* @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage groupdav
* @subpackage framework
* @author Andreas Stöckel
* @copyright (c) 2011 Stylite
* @version $Id$

247
api/src/Framework/Login.php Normal file
View File

@ -0,0 +1,247 @@
<?php
/**
* EGroupware API - Render (deny-)login screen
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> rewrite in 12/2006
* @author Pim Snel <pim@lingewoud.nl> 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$
*/
namespace EGroupware\Api\Framework;
use EGroupware\Api;
// explicitly import old, not yet ported api classes
use Template;
/**
* Render (deny-)login screen
*/
class Login
{
/**
* Framework object
*
* @var Api\Framework
*/
protected $framework;
/**
* Constructor
*
* @param Api\Framework $framework
*/
function __construct(Api\Framework $framework)
{
$this->framework = $framework;
}
/**
* Displays the login screen
*
* @param string $extra_vars for login url
* @param string $change_passwd =null string with message to render input fields for password change
*/
function screen($extra_vars, $change_passwd=null)
{
Api\Header\ContentSecurityPolicy::add('frame-src', array()); // array() no external frame-sources
//error_log(__METHOD__."() this->template=$this->framework->template, this->template_dir=$this->framework->template_dir, get_class(this)=".get_class($this));
$tmpl = new Template(EGW_SERVER_ROOT.$this->framework->template_dir);
$tmpl->set_file(array('login_form' => Api\Header\UserAgent::mobile()?'login_mobile.tpl':'login.tpl'));
$tmpl->set_var('lang_message',$GLOBALS['loginscreenmessage']);
// hide change-password fields, if not requested
if (!$change_passwd)
{
$tmpl->set_block('login_form','change_password');
$tmpl->set_var('change_password', '');
$tmpl->set_var('lang_password',lang('password'));
$tmpl->set_var('cd',check_logoutcode($_GET['cd']));
$tmpl->set_var('cd_class', isset($_GET['cd']) && $_GET['cd'] != 1 ? 'error' : '');
$last_loginid = $_COOKIE['last_loginid'];
$last_domain = $_COOKIE['last_domain'];
$tmpl->set_var('passwd', '');
$tmpl->set_var('autofocus_login', 'autofocus');
}
else
{
$tmpl->set_var('lang_password',lang('Old password'));
$tmpl->set_var('lang_new_password',lang('New password'));
$tmpl->set_var('lang_repeat_password',lang('Repeat password'));
$tmpl->set_var('cd', $change_passwd);
$tmpl->set_var('cd_class', 'error');
$last_loginid = $_POST['login'];
$last_domain = $_POST['domain'];
$tmpl->set_var('passwd', $_POST['passwd']);
$tmpl->set_var('autofocus_login', '');
$tmpl->set_var('autofocus_new_passwd', 'autofocus');
}
if($GLOBALS['egw_info']['server']['show_domain_selectbox'])
{
foreach(array_keys($GLOBALS['egw_domain']) as $domain)
{
$domains[$domain] = $domain;
}
$tmpl->set_var(array(
'lang_domain' => lang('domain'),
'select_domain' => Api\Html::select('logindomain',$last_domain,$domains,true,'tabindex="2"',0,false),
));
}
else
{
/* trick to make domain section disapear */
$tmpl->set_block('login_form','domain_selection');
$tmpl->set_var('domain_selection',$GLOBALS['egw_info']['user']['domain'] ?
Api\Html::input_hidden('logindomain',$GLOBALS['egw_info']['user']['domain']) : '');
if($last_loginid !== '')
{
reset($GLOBALS['egw_domain']);
list($default_domain) = each($GLOBALS['egw_domain']);
if(!empty ($last_domain) && $last_domain != $default_domain)
{
$last_loginid .= '@' . $last_domain;
}
}
}
$config_reg = Api\Config::read('registration');
if($config_reg['enable_registration'])
{
if ($config_reg['register_link'])
{
$reg_link='&nbsp;<a href="'. $this->framework->link('/registration/index.php','lang_code='.$_GET['lang']). '">'.lang('Not a user yet? Register now').'</a><br/>';
}
if ($config_reg['lostpassword_link'])
{
$lostpw_link='&nbsp;<a href="'. $this->framework->link('/registration/index.php','menuaction=registration.registration_ui.lost_password&lang_code='.$_GET['lang']). '">'.lang('Lost password').'</a><br/>';
}
if ($config_reg['lostid_link'])
{
$lostid_link='&nbsp;<a href="'. $this->framework->link('/registration/index.php','menuaction=registration.registration_ui.lost_username&lang_code='.$_GET['lang']). '">'.lang('Lost Login Id').'</a><br/>';
}
/* if at least one option of "registration" is activated display the registration section */
if($config_reg['register_link'] || $config_reg['lostpassword_link'] || $config_reg['lostid_link'] )
{
$tmpl->set_var(array(
'register_link' => $reg_link,
'lostpassword_link' => $lostpw_link,
'lostid_link' => $lostid_link,
));
}
else
{
/* trick to make registration section disapear */
$tmpl->set_block('login_form','registration');
$tmpl->set_var('registration','');
}
}
$tmpl->set_var('login_url', $GLOBALS['egw_info']['server']['webserver_url'] . '/login.php' . $extra_vars);
$tmpl->set_var('version', $GLOBALS['egw_info']['server']['versions']['phpgwapi']);
$tmpl->set_var('login', $last_loginid);
$tmpl->set_var('lang_username',lang('username'));
$tmpl->set_var('lang_login',lang('login'));
$tmpl->set_var('website_title', $GLOBALS['egw_info']['server']['site_title']);
$tmpl->set_var('template_set',$this->framework->template);
if (substr($GLOBALS['egw_info']['server']['login_logo_file'], 0, 4) == 'http' ||
$GLOBALS['egw_info']['server']['login_logo_file'][0] == '/')
{
$var['logo_file'] = $GLOBALS['egw_info']['server']['login_logo_file'];
}
else
{
$var['logo_file'] = Api\Image::find('phpgwapi',$GLOBALS['egw_info']['server']['login_logo_file']?$GLOBALS['egw_info']['server']['login_logo_file']:'logo', '', null); // null=explicit allow svg
}
$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';
$tmpl->set_var($var);
/* language section if activated in site Config */
if (@$GLOBALS['egw_info']['server']['login_show_language_selection'])
{
$tmpl->set_var(array(
'lang_language' => lang('Language'),
'select_language' => Api\Html::select('lang',$GLOBALS['egw_info']['user']['preferences']['common']['lang'],
Api\Translation::get_installed_langs(),true,'tabindex="1"',0,false),
));
}
else
{
$tmpl->set_block('login_form','language_select');
$tmpl->set_var('language_select','');
}
/********************************************************\
* Check if authentification via cookies is allowed *
* and place a time selectbox, how long cookie is valid *
\********************************************************/
if($GLOBALS['egw_info']['server']['allow_cookie_auth'])
{
$tmpl->set_block('login_form','remember_me_selection');
$tmpl->set_var('lang_remember_me',lang('Remember me'));
$tmpl->set_var('select_remember_me',Api\Html::select('remember_me', '', array(
'' => lang('not'),
'1hour' => lang('1 Hour'),
'1day' => lang('1 Day'),
'1week'=> lang('1 Week'),
'1month' => lang('1 Month'),
'forever' => lang('Forever'),
),true,'tabindex="3"',0,false));
}
else
{
/* trick to make remember_me section disapear */
$tmpl->set_block('login_form','remember_me_selection');
$tmpl->set_var('remember_me_selection','');
}
$tmpl->set_var('autocomplete', ($GLOBALS['egw_info']['server']['autocomplete_login'] ? 'autocomplete="off"' : ''));
// load jquery for login screen too
Api\Framework::includeJS('jquery', 'jquery');
$this->framework->render($tmpl->fp('loginout','login_form'),false,false);
}
/**
* displays a login denied message
*/
function denylogin_screen()
{
$tmpl = new Template(EGW_SERVER_ROOT.$this->framework->template_dir);
$tmpl->set_file(array(
'login_form' => 'login_denylogin.tpl'
));
$tmpl->set_var(array(
'template_set' => 'default',
'deny_msg' => lang('Oops! You caught us in the middle of system maintainance.').
'<br />'.lang('Please, check back with us shortly.'),
));
// load jquery for deny-login screen too
Api\Framework::includeJS('jquery', 'jquery');
$this->framework->render($tmpl->fp('loginout','login_form'),false,false);
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* EGroupware API - Check for updates
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage framework
* @access public
* @version $Id$
*/
namespace EGroupware\Api\Framework;
use EGroupware\Api\Html;
use EGroupware\Api\Cache;
use EGroupware\Api;
/**
* Check for updates
*/
class Updates
{
/**
* URL to check for security or maintenance updates
*/
const CURRENT_VERSION_URL = 'http://www.egroupware.org/currentversion';
/**
* How long to cache (in secs) / often to check for updates
*/
const VERSIONS_CACHE_TIMEOUT = 7200;
/**
* After how many days of not applied security updates, start warning non-admins too
*/
const WARN_USERS_DAYS = 3;
/**
* Get versions of available updates
*
* @return array verions for keys "current" and "security"
*/
public static function available()
{
$versions = Cache::getTree(__CLASS__, 'versions', function()
{
$versions = array();
$security = null;
if (($remote = file_get_contents(self::CURRENT_VERSION_URL, false, Api\Framework::proxy_context())))
{
list($current, $security) = explode("\n", $remote);
if (empty($security)) $security = $current;
$versions = array(
'current' => $current, // last maintenance update
'security' => $security, // last security update
);
}
return $versions;
}, array(), self::VERSIONS_CACHE_TIMEOUT);
return $versions;
}
/**
* Check update status
*
* @return string
* @todo Check from client-side, if server-side check fails
*/
public static function notification()
{
$versions = self::available();
$api = self::api_version();
if ($versions)
{
if (version_compare($api, $versions['security'], '<'))
{
if (!$GLOBALS['egw_info']['user']['apps']['admin'] && !self::update_older($versions['security'], self::WARN_USERS_DAYS))
{
return null;
}
return Html::a_href(Html::image('phpgwapi', 'security-update', lang('EGroupware security update %1 needs to be installed!', $versions['security'])),
'http://www.egroupware.org/changelog', null, ' target="_blank"');
}
if ($GLOBALS['egw_info']['user']['apps']['admin'] && version_compare($api, $versions['current'], '<'))
{
return Html::a_href(Html::image('phpgwapi', 'update', lang('EGroupware maintenance update %1 available', $versions['current'])),
'http://www.egroupware.org/changelog', null, ' target="_blank"');
}
}
elseif ($GLOBALS['egw_info']['user']['apps']['admin'])
{
$error = lang('Automatic update check failed, you need to check manually!');
if (!ini_get('allow_url_fopen'))
{
$error .= "\n".lang('%1 setting "%2" = %3 disallows access via http!',
'php.ini', 'allow_url_fopen', array2string(ini_get('allow_url_fopen')));
}
return Html::a_href(Html::image('phpgwapi', 'update', $error),
'http://www.egroupware.org/changelog', null, ' target="_blank" data-api-version="'.$api.'"');
}
return null;
}
/**
* Check if version is older then $days days
*
* @param string $version eg. "14.1.20140715" last part is checked (only if > 20140000!)
* @param int $days
* @return boolean
*/
protected static function update_older($version, $days)
{
list(,,$date) = explode('.', $version);
if ($date < 20140000) return false;
$version_timestamp = mktime(0, 0, 0, (int)substr($date, 4, 2), (int)substr($date, -2), (int)substr($date, 0, 4));
return (time() - $version_timestamp) / 86400 > $days;
}
/**
* Get current API version from changelog or database, whichever is bigger
*
* @param string &$changelog on return path to changelog
* @return string
*/
public static function api_version(&$changelog=null)
{
$changelog = EGW_SERVER_ROOT.'/doc/rpm-build/debian.changes';
return Cache::getTree(__CLASS__, 'api_version', function() use ($changelog)
{
$version = preg_replace('/[^0-9.]/', '', $GLOBALS['egw_info']['server']['versions']['phpgwapi']);
// parse version from changelog
$matches = null;
if (($f = fopen($changelog, 'r')) && preg_match('/egroupware-epl \(([0-9.]+)/', fread($f, 80), $matches) &&
version_compare($version, $matches[1], '<'))
{
$version = $matches[1];
fclose($f);
}
return $version;
}, array(), 300);
}
}

View File

@ -14,10 +14,6 @@
namespace EGroupware\Api;
// explicitly import classes not yet imported into Api
use egw_framework; // validate_file, includeCSS
use egw; // link
/**
* Generates html with methods representing html-tags or higher widgets
*
@ -197,8 +193,8 @@ class Html
$out .= "</select>\n";
if($enhanced) {
egw_framework::validate_file('/api/js/jquery/chosen/chosen.jquery.js');
egw_framework::includeCSS('/api/js/jquery/chosen/chosen.css',null,false);
Framework::includeJS('/api/js/jquery/chosen/chosen.jquery.js');
Framework::includeCSS('/api/js/jquery/chosen/chosen.css',null,false);
$out .= "<script>var lab = egw_LAB || \$LAB; lab.wait(function() {\$j(function() {if(\$j().chosen) \$j('select[name=\"$name\"]').chosen({width: '100%'});});})</script>\n";
}
return $out;
@ -433,7 +429,7 @@ class Html
}
//include the ckeditor js file
egw_framework::validate_file('ckeditor','ckeditor','phpgwapi');
Framework::includeJS('ckeditor','ckeditor','phpgwapi');
// run content through htmlpurifier
if ($_purify && !empty($_content))
@ -675,7 +671,7 @@ egw_LAB.wait(function() {
parse_str($v,$v);
$vars += $v;
}
return egw::link($url,$vars);
return Framework::link($url,$vars);
}
/**
@ -890,7 +886,7 @@ egw_LAB.wait(function() {
}
if (substr($name,0,5) == 'vfs:/') // vfs pseudo protocoll
{
$name = egw::link(Vfs::download_url(substr($name,4)));
$name = Framework::link(Vfs::download_url(substr($name,4)));
}
if ($name[0] == '/' || substr($name,0,7) == 'http://' || substr($name,0,8) == 'https://' || stripos($name,'api/thumbnail.php') )
{
@ -1087,7 +1083,7 @@ egw_LAB.wait(function() {
* @param boolean|string $_onCheckHandler =false string with handler-name to display a checkbox for each folder, or false (default), 'null' switches checkboxes on without an handler!
* @param string $delimiter ='/' path-delimiter, default /
* @param string $folderImageDir =null string path to the tree menu images, null uses default path
* @param string|array $autoLoading =null EGw relative path or array with get parameter, both send through egw::link
* @param string|array $autoLoading =null EGw relative path or array with get parameter, both send through Framework::link
* @param string $dataMode ='JSON' data type for autoloading: XML, JSON, CSV
* @param boolean $dragndrop =false true to enable drag-n-drop (must be before autoloading get enabled!)
*
@ -1121,10 +1117,10 @@ egw_LAB.wait(function() {
static $tree_initialised=false;
if (!$tree_initialised)
{
egw_framework::includeCSS('/api/js/dhtmlxtree/codebase/dhtmlxtree.css');
egw_framework::validate_file('/api/js/dhtmlxtree/codebase/dhtmlxcommon.js');
egw_framework::validate_file('/api/js/dhtmlxtree/sources/dhtmlxtree.js');
if ($autoLoading && $dataMode != 'XML') egw_framework::validate_file('/api/js/dhtmlxtree/sources/ext/dhtmlxtree_json.js');
Framework::includeCSS('/api/js/dhtmlxtree/codebase/dhtmlxtree.css');
Framework::includeJS('/api/js/dhtmlxtree/codebase/dhtmlxcommon.js');
Framework::includeJS('/api/js/dhtmlxtree/sources/dhtmlxtree.js');
if ($autoLoading && $dataMode != 'XML') Framework::includeJS('/api/js/dhtmlxtree/sources/ext/dhtmlxtree_json.js');
$tree_initialised = true;
if (!$_folders && !$autoLoading) return null;
}
@ -1148,7 +1144,7 @@ egw_LAB.wait(function() {
if ($autoLoading)
{
$autoLoading = is_array($autoLoading) ?
egw::link('/index.php',$autoLoading) : egw::link($autoLoading);
Framework::link('/index.php',$autoLoading) : Framework::link($autoLoading);
$html .= "$tree.setXMLAutoLoading('$autoLoading');\n";
if ($dataMode != 'XML') $html .= "$tree.setDataMode('$dataMode');\n";

View File

@ -18,7 +18,6 @@ use EGroupware\Api;
// explicitly import old, not yet ported api classes
use notifications_push;
use egw_framework;
/**
* Class handling JSON requests to the server
@ -174,7 +173,7 @@ class Request
// for Ajax: no need to load the "standard" javascript files,
// they are already loaded, in fact jquery has a problem if loaded twice
egw_framework::js_files(array());
Api\Framework::js_files(array());
call_user_func_array(array($ajaxClass, $functionName),
Api\Translation::convert($parameters, 'utf-8'));

View File

@ -23,7 +23,6 @@ use ZipArchive;
// explicit import old, non-namespaced phpgwapi classes
use uiaccountsel;
use egw; // link
/**
* Document merge print
@ -345,11 +344,11 @@ abstract class Merge
if($link_info['app'] != Api\Link::VFS_APPNAME)
{
// Set app to false so we always get an external link
$link = str_replace(',','%2C',egw::link('/index.php',$link, false));
$link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php',$link, false));
}
else
{
$link = egw::link($link, array());
$link = Api\Framework::link($link, array());
}
// Prepend site
if ($link{0} == '/')
@ -404,11 +403,11 @@ abstract class Merge
if($app != Api\Link::VFS_APPNAME)
{
// Set app to false so we always get an external link
$link = str_replace(',','%2C',egw::link('/index.php',$link, false));
$link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php',$link, false));
}
else
{
$link = egw::link($link, array());
$link = Api\Framework::link($link, array());
}
// Prepend site
if ($link{0} == '/')

View File

@ -16,10 +16,6 @@ namespace EGroupware\Api\Vfs;
use EGroupware\Api;
use EGroupware\Api\Vfs;
// explicitly list old, not yet ported api classes
use egw_framework;
use egw; // link
use filemanager_ui;
/**
@ -357,7 +353,7 @@ class Sharing
$GLOBALS['egw_info']['user']['preferences']['filemanager']['nm_view'] = 'tile';
$_GET['cd'] = 'no';
$GLOBALS['egw_info']['flags']['js_link_registry'] = true;
egw_framework::includeCSS('filemanager', 'sharing');
Api\Framework::includeCSS('filemanager', 'sharing');
$ui = new SharingUi();
$ui->index();
}
@ -657,7 +653,7 @@ class Sharing
{
if (is_array($share)) $share = $share['share_token'];
$link = egw::link('/share.php').'/'.$share;
$link = Api\Framework::link('/share.php').'/'.$share;
if ($link[0] == '/')
{
$link = ($_SERVER['HTTPS'] ? 'https://' : 'http://').

View File

@ -29,11 +29,16 @@ $replace = array(
"#\\\$GLOBALS\['egw'\]->session->appsession\(([^,]+),\s*('[^']+'),\s*#" => 'Api\\Cache::setSession($2, $1, ',
"#\\\$GLOBALS\['egw'\]->common->#" => 'common::',
"#\\\$GLOBALS\['egw'\]->hooks->#" => 'Api\\Hooks::',
'#Api\\Hooks::hook_implemented#' => 'Api\\Hooks::implemented',
"#\\\$GLOBALS\['egw'\]->translation->#" => 'Api\\Translation::',
'#egw_framework::csp_script_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('script-src', \$1);",
'#egw_framework::csp_style_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('style-src', \$1);",
'#egw_framework::csp_connect_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('connect-src', \$1);",
'#egw_framework::csp_frame_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('frame-src', \$1);",
);
// enclose class-names and static methods with some syntax check
$class_start = '#([\[\s,;(])';
$class_end = '(::|\\(|;|\?|:|\\s|$)#';
$class_start = '#([\[\s,;(.!])';
$class_end = '(::|\\(|\\)|;|\?|:|\\s|,|$)#';
foreach(array(
'accounts' => 'Api\\Accounts',
'acl' => 'Api\\Acl',
@ -88,8 +93,10 @@ foreach(array(
'egw_exception_db' => 'Api\\Db\\Exception',
'egw_exception_db_invalid_sql' => 'Api\\Db\\Exception\\InvalidSql',
'egw_exception_redirect' => 'Api\\Exception\\Redirect',
//'egw_favorites' =>
//'egw_framework' =>
'egw_favorites' => 'Api\\Framework\\Favorites',
'egw_framework::validate_file' => 'Api\\Framework::includeJS',
'egw_framework::favorite_list' => 'Api\\Framework\\Favorites::list_favorites',
'egw_framework' => 'Api\\Framework',
'egw_json_request' => 'Api\\Json\\Request',
'egw_json_response' => 'Api\\Json\\Response',
'egw_link' => 'Api\\Link',
@ -156,14 +163,15 @@ foreach(array(
* Check namespace usage in converted code
*
* @param string $file filename
* @param boolean $dry_run =false true: only echo fixed file, not fix it
* @return boolean false on error
*/
function fix_api($file)
function fix_api($file, $dry_run=false)
{
global $prog, $replace;
if (basename($file) == $prog) return true; // dont fix ourself ;-)
if (($content = file_get_contents($file)) === false) return false;
if (($content = $content_in = file_get_contents($file)) === false) return false;
if (!preg_match("|<\?php\n/\*\*.*\*/|msU", $content))
{
@ -184,9 +192,15 @@ function fix_api($file)
}
}
die($content);
if ($dry_run)
{
echo $content;
}
elseif ($content_in != $content)
{
file_put_contents($file, $content);
}
//print_r($use);
return true;
}
@ -194,9 +208,10 @@ function fix_api($file)
* Loop recursive through directory and call fix_api for each php file
*
* @param string $dir
* @param boolean $dry_run =false true: only echo fixed file, not fix it
* @return boolean false on error
*/
function fix_api_recursive($dir)
function fix_api_recursive($dir, $dry_run=false)
{
if (!is_dir($dir)) return false;
@ -206,12 +221,12 @@ function fix_api_recursive($dir)
if (is_dir($dir.'/'.$file))
{
fix_api_recursive($dir.'/'.$file);
fix_api_recursive($dir.'/'.$file, $dry_run);
}
elseif(substr($file,-4) == '.php')
{
echo "\r".str_repeat(' ',100)."\r".$dir.'/'.$file.': ';
fix_api($dir.'/'.$file);
fix_api($dir.'/'.$file, $dry_run);
}
}
echo "\r".str_repeat(' ',100)."\r";
@ -226,7 +241,7 @@ function fix_api_recursive($dir)
function usage($error=null)
{
global $prog;
echo "Usage: $prog [-h|--help] file or dir\n\n";
echo "Usage: $prog [-h|--help] [-d|--dry-run] file or dir\n\n";
if ($error) echo $error."\n\n";
exit($error ? 1 : 0);
}
@ -236,7 +251,7 @@ $prog = basename(array_shift($args));
if (!$args) usage();
$replace_file = false;
$dry_run = false;
while(($arg = array_shift($args)))
{
switch($arg)
@ -246,6 +261,11 @@ while(($arg = array_shift($args)))
usage();
break;
case '-d':
case '--dry-run':
$dry_run = true;
break;
default:
if ($args) // not last argument
{
@ -259,9 +279,9 @@ if (!file_exists($arg)) usage("Error: $arg not found!");
if (!is_dir($arg))
{
fix_api($arg,$replace_file);
fix_api($arg, $dry_run);
}
else
{
fix_api_recursive($arg,$replace_file);
fix_api_recursive($arg, $dry_run);
}

View File

@ -479,45 +479,7 @@ class egw extends egw_minimal
*/
static function redirect($url, $link_app=null)
{
// Determines whether the current output buffer should be flushed
$do_flush = true;
if (egw_json_response::isJSONResponse() || egw_json_request::isJSONRequest())
{
$response = egw_json_response::get();
$response->redirect($url, false, $link_app);
// If we are in a json request, we should not flush the current output!
$do_flush = false;
}
else
{
$file = $line = null;
if (headers_sent($file,$line))
{
throw new Api\Exception\AssertionFailed(__METHOD__."('".htmlspecialchars($url)."') can NOT redirect, output already started at $file line $line!");
}
if ($GLOBALS['egw']->framework instanceof jdots_framework && !empty($link_app))
{
egw_framework::set_extra('egw', 'redirect', array($url, $link_app));
$GLOBALS['egw']->framework->render('');
}
else
{
Header("Location: $url");
print("\n\n");
}
}
if ($do_flush)
{
@ob_flush(); flush();
}
// commit session (if existing), to fix timing problems sometimes preventing session creation ("Your session can not be verified")
if (isset($GLOBALS['egw']->session)) $GLOBALS['egw']->session->commit_session();
exit;
Api\Framework::redirect($url, $link_app);
}
/**

View File

@ -1,6 +1,6 @@
<?php
/**
* EGroupware API - favorites
* EGroupware API - Favorites server-side
*
* @link http://www.egroupware.org
* @author Nathan Gray <ng@stylite.de>
@ -11,246 +11,11 @@
* @version $Id$
*/
use EGroupware\Api\Framework\Favorites;
/**
* EGroupware favorites service-side:
* Favorites service-side
*
* Favorites are generated on serverside by following code in apps sidebox hook:
*
* display_sidebox($appname, lang('Favorites'), egw_favorites::favorite_list($appname));
*
* Clientside code resides in:
* - phpgwapi/js/jsapi/app_base.js
* - etemplate/js/et2_widget_favorites.js
*
* Favorites are stored with prefix "favorite_" in app preferences.
* @deprecated use Api\Framework\Favorites
*/
class egw_favorites
{
/**
* Include favorites when generating the page server-side
*
* Use this function in your sidebox (or anywhere else, I suppose) to
* get the favorite list when a nextmatch is _not_ on the page. If
* a nextmatch is on the page, it will update / replace this list.
*
* @param string $app application, needed to find preferences
* @param string $default preference name for default favorite, default "nextmatch-$app.index.rows-favorite"
*
* @return array with a single sidebox menu item (array) containing html for favorites
*/
public static function list_favorites($app, $default=null)
{
if (!$app)
{
return '';
}
if (!$default)
{
$default = "nextmatch-$app.index.rows-favorite";
}
// This target is used client-side to find & enable adding new favorites
$target = 'favorite_sidebox_'.$app;
/* @var $filters array an array of favorites*/
$filters = self::get_favorites($app);
$is_admin = $GLOBALS['egw_info']['user']['apps']['admin'];
$html = "<span id='$target' class='ui-helper-clearfix sidebox-favorites'><ul class='ui-menu ui-widget-content ui-corner-all favorites' role='listbox'>\n";
$default_filter = $GLOBALS['egw_info']['user']['preferences'][$app][$default];
if (!isset($default_filter) || !isset($filters[$default_filter]))
{
$default_filter = "blank";
}
// Get link for if there is no nextmatch - this is the fallback
$registry = egw_link::get_registry($app,'list');
if (!$registry)
{
$registry = egw_link::get_registry($app, 'index');
}
foreach($filters as $name => $filter)
{
//filter must not be empty if there's one, ignore it at the moment but it need to be checked how it got there in database
if (!$filter)
{
error_log(__METHOD__.'Favorite filter "'.$name.'" is not supposed to be empty, it should be an array. Skipping, more investigation needed. filter = '. array2string($filters[$name]));
continue;
}
$li = "<li data-id='$name' data-group='{$filter['group']}' class='ui-menu-item' role='menuitem'>\n";
$li .= '<a href="#" class="ui-corner-all" tabindex="-1">';
$li .= "<div class='" . ((string)$name === (string)$default_filter ? 'ui-icon ui-icon-heart' : 'sideboxstar') . "'></div>".
$filter['name'];
$li .= ($filter['group'] != false && !$is_admin || $name === 'blank' ? "" :
"<div class='ui-icon ui-icon-trash' title='" . lang('Delete') . "'></div>");
$li .= "</a></li>\n";
//error_log(__METHOD__."() $name, filter=".array2string($filter)." --> ".$li);
$html .= $li;
}
// If were're here, the app supports favorites, so add a 'Add' link too
$html .= "<li data-id='add' class='ui-menu-item' role='menuitem'><a href='javascript:app.$app.add_favorite()' class='ui-corner-all'>";
$html .= html::image($app, 'new') . lang('Add current'). '</a></li>';
$html .= '</ul></span>';
return array(
array(
'no_lang' => true,
'text' => $html,
'link' => false,
'icon' => false,
),
);
}
/**
* Get preferenced favorites sorted list
*
* @param string $app Application name as string
*
* @return (array|boolean) An array of sorted favorites or False if there's no preferenced sorted list
*
*/
public static function get_fav_sort_pref ($app)
{
$fav_sorted_list = array();
if (($fav_sorted_list = $GLOBALS['egw_info']['user']['preferences'][$app]['fav_sort_pref']))
{
return $fav_sorted_list;
}
else
{
return false;
}
}
/**
* Get a list of actual user favorites
* The default 'Blank' favorite is not included here
*
* @param string $app Current application
*
* @return array Favorite information
*/
public static function get_favorites($app)
{
$favorites = array(
'blank' => array(
'name' => lang('No filters'),
// Old
'filter' => array(),
// New
'state' => array(),
'group' => true
)
);
$pref_prefix = 'favorite_';
$sorted_list = array();
$fav_sort_pref = self::get_fav_sort_pref($app);
// Look through all preferences & pull out favorites
foreach((array)$GLOBALS['egw_info']['user']['preferences'][$app] as $pref_name => $pref)
{
if(strpos($pref_name, $pref_prefix) === 0)
{
if(!is_array($pref)) continue; // old favorite
$favorites[(string)substr($pref_name,strlen($pref_prefix))] = $pref;
}
}
if (is_array($fav_sort_pref))
{
foreach ($fav_sort_pref as $key)
{
$sorted_list[$key] = $favorites[$key];
}
$favorites = array_merge($sorted_list,$favorites);
}
return $favorites;
}
/**
* Create or delete a favorite for multiple users
*
* Current user needs to be an admin or it will just do nothing quietly
*
* @param string $app Current application, needed to save preference
* @param string $_name Name of the favorite
* @param string $action "add" or "delete"
* @param boolean|int|String $group ID of the group to create the favorite for, or 'all' for all users
* @param array $filters key => value pairs for the filter
* @return boolean Success
*/
public static function set_favorite($app, $_name, $action, $group, $filters = array())
{
// Only use alphanumeric for preference name, so it can be used directly as DOM ID
$name = strip_tags($_name);
$pref_name = "favorite_".$name;
// older group-favorites have just true as their group and are not deletable, if we dont find correct group
if ($group === true || $group === '1')
{
if (isset($GLOBALS['egw']->preferences->default[$app][$pref_name]))
{
$group = 'all';
}
else
{
foreach($GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'], true) as $gid)
{
$prefs = new preferences($gid);
$prefs->read_repository();
if (isset($prefs->user[$app][$pref_name]))
{
$group = $gid;
break;
}
}
}
}
if($group && $GLOBALS['egw_info']['apps']['admin'] && $group !== 'all')
{
$prefs = new preferences(is_numeric($group) ? $group : $GLOBALS['egw_info']['user']['account_id']);
}
else
{
$prefs = $GLOBALS['egw']->preferences;
}
$prefs->read_repository();
$type = $group === "all" ? "default" : "user";
//error_log(__METHOD__."('$app', '$name', '$action', ".array2string($group).", ...) pref_name=$pref_name, type=$type");
if($action == "add")
{
$filters = array(
// This is the name as user entered it, minus tags
'name' => $name,
'group' => $group ? $group : false,
'state' => $filters
);
$pref_name = "favorite_".preg_replace('/[^A-Za-z0-9-_]/','_',$name);
$result = $prefs->add($app,$pref_name,$filters,$type);
$pref = $prefs->save_repository(false,$type);
// Update preferences client side, or it could disappear
egw_json_response::get()->call('egw.set_preferences', (array)$pref[$app], $app);
egw_json_response::get()->data(isset($result[$app][$pref_name]));
return isset($result[$app][$pref_name]);
}
else if ($action == "delete")
{
$result = $prefs->delete($app,$pref_name, $type);
$pref = $prefs->save_repository(false,$type);
// Update preferences client side, or it could come back
egw_json_response::get()->call('egw.set_preferences', (array)$pref[$app], $app);
egw_json_response::get()->data(!isset($result[$app][$pref_name]));
return !isset($result[$app][$pref_name]);
}
}
}
class egw_favorites extends Favorites {}

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,8 @@
* @version $Id$
*/
use EGroupware\Api;
/**
* Stylite Pixelegg template
*/
@ -46,7 +48,7 @@ class pixelegg_framework extends jdots_framework
parent::__construct($template); // call the constructor of the extended class
// search 'mobile' dirs first
if (html::$ua_mobile) array_unshift ($this->template_dirs, 'mobile');
if (Api\Header\UserAgent::mobile()) array_unshift ($this->template_dirs, 'mobile');
}
/**
@ -61,9 +63,9 @@ class pixelegg_framework extends jdots_framework
{
// load our slider.js, but only if framework requested
if (!self::$header_done && $_GET['cd'] === 'yes' &&
!(html::$ua_mobile || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile'))
!(Api\Header\UserAgent::mobile() || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile'))
{
self::validate_file('/pixelegg/js/slider.js');
self::includeJS('/pixelegg/js/slider.js');
}
return parent::header($extra);
}
@ -97,7 +99,7 @@ class pixelegg_framework extends jdots_framework
/**
* Overwrite to NOT add customizable colors from jDots
*
* @see egw_framework::_get_css()
* @see Api\Framework::_get_css()
* @return array
*/
public function _get_css()
@ -131,7 +133,7 @@ class pixelegg_framework extends jdots_framework
if (preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i',$color)) // a little xss check
{
if (!html::$ua_mobile)
if (!Api\Header\UserAgent::mobile())
{
$ret['app_css'] .= "
/**

View File

@ -10,6 +10,8 @@
* @version $Id$
*/
use EGroupware\Api\Framework\Bundle;
if (php_sapi_name() !== 'cli') die("This is a commandline ONLY tool!\n");
$GLOBALS['egw_info'] = array(
@ -35,7 +37,7 @@ if (!preg_match('/grunt\.initConfig\(({.+})\);/s', $content, $matches) ||
$uglify =& $config['uglify'];
foreach(egw_framework::get_bundles() as $name => $files)
foreach(Bundle::all() as $name => $files)
{
if ($name == '.ts') continue; // ignore timestamp