source: subversion/branches/devel-vnext/program/include/rcmail_template.inc @ 688

Last change on this file since 688 was 688, checked in by till, 6 years ago

+ documentation
# many smaller bugfixes

  • added to logout call/command (HACK, FIXME)
  • Property svn:executable set to *
File size: 26.7 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | program/include/rcmail_template.inc                                   |
6 |                                                                       |
7 | This file is part of the RoundCube Webmail client                     |
8 | Copyright (C) 2007, RoundCube Dev. - Switzerland                      |
9 | Licensed under the GNU GPL                                            |
10 |                                                                       |
11 | PURPOSE:                                                              |
12 |   Class to handle HTML page output using a skin template.             |
13 |   Extends rcube_html_page class from rcube_shared.inc                 |
14 |                                                                       |
15 +-----------------------------------------------------------------------+
16 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
17 +-----------------------------------------------------------------------+
18
19 $Id:  $
20
21*/
22
23require_once dirname(__FILE__) . '/rcube_shared.inc';
24
25/**
26 * rcmail_template
27 *
28 * @todo Documentation
29 * @todo CS
30 * @todo PHP5?
31 * @uses rcube_html_page
32 */
33class rcmail_template extends rcube_html_page
34{
35    var $config;
36    var $task = '';
37    var $framed = false;
38    var $ajax_call = false;
39    var $pagetitle = '';
40    var $env = array();
41    var $js_env = array();
42    var $js_commands = array();
43    var $object_handlers = array();
44
45
46    /**
47     * PHP 5 constructor
48     *
49     * @access public
50     * @param  array $config
51     * @param  string $task
52     * @todo   Use jQuery's $(document).ready() here.
53     */
54    function __construct($config, $task)
55    {
56        parent::__construct();
57
58        $this->task      = $task;
59        $this->config    = $config;
60        $this->ajax_call = !empty($_GET['_remote']) || !empty($_POST['_remote']);
61
62        // add common javascripts
63        if (!$this->ajax_call) {
64            $javascript = "var ".JS_OBJECT_NAME." = new rcube_webmail();";
65
66            // don't wait for page onload. Call init at the bottom of the page (delayed)
67            $javascript_foot = "if (window.call_init)\n call_init('".JS_OBJECT_NAME."');";
68
69            $this->add_script($javascript, 'head_top');
70            $this->add_script($javascript_foot, 'foot');
71            $this->scripts_path = 'program/js/';
72            $this->include_script('common.js');
73            $this->include_script('app.js');
74        }
75    }
76
77    /**
78     * Set environment variable
79     */
80    function set_env($name, $value, $addtojs=true)
81    {
82        $this->env[$name] = $value;
83        if ($addtojs || isset($this->js_env[$name])) {
84            $this->js_env[$name] = $value;
85        }
86    }
87
88
89    /**
90     * Set page title variable
91     */
92    function set_pagetitle($title)
93    {
94        $this->pagetitle = $title;
95    }
96
97
98    /**
99     * Register a template object handler
100     *
101     * @access protected
102     * @param  string Object name
103     * @param  string Function name to call
104     * @return void
105     */
106    function add_handler($obj, $func)
107    {
108        $this->object_handlers[$obj] = $func;
109    }
110
111    /**
112     * Register a list of template object handlers
113     *
114     * @param  array Hash array with object=>handler pairs
115     * @return void
116     */
117    function add_handlers($arr)
118    {
119        $this->object_handlers = array_merge($this->object_handlers, $arr);
120    }
121
122    /**
123     * Register a GUI object to the client script
124     *
125     * @param  string Object name
126     * @param  string Object ID
127     * @return void
128     */
129    function add_gui_object($obj, $id)
130    {
131        $this->add_script(JS_OBJECT_NAME.".gui_object('$obj', '$id');");
132    }
133
134    /**
135     * Call a client method
136     *
137     * @param string Method to call
138     * @param ... Additional arguments
139     */
140    function command()
141    {
142        $this->js_commands[] = func_get_args();
143    }
144
145    /**
146     * Invoke display_message command
147     *
148     * @param  string $message
149     * @param  string $type
150     * @param  mixed  $vars
151     * @return void
152     * @uses   self::command()
153     */
154    function show_message($message, $type='notice', $vars=NULL)
155    {
156        $this->command(
157                'display_message',
158                rcube_label(array('name' => $message, 'vars' => $vars)),
159                $type
160        );
161    }
162
163    /**
164     * Delete all stored env variables and commands
165     *
166     * @access public
167     * @return void
168     * @uses   rcube_html::reset()
169     * @uses   self::$env
170     * @uses   self::$js_env
171     * @uses   self::$js_commands
172     * @uses   self::$object_handlers
173     */
174    public function reset()
175    {
176        $this->env = array();
177        $this->js_env = array();
178        $this->js_commands = array();
179        $this->object_handlers = array();
180        parent::reset();
181    }
182
183    /**
184     * Send the request output to the client.
185     * This will either parse a skin tempalte or send an AJAX response
186     *
187     * @access public
188     * @param  string  $templ Template name
189     * @param  boolean $exit True if script should terminate (default)
190     */
191    function send($templ=null, $exit=true)
192    {
193        if ($this->ajax_call) {
194            $this->remote_response('', !$exit);
195        }
196        elseif ($templ != 'iframe') {
197            //rc_main::tfk_debug("/Parsing $templ");
198            $this->parse($templ, false);
199        }
200        else {
201            $this->framed = $templ == 'iframe' ? true : $this->framed;
202            $this->write();
203        }
204
205        if ($exit) {
206            exit;
207        }
208    }
209
210
211    /**
212     * Send an AJAX response with executable JS code
213     *
214     * @param  string  Additional JS code
215     * @param  boolean True if output buffer should be flushed
216     * @return void
217     */
218    function remote_response($add='', $flush=false)
219    {
220        static $s_header_sent = FALSE;
221
222        if (!$s_header_sent) {
223            $s_header_sent = TRUE;
224            send_nocacheing_headers();
225            header('Content-Type: application/x-javascript; charset='.RCMAIL_CHARSET);
226            print '/** ajax response ['.date('d/M/Y h:i:s O')."] **/\n";
227        }
228
229        // unset default env vars
230        unset($this->js_env['task'], $this->js_env['action'], $this->js_env['comm_path']);
231
232        // send response code
233        echo rc_main::rcube_charset_convert(
234                $this->get_js_commands() . $add,
235                RCMAIL_CHARSET,
236                $this->get_charset()
237        );
238
239        if ($flush) {  // flush the output buffer
240            flush();
241        }
242    }
243
244    /**
245     * @override
246     */
247    function write($template='')
248    {
249        // write all env variables to client
250        $js = $this->framed ? "if(window.parent) {\n" : '';
251        $js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
252        $this->add_script($js, 'head_top');
253
254        // call super method
255        parent::write($template, $this->config['skin_path']);
256    }
257
258    /**
259     * Parse a specific skin template and deliver to stdout
260     *
261     * Either returns nothing, or exists hard (exit();)
262     *
263     * @access public
264     * @param  string  Template name
265     * @param  boolean Exit script
266     * @return void
267     * @link   http://php.net/manual/en/function.exit.php
268     */
269    function parse($name='main', $exit=true)
270    {
271        $skin_path = $this->config['skin_path'];
272
273        //rc_main::tfk_debug(var_export($this->config['skin_path'], true));
274
275        // read template file
276        $templ = '';
277        $path = "$skin_path/templates/$name.html";
278
279        if(($fp = @fopen($path, 'r')) === false) {
280            $message = '';
281            ob_start();
282            fopen($path, 'r');
283            $message.= ob_get_contents();
284            ob_end_clean();
285            rc_bugs::raise_error(
286                array(
287                    'code' => 501,
288                    'type' => 'php',
289                    'line' => __LINE__,
290                    'file' => __FILE__,
291                    'message' => "Error loading template for '$name': $message"
292                ),
293                TRUE,
294                TRUE
295            );
296            return FALSE;
297        }
298        $templ = fread($fp, filesize($path));
299        @fclose($fp);
300
301        //rc_main::tfk_debug("// parsed: $path");
302
303        // parse for specialtags
304        $output = $this->parse_conditions($templ);
305        $output = $this->parse_xml($output);
306
307        // add debug console
308        if ($this->config['debug_level'] & 8) {
309            $this->add_footer('<div style="position:absolute;top:5px;left:5px;width:400px;padding:0.2em;background:white;opacity:0.8;z-index:9000">
310                            <a href="#toggle" onclick="con=document.getElementById(\'dbgconsole\');con.style.display=(con.style.display==\'none\'?\'block\':\'none\');return false">console</a>
311                            <form action="/" name="debugform"><textarea name="console" id="dbgconsole" rows="20" cols="40" wrap="off" style="display:none;width:400px;border:none;font-size:x-small"></textarea></form></div>'
312            );
313        }
314        $output = $this->parse_with_globals($output);
315        $this->write(trim($output), $skin_path);
316        if ($exit) {
317            exit;
318        }
319    }
320
321
322    /**
323     * Return executable javascript code for all registered commands
324     * @access private
325     * @return string $out
326     */
327    function get_js_commands()
328    {
329        $out = '';
330        if (!$this->framed) {
331            $out .= ($this->ajax_call ? 'this' : JS_OBJECT_NAME) . '.set_env('.json_serialize($this->js_env).");\n";
332        }
333        foreach ($this->js_commands as $i => $args) {
334            $method = array_shift($args);
335            foreach ($args as $i => $arg) {
336                $args[$i] = json_serialize($arg);
337            }
338            $parent = $this->framed || preg_match('/^parent\./', $method);
339            $out .= sprintf(
340                        "%s.%s(%s);\n",
341                        $this->ajax_call ? 'this' : ($parent ? 'parent.' : '') . JS_OBJECT_NAME,
342                        preg_replace('/^parent\./', '', $method),
343                        implode(',', $args)
344            );
345        }
346        return $out;
347    }
348
349    /**
350     * Make URLs starting with a slash point to skin directory
351     *
352     * @access protected
353     * @param  string $str
354     * @todo   Check if str_replace() would be sufficient
355     * @return string
356     */
357    function abs_url($str)
358    {
359        return preg_replace('/^\//', $this->config['skin_path'].'/', $str);
360    }
361
362
363
364    /*****  Template parsing methods  *****/
365
366    /**
367     * Replace all strings ($varname) with the content
368     * of the according global variable.
369     */
370    function parse_with_globals($input)
371    {
372        $registry  = rc_registry::getInstance();
373        $COMM_PATH = $registry->get('COMM_PATH', 'core');
374
375        $GLOBALS['__comm_path'] = $COMM_PATH;
376        return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input);
377    }
378
379    /**
380     * Public wrapper to dipp into template parsing.
381     *
382     * @access public
383     * @param  string $input
384     * @return string
385     * @uses   rcmail_template::parse_conditions()
386     * @since  0.1-rc1
387     */
388    public function just_parse($input)
389    {
390        return $this->parse_xml($input);
391    }
392
393    /**
394     * Parse for conditional tags
395     *
396     * @access protected
397     * @param  string $input
398     * @return string
399     */
400    protected function parse_conditions($input)
401    {
402        $matches = preg_split(
403                        '/<roundcube:(if|elseif|else|endif)\s+([^>]+)>/is',
404                        $input,
405                        2,
406                        PREG_SPLIT_DELIM_CAPTURE
407        );
408        if ($matches && count($matches)==4) {
409            if (preg_match('/^(else|endif)$/i', $matches[1])) {
410                return $matches[0] . $this->parse_conditions($matches[3]);
411            }
412            $attrib = rc_main::parse_attrib_string($matches[2]);
413            if (isset($attrib['condition'])) {
414                $condmet = $this->check_condition($attrib['condition']);
415                $submatches = preg_split(
416                                '/<roundcube:(elseif|else|endif)\s+([^>]+)>/is',
417                                $matches[3],
418                                2,
419                                PREG_SPLIT_DELIM_CAPTURE
420                );
421                if ($condmet) {
422                    $result = $submatches[0];
423                    $result.= ($submatches[1] != 'endif' ? preg_replace('/.*<roundcube:endif\s+[^>]+>/Uis', '', $submatches[3], 1) : $submatches[3]);
424                }
425                else {
426                    $result = "<roundcube:$submatches[1] $submatches[2]>" . $submatches[3];
427                }
428                return $matches[0] . $this->parse_conditions($result);
429            }
430            rc_bugs::raise_error(
431                array(
432                    'code' => 500,
433                    'type' => 'php',
434                    'line' => __LINE__,
435                    'file' => __FILE__,
436                    'message' => "Unable to parse conditional tag " . $matches[2]
437                ),
438                TRUE,
439                FALSE
440            );
441        }
442        return $input;
443    }
444
445
446    /**
447     * Determines if a given condition is met
448     *
449     * @todo   Get rid off eval() once I understand what this does.
450     * @return True if condition is valid, False is not
451     */
452    function check_condition($condition)
453    {
454        $condition = preg_replace(
455                array('/session:([a-z0-9_]+)/i', '/config:([a-z0-9_]+)/i', '/env:([a-z0-9_]+)/i', '/request:([a-z0-9_]+)/ie'),
456                array("\$_SESSION['\\1']", "\$this->config['\\1']", "\$this->env['\\1']", "get_input_value('\\1', RCUBE_INPUT_GPC)"),
457                $condition
458        );
459        return @eval("return (".$condition.");");
460    }
461
462
463   /**
464    * Search for special tags in input and replace them
465    * with the appropriate content
466    *
467    * @access protected
468    * @param  string Input string to parse
469    * @return Altered input string
470    * @todo   Maybe a cache.
471    */
472   protected function parse_xml($input)
473   {
474        return preg_replace('/<roundcube:([-_a-z]+)\s+([^>]+)>/Uie', "\$this->xml_command('\\1', '\\2')", $input);
475   }
476
477
478    /**
479     * Convert a xml command tag into real content
480     *
481     * @access protected
482     * @param  string Tag command: object,button,label, etc.
483     * @param  string Attribute string
484     * @return Tag/Object content string
485     */
486    protected function xml_command($command, $str_attrib, $add_attrib=array())
487    {
488        $command = strtolower($command);
489        $attrib  = rc_main::parse_attrib_string($str_attrib) + $add_attrib;
490        //var_dump($attrib); exit;
491
492        //rc_main::tfk_debug("// $command");
493
494        // empty output if required condition is not met
495        if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) {
496            return '';
497        }
498
499        //rc_main::tfk_debug("// $command #2");
500
501        // execute command
502        switch ($command) {
503            // return a button
504            case 'button':
505                if ($attrib['command']) {
506                    return $this->button($attrib);
507                }
508                break;
509
510            // show a label
511            case 'label':
512                if ($attrib['name'] || $attrib['command']) {
513                    return rc_main::Q(
514                                rcube_label(
515                                    $attrib + array('vars' => array('product' => $this->config['product_name']))
516                                )
517                    );
518                }
519                break;
520
521            // include a file
522            case 'include':
523                $path = realpath($this->config['skin_path'].$attrib['file']);
524                if ($path === FALSE) {
525                    //rc_main::tfk_debug("Does not exist.");
526                    return $this->parse_xml('');
527                }
528                if (($tpl_filesize = filesize($path)) == 0) {
529                    return $this->parse_xml('');
530                }
531                if ($fp = @fopen($path, 'r')) {
532                    $incl = fread($fp, $tpl_filesize);
533                    fclose($fp);
534                    return $this->parse_xml($incl);
535                }
536                break;
537
538            case 'plugin.include':
539                //rc_main::tfk_debug(var_export($this->config['skin_path'], true));
540                $path = realpath($this->config['skin_path'].$attrib['file']);
541                if ($path === FALSE) {
542                    //rc_main::tfk_debug("Does not exist:");
543                    //rc_main::tfk_debug($this->config['skin_path']);
544                    //rc_main::tfk_debug($attrib['file']);
545                    //rc_main::tfk_debug($path);
546                }
547                $incl = file_get_contents($path);
548                if ($incl === FALSE) {
549                    //rc_main::tfk_debug("Could not read template.");
550                    return $this->parse_xml('');
551                }
552                return $this->parse_xml($incl);
553                break;
554
555            // return code for a specific application object
556            case 'object':
557                $object = strtolower($attrib['name']);
558
559                rc_main::tfk_debug("// object: $object");
560                rc_main::tfk_debug(var_export($this->object_handlers[$object], true));
561
562                // execute object handler function
563                if ($this->object_handlers[$object] && function_exists($this->object_handlers[$object])) {
564                    return call_user_func($this->object_handlers[$object], $attrib);
565                }
566                else {
567                    // we are calling a class/method
568                    if ($this->object_handlers[$object] && is_array($this->object_handlers[$object])) {
569                        if (class_exists($this->object_handlers[$object][0])) {
570                            return call_user_func($this->object_handlers[$object], $attrib);
571                        }
572                        rc_main::tfk_debug('Unknown handler: ' . var_export($this->object_handlers[$object], true));
573                    }
574                }
575                if ($object=='productname') {
576                    $name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail';
577                    return rc_main::Q($name);
578                }
579                if ($object=='version') {
580                    return (string)RCMAIL_VERSION;
581                }
582                if ($object=='pagetitle') {
583                    $task  = $this->task;
584                    $title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '';
585
586                    if (!empty($this->pagetitle))
587                        $title .= $this->pagetitle;
588                    else if ($task == 'login')
589                        $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name'])));
590                    else
591                        $title .= ucfirst($task);
592
593                    return rc_main::Q($title);
594                }
595                break;
596        }
597        return '';
598    }
599
600
601    /**
602     * Create and register a button
603     *
604     * @access public
605     * @param  array Button attributes
606     * @return HTML button
607     * @todo   Remove all inline JS calls and use jQuery instead.
608     * @todo   Remove all sprintf()'s - they are pretty, but also slow.
609     */
610    public function button($attrib)
611    {
612        $registry   = rc_registry::getInstance();
613        $CONFIG     = $registry->get('CONFIG', 'core');
614        $OUTPUT     = $registry->get('OUTPUT', 'core');
615        $BROWSER    = $registry->get('BROWSER', 'core');
616        $MAIN_TASKS = $registry->get('MAIN_TASKS', 'core');
617
618        static $sa_buttons = array();
619        static $s_button_count = 100;
620
621        // these commands can be called directly via url
622        $a_static_commands = array('compose', 'list');
623
624        $skin_path = $this->config['skin_path'];
625
626        if (!($attrib['command'] || $attrib['name'])) {
627            return '';
628        }
629        // try to find out the button type
630        if ($attrib['type']) {
631            $attrib['type'] = strtolower($attrib['type']);
632        }
633        else {
634            $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link';
635        }
636        $command = $attrib['command'];
637
638        // take the button from the stack
639        if($attrib['name'] && $sa_buttons[$attrib['name']]) {
640            $attrib = $sa_buttons[$attrib['name']];
641        }
642        // add button to button stack
643        else if($attrib['image'] || $attrib['imageact'] || $attrib['imagepas'] || $attrib['class'])
644        {
645            if (!$attrib['name']) {
646                $attrib['name'] = $command;
647            }
648            if (!$attrib['image']) {
649                $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact'];
650            }
651            $sa_buttons[$attrib['name']] = $attrib;
652        }
653
654        // get saved button for this command/name
655        else if ($command && $sa_buttons[$command]) {
656            $attrib = $sa_buttons[$command];
657        }
658        //else
659        //  return '';
660
661
662        // set border to 0 because of the link arround the button
663        if ($attrib['type']=='image' && !isset($attrib['border'])) {
664            $attrib['border'] = 0;
665        }
666        if (!$attrib['id']) {
667            $attrib['id'] =  sprintf('rcmbtn%d', $s_button_count++);
668        }
669        // get localized text for labels and titles
670        if ($attrib['title']) {
671            $attrib['title'] = rc_main::Q(rcube_label($attrib['title']));
672        }
673        if ($attrib['label']) {
674            $attrib['label'] = rc_main::Q(rcube_label($attrib['label']));
675        }
676        if ($attrib['alt']) {
677            $attrib['alt'] = rc_main::Q(rcube_label($attrib['alt']));
678        }
679        // set title to alt attribute for IE browsers
680        if ($BROWSER['ie'] && $attrib['title'] && !$attrib['alt']) {
681            $attrib['alt'] = $attrib['title'];
682            unset($attrib['title']);
683        }
684
685        // add empty alt attribute for XHTML compatibility
686        if (!isset($attrib['alt'])) {
687            $attrib['alt'] = '';
688        }
689
690        // register button in the system
691        if ($attrib['command'])
692        {
693            $this->add_script(
694                sprintf(
695                    "%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');",
696                    JS_OBJECT_NAME,
697                    $command,
698                    $attrib['id'],
699                    $attrib['type'],
700                    $attrib['imageact'] ? $skin_path.$attrib['imageact'] : $attrib['classact'],
701                    $attrib['imagesel'] ? $skin_path.$attrib['imagesel'] : $attrib['classsel'],
702                    $attrib['imageover'] ? $skin_path.$attrib['imageover'] : ''
703                )
704            );
705
706            // make valid href to specific buttons
707            if (in_array($attrib['command'], $MAIN_TASKS)) {
708                $attrib['href'] = rc_main::Q(rc_main::rcmail_url(null, null, $attrib['command']));
709            }
710            else if (in_array($attrib['command'], $a_static_commands)) {
711                $attrib['href'] = rc_main::Q(rc_main::rcmail_url($attrib['command']));
712            }
713        }
714
715        // overwrite attributes
716        if (!$attrib['href']) {
717            $attrib['href'] = '#';
718        }
719        if ($command) {
720            $attrib['onclick'] = sprintf(
721                                    "return %s.command('%s','%s',this)",
722                                    JS_OBJECT_NAME,
723                                    $command,
724                                    $attrib['prop']
725            );
726        }
727        if ($command && $attrib['imageover']) {
728            $attrib['onmouseover'] = sprintf(
729                                        "return %s.button_over('%s','%s')",
730                                        JS_OBJECT_NAME,
731                                        $command,
732                                        $attrib['id']
733            );
734            $attrib['onmouseout'] = sprintf(
735                                        "return %s.button_out('%s','%s')",
736                                        JS_OBJECT_NAME,
737                                        $command,
738                                        $attrib['id']
739            );
740        }
741
742        if ($command && $attrib['imagesel']) {
743            $attrib['onmousedown'] = sprintf(
744                                        "return %s.button_sel('%s','%s')",
745                                        JS_OBJECT_NAME,
746                                        $command,
747                                        $attrib['id']
748            );
749            $attrib['onmouseup'] = sprintf(
750                                        "return %s.button_out('%s','%s')",
751                                        JS_OBJECT_NAME,
752                                        $command,
753                                        $attrib['id']
754            );
755        }
756
757        $out = '';
758
759        // generate image tag
760        if ($attrib['type']=='image') {
761            $attrib_str = rc_main::create_attrib_string(
762                                $attrib,
763                                array(
764                                    'style', 'class', 'id', 'width',
765                                    'height', 'border', 'hspace',
766                                    'vspace', 'align', 'alt'
767                                )
768            );
769            $img_tag = sprintf('<img src="%%s"%s />', $attrib_str);
770            $btn_content = sprintf($img_tag, $skin_path.$attrib['image']);
771            if ($attrib['label']) {
772                $btn_content .= ' '.$attrib['label'];
773            }
774            $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title');
775        }
776        else if ($attrib['type']=='link') {
777            $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command'];
778            $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style');
779        }
780        else if ($attrib['type']=='input') {
781            $attrib['type'] = 'button';
782
783            if ($attrib['label'])
784                $attrib['value'] = $attrib['label'];
785
786            $attrib_str = rc_main::create_attrib_string(
787                                $attrib,
788                                array(
789                                    'type', 'value', 'onclick',
790                                    'id', 'class', 'style'
791                                )
792            );
793            $out = sprintf('<input%s disabled="disabled" />', $attrib_str);
794        }
795
796        // generate html code for button
797        if ($btn_content) {
798            if ($command == 'logout') {
799                $btn_content = '<span>Hallo ' . $_SESSION['username'] . ', ' . $btn_content . '</span>';
800            }           
801            $attrib_str = rc_main::create_attrib_string($attrib, $link_attrib);
802            $out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content);
803        }
804
805        return $out;
806    }
807
808}
809
810?>
Note: See TracBrowser for help on using the repository browser.