Dreamstime

Sunday 1 March 2015

RavenPlus: Getting iframes To Work Correctly

Here is an update to my previous work on iframes in RavenPlus. If you recall, my first attempt only allows iframes to be placed at the end of a blog post. Well, not anymore with this fix, as you can see with the Amazon iframe banner ad above.

Self-Terminating Tags

It took me awhile but I managed to figure it out in the end.

Like all of my previous bug fixes, I always start by looking at the Python code of RavenPlus. Unfortunately, I got nowhere despite a couple of days work.

I finally resorted to looking for the temporary HTML script file that the RavenPlus editor creates, made a copy for myself and then loading this HTML file into my desktop web browser, Opera, to verify if it will load correctly. To my surprise, it did not. Somewhat bewildered, I tried loading again using Firefox and Internet Explorer. And I go the same result.

With this new lead, my suspicion turned to malformed HTML tags. My hunch was confirmed when I scrutinised the HTML script file with a text editor. The culprit: self-terminating <iframe> tag - AGAIN!

uTidyLib To The Rescue

Fixing this problem is easy, and it is similar to what I have done before.

Like what I did previously, I just filter the HTML scripts through uTidyLib before loading it into the WYSIWYG editor of RavenPlus. uTidyLib will replace all offending self-terminating iframe tags with opening-and-closing iframe tags instead. This will fix the problem.

With this modification, I can now place Amazon iframe ads at almost anywhere within my blog post, subject obviously, to the limitations of the HTML specifications of iframe.

As an example, the words in this section wraps around the Amazon iframe ad that is displayed on the left.

There maybe other fancier possibilities but I have not looked into it.

Anybody wants to buy a set of 3 Glass Wall Terrarium Globe Bubbles from Amazon? It creates an amazing mini ecosystem at your workplace. It won't take up much space as it hangs on the wall. Maybe improving the Feng Shui around your workplace too.


A Word Of Caution

You might want to encapsulate the iframe code between the HTML <P> </P> or <DIV> </DIV> tags first before inserting it into you blog post via the "XHTML" tab. Otherwise, RavenPlus might mess up your blog post in the "Design" tab. This happened to me once when I tried to insert an Amazon iframe ad at the very top of my blog post.

Also, after placing your iframe code, editing is allowed in the "Design" tab ONLY when there is an active Internet connection on your PC. There is no way round it - I have tried. The RavenPlus WYSIWYG editor is actually an embedded Microsoft's Internet Explorer (IE) in edit mode and that is how the IE engine works.


The Source Code

This fix only requires modification to just one file:


zoundry/appframework/ui/widgets/controls/advanced/mshtml/mshtmlcontrol.py


To use uTidyLib, we first need to include the following line somewhere at the top of this file (I placed mine at line 40).

#
# To ensure we get "<iframe></iframe>" instead of "<iframe/>" tags, we employ the help of "tidy HTML".
# 
#    ChuahTC Date:2014-Sept-12
from zoundry.base.zdom import tidyutil

Add the following lines in RED below into the function _loadStringFromFile (found at around line 355). These are the only additional lines of code that is neeeded. What these lines of code will do is that it will filter the HTML scripts (passed in via the parameter in this function) through uTidyLib and replace the self-terminating iframe tag with opening-and-closing iframe tags.

    def _loadStringFromFile(self, html):
        # ---- START ----
        #
        # To avoid getting self-terminating "iframe" tags, we filter the body content through "tidyutil.py".
        # tidyOptions parameters are actually tidyutil.SOURCE_OPTIONS but with the "new_inline_tags" and "new_blocklevel_tags"
        # parameters removed.
        #
        #    ChuahTC Date: 2014-Sept-12
        #
        tidyOptions  = dict(output_xhtml=1, add_xml_decl=0, add_xml_space=0, quiet=1, char_encoding="utf8", \
                     output_error=0, show_warnings=0, quote_nbsp=1, raw=1, indent="yes", show_body_only=1, \
                     quote_ampersand=1, quote_marks=1, logical_emphasis=1, hide_comments=0, wrap=140, \
                     word_2000=1, break_before_br=1, clean=0, indent_spaces=3, tab_size=1, drop_empty_paras=1, \
                     enclose_block_text=1, lower_literals=1, bare=1,drop_proprietary_attributes=1 )

        html = tidyutil.tidyHtml(html, tidyOptions)
        # ---- END -----

        # MSHTML control requires a <head> and <title> element
        title = getNoneString( extractTitle(html) )
        if not title or html.find(u"<html") == -1: #$NON-NLS-1$
            # case where only the body content is given or the content did not have non-empty <head> and <title> elems.
            # try and create wrapper around the body. Eg:  <html><head><title>ZoundryDocument</title></head><body> CONTENT </body> </html>
            html = wrapHtmlBody(html, u"ZoundryDocument") #$NON-NLS-1$

        # note: \r\n must be replace with \n. Otherwise, in <pre> blocks, the \r' will show up as an extra line.
        html = html.replace(u"\r\n", u"\n")  #$NON-NLS-1$  #$NON-NLS-2$
        # For the test-harness to work, hard code temp dir
        tmpDir = u"c:/temp" #$NON-NLS-1$
        if getApplicationModel():
            userProfile = getApplicationModel().getUserProfile()
            tmpDir = userProfile.getTempDirectory()
        d = str(time.time())

        # For Microsoft Internet Explorer Version 9 (and above?) the file extension for the temporary file must have
        # a ".html" (previously a ".xhtml") extension in order for the blog post to load successfully into the ActiveX
        # mshtml IHtmlDocument. Otherwise, the blog posts will appear to be mal-formatted during previews and fail to
        # load correctly during editing.
        #
        # Chuah TC    23 December 2013
        #
        # fname = os.path.join(tmpDir, u"_z_raven_mshtml_%s_tmp.xhtml" % d) #$NON-NLS-1$
        fname = os.path.join(tmpDir, u"_z_raven_mshtml_%s_tmp.html" % d) #$NON-NLS-1$


        tmpFile = codecs.open(fname, u"w") #$NON-NLS-1$
        try:
            # write the utf-8 byte order marker for wintel platforms.
            tmpFile.write(codecs.BOM_UTF8)
            tmpFile.write( convertToUtf8(html) )
            tmpFile.close()
            self._loadFile(fname)
        finally:
            tmpFile.close()
    # end _loadStringFromFile()



0 comments:

Post a Comment