2005-10-28 20:29:05 +02:00
< ? php
2006-04-20 19:12:30 +02:00
/**
* eGroupWare eTemplate Widget for custom fields
*
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ package etemplate
* @ link http :// www . egroupware . org
* @ author Cornelius Weiss < egw @ von - und - zu - weiss . de >
* @ version $Id $
*/
2005-10-28 20:29:05 +02:00
/**
2006-03-14 14:54:17 +01:00
* This widget generates a template for customfields based on definitions in egw_config table
2005-10-28 20:29:05 +02:00
*
2005-11-10 06:15:06 +01:00
* @ package etemplate
2005-11-08 15:33:16 +01:00
* @ subpackage extensions
2005-10-28 20:29:05 +02:00
* @ author RalfBecker - At - outdoor - training . de
* @ author Cornelius Weiss < egw @ von - und - zu - weiss . de >
2005-11-08 15:33:16 +01:00
* @ license GPL - GNU General Public License
2005-10-28 20:29:05 +02:00
*/
class customfields_widget
{
var $public_functions = array (
'pre_process' => True ,
);
2007-07-11 17:39:41 +02:00
var $human_name = array (
'customfields' => 'custom fields' ,
'customfields-types' => 'custom field types' ,
'customfields-list' => 'custom field list' ,
2007-11-22 21:08:58 +01:00
'customfields-no-label' => 'custom fields without label' ,
2007-07-11 17:39:41 +02:00
);
2005-10-28 20:29:05 +02:00
2007-07-11 17:39:41 +02:00
/**
2007-11-27 16:03:54 +01:00
* Allowd types of customfields
*
* The additionally allowed app - names from the link - class , will be add by the edit - method only ,
* as the link - class has to be called , which can NOT be instanciated by the constructor , as
* we get a loop in the instanciation .
*
* @ var array
*/
2007-07-11 17:39:41 +02:00
var $cf_types = array (
'text' => 'Text' ,
'label' => 'Label' ,
'select' => 'Selectbox' ,
'radio' => 'Radiobutton' ,
'checkbox' => 'Checkbox' ,
'date' => 'Date' ,
'date-time' => 'Date+Time' ,
'select-account' => 'Select account' ,
2007-11-27 16:03:54 +01:00
'button' => 'Button' , // button to execute javascript
2007-07-11 17:39:41 +02:00
'link-entry' => 'Select entry' , // should be last type, as the individual apps get added behind
);
2005-10-28 20:29:05 +02:00
/**
2007-11-27 16:03:54 +01:00
* @ var $prefix string Prefix for every custiomfield name returned in $content ( # for general (admin) customfields)
*/
2005-10-28 20:29:05 +02:00
var $prefix = '#' ;
2007-11-22 21:08:58 +01:00
/**
* Current application
*
* @ var string
*/
var $appname ;
/**
* Instance of the config class for $appname
*
* @ var config
*/
var $config ;
/**
* Our customfields as name => data array
*
* @ var array
*/
var $customfields ;
var $types ;
var $advanced_search ;
2005-10-28 20:29:05 +02:00
2007-11-27 16:03:54 +01:00
2007-11-22 21:08:58 +01:00
function customfields_widget ( $ui , $appname = null )
2005-10-28 20:29:05 +02:00
{
2007-11-22 21:08:58 +01:00
$this -> appname = $appname ? $appname : $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
2005-10-28 20:29:05 +02:00
$this -> config =& CreateObject ( 'phpgwapi.config' , $this -> appname );
$this -> config -> appname = $this -> appname ;
$config = $this -> config -> read_repository ();
2005-11-08 15:33:16 +01:00
//merge old config_name in egw_config table
2005-10-28 20:29:05 +02:00
$config_name = isset ( $config [ 'customfields' ]) ? 'customfields' : 'custom_fields' ;
2007-11-26 18:35:29 +01:00
$this -> customfields = $config [ $config_name ];
2006-03-14 14:54:17 +01:00
$this -> types = $config [ 'types' ];
2005-11-02 17:48:24 +01:00
$this -> advanced_search = $GLOBALS [ 'egw_info' ][ 'etemplate' ][ 'advanced_search' ];
2005-10-28 20:29:05 +02:00
}
function pre_process ( $name , & $value , & $cell , & $readonlys , & $extension_data , & $tmpl )
{
2007-11-26 18:35:29 +01:00
if ( $this -> appname == 'etemplate' || ! $this -> customfields ) // if we are in the etemplate editor or the app has no cf's, load the cf's from the app the tpl belongs too
2007-11-22 21:08:58 +01:00
{
list ( $app ) = explode ( '.' , $tmpl -> name );
if ( $app && $app != $this -> appname ) $this -> customfields_widget ( null , $app );
}
2007-07-12 09:30:20 +02:00
$type2 = $cell [ 'size' ];
2007-11-27 16:03:54 +01:00
$fields_with_vals = array ();
2007-07-12 09:30:20 +02:00
2007-11-22 21:08:58 +01:00
$fields = $this -> customfields ;
// check if name refers to a single custom field --> show only that
if (( $pos = strpos ( $cell [ 'name' ], $this -> prefix )) !== false && // allow the prefixed name to be an array index too
preg_match ( " / $this->prefix ([^ \ ]]+)/ " , $cell [ 'name' ], $matches ) && isset ( $fields [ $name = $matches [ 1 ]]))
{
$fields = array ( $name => $fields [ $name ]);
$value = array ( $this -> prefix . $name => $value );
}
2007-07-11 17:39:41 +02:00
switch ( $type = $cell [ 'type' ])
{
case 'customfields-types' :
$cell [ 'type' ] = 'select' ;
2007-11-27 16:03:54 +01:00
foreach ( $this -> cf_types as $lname => $label )
{
$cell [ 'sel_options' ][ $lname ] = lang ( $label );
$fields_with_vals [] = $lname ;
}
2007-07-11 17:39:41 +02:00
$link_types = ExecMethod ( 'phpgwapi.bolink.app_list' , '' );
ksort ( $link_types );
2007-11-27 16:03:54 +01:00
foreach ( $link_types as $lname => $label ) $cell [ 'sel_options' ][ $lname ] = '- ' . $label ;
2007-07-11 17:39:41 +02:00
$cell [ 'no_lang' ] = true ;
return true ;
case 'customfields-list' :
2007-11-27 16:03:54 +01:00
foreach ( array_reverse ( $fields ) as $lname => $field )
2007-07-11 17:39:41 +02:00
{
2007-11-27 16:03:54 +01:00
if ( ! empty ( $type2 ) && ! empty ( $field [ 'type2' ]) && strpos ( ',' . $field [ 'type2' ] . ',' , ',' . $type2 . ',' ) === false ) continue ; // not for our content type//
if ( isset ( $value [ $this -> prefix . $lname ]) && $value [ $this -> prefix . $lname ] !== '' ) //break;
{
$fields_with_vals [] = $lname ;
}
//$stop_at_field = $name;
2007-07-11 17:39:41 +02:00
}
break ;
2007-11-27 16:03:54 +01:00
default :
foreach ( array_reverse ( $fields ) as $lname => $field )
{
$fields_with_vals [] = $lname ;
}
2007-07-11 17:39:41 +02:00
}
$readonly = $cell [ 'readonly' ] || $readonlys [ $name ] || $type == 'customfields-list' ;
2005-11-08 15:33:16 +01:00
2007-11-22 21:08:58 +01:00
if ( ! is_array ( $fields ))
2005-10-28 20:29:05 +02:00
{
$cell [ 'type' ] = 'label' ;
return True ;
}
2007-07-11 17:39:41 +02:00
// making the cell an empty grid
$cell [ 'type' ] = 'grid' ;
$cell [ 'data' ] = array ( array ());
$cell [ 'rows' ] = $cell [ 'cols' ] = 0 ;
2007-11-22 21:08:58 +01:00
2007-07-11 17:39:41 +02:00
$n = 1 ;
2007-11-27 16:03:54 +01:00
foreach ( $fields as $lname => $field )
2005-10-28 20:29:05 +02:00
{
2007-11-27 16:03:54 +01:00
if ( ! ( array_search ( $lname , $fields_with_vals ) === false ))
{
if ( $stop_at_field && $lname == $stop_at_field ) break ; // no further row necessary
2007-07-11 17:39:41 +02:00
2006-11-23 14:52:56 +01:00
// check if the customfield get's displayed for type $value, we can have multiple comma-separated types now
2007-11-27 16:03:54 +01:00
if ( ! empty ( $type2 ) && ! empty ( $field [ 'type2' ]) && strpos ( ',' . $field [ 'type2' ] . ',' , ',' . $type2 . ',' ) === false )
2005-10-28 20:29:05 +02:00
{
2006-03-14 14:54:17 +01:00
continue ; // not for our content type
2005-10-28 20:29:05 +02:00
}
2007-07-11 17:39:41 +02:00
$new_row = null ; etemplate :: add_child ( $cell , $new_row );
2007-11-27 16:03:54 +01:00
if ( $type != 'customfields-list' && $type == 'customfields' )
2007-07-11 17:39:41 +02:00
{
$row_class = 'row' ;
etemplate :: add_child ( $cell , $label =& etemplate :: empty_cell ( 'label' , '' , array (
'label' => $field [ 'label' ],
2007-07-12 09:53:21 +02:00
'no_lang' => substr ( lang ( $field [ 'label' ]), - 1 ) == '*' ? 2 : 0 ,
'span' => $field [ 'type' ] === 'label' ? '2' : '' ,
2007-07-11 17:39:41 +02:00
)));
2007-11-27 16:03:54 +01:00
} elseif ( $type == 'customfields-list' ) {
if ( isset ( $value [ $this -> prefix . $lname ]) && $value [ $this -> prefix . $lname ] !== '' ) {
etemplate :: add_child ( $cell , $input =& etemplate :: empty_cell ( 'image' , 'info.png' ,
array ( 'label' => lang ( " custom fields " ) . " : " . $field [ 'label' ], 'width' => " 16px " ,
'onclick' => " return alert(' " . lang ( " custom fields " ) . " : " . $field [ 'label' ] . " '); " )));
}
2007-07-11 17:39:41 +02:00
}
2007-11-27 16:03:54 +01:00
2006-10-04 19:10:05 +02:00
switch (( string ) $field [ 'type' ])
2005-10-28 20:29:05 +02:00
{
case 'select' :
2007-09-13 14:43:58 +02:00
if ( count ( $field [ 'values' ]) == 1 && isset ( $field [ 'values' ][ '@' ]))
{
$field [ 'values' ] = $this -> _get_options_from_file ( $field [ 'values' ][ '@' ]);
}
if ( $this -> advanced_search && $field [ 'rows' ] <= 1 ) $field [ 'values' ][ '' ] = lang ( 'doesn\'t matter' );
2005-10-28 20:29:05 +02:00
foreach ( $field [ 'values' ] as $key => $val )
{
if ( substr ( $val = lang ( $val ), - 1 ) != '*' )
{
$field [ 'values' ][ $key ] = $val ;
}
}
2007-11-27 16:03:54 +01:00
$input =& etemplate :: empty_cell ( 'select' , $this -> prefix . $lname , array (
2007-07-11 17:39:41 +02:00
'sel_options' => $field [ 'values' ],
'size' => $field [ 'rows' ],
2007-11-27 16:03:54 +01:00
'no_lang' => True ,
2007-07-11 17:39:41 +02:00
));
2005-11-10 13:10:17 +01:00
if ( $this -> advanced_search )
{
2007-07-11 17:39:41 +02:00
$select =& $input ; unset ( $input );
$input =& etemplate :: empty_cell ( 'hbox' );
etemplate :: add_child ( $input , $select ); unset ( $select );
2007-11-27 16:03:54 +01:00
etemplate :: add_child ( $input , etemplate :: empty_cell ( 'select' , $this -> prefix . $lname , array (
2007-07-11 17:39:41 +02:00
'sel_options' => $field [ 'values' ],
'size' => $field [ 'rows' ],
2005-11-10 13:10:17 +01:00
'no_lang' => True
)));
}
2005-10-28 20:29:05 +02:00
break ;
case 'label' :
$row_class = 'th' ;
break ;
case 'checkbox' :
2007-11-27 16:03:54 +01:00
$input =& etemplate :: empty_cell ( 'checkbox' , $this -> prefix . $lname );
2005-10-28 20:29:05 +02:00
break ;
case 'radio' :
2007-09-13 14:43:58 +02:00
if ( count ( $field [ 'values' ]) == 1 && isset ( $field [ 'values' ][ '@' ]))
{
$field [ 'values' ] = $this -> _get_options_from_file ( $field [ 'values' ][ '@' ]);
}
2007-07-11 17:39:41 +02:00
$input =& etemplate :: empty_cell ( 'groupbox' );
2005-10-28 20:29:05 +02:00
$m = 0 ;
foreach ( $field [ 'values' ] as $key => $val )
{
2007-11-27 16:03:54 +01:00
$radio = etemplate :: empty_cell ( 'radio' , $this -> prefix . $lname );
2005-10-28 23:05:56 +02:00
$radio [ 'label' ] = $val ;
$radio [ 'size' ] = $key ;
2007-07-11 17:39:41 +02:00
etemplate :: add_child ( $input , $radio );
2005-10-28 23:05:56 +02:00
unset ( $radio );
2005-10-28 20:29:05 +02:00
}
break ;
case 'text' :
case 'textarea' :
2006-10-04 19:10:05 +02:00
case '' : // not set
2005-10-28 20:29:05 +02:00
$field [ 'len' ] = $field [ 'len' ] ? $field [ 'len' ] : 20 ;
2007-11-27 16:03:54 +01:00
if ( $type != 'customfields-list' )
2005-10-28 20:29:05 +02:00
{
2007-11-27 16:03:54 +01:00
if ( $field [ 'rows' ] <= 1 )
{ //text
list ( $max , $shown ) = explode ( ',' , $field [ 'len' ]);
$tmparray = array (
'size' => intval ( $shown > 0 ? $shown : $max ) . ',' . intval ( $max ),
'maxlength' => intval ( $max ),
);
if ( is_array ( $field [ 'values' ]))
{
if ( array_key_exists ( 'readonly' , $field [ 'values' ]))
{
$tmparray [ 'readonly' ] = 'readonly' ;
}
}
$input =& etemplate :: empty_cell ( 'text' , $this -> prefix . $lname , $tmparray );
}
else
{ //textarea
$tmparray = array (
'size' => $field [ 'rows' ] . ( $field [ 'len' ] > 0 ? ',' . ( int ) $field [ 'len' ] : '' )
);
if ( array_key_exists ( 'readonly' , $field [ 'values' ]))
{
$tmparray [ 'readonly' ] = 'readonly' ;
}
$input =& etemplate :: empty_cell ( 'textarea' , $this -> prefix . $lname , $tmparray );
}
} else {
$input =& etemplate :: empty_cell ( 'label' , $this -> prefix . $lname ,
array (
'onclick' => " return alert(' " . lang ( " custom fields " ) . " : " .
$lname . " => " . htmlentities ( str_replace ( " \r " , " " , str_replace ( " \n " , " " , $value [ $this -> prefix . $lname ]))) . " '); " ,
)
);
2005-10-28 20:29:05 +02:00
}
break ;
2007-05-17 08:04:24 +02:00
case 'date' :
case 'date-time' :
2007-11-27 16:03:54 +01:00
$input =& etemplate :: empty_cell ( $field [ 'type' ], $this -> prefix . $lname , array (
2007-05-17 08:04:24 +02:00
'size' => $field [ 'len' ] ? $field [ 'len' ] : ( $field [ 'type' ] == 'date' ? 'Y-m-d' : 'Y-m-d H:i:s' ),
));
break ;
2007-07-11 17:39:41 +02:00
case 'select-account' :
list ( $opts ) = explode ( '=' , $field [ 'values' ][ 0 ]);
2007-11-27 16:03:54 +01:00
$input =& etemplate :: empty_cell ( 'select-account' , $this -> prefix . $lname , array (
2007-07-11 17:39:41 +02:00
'size' => ( $field [ 'rows' ] > 1 ? $field [ 'rows' ] : lang ( 'None' )) . ',' . $opts ,
));
break ;
2007-11-27 16:03:54 +01:00
case 'button' : // button(s) to execute javascript (label=onclick) or textinputs (empty label, readonly with neg. length)
2007-09-13 14:43:58 +02:00
$input =& etemplate :: empty_cell ( 'hbox' );
foreach ( $field [ 'values' ] as $label => $js )
{
2007-11-27 16:03:54 +01:00
if ( ! $label ) // display an readonly input
2007-09-13 14:43:58 +02:00
{
2007-11-27 16:03:54 +01:00
$widget =& etemplate :: empty_cell ( 'text' , $this -> prefix . $lname . $label , array (
2007-09-13 14:43:58 +02:00
'size' => $field [ 'len' ] ? $field [ 'len' ] : 20 ,
'readonly' => $field [ 'len' ] < 0 ,
'onchange' => $js ,
));
}
else
{
2007-11-27 16:03:54 +01:00
if ( $readonly ) continue ; // dont display buttons if we're readonly
$widget =& etemplate :: empty_cell ( 'buttononly' , $this -> prefix . $lname . $label , array (
2007-09-13 14:43:58 +02:00
'label' => $label ? $label : lang ( 'Submit' ),
'onclick' => $js ,
2007-11-27 16:03:54 +01:00
'no_lang' => True
2007-09-13 14:43:58 +02:00
));
}
etemplate :: add_child ( $input , $widget );
unset ( $widget );
}
2007-11-27 16:03:54 +01:00
break ;
case 'link-entry' :
default : // link-entry to given app
$input =& etemplate :: empty_cell ( 'link-entry' , $this -> prefix . $lname , array (
'size' => $field [ 'type' ] == 'link-entry' ? '' : $field [ 'type' ],
));
2005-10-28 20:29:05 +02:00
}
2007-07-12 09:53:21 +02:00
$cell [ 'data' ][ 0 ][ 'c' . $n ++ ] = $row_class . ',top' ;
2005-10-28 20:29:05 +02:00
2007-07-12 09:53:21 +02:00
if ( ! is_null ( $input ))
2005-10-28 20:29:05 +02:00
{
2007-07-12 09:53:21 +02:00
if ( $readonly ) $input [ 'readonly' ] = true ;
2007-11-27 16:03:54 +01:00
2007-11-26 18:35:29 +01:00
if ( $cell [ 'needed' ]) $input [ 'needed' ] = $cell [ 'needed' ];
2007-07-12 09:53:21 +02:00
if ( ! empty ( $field [ 'help' ]) && $row_class != 'th' )
{
$input [ 'help' ] = $field [ 'help' ];
$input [ 'no_lang' ] = substr ( lang ( $help ), - 1 ) == '*' ? 2 : 0 ;
}
etemplate :: add_child ( $cell , $input );
unset ( $input );
2005-10-28 20:29:05 +02:00
}
2007-07-11 17:39:41 +02:00
unset ( $label );
2007-11-27 16:03:54 +01:00
}
2005-10-28 20:29:05 +02:00
}
2007-07-11 17:39:41 +02:00
if ( $type != 'customfields-list' )
2005-10-28 20:29:05 +02:00
{
2007-07-11 17:39:41 +02:00
$cell [ 'data' ][ 0 ][ 'A' ] = '100' ;
2005-10-28 20:29:05 +02:00
}
2007-07-11 17:39:41 +02:00
list ( $span , $class ) = explode ( ',' , $cell [ 'span' ]); // msie (at least 5.5) shows nothing with div overflow=auto
2007-11-27 16:03:54 +01:00
// we dont want to use up the full space for the table created, so we skip the line below
//$cell['size'] = '100%,100%,0,'.$class.','.(in_array($type,array('customfields-list','customfields-no-label'))?'0,0':',').($tmpl->html->user_agent != 'msie' ? ',auto' : '');
2005-10-28 20:29:05 +02:00
return True ; // extra Label is ok
}
2007-11-27 16:03:54 +01:00
2007-09-13 14:43:58 +02:00
/**
* Read the options of a 'select' or 'radio' custom field from a file
2007-11-27 16:03:54 +01:00
*
* For security reasons that file has to be relative to the eGW root
2007-09-13 14:43:58 +02:00
* ( to not use that feature to explore arbitrary files on the server )
* and it has to be a php file setting one variable called options ,
2007-11-27 16:03:54 +01:00
* ( to not display it to anonymously by the webserver ) .
2007-09-13 14:43:58 +02:00
* The $options var has to be an array with value => label pairs , eg :
2007-11-27 16:03:54 +01:00
*
2007-09-13 14:43:58 +02:00
* < ? php
* $options = array (
2007-11-27 16:03:54 +01:00
* 'a' => 'Option A' ,
* 'b' => 'Option B' ,
* 'c' => 'Option C' ,
2007-09-13 14:43:58 +02:00
* );
*
* @ param string $file file name inside the eGW server root , either relative to it or absolute
* @ return array in case of an error we return a single option with the message
*/
function _get_options_from_file ( $file )
{
if ( ! ( $path = realpath ( $file { 0 } == '/' ? $file : EGW_SERVER_ROOT . '/' . $file )) || // file does not exist
substr ( $path , 0 , strlen ( EGW_SERVER_ROOT ) + 1 ) != EGW_SERVER_ROOT . '/' || // we are NOT inside the eGW root
basename ( $path , '.php' ) . '.php' != basename ( $path ) || // extension is NOT .php
basename ( $path ) == 'header.inc.php' ) // dont allow to include our header again
{
return array ( lang ( " '%1' is no php file in the eGW server root (%2)! " . ': ' . $path , $file , EGW_SERVER_ROOT ));
}
include ( $path );
2007-11-27 16:03:54 +01:00
2007-09-13 14:43:58 +02:00
return $options ;
}
2005-10-28 20:29:05 +02:00
}