Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('yui2-profilerviewer', function(Y) {
2
    var YAHOO    = Y.YUI2;
3
    /*
4
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
5
Code licensed under the BSD License:
6
http://developer.yahoo.com/yui/license.html
7
version: 2.9.0
8
*/
9
(function() {
10
 
11
    /**
12
     * The ProfilerViewer module provides a graphical display for viewing
13
	 * the output of the YUI Profiler <http://developer.yahoo.com/yui/profiler>.
14
     * @module profilerviewer
15
     * @requires yahoo, dom, event, element, profiler, yuiloader
16
     */
17
 
18
    /**
19
     * A widget to view YUI Profiler output.
20
     * @namespace YAHOO.widget
21
     * @class ProfilerViewer
22
     * @extends YAHOO.util.Element
23
     * @constructor
24
     * @param {HTMLElement | String | Object} el(optional) The html
25
     * element into which the ProfileViewer should be rendered.
26
     * An element will be created if none provided.
27
     * @param {Object} attr (optional) A key map of the ProfilerViewer's
28
     * initial attributes.  Ignored if first arg is an attributes object.
29
     */
30
    YAHOO.widget.ProfilerViewer = function(el, attr) {
31
        attr = attr || {};
32
        if (arguments.length == 1 && !YAHOO.lang.isString(el) && !el.nodeName) {
33
            attr = el;
34
            el = attr.element || null;
35
        }
36
        if (!el && !attr.element) {
37
            el = this._createProfilerViewerElement();
38
        }
39
 
40
    	YAHOO.widget.ProfilerViewer.superclass.constructor.call(this, el, attr);
41
 
42
		this._init();
43
 
44
		YAHOO.log("ProfilerViewer instantiated.", "info", "ProfilerViewer");
45
    };
46
 
47
    YAHOO.extend(YAHOO.widget.ProfilerViewer, YAHOO.util.Element);
48
 
49
	// Static members of YAHOO.widget.ProfilerViewer:
50
	YAHOO.lang.augmentObject(YAHOO.widget.ProfilerViewer, {
51
		/**
52
		 * Classname for ProfilerViewer containing element.
53
		 * @static
54
		 * @property CLASS
55
		 * @type string
56
		 * @public
57
		 * @default "yui-pv"
58
		 */
59
		CLASS: 'yui-pv',
60
 
61
		/**
62
		 * Classname for ProfilerViewer button dashboard.
63
		 * @static
64
		 * @property CLASS_DASHBOARD
65
		 * @type string
66
		 * @public
67
		 * @default "yui-pv-dashboard"
68
		 */
69
		CLASS_DASHBOARD: 'yui-pv-dashboard',
70
 
71
		/**
72
		 * Classname for the "refresh data" button.
73
		 * @static
74
		 * @property CLASS_REFRESH
75
		 * @type string
76
		 * @public
77
		 * @default "yui-pv-refresh"
78
		 */
79
		CLASS_REFRESH: 'yui-pv-refresh',
80
 
81
		/**
82
		 * Classname for busy indicator in the dashboard.
83
		 * @static
84
		 * @property CLASS_BUSY
85
		 * @type string
86
		 * @public
87
		 * @default "yui-pv-busy"
88
		 */
89
		CLASS_BUSY: 'yui-pv-busy',
90
 
91
		/**
92
		 * Classname for element containing the chart and chart
93
		 * legend elements.
94
		 * @static
95
		 * @property CLASS_CHART_CONTAINER
96
		 * @type string
97
		 * @public
98
		 * @default "yui-pv-chartcontainer"
99
		 */
100
		CLASS_CHART_CONTAINER: 'yui-pv-chartcontainer',
101
 
102
		/**
103
		 * Classname for element containing the chart.
104
		 * @static
105
		 * @property CLASS_CHART
106
		 * @type string
107
		 * @public
108
		 * @default "yui-pv-chart"
109
		 */
110
		CLASS_CHART: 'yui-pv-chart',
111
 
112
		/**
113
		 * Classname for element containing the chart's legend.
114
		 * @static
115
		 * @property CLASS_CHART_LEGEND
116
		 * @type string
117
		 * @public
118
		 * @default "yui-pv-chartlegend"
119
		 */
120
		CLASS_CHART_LEGEND: 'yui-pv-chartlegend',
121
 
122
		/**
123
		 * Classname for element containing the datatable.
124
		 * @static
125
		 * @property CLASS_TABLE
126
		 * @type string
127
		 * @public
128
		 * @default "yui-pv-table"
129
		 */
130
		CLASS_TABLE: 'yui-pv-table',
131
 
132
		/**
133
		 * HTML strings used in the UI. Values will be inserted into DOM with innerHTML.
134
		 * @static
135
		 * @property STRINGS
136
		 * @object
137
		 * @public
138
		 * @default English language strings for UI.
139
		 */
140
		STRINGS: {
141
			title: "YUI ProfilerViewer",
142
			buttons: {
143
				viewprofiler: "View Profiler Data",
144
				hideprofiler: "Hide Profiler Report",
145
				showchart: "Show Chart",
146
				hidechart: "Hide Chart",
147
				refreshdata: "Refresh Data"
148
			},
149
			colHeads: {
150
				//key: [column head label, width in pixels]
151
				fn: ["Function/Method", null], //must auto-size
152
				calls: ["Calls", 40],
153
				avg: ["Average", 80],
154
				min: ["Shortest", 70],
155
				max: ["Longest", 70],
156
				total: ["Total Time", 70],
157
				pct: ["Percent", 70]
158
			},
159
			millisecondsAbbrev: "ms",
160
			initMessage: "initialiazing chart...",
161
			installFlashMessage: "Unable to load Flash content. The YUI Charts Control requires Flash Player 9.0.45 or higher. You can download the latest version of Flash Player from the <a href='http://www.adobe.com/go/getflashplayer'>Adobe Flash Player Download Center</a>."
162
		},
163
 
164
		/**
165
		 * Function used to format numbers in milliseconds
166
		 * for chart; must be publicly accessible, per Charts spec.
167
		 * @static
168
		 * @property timeAxisLabelFunction
169
		 * @type function
170
		 * @private
171
		 */
172
		timeAxisLabelFunction: function(n) {
173
			var a = (n === Math.floor(n)) ? n : (Math.round(n*1000))/1000;
174
			return (a + " " + YAHOO.widget.ProfilerViewer.STRINGS.millisecondsAbbrev);
175
		},
176
 
177
		/**
178
		 * Function used to format percent numbers for chart; must
179
		 * be publicly accessible, per Charts spec.
180
		 * @static
181
		 * @property percentAxisLabelFunction
182
		 * @type function
183
		 * @private
184
		 */
185
		percentAxisLabelFunction: function(n) {
186
			var a = (n === Math.floor(n)) ? n : (Math.round(n*100))/100;
187
			return (a + "%");
188
		}
189
 
190
 
191
	},true);
192
 
193
 
194
	//
195
	// STANDARD SHORTCUTS
196
	//
197
    var Dom = YAHOO.util.Dom;
198
    var Event = YAHOO.util.Event;
199
	var Profiler = YAHOO.tool.Profiler;
200
	var PV = YAHOO.widget.ProfilerViewer;
201
	var proto = PV.prototype;
202
 
203
 
204
	//
205
	// PUBLIC METHODS
206
	//
207
 
208
	 /**
209
     * Refreshes the data displayed in the ProfilerViewer. When called,
210
	 * this will invoke a refresh of the DataTable and (if displayed)
211
	 * the Chart.
212
     * @method refreshData
213
     * @return void
214
	 * @public
215
     */
216
	proto.refreshData = function() {
217
		YAHOO.log("Data refresh requested via refreshData method.", "info", "ProfilerViewer");
218
		this.fireEvent("dataRefreshEvent");
219
	};
220
 
221
	 /**
222
     * Returns the element containing the console's header.
223
     * @method getHeadEl
224
     * @return HTMLElement
225
	 * @public
226
     */
227
	proto.getHeadEl = function() {
228
		YAHOO.log("Head element requested via getHeadEl.", "info", "ProfilerViewer");
229
		return (this._headEl) ? Dom.get(this._headEl) : false;
230
	};
231
 
232
	 /**
233
     * Returns the element containing the console's body, including
234
	 * the chart and the datatable..
235
     * @method getBodyEl
236
     * @return HTMLElement
237
	 * @public
238
     */
239
	proto.getBodyEl = function() {
240
		YAHOO.log("Body element requested via getBodyEl.", "info", "ProfilerViewer");
241
		return (this._bodyEl) ? Dom.get(this._bodyEl) : false;
242
	};
243
 
244
	 /**
245
     * Returns the element containing the console's chart.
246
     * @method getChartEl
247
     * @return HTMLElement
248
	 * @public
249
     */
250
	proto.getChartEl = function() {
251
		YAHOO.log("Chart element requested via getChartEl.", "info", "ProfilerViewer");
252
		return (this._chartEl) ? Dom.get(this._chartEl) : false;
253
	};
254
 
255
	 /**
256
     * Returns the element containing the console's dataTable.
257
     * @method getTableEl
258
     * @return HTMLElement
259
	 * @public
260
     */
261
	proto.getTableEl = function() {
262
		YAHOO.log("DataTable element requested via getTableEl.", "info", "ProfilerViewer");
263
		return (this._tableEl) ? Dom.get(this._tableEl) : false;
264
	};
265
 
266
	 /**
267
     * Returns the element containing the console's DataTable
268
	 * instance.
269
     * @method getDataTable
270
     * @return YAHOO.widget.DataTable
271
	 * @public
272
     */
273
	proto.getDataTable = function() {
274
		YAHOO.log("DataTable instance requested via getDataTable.", "info", "ProfilerViewer");
275
		return this._dataTable;
276
	};
277
 
278
	 /**
279
     * Returns the element containing the console's Chart instance.
280
     * @method getChart
281
     * @return YAHOO.widget.BarChart
282
	 * @public
283
     */
284
	proto.getChart = function() {
285
		YAHOO.log("Chart instance requested via getChart.", "info", "ProfilerViewer");
286
		return this._chart;
287
	};
288
 
289
 
290
    //
291
    // PRIVATE PROPERTIES
292
    //
293
    proto._rendered = false;
294
	proto._headEl = null;
295
	proto._bodyEl = null;
296
	proto._toggleVisibleEl = null;
297
	proto._busyEl = null;
298
	proto._busy = false;
299
 
300
	proto._tableEl = null;
301
	proto._dataTable = null;
302
 
303
	proto._chartEl = null;
304
	proto._chartLegendEl = null;
305
	proto._chartElHeight = 250;
306
	proto._chart = null;
307
	proto._chartInitialized = false;
308
 
309
    //
310
    // PRIVATE METHODS
311
    //
312
 
313
	proto._init = function() {
314
		/**
315
		 * CUSTOM EVENTS
316
		 **/
317
 
318
		/**
319
		 * Fired when a data refresh is requested. No arguments are passed
320
		 * with this event.
321
		 *
322
		 * @event refreshDataEvent
323
		 */
324
		this.createEvent("dataRefreshEvent");
325
 
326
		/**
327
		 * Fired when the viewer canvas first renders. No arguments are passed
328
		 * with this event.
329
		 *
330
		 * @event renderEvent
331
		 */
332
		this.createEvent("renderEvent");
333
 
334
		this.on("dataRefreshEvent", this._refreshDataTable, this, true);
335
 
336
		this._initLauncherDOM();
337
 
338
		if(this.get("showChart")) {
339
			this.on("sortedByChange", this._refreshChart);
340
		}
341
 
342
		YAHOO.log("ProfilerViewer instance initialization complete.", "info", "ProfilerViewer");
343
	};
344
 
345
	/**
346
	 * If no element is passed in, create it as the first element
347
	 * in the document.
348
	 * @method _createProfilerViewerElement
349
	 * @return HTMLElement
350
	 * @private
351
	 */
352
	proto._createProfilerViewerElement = function() {
353
		YAHOO.log("Creating root element...", "info", "ProfilerViewer");
354
 
355
		var el = document.createElement("div");
356
		document.body.insertBefore(el, document.body.firstChild);
357
		Dom.addClass(el, this.SKIN_CLASS);
358
		Dom.addClass(el, PV.CLASS);
359
		YAHOO.log(el);
360
		return el;
361
	};
362
 
363
    /**
364
     * Provides a readable name for the ProfilerViewer instance.
365
     * @method toString
366
     * @return String
367
	 * @private
368
	 */
369
    proto.toString = function() {
370
        return "ProfilerViewer " + (this.get('id') || this.get('tagName'));
371
    };
372
 
373
    /**
374
     * Toggles visibility of the viewer canvas.
375
     * @method _toggleVisible
376
     * @return void
377
	 * @private
378
     */
379
	proto._toggleVisible = function() {
380
		YAHOO.log("Toggling visibility to " + !this.get("visible") + ".", "info", "ProfilerViewer");
381
 
382
		var newVis = (this.get("visible")) ? false : true;
383
		this.set("visible", newVis);
384
    };
385
 
386
    /**
387
     * Shows the viewer canvas.
388
     * @method show
389
     * @return void
390
	 * @private
391
     */
392
	 proto._show = function() {
393
	 	if(!this._busy) {
394
			this._setBusyState(true);
395
			if(!this._rendered) {
396
				var loader = new YAHOO.util.YUILoader();
397
				if (this.get("base")) {
398
					loader.base = this.get("base");
399
				}
400
 
401
				var modules = ["datatable"];
402
				if(this.get("showChart")) {
403
					modules.push("charts");
404
				}
405
 
406
				loader.insert({ require: modules,
407
								onSuccess: function() {
408
									this._render();
409
								},
410
								scope: this});
411
			} else {
412
				var el = this.get("element");
413
				Dom.removeClass(el, "yui-pv-minimized");
414
				this._toggleVisibleEl.innerHTML = PV.STRINGS.buttons.hideprofiler;
415
 
416
				//The Flash Charts component can't be set to display:none,
417
				//and even after positioning it offscreen the screen
418
				//may fail to repaint in some browsers.  Adding an empty
419
				//style rule to the console body can help force a repaint:
420
				Dom.addClass(el, "yui-pv-null");
421
				Dom.removeClass(el, "yui-pv-null");
422
 
423
				//Always refresh data when changing to visible:
424
				this.refreshData();
425
			}
426
		}
427
    };
428
 
429
    /**
430
     * Hides the viewer canvas.
431
     * @method hide
432
     * @return void
433
	 * @private
434
     */
435
	proto._hide = function() {
436
		this._toggleVisibleEl.innerHTML = PV.STRINGS.buttons.viewprofiler;
437
		Dom.addClass(this.get("element"), "yui-pv-minimized");
438
    };
439
 
440
	/**
441
	 * Render the viewer canvas
442
	 * @method _render
443
	 * @return void
444
	 * @private
445
	 */
446
	proto._render = function() {
447
		YAHOO.log("Beginning to render ProfilerViewer canvas...", "info", "ProfilerViewer");
448
 
449
		Dom.removeClass(this.get("element"), "yui-pv-minimized");
450
 
451
		this._initViewerDOM();
452
		this._initDataTable();
453
		if(this.get("showChart")) {
454
			this._initChartDOM();
455
			this._initChart();
456
		}
457
		this._rendered = true;
458
		this._toggleVisibleEl.innerHTML = PV.STRINGS.buttons.hideprofiler;
459
 
460
		this.fireEvent("renderEvent");
461
 
462
		YAHOO.log("ProfilerViewer rendering complete...", "info", "ProfilerViewer");
463
	};
464
 
465
	/**
466
	 * Set up the DOM structure for the ProfilerViewer launcher.
467
	 * @method _initLauncherDOM
468
	 * @private
469
	 */
470
	proto._initLauncherDOM = function() {
471
		YAHOO.log("Creating the launcher...", "info", "ProfilerViewer");
472
 
473
		var el = this.get("element");
474
		Dom.addClass(el, PV.CLASS);
475
		Dom.addClass(el, "yui-pv-minimized");
476
 
477
		this._headEl = document.createElement("div");
478
		Dom.addClass(this._headEl, "hd");
479
 
480
		var s = PV.STRINGS.buttons;
481
		var b = (this.get("visible")) ? s.hideprofiler : s.viewprofiler;
482
 
483
		this._toggleVisibleEl = this._createButton(b, this._headEl);
484
 
485
		this._refreshEl = this._createButton(s.refreshdata, this._headEl);
486
		Dom.addClass(this._refreshEl, PV.CLASS_REFRESH);
487
 
488
		this._busyEl = document.createElement("span");
489
		this._headEl.appendChild(this._busyEl);
490
 
491
		var title = document.createElement("h4");
492
		title.innerHTML = PV.STRINGS.title;
493
		this._headEl.appendChild(title);
494
 
495
		el.appendChild(this._headEl);
496
 
497
		Event.on(this._toggleVisibleEl, "click", this._toggleVisible, this, true);
498
		Event.on(this._refreshEl, "click", function() {
499
			if(!this._busy) {
500
				this._setBusyState(true);
501
				this.fireEvent("dataRefreshEvent");
502
			}
503
		}, this, true);
504
	};
505
 
506
	/**
507
	 * Set up the DOM structure for the ProfilerViewer canvas,
508
	 * including the holder for the DataTable.
509
	 * @method _initViewerDOM
510
	 * @private
511
	 */
512
	proto._initViewerDOM = function() {
513
		YAHOO.log("Creating DOM structure for viewer...", "info", "ProfilerViewer");
514
 
515
		var el = this.get("element");
516
		this._bodyEl = document.createElement("div");
517
		Dom.addClass(this._bodyEl, "bd");
518
	 	this._tableEl = document.createElement("div");
519
		Dom.addClass(this._tableEl, PV.CLASS_TABLE);
520
		this._bodyEl.appendChild(this._tableEl);
521
		el.appendChild(this._bodyEl);
522
	};
523
 
524
	/**
525
	 * Set up the DOM structure for the ProfilerViewer canvas.
526
	 * @method _initChartDOM
527
	 * @private
528
	 */
529
	proto._initChartDOM = function() {
530
		YAHOO.log("Adding DOM structure for chart...", "info", "ProfilerViewer");
531
 
532
		this._chartContainer = document.createElement("div");
533
		Dom.addClass(this._chartContainer, PV.CLASS_CHART_CONTAINER);
534
 
535
		var chl = document.createElement("div");
536
		Dom.addClass(chl, PV.CLASS_CHART_LEGEND);
537
 
538
		var chw = document.createElement("div");
539
 
540
		this._chartLegendEl = document.createElement("dl");
541
		this._chartLegendEl.innerHTML = "<dd>" + PV.STRINGS.initMessage + "</dd>";
542
 
543
		this._chartEl = document.createElement("div");
544
		Dom.addClass(this._chartEl, PV.CLASS_CHART);
545
 
546
		var msg = document.createElement("p");
547
		msg.innerHTML = PV.STRINGS.installFlashMessage;
548
		this._chartEl.appendChild(msg);
549
 
550
		this._chartContainer.appendChild(chl);
551
		chl.appendChild(chw);
552
		chw.appendChild(this._chartLegendEl);
553
		this._chartContainer.appendChild(this._chartEl);
554
		this._bodyEl.insertBefore(this._chartContainer,this._tableEl);
555
	};
556
 
557
 
558
	/**
559
	 * Create anchor elements for use as buttons. Args: label
560
	 * is text to appear on the face of the button, parentEl
561
	 * is the el to which the anchor will be attached, position
562
	 * is true for inserting as the first node and false for
563
	 * inserting as the last node of the parentEl.
564
	 * @method _createButton
565
	 * @private
566
	 */
567
	proto._createButton = function(label, parentEl, position) {
568
		var b = document.createElement("a");
569
		b.innerHTML = b.title = label;
570
		if(parentEl) {
571
			if(!position) {
572
				parentEl.appendChild(b);
573
			} else {
574
				parentEl.insertBefore(b, parentEl.firstChild);
575
			}
576
		}
577
		return b;
578
	};
579
 
580
	/**
581
	 * Set's console busy state.
582
	 * @method _setBusyState
583
	 * @private
584
	 **/
585
	proto._setBusyState = function(b) {
586
		if(b) {
587
			Dom.addClass(this._busyEl, PV.CLASS_BUSY);
588
			this._busy = true;
589
		} else {
590
			Dom.removeClass(this._busyEl, PV.CLASS_BUSY);
591
			this._busy = false;
592
		}
593
	};
594
 
595
	/**
596
	 * Generages a sorting function based on current sortedBy
597
	 * values.
598
	 * @method _createProfilerViewerElement
599
	 * @private
600
	 **/
601
	proto._genSortFunction = function(key, dir) {
602
		var by = key;
603
		var direction = dir;
604
		return function(a, b) {
605
			if (direction == YAHOO.widget.DataTable.CLASS_ASC) {
606
				return a[by] - b[by];
607
			} else {
608
				return ((a[by] - b[by]) * -1);
609
			}
610
		};
611
	};
612
 
613
	/**
614
	 * Utility function for array sums.
615
	 * @method _arraySum
616
	 * @private
617
	 **/
618
	 var _arraySum = function(arr){
619
		var ct = 0;
620
		for(var i = 0; i < arr.length; ct+=arr[i++]){}
621
		return ct;
622
	};
623
 
624
	/**
625
	 * Retrieves data from Profiler, filtering and sorting as needed
626
	 * based on current widget state.  Adds calculated percentage
627
	 * column and function name to data returned by Profiler.
628
	 * @method _getProfilerData
629
	 * @private
630
	 **/
631
	proto._getProfilerData = function() {
632
		YAHOO.log("Profiler data requested from function DataSource.", "info", "ProfilerViewer");
633
 
634
		var obj = Profiler.getFullReport();
635
		var arr = [];
636
		var totalTime = 0;
637
		for (name in obj) {
638
    		if (YAHOO.lang.hasOwnProperty(obj, name)) {
639
				var r = obj[name];
640
				var o = {};
641
				o.fn = name; //add function name to record
642
				o.points = r.points.slice(); //copy live array
643
				o.calls = r.calls;
644
				o.min = r.min;
645
				o.max = r.max;
646
				o.avg = r.avg;
647
				o.total = _arraySum(o.points);
648
				o.points = r.points;
649
				var f = this.get("filter");
650
				if((!f) || (f(o))) {
651
					arr.push(o);
652
					totalTime += o.total;
653
				}
654
			}
655
		}
656
 
657
		//add calculated percentage column
658
		for (var i = 0, j = arr.length; i < j; i++) {
659
			arr[i].pct = (totalTime) ? (arr[i].total * 100) / totalTime : 0;
660
		}
661
 
662
		var sortedBy = this.get("sortedBy");
663
		var key = sortedBy.key;
664
		var dir = sortedBy.dir;
665
 
666
		arr.sort(this._genSortFunction(key, dir));
667
 
668
		YAHOO.log("Returning data from DataSource: " + YAHOO.lang.dump(arr), "info", "ProfilerViewer");
669
 
670
		return arr;
671
	};
672
 
673
	/**
674
	 * Set up the DataTable.
675
	 * @method _initDataTable
676
	 * @private
677
	 */
678
	proto._initDataTable = function() {
679
		YAHOO.log("Creating DataTable instance...", "info", "ProfilerViewer");
680
 
681
		var self = this;
682
 
683
		//Set up the JS Function DataSource, pulling data from
684
		//the Profiler.
685
		this._dataSource = new YAHOO.util.DataSource(
686
			function() {
687
				return self._getProfilerData.call(self);
688
			},
689
			{
690
				responseType: YAHOO.util.DataSource.TYPE_JSARRAY,
691
				maxCacheEntries: 0
692
			}
693
		);
694
		var ds = this._dataSource;
695
 
696
		ds.responseSchema =
697
		{
698
			fields: [ "fn", "avg", "calls", "max", "min", "total", "pct", "points"]
699
		};
700
 
701
		//Set up the DataTable.
702
		var formatTimeValue = function(elCell, oRecord, oColumn, oData) {
703
			var a = (oData === Math.floor(oData)) ? oData : (Math.round(oData*1000))/1000;
704
			elCell.innerHTML = a + " " + PV.STRINGS.millisecondsAbbrev;
705
		};
706
 
707
		var formatPercent = function(elCell, oRecord, oColumn, oData) {
708
			var a = (oData === Math.floor(oData)) ? oData : (Math.round(oData*100))/100;
709
			elCell.innerHTML = a + "%";
710
		};
711
 
712
		var a = YAHOO.widget.DataTable.CLASS_ASC;
713
		var d = YAHOO.widget.DataTable.CLASS_DESC;
714
		var c = PV.STRINGS.colHeads;
715
		var f = formatTimeValue;
716
 
717
		var cols = [
718
			{key:"fn", sortable:true, label: c.fn[0],
719
				sortOptions: {defaultDir:a},
720
				resizeable: (YAHOO.util.DragDrop) ? true : false,
721
				minWidth:c.fn[1]},
722
			{key:"calls", sortable:true, label: c.calls[0],
723
				sortOptions: {defaultDir:d},
724
				width:c.calls[1]},
725
			{key:"avg", sortable:true, label: c.avg[0],
726
				sortOptions: {defaultDir:d},
727
				formatter:f,
728
				width:c.avg[1]},
729
			{key:"min", sortable:true, label: c.min[0],
730
				sortOptions: {defaultDir:a},
731
				formatter:f,
732
				width:c.min[1]},
733
			{key:"max", sortable:true, label: c.max[0],
734
				sortOptions: {defaultDir:d},
735
				formatter:f,
736
				width:c.max[1]},
737
			{key:"total", sortable:true, label: c.total[0],
738
				sortOptions: {defaultDir:d},
739
				formatter:f,
740
				width:c.total[1]},
741
			{key:"pct", sortable:true, label: c.pct[0],
742
				sortOptions: {defaultDir:d},
743
				formatter:formatPercent,
744
				width:c.pct[1]}
745
		];
746
 
747
		this._dataTable = new YAHOO.widget.DataTable(this._tableEl, cols, ds, {
748
			scrollable:true,
749
			height:this.get("tableHeight"),
750
			initialRequest:null,
751
			sortedBy: {
752
				key: "total",
753
				dir: YAHOO.widget.DataTable.CLASS_DESC
754
			}
755
		});
756
		var dt = this._dataTable;
757
 
758
		//Wire up DataTable events to drive the rest of the UI.
759
		dt.subscribe("sortedByChange", this._sortedByChange, this, true);
760
		dt.subscribe("renderEvent", this._dataTableRenderHandler, this, true);
761
		dt.subscribe("initEvent", this._dataTableRenderHandler, this, true);
762
		Event.on(this._tableEl.getElementsByTagName("th"), "click", this._thClickHandler, this, true);
763
		YAHOO.log("DataTable initialized.", "info", "ProfilerViewer");
764
	};
765
 
766
	/**
767
	 * Proxy the sort event in DataTable into the ProfilerViewer
768
	 * attribute.
769
	 * @method _sortedByChange
770
	 * @private
771
	 **/
772
	proto._sortedByChange = function(o) {
773
		if(o.newValue && o.newValue.key) {
774
			YAHOO.log("Relaying DataTable sortedBy value change; new key: " + o.newValue.key + "; new direction: " + o.newValue.dir + ".", "info", "ProfilerViewer");
775
			this.set("sortedBy", {key: o.newValue.key, dir:o.newValue.dir});
776
		}
777
	};
778
 
779
	/**
780
	 * Proxy the render event in DataTable into the ProfilerViewer
781
	 * attribute.
782
	 * @method _dataTableRenderHandler
783
	 * @private
784
	 **/
785
	proto._dataTableRenderHandler = function(o) {
786
		YAHOO.log("DataTable's render event has fired.", "info", "ProfilerViewer");
787
		this._setBusyState(false);
788
	};
789
 
790
	/**
791
	 * Event handler for clicks on the DataTable's sortable column
792
	 * heads.
793
	 * @method _thClickHandler
794
	 * @private
795
	 **/
796
	proto._thClickHandler = function(o) {
797
		YAHOO.log("DataTable's header row was clicked for sorting.", "info", "ProfilerViewer");
798
		this._setBusyState(true);
799
	};
800
 
801
	/**
802
	 * Refresh DataTable, getting new data from Profiler.
803
	 * @method _refreshDataTable
804
	 * @private
805
	 **/
806
	proto._refreshDataTable = function(args) {
807
		YAHOO.log("Beginning to refresh DataTable contents...", "info", "ProfilerViewer");
808
		var dt = this._dataTable;
809
		dt.getDataSource().sendRequest("", dt.onDataReturnInitializeTable, dt);
810
		YAHOO.log("DataTable refresh complete.", "info", "ProfilerViewer");
811
	};
812
 
813
	/**
814
	 * Refresh chart, getting new data from table.
815
	 * @method _refreshChart
816
	 * @private
817
	 **/
818
	proto._refreshChart = function() {
819
		YAHOO.log("Beginning to refresh Chart contents...", "info", "ProfilerViewer");
820
 
821
		switch (this.get("sortedBy").key) {
822
			case "fn":
823
				/*Keep the same data on the chart, but force update to
824
				  reflect new sort order on function/method name: */
825
				this._chart.set("dataSource", this._chart.get("dataSource"));
826
				/*no further action necessary; chart redraws*/
827
				return;
828
			case "calls":
829
				/*Null out the xAxis formatting before redrawing chart.*/
830
				this._chart.set("xAxis", this._chartAxisDefinitionPlain);
831
				break;
832
			case "pct":
833
				this._chart.set("xAxis", this._chartAxisDefinitionPercent);
834
				break;
835
			default:
836
				/*Set the default xAxis; redraw legend; set the new series definition.*/
837
				this._chart.set("xAxis", this._chartAxisDefinitionTime);
838
				break;
839
		}
840
 
841
		this._drawChartLegend();
842
		this._chart.set("series", this._getSeriesDef(this.get("sortedBy").key));
843
 
844
		YAHOO.log("Chart refresh complete.", "info", "ProfilerViewer");
845
	};
846
 
847
	/**
848
	 * Get data for the Chart from DataTable recordset
849
	 * @method _getChartData
850
	 * @private
851
	 */
852
	proto._getChartData = function() {
853
		YAHOO.log("Getting data for chart from function DataSource.", "info", "ProfilerViewer");
854
		//var records = this._getProfilerData();
855
		var records = this._dataTable.getRecordSet().getRecords(0, this.get("maxChartFunctions"));
856
		var arr = [];
857
		for (var i = 0, j = records.length; i<j; i++) {
858
			arr.push(records[i].getData());
859
		}
860
		YAHOO.log("Returning data to Chart: " + YAHOO.lang.dump(arr), "info", "ProfilerViewer");
861
		return arr;
862
	};
863
 
864
	/**
865
	 * Build series definition based on current configuration attributes.
866
	 * @method _getSeriesDef
867
	 * @private
868
	 */
869
	proto._getSeriesDef = function(field) {
870
		var sd = this.get("chartSeriesDefinitions")[field];
871
		var arr = [];
872
		for(var i = 0, j = sd.group.length; i<j; i++) {
873
			var c = this.get("chartSeriesDefinitions")[sd.group[i]];
874
			arr.push(
875
				{displayName:c.displayName,
876
				 xField:c.xField,
877
				 style: {color:c.style.color, size:c.style.size}
878
				}
879
			);
880
		}
881
 
882
		YAHOO.log("Returning new series definition to chart: " + YAHOO.lang.dump(arr), "info", "ProfilerViewer");
883
		return arr;
884
	};
885
 
886
	/**
887
	 * Set up the Chart.
888
	 * @method _initChart
889
	 * @private
890
	 */
891
	proto._initChart = function() {
892
		YAHOO.log("Initializing chart...", "info", "ProfilerViewer");
893
 
894
		this._sizeChartCanvas();
895
 
896
		YAHOO.widget.Chart.SWFURL = this.get("swfUrl");
897
 
898
		var self = this;
899
 
900
		//Create DataSource based on records currently displayed
901
		//at the top of the sort list in the DataTable.
902
		var ds = new YAHOO.util.DataSource(
903
			//force the jsfunction DataSource to run in the scope of
904
			//the ProfilerViewer, not in the YAHOO.util.DataSource scope:
905
			function() {
906
				return self._getChartData.call(self);
907
			},
908
			{
909
				responseType: YAHOO.util.DataSource.TYPE_JSARRAY,
910
				maxCacheEntries: 0
911
			}
912
		);
913
 
914
		ds.responseSchema =
915
		{
916
			fields: [ "fn", "avg", "calls", "max", "min", "total", "pct" ]
917
		};
918
 
919
		ds.subscribe('responseEvent', this._sizeChartCanvas, this, true);
920
 
921
		//Set up the chart itself.
922
		this._chartAxisDefinitionTime = new YAHOO.widget.NumericAxis();
923
		this._chartAxisDefinitionTime.labelFunction = "YAHOO.widget.ProfilerViewer.timeAxisLabelFunction";
924
 
925
		this._chartAxisDefinitionPercent = new YAHOO.widget.NumericAxis();
926
		this._chartAxisDefinitionPercent.labelFunction = "YAHOO.widget.ProfilerViewer.percentAxisLabelFunction";
927
 
928
		this._chartAxisDefinitionPlain = new YAHOO.widget.NumericAxis();
929
 
930
		this._chart = new YAHOO.widget.BarChart( this._chartEl, ds,
931
		{
932
			yField: "fn",
933
			series: this._getSeriesDef(this.get("sortedBy").key),
934
			style: this.get("chartStyle"),
935
			xAxis: this._chartAxisDefinitionTime
936
		} );
937
 
938
		this._drawChartLegend();
939
		this._chartInitialized = true;
940
		this._dataTable.unsubscribe("initEvent", this._initChart, this);
941
		this._dataTable.subscribe("initEvent", this._refreshChart, this, true);
942
 
943
		YAHOO.log("Chart initialization complete.", "info", "ProfilerViewer");
944
	};
945
 
946
	/**
947
	 * Set up the Chart's legend
948
	 * @method _drawChartLegend
949
	 * @private
950
	 **/
951
	proto._drawChartLegend = function() {
952
		YAHOO.log("Drawing chart legend...", "info", "ProfilerViewer");
953
		var seriesDefs = this.get("chartSeriesDefinitions");
954
		var currentDef = seriesDefs[this.get("sortedBy").key];
955
		var l = this._chartLegendEl;
956
		l.innerHTML = "";
957
		for(var i = 0, j = currentDef.group.length; i<j; i++) {
958
			var c = seriesDefs[currentDef.group[i]];
959
			var dt = document.createElement("dt");
960
			Dom.setStyle(dt, "backgroundColor", "#" + c.style.color);
961
			var dd = document.createElement("dd");
962
			dd.innerHTML = c.displayName;
963
			l.appendChild(dt);
964
			l.appendChild(dd);
965
		}
966
	};
967
 
968
	/**
969
	 * Resize the chart's canvas if based on number of records
970
	 * returned from the chart's datasource.
971
	 * @method _sizeChartCanvas
972
	 * @private
973
	 **/
974
	proto._sizeChartCanvas = function(o) {
975
		YAHOO.log("Resizing chart canvas...", "info", "ProfilerViewer");
976
		var bars = (o) ? o.response.length : this.get("maxChartFunctions");
977
		var s = (bars * 36) + 34;
978
		if (s != parseInt(this._chartElHeight, 10)) {
979
			this._chartElHeight = s;
980
			Dom.setStyle(this._chartEl, "height", s + "px");
981
		}
982
	};
983
 
984
    /**
985
     * setAttributeConfigs TabView specific properties.
986
     * @method initAttributes
987
     * @param {Object} attr Hash of initial attributes
988
	 * @method initAttributes
989
	 * @private
990
     */
991
    proto.initAttributes = function(attr) {
992
		YAHOO.log("Initializing attributes...", "info", "ProfilerViewer");
993
        YAHOO.widget.ProfilerViewer.superclass.initAttributes.call(this, attr);
994
        /**
995
         * The YUI Loader base path from which to pull YUI files needed
996
		 * in the rendering of the ProfilerViewer canvas.  Passed directly
997
		 * to YUI Loader.  Leave blank to draw files from
998
		 * yui.yahooapis.com.
999
         * @attribute base
1000
         * @type string
1001
		 * @default ""
1002
         */
1003
        this.setAttributeConfig('base', {
1004
            value: attr.base
1005
        });
1006
 
1007
        /**
1008
         * The height of the DataTable.  The table will scroll
1009
		 * vertically if the content overflows the specified
1010
		 * height.
1011
         * @attribute tableHeight
1012
         * @type string
1013
		 * @default "15em"
1014
         */
1015
        this.setAttributeConfig('tableHeight', {
1016
            value: attr.tableHeight || "15em",
1017
			method: function(s) {
1018
				if(this._dataTable) {
1019
					this._dataTable.set("height", s);
1020
				}
1021
			}
1022
        });
1023
 
1024
        /**
1025
         * The default column key to sort by.  Valid keys are: fn, calls,
1026
		 * avg, min, max, total.  Valid dir values are:
1027
		 * YAHOO.widget.DataTable.CLASS_ASC and
1028
		 * YAHOO.widget.DataTable.CLASS_DESC (or their
1029
		 * string equivalents).
1030
         * @attribute sortedBy
1031
         * @type string
1032
		 * @default {key:"total", dir:"yui-dt-desc"}
1033
         */
1034
        this.setAttributeConfig('sortedBy', {
1035
            value: attr.sortedBy || {key:"total", dir:"yui-dt-desc"}
1036
        });
1037
 
1038
        /**
1039
         * A filter function to use in selecting functions that will
1040
		 * appear in the ProfilerViewer report.  The function is passed
1041
		 * a function report object and should return a boolean indicating
1042
		 * whether that function should be included in the ProfilerViewer
1043
		 * display.  The argument is structured as follows:
1044
		 *
1045
		 * {
1046
		 *	 	fn: <str function name>,
1047
		 *		calls : <n number of calls>,
1048
		 *		avg : <n average call duration>,
1049
		 *		max: <n duration of longest call>,
1050
		 *		min: <n duration of shortest call>,
1051
		 *		total: <n total time of all calls>
1052
		 *		points : <array time in ms of each call>
1053
		 *	}
1054
		 *
1055
		 * For example, you would use the follwing filter function to
1056
		 * return only functions that have been called at least once:
1057
		 *
1058
		 * 	function(o) {
1059
		 *		return (o.calls > 0);
1060
		 *	}
1061
		 *
1062
         * @attribute filter
1063
         * @type function
1064
		 * @default null
1065
         */
1066
        this.setAttributeConfig('filter', {
1067
            value: attr.filter || null,
1068
			validator: YAHOO.lang.isFunction
1069
        });
1070
 
1071
		/**
1072
		 * The path to the YUI Charts swf file; must be a full URI
1073
		 * or a path relative to the page being profiled. Changes at runtime
1074
		 * not supported; pass this value in at instantiation.
1075
		 * @attribute swfUrl
1076
		 * @type string
1077
		 * @default "http://yui.yahooapis.com/2.5.0/build/charts/assets/charts.swf"
1078
		 */
1079
		this.setAttributeConfig('swfUrl', {
1080
			value: attr.swfUrl || "http://yui.yahooapis.com/2.5.0/build/charts/assets/charts.swf"
1081
		});
1082
 
1083
        /**
1084
         * The maximum number of functions to profile in the chart. The
1085
		 * greater the number of functions, the greater the height of the
1086
		 * chart canvas.
1087
		 * height.
1088
         * @attribute maxChartFunctions
1089
         * @type int
1090
		 * @default 6
1091
         */
1092
        this.setAttributeConfig('maxChartFunctions', {
1093
            value: attr.maxChartFunctions || 6,
1094
			method: function(s) {
1095
				if(this._rendered) {
1096
					this._sizeChartCanvas();
1097
				}
1098
			},
1099
			validator: YAHOO.lang.isNumber
1100
        });
1101
 
1102
        /**
1103
         * The style object that defines the chart's visual presentation.
1104
		 * Conforms to the style attribute passed to the Charts Control
1105
		 * constructor.  See Charts Control User's Guide for more information
1106
		 * on how to format this object.
1107
         * @attribute chartStyle
1108
         * @type obj
1109
		 * @default See JS source for default definitions.
1110
         */
1111
        this.setAttributeConfig('chartStyle', {
1112
            value: 	attr.chartStyle || {
1113
				font:
1114
					{
1115
						name: "Arial",
1116
						color: 0xeeee5c,
1117
						size: 12
1118
					},
1119
					background:
1120
					{
1121
						color: "6e6e63"
1122
					}
1123
				},
1124
			method: function() {
1125
					if(this._rendered && this.get("showChart")) {
1126
						this._refreshChart();
1127
					}
1128
				}
1129
        });
1130
 
1131
        /**
1132
         * The series definition information to use when charting
1133
		 * specific fields on the chart.  "displayName", "xField",
1134
		 * and "style" members are used to construct the series
1135
		 * definition; the "group" member is the array of fields
1136
		 * that should be charted when the table is sorted by a
1137
		 * given field. The "displayName" string value will be
1138
		 * treated as markup and inserted into the DOM with innerHTML.
1139
         * @attribute chartSeriesDefinitions
1140
         * @type obj
1141
		 * @default See JS source for full default definitions.
1142
         */
1143
        this.setAttributeConfig('chartSeriesDefinitions', {
1144
            value: 	attr.chartSeriesDefinitions ||  {
1145
						total: {
1146
							displayName: PV.STRINGS.colHeads.total[0],
1147
							xField: "total",
1148
							style: {color:"4d95dd", size:20},
1149
							group: ["total"]
1150
						},
1151
						calls: {
1152
							displayName: PV.STRINGS.colHeads.calls[0],
1153
							xField: "calls",
1154
							style: {color:"edff9f", size:20},
1155
							group: ["calls"]
1156
						},
1157
						avg: {
1158
							displayName: PV.STRINGS.colHeads.avg[0],
1159
							xField: "avg",
1160
							style: {color:"209daf", size:9},
1161
							group: ["avg", "min", "max"]
1162
						},
1163
						min: {
1164
							displayName: PV.STRINGS.colHeads.min[0],
1165
							xField: "min",
1166
							style: {color:"b6ecf4", size:9},
1167
							group: ["avg", "min", "max"]
1168
						},
1169
						max: {
1170
							displayName: PV.STRINGS.colHeads.max[0],
1171
							xField: "max",
1172
							style: {color:"29c7de", size:9},
1173
							group: ["avg", "min", "max"]
1174
						},
1175
						pct: {
1176
							displayName: PV.STRINGS.colHeads.pct[0],
1177
							xField: "pct",
1178
							style: {color:"C96EDB", size:20},
1179
							group: ["pct"]
1180
						}
1181
				},
1182
			method: function() {
1183
					if(this._rendered && this.get("showChart")) {
1184
						this._refreshChart();
1185
					}
1186
				}
1187
        });
1188
 
1189
        /**
1190
         * The default visibility setting for the viewer canvas. If true,
1191
		 * the viewer will load all necessary files and render itself
1192
		 * immediately upon instantiation; otherwise, the viewer will
1193
		 * load only minimal resources until the user toggles visibility
1194
		 * via the UI.
1195
         * @attribute visible
1196
         * @type boolean
1197
		 * @default false
1198
         */
1199
        this.setAttributeConfig('visible', {
1200
            value: attr.visible || false,
1201
			validator: YAHOO.lang.isBoolean,
1202
			method: function(b) {
1203
				if(b) {
1204
					this._show();
1205
				} else {
1206
					if (this._rendered) {
1207
						this._hide();
1208
					}
1209
				}
1210
			}
1211
        });
1212
 
1213
        /**
1214
         * The default visibility setting for the chart.
1215
         * @attribute showChart
1216
         * @type boolean
1217
		 * @default true
1218
         */
1219
        this.setAttributeConfig('showChart', {
1220
            value: attr.showChart || true,
1221
			validator: YAHOO.lang.isBoolean,
1222
			writeOnce: true
1223
 
1224
        });
1225
 
1226
		YAHOO.widget.ProfilerViewer.superclass.initAttributes.call(this, attr);
1227
 
1228
		YAHOO.log("Attributes initialized.", "info", "ProfilerViewer");
1229
    };
1230
 
1231
})();
1232
 
1233
YAHOO.register("profilerviewer", YAHOO.widget.ProfilerViewer, {version: "2.9.0", build: "2800"});
1234
 
1235
}, '2.9.0' ,{"requires": ["yui2-skin-sam-profilerviewer", "yui2-yuiloader", "yui2-dom", "yui2-event", "yui2-element", "yui2-profiler"]});