| 9 | | function adjustCssPaths(cssUrl, cssText, imports){ |
| 10 | | // summary |
| 11 | | // say cssText comes from dojoroot/src/widget/templates/Foobar.css |
| 12 | | // it has a css selector: .dojoFoo { background-image: url(images/bar.png);} |
| 13 | | // then uri should point to dojoroot/src/widget/templates/ |
| | 8 | |
| | 9 | // css at-rules must be set before any css declarations according to CSS spec |
| | 10 | // match: |
| | 11 | // @import 'http://dojotoolkit.org/dojo.css'; |
| | 12 | // @import 'you/never/thought/' print; |
| | 13 | // @import url("it/would/work") tv, screen; |
| | 14 | // @import url(/did/you/now.css); |
| | 15 | // but not: |
| | 16 | // @namespace dojo "http://dojotoolkit.org/dojo.css"; /* namespace URL should always be a absolute URI */ |
| | 17 | // @charset 'utf-8'; |
| | 18 | // @media print{ #menuRoot {display:none;} } |
| | 19 | |
| | 20 | |
| | 21 | // we adjust all paths that dont start on '/' or contains ':' |
| | 22 | //(?![a-z]+:|\/) |
| | 23 | |
| | 24 | if(dojo.isIE){ |
| | 25 | var alphaImageLoader = /(AlphaImageLoader\([^)]*?src=(['"]))(?![a-z]+:|\/)([^\r\n;}]+?)(\2[^)]*\)\s*[;}]?)/g; |
| | 26 | } |
| | 27 | |
| | 28 | var cssPaths = /(?:(?:@import\s*(['"])(?![a-z]+:|\/)([^\r\n;{]+?)\1)|url\(\s*(['"]?)(?![a-z]+:|\/)([^\r\n;]+?)\3\s*\))([a-z, \s]*[;}]?)/g; |
| | 29 | |
| | 30 | function adjustCssPaths(cssUrl, cssText){ |
| | 31 | // summary: |
| | 32 | // adjusts relative paths in cssText to be relative to cssUrl |
| | 33 | // a path is considered relative if it doesn't start with '/' and not contains ':' |
| | 34 | // description: |
| | 35 | // Say we fetch a HTML page from level1/page.html |
| | 36 | // It has some inline CSS: |
| | 37 | // @import "css/page.css" tv, screen; |
| | 38 | // ... |
| | 39 | // background-image: url(images/aplhaimage.png); |
| | 40 | // |
| | 41 | // as we fetched this HTML and therefore this CSS |
| | 42 | // from level1/page.html, these paths needs to be adjusted to: |
| | 43 | // @import 'level1/css/page.css' tv, screen; |
| | 44 | // ... |
| | 45 | // background-image: url(level1/images/alphaimage.png); |
| | 46 | // |
| | 47 | // In IE it will also adjust relative paths in AlphaImageLoader() |
| | 48 | // filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/alphaimage.png'); |
| | 49 | // will be adjusted to: |
| | 50 | // filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='level1/images/alphaimage.png'); |
| | 51 | // |
| | 52 | // Please note that any relative paths in AlphaImageLoader in external css files wont work, as |
| | 53 | // the paths in AlphaImageLoader is MUST be declared relative to the HTML page, |
| | 54 | // not relative to the CSS file that declares it |
| | 55 | |
| 16 | | var match, str = "", url = "", regex, pad = ""; |
| 17 | | var urlChrs = "[\\t\\s\\w\\(\\)\\/\\.\\\\'\"-:#=&?~]+"; |
| 18 | | |
| 19 | | if(imports){ |
| 20 | | pad = " "; |
| 21 | | regex = new RegExp('(@import)(\\s+'+urlChrs+')\\s*(;)'); // TODO support media rules |
| 22 | | }else{ |
| 23 | | regex = new RegExp('(url\\()\\s*('+urlChrs+')\\s*(\\))'); |
| 24 | | } |
| 25 | | var regexProtocol = /https?:\/\//; |
| 26 | | var regexTrim = new RegExp("^[\\s]*(['\"]?)("+urlChrs+")\\1[\\s]*?$"); |
| 27 | | |
| 28 | | while(match = regex.exec(cssText)){ |
| 29 | | url = match[2].replace(regexTrim, "$2"); |
| 30 | | if(!regexProtocol.exec(url)){ |
| 31 | | url = (new dojo._Url(cssUrl, url).toString()); |
| 32 | | } |
| 33 | | str += cssText.substring(0, match.index) + match[1] + pad + "'" + url + "'" + match[3]; |
| 34 | | cssText = cssText.substr(match.index + match[0].length); |
| 35 | | } |
| 36 | | |
| 37 | | str = str + cssText; |
| 38 | | |
| 39 | | if(!imports){ |
| 40 | | str = arguments.callee(cssUrl, str, true); |
| 41 | | } |
| 42 | | return str; // String |
| 43 | | } |
| | 58 | // support the ImageAlphaFilter if it exists, most people use it in IE 6 for transparent PNGs |
| | 59 | // We are NOT going to kill it in IE 7 just because the PNGs work there. Somebody might have |
| | 60 | // other uses for it. |
| | 61 | // If user want to disable css filter in IE6 he/she should |
| | 62 | // unset filter in a declaration that just IE 6 doesn't understands |
| | 63 | // like * > .myselector { filter:none; } |
| | 64 | if(alphaImageLoader){ |
| | 65 | cssText = cssText.replace(alphaImageLoader, function(ignore, pre, delim, url, post){ |
| | 66 | return pre + (new dojo._Url(cssUrl, './'+url).toString()) + post; |
| | 67 | }); |
| | 68 | } |
| | 69 | |
| | 70 | return cssText.replace(cssPaths, function(ignore, delimStr, strUrl, delimUrl, urlUrl, media){ |
| | 71 | if(strUrl){ |
| | 72 | return '@import "' + (new dojo._Url(cssUrl, './'+strUrl).toString()) + '"' + media; |
| | 73 | }else{ |
| | 74 | return 'url(' + (new dojo._Url(cssUrl, './'+urlUrl).toString()) + ')' + media; |
| | 75 | } |
| | 76 | }); |
| | 77 | } |
| | 78 | |
| | 79 | // attributepaths one tag can have multiple paths, example: |
| | 80 | // <input src="..." style="url(..)"/> or <a style="url(..)" href=".."> |
| | 81 | // <img style='filter:progid...AlphaImageLoader(src="noticeTheSrcHereRunsThroughHtmlSrc")' src="img"> |
| | 82 | var htmlAttrPaths = /(<[a-z][a-z0-9]*\s[^>]*)(?:(href|src)=(['"]?)([^>]*?)\3|style=(['"]?)([^>]*?)\5)([^>]*>)/gi; |
| 46 | | // TODO: clean up this mess! |
| 47 | | // use dojox string builder to achive more speed on slow string merging env. |
| 48 | | |
| 49 | | // attributepaths one tag can have multiple paths example: |
| 50 | | // <input src="..." style="url(..)"/> or <a style="url(..)" href=".."> |
| 51 | | // strip out the tag and run fix on that. |
| 52 | | // this guarantees that we won't run replace on another tag's attribute + it was easier do |
| 53 | | var regexFindTag = /<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i; |
| 54 | | // FIXME: get the url regex part from dojo.regex instead |
| 55 | | var regexFindAttr = /\s(src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i; |
| 56 | | // these are the supported protocols, all other is considered relative |
| 57 | | var regexProtocols = /^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/; |
| 60 | | var str = "", tag, tagFix = '', attr, path, origPath; |
| 61 | | |
| 62 | | while(tag = regexFindTag.exec(cont)){ |
| 63 | | str += cont.substring(0, tag.index); |
| 64 | | cont = cont.substring((tag.index + tag[0].length), cont.length); |
| 65 | | tag = tag[0]; |
| 66 | | |
| 67 | | // loop through attributes |
| 68 | | tagFix = ''; |
| 69 | | while(attr = regexFindAttr.exec(tag)){ |
| 70 | | path = ""; origPath = attr[3]; |
| 71 | | switch(attr[1].toLowerCase()){ |
| 72 | | case "src":// falltrough |
| 73 | | case "href": |
| 74 | | if(regexProtocols.exec(origPath)){ |
| 75 | | path = origPath; |
| 76 | | } else { |
| 77 | | path = (new dojo._Url(url, origPath).toString()); |
| 78 | | } |
| 79 | | break; |
| 80 | | case "style":// style |
| 81 | | path = adjustCssPaths(url, origPath); |
| 82 | | attr[2] = '"'; |
| 83 | | break; |
| 84 | | default: |
| 85 | | path = origPath; |
| 86 | | } |
| 87 | | fix = " " + attr[1] + '=' + attr[2] + path + attr[2]; |
| 88 | | // slices up tag before next attribute check |
| 89 | | tagFix += tag.substring(0, attr.index) + fix; |
| 90 | | tag = tag.substring((attr.index + attr[0].length), tag.length); |
| 91 | | } |
| 92 | | str += tagFix + tag; |
| 93 | | //console.debug(tagFix + tag); |
| 94 | | } |
| 95 | | return str+cont; |
| | 87 | return cont.replace(htmlAttrPaths, |
| | 88 | function(tag, start, name, delim, relUrl, delim2, cssText, end){ |
| | 89 | return start + (name ? |
| | 90 | (name + '=' + delim + (new dojo._Url(url, relUrl).toString()) + delim) |
| | 91 | : ('style=' + delim2 + adjustCssPaths(url, cssText) + delim2) |
| | 92 | ) + end; |
| | 93 | } |
| | 94 | ); |
| 115 | | var regex = /(?:<(style)[^>]*>([\s\S]*?)<\/style>|<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>)/i; |
| 116 | | var match, attr; |
| 117 | | while(match = regex.exec(cont)){ |
| 118 | | if(match[1] && match[1].toLowerCase() == "style"){ |
| 119 | | styles.push(adjustCssPaths(cssUrl, match[2])); |
| 120 | | }else if(attr = match[3].match(/href=(['"]?)([^'">]*)\1/i)){ |
| 121 | | styles.push("@import '" + attr[2] + "';"); |
| 122 | | } |
| 123 | | cont = cont.substring(0, match.index) + cont.substr(match.index + match[0].length); |
| 124 | | }; |
| 125 | | return cont; |
| | 106 | // also return any attributes from this tag (might be a media attribute) |
| | 107 | // if cssUrl is set it will adjust paths accordingly |
| | 108 | styles.attributes = []; |
| | 109 | |
| | 110 | return cont.replace(/(?:<style([^>]*)>([\s\S]*?)<\/style>|<link\s+(?=[^>]*rel=['"]?stylesheet)([^>]*?href=(['"])([^>]*?)\4[^>\/]*)\/?>)/gi, |
| | 111 | function(ignore, styleAttr, cssText, linkAttr, delim, href){ |
| | 112 | // trim attribute |
| | 113 | var i, attr = (styleAttr||linkAttr||"").replace(/^\s*([\s\S]*?)\s*$/i, "$1"); |
| | 114 | if(cssText){ |
| | 115 | i = styles.push(cssUrl ? adjustCssPaths(cssUrl, cssText) : cssText); |
| | 116 | }else{ |
| | 117 | i = styles.push('@import "' + href + '";') |
| | 118 | attr = attr.replace(/\s*(?:rel|href)=(['"])?[^\s]*\1\s*/gi, ""); // remove rel=... and href=... |
| | 119 | } |
| | 120 | if(attr){ |
| | 121 | attr = attr.split(/\s+/);// split on both "\n", "\t", " " etc |
| | 122 | var atObj = {}, tmp; |
| | 123 | for(var j = 0, e = attr.length; j < e; j++){ |
| | 124 | tmp = attr[j].split('=')// split name='value' |
| | 125 | atObj[tmp[0]] = tmp[1].replace(/^\s*['"]?([\s\S]*?)['"]?\s*$/, "$1"); // trim and remove '' |
| | 126 | } |
| | 127 | styles.attributes[i - 1] = atObj; |
| | 128 | } |
| | 129 | return ""; // squelsh the <style> or <link> |
| | 130 | } |
| | 131 | ); |
| 135 | | var regex = /<script([^>]*)>([\s\S]*?)<\/script>/i; |
| 136 | | var regexSrc = /src=(['"])([^'"]*)\1/, regexExcl = /type=['"]dojo\/method/i; |
| 137 | | var tag, match, attr, src, s = ""; |
| 138 | | while(tag = cont.match(regex)){ |
| 139 | | s = cont.substring(0, tag.index); |
| 140 | | cont = cont.substr(tag.index + tag[0].length); |
| 141 | | |
| 142 | | if(byRef.downloadRemote && tag[1].length |
| 143 | | && (src = tag[1].match(regexSrc)) |
| 144 | | ){ |
| | 141 | |
| | 142 | function download(src){ |
| | 143 | if(byRef.downloadRemote){ |
| | 144 | // console.debug('downloading',src); |
| 153 | | }else if(!regexExcl.test(tag[1])){ |
| 154 | | byRef.code += tag[2] + ";"; |
| 155 | | } |
| 156 | | } |
| 157 | | |
| 158 | | return s + cont; // String |
| | 153 | } |
| | 154 | } |
| | 155 | |
| | 156 | // match <script>, <script type="text/..., but not <script type="dojo(/method)... |
| | 157 | return cont.replace(/<script\s*(?![^>]*type=['"]?dojo)(?:[^>]*?src=(['"]?)([^>]*?)\1[^>]*)?>([\s\S]*?)<\/script>/gi, |
| | 158 | function(ignore, delim, src, code){ |
| | 159 | if(src){ |
| | 160 | download(src); |
| | 161 | }else{ |
| | 162 | byRef.code += code; |
| | 163 | } |
| | 164 | return ""; |
| | 165 | } |
| | 166 | ); |
| 198 | | // Supports inline scrips, relative path adjustments, |
| 199 | | // Java function content generation |
| | 206 | // Supports infile scrips and external ones declared by <script src='' |
| | 207 | // relative path adjustments (content fetched from a different folder) |
| | 208 | // <style> and <link rel='stylesheet' href='..'> tags, |
| | 209 | // css paths inside cssText is adjusted (if you set adjustPaths = true) |
| | 210 | // |
| | 211 | // NOTE that dojo.require in script in the fetched file isn't recommended |
| | 212 | // Many widgets need to be required at page load to work properly |
| 444 | | dojo.forEach(styles, function(cssText){ |
| 445 | | var st = doc.createElement('style'); |
| 446 | | st.setAttribute("type", "text/css"); |
| | 456 | for(var i = 0, e = styles.length; i < e; i++){ |
| | 457 | cssText = styles[i]; att = styles.attributes[i]; |
| | 458 | st = doc.createElement('style'); |
| | 459 | st.setAttribute("type", "text/css"); // this is required in CSS spec! |
| | 460 | |
| | 461 | for(var x in att){ |
| | 462 | st.setAttribute(x, att[x]) |
| | 463 | } |
| | 464 | |