inliner.js
[app.webkitpdf] / inliner.js
1 /**
2  *
3  * Based on...
4  * CSS Inline Transform v0.1
5  * http://tikku.com/css-inline-transformer-simplified
6  * 
7  * Copyright 2010-2012, Nirvana Tikku
8  * Dual licensed under the MIT or GPL Version 2 licenses.
9  * https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt
10  * 
11  * This tool leverages the jQuery library.
12  * 
13  * Compatibility only tested with FireFox 3.5+, Chrome 5+
14  * 
15  * @author Nirvana Tikku
16  * @dependent jQuery 1.4
17  * @date Wed Mar 31 14:58:04 2010 -0500
18  * @updated Sat Mar 10 16:21:20 2012 -0500
19  * 
20  */
21
22 (function(){
23     
24     //
25     // private methods
26     //
27     /**
28      * @param stylesArray - the array of string 
29      *                  "{name}:{value};" pairs that are to be broken down
30      *
31      */
32     function createCSSRuleObject (stylesArray) {
33         var cssObj = {};
34         for(_s in stylesArray){
35                 var S = stylesArray[_s].split(":");
36                 if(S[0].trim()==""||S[1].trim()=="")continue;
37                 cssObj[S[0].trim()] = S[1].trim();
38         }
39         return cssObj;
40     }
41
42     /**
43      * @param $out - the tmp html content
44      * 
45      */
46     function interpritAppendedStylesheet ($out) { 
47         var stylesheet = $out[0].styleSheets[0]; // first stylesheet
48         for(r in stylesheet.cssRules){
49                 try{
50                         var rule = stylesheet.cssRules[r]; 
51                         if(!isNaN(rule))break; // make sure the rule exists
52                         var $destObj = $out.find(rule.selectorText);
53                         var obj = rule.cssText.replace(rule.selectorText, '');
54                         obj = obj.replace('{','').replace('}',''); // clean up the { and }'s
55                         var styles = obj.split(";"); // separate each 
56                         $destObj.css(createCSSRuleObject(styles)); // do the inline styling
57                 } catch (e) { }
58         }
59     };
60     
61     
62         function isPatternRelevant (newHTML, pattern, relevantPatterns) {
63             if( newHTML.indexOf(pattern) > -1 )
64                 relevantPatterns.push(new RegExp(pattern,"i"));
65         };
66
67     /**
68      * The main method - inflinify
69      *  this utilizes two text areas and a div for final output -  
70      *          (1) css input textarea for the css to apply
71      *          (2) html content for the css to apply TO
72      */
73     function inlinify (input) {
74         var tmpWindow = window.open("", "tmpHtml", "width=0,height=0");
75         window.blur(); // re focus on main window
76         var tmpDoc = tmpWindow.document; // create a window that we can use 
77         var $tmpDoc = jQuery(tmpDoc); // jquerify the temp window 
78
79         tmpDoc.write(input); // write the HTML out to a new window doc
80         interpritAppendedStylesheet($tmpDoc); // apply styles to the document just created
81         $tmpDoc.find("style").remove(); // sanitize all style tags present prior to the transformation
82         
83         var newHTML = $tmpDoc.find("html").html();
84         tmpWindow.close();
85         
86         var relevantPatterns = [];
87         isPatternRelevant(newHTML, "href=\"", relevantPatterns);
88         isPatternRelevant(newHTML, "src=\"", relevantPatterns);
89         return sanitize( newHTML, relevantPatterns );
90     };
91     
92     function sanitize(html, patterns){
93         var ret = html;
94         for(var i=0; i<patterns.length; i++){
95             ret = san(ret, patterns[i])
96         }  
97         return ret;
98     };
99
100     /**
101      * This method will take HTML and a PATTERN and essentially
102      * sanitize the following chars within the HTML with that 
103      * pattern through a filter: 
104      *      Currently this only applies to &amp;' -> &
105      */
106     function san(html, pattern){
107     
108         var ret = "";
109         var remainingString;
110         var hrefIndex;
111         for(var i=0; i<html.length; i++){
112                 remainingString = html.substring(i);
113                 hrefIndex = remainingString.search(pattern);
114                 if( hrefIndex === 0 ){
115                     // actually sanitize the pattern, i.e. href="[sanitize-candidate]"
116                     // must be encapsulated within quotes, "
117                (function(){
118                    // get the start of what we will sanitize
119                    var startIndex = remainingString.indexOf("\"");
120                    // and the end 
121                    var endIndex = remainingString.indexOf("\"",startIndex+1);
122                    // get the data to sanitize
123                    var newHREF = html.substring(i+startIndex+1, i+endIndex+1);
124                    // here we actually perform the replacement
125                    newHREF = newHREF.replace(/&amp;/g, '&');
126                    // add the pattern + the new data + a closing quote
127                    var regExpStartLen = "/".length;
128                    var regExpFlagsLen = "/i".length;
129                    ret += String(pattern).substring( regExpStartLen, String(pattern).length - regExpFlagsLen)
130                         + newHREF;
131                    i += endIndex;
132                })();
133                continue;
134                 } else { 
135                     // if we have another href, copy everything until that href index
136                     if( hrefIndex > 0 ) {
137                         ret += html.substring(i, hrefIndex);
138                         i = hrefIndex-1;
139                     } else { 
140                         // otherwise just add the remaining chars and stop trying to sanitize
141                         ret += html.substring(i);
142                         break;
143                     }
144                 }
145         }
146         return ret;
147         
148     };
149     
150     //
151     // public methods
152     //
153     doInline = function(input) {
154         return inlinify(input);
155     }
156     
157 })();