Fix bug 753305 - Change invitation template to use a standalone file. r=laurent
authorPhilipp Kewisch <mozilla@kewis.ch>
Sat, 12 May 2012 17:02:35 +0700
changeset 10152 e31710132acbcfaabfb50430622b68b567c3ebb9
parent 10151 bdfc9e0e2918e9af4fca3f733cf61d4abf97666a
child 10153 b79072737e40c27a37dde664551ca366b75e3367
push id7718
push usermozilla@kewis.ch
push dateTue, 15 May 2012 07:13:03 +0000
treeherdercomm-central@b79072737e40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslaurent
bugs753305
Fix bug 753305 - Change invitation template to use a standalone file. r=laurent
calendar/lightning/components/lightningTextCalendarConverter.js
calendar/lightning/content/lightning-invitation.xhtml
calendar/lightning/jar.mn
--- a/calendar/lightning/components/lightningTextCalendarConverter.js
+++ b/calendar/lightning/components/lightningTextCalendarConverter.js
@@ -1,278 +1,199 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Lightning code.
- *
- * The Initial Developer of the Original Code is Oracle Corporation
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Mike Shaver <shaver@mozilla.org>
- *   Clint Talbert <ctalbert.moz@gmail.com>
- *   Matthew Willis <lilmatt@mozilla.com>
- *   Mauro Cicognini <mcicogni@libero.it>
- *   Philipp Kewisch <mozilla@kewis.ch>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or 
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 
-function makeTableRow(val) {
-    return "<tr><td>" + val[0] + "</td><td>" + val[1] + "</td></tr>\n";
-}
-
-function getLightningStringBundle()
-{
-    var svc = Components.classes["@mozilla.org/intl/stringbundle;1"].
-              getService(Components.interfaces.nsIStringBundleService);
-    return svc.createBundle("chrome://lightning/locale/lightning.properties");
-}
-
-function linkifyText(text) {
-    // Save off the settings
-    var savedSettings = XML.settings();
-
-    XML.ignoreWhitespace = false;
-    XML.prettyPrinting = false;
-    XML.prettyIndent = false;
-    var linkifiedText = <p/>;
-    var localText = text;
-
-    // XXX This should be improved to also understand abbreviated urls, could be
-    // extended to only linkify urls that have an internal protocol handler, or
-    // have an external protocol handler that has an app assigned. The same
-    // could be done for mailto links which are not handled here either.
-
-    while (localText.length) {
-        var pos = localText.search(/(^|\s+)([a-zA-Z0-9]+):\/\/[^\s]+/);
-        if (pos == -1) {
-            linkifiedText.appendChild(localText);
-            break;
-        }
-        pos += localText.substr(pos).match(/^\s*/)[0].length;
-        var endPos = pos + localText.substr(pos).search(/([.!,<>(){}]+)?(\s+|$)/);
-        var url = localText.substr(pos, endPos - pos);
-
-        if (pos > 0) {
-            linkifiedText.appendChild(localText.substr(0, pos));
-        }
-        var a = <a>{url}</a>;
-        a.@href = url;
-
-        linkifiedText.appendChild(a);
-
-        localText = localText.substr(endPos);
-    }
-    // restore the settings
-    XML.setSettings(savedSettings);
-
-    return linkifiedText;
-}
-
-function createHtmlTableSection(label, text, linkify)
-{
-    var tblRow = <tr>
-                    <td class="description">
-                        <p>{label}</p>
-                    </td>
-                    <td class="content">
-                        <p/>
-                    </td>
-                 </tr>;
-    if (linkify) {
-        tblRow.td.(@class == "content").p = linkifyText(text);
-    } else {
-        tblRow.td.(@class == "content").p = text;
-    }
-    return tblRow;
+function ltnMimeConverter() {
 }
 
-function createHtml(event)
-{
-    // Creates HTML using the Node strings in the properties file
-    var stringBundle = getLightningStringBundle();
-    var html;
-    if (stringBundle) {
-        // Using e4x javascript support here
-        html =
-               <html>
-               <head>
-                    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
-                    <link rel='stylesheet' type='text/css' href='chrome://messagebody/skin/imip.css'/>
-               </head>
-               <body>
-                    <table>
-                    </table>
-               </body>
-               </html>;
-        // Create header row
-        var labelText = stringBundle.GetStringFromName("imipHtml.header");
-        html.body.table.appendChild(
-            <tr>
-                <td colspan="3" class="header">
-                    <p class="header">{labelText}</p>
-                </td>
-            </tr>
-        );
-        if (event.title) {
-            labelText = stringBundle.GetStringFromName("imipHtml.summary");
-            html.body.table.appendChild(createHtmlTableSection(labelText,
-                                                               event.title));
-        }
-
-        var eventLocation = event.getProperty("LOCATION");
-        if (eventLocation) {
-            labelText = stringBundle.GetStringFromName("imipHtml.location");
-            html.body.table.appendChild(createHtmlTableSection(labelText,
-                                                               eventLocation));
-        }
-
-        var dateString = cal.getDateFormatter().formatItemInterval(event);
-        var labelText = stringBundle.GetStringFromName("imipHtml.when");
-        html.body.table.appendChild(createHtmlTableSection(labelText,
-                                                           dateString));
-
-        if (event.organizer &&
-            (event.organizer.commonName || event.organizer.id))
-        {
-            labelText = stringBundle.GetStringFromName("imipHtml.organizer");
-            // Trim any instances of "mailto:" for better readibility.
-            var orgname = event.organizer.commonName ||
-                          event.organizer.id.replace(/mailto:/ig, "");
-            html.body.table.appendChild(createHtmlTableSection(labelText, orgname));
-        }
-
-        var eventDescription = event.getProperty("DESCRIPTION");
-        if (eventDescription) {
-            // Remove the useless "Outlookism" squiggle.
-            var desc = eventDescription.replace("*~*~*~*~*~*~*~*~*~*", "");
-
-            labelText = stringBundle.GetStringFromName("imipHtml.description");
-            html.body.table.appendChild(createHtmlTableSection(labelText, desc, true));
-        }
-
-        var eventComment = event.getProperty("COMMENT");
-        if (eventComment) {
-            labelText = stringBundle.GetStringFromName("imipHtml.comment");
-            html.body.table.appendChild(createHtmlTableSection(labelText,eventComment, true));
-        }
-    }
-
-    return html;
-}
-
-function ltnMimeConverter() { }
-
 ltnMimeConverter.prototype = {
     classID: Components.ID("{c70acb08-464e-4e55-899d-b2c84c5409fa}"),
-    contractID: "@mozilla.org/lightning/mime-converter;1",
-    classDescription: "Lightning text/calendar handler",
+
+    QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISimpleMimeConverter]),
+
+    classInfo: XPCOMUtils.generateCI({
+        classID: Components.ID("{c70acb08-464e-4e55-899d-b2c84c5409fa}"),
+        contractID: "@mozilla.org/lightning/mime-converter;1",
+        classDescription: "Lightning text/calendar handler",
+        interfaces: [Components.interfaces.nsISimpleMimeConverter]
+    }),
+
+    /**
+     * Append the text to node, converting contained URIs to <a> links.
+     *
+     * @param text      The text to convert.
+     * @param node      The node to append the text to.
+     */
+    linkifyText: function linkifyText(text, node) {
+        let doc = node.ownerDocument;
+        let localText = text;
 
-    getInterfaces: function getInterfaces(count) {
-        const ifaces = [Components.interfaces.nsISimpleMimeConverter,
-                        Components.interfaces.nsIClassInfo,
-                        Components.interfaces.nsISupports];
-        count.value = ifaces.length;
-        return ifaces;
-    },
-    getHelperForLanguage: function getHelperForLanguage(language) {
-        return null;
-    },
-    implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
-    flags: 0,
+        // XXX This should be improved to also understand abbreviated urls, could be
+        // extended to only linkify urls that have an internal protocol handler, or
+        // have an external protocol handler that has an app assigned. The same
+        // could be done for mailto links which are not handled here either.
+
+        // XXX Ideally use mozITXTToHTMLConv here, but last time I tried it didn't work.
 
-    QueryInterface: function QI(aIID) {
-        return cal.doQueryInterface(this, ltnMimeConverter.prototype, aIID, null, this);
+        while (localText.length) {
+            let pos = localText.search(/(^|\s+)([a-zA-Z0-9]+):\/\/[^\s]+/);
+            if (pos == -1) {
+                node.appendChild(doc.createTextNode(localText));
+                break;
+            }
+            pos += localText.substr(pos).match(/^\s*/)[0].length;
+            let endPos = pos + localText.substr(pos).search(/([.!,<>(){}]+)?(\s+|$)/);
+            let url = localText.substr(pos, endPos - pos);
+
+            if (pos > 0) {
+                node.appendChild(doc.createTextNode(localText.substr(0, pos)));
+            }
+            let a = doc.createElement("a");
+            a.setAttribute("href", url);
+            a.textContent = url;
+
+            node.appendChild(a);
+
+            localText = localText.substr(endPos);
+        }
     },
 
-    mUri: null,
-    get uri() {
-        return this.mUri;
+    /**
+     * Synchronously read the given uri and return its xml document
+     *
+     * @param uri       The uri to read.
+     * @return          The response DOM Document.
+     */
+    readChromeUri: function readChromeUri(uri) {
+        let req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                            .createInstance(Components.interfaces.nsIXMLHttpRequest);
+
+        req.open('GET', uri, false);
+        req.overrideMimeType("text/xml");
+        req.send(null);
+        return req.responseXML;
     },
-    set uri(aUri) {
-        return (this.mUri = aUri);
+
+    /**
+     * Returns the html representation of the event as a DOM document.
+     *
+     * @param event     The calIItemBase to parse into html.
+     * @return          The DOM document with values filled in.
+     */
+    createHtml: function createHtml(event) {
+        // Creates HTML using the Node strings in the properties file
+        let doc = this.readChromeUri("chrome://lightning/content/lightning-invitation.xhtml");
+        let self = this;
+        function field(field, contentText, linkify) {
+            let descr = doc.getElementById("imipHtml-" + field + "-descr");
+            if (descr) {
+                let labelText = cal.calGetString("lightning", "imipHtml." + field, null, "lightning");
+                descr.textContent = labelText;
+            }
+
+            if (contentText) {
+                let content = doc.getElementById("imipHtml-" + field + "-content");
+                doc.getElementById("imipHtml-" + field + "-row").hidden = false;
+                if (linkify) {
+                    self.linkifyText(contentText, content);
+                } else {
+                    content.textContent = contentText;
+                }
+            }
+        }
+
+        // Simple fields
+        field("header", null);
+        field("summary", event.title);
+        field("location", event.getProperty("LOCATION"));
+        field("when", cal.getDateFormatter().formatItemInterval(event));
+        field("comment", event.getProperty("COMMENT"), true);
+
+        // ORGANIZER field
+        if (event.organizer && (event.organizer.commonName || event.organizer.id)) {
+            // Trim any instances of "mailto:" for better readibility.
+            let orgname = event.organizer.commonName ||
+                          event.organizer.id.replace(/mailto:/ig, "");
+            field("organizer", orgname);
+        }
+
+        // DESCRIPTION field
+        let eventDescription = (event.getProperty("DESCRIPTION") || "")
+                                    /* Remove the useless "Outlookism" squiggle. */
+                                    .replace("*~*~*~*~*~*~*~*~*~*", "");
+        field("description", eventDescription, true);
+
+        return doc;
     },
 
+
+    /* nsISimpleMimeConverter */
+
+    uri: null,
+
     convertToHTML: function lmcCTH(contentType, data) {
         let parser = Components.classes["@mozilla.org/calendar/ics-parser;1"]
                                .createInstance(Components.interfaces.calIIcsParser);
         parser.parseString(data);
         let event = null;
-        for each (var item in parser.getItems({})) {
+        for each (let item in parser.getItems({})) {
             if (cal.isEvent(item)) {
                 if (item.hasProperty("X-MOZ-FAKED-MASTER")) {
                     // if it's a faked master, take any overridden item to get a real occurrence:
                     let exc = item.recurrenceInfo.getExceptionFor(item.startDate);
                     cal.ASSERT(exc, "unexpected!");
                     if (exc) {
                         item = exc;
                     }
                 }
                 event = item;
                 break;
             }
         }
         if (!event) {
             return;
         }
-        let html = createHtml(event);
+
+        // Create the HTML string for display
+        let serializer = Components.classes["@mozilla.org/xmlextras/xmlserializer;1"]
+                                   .createInstance(Components.interfaces.nsIDOMSerializer);
+        let html = serializer.serializeToString(this.createHtml(event));
 
         try {
-            // this.mUri is the message URL that we are processing.
+            // this.uri is the message URL that we are processing.
             // We use it to get the nsMsgHeaderSink to store the calItipItem.
-            if (this.mUri) {
+            if (this.uri) {
                 let msgWindow = null;
                 try {
-                    let msgUrl = this.mUri.QueryInterface(Components.interfaces.nsIMsgMailNewsUrl);
+                    let msgUrl = this.uri.QueryInterface(Components.interfaces.nsIMsgMailNewsUrl);
                     // msgWindow is optional in some scenarios
                     // (e.g. gloda in action, throws NS_ERROR_INVALID_POINTER then)
                     msgWindow = msgUrl.msgWindow;
                 } catch (exc) {
                 }
                 if (msgWindow) {
                     let itipItem = Components.classes["@mozilla.org/calendar/itip-item;1"]
                                              .createInstance(Components.interfaces.calIItipItem);
                     itipItem.init(data);
 
                     let sinkProps = msgWindow.msgHeaderSink.properties;
                     sinkProps.setPropertyAsInterface("itipItem", itipItem);
-            
+
                     // Notify the observer that the itipItem is available
                     let observer = Components.classes["@mozilla.org/observer-service;1"]
                                              .getService(Components.interfaces.nsIObserverService);
                     observer.notifyObservers(null, "onItipItemCreation", 0);
                 }
             }
         } catch (e) {
-            Components.utils.reportError("[ltnMimeConverter] convertToHTML: " + e);
+            cal.ERROR("[ltnMimeConverter] convertToHTML: " + e);
         }
 
         return html;
     }
 };
 
 var NSGetFactory = XPCOMUtils.generateNSGetFactory([ltnMimeConverter]);
new file mode 100644
--- /dev/null
+++ b/calendar/lightning/content/lightning-invitation.xhtml
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
+    <link rel='stylesheet' type='text/css' href='chrome://messagebody/skin/imip.css'/>
+  </head>
+  <body>
+    <table>
+      <tr id="imipHtml-header-row">
+        <th colspan="2" class="header">
+          <p id="imipHtml-header-descr" class="header"/>
+        </th>
+      </tr>
+      <tr id="imipHtml-summary-row" hidden="true">
+        <td class="description"><p id="imipHtml-summary-descr"/></td>
+        <td class="content"><p id="imipHtml-summary-content"/></td>
+      </tr>
+      <tr id="imipHtml-location-row" hidden="true">
+        <td class="description"><p id="imipHtml-location-descr"/></td>
+        <td class="content"><p id="imipHtml-location-content"/></td>
+      </tr>
+      <tr id="imipHtml-when-row" hidden="true">
+        <td class="description"><p id="imipHtml-when-descr"/></td>
+        <td class="content"><p id="imipHtml-when-content"/></td>
+      </tr>
+      <tr id="imipHtml-organizer-row" hidden="true">
+        <td class="description"><p id="imipHtml-organizer-descr"/></td>
+        <td class="content"><p id="imipHtml-organizer-content"/></td>
+      </tr>
+      <tr id="imipHtml-description-row" hidden="true">
+        <td class="description"><p id="imipHtml-description-descr"/></td>
+        <td class="content"><p id="imipHtml-description-content"/></td>
+      </tr>
+      <tr id="imipHtml-comment-row" hidden="true">
+        <td class="description"><p id="imipHtml-comment-descr"/></td>
+        <td class="content"><p id="imipHtml-comment-content"/></td>
+      </tr>
+    </table>
+  </body>
+</html>
--- a/calendar/lightning/jar.mn
+++ b/calendar/lightning/jar.mn
@@ -25,16 +25,17 @@ lightning.jar:
 % override chrome://lightning/skin/accountCentral.css chrome://lightning/skin/suite-accountCentral.css application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
 % content lightning %content/lightning/
     content/lightning/imip-bar.js                          (content/imip-bar.js)
     content/lightning/imip-bar-overlay.xul                 (content/imip-bar-overlay.xul)
     content/lightning/lightning-calendar-creation.xul      (content/lightning-calendar-creation.xul)
     content/lightning/lightning-calendar-creation.js       (content/lightning-calendar-creation.js)
     content/lightning/lightning-calendar-properties.xul    (content/lightning-calendar-properties.xul)
     content/lightning/lightning-calendar-properties.js     (content/lightning-calendar-properties.js)
+    content/lightning/lightning-invitation.xhtml           (content/lightning-invitation.xhtml)
     content/lightning/lightning-menus.xul                  (content/lightning-menus.xul)
     content/lightning/lightning-migration.xul              (content/lightning-migration.xul)
     content/lightning/lightning-standalone.xul             (content/lightning-standalone.xul)
 *   content/lightning/lightning-toolbar.xul                (content/lightning-toolbar.xul)
     content/lightning/lightning-utils.js                   (content/lightning-utils.js)
     content/lightning/lightning-widgets.css                (content/lightning-widgets.css)
     content/lightning/lightning-widgets.xml                (content/lightning-widgets.xml)
     content/lightning/messenger-overlay-accountCentral.xul (content/messenger-overlay-accountCentral.xul)