<?php if(!function_exists('startedIndexPhp')) { header("location:../index.php"); exit();}
# streber - a php5 based project management system (c) 2005-2007 / www.streber-pm.org
# Distributed under the terms and conditions of the GPL as stated in lang/license.html
/**
* classes related to miscellenious string formatting and rendering
*
* included from: render_page.inc
*
*
* @author Thomas Mann
* @uses:
* @usedby: throughout everywhere
*
*/
/**
* Handy function to set a message that welcomes a user after login.
* This message can be adjusted conf
*/
function setWelcomeToProjectMessage($project)
{
global $auth;
$PH->messages[]= sprintf( __("Hello %s. Welcome to project %s"),
"<b>". asHtml($auth->cur_user->name) . "</b>",
"<b>". asHtml($project->name) . "</b>"
);
}
/**
* get theme-directory (without slashes) from current user-definition
*
* if undefined, return default-theme
*/
function getCurTheme()
{
global $auth;
global $PH;
global $g_theme_names;
### make sure theme is define ###
if(!is_null(confGet('THEME_OVERWRITE'))) {
$t= confGet('THEME_OVERWRITE');
if(isset($g_theme_names[$t]) && ($theme= $g_theme_names[$t])) {
return $theme;
}
}
if(isset($auth)
&& isset($auth->cur_user)
&& isset($g_theme_names[$auth->cur_user->theme])
&& ($theme= $g_theme_names[$auth->cur_user->theme])) {
return $theme;
}
return $g_theme_names[confGet('THEME_DEFAULT')];
}
/**
* get url to file from the current theme
*
* Used to access files from a theme. Example:
*
* echo '<img src="'. getThemeFile("/img/prio_{$obj->prio}.png") . '">';
*
*
* - if file does not exists, returns path to default theme
* - if file does not exists there a warning is been triggered
*/
function getThemeFile($filepath)
{
$theme= getCurTheme();
$path= "themes/".getCurTheme()."/".$filepath;
if(file_exists($path)) {
return $path;
}
### @@@pixtur:2006-10-11 using clean is not very good. Better would be default theme.
$path= "themes/clean/". $filepath;
if(file_exists($path)) {
return $path;
}
else {
trigger_error("unknown theme file '". $filepath. "'", E_USER_WARNING);
return "";
}
}
/**
* Exception thrown related to rendering
*
* Prints message and some debug-output.
*/
class RenderException extends Exception
{
public $backtrace=NULL;
function __construct($message=false, $code=false)
{
$this->message="";
if($message) {
$this->message="<pre>$message";
}
$this->backtrace = debug_backtrace();
}
}
/**
* convert url to external link-tag (remove http:/ and reduced to reasonable length)
*
* add http:/ if missing
* escapes html entities and returns save string
*/
function url2linkExtern($url, $show=NULL, $maxlen=20) {
if(!preg_match("/^http:\/\//",$url)) {
if(!$show) {
$show= $url;
}
$url="http://$url";
}
else {
if(!$show) {
$show= preg_replace("/^https?:\/\//","",$url);
}
}
if(strlen($show) > $maxlen) {
$show=substr($show,0,$maxlen)."...";
}
return "<a target='_blank' class='extern' href='". asHtml($url) ."'>" . asHtml($show) ."</a>";
}
/**
* convert url to mail link-tag (remove mail:// and reduced to reasonable length)
*/
function url2linkMail($url,$show=false, $maxlen=32) {
$url= asHtml($url);
if(!preg_match("/^mailto:/",$url)) {
if(!$show) {
$show= $url;
}
$url="mailto:$url";
}
else {
if(!$show) {
$show= preg_replace("/^mailto?:/","",$url);
}
}
if(strlen($show) > $maxlen) {
$show=substr($show,0,$maxlen)."...";
}
return "<a class='mail' href='".$url. "'>". $show."</a>";
}
/**
* Initialize a page for displaying task related content
*
* - inits:
* - breadcrumps
* - options
* - current section
* - navigation
* - pageType (including task folders)
* - pageTitle (as Task title)
*/
function initPageForTask($page, $task, $project=NULL)
{
global $PH;
$crumbs=array();
if(!$project) {
$project= Project::getVisibleById($task->project);
}
if($task->category == TCATEGORY_MILESTONE) {
$page->cur_crumb= 'projViewMilestones';
}
else if($task->category == TCATEGORY_VERSION) {
$page->cur_crumb= 'projViewVersions';
}
else if($task->category == TCATEGORY_DOCU || ($task->category == TCATEGORY_FOLDER && $task->show_folder_as_documentation)) {
$page->cur_crumb= 'projViewDocu';
}
else {
$page->cur_crumb= 'projViewTasks';
}
$page->crumbs= build_project_crumbs($project);
$page->options= build_projView_options($project);
$page->cur_tab='projects';
$page->title = $task->name;
$page->title_minor_html= $PH->getLink('taskView', sprintf('#%d', $task->id), array('tsk'=>$task->id));
/**
* render html buffer with page type of this task, including parent folders
* and type and status.
*
* - This is the tiny text about the page title.
*/
{
global $g_status_names;
$type ="";
$status= $task->status != STATUS_OPEN && isset($g_status_names[$task->status])
? ' ('.$g_status_names[$task->status] .')'
: '';
$label= $task->getLabel();
if(!$label) {
$label= __("Task");
}
if($folder= $task->getFolderLinks()) {
$type = $folder ." > " . $label . ' '. $status ;
}
else {
$type = $label .' ' . $status;
}
$page->type = $type;
}
}
/**
* Initialize a page for displaying comment related content
*
* - inits:
* - breadcrumps
* - options
* - current section
* - navigation
* - pageType (including task folders)
* - pageTitle (as Task title)
*/
function initPageForComment($page, $comment, $project=NULL)
{
global $PH;
$crumbs=array();
if(!$project) {
$project= Project::getVisibleById($comment->project);
}
$page->cur_crumb= 'projViewTasks';
if($comment->task) {
if($task = Task::getVisibleById($comment->task)) {
if($task->category == TCATEGORY_MILESTONE) {
$page->cur_crumb= 'projViewMilestones';
}
else if($task->category == TCATEGORY_VERSION) {
$page->cur_crumb= 'projViewVersions';
}
else if($task->category == TCATEGORY_DOCU) {
$page->cur_crumb= 'projViewDocu';
}
}
}
$page->crumbs= build_project_crumbs($project);
$page->options= build_projView_options($project);
$page->cur_tab='projects';
if($comment->name) {
$page->title = $comment->name;
}
else {
$page->title = __('Comment');
}
$page->title_minor_html= $PH->getLink('commentView', sprintf('#%d', $comment->id), array('comment'=>$comment->id));
/**
* render html buffer with page type of this task, including parent folders
* and type and status.
*
* - This is the tiny text about the page title.
*/
{
global $g_status_names;
$type ="";
if($task) {
if($folder= $task->getFolderLinks()) {
$type = $folder ." > " ;
}
$type.= $task->getLink() . ' > ' ;
}
$type .= __('Comment');
$page->type = $type;
}
}
/**
* Initialize a page for displaying file related content
*
* - inits:
* - breadcrumps
* - options
* - current section
* - navigation
* - pageType (including task folders)
* - pageTitle (as Task title)
*/
function initPageForFile($page, $file, $project=NULL)
{
global $PH;
$crumbs=array();
if(!$project) {
$project= Project::getVisibleById($file->project);
}
$task = Task::getVisibleById($file->parent_item);
$page->cur_crumb= 'projViewFiles';
$page->crumbs= build_project_crumbs($project);
$page->options= build_projView_options($project);
$page->cur_tab='projects';
if($file->name) {
$page->title = $file->name;
}
else {
$page->title = __('File');
}
$page->title_minor_html= $PH->getLink('fileView', sprintf('#%d', $file->id), array('file'=>$file->id));
/**
* render html buffer with page type of this task, including parent folders
* and type and status.
*
* - This is the tiny text about the page title.
*/
{
global $g_status_names;
$type ="";
if($task) {
if($folder= $task->getFolderLinks()) {
$type = $folder ." > " ;
}
$type.= $task->getLink() . ' > ' ;
}
$type .= __('File');
$page->type = $type;
}
}
/**
* Initialize a page for displaying effort related content
*
* - inits:
* - breadcrumps
* - options
* - current section
* - navigation
* - pageType (including task folders)
* - pageTitle (as Task title)
*/
function initPageForEffort($page, $effort, $project=NULL)
{
global $PH;
$crumbs=array();
if(!$project) {
$project= Project::getVisibleById($effort->project);
}
$task = Task::getVisibleById($effort->task);
$page->cur_crumb= 'projViewEfforts';
$page->crumbs= build_project_crumbs($project);
$page->options= build_projView_options($project);
$page->cur_tab='projects';
if($effort->name) {
$page->title = $effort->name;
}
else {
$page->title = __('Effort');
}
$page->title_minor_html= $PH->getLink('effortView', sprintf('#%d', $effort->id), array('effort'=>$effort->id));
/**
* render html buffer with page type of this task, including parent folders
* and type and status.
*
* - This is the tiny text about the page title.
*/
{
global $g_status_names;
$type ="";
if($task) {
if($folder= $task->getFolderLinks()) {
$type = $folder ." > " ;
}
$type.= $task->getLink() . ' > ' ;
}
$type .= __('Effort');
$page->type = $type;
}
}
function build_person_crumbs(&$person) {
$crumbs=array();
$crumbs[]= new NaviCrumb(array(
'target_id' =>'personList',
'name' =>__('Other Persons','page option'),
));
$crumbs[]= new NaviCrumb(array(
'target_id' => 'personView',
'target_params' => array('person'=> $person->id),
'name' => $person->name,
'type'=>'person',
));
return $crumbs;
}
function build_company_crumbs(&$company) {
$crumbs=array();
$crumbs[]= new NaviCrumb(array(
'target_id' => 'companyList',
));
$crumbs[]= new NaviCrumb(array(
'target_id' => 'companyView',
'name' => $company->name,
'target_params' => array('company'=>$company->id),
));
return $crumbs;
}
function build_project_crumbs($project) {
$a=array();
### breadcrumbs (distinguish active/closed projects ###
/*if($project->status > 3) {
$a[]=
new NaviCrumb(array(
'target_id'=>'projListClosed',
));
}
else if($project->status == -1) {
$a[]=
new NaviCrumb(array(
'target_id'=>'projListTemplates',
));
}
else {
$a[]=
new NaviCrumb(array(
'target_id'=>'projList',
));
}
*/
$a[]= new NaviCrumb(array(
'target_id'=>'projView',
'name'=> $project->getShort(),
'tooltip'=> $project->name,
'target_params'=>array('prj'=>$project->id ),
'type'=>'project',
));
return $a;
}
/**
* renders the list of open projects that will be display when opening the project selector
*
* The opening is done with javascript. Placing the list beside the Project Selector icon
* is done by css only. This is a little bit tricky, because the Tab-list is already an
* span which allows only further Spans to be included...
*
* The selectorlist is triggered by
*
* read more at #3867
*/
function buildProjectSelector()
{
global $auth;
if(!$auth->cur_user || !$auth->cur_user->id) {
return "";
}
$buffer= "";
global $PH;
require_once(confGet('DIR_STREBER') . 'db/class_company.inc.php');
require_once(confGet('DIR_STREBER') . "db/class_project.inc.php");
$buffer.="<span id=projectselector class=selector> </span>";
$buffer.= "<span style='display:none;' id='projectselectorlist' class=selectorlist><span class=selectorlist_content>";
foreach(Company::getAll() as $c) {
if($projects= Project::getAll(array(
'order_by' => 'c.name',
'company' => $c->id,
))) {
$buffer .= "<div class='companies'><span style='float:left;margin-right:3px;'>" . __("for","short for client") . "</span>" . $c->getLink() . "</div>";
$buffer .= "<div class='projects'><ul>";
foreach($projects as $p) {
$buffer.= "<li>" . $PH->getLink('projView',$p->name, array('prj' => $p->id)) . "</li>";
}
$buffer .= "</ul></div>";
}
}
/* projects without client */
if($projects= Project::getAll(array(
'order_by' => 'c.name',
'company' => 0,
))) {
$buffer .= "<div class='companies'><span style='float:left;margin-right:3px;'>" . __("without client","short for client") . "</span> </div>";
$buffer .= "<div class='projects'><ul>";
foreach($projects as $p){
$buffer.= "<li>" . $PH->getLink('projView',$p->name, array('prj' => $p->id)) . "</li>";
}
$buffer .= "</ul></div>";
}
$buffer.="</span></span>";
return $buffer;
}
/**
* renders the list of open pages available in homeView
*
* The opening is done with javascript. Placing the list beside the Home Selector icon
* is done by css only. This is a little bit tricky, because the Tab-list is already an
* span which allows only further Spans to be included...
*
* read more at #3867
*/
function buildHomeSelector()
{
global $auth;
global $PH;
if(!$auth->cur_user || !$auth->cur_user->id) {
return "";
}
$buffer= "";
$buffer.="<span id=homeselector class=selector> </span>";
$buffer.= "<span style='display:none;' id='homeselectorlist' class=selectorlist><span class=selectorlist_content>";
/*
foreach(array('home', 'homeTasks', 'homeBookmarks', 'homeEfforts', 'homeAllChanges') as $p) {
$buffer.= $PH->getLink($p,NULL, array());
}
*/
$buffer.= $PH->getLink('home',NULL, array());
$buffer.= $PH->getLink('homeTasks',NULL, array());
if($auth->cur_user->settings & USER_SETTING_ENABLE_EFFORTS) {
$buffer.= $PH->getLink('homeEfforts',NULL, array());
}
if($auth->cur_user->settings & USER_SETTING_ENABLE_BOOKMARKS) {
$buffer.= $PH->getLink('homeBookmarks',NULL, array());
}
$buffer.= $PH->getLink('homeAllChanges',NULL, array());
$buffer.="</span></span>";
return $buffer;
}
/**
* build the navigation-options for project view
* Note: for project_breadcrumps see render/render_misc
*/
function build_projView_options($project)
{
global $auth;
$options=array();
if($project->settings & PROJECT_SETTING_ENABLE_TASKS) {
$options[]= new NaviOption(array(
'target_id'=>'projViewTasks',
'name'=>__('Tasks','Project option'),
'target_params'=>array('prj'=>$project->id )
));
}
$options[]= new NaviOption(array(
'target_id'=>'projViewDocu',
'name'=>__('Topics','Project option'),
'target_params'=>array('prj'=>$project->id )
));
if($project->settings & PROJECT_SETTING_ENABLE_MILESTONES) {
$options[]= new NaviOption(array(
'target_id'=>'projViewMilestones',
'name'=>__('Milestones','Project option'),
'target_params'=>array('prj'=>$project->id )
));
}
if($project->settings & PROJECT_SETTING_ENABLE_VERSIONS) {
$options[]= new NaviOption(array(
'target_id'=>'projViewVersions',
'name'=>__('Versions','Project option'),
'target_params'=>array('prj'=>$project->id )
));
}
if($project->settings & PROJECT_SETTING_ENABLE_FILES) {
$options[]=new NaviOption(array(
'target_id'=>'projViewFiles',
'name'=>__('Files','Project option'),
'target_params'=>array('prj'=>$project->id )
));
}
if($project->settings & PROJECT_SETTING_ENABLE_EFFORTS) {
$options[]= new NaviOption(array(
'target_id'=>'projViewEfforts',
'name'=>__('Efforts','Project option'),
'target_params'=>array('prj'=>$project->id )
));
}
#if(($auth->cur_user->user_rights & RIGHT_VIEWALL) && ($auth->cur_user->user_rights & RIGHT_EDITALL)){
# $options[]= new NaviOption(array(
# 'target_id'=>'projViewEffortCalculations',
# 'name'=>__('Calculation','Project option'),
# 'target_params'=>array('prj'=>$project->id )
# ));
#}
$options[]= new NaviOption(array(
'target_id'=>'projViewChanges',
'name'=>__('Changes','Project option'),
'target_params'=>array('prj'=>$project->id )
));
return $options;
}
function build_personList_options()
{
return array(
new NaviOption(array(
'target_id'=>'personList',
'name'=>__('Persons', 'page option')
))
);
}
function build_companyList_options()
{
return array(
new NaviOption(array(
'target_id'=>'companyList',
'name'=>__('Companies', 'page option')
)),
);
}
function build_projList_options()
{
return array(
new NaviOption(array(
'target_id'=>'projList',
'name'=>__('Active')
)),
new NaviOption(array(
'target_id'=>'projListClosed',
'name'=>__('Closed')
)),
new NaviOption(array(
'target_id'=>'projListTemplates',
'name'=>__('Templates'),
'separated'=> true,
)),
);
}
/**
* actually this function is obsolete since all error-related debug-output should
* be generated by trigger_error (which has it's own backtrace-function)
*/
function renderBacktrace($arr)
{
$buffer='';
### ignore empty array ###
if(!count($arr)) {
return false;
}
$buffer.= "<table class=backtrace>";
### write header ###
$buffer.="<tr>";
foreach($arr[0] as $key=>$value) {
$buffer.="<th>$key</th>";
}
$buffer.="</tr>";
### write lines ###
foreach($arr as $n) {
$buffer.="<tr>";
foreach($n as $key=>$value) {
if(is_array($value)) {
$buffer.='<td>';
foreach($value as $no) {
if(is_object($no)) {
$buffer.=get_class($no);
}
else {
$buffer.=$no;
}
$buffer.=".<br>";
}
$buffer.="</td>";
}
else if(is_object($value)) {
$buffer.='<td>';
#$buffer.=join("##<br>",$value);
$buffer.="</td>";
}
else {
$value= str_replace("c:\\programme\\Apache13\\Apache\\htdocs\\nod\\","",$value);
$buffer.="<td>$value</td>";
}
}
$buffer.="</tr>";
}
$buffer.= "</table>";
return $buffer;
}
/**
* wrapper functions for formatted time output
* cache strings to avoid too many access to the language tables and
* to attempt to fix portability problems with strftime
*/
function getUserFormatDate()
{
global $g_userFormatDate;
if(!$g_userFormatDate)
{
$g_userFormatDate = __('%b %e, %Y', 'strftime format string');
// fix %e formatter if not supported (e.g. on Windows)
if(strftime("%e", mktime(12, 0, 0, 1, 1)) != '1') {
$g_userFormatDate = str_replace("%e", "%d", $g_userFormatDate);
}
}
return $g_userFormatDate;
}
/**
* Note: we cache the format in a global variable to speed things up
* use clearCachedTimeFormats() when dealing with changing languages.
*/
function getUserFormatTime()
{
global $g_userFormatTime;
if(!$g_userFormatTime) {
$g_userFormatTime = __('%I:%M%P', 'strftime format string');
}
return $g_userFormatTime;
}
function getUserFormatTimestamp()
{
global $g_userFormatTimestamp;
if(!$g_userFormatTimestamp)
{
$g_userFormatTimestamp = __('%a %b %e, %Y %I:%M%P', 'strftime format string');
# Fix %e formatter if not supported (e.g. on Windows)
if(strftime("%e", mktime(12, 0, 0, 1, 1)) != '1') {
$g_userFormatTimestamp = str_replace("%e", "%d", $g_userFormatTimestamp);
}
}
return $g_userFormatTimestamp;
}
/**
* NOTE:
* - all time RENDER functions will ADD user's Time offset to render time in client time
* - vize versa all parseTime functions (see render/render_fields.inc.php) will SUBSTRACT the time offset
* before storing anything to the DB
*/
function renderTimestamp($t)
{
if(!$t || $t=="0000-00-00 00:00:00") {
return "";
}
if(is_string($t)) {
$t= strToClientTime($t);
}
### omit time with exactly midnight
if(gmdate("H:i:s",$t)=="00:00:00") {
$str= gmstrftime(getUserFormatDate(), $t);
}
else {
$str= gmstrftime(getUserFormatTimestamp(), $t);
}
return $str;
}
function renderTimestampHtml($t)
{
if(!$str= renderTimestamp($t)) {
return "-";
}
if(is_string($t)) {
$t= strToClientTime($t);
}
/* ### hilight new dates ###
if(isset($auth) && isset($auth->cur_user) && gmdate("Y-m-d H:i:s",$t) > $auth->cur_user->last_logout) {
$str_tooltip= __("new since last logout");
return "<span class=new title='$str_tooltip'>$str</span>";
}
else {
*/
return $str;
}
function renderTime($t)
{
if(!$t || $t=="0000-00-00 00:00:00") {
return "";
}
if(is_string($t)) {
$t= strToClientTime($t);
}
return gmstrftime(getUserFormatTime(), $t);
}
function renderDuration($t)
{
if(!$t || $t=="0000-00-00 00:00:00") {
return "";
}
if($t > confGet('WORKDAYS_PER_WEEK') * confGet('WORKHOURS_PER_DAY') * 60 * 60) {
return sprintf(__('%s weeks'), floor($t / (confGet('WORKDAYS_PER_WEEK') * confGet('WORKHOURS_PER_DAY') * 60 * 60)));
}
else if($t > confGet('WORKHOURS_PER_DAY') * 60 * 60) {
return sprintf(__('%s days'), floor($t / (confGet('WORKHOURS_PER_DAY') * 60 * 60)));
}
else if($t > 60 * 60) {
return sprintf(__('%s hours'), floor($t / (60 * 60)));
}
else {
return sprintf(__('%s min'), floor($t / 60));
}
}
/**
* expects GMT times!
*/
function renderDate($t, $smartnames= true) {
if(!$t || $t=="0000-00-00 00:00:00" || $t=="0000-00-00") {
return "";
}
if(is_string($t)) {
### do not offset simple dates ###
if(preg_match("/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/", $t)) {
$t= strToClientTime($t);
}
else {
$t= strToGMTime($t);
}
}
else {
global $auth;
$time_offset= 0;
if(isset($auth->cur_user)) {
$time_offset = $auth->cur_user->time_offset;
}
$t= $time_offset;
}
if($smartnames && gmdate('Y-m-d', time()) == gmdate('Y-m-d', $t)) {
$str= __('Today');
if(gmdate('H:i:s',$t) !== '00:00:00') {
$str.= ' ' . gmstrftime(getUserFormatTime(), $t);
}
}
else if($smartnames && gmdate('Y-m-d',time()) == gmdate('Y-m-d', $t + 60*60*24)) {
$str= __('Yesterday');
#if(gmdate('H:i:s',$t) !== '00:00:00') {
# $str.= ' ' . gmstrftime(getUserFormatTime(), $t);
#}
}
else {
$str= gmstrftime(getUserFormatDate(), $t);
}
return $str;
}
function renderDateHtml($t)
{
global $auth;
### this is the visible string ###
if(!$str= renderDate($t)) {
return "-";
}
### this is for the tooltip ###
if(is_string($t)) {
$t= strToClientTime($t);
}
else {
global $auth;
$time_offset= 0;
if(isset($auth->cur_user)) {
$time_offset = $auth->cur_user->time_offset;
}
$t+= $time_offset;
}
### tooltip ? ###
$str_tooltip='';
if(gmdate('H:i:s',$t) != '00:00:00') {
$str_tooltip= gmstrftime(getUserFormatTimestamp(), $t);
}
if($str_tooltip){
return "<span class='date' title='$str_tooltip'>$str</span>";
}
else {
return $str;
}
}
/**
* renders a time as distance ago... (expects GMT times)
*/
function renderTimeAgo($t)
{
$duration= time() - strToGMTime($t);
if(strToGMTime($t) == 0) {
return __("never");
}
if($duration < 60 * 5) {
return __('just now');
}
if($duration < 60 * 60) {
return sprintf(__('%smin ago'), ceil($duration / 60));
}
if($duration < 60 * 60 * 2) {
return __('1 hour ago');
}
if($duration < 60 * 60 * 24) {
return sprintf(__('%sh ago'), ceil($duration / 60 / 60));
}
if($duration < 60 * 60 * 24 * 62) {
return sprintf(__('%s days ago'), ceil($duration / 60 / 60 / 24));
}
if($duration < 60 * 60 * 24 * 365 * 2) {
return sprintf(__('%s months ago'), ceil($duration / 60 / 60 / 24 / 30));
}
if($duration < 60 * 60 * 24 * 365 * 20) {
return sprintf(__('%s years ago'), ceil($duration / 60 / 60 / 24 / 365));
}
}
function renderPubLevelName($pub_level)
{
global $g_pub_level_names;
if(isset($g_pub_level_names[$pub_level])) {
return $g_pub_level_names[$pub_level];
}
else {
return '';
}
}
/**
* want duration in seconds
*/
function renderEstimatedDuration($duration)
{
$duration /= (60 * 60);
$hours_per_day= confGet('WORKHOURS_PER_DAY');
$days_per_week= confGet('WORKDAYS_PER_WEEK');
if(!$duration) {
return '';
}
if($duration <= $hours_per_day) {
$type= 'hours';
$str= sprintf(__('%s hours'), $duration);
}
else if($duration < $hours_per_day * $days_per_week) {
$type= 'days';
$str= sprintf(__('%s days'), $duration / $hours_per_day);
}
else {
$type= 'weeks';
$str= sprintf(__('%s weeks'), $duration / $hours_per_day / $days_per_week);
}
return $str;
}
/**
* renders a html-estimation / completion graph
*
* @used_by: list_tasks, list_milestones
*/
function renderEstimationGraph($estimated, $estimated_max, $completion)
{
$str= '';
#if(preg_match("/(\d\d):(\d\d):(\d\d)/", $obj->estimated, $matches)) {
# $estimated= ($matches[1]*60*60 + $matches[2]*60 + $matches[3]) / 60;
if($estimated) {
$estimated= $estimated/60/60;
$estimated_max= $estimated_max/60/60;
$hours_per_day= confGet('WORKHOURS_PER_DAY');
$days_per_week= confGet('WORKDAYS_PER_WEEK');
if($estimated_max <= $hours_per_day*2) {
$type= 'hours';
$width_estimated= $estimated * 4;
$width_estimated_max= $estimated_max * 4;
$str_estimated= sprintf(__('estimated %s hours'), $estimated);
$str_estimated_max= $estimated_max
? '('. sprintf(__('%s hours max'), $estimated_max) .')'
: '';
}
else if($estimated_max < $hours_per_day * $days_per_week*2) {
$type= 'days';
$width_estimated= $estimated / $hours_per_day * 6;
$width_estimated_max= $estimated_max / $hours_per_day * 6;
$str_estimated= sprintf(__('estimated %s days'), $estimated / $hours_per_day);
$str_estimated_max= $estimated_max
? '('. sprintf(__('%s days max'), $estimated_max / $hours_per_day) .')'
: '';
}
else {
$type= 'weeks';
$width_estimated= $estimated / $hours_per_day / $days_per_week * 12;
$width_estimated_max= $estimated_max / $hours_per_day / $days_per_week * 12;
$str_estimated= sprintf(__('estimated %s weeks'), $estimated / $hours_per_day / $days_per_week);
$str_estimated_max = $estimated_max
? '('. sprintf(__('%s weeks max'), $estimated_max / $hours_per_day / $days_per_week) .')'
: '';
}
$str_completion= sprintf(__("%2.0f%% completed"), $completion);
$html_tooltip= "title='". $str_estimated . " ". $str_estimated_max." / " . $str_completion. "'";
if($completion) {
$width_completion= $completion / 100 * $width_estimated;
$html_completion= "<div class='estimated {$type}_completed' style='width:{$width_completion}px;'></div>";
}
else {
$html_completion='';
}
if($width_estimated_max > $width_estimated) {
$width_risk= floor($width_estimated_max - $width_estimated)-1;
$html_risk= "<div class='{$type}_risk' style='width:{$width_risk}px;'></div>";
}
else {
$html_risk='';
}
$str= "<div $html_tooltip class='estimated {$type}' style='width:{$width_estimated_max}px;'>"
. $html_completion
. $html_risk
. "</div>";
}
return $str;
}
/**
* renders a date suitable for page titles/subtitles
* e.g.: Monday, 1st
*/
function renderTitleDate($t)
{
/*
As far as I (ganesh) know, the strftime %e format is good enough for all languages except English.
For English we use the S format of function date() to get ordinals, which has no strftime equivalent.
*/
global $g_lang;
if($g_lang == 'en')
$str = date('l, F jS', $t);
else
$str = strftime(__('%A, %B %e', 'strftime format string'), $t);
return $str;
}
function renderFilesize($bytes)
{
$bytes= intval($bytes);
if( $bytes < 1024 ) {
return $bytes;
}
else if( $bytes < 1024 * 1024) {
return intval($bytes / 1024) . "k";
}
else {
return (intval(($bytes / 1024/1024) * 10) / 10.0) . "mb";
}
}
/**
* @@@ move this somewhere else...
* use difference_engine to render differences between two versions of a texts
*/
function render_changes($text_org,$text_new)
{
require_once(confGet('DIR_STREBER') . "std/difference_engine.inc.php");
$buffer= '';
$ota = explode( "\n", str_replace( "\r\n", "\n", $text_org ) );
$nta = explode( "\n", str_replace( "\r\n", "\n", $text_new ) );
$diffs = new Diff( $ota, $nta );
$debug='';
$buffer.="<table class=diff>";
foreach($diffs as $d) {
$buffer.="<tr>";
$buffer.="<td class=changeblock colspan=2></td></tr><tr>";
foreach($d as $do) {
if($do->type == 'add') {
$buffer.="<tr>";
$buffer.="<td class=neutral></td>";
$buffer.="<td class=add>". arrayAsHtml($do->closing). "</td>";
$buffer.="</tr>";
}
else if($do->type =='delete') {
$buffer.="<tr>";
$buffer.="<td class=deleted>". arrayAsHtml($do->orig). "</td>";
$buffer.="<td class=neutral></td>";
$buffer.="</tr>";
}
else if($do->type =='change') {
$wld= new WordLevelDiff($do->orig, $do->closing);
$buffer_org ='';
$buffer_new ='';
foreach($wld->edits as $e) {
switch($e->type) {
case 'copy':
$orig= implode('',$e->orig);
$buffer_org.= asHtml($orig);
$buffer_new.= asHtml($orig);
break;
case 'add':
$buffer_org.= '<span class=add_place> </span>';
$closing=implode('',$e->closing);
$buffer_new.= '<span class=add>'.asHtml($closing).'</span>';
break;
case 'change':
$orig= implode('',$e->orig);
$closing= implode('',$e->closing);
$buffer_org.= '<span class=changed>'.asHtml($orig).'</span>';
$buffer_new.= '<span class=changed>'.asHtml($closing).'</span>';
break;
case 'delete':
$orig= implode('',$e->orig);
$buffer_org.= '<span class=deleted>'.asHtml($orig).'</span>';
$buffer_new.= '<span class=delete_place> </span>';
break;
default:
trigger_error("undefined edit work edit", E_USER_WARNING);
break;
}
}
$buffer_org= str_replace("\n", '<br>', $buffer_org);
$buffer_new= str_replace("\n", '<br>', $buffer_new);
$buffer.="<tr>";
$buffer.="<td class='changed'>". $buffer_org. "</td>";
$buffer.="<td class='changed'>". $buffer_new. "</td>";
$buffer.="</tr>";
}
else if($do->type == 'copy') {
$buffer.="<tr>";
$buffer.="<td class='copy'>". arrayAsHtml($do->orig). "</td>";
$buffer.="<td class='copy'>". arrayAsHtml($do->closing). "</td>";
$buffer.="</tr>";
}
else {
trigger_error("unknown diff type");
}
}
$buffer.="</tr>";
}
$buffer.="</table>";
return $buffer;
}
/**
* implodes an array of strings into save html output
*
* - used for rendering differences
*/
function arrayAsHtml($strings)
{
$buffer = '';
$sep = '';
foreach($strings as $s) {
$buffer.= $sep.asHtml($s);
$sep = '<br>';
}
$buffer= str_replace(" ", " ", $buffer);
return $buffer;
}
?>