4 +-----------------------------------------------------------------------+
5 | program/include/rcube_template.php |
7 | This file is part of the RoundCube Webmail client |
8 | Copyright (C) 2006-2009, RoundCube Dev. - Switzerland |
9 | Licensed under the GNU GPL |
12 | Class to handle HTML page output using a skin template. |
13 | Extends rcube_html_page class from rcube_shared.inc |
15 +-----------------------------------------------------------------------+
16 | Author: Thomas Bruederli <roundcube@gmail.com> |
17 +-----------------------------------------------------------------------+
25 * Class to create HTML page output using a skin template
29 * @uses rcube_html_page
31 class rcube_template extends rcube_html_page
38 var $js_env = array();
39 var $js_commands = array();
40 var $object_handlers = array();
42 public $type = 'html';
43 public $ajax_call = false;
48 * @todo Use jQuery's $(document).ready() here.
49 * @todo Replace $this->config with the real rcube_config object
51 public function __construct($task, $framed = false)
53 parent::__construct();
55 $this->app = rcmail::get_instance();
56 $this->config = $this->app->config->all();
57 $this->browser = new rcube_browser();
59 //$this->framed = $framed;
60 $this->set_env('task', $task);
62 // load the correct skin (in case user-defined)
63 $this->set_skin($this->config['skin']);
65 // add common javascripts
66 $javascript = 'var '.JS_OBJECT_NAME.' = new rcube_webmail();';
68 // don't wait for page onload. Call init at the bottom of the page (delayed)
69 $javascript_foot = "if (window.call_init)\n call_init('".JS_OBJECT_NAME."');";
71 $this->add_script($javascript, 'head_top');
72 $this->add_script($javascript_foot, 'foot');
73 $this->scripts_path = 'program/js/';
74 $this->include_script('common.js');
75 $this->include_script('app.js');
77 // register common UI objects
78 $this->add_handlers(array(
79 'loginform' => array($this, 'login_form'),
80 'username' => array($this, 'current_username'),
81 'message' => array($this, 'message_container'),
82 'charsetselector' => array($this, 'charset_selector'),
87 * Set environment variable
89 * @param string Property name
90 * @param mixed Property value
91 * @param boolean True if this property should be added to client environment
93 public function set_env($name, $value, $addtojs = true)
95 $this->env[$name] = $value;
96 if ($addtojs || isset($this->js_env[$name])) {
97 $this->js_env[$name] = $value;
103 * Set page title variable
105 public function set_pagetitle($title)
107 $this->pagetitle = $title;
112 * Getter for the current page title
114 * @return string The page title
116 public function get_pagetitle()
118 if (!empty($this->pagetitle)) {
119 $title = $this->pagetitle;
121 else if ($this->env['task'] == 'login') {
122 $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name'])));
125 $title = ucfirst($this->env['task']);
135 public function set_skin($skin)
137 if (!empty($skin) && is_dir('skins/'.$skin) && is_readable('skins/'.$skin))
138 $skin_path = 'skins/'.$skin;
140 $skin_path = $this->config['skin_path'] ? $this->config['skin_path'] : 'skins/default';
142 $this->app->config->set('skin_path', $skin_path);
143 $this->config['skin_path'] = $skin_path;
147 * Check if a specific template exists
149 * @param string Template name
150 * @return boolean True if template exists
152 public function template_exists($name)
154 $filename = $this->config['skin_path'] . '/templates/' . $name . '.html';
156 return (is_file($filename) && is_readable($filename));
160 * Register a template object handler
162 * @param string Object name
163 * @param string Function name to call
166 public function add_handler($obj, $func)
168 $this->object_handlers[$obj] = $func;
172 * Register a list of template object handlers
174 * @param array Hash array with object=>handler pairs
177 public function add_handlers($arr)
179 $this->object_handlers = array_merge($this->object_handlers, $arr);
183 * Register a GUI object to the client script
185 * @param string Object name
186 * @param string Object ID
189 public function add_gui_object($obj, $id)
191 $this->add_script(JS_OBJECT_NAME.".gui_object('$obj', '$id');");
195 * Call a client method
197 * @param string Method to call
198 * @param ... Additional arguments
200 public function command()
202 $this->js_commands[] = func_get_args();
207 * Add a localized label to the client environment
209 public function add_label()
211 $arg_list = func_get_args();
212 foreach ($arg_list as $i => $name) {
213 $this->command('add_label', $name, rcube_label($name));
219 * Invoke display_message command
221 * @param string Message to display
222 * @param string Message type [notice|confirm|error]
223 * @param array Key-value pairs to be replaced in localized text
224 * @uses self::command()
226 public function show_message($message, $type='notice', $vars=NULL)
230 rcube_label(array('name' => $message, 'vars' => $vars)),
236 * Delete all stored env variables and commands
239 * @uses rcube_html::reset()
241 * @uses self::$js_env
242 * @uses self::$js_commands
243 * @uses self::$object_handlers
245 public function reset()
247 $this->env = array();
248 $this->js_env = array();
249 $this->js_commands = array();
250 $this->object_handlers = array();
256 * Redirect to a certain url
258 * @param mixed Either a string with the action or url parameters as key-value pairs
261 public function redirect($p = array())
263 $location = $this->app->url($p);
264 header('Location: ' . $location);
270 * Send the request output to the client.
271 * This will either parse a skin tempalte or send an AJAX response
273 * @param string Template name
274 * @param boolean True if script should terminate (default)
276 public function send($templ = null, $exit = true)
278 if ($templ != 'iframe') {
279 $this->parse($templ, false);
282 $this->framed = $templ == 'iframe' ? true : $this->framed;
292 * Process template and write to stdOut
294 * @param string HTML template
295 * @see rcube_html_page::write()
298 public function write($template = '')
300 // unlock interface after iframe load
302 array_unshift($this->js_commands, array('set_busy', false));
304 // write all env variables to client
305 $js = $this->framed ? "if(window.parent) {\n" : '';
306 $js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
307 $this->add_script($js, 'head_top');
310 parent::write($template, $this->config['skin_path']);
314 * Parse a specific skin template and deliver to stdout
316 * Either returns nothing, or exists hard (exit();)
318 * @param string Template name
319 * @param boolean Exit script
321 * @link http://php.net/manual/en/function.exit.php
323 private function parse($name = 'main', $exit = true)
325 $skin_path = $this->config['skin_path'];
326 $path = "$skin_path/templates/$name.html";
328 // read template file
329 if (($templ = @file_get_contents($path)) === false) {
335 'message' => 'Error loading template for '.$name
340 // parse for specialtags
341 $output = $this->parse_conditions($templ);
342 $output = $this->parse_xml($output);
345 if ($this->config['debug_level'] & 8) {
346 $this->add_footer('<div style="position:absolute;top:5px;left:5px;width:405px;padding:2px;background:white;opacity:0.8;filter:alpha(opacity=80);z-index:9000">
347 <a href="#toggle" onclick="con=document.getElementById(\'dbgconsole\');con.style.display=(con.style.display==\'none\'?\'block\':\'none\');return false">console</a>
348 <form action="/" name="debugform" style="display:inline"><textarea name="console" id="dbgconsole" rows="20" cols="40" wrap="off" style="display:none;width:400px;border:none;font-size:x-small" spellcheck="false"></textarea></form></div>'
351 $output = $this->parse_with_globals($output);
352 $this->write(trim($output), $skin_path);
360 * Return executable javascript code for all registered commands
362 * @return string $out
364 private function get_js_commands()
367 if (!$this->framed && !empty($this->js_env)) {
368 $out .= JS_OBJECT_NAME . '.set_env('.json_serialize($this->js_env).");\n";
370 foreach ($this->js_commands as $i => $args) {
371 $method = array_shift($args);
372 foreach ($args as $i => $arg) {
373 $args[$i] = json_serialize($arg);
375 $parent = $this->framed || preg_match('/^parent\./', $method);
378 ($parent ? 'parent.' : '') . JS_OBJECT_NAME,
379 preg_replace('/^parent\./', '', $method),
388 * Make URLs starting with a slash point to skin directory
390 * @param string Input string
393 public function abs_url($str)
395 return preg_replace('/^\//', $this->config['skin_path'].'/', $str);
399 /***** Template parsing methods *****/
402 * Replace all strings ($varname)
403 * with the content of the according global variable.
405 private function parse_with_globals($input)
407 $GLOBALS['__comm_path'] = Q($this->app->comm_path);
408 return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input);
412 * Public wrapper to dipp into template parsing.
414 * @param string $input
416 * @uses rcube_template::parse_xml()
419 public function just_parse($input)
421 return $this->parse_xml($input);
425 * Parse for conditional tags
427 * @param string $input
430 private function parse_conditions($input)
432 $matches = preg_split('/<roundcube:(if|elseif|else|endif)\s+([^>]+)>/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE);
433 if ($matches && count($matches) == 4) {
434 if (preg_match('/^(else|endif)$/i', $matches[1])) {
435 return $matches[0] . $this->parse_conditions($matches[3]);
437 $attrib = parse_attrib_string($matches[2]);
438 if (isset($attrib['condition'])) {
439 $condmet = $this->check_condition($attrib['condition']);
440 $submatches = preg_split('/<roundcube:(elseif|else|endif)\s+([^>]+)>/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE);
442 $result = $submatches[0];
443 $result.= ($submatches[1] != 'endif' ? preg_replace('/.*<roundcube:endif\s+[^>]+>/Uis', '', $submatches[3], 1) : $submatches[3]);
446 $result = "<roundcube:$submatches[1] $submatches[2]>" . $submatches[3];
448 return $matches[0] . $this->parse_conditions($result);
455 'message' => "Unable to parse conditional tag " . $matches[2]
463 * Determines if a given condition is met
465 * @todo Get rid off eval() once I understand what this does.
466 * @todo Extend this to allow real conditions, not just "set"
467 * @param string Condition statement
468 * @return boolean True if condition is met, False if not
470 private function check_condition($condition)
472 return eval("return (".$this->parse_expression($condition).");");
477 * Parses expression and replaces variables
479 * @param string Expression statement
480 * @return string Expression statement
482 private function parse_expression($expression)
486 '/session:([a-z0-9_]+)/i',
487 '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i',
488 '/env:([a-z0-9_]+)/i',
489 '/request:([a-z0-9_]+)/i',
490 '/cookie:([a-z0-9_]+)/i'
494 "\$this->app->config->get('\\1',get_boolean('\\3'))",
495 "\$this->env['\\1']",
496 "get_input_value('\\1', RCUBE_INPUT_GPC)",
504 * Search for special tags in input and replace them
505 * with the appropriate content
507 * @param string Input string to parse
508 * @return string Altered input string
509 * @todo Use DOM-parser to traverse template HTML
510 * @todo Maybe a cache.
512 private function parse_xml($input)
514 return preg_replace_callback('/<roundcube:([-_a-z]+)\s+([^>]+)>/Ui', array($this, 'xml_command_callback'), $input);
519 * This is a callback function for preg_replace_callback (see #1485286)
520 * It's only purpose is to reconfigure parameters for xml_command, so that the signature isn't disturbed
522 private function xml_command_callback($matches)
524 $str_attrib = isset($matches[2]) ? $matches[2] : '';
525 $add_attrib = isset($matches[3]) ? $matches[3] : array();
527 $command = $matches[1];
528 //matches[0] is the entire matched portion of the string
530 return $this->xml_command($command, $str_attrib, $add_attrib);
535 * Convert a xml command tag into real content
537 * @param string Tag command: object,button,label, etc.
538 * @param string Attribute string
539 * @return string Tag/Object content
541 private function xml_command($command, $str_attrib, $add_attrib = array())
543 $command = strtolower($command);
544 $attrib = parse_attrib_string($str_attrib) + $add_attrib;
546 // empty output if required condition is not met
547 if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) {
555 if ($attrib['name'] || $attrib['command']) {
556 return $this->button($attrib);
562 if ($attrib['name'] || $attrib['command']) {
563 return Q(rcube_label($attrib + array('vars' => array('product' => $this->config['product_name']))));
569 $path = realpath($this->config['skin_path'].$attrib['file']);
570 if (is_readable($path)) {
571 if ($this->config['skin_include_php']) {
572 $incl = $this->include_php($path);
575 $incl = file_get_contents($path);
577 return $this->parse_xml($incl);
581 case 'plugin.include':
582 //rcube::tfk_debug(var_export($this->config['skin_path'], true));
583 $path = realpath($this->config['skin_path'].$attrib['file']);
585 //rcube::tfk_debug("Does not exist:");
586 //rcube::tfk_debug($this->config['skin_path']);
587 //rcube::tfk_debug($attrib['file']);
588 //rcube::tfk_debug($path);
590 $incl = file_get_contents($path);
592 return $this->parse_xml($incl);
596 // return code for a specific application object
598 $object = strtolower($attrib['name']);
600 // we are calling a class/method
601 if (($handler = $this->object_handlers[$object]) && is_array($handler)) {
602 if ((is_object($handler[0]) && method_exists($handler[0], $handler[1])) ||
603 (is_string($handler[0]) && class_exists($handler[0])))
604 return call_user_func($handler, $attrib);
606 else if (function_exists($handler)) {
607 // execute object handler function
608 return call_user_func($handler, $attrib);
611 if ($object=='productname') {
612 $name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail';
615 if ($object=='version') {
616 $ver = (string)RCMAIL_VERSION;
617 if (is_file(INSTALL_PATH . '.svn/entries')) {
618 if (preg_match('/Revision:\s(\d+)/', @shell_exec('svn info'), $regs))
619 $ver .= ' [SVN r'.$regs[1].']';
623 if ($object=='steptitle') {
624 return Q($this->get_pagetitle());
626 if ($object=='pagetitle') {
627 $title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '';
628 $title .= $this->get_pagetitle();
633 // return code for a specified eval expression
635 $value = $this->parse_expression($attrib['expression']);
636 return eval("return Q($value);");
640 $var = explode(':', $attrib['name']);
646 $value = $this->env[$name];
649 $value = $this->config[$name];
650 if (is_array($value) && $value[$_SESSION['imap_host']]) {
651 $value = $value[$_SESSION['imap_host']];
655 $value = get_input_value($name, RCUBE_INPUT_GPC);
658 $value = $_SESSION[$name];
661 $value = htmlspecialchars($_COOKIE[$name]);
665 if (is_array($value)) {
666 $value = implode(', ', $value);
676 * Include a specific file and return it's contents
678 * @param string File path
679 * @return string Contents of the processed file
681 private function include_php($file)
685 $out = ob_get_contents();
692 * Create and register a button
694 * @param array Named button attributes
695 * @return string HTML button
696 * @todo Remove all inline JS calls and use jQuery instead.
697 * @todo Remove all sprintf()'s - they are pretty, but also slow.
699 public function button($attrib)
701 static $sa_buttons = array();
702 static $s_button_count = 100;
704 // these commands can be called directly via url
705 $a_static_commands = array('compose', 'list');
707 if (!($attrib['command'] || $attrib['name'])) {
711 // try to find out the button type
712 if ($attrib['type']) {
713 $attrib['type'] = strtolower($attrib['type']);
716 $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link';
718 $command = $attrib['command'];
720 // take the button from the stack
721 if ($attrib['name'] && $sa_buttons[$attrib['name']]) {
722 $attrib = $sa_buttons[$attrib['name']];
724 else if($attrib['image'] || $attrib['imageact'] || $attrib['imagepas'] || $attrib['class']) {
725 // add button to button stack
726 if (!$attrib['name']) {
727 $attrib['name'] = $command;
729 if (!$attrib['image']) {
730 $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact'];
732 $sa_buttons[$attrib['name']] = $attrib;
734 else if ($command && $sa_buttons[$command]) {
735 // get saved button for this command/name
736 $attrib = $sa_buttons[$command];
739 if (!$attrib['id']) {
740 $attrib['id'] = sprintf('rcmbtn%d', $s_button_count++);
742 // get localized text for labels and titles
743 if ($attrib['title']) {
744 $attrib['title'] = Q(rcube_label($attrib['title']));
746 if ($attrib['label']) {
747 $attrib['label'] = Q(rcube_label($attrib['label']));
749 if ($attrib['alt']) {
750 $attrib['alt'] = Q(rcube_label($attrib['alt']));
752 // set title to alt attribute for IE browsers
753 if ($this->browser->ie && $attrib['title'] && !$attrib['alt']) {
754 $attrib['alt'] = $attrib['title'];
755 unset($attrib['title']);
758 // add empty alt attribute for XHTML compatibility
759 if (!isset($attrib['alt'])) {
763 // register button in the system
764 if ($attrib['command']) {
765 $this->add_script(sprintf(
766 "%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');",
771 $attrib['imageact'] ? $this->abs_url($attrib['imageact']) : $attrib['classact'],
772 $attrib['imagesel'] ? $this->abs_url($attrib['imagesel']) : $attrib['classsel'],
773 $attrib['imageover'] ? $this->abs_url($attrib['imageover']) : ''
776 // make valid href to specific buttons
777 if (in_array($attrib['command'], rcmail::$main_tasks)) {
778 $attrib['href'] = rcmail_url(null, null, $attrib['command']);
780 else if (in_array($attrib['command'], $a_static_commands)) {
781 $attrib['href'] = rcmail_url($attrib['command']);
783 else if ($attrib['command'] == 'permaurl' && !empty($this->env['permaurl'])) {
784 $attrib['href'] = $this->env['permaurl'];
788 // overwrite attributes
789 if (!$attrib['href']) {
790 $attrib['href'] = '#';
793 $attrib['onclick'] = sprintf(
794 "return %s.command('%s','%s',this)",
800 if ($command && $attrib['imageover']) {
801 $attrib['onmouseover'] = sprintf(
802 "return %s.button_over('%s','%s')",
807 $attrib['onmouseout'] = sprintf(
808 "return %s.button_out('%s','%s')",
815 if ($command && $attrib['imagesel']) {
816 $attrib['onmousedown'] = sprintf(
817 "return %s.button_sel('%s','%s')",
822 $attrib['onmouseup'] = sprintf(
823 "return %s.button_out('%s','%s')",
832 // generate image tag
833 if ($attrib['type']=='image') {
834 $attrib_str = html::attrib_string(
837 'style', 'class', 'id', 'width',
838 'height', 'border', 'hspace',
839 'vspace', 'align', 'alt', 'tabindex'
842 $btn_content = sprintf('<img src="%s"%s />', $this->abs_url($attrib['image']), $attrib_str);
843 if ($attrib['label']) {
844 $btn_content .= ' '.$attrib['label'];
846 $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title', 'target');
848 else if ($attrib['type']=='link') {
849 $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command'];
850 $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style', 'tabindex', 'target');
852 else if ($attrib['type']=='input') {
853 $attrib['type'] = 'button';
855 if ($attrib['label']) {
856 $attrib['value'] = $attrib['label'];
859 $attrib_str = html::attrib_string(
862 'type', 'value', 'onclick',
863 'id', 'class', 'style', 'tabindex'
866 $out = sprintf('<input%s disabled="disabled" />', $attrib_str);
869 // generate html code for button
871 $attrib_str = html::attrib_string($attrib, $link_attrib);
872 $out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content);
879 /* ************* common functions delivering gui objects ************** */
883 * Create a form tag with the necessary hidden fields
885 * @param array Named tag parameters
886 * @return string HTML code for the form
888 public function form_tag($attrib, $content = null)
891 $hiddenfield = new html_hiddenfield(array('name' => '_framed', 'value' => '1'));
892 $hidden = $hiddenfield->show();
896 $attrib['noclose'] = true;
898 return html::tag('form',
899 $attrib + array('action' => "./", 'method' => "get"),
905 * GUI object 'username'
906 * Showing IMAP username of the current session
908 * @param array Named tag parameters (currently not used)
909 * @return string HTML code for the gui object
911 public function current_username($attrib)
916 if (!empty($username)) {
920 // get e-mail address form default identity
921 if ($sql_arr = $this->app->user->get_identity()) {
922 $username = $sql_arr['email'];
925 $username = $this->app->user->get_username();
933 * GUI object 'loginform'
934 * Returns code for the webmail login form
936 * @param array Named parameters
937 * @return string HTML code for the gui object
939 private function login_form($attrib)
941 $default_host = $this->config['default_host'];
943 $_SESSION['temp'] = true;
945 $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30) + $attrib);
946 $input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30) + $attrib);
947 $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login'));
948 $input_tzone = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_'));
951 if (is_array($default_host)) {
952 $input_host = new html_select(array('name' => '_host', 'id' => 'rcmloginhost'));
954 foreach ($default_host as $key => $value) {
955 if (!is_array($value)) {
956 $input_host->add($value, (is_numeric($key) ? $value : $key));
964 else if (empty($default_host)) {
965 $input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30));
968 $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
969 $this->add_gui_object('loginform', $form_name);
971 // create HTML table with two cols
972 $table = new html_table(array('cols' => 2));
974 $table->add('title', html::label('rcmloginuser', Q(rcube_label('username'))));
975 $table->add(null, $input_user->show(get_input_value('_user', RCUBE_INPUT_POST)));
977 $table->add('title', html::label('rcmloginpwd', Q(rcube_label('password'))));
978 $table->add(null, $input_pass->show());
980 // add host selection row
981 if (is_object($input_host)) {
982 $table->add('title', html::label('rcmloginhost', Q(rcube_label('server'))));
983 $table->add(null, $input_host->show(get_input_value('_host', RCUBE_INPUT_POST)));
986 $out = $input_action->show();
987 $out .= $input_tzone->show();
988 $out .= $table->show();
990 // surround html output with a form tag
991 if (empty($attrib['form'])) {
992 $out = $this->form_tag(array('name' => $form_name, 'method' => "post"), $out);
1000 * GUI object 'searchform'
1001 * Returns code for search function
1003 * @param array Named parameters
1004 * @return string HTML code for the gui object
1006 private function search_form($attrib)
1008 // add some labels to client
1009 $this->add_label('searching');
1011 $attrib['name'] = '_q';
1013 if (empty($attrib['id'])) {
1014 $attrib['id'] = 'rcmqsearchbox';
1016 if ($attrib['type'] == 'search' && !$this->browser->khtml) {
1017 unset($attrib['type'], $attrib['results']);
1020 $input_q = new html_inputfield($attrib);
1021 $out = $input_q->show();
1023 $this->add_gui_object('qsearchbox', $attrib['id']);
1025 // add form tag around text field
1026 if (empty($attrib['form'])) {
1027 $out = $this->form_tag(array(
1028 'name' => "rcmqsearchform",
1029 'onsubmit' => JS_OBJECT_NAME . ".command('search');return false;",
1030 'style' => "display:inline"),
1039 * Builder for GUI object 'message'
1041 * @param array Named tag parameters
1042 * @return string HTML code for the gui object
1044 private function message_container($attrib)
1046 if (isset($attrib['id']) === false) {
1047 $attrib['id'] = 'rcmMessageContainer';
1050 $this->add_gui_object('message', $attrib['id']);
1051 return html::div($attrib, "");
1056 * GUI object 'charsetselector'
1058 * @param array Named parameters for the select tag
1059 * @return string HTML code for the gui object
1061 static function charset_selector($attrib)
1063 // pass the following attributes to the form class
1064 $field_attrib = array('name' => '_charset');
1065 foreach ($attrib as $attr => $value) {
1066 if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex'))) {
1067 $field_attrib[$attr] = $value;
1071 'US-ASCII' => 'ASCII (English)',
1072 'EUC-JP' => 'EUC-JP (Japanese)',
1073 'EUC-KR' => 'EUC-KR (Korean)',
1074 'BIG5' => 'BIG5 (Chinese)',
1075 'GB2312' => 'GB2312 (Chinese)',
1076 'ISO-2022-JP' => 'ISO-2022-JP (Japanese)',
1077 'ISO-8859-1' => 'ISO-8859-1 (Latin-1)',
1078 'ISO-8859-2' => 'ISO-8895-2 (Central European)',
1079 'ISO-8859-7' => 'ISO-8859-7 (Greek)',
1080 'ISO-8859-9' => 'ISO-8859-9 (Turkish)',
1081 'Windows-1251' => 'Windows-1251 (Cyrillic)',
1082 'Windows-1252' => 'Windows-1252 (Western)',
1083 'Windows-1255' => 'Windows-1255 (Hebrew)',
1084 'Windows-1256' => 'Windows-1256 (Arabic)',
1085 'Windows-1257' => 'Windows-1257 (Baltic)',
1089 $select = new html_select($field_attrib);
1090 $select->add(array_values($charsets), array_keys($charsets));
1092 $set = $_POST['_charset'] ? $_POST['_charset'] : $this->get_charset();
1093 return $select->show($set);
1096 } // end class rcube_template