mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3488 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
832 lines
27 KiB
JavaScript
832 lines
27 KiB
JavaScript
dojo.provide("dojo.widget.html.loader");
|
|
|
|
dojo.require("dojo.widget.HtmlWidget");
|
|
dojo.require("dojo.io.*");
|
|
dojo.require("dojo.lang.extras");
|
|
|
|
dojo.require("dojo.experimental");
|
|
|
|
// as this is a singleton dojo.declare doesnt by us anything here
|
|
dojo.widget.html.loader = new (function(){
|
|
// summary:
|
|
// loading stuff moved out of contentpane to make it directly accessible by other widgets
|
|
this.toString = function(){ return "dojo.widget.html.loader"; }
|
|
var _loader = this;
|
|
|
|
// back/forward tracking
|
|
dojo.addOnLoad(function(){
|
|
dojo.experimental(_loader.toString());
|
|
var undo = dojo.evalObjPath("dojo.undo.browser");
|
|
if(djConfig["preventBackButtonFix"] && undo && !undo.initialState){
|
|
undo.setInitialState(new trackerObj);
|
|
}
|
|
});
|
|
|
|
var logger = {};
|
|
var trackerObj = function(id, data){
|
|
this.id = id;
|
|
this.data = data
|
|
};
|
|
trackerObj.prototype.handle = function(type){
|
|
if(typeof dojo == 'undefined'){ return; } // wtf? how can dojo become undef?
|
|
var wg = dojo.widget.byId(this.id);
|
|
if(wg){ wg.setContent(this.data, true); }
|
|
};
|
|
|
|
this._log = function(widget, data){
|
|
// if a loader widget B is a child of loader widget A
|
|
// we need to destroy all of B's undo if we switch content
|
|
if(widget.trackHistory){
|
|
if(!logger[widget.widgetId]){
|
|
logger[widget.widgetId] = { childrenIds: [], stack:[data] };
|
|
}var children = logger[widget.widgetId].childrenIds;
|
|
while(children && children.length){
|
|
delete logger[children.pop()];
|
|
}
|
|
for(var child in widget.children){
|
|
logger[widget.widgetId].childrenIds = child.widgetId;
|
|
}
|
|
dojo.undo.browser.addToHistory(new trackerObj(widget.widgetId, dojo.lang.shallowCopy(data, true)));
|
|
}
|
|
}
|
|
|
|
// shortCuts
|
|
var undef = dojo.lang.isUndefined;
|
|
var isFunc = dojo.lang.isFunction;
|
|
|
|
|
|
|
|
/************ private needed functions, no need to be part of widget API ***********/
|
|
// usefull if user wants to prevent default behaviour ie: _setContent("Error...")
|
|
function handleDefaults(e, handler, useAlert){
|
|
if(!handler){ handler = "onContentError"; }
|
|
if(dojo.lang.isString(e)){ e = {_text: e}; }
|
|
if(!e._text){ e._text = e.toString(); }
|
|
e.toString = function(){ return this._text; };
|
|
if(typeof e.returnValue != "boolean"){
|
|
e.returnValue = true;
|
|
}
|
|
if(typeof e.preventDefault != "function"){
|
|
e.preventDefault = function(){ this.returnValue = false; };
|
|
}
|
|
// call our handler
|
|
this[handler](e);
|
|
if(e.returnValue){
|
|
if(useAlert){
|
|
alert(e.toString());
|
|
}else{
|
|
this.loader.callOnUnLoad.call(this, false);
|
|
this.onSetContent(e.toString());
|
|
}
|
|
}
|
|
};
|
|
|
|
// set up downloader, used by both scripts and content
|
|
function downloader(bindArgs) {
|
|
for(var x in this.bindArgs){
|
|
bindArgs[x] = (undef(bindArgs[x]) ? this.bindArgs[x] : undefined);
|
|
}
|
|
var cache = this.cacheContent;
|
|
if(undef(bindArgs.useCache)){ bindArgs.useCache = cache; }
|
|
if(undef(bindArgs.preventCache)){ bindArgs.preventCache = !cache; }
|
|
if(undef(bindArgs.mimetype)){ bindArgs.mimetype = "text/html"; }
|
|
this.loader.bindObj = dojo.io.bind(bindArgs);
|
|
};
|
|
|
|
// runs addOnLoad/addOnUnLoad functions
|
|
function stackRunner(st){
|
|
var err = "", func = null;
|
|
var scope = this.scriptScope || dojo.global();
|
|
while(st.length){
|
|
func = st.shift();
|
|
try{
|
|
func.call(scope);
|
|
}catch(e){
|
|
err += "\n"+func+" failed: "+e;
|
|
}
|
|
}
|
|
if(err.length){
|
|
var name = (st== this.loader.addOnLoads) ? "addOnLoad" : "addOnUnLoad";
|
|
handleDefaults.call(this, name+" failure\n "+err, "onExecError", true);
|
|
}
|
|
};
|
|
|
|
// push addOnLoad and addOnUnLoad functions onto stack
|
|
function stackPusher(st, obj, func){
|
|
if(typeof func == 'undefined') {
|
|
st.push(obj);
|
|
}else{
|
|
st.push(function(){ obj[func](); });
|
|
}
|
|
};
|
|
|
|
// code saver, collects onLoad, onResized and isLoaded
|
|
function refreshed(){
|
|
this.onResized();
|
|
this.onLoad();
|
|
this.isLoaded = true;
|
|
};
|
|
|
|
// runs scripts and starts the content parser
|
|
function asyncParse(data){
|
|
if(this.executeScripts){
|
|
this.onExecScript.call(this, data.scripts);
|
|
}
|
|
if(this.parseContent){
|
|
this.onContentParse.call(this);
|
|
}
|
|
refreshed.call(this);
|
|
};
|
|
|
|
// run java function
|
|
function runHandler(){
|
|
//FIXME: current behaviour is to return false if handler is there, is that intended?
|
|
if(dojo.lang.isFunction(this.handler)) {
|
|
this.handler(this, this.containerNode||this.domNode);
|
|
refreshed.call(this);
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// divided up splitAndFixPaths in different parts
|
|
this.htmlContentBasicFix = function(/*string*/s, /*string||dojo.uri.Uri*/url){
|
|
// summary:
|
|
// strips out <style, <link rel=stylesheet and <title tags
|
|
// intended to take out tags that might cause DOM faults
|
|
var titles = [], styles = [];
|
|
/************** <title> ***********/
|
|
// khtml can't attach a <style> or <title> node as child of body
|
|
var regex = /<title[^>]*>([\s\S]*?)<\/title>/i;
|
|
while(match = regex.exec(s)){
|
|
titles.push(match[1]);
|
|
s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
|
|
};
|
|
/**************** cut out all <style> and <link rel="stylesheet" href=".."> **************/
|
|
regex = /(?:<(style)[^>]*>([\s\S]*?)<\/style>|<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>)/i;
|
|
while(match = regex.exec(s)){
|
|
if(match[1] && match[1].toLowerCase() == "style"){
|
|
styles.push(dojo.html.fixPathsInCssText(match[2],url));
|
|
}else if(attr = match[3].match(/href=(['"]?)([^'">]*)\1/i)){
|
|
styles.push({path: attr[2]});
|
|
}
|
|
s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
|
|
};
|
|
return {'s': s, 'titles': titles, 'styles': styles};//object
|
|
};
|
|
|
|
this.htmlContentAdjustPaths = function(/*string*/s, /*string||dojo.uri.Uri*/url){
|
|
// summary:
|
|
// adjusts relative paths in content to be relative to current page
|
|
var tag = "", str = "", tagFix = "", path = "";
|
|
var attr = [], origPath = "", fix = "";
|
|
|
|
// attributepaths one tag can have multiple paths example:
|
|
// <input src="..." style="url(..)"/> or <a style="url(..)" href="..">
|
|
// strip out the tag and run fix on that.
|
|
// this guarantees that we won't run replace on another tag's attribute + it was easier do
|
|
var regexFindTag = /<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i;
|
|
var regexFindAttr = /\s(src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i;
|
|
// these are the supported protocols, all other is considered relative
|
|
var regexProtocols = /^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/;
|
|
|
|
while(tag = regexFindTag.exec(s)){
|
|
str += s.substring(0, tag.index);
|
|
s = s.substring((tag.index + tag[0].length), s.length);
|
|
tag = tag[0];
|
|
|
|
// loop through attributes
|
|
tagFix = '';
|
|
while(attr = regexFindAttr.exec(tag)){
|
|
path = ""; origPath = attr[3];
|
|
switch(attr[1].toLowerCase()){
|
|
case "src":// falltrough
|
|
case "href":
|
|
if(regexProtocols.exec(origPath)){
|
|
path = origPath;
|
|
} else {
|
|
path = (new dojo.uri.Uri(url, origPath).toString());
|
|
}
|
|
break;
|
|
case "style":// style
|
|
path = dojo.html.fixPathsInCssText(origPath, url);
|
|
break;
|
|
default:
|
|
path = origPath;
|
|
}
|
|
|
|
fix = " " + attr[1] + "=" + attr[2] + path + attr[2];
|
|
|
|
// slices up tag before next attribute check
|
|
tagFix += tag.substring(0, attr.index) + fix;
|
|
tag = tag.substring((attr.index + attr[0].length), tag.length);
|
|
}
|
|
str += tagFix + tag;
|
|
}
|
|
return str+s; // string
|
|
};
|
|
|
|
|
|
this.htmlContentScripts = function(/*string*/s, /*boolean*/collectScripts){
|
|
// summary:
|
|
// handles scripts and dojo .require(...) etc calls
|
|
// NOTE: we need to go through here even if we have executeScripts=false
|
|
// and if we have parseWidgets true
|
|
var scripts = [], requires = [], match = [];
|
|
var attr = "", tmp = null, tag = "", sc = "", str = "";
|
|
|
|
/***************** cut out all <script> tags, push them into scripts array ***************/
|
|
var regex = /<script([^>]*)>([\s\S]*?)<\/script>/i;
|
|
var regexSrc = /src=(['"]?)([^"']*)\1/i;
|
|
var regexDojoJs = /.*(\bdojo\b\.js(?:\.uncompressed\.js)?)$/;
|
|
var regexInvalid = /(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g;
|
|
var regexRequires = /dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix)|defineNamespace)\((['"]).*?\1\)\s*;?/;
|
|
|
|
while(match = regex.exec(s)){
|
|
if(this.executeScripts && match[1]){
|
|
if(attr = regexSrc.exec(match[1])){
|
|
// remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
|
|
// we declare all files named dojo.js as bad, regardless of path
|
|
if(regexDojoJs.exec(attr[2])){
|
|
dojo.debug("Security note! inhibit:"+attr[2]+" from beeing loaded again.");
|
|
}else{
|
|
scripts.push({path: attr[2]});
|
|
}
|
|
}
|
|
}
|
|
if(match[2]){
|
|
// remove all invalid variables etc like djConfig and dojo.hostenv.writeIncludes()
|
|
sc = match[2].replace(regexInvalid, "");
|
|
if(!sc){ continue; }
|
|
|
|
// cut out all dojo .require (...) calls, if we have execute
|
|
// scripts false widgets dont get there require calls
|
|
// takes out possible widgetpackage registration as well
|
|
while(tmp = regexRequires.exec(sc)){
|
|
requires.push(tmp[0]);
|
|
sc = sc.substring(0, tmp.index) + sc.substr(tmp.index + tmp[0].length);
|
|
}
|
|
if(collectScripts){
|
|
scripts.push(sc);
|
|
}
|
|
}
|
|
s = s.substr(0, match.index) + s.substr(match.index + match[0].length);
|
|
}
|
|
/******** scan for scriptScope in html eventHandlers
|
|
and replace with link to this widget *********/
|
|
if(collectScripts){
|
|
var regex = /(<[a-zA-Z][a-zA-Z0-9]*\s[^>]*\S=(['"])[^>]*[^\.\]])scriptScope([^>]*>)/;
|
|
str = "";
|
|
while(tag = regex.exec(s)){
|
|
tmp = ((tag[2]=="'") ? '"': "'");
|
|
str += s.substring(0, tag.index);
|
|
s = s.substr(tag.index).replace(regex, "$1dojo.widget.byId("+ tmp + this.widgetId + tmp + ").scriptScope$3");
|
|
}
|
|
s = str + s;
|
|
}
|
|
return {'s': s, 'requires': requires, 'scripts': scripts}; // object
|
|
};
|
|
|
|
|
|
this.splitAndFixPaths = function(/*object*/args){
|
|
// summary:
|
|
// pathfixes, require calls, css stuff and neccesary content clean
|
|
// args:
|
|
// content string
|
|
// url string? or dojo.uri.Uri that that pulled the content in, for path adjust
|
|
// adjustPaths boolean, if true adjust relative paths in content to match this page
|
|
// collectScripts boolean, if true it takes out all <script and <script src=.. tags and collects
|
|
// dojo.require calls in a separate array, usefull for eval
|
|
// collectRequires boolean, if true and collectScripts is false it still collects scripts along with
|
|
// dojo.require calls
|
|
// bodyExtract boolean, if true only return content inside of the body tag
|
|
|
|
// return: {xml: string,
|
|
// styles: array, remote style get object {path: /*string*/url}
|
|
// requires: array,
|
|
// scripts: array, remote scripts get object {path: /*string*/url}
|
|
// url: string}
|
|
if(!args.url) { args.url = "./"; } // point to this page if not set
|
|
// make sure back/forward buttons dont mess up url.
|
|
url = new dojo.uri.Uri(location, args.url).toString();
|
|
var ret = {'xml': "",
|
|
'styles': [],
|
|
'titles': [],
|
|
'requires': [],
|
|
'scripts': [],
|
|
'url': url };
|
|
|
|
if(args.content){ // make sure we dont run regexes on empty content
|
|
var tmp = null, content = args.content;
|
|
if(args.adjustPaths){
|
|
content = _loader.htmlContentAdjustPaths.call(this, content, url);
|
|
}
|
|
|
|
tmp = _loader.htmlContentBasicFix.call(this, content, url);
|
|
content = tmp.s;
|
|
ret.styles = tmp.styles;
|
|
ret.titles = tmp.titles;
|
|
|
|
if(args.collectRequires || args.collectScripts){
|
|
tmp = _loader.htmlContentScripts.call(this, content, args.collectScripts);
|
|
content = tmp.s;
|
|
ret.requires = tmp.requires;
|
|
ret.scripts = tmp.scripts;
|
|
}
|
|
|
|
/********* extract content *********/
|
|
var match = [];
|
|
if(args.bodyExtract){
|
|
match = content.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
|
|
if(match) { content = match[1]; }
|
|
}
|
|
ret.xml = content;
|
|
}
|
|
return ret;// object
|
|
};
|
|
|
|
|
|
// the all important startup function
|
|
this.hookUp = function(/*object*/args){
|
|
// summary:
|
|
// mixin or extend loader into a widget
|
|
// args:
|
|
// widget: widget reference
|
|
// mixin: boolean, default false
|
|
// if mixin true, it will only extend the current widget, not its prototype
|
|
var widget = args.widget;
|
|
if(dojo.lang.isString(widget)){
|
|
if(args.mixin){
|
|
dojo.raise(this.toString()+", cant use mixin when widget is a string");
|
|
}
|
|
widget = dojo.evalObjPath(widget);
|
|
}
|
|
if(!widget || !(widget instanceof dojo.widget.HtmlWidget)){
|
|
dojo.raise(this.toString()+" Widget is'nt defined or isnt a HtmlWidget instance");
|
|
}
|
|
// make sure we dont mixin more than once
|
|
if(widget.loader && widget.setUrl){ return; }
|
|
|
|
// extend widget prototype or mixin this widget instance
|
|
var widgetProto = (args.mixin) ? widget : widget.constructor.prototype;
|
|
|
|
/********************************************
|
|
** per widgetImpl variables, mixin into widget
|
|
********************************************/
|
|
// stuff it into a loader obj
|
|
widget.loader = {
|
|
isLoaded: false,
|
|
styleNodes: [],
|
|
addOnLoads: [],
|
|
addOnUnLoads: [],
|
|
callOnUnLoad:(function(canCall){
|
|
return function(after){ this.abort();
|
|
if(canCall){ this.onUnLoad(); }
|
|
canCall = after;
|
|
};
|
|
})(false),
|
|
bindObj: null,
|
|
// to disconnect widget
|
|
unHook: (function(w, wg){
|
|
var oldProps = {
|
|
isContainer: w.isContainer,
|
|
adjustPats: w.adjustPaths,
|
|
href: w.href,
|
|
extractContent: w.extractContent,
|
|
parseContent: w.parseContent,
|
|
cacheContent: w.cacheContent,
|
|
bindArgs: w.bindArgs,
|
|
preload: w.preload,
|
|
refreshOnShow: w.refreshOnShow,
|
|
handler: w.handler,
|
|
trackHistory: w.trackHistory,
|
|
executeScripts: w.executeScripts,
|
|
scriptScope: w.scriptScope,
|
|
// functions
|
|
postCreate: w.postCreate,
|
|
show: w.show,
|
|
refresh: w.refresh,
|
|
loadContents: w.loadContents,
|
|
abort: w.abort,
|
|
destroy: w.destroy,
|
|
onLoad: w.onLoad,
|
|
onUnLoad: w.onUnLoad,
|
|
addOnLoad: w.addOnLoad,
|
|
addOnUnLoad: w.addOnUnLoad,
|
|
onDownloadStart: w.onDownloadStart,
|
|
onDownloadEnd: w.onDownloadEnd,
|
|
onDownloadError: w.onDownloadError,
|
|
onContentError: w.onContentError,
|
|
onExecError: w.onExecError,
|
|
onSetContent: w.onSetContent,
|
|
setUrl: w.setUrl,
|
|
setContent: w.setContent,
|
|
onContentParse: w.onContentParse,
|
|
onExecScript: w.onExecScript,
|
|
setHandler: w.setHandler
|
|
};
|
|
return function(){
|
|
if(wg.abort){ wg.abort(); }
|
|
// make sure we dont unhook prototype if there is more widgets of this type left
|
|
if((w != wg) && (dojo.widget.byType(wg.widgetType).length>1)){ return; }
|
|
for(var x in oldProps){
|
|
if(oldProps[x]===undefined){
|
|
delete w[x]; continue;
|
|
}
|
|
w[x] = oldProps[x];
|
|
}
|
|
delete wg._loader_defined;
|
|
delete wg.loader;
|
|
};
|
|
})(widgetProto, widget)
|
|
};
|
|
|
|
// make sure we dont do this more than once per widget/widgetprototype
|
|
if(widgetProto._loader_defined || widget._loader_defined){ return; }
|
|
|
|
/**************** private variables *********************/
|
|
|
|
// loading options, prototype parts of widgets mixin to prototype
|
|
dojo.mixin(widgetProto, {
|
|
// always set to a containerwidget
|
|
isContainer: true,
|
|
// fix relative paths in content to fit into this page
|
|
adjustPaths: undef(widgetProto.adjustPaths) ? true : widgetProto.adjustPaths,
|
|
// only usable on construction, use setUrl or setContent after that
|
|
href: undef(widgetProto.href) ? "" : widgetProto.href,
|
|
// extract visible content from inside of <body> .... </body>
|
|
extractContent: undef(widgetProto.extractContent) ? true : widgetProto.extractContent,
|
|
// construct all widgets that is in content
|
|
// FIXME: rename to parseWidgets?
|
|
parseContent: undef(widgetProto.parseContent) ? true : widgetProto.parseContent,
|
|
// use io binds javascript cache, or if false, prevent browsercache
|
|
cacheContent: undef(widgetProto.cacheContent) ? true : widgetProto.cacheContent,
|
|
// specify specific io.bind arguments such as transport and useCache
|
|
bindArgs: undef(widgetProto.bindArgs) ? {} : widgetProto.bindArgs,
|
|
// force load even if widget isnt shown (lazyload setting)
|
|
preload: undef(widgetProto.preload) ? false : widgetProto.preload,
|
|
// reload content automatically onShow, use with cacheContent = flase
|
|
refreshOnShow: undef(widgetProto.refreshOnShow) ? false : widgetProto.refreshOnShow,
|
|
// name of java function which should generate content
|
|
handler: undef(widgetProto.handler) ? "" : widgetProto.handler,
|
|
// if true scripts in content will be evaled after content is innerHTML'ed
|
|
executeScripts: undef(widgetProto.executeScripts) ? false : widgetProto.executeScripts,
|
|
// log contents (back/forward support)
|
|
trackHistory: undef(widgetProto.tracHistory) ? false : widgetProto.trackHistory,
|
|
scriptScope: null // always overwrite
|
|
});
|
|
|
|
/****************************************************
|
|
******* public functions, becomes part of widgets API
|
|
*****************************************************/
|
|
|
|
/*********** Public functions that wigets cant overide **********/
|
|
// set up postCreate, call originalcode before our own
|
|
widgetProto.postCreate = (function(postCreate){
|
|
return function(){
|
|
if(widgetProto.constructor.superclass.postCreate != postCreate){
|
|
postCreate.apply(this, arguments);
|
|
}else{
|
|
widgetProto.constructor.superclass.postCreate.apply(this, arguments);
|
|
}
|
|
if(this.handler!==""){ this.setHandler(this.handler); }
|
|
if(this.isShowing() || this.preload){
|
|
this.loadContents();
|
|
if(!this.href){ // back/forward save initial state
|
|
_loader._log(this,(this.domNode||this.containerNode).innerHTML);
|
|
}
|
|
}
|
|
}
|
|
})(widgetProto.postCreate);
|
|
|
|
// set up onShow listener, call original code after this block
|
|
widgetProto.show = (function(show){
|
|
return function(){
|
|
// if refreshOnShow is true, reload the contents every time; otherwise, load only the first time
|
|
if(this.refreshOnShow){
|
|
this.refresh();
|
|
}else{
|
|
this.loadContents();
|
|
}
|
|
if((widgetProto.constructor.superclass.show == show) || !isFunc(show)){
|
|
widgetProto.constructor.superclass.show.apply(this, arguments);
|
|
}else{
|
|
show.apply(this, arguments);
|
|
}
|
|
};
|
|
})(widgetProto.show);
|
|
|
|
// destroy cleanups, original code in the middle
|
|
widgetProto.destroy = (function(destroy){
|
|
return function(destroy){
|
|
this.onUnLoad();
|
|
this.abort();
|
|
this.loader.unHook();
|
|
if((widgetProto.constructor.superclass.destroy != destroy) && isFunc(destroy)){
|
|
destroy.apply(this, arguments);
|
|
}else{
|
|
widgetProto.constructor.superclass.destroy.apply(this, arguments);
|
|
}
|
|
}
|
|
})(widgetProto.destroy);
|
|
|
|
|
|
/******* Public functions that widgets can overide *****/
|
|
// set up a refresh function
|
|
if(!widgetProto.refresh){
|
|
widgetProto.refresh = function(){
|
|
this.loader.isLoaded = false;
|
|
this.loadContents();
|
|
};
|
|
}
|
|
|
|
// set up html loading contents
|
|
if(!widgetProto.loadContents){
|
|
widgetProto.loadContents = function(){
|
|
if(this.loader.isLoaded){ return; }
|
|
// javafunction
|
|
if(isFunc(this.handler)){
|
|
runHandler.call(this);
|
|
}else if(this.href !== ""){
|
|
handleDefaults.call(this, "Loading...", "onDownloadStart");
|
|
var self = this, url = this.href;
|
|
downloader.call(this, {
|
|
url: url,
|
|
load: function(type, data, xhr){
|
|
self.onDownloadEnd.call(self, url, data);
|
|
},
|
|
error: function(type, err, xhr){
|
|
// XHR insnt a normal JS object, copy esentials
|
|
var e = {
|
|
responseText: xhr.responseText,
|
|
status: xhr.status,
|
|
statusText: xhr.statusText,
|
|
responseHeaders: (xhr.getAllResponseHeaders) ? xhr.getAllResponseHeaders():[],
|
|
_text: "Error loading '" + url + "' (" + xhr.status + " "+ xhr.statusText + ")"
|
|
};
|
|
handleDefaults.call(self, e, "onDownloadError");
|
|
self.onLoad();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
// set up abort
|
|
if(!widgetProto.abort){
|
|
widgetProto.abort = function(){
|
|
if(!this.loader || !this.loader.bindObj || !this.loader.bindObj.abort){ return; }
|
|
this.loader.bindObj.abort();
|
|
this.loader.bindObj = null;
|
|
};
|
|
}
|
|
|
|
// onLoad
|
|
if(!widgetProto.onLoad){
|
|
widgetProto.onLoad = function(){
|
|
stackRunner.call(this, this.loader.addOnLoads);
|
|
this.loader.isLoaded = true;
|
|
};
|
|
}
|
|
|
|
// onUnLoad, original code in the middle
|
|
if(!widgetProto.onUnLoad){
|
|
widgetProto.onUnLoad = function(){
|
|
stackRunner.call(this, this.loader.addOnUnLoads);
|
|
delete this.scriptScope;
|
|
}
|
|
}
|
|
|
|
// add to onLoad queue
|
|
if(!widgetProto.addOnLoad){
|
|
widgetProto.addOnLoad = function(obj, func){
|
|
stackPusher.call(this, this.loader.addOnLoads, obj, func);
|
|
};
|
|
}
|
|
|
|
// add to onUnLoad queue
|
|
if(!widgetProto.addOnUnLoad){
|
|
widgetProto.addOnUnLoad = function(obj, func){
|
|
stackPusher.call(this, this.loader.addOnUnLoads, obj, func);
|
|
}
|
|
}
|
|
|
|
// script or java errors, preventDefault-able
|
|
if(!widgetProto.onExecError){
|
|
widgetProto.onExecError = function(){/*stub*/};
|
|
}
|
|
|
|
// called on DOM faults, require fault etc in content, preventDefault-able
|
|
if(!widgetProto.onContentError){
|
|
widgetProto.onContentError = function(){/*stub*/};
|
|
}
|
|
|
|
// called when download error occurs, preventDefault-able
|
|
if(!widgetProto.onDownloadError){
|
|
widgetProto.onDownloadError = function(){/*stub*/};
|
|
}
|
|
|
|
// called before download starts, preventDefault-able
|
|
if(!widgetProto.onDownloadStart){
|
|
widgetProto.onDownloadStart = function(onDownloadStart){/*stub*/};
|
|
}
|
|
|
|
// called when download is finished successfully
|
|
if(!widgetProto.onDownloadEnd){
|
|
widgetProto.onDownloadEnd = function(url, data){
|
|
var args = {content: data,
|
|
url: url,
|
|
adjustPaths: this.adjustPaths,
|
|
collectScripts: this.executeScripts,
|
|
collectRequires: this.parseContent,
|
|
bodyExtract: this.extractContent };
|
|
data = _loader.splitAndFixPaths.call(this, args);
|
|
this.setContent(data);
|
|
}
|
|
}
|
|
|
|
// previously called _setContent, widget defined onSetContent can modify content or cancel
|
|
if(!widgetProto.onSetContent){
|
|
widgetProto.onSetContent = function(cont){
|
|
this.destroyChildren();
|
|
|
|
// remove old stylenodes from HEAD
|
|
var styleNodes = this.loader.styleNodes;
|
|
while(styleNodes.length){
|
|
var st = styleNodes.pop();
|
|
if(st && st.parentNode){
|
|
st.parentNode.removeChild(st);
|
|
}
|
|
}
|
|
|
|
var node = this.containerNode || this.domNode;
|
|
while(node.firstChild){
|
|
try{
|
|
dojo.event.browser.clean(node.firstChild);
|
|
}catch(e){}
|
|
node.removeChild(node.firstChild);
|
|
}
|
|
try{
|
|
if(typeof cont != "string"){
|
|
node.appendChild(cont);
|
|
}else{
|
|
try{// hack to deal with domfaults, ie. appending div to tablenodes
|
|
node.innerHTML = cont;
|
|
}catch(e){var tmp;
|
|
(tmp = dojo.doc().createElement("div")).innerHTML = cont;
|
|
while(tmp.firstChild){
|
|
node.appendChild(tmp.removeChild(tmp.firstChild));
|
|
}
|
|
}
|
|
}
|
|
}catch(e){
|
|
e._text = "Could'nt load content: "+e;
|
|
var useAlert = (this.loader._onSetContent_err == e._text); // make sure we dont loop
|
|
this.loader._onSetContent_err = e._text;
|
|
handleDefaults.call(this, e, "onContentError", useAlert);
|
|
}
|
|
};
|
|
}
|
|
|
|
if(!widgetProto.setUrl){
|
|
widgetProto.setUrl = function(url){
|
|
this.href = url;
|
|
this.loader.isLoaded = false;
|
|
if ( this.preload || this.isShowing() ){
|
|
this.loadContents();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!widgetProto.setContent){
|
|
widgetProto.setContent = function(data, dontLog){
|
|
this.loader.callOnUnLoad.call(this, true);
|
|
|
|
if(!data||dojo.html.isNode(data)){
|
|
this.onSetContent(data);
|
|
refreshed.call(this);
|
|
}else{
|
|
// need to run splitAndFixPaths? ie. manually setting content
|
|
// adjustPaths is taken care of inside splitAndFixPaths
|
|
if(typeof data.xml != 'string'){
|
|
this.href = ""; // so we can refresh safely
|
|
var args = {content: data,
|
|
url: this.href,
|
|
adjustPaths: this.adjustPaths,
|
|
collectScripts: this.executeScripts,
|
|
collectRequires: this.parseContent,
|
|
bodyExtract: this.extractContent };
|
|
data = _loader.splitAndFixPaths.call(this, args);
|
|
}else if(data.url!="./"){
|
|
this.url = data.url;// backbutton thing
|
|
}
|
|
this.onSetContent(data.xml);
|
|
|
|
// insert styles from content (in same order they came in)
|
|
for(var i = 0, styles = data.styles; i < styles.length; i++){
|
|
if(styles[i].path){
|
|
this.loader.styleNodes.push(dojo.html.insertCssFile(styles[i].path));
|
|
}else{
|
|
this.loader.styleNodes.push(dojo.html.insertCssText(styles[i]));
|
|
}
|
|
}
|
|
|
|
if(this.parseContent){
|
|
for(var i = 0, requires = data.requires; i < requires.length; i++){
|
|
try{
|
|
eval(requires[i]);
|
|
} catch(e){
|
|
e._text = "Error in packageloading calls, "+(e.description||e);
|
|
handleDefaults.call(this, e, "onContentError", true);
|
|
}
|
|
}
|
|
}
|
|
// need to allow async load, Xdomain uses it
|
|
// NOTE: on Xdomain loads this can break the sync thread of setContent
|
|
// if you you do any dojo. require(...) etc
|
|
if(dojo.hostenv.isXDomain && data.requires.length){
|
|
dojo.addOnLoad(function(){
|
|
asyncParse.call(this, data);
|
|
if(!dontLog){
|
|
_loader._log(this, data);
|
|
}
|
|
});// this opens a thread need abort undo
|
|
dontLog = true;
|
|
}else{
|
|
asyncParse.call(this, data);
|
|
}
|
|
}if(!dontLog){
|
|
// _loader._log(this, data);
|
|
}
|
|
};
|
|
}
|
|
|
|
if(!widgetProto.onContentParse){
|
|
widgetProto.onContentParse = function(){
|
|
var node = this.containerNode || this.domNode;
|
|
var parser = new dojo.xml.Parse();
|
|
var frag = parser.parseElement(node, null, true);
|
|
dojo.widget.getParser().createSubComponents(frag, this);
|
|
};
|
|
}
|
|
|
|
// previously called _executeScripts
|
|
if(!widgetProto.onExecScript){
|
|
widgetProto.onExecScript = function(scripts){
|
|
// loop through the scripts in the order they came in
|
|
var self = this, tmp = "", code = "";
|
|
for(var i = 0; i < scripts.length; i++){ // remotescript
|
|
if(scripts[i].path){
|
|
var url = scripts[i].path;
|
|
downloader.call(this,{
|
|
'url': url,
|
|
'load': function(type, scriptStr){
|
|
(function(){tmp = scriptStr; scripts[i] = scriptStr;}).call(self);
|
|
},
|
|
'error': function(type, error){
|
|
error._text = type + " downloading remote script";
|
|
handleDefaults.call(self, error, "onExecError", true);
|
|
},
|
|
'mimetype': "text/plain",
|
|
'sync': true
|
|
});
|
|
code += tmp;
|
|
}else{
|
|
code += scripts[i];
|
|
}
|
|
}
|
|
|
|
try{
|
|
// initialize a new anonymous container for our script, dont make it part of this widgets scope chain
|
|
// instead send in a variable that points to this widget, usefull to connect events to onLoad, onUnLoad etc..
|
|
delete this.scriptScope;
|
|
this.scriptScope = new (new Function('_container_', code+'; return this;'))(self);
|
|
}catch(e){
|
|
e._text = "Error running scripts from content:\n"+(e.description||e.toString());
|
|
handleDefaults.call(this, e, "onExecError", true);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Generate content from given java function
|
|
if(!widgetProto.setHandler){
|
|
widgetProto.setHandler = function(handler) {
|
|
var fcn = dojo.lang.isFunction(handler) ? handler : window[handler];
|
|
if(!isFunc(fcn)) {
|
|
// FIXME: needs testing! somebody with java knowledge needs to try this
|
|
handleDefaults.call(this, "Unable to set handler, '" + handler + "' not a function.", "onExecError", true);
|
|
return;
|
|
}
|
|
this.handler = function() {
|
|
return fcn.apply(this, arguments);
|
|
};
|
|
};
|
|
}
|
|
|
|
// make sure we extend this widget only once
|
|
widgetProto._loader_defined = true;
|
|
};
|
|
|
|
|
|
})();
|