New file |
0,0 → 1,478 |
if(!dojo._hasResource["dojox.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dojox.layout.ContentPane"] = true; |
dojo.provide("dojox.layout.ContentPane"); |
|
dojo.require("dijit.layout.ContentPane"); |
|
(function(){ // private scope, sort of a namespace |
|
// TODO: should these methods be moved to dojox.html.cssPathAdjust or something? |
|
// css at-rules must be set before any css declarations according to CSS spec |
// match: |
// @import 'http://dojotoolkit.org/dojo.css'; |
// @import 'you/never/thought/' print; |
// @import url("it/would/work") tv, screen; |
// @import url(/did/you/now.css); |
// but not: |
// @namespace dojo "http://dojotoolkit.org/dojo.css"; /* namespace URL should always be a absolute URI */ |
// @charset 'utf-8'; |
// @media print{ #menuRoot {display:none;} } |
|
|
// we adjust all paths that dont start on '/' or contains ':' |
//(?![a-z]+:|\/) |
|
if(dojo.isIE){ |
var alphaImageLoader = /(AlphaImageLoader\([^)]*?src=(['"]))(?![a-z]+:|\/)([^\r\n;}]+?)(\2[^)]*\)\s*[;}]?)/g; |
} |
|
var cssPaths = /(?:(?:@import\s*(['"])(?![a-z]+:|\/)([^\r\n;{]+?)\1)|url\(\s*(['"]?)(?![a-z]+:|\/)([^\r\n;]+?)\3\s*\))([a-z, \s]*[;}]?)/g; |
|
function adjustCssPaths(cssUrl, cssText){ |
// summary: |
// adjusts relative paths in cssText to be relative to cssUrl |
// a path is considered relative if it doesn't start with '/' and not contains ':' |
// description: |
// Say we fetch a HTML page from level1/page.html |
// It has some inline CSS: |
// @import "css/page.css" tv, screen; |
// ... |
// background-image: url(images/aplhaimage.png); |
// |
// as we fetched this HTML and therefore this CSS |
// from level1/page.html, these paths needs to be adjusted to: |
// @import 'level1/css/page.css' tv, screen; |
// ... |
// background-image: url(level1/images/alphaimage.png); |
// |
// In IE it will also adjust relative paths in AlphaImageLoader() |
// filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/alphaimage.png'); |
// will be adjusted to: |
// filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='level1/images/alphaimage.png'); |
// |
// Please note that any relative paths in AlphaImageLoader in external css files wont work, as |
// the paths in AlphaImageLoader is MUST be declared relative to the HTML page, |
// not relative to the CSS file that declares it |
|
if(!cssText || !cssUrl){ return; } |
|
// support the ImageAlphaFilter if it exists, most people use it in IE 6 for transparent PNGs |
// We are NOT going to kill it in IE 7 just because the PNGs work there. Somebody might have |
// other uses for it. |
// If user want to disable css filter in IE6 he/she should |
// unset filter in a declaration that just IE 6 doesn't understands |
// like * > .myselector { filter:none; } |
if(alphaImageLoader){ |
cssText = cssText.replace(alphaImageLoader, function(ignore, pre, delim, url, post){ |
return pre + (new dojo._Url(cssUrl, './'+url).toString()) + post; |
}); |
} |
|
return cssText.replace(cssPaths, function(ignore, delimStr, strUrl, delimUrl, urlUrl, media){ |
if(strUrl){ |
return '@import "' + (new dojo._Url(cssUrl, './'+strUrl).toString()) + '"' + media; |
}else{ |
return 'url(' + (new dojo._Url(cssUrl, './'+urlUrl).toString()) + ')' + media; |
} |
}); |
} |
|
// attributepaths one tag can have multiple paths, example: |
// <input src="..." style="url(..)"/> or <a style="url(..)" href=".."> |
// <img style='filter:progid...AlphaImageLoader(src="noticeTheSrcHereRunsThroughHtmlSrc")' src="img"> |
var htmlAttrPaths = /(<[a-z][a-z0-9]*\s[^>]*)(?:(href|src)=(['"]?)([^>]*?)\3|style=(['"]?)([^>]*?)\5)([^>]*>)/gi; |
|
function adjustHtmlPaths(htmlUrl, cont){ |
var url = htmlUrl || "./"; |
|
return cont.replace(htmlAttrPaths, |
function(tag, start, name, delim, relUrl, delim2, cssText, end){ |
return start + (name ? |
(name + '=' + delim + (new dojo._Url(url, relUrl).toString()) + delim) |
: ('style=' + delim2 + adjustCssPaths(url, cssText) + delim2) |
) + end; |
} |
); |
} |
|
function secureForInnerHtml(cont){ |
/********* remove <!DOCTYPE.. and <title>..</title> tag **********/ |
// khtml is picky about dom faults, you can't attach a <style> or <title> node as child of body |
// must go into head, so we need to cut out those tags |
return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); |
} |
|
function snarfStyles(/*String*/cssUrl, /*String*/cont, /*Array*/styles){ |
/**************** cut out all <style> and <link rel="stylesheet" href=".."> **************/ |
// also return any attributes from this tag (might be a media attribute) |
// if cssUrl is set it will adjust paths accordingly |
styles.attributes = []; |
|
return cont.replace(/(?:<style([^>]*)>([\s\S]*?)<\/style>|<link\s+(?=[^>]*rel=['"]?stylesheet)([^>]*?href=(['"])([^>]*?)\4[^>\/]*)\/?>)/gi, |
function(ignore, styleAttr, cssText, linkAttr, delim, href){ |
// trim attribute |
var i, attr = (styleAttr||linkAttr||"").replace(/^\s*([\s\S]*?)\s*$/i, "$1"); |
if(cssText){ |
i = styles.push(cssUrl ? adjustCssPaths(cssUrl, cssText) : cssText); |
}else{ |
i = styles.push('@import "' + href + '";') |
attr = attr.replace(/\s*(?:rel|href)=(['"])?[^\s]*\1\s*/gi, ""); // remove rel=... and href=... |
} |
if(attr){ |
attr = attr.split(/\s+/);// split on both "\n", "\t", " " etc |
var atObj = {}, tmp; |
for(var j = 0, e = attr.length; j < e; j++){ |
tmp = attr[j].split('=')// split name='value' |
atObj[tmp[0]] = tmp[1].replace(/^\s*['"]?([\s\S]*?)['"]?\s*$/, "$1"); // trim and remove '' |
} |
styles.attributes[i - 1] = atObj; |
} |
return ""; // squelsh the <style> or <link> |
} |
); |
} |
|
function snarfScripts(cont, byRef){ |
// summary |
// strips out script tags from cont |
// invoke with |
// byRef = {errBack:function(){/*add your download error code here*/, downloadRemote: true(default false)}} |
// byRef will have {code: 'jscode'} when this scope leaves |
byRef.code = ""; |
|
function download(src){ |
if(byRef.downloadRemote){ |
// console.debug('downloading',src); |
dojo.xhrGet({ |
url: src, |
sync: true, |
load: function(code){ |
byRef.code += code+";"; |
}, |
error: byRef.errBack |
}); |
} |
} |
|
// match <script>, <script type="text/..., but not <script type="dojo(/method)... |
return cont.replace(/<script\s*(?![^>]*type=['"]?dojo)(?:[^>]*?(?:src=(['"]?)([^>]*?)\1[^>]*)?)*>([\s\S]*?)<\/script>/gi, |
function(ignore, delim, src, code){ |
if(src){ |
download(src); |
}else{ |
byRef.code += code; |
} |
return ""; |
} |
); |
} |
|
function evalInGlobal(code, appendNode){ |
// we do our own eval here as dojo.eval doesn't eval in global crossbrowser |
// This work X browser but but it relies on a DOM |
// plus it doesn't return anything, thats unrelevant here but not for dojo core |
appendNode = appendNode || dojo.doc.body; |
var n = appendNode.ownerDocument.createElement('script'); |
n.type = "text/javascript"; |
appendNode.appendChild(n); |
n.text = code; // DOM 1 says this should work |
} |
|
/*===== |
dojox.layout.ContentPane.DeferredHandle = { |
// cancel: Function |
cancel: function(){ |
// summary: cancel a in flight download |
}, |
|
addOnLoad: function(func){ |
// summary: add a callback to the onLoad chain |
// func: Function |
}, |
|
addOnUnload: function(func){ |
// summary: add a callback to the onUnload chain |
// func: Function |
} |
} |
=====*/ |
|
|
dojo.declare("dojox.layout.ContentPane", dijit.layout.ContentPane, { |
// summary: |
// An extended version of dijit.layout.ContentPane |
// Supports infile scrips and external ones declared by <script src='' |
// relative path adjustments (content fetched from a different folder) |
// <style> and <link rel='stylesheet' href='..'> tags, |
// css paths inside cssText is adjusted (if you set adjustPaths = true) |
// |
// NOTE that dojo.require in script in the fetched file isn't recommended |
// Many widgets need to be required at page load to work properly |
|
// adjustPaths: Boolean |
// Adjust relative paths in html string content to point to this page |
// Only usefull if you grab content from a another folder then the current one |
adjustPaths: false, |
|
// cleanContent: Boolean |
// summary: |
// cleans content to make it less likly to generate DOM/JS errors. |
// description: |
// usefull if you send contentpane a complete page, instead of a html fragment |
// scans for |
// style nodes, inserts in Document head |
// title Node, remove |
// DOCTYPE tag, remove |
// <!-- *JS code here* --> |
// <![CDATA[ *JS code here* ]]> |
cleanContent: false, |
|
// renderStyles: Boolean |
// trigger/load styles in the content |
renderStyles: false, |
|
// executeScripts: Boolean |
// Execute (eval) scripts that is found in the content |
executeScripts: true, |
|
// scriptHasHooks: Boolean |
// replace keyword '_container_' in scripts with 'dijit.byId(this.id)' |
// NOTE this name might change in the near future |
scriptHasHooks: false, |
|
/*====== |
// ioMethod: dojo.xhrGet|dojo.xhrPost |
// reference to the method that should grab the content |
ioMethod: dojo.xhrGet, |
|
// ioArgs: Object |
// makes it possible to add custom args to xhrGet, like ioArgs.headers['X-myHeader'] = 'true' |
ioArgs: {}, |
|
// onLoadDeferred: dojo.Deferred |
// callbackchain will start when onLoad occurs |
onLoadDeferred: new dojo.Deferred(), |
|
// onUnloadDeferred: dojo.Deferred |
// callbackchain will start when onUnload occurs |
onUnloadDeferred: new dojo.Deferred(), |
|
setHref: function(url){ |
// summary: replace current content with url's content |
return ;// dojox.layout.ContentPane.DeferredHandle |
}, |
|
refresh: function(){ |
summary: force a re-download of content |
return ;// dojox.layout.ContentPane.DeferredHandle |
}, |
|
======*/ |
|
constructor: function(){ |
// init per instance properties, initializer doesn't work here because how things is hooked up in dijit._Widget |
this.ioArgs = {}; |
this.ioMethod = dojo.xhrGet; |
this.onLoadDeferred = new dojo.Deferred(); |
this.onUnloadDeferred = new dojo.Deferred(); |
}, |
|
postCreate: function(){ |
// override to support loadDeferred |
this._setUpDeferreds(); |
|
dijit.layout.ContentPane.prototype.postCreate.apply(this, arguments); |
}, |
|
onExecError: function(e){ |
// summary |
// event callback, called on script error or on java handler error |
// overide and return your own html string if you want a some text |
// displayed within the ContentPane |
}, |
|
setContent: function(data){ |
// summary: set data as new content, sort of like innerHTML |
// data: String|DomNode|NodeList|dojo.NodeList |
if(!this._isDownloaded){ |
var defObj = this._setUpDeferreds(); |
} |
|
dijit.layout.ContentPane.prototype.setContent.apply(this, arguments); |
return defObj; // dojox.layout.ContentPane.DeferredHandle |
}, |
|
cancel: function(){ |
// summary: cancels a inflight download |
if(this._xhrDfd && this._xhrDfd.fired == -1){ |
// we are still in flight, which means we should reset our DeferredHandle |
// otherwise we will trigger onUnLoad chain of the canceled content, |
// the canceled content have never gotten onLoad so it shouldn't get onUnload |
this.onUnloadDeferred = null; |
} |
dijit.layout.ContentPane.prototype.cancel.apply(this, arguments); |
}, |
|
_setUpDeferreds: function(){ |
var _t = this, cancel = function(){ _t.cancel(); } |
var onLoad = (_t.onLoadDeferred = new dojo.Deferred()); |
var onUnload = (_t._nextUnloadDeferred = new dojo.Deferred()); |
return { |
cancel: cancel, |
addOnLoad: function(func){onLoad.addCallback(func);}, |
addOnUnload: function(func){onUnload.addCallback(func);} |
}; |
}, |
|
_onLoadHandler: function(){ |
dijit.layout.ContentPane.prototype._onLoadHandler.apply(this, arguments); |
if(this.onLoadDeferred){ |
this.onLoadDeferred.callback(true); |
} |
}, |
|
_onUnloadHandler: function(){ |
this.isLoaded = false; |
this.cancel();// need to cancel so we don't get any inflight suprises |
if(this.onUnloadDeferred){ |
this.onUnloadDeferred.callback(true); |
} |
|
dijit.layout.ContentPane.prototype._onUnloadHandler.apply(this, arguments); |
|
if(this._nextUnloadDeferred){ |
this.onUnloadDeferred = this._nextUnloadDeferred; |
} |
}, |
|
_onError: function(type, err){ |
dijit.layout.ContentPane.prototype._onError.apply(this, arguments); |
if(this.onLoadDeferred){ |
this.onLoadDeferred.errback(err); |
} |
}, |
|
_prepareLoad: function(forceLoad){ |
// sets up for a xhrLoad, load is deferred until widget is showing |
var defObj = this._setUpDeferreds(); |
|
dijit.layout.ContentPane.prototype._prepareLoad.apply(this, arguments); |
|
return defObj; |
}, |
|
_setContent: function(cont){ |
// override dijit.layout.ContentPane._setContent, to enable path adjustments |
var styles = [];// init vars |
if(dojo.isString(cont)){ |
if(this.adjustPaths && this.href){ |
cont = adjustHtmlPaths(this.href, cont); |
} |
if(this.cleanContent){ |
cont = secureForInnerHtml(cont); |
} |
if(this.renderStyles || this.cleanContent){ |
cont = snarfStyles(this.href, cont, styles); |
} |
|
// because of a bug in IE, script tags that is first in html hierarchy doesnt make it into the DOM |
// when content is innerHTML'ed, so we can't use dojo.query to retrieve scripts from DOM |
if(this.executeScripts){ |
var _t = this, code, byRef = { |
downloadRemote: true, |
errBack:function(e){ |
_t._onError.call(_t, 'Exec', 'Error downloading remote script in "'+_t.id+'"', e); |
} |
}; |
cont = snarfScripts(cont, byRef); |
code = byRef.code; |
} |
|
// rationale for this block: |
// if containerNode/domNode is a table derivate tag, some browsers dont allow innerHTML on those |
var node = (this.containerNode || this.domNode), pre = post = '', walk = 0; |
switch(name = node.nodeName.toLowerCase()){ |
case 'tr': |
pre = '<tr>'; post = '</tr>'; |
walk += 1;//fallthrough |
case 'tbody': case 'thead':// children of THEAD is of same type as TBODY |
pre = '<tbody>' + pre; post += '</tbody>'; |
walk += 1;// falltrough |
case 'table': |
pre = '<table>' + pre; post += '</table>'; |
walk += 1; |
break; |
} |
if(walk){ |
var n = node.ownerDocument.createElement('div'); |
n.innerHTML = pre + cont + post; |
do{ |
n = n.firstChild; |
}while(--walk); |
cont = n.childNodes; |
} |
} |
|
// render the content |
dijit.layout.ContentPane.prototype._setContent.call(this, cont); |
|
// clear old stylenodes from the DOM |
if(this._styleNodes && this._styleNodes.length){ |
while(this._styleNodes.length){ |
dojo._destroyElement(this._styleNodes.pop()); |
} |
} |
// render new style nodes |
if(this.renderStyles && styles && styles.length){ |
this._renderStyles(styles); |
} |
|
if(this.executeScripts && code){ |
if(this.cleanContent){ |
// clean JS from html comments and other crap that browser |
// parser takes care of in a normal page load |
code = code.replace(/(<!--|(?:\/\/)?-->|<!\[CDATA\[|\]\]>)/g, ''); |
} |
if(this.scriptHasHooks){ |
// replace _container_ with dijit.byId(this.id) |
code = code.replace(/_container_(?!\s*=[^=])/g, "dijit.byId('"+this.id+"')"); |
} |
try{ |
evalInGlobal(code, (this.containerNode || this.domNode)); |
}catch(e){ |
this._onError('Exec', 'Error eval script in '+this.id+', '+e.message, e); |
} |
} |
}, |
|
_renderStyles: function(styles){ |
// insert css from content into document head |
this._styleNodes = []; |
var st, att, cssText, doc = this.domNode.ownerDocument; |
var head = doc.getElementsByTagName('head')[0]; |
|
for(var i = 0, e = styles.length; i < e; i++){ |
cssText = styles[i]; att = styles.attributes[i]; |
st = doc.createElement('style'); |
st.setAttribute("type", "text/css"); // this is required in CSS spec! |
|
for(var x in att){ |
st.setAttribute(x, att[x]) |
} |
|
this._styleNodes.push(st); |
head.appendChild(st); // must insert into DOM before setting cssText |
|
if(st.styleSheet){ // IE |
st.styleSheet.cssText = cssText; |
}else{ // w3c |
st.appendChild(doc.createTextNode(cssText)); |
} |
} |
} |
}); |
|
})(); |
|
} |