From 0c259682f65eaaf23ea4ccb56a706d6baf3007e4 Mon Sep 17 00:00:00 2001
From: alecpl
Date: Fri, 13 Apr 2012 08:52:02 +0000
Subject: - Merge devel-framework branch, resolved conflicts
---
program/include/rcube_output_html.php | 1604 +++++++++++++++++++++++++++++++++
1 file changed, 1604 insertions(+)
create mode 100644 program/include/rcube_output_html.php
(limited to 'program/include/rcube_output_html.php')
diff --git a/program/include/rcube_output_html.php b/program/include/rcube_output_html.php
new file mode 100644
index 000000000..a047aba45
--- /dev/null
+++ b/program/include/rcube_output_html.php
@@ -0,0 +1,1604 @@
+ |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+ */
+
+
+/**
+ * Class to create HTML page output using a skin template
+ *
+ * @package View
+ */
+class rcube_output_html extends rcube_output
+{
+ public $type = 'html';
+
+ protected $message = null;
+ protected $js_env = array();
+ protected $js_labels = array();
+ protected $js_commands = array();
+ protected $plugin_skin_path;
+ protected $template_name;
+ protected $scripts_path = '';
+ protected $script_files = array();
+ protected $css_files = array();
+ protected $scripts = array();
+ protected $default_template = "\n\n\n";
+ protected $header = '';
+ protected $footer = '';
+ protected $body = '';
+ protected $base_path = '';
+
+ // deprecated names of templates used before 0.5
+ protected $deprecated_templates = array(
+ 'contact' => 'showcontact',
+ 'contactadd' => 'addcontact',
+ 'contactedit' => 'editcontact',
+ 'identityedit' => 'editidentity',
+ 'messageprint' => 'printmessage',
+ );
+
+ /**
+ * Constructor
+ *
+ * @todo Replace $this->config with the real rcube_config object
+ */
+ public function __construct($task = null, $framed = false)
+ {
+ parent::__construct();
+
+ //$this->framed = $framed;
+ $this->set_env('task', $task);
+ $this->set_env('x_frame_options', $this->config->get('x_frame_options', 'sameorigin'));
+
+ // load the correct skin (in case user-defined)
+ $this->set_skin($this->config->get('skin'));
+
+ // add common javascripts
+ $this->add_script('var '.JS_OBJECT_NAME.' = new rcube_webmail();', 'head_top');
+
+ // don't wait for page onload. Call init at the bottom of the page (delayed)
+ $this->add_script(JS_OBJECT_NAME.'.init();', 'docready');
+
+ $this->scripts_path = 'program/js/';
+ $this->include_script('jquery.min.js');
+ $this->include_script('common.js');
+ $this->include_script('app.js');
+
+ // register common UI objects
+ $this->add_handlers(array(
+ 'loginform' => array($this, 'login_form'),
+ 'preloader' => array($this, 'preloader'),
+ 'username' => array($this, 'current_username'),
+ 'message' => array($this, 'message_container'),
+ 'charsetselector' => array($this, 'charset_selector'),
+ 'aboutcontent' => array($this, 'about_content'),
+ ));
+ }
+
+
+ /**
+ * Set environment variable
+ *
+ * @param string Property name
+ * @param mixed Property value
+ * @param boolean True if this property should be added to client environment
+ */
+ public function set_env($name, $value, $addtojs = true)
+ {
+ $this->env[$name] = $value;
+ if ($addtojs || isset($this->js_env[$name])) {
+ $this->js_env[$name] = $value;
+ }
+ }
+
+
+ /**
+ * Getter for the current page title
+ *
+ * @return string The page title
+ */
+ protected function get_pagetitle()
+ {
+ if (!empty($this->pagetitle)) {
+ $title = $this->pagetitle;
+ }
+ else if ($this->env['task'] == 'login') {
+ $title = $this->app->gettext(array(
+ 'name' => 'welcome',
+ 'vars' => array('product' => $this->config->get('product_name')
+ )));
+ }
+ else {
+ $title = ucfirst($this->env['task']);
+ }
+
+ return $title;
+ }
+
+
+ /**
+ * Set skin
+ */
+ public function set_skin($skin)
+ {
+ $valid = false;
+
+ if (!empty($skin) && is_dir('skins/'.$skin) && is_readable('skins/'.$skin)) {
+ $skin_path = 'skins/'.$skin;
+ $valid = true;
+ }
+ else {
+ $skin_path = $this->config->get('skin_path');
+ if (!$skin_path) {
+ $skin_path = 'skins/default';
+ }
+ $valid = !$skin;
+ }
+
+ $this->config->set('skin_path', $skin_path);
+
+ return $valid;
+ }
+
+
+ /**
+ * Check if a specific template exists
+ *
+ * @param string Template name
+ * @return boolean True if template exists
+ */
+ public function template_exists($name)
+ {
+ $filename = $this->config->get('skin_path') . '/templates/' . $name . '.html';
+ return (is_file($filename) && is_readable($filename)) || ($this->deprecated_templates[$name] && $this->template_exists($this->deprecated_templates[$name]));
+ }
+
+
+ /**
+ * Register a GUI object to the client script
+ *
+ * @param string Object name
+ * @param string Object ID
+ * @return void
+ */
+ public function add_gui_object($obj, $id)
+ {
+ $this->add_script(JS_OBJECT_NAME.".gui_object('$obj', '$id');");
+ }
+
+
+ /**
+ * Call a client method
+ *
+ * @param string Method to call
+ * @param ... Additional arguments
+ */
+ public function command()
+ {
+ $cmd = func_get_args();
+ if (strpos($cmd[0], 'plugin.') !== false)
+ $this->js_commands[] = array('triggerEvent', $cmd[0], $cmd[1]);
+ else
+ $this->js_commands[] = $cmd;
+ }
+
+
+ /**
+ * Add a localized label to the client environment
+ */
+ public function add_label()
+ {
+ $args = func_get_args();
+ if (count($args) == 1 && is_array($args[0]))
+ $args = $args[0];
+
+ foreach ($args as $name) {
+ $this->js_labels[$name] = $this->app->gettext($name);
+ }
+ }
+
+
+ /**
+ * Invoke display_message command
+ *
+ * @param string $message Message to display
+ * @param string $type Message type [notice|confirm|error]
+ * @param array $vars Key-value pairs to be replaced in localized text
+ * @param boolean $override Override last set message
+ * @param int $timeout Message display time in seconds
+ * @uses self::command()
+ */
+ public function show_message($message, $type='notice', $vars=null, $override=true, $timeout=0)
+ {
+ if ($override || !$this->message) {
+ if ($this->app->text_exists($message)) {
+ if (!empty($vars))
+ $vars = array_map('Q', $vars);
+ $msgtext = $this->app->gettext(array('name' => $message, 'vars' => $vars));
+ }
+ else
+ $msgtext = $message;
+
+ $this->message = $message;
+ $this->command('display_message', $msgtext, $type, $timeout * 1000);
+ }
+ }
+
+
+ /**
+ * Delete all stored env variables and commands
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->js_env = array();
+ $this->js_labels = array();
+ $this->js_commands = array();
+ $this->script_files = array();
+ $this->scripts = array();
+ $this->header = '';
+ $this->footer = '';
+ $this->body = '';
+ }
+
+
+ /**
+ * Redirect to a certain url
+ *
+ * @param mixed $p Either a string with the action or url parameters as key-value pairs
+ * @param int $delay Delay in seconds
+ */
+ public function redirect($p = array(), $delay = 1)
+ {
+ $location = $this->app->url($p);
+ header('Location: ' . $location);
+ exit;
+ }
+
+
+ /**
+ * Send the request output to the client.
+ * This will either parse a skin tempalte or send an AJAX response
+ *
+ * @param string Template name
+ * @param boolean True if script should terminate (default)
+ */
+ public function send($templ = null, $exit = true)
+ {
+ if ($templ != 'iframe') {
+ // prevent from endless loops
+ if ($exit != 'recur' && $this->app->plugins->is_processing('render_page')) {
+ rcube::raise_error(array('code' => 505, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => 'Recursion alert: ignoring output->send()'), true, false);
+ return;
+ }
+ $this->parse($templ, false);
+ }
+ else {
+ $this->framed = $templ == 'iframe' ? true : $this->framed;
+ $this->write();
+ }
+
+ // set output asap
+ ob_flush();
+ flush();
+
+ if ($exit) {
+ exit;
+ }
+ }
+
+
+ /**
+ * Process template and write to stdOut
+ *
+ * @param string $template HTML template content
+ */
+ public function write($template = '')
+ {
+ // unlock interface after iframe load
+ $unlock = preg_replace('/[^a-z0-9]/i', '', $_REQUEST['_unlock']);
+ if ($this->framed) {
+ array_unshift($this->js_commands, array('set_busy', false, null, $unlock));
+ }
+ else if ($unlock) {
+ array_unshift($this->js_commands, array('hide_message', $unlock));
+ }
+
+ if (!empty($this->script_files))
+ $this->set_env('request_token', $this->app->get_request_token());
+
+ // write all env variables to client
+ $js = $this->framed ? "if(window.parent) {\n" : '';
+ $js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
+ $this->add_script($js, 'head_top');
+
+ // send clickjacking protection headers
+ $iframe = $this->framed || !empty($_REQUEST['_framed']);
+ if (!headers_sent() && ($xframe = $this->app->config->get('x_frame_options', 'sameorigin')))
+ header('X-Frame-Options: ' . ($iframe && $xframe == 'deny' ? 'sameorigin' : $xframe));
+
+ // call super method
+ $this->_write($template, $this->config->get('skin_path'));
+ }
+
+
+ /**
+ * Parse a specific skin template and deliver to stdout (or return)
+ *
+ * @param string Template name
+ * @param boolean Exit script
+ * @param boolean Don't write to stdout, return parsed content instead
+ *
+ * @link http://php.net/manual/en/function.exit.php
+ */
+ function parse($name = 'main', $exit = true, $write = true)
+ {
+ $skin_path = $this->config->get('skin_path');
+ $plugin = false;
+ $realname = $name;
+ $temp = explode('.', $name, 2);
+
+ $this->plugin_skin_path = null;
+ $this->template_name = $realname;
+
+ if (count($temp) > 1) {
+ $plugin = $temp[0];
+ $name = $temp[1];
+ $skin_dir = $plugin . '/skins/' . $this->config->get('skin');
+ $skin_path = $this->plugin_skin_path = $this->app->plugins->dir . $skin_dir;
+
+ // fallback to default skin
+ if (!is_dir($skin_path)) {
+ $skin_dir = $plugin . '/skins/default';
+ $skin_path = $this->plugin_skin_path = $this->app->plugins->dir . $skin_dir;
+ }
+ }
+
+ $path = "$skin_path/templates/$name.html";
+
+ if (!is_readable($path) && $this->deprecated_templates[$realname]) {
+ $path = "$skin_path/templates/".$this->deprecated_templates[$realname].".html";
+ if (is_readable($path))
+ rcube::raise_error(array('code' => 502, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Using deprecated template '".$this->deprecated_templates[$realname]
+ ."' in $skin_path/templates. Please rename to '".$realname."'"),
+ true, false);
+ }
+
+ // read template file
+ if (($templ = @file_get_contents($path)) === false) {
+ rcube::raise_error(array(
+ 'code' => 501,
+ 'type' => 'php',
+ 'line' => __LINE__,
+ 'file' => __FILE__,
+ 'message' => 'Error loading template for '.$realname
+ ), true, true);
+ return false;
+ }
+
+ // replace all path references to plugins/... with the configured plugins dir
+ // and /this/ to the current plugin skin directory
+ if ($plugin) {
+ $templ = preg_replace(array('/\bplugins\//', '/(["\']?)\/this\//'), array($this->app->plugins->url, '\\1'.$this->app->plugins->url.$skin_dir.'/'), $templ);
+ }
+
+ // parse for specialtags
+ $output = $this->parse_conditions($templ);
+ $output = $this->parse_xml($output);
+
+ // trigger generic hook where plugins can put additional content to the page
+ $hook = $this->app->plugins->exec_hook("render_page", array('template' => $realname, 'content' => $output));
+
+ // save some memory
+ $output = $hook['content'];
+ unset($hook['content']);
+
+ $output = $this->parse_with_globals($output);
+
+ // make sure all
') {
+ $hpos++;
+ }
+ $hpos++;
+ }
+ $page_header = "\n$page_title\n$page_header\n\n";
+ }
+
+ // add page hader
+ if ($hpos) {
+ $output = substr_replace($output, $page_header, $hpos, 0);
+ }
+ else {
+ $output = $page_header . $output;
+ }
+
+ // add page footer
+ if (($fpos = strripos($output, '