From: Michael M Slusarz Date: Mon, 28 Sep 2009 03:12:59 +0000 (-0600) Subject: Ticket #8592 - More IFRAME/HTML work X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=c1716b393f3d2656419610100aeb8e9d4a6b6670;p=horde.git Ticket #8592 - More IFRAME/HTML work IFRAME & IFRAME data are now loaded on the same page; javascript does the dynamic addition of the text to the IFRAME. Saves a server access. Image block display now works again entirely via javascript, rather than requiring another server access. --- diff --git a/imp/js/imp.js b/imp/js/imp.js index 0fb08f2d7..9843cf592 100644 --- a/imp/js/imp.js +++ b/imp/js/imp.js @@ -26,9 +26,34 @@ document.observe('dom:loaded', function() { */ IMP.unblockImages = function(e) { - var elt = e.element().up('TABLE.mimeStatusMessage'); + var elt = e.element().up('TABLE.mimeStatusMessage'), + iframe = elt.up().next('.htmlMsgData'), + s = new Selector('[htmlimgblocked]'); - elt.up().next('.htmlMessage').writeAttribute('src', e.element().readAttribute('href')); + // Need to use non-prototypejs methods to work with data inside of + // the IFRAME. Prototypejs's Selector works, but only if we use + // the pure javascript method. + if (s.mode != 'normal') { + delete Selector._cache['[htmlimgblocked]']; + s.mode = 'normal'; + s.compileMatcher(); + } + + s.findElements(iframe.contentWindow.document).each(function(b) { + var src = decodeURIComponent(b.getAttribute('htmlimgblocked')); + if (b.getAttribute('src')) { + b.setAttribute('src', src); + } else if (b.getAttribute('background')) { + b.setAttribute('background', src); + } else if (b.style.backgroundImage) { + b.style.setProperty('background-image', 'url(' + src + ')', ''); + } + }); + + // Delete this entry, because in the rare case that another selector + // on the page uses the same expression, it will break the next time + // it is used. + delete Selector._cache['[htmlimgblocked]']; Effect.Fade(elt, { afterFinish: function() { elt.remove(); }, @@ -38,6 +63,24 @@ document.observe('dom:loaded', function() { e.stop(); }; + IMP.iframeInject = function(id, data) + { + id = $(id); + var d = id.contentWindow.document; + + d.open(); + d.write(data); + d.close(); + + this.iframeResize(id); + }; + + IMP.iframeResize = function(id) + { + id = $(id); + id.setStyle({ height: id.contentWindow.document.height + 'px' }); + }; + // If menu is present, attach event handlers to folder switcher. var tmp = $('openfoldericon'); if (tmp) { diff --git a/imp/lib/Contents.php b/imp/lib/Contents.php index fb0374128..4b7afa238 100644 --- a/imp/lib/Contents.php +++ b/imp/lib/Contents.php @@ -373,9 +373,11 @@ class IMP_Contents * identified in the MIME part. * * - * @return array See Horde_Mime_Viewer_Driver::render(). Additionally, - * a entry in the base array labeled 'name' will be present - * which contains the MIME name information. + * @return array See Horde_Mime_Viewer_Driver::render(). The following + * fields may also be present: + * 'js' - (array) A list of javascript commands to run + * after the content is displayed on screen. + * 'name' - (string) Contains the MIME name information. */ public function renderMIMEPart($mime_id, $mode, $options = array()) { diff --git a/imp/lib/Mime/Viewer/Html.php b/imp/lib/Mime/Viewer/Html.php index 680064e2e..a39acbfcb 100644 --- a/imp/lib/Mime/Viewer/Html.php +++ b/imp/lib/Mime/Viewer/Html.php @@ -57,20 +57,20 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html \s* # opening quotes, parenthesis; match 4 ("|\')? - # the image url - (?(2) + # the image url; match 5 + ((?(2) # matched a "style" attribute (?(4)[^"\')>]*|[^\s)>]*) # did not match a "style" attribute |(?(4)[^"\'>]*|[^\s>]*) - ) + )) # closing quotes (?(4)\\4) # matched a "style" attribute? (?(2) # closing parenthesis \s*\) - # remainder of the "style" attribute; match 5 + # remainder of the "style" attribute; match 6 ((?(3)[^"\'>]*|[^\s>]*)) ) /isx'; @@ -90,56 +90,40 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html /** * Return the rendered inline version of the Horde_Mime_Part object. * - * URL parameters used by this function: - *
-     * 'html_iframe_data' - (boolean) If true, output the iframe content only.
-     * 'html_view_images' - (boolean) If true, force display of images.
-     * 
- * * @return array See Horde_Mime_Viewer_Driver::render(). */ protected function _renderInline() { - if (Horde_Util::getFormData('html_iframe_data')) { - $html = $this->_IMPrender(true); - } else { - $data = ''; - $view_part = isset($this->_params['related_id']) - ? $this->_params['contents']->getMIMEPart($this->_params['related_id']) - : $this->_mimepart; - - $src = $this->_params['contents']->urlView($view_part, 'view_attach', array('params' => array('html_iframe_data' => 1, 'mode' => IMP_Contents::RENDER_INLINE))); - - /* Check for phishing exploits. */ - $contents = $this->_mimepart->getContents(); - $this->_phishingCheck($contents, true); - $status = array($this->_phishingStatus()); - - /* Only display images if specifically allowed by user. */ - if ($GLOBALS['prefs']->getValue('html_image_replacement') && - preg_match($this->_img_regex, $contents)) { - // Unblock javascript code in js/imp.js - $data = Horde_Util::bufferOutput(array('Horde', 'addScriptFile'), 'imp.js', 'imp', true); - - $status[] = array( - 'icon' => Horde::img('mime/image.png'), - 'text' => array( - _("Images have been blocked to protect your privacy."), - Horde::link(Horde_Util::addParameter($src, 'html_view_images', 1), '', 'unblockImageLink') . _("Show Images?") . '' - ) - ); - } - - $html = array( - // TODO: Why do we need extra 10 pixels, at least on FF 3.1? - 'data' => '' . $data, - 'status' => $status, - 'type' => 'text/html; charset=' . Horde_Nls::getCharset() + /* Non-javascript browsers can't handle IFRAME resizing, so it isn't + * possible to view inline. */ + if (!$GLOBALS['browser']->hasFeature('javascript')) { + return array( + $this->_mimepart->getMimeId() => array( + 'data' => '', + 'status' => array( + array( + 'icon' => Horde::img('mime/html.png'), + 'text' => array( + _("This message part contains HTML data, but this data can not be displayed inline."), + $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("View HTML data in new window.")), + ) + ) + ), + 'type' => 'text/html; charset=' . Horde_Nls::getCharset() + ) ); } + $data = $this->_IMPrender(true); + $uid = 'htmldata_' . uniqid(mt_rand()); + + $data['js'] = array('IMP.iframeInject("' . $uid . '", ' . Horde_Serialize::serialize($data['data'], Horde_Serialize::JSON, $this->_mimepart->getCharset()) . ')'); + $data['data'] = '' . + Horde_Util::bufferOutput(array('Horde', 'addScriptFile'), 'imp.js', 'imp', true); + $data['type'] = 'text/html; charset=' . Horde_Nls::getCharset(); + return array( - $this->_mimepart->getMimeId() => $html + $this->_mimepart->getMimeId() => $data ); } @@ -154,19 +138,17 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html return array(); } - $status = array( - _("This message part contains HTML data, but inline HTML display is disabled."), - $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("View HTML data in new window.")), - $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("Convert HTML data to plain text and view in new window."), array('params' => array('convert_text' => 1))) - ); - return array( $this->_mimepart->getMimeId() => array( 'data' => '', 'status' => array( array( 'icon' => Horde::img('mime/html.png', _("HTML data")), - 'text' => $status + 'text' => array( + _("This message part contains HTML data, but inline HTML display is disabled."), + $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("View HTML data in new window.")), + $this->_params['contents']->linkViewJS($this->_mimepart, 'view_attach', _("Convert HTML data to plain text and view in new window."), array('params' => array('convert_text' => 1))) + ) ) ), 'type' => 'text/html; charset=' . Horde_Nls::getCharset() @@ -184,10 +166,10 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html protected function _IMPrender($inline) { $data = $this->_mimepart->getContents(); - $charset = Horde_Nls::getCharset(); /* Sanitize the HTML. */ $data = $this->_cleanHTML($data, array('phishing' => $inline)); + $status = array($this->_phishingStatus()); /* We are done processing if in mimp mode, or we are converting to * text. */ @@ -199,7 +181,7 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html return array( 'data' => IMP::filterText($data), 'status' => array(), - 'type' => 'text/plain; charset=' . $charset + 'type' => 'text/plain; charset=' . Horde_Nls::getCharset() ); } @@ -253,12 +235,19 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html /* Image filtering. */ if ($inline && - !Horde_Util::getFormData('html_view_images') && $GLOBALS['prefs']->getValue('html_image_replacement') && preg_match($this->_img_regex, $this->_mimepart->getContents()) && (!$GLOBALS['prefs']->getValue('html_image_addrbook') || !$this->_inAddressBook())) { $data = preg_replace_callback($this->_img_regex, array($this, '_blockImages'), $data); + + $status[] = array( + 'icon' => Horde::img('mime/image.png'), + 'text' => array( + _("Images have been blocked to protect your privacy."), + Horde::link('#', '', 'unblockImageLink') . _("Show Images?") . '' + ) + ); } if ($GLOBALS['prefs']->getValue('emoticons')) { @@ -267,7 +256,7 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html return array( 'data' => $data, - 'status' => array(), + 'status' => $status, 'type' => $this->_mimepart->getType(true) ); } @@ -290,12 +279,12 @@ class IMP_Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Html protected function _blockImages($matches) { if (is_null($this->_blockimg)) { - $this->_blockimg = Horde::url($GLOBALS['registry']->getImageDir('imp', false) . '/spacer_red.png', false, -1); + $this->_blockimg = Horde::url($GLOBALS['registry']->getImageDir('imp', false) . '/spacer_red.png', true, -1); } return empty($matches[2]) - ? $matches[1] . '"' . $this->_blockimg . '"' - : $matches[1] . "'" . $this->_blockimg . '\')' . $matches[5] . '"'; + ? $matches[1] . '"' . $this->_blockimg . '" htmlimgblocked="' . rawurlencode(str_replace('&', '&', trim($matches[5], '\'" '))) . '"' + : $matches[1] . "'" . $this->_blockimg . '\')' . $matches[6] . '" htmlimgblocked="' . rawurlencode(str_replace('&', '&', trim($matches[5], '\'" '))); } /** diff --git a/imp/lib/Views/ShowMessage.php b/imp/lib/Views/ShowMessage.php index 7316327a6..ee553d30d 100644 --- a/imp/lib/Views/ShowMessage.php +++ b/imp/lib/Views/ShowMessage.php @@ -68,6 +68,7 @@ class IMP_Views_ShowMessage * 'errortype' - Contains the error type (only on error) * 'from' - The From addresses * 'index' - The IMAP UID + * 'js' - Javascript code to run on display * 'log' - Log information * 'mailbox' - The IMAP mailbox * 'msgtext' - The text of the message @@ -75,8 +76,6 @@ class IMP_Views_ShowMessage * * FOR PREVIEW MODE: * 'fulldate' - The fully formatted date - * 'js' - Javascript code to run on display (only if the previewview - * hook is active) * 'minidate' - A miniature date * * FOR NON-PREVIEW MODE: @@ -98,6 +97,7 @@ class IMP_Views_ShowMessage $result = array( 'index' => $index, + 'js' => array(), 'mailbox' => $mailbox ); @@ -296,6 +296,10 @@ class IMP_Views_ShowMessage } $result['msgtext'] .= '
' . implode(' ', $tmp_summary) . '
' . implode("\n", $tmp_status) . $info['data']; + + if (isset($info['js'])) { + $result['js'] = array_merge($result['js'], $info['js']); + } } } @@ -338,7 +342,7 @@ class IMP_Views_ShowMessage $res = Horde::callHook('dimp_previewview', array($result), 'imp'); if (!empty($res)) { $result = $res[0]; - $result['js'] = $res[1]; + $result['js'] = array_merge($result['js'], $res[1]); } } catch (Horde_Exception_HookNotSet $e) {} } elseif (!$preview) { @@ -352,6 +356,10 @@ class IMP_Views_ShowMessage $result['save_as'] = Horde::downloadUrl(htmlspecialchars_decode($result['subject']), array_merge(array('actionID' => 'save_message'), IMP::getIMPMboxParameters($mailbox, $index, $mailbox))); } + if (empty($result['js'])) { + unset($result['js']); + } + return $result; } } diff --git a/imp/message-dimp.php b/imp/message-dimp.php index 757ace4cd..7198af376 100644 --- a/imp/message-dimp.php +++ b/imp/message-dimp.php @@ -41,8 +41,7 @@ if (isset($show_msg_result['error'])) { $scripts = array( array('ContextSensitive.js', 'imp', true), - array('fullmessage-dimp.js', 'imp', true), - array('imp.js', 'imp', true) + array('fullmessage-dimp.js', 'imp', true) ); $js_out = array(); @@ -78,8 +77,13 @@ if (!$disable_compose) { Horde::addInlineScript($compose_result['jsonload'], 'load'); } +$js_onload = array(IMP_Dimp::notify()); +if (isset($show_msg_result['js'])) { + $js_onload = array_merge($js_onload, $show_msg_result['js']); +} + Horde::addInlineScript($js_out); -Horde::addInlineScript(array(IMP_Dimp::notify()), 'dom'); +Horde::addInlineScript($js_onload, 'dom'); IMP_Dimp::header($show_msg_result['subject'], $scripts); echo "\n"; diff --git a/imp/message.php b/imp/message.php index e8c6535e3..a4bf739b5 100644 --- a/imp/message.php +++ b/imp/message.php @@ -579,6 +579,7 @@ $part_info_action = array('download', 'download_zip', 'img_save', 'strip'); $parts_list = $imp_contents->getContentTypeMap(); $strip_atc = $prefs->getValue('strip_attachments'); $atc_parts = $display_ids = array(); +$js_onload = array(); $msgtext = ''; /* Do MDN processing now. */ @@ -649,6 +650,10 @@ foreach ($parts_list as $mime_id => $mime_type) { $msgtext .= '
' . implode(' ', $tmp_summary) . '
' . implode("\n", $tmp_status) . $info['data']; + + if (isset($info['js'])) { + $js_onload = array_merge($js_onload, $info['js']); + } } } @@ -713,6 +718,7 @@ $m_template->set('headers', $hdrs); $m_template->set('msgtext', $msgtext); /* Output message page now. */ +Horde::addInlineScript($js_onload, 'dom'); Horde::addScriptFile('effects.js', 'horde', true); Horde::addScriptFile('imp.js', 'imp', true); Horde::addScriptFile('message.js', 'imp', true); diff --git a/imp/themes/screen.css b/imp/themes/screen.css index a827c1747..8415d942a 100644 --- a/imp/themes/screen.css +++ b/imp/themes/screen.css @@ -210,7 +210,7 @@ span.trashImg { } /* Style for HTML data iframe. */ -.htmlMessage { +.htmlMsgData { margin: 5px 0; border: 0; width: 100%;