Subversion Repositories Applications.papyrus

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dijit.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dijit.layout.ContentPane"] = true;
3
dojo.provide("dijit.layout.ContentPane");
4
 
5
dojo.require("dijit._Widget");
6
dojo.require("dijit.layout._LayoutWidget");
7
 
8
dojo.require("dojo.parser");
9
dojo.require("dojo.string");
10
dojo.requireLocalization("dijit", "loading", null, "ko,zh,ja,zh-tw,ru,it,ROOT,hu,fr,pt,pl,es,de,cs");
11
 
12
dojo.declare(
13
	"dijit.layout.ContentPane",
14
	dijit._Widget,
15
{
16
	// summary:
17
	//		A widget that acts as a Container for other widgets, and includes a ajax interface
18
	// description:
19
	//		A widget that can be used as a standalone widget
20
	//		or as a baseclass for other widgets
21
	//		Handles replacement of document fragment using either external uri or javascript
22
	//		generated markup or DOM content, instantiating widgets within that content.
23
	//		Don't confuse it with an iframe, it only needs/wants document fragments.
24
	//		It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
25
	//		But note that those classes can contain any widget as a child.
26
	// example:
27
	//		Some quick samples:
28
	//		To change the innerHTML use .setContent('<b>new content</b>')
29
	//
30
	//		Or you can send it a NodeList, .setContent(dojo.query('div [class=selected]', userSelection))
31
	//		please note that the nodes in NodeList will copied, not moved
32
	//
33
	//		To do a ajax update use .setHref('url')
34
	//
35
	// href: String
36
	//		The href of the content that displays now.
37
	//		Set this at construction if you want to load data externally when the
38
	//		pane is shown.  (Set preload=true to load it immediately.)
39
	//		Changing href after creation doesn't have any effect; see setHref();
40
	href: "",
41
 
42
	// extractContent: Boolean
43
	//	Extract visible content from inside of <body> .... </body>
44
	extractContent: false,
45
 
46
	// parseOnLoad: Boolean
47
	//	parse content and create the widgets, if any
48
	parseOnLoad:	true,
49
 
50
	// preventCache: Boolean
51
	//		Cache content retreived externally
52
	preventCache:	false,
53
 
54
	// preload: Boolean
55
	//	Force load of data even if pane is hidden.
56
	preload: false,
57
 
58
	// refreshOnShow: Boolean
59
	//		Refresh (re-download) content when pane goes from hidden to shown
60
	refreshOnShow: false,
61
 
62
	// loadingMessage: String
63
	//	Message that shows while downloading
64
	loadingMessage: "<span class='dijitContentPaneLoading'>${loadingState}</span>",
65
 
66
	// errorMessage: String
67
	//	Message that shows if an error occurs
68
	errorMessage: "<span class='dijitContentPaneError'>${errorState}</span>",
69
 
70
	// isLoaded: Boolean
71
	//	Tells loading status see onLoad|onUnload for event hooks
72
	isLoaded: false,
73
 
74
	// class: String
75
	//	Class name to apply to ContentPane dom nodes
76
	"class": "dijitContentPane",
77
 
78
	postCreate: function(){
79
		// remove the title attribute so it doesn't show up when i hover
80
		// over a node
81
		this.domNode.title = "";
82
 
83
		if(this.preload){
84
			this._loadCheck();
85
		}
86
 
87
		var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
88
		this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
89
		this.errorMessage = dojo.string.substitute(this.errorMessage, messages);
90
 
91
		// for programatically created ContentPane (with <span> tag), need to muck w/CSS
92
		// or it's as though overflow:visible is set
93
		dojo.addClass(this.domNode, this["class"]);
94
	},
95
 
96
	startup: function(){
97
		if(this._started){ return; }
98
		this._checkIfSingleChild();
99
		if(this._singleChild){
100
			this._singleChild.startup();
101
		}
102
		this._loadCheck();
103
		this._started = true;
104
	},
105
 
106
	_checkIfSingleChild: function(){
107
		// summary:
108
		// 	Test if we have exactly one widget as a child, and if so assume that we are a container for that widget,
109
		//	and should propogate startup() and resize() calls to it.
110
		var childNodes = dojo.query(">", this.containerNode || this.domNode),
111
			childWidgets = childNodes.filter("[widgetId]");
112
 
113
		if(childNodes.length == 1 && childWidgets.length == 1){
114
			this.isContainer = true;
115
			this._singleChild = dijit.byNode(childWidgets[0]);
116
		}else{
117
			delete this.isContainer;
118
			delete this._singleChild;
119
		}
120
	},
121
 
122
	refresh: function(){
123
		// summary:
124
		//	Force a refresh (re-download) of content, be sure to turn off cache
125
 
126
		// we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
127
		return this._prepareLoad(true);
128
	},
129
 
130
	setHref: function(/*String|Uri*/ href){
131
		// summary:
132
		//		Reset the (external defined) content of this pane and replace with new url
133
		//		Note: It delays the download until widget is shown if preload is false
134
		//	href:
135
		//		url to the page you want to get, must be within the same domain as your mainpage
136
		this.href = href;
137
 
138
		// we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
139
		return this._prepareLoad();
140
	},
141
 
142
	setContent: function(/*String|DomNode|Nodelist*/data){
143
		// summary:
144
		//		Replaces old content with data content, include style classes from old content
145
		//	data:
146
		//		the new Content may be String, DomNode or NodeList
147
		//
148
		//		if data is a NodeList (or an array of nodes) nodes are copied
149
		//		so you can import nodes from another document implicitly
150
 
151
		// clear href so we cant run refresh and clear content
152
		// refresh should only work if we downloaded the content
153
		if(!this._isDownloaded){
154
			this.href = "";
155
			this._onUnloadHandler();
156
		}
157
 
158
		this._setContent(data || "");
159
 
160
		this._isDownloaded = false; // must be set after _setContent(..), pathadjust in dojox.layout.ContentPane
161
 
162
		if(this.parseOnLoad){
163
			this._createSubWidgets();
164
		}
165
 
166
		this._checkIfSingleChild();
167
		if(this._singleChild && this._singleChild.resize){
168
			this._singleChild.resize(this._contentBox);
169
		}
170
 
171
		this._onLoadHandler();
172
	},
173
 
174
	cancel: function(){
175
		// summary:
176
		//		Cancels a inflight download of content
177
		if(this._xhrDfd && (this._xhrDfd.fired == -1)){
178
			this._xhrDfd.cancel();
179
		}
180
		delete this._xhrDfd; // garbage collect
181
	},
182
 
183
	destroy: function(){
184
		// if we have multiple controllers destroying us, bail after the first
185
		if(this._beingDestroyed){
186
			return;
187
		}
188
		// make sure we call onUnload
189
		this._onUnloadHandler();
190
		this._beingDestroyed = true;
191
		this.inherited("destroy",arguments);
192
	},
193
 
194
	resize: function(size){
195
		dojo.marginBox(this.domNode, size);
196
 
197
		// Compute content box size in case we [later] need to size child
198
		// If either height or width wasn't specified by the user, then query node for it.
199
		// But note that setting the margin box and then immediately querying dimensions may return
200
		// inaccurate results, so try not to depend on it.
201
		var node = this.containerNode || this.domNode,
202
			mb = dojo.mixin(dojo.marginBox(node), size||{});
203
 
204
		this._contentBox = dijit.layout.marginBox2contentBox(node, mb);
205
 
206
		// If we have a single widget child then size it to fit snugly within my borders
207
		if(this._singleChild && this._singleChild.resize){
208
			this._singleChild.resize(this._contentBox);
209
		}
210
	},
211
 
212
	_prepareLoad: function(forceLoad){
213
		// sets up for a xhrLoad, load is deferred until widget onShow
214
		// cancels a inflight download
215
		this.cancel();
216
		this.isLoaded = false;
217
		this._loadCheck(forceLoad);
218
	},
219
 
220
	_loadCheck: function(forceLoad){
221
		// call this when you change onShow (onSelected) status when selected in parent container
222
		// it's used as a trigger for href download when this.domNode.display != 'none'
223
 
224
		// sequence:
225
		// if no href -> bail
226
		// forceLoad -> always load
227
		// this.preload -> load when download not in progress, domNode display doesn't matter
228
		// this.refreshOnShow -> load when download in progress bails, domNode display !='none' AND
229
		//						this.open !== false (undefined is ok), isLoaded doesn't matter
230
		// else -> load when download not in progress, if this.open !== false (undefined is ok) AND
231
		//						domNode display != 'none', isLoaded must be false
232
 
233
		var displayState = ((this.open !== false) && (this.domNode.style.display != 'none'));
234
 
235
		if(this.href &&
236
			(forceLoad ||
237
				(this.preload && !this._xhrDfd) ||
238
				(this.refreshOnShow && displayState && !this._xhrDfd) ||
239
				(!this.isLoaded && displayState && !this._xhrDfd)
240
			)
241
		){
242
			this._downloadExternalContent();
243
		}
244
	},
245
 
246
	_downloadExternalContent: function(){
247
		this._onUnloadHandler();
248
 
249
		// display loading message
250
		this._setContent(
251
			this.onDownloadStart.call(this)
252
		);
253
 
254
		var self = this;
255
		var getArgs = {
256
			preventCache: (this.preventCache || this.refreshOnShow),
257
			url: this.href,
258
			handleAs: "text"
259
		};
260
		if(dojo.isObject(this.ioArgs)){
261
			dojo.mixin(getArgs, this.ioArgs);
262
		}
263
 
264
		var hand = this._xhrDfd = (this.ioMethod || dojo.xhrGet)(getArgs);
265
 
266
		hand.addCallback(function(html){
267
			try{
268
				self.onDownloadEnd.call(self);
269
				self._isDownloaded = true;
270
				self.setContent.call(self, html); // onload event is called from here
271
			}catch(err){
272
				self._onError.call(self, 'Content', err); // onContentError
273
			}
274
			delete self._xhrDfd;
275
			return html;
276
		});
277
 
278
		hand.addErrback(function(err){
279
			if(!hand.cancelled){
280
				// show error message in the pane
281
				self._onError.call(self, 'Download', err); // onDownloadError
282
			}
283
			delete self._xhrDfd;
284
			return err;
285
		});
286
	},
287
 
288
	_onLoadHandler: function(){
289
		this.isLoaded = true;
290
		try{
291
			this.onLoad.call(this);
292
		}catch(e){
293
			console.error('Error '+this.widgetId+' running custom onLoad code');
294
		}
295
	},
296
 
297
	_onUnloadHandler: function(){
298
		this.isLoaded = false;
299
		this.cancel();
300
		try{
301
			this.onUnload.call(this);
302
		}catch(e){
303
			console.error('Error '+this.widgetId+' running custom onUnload code');
304
		}
305
	},
306
 
307
	_setContent: function(cont){
308
		this.destroyDescendants();
309
 
310
		try{
311
			var node = this.containerNode || this.domNode;
312
			while(node.firstChild){
313
				dojo._destroyElement(node.firstChild);
314
			}
315
			if(typeof cont == "string"){
316
				// dijit.ContentPane does only minimal fixes,
317
				// No pathAdjustments, script retrieval, style clean etc
318
				// some of these should be available in the dojox.layout.ContentPane
319
				if(this.extractContent){
320
					match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
321
					if(match){ cont = match[1]; }
322
				}
323
				node.innerHTML = cont;
324
			}else{
325
				// domNode or NodeList
326
				if(cont.nodeType){ // domNode (htmlNode 1 or textNode 3)
327
					node.appendChild(cont);
328
				}else{// nodelist or array such as dojo.Nodelist
329
					dojo.forEach(cont, function(n){
330
						node.appendChild(n.cloneNode(true));
331
					});
332
				}
333
			}
334
		}catch(e){
335
			// check if a domfault occurs when we are appending this.errorMessage
336
			// like for instance if domNode is a UL and we try append a DIV
337
			var errMess = this.onContentError(e);
338
			try{
339
				node.innerHTML = errMess;
340
			}catch(e){
341
				console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
342
			}
343
		}
344
	},
345
 
346
	_onError: function(type, err, consoleText){
347
		// shows user the string that is returned by on[type]Error
348
		// overide on[type]Error and return your own string to customize
349
		var errText = this['on' + type + 'Error'].call(this, err);
350
		if(consoleText){
351
			console.error(consoleText, err);
352
		}else if(errText){// a empty string won't change current content
353
			this._setContent.call(this, errText);
354
		}
355
	},
356
 
357
	_createSubWidgets: function(){
358
		// summary: scan my contents and create subwidgets
359
		var rootNode = this.containerNode || this.domNode;
360
		try{
361
			dojo.parser.parse(rootNode, true);
362
		}catch(e){
363
			this._onError('Content', e, "Couldn't create widgets in "+this.id
364
				+(this.href ? " from "+this.href : ""));
365
		}
366
	},
367
 
368
	// EVENT's, should be overide-able
369
	onLoad: function(e){
370
		// summary:
371
		//		Event hook, is called after everything is loaded and widgetified
372
	},
373
 
374
	onUnload: function(e){
375
		// summary:
376
		//		Event hook, is called before old content is cleared
377
	},
378
 
379
	onDownloadStart: function(){
380
		// summary:
381
		//		called before download starts
382
		//		the string returned by this function will be the html
383
		//		that tells the user we are loading something
384
		//		override with your own function if you want to change text
385
		return this.loadingMessage;
386
	},
387
 
388
	onContentError: function(/*Error*/ error){
389
		// summary:
390
		//		called on DOM faults, require fault etc in content
391
		//		default is to display errormessage inside pane
392
	},
393
 
394
	onDownloadError: function(/*Error*/ error){
395
		// summary:
396
		//		Called when download error occurs, default is to display
397
		//		errormessage inside pane. Overide function to change that.
398
		//		The string returned by this function will be the html
399
		//		that tells the user a error happend
400
		return this.errorMessage;
401
	},
402
 
403
	onDownloadEnd: function(){
404
		// summary:
405
		//		called when download is finished
406
	}
407
});
408
 
409
}