Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
12345 anikendra 1
/**
2
 * Debug Toolbar Javascript.
3
 *
4
 * Creates the DEBUGKIT namespace and provides methods for extending
5
 * and enhancing the Html toolbar. Includes library agnostic Event, Element,
6
 * Cookie and Request wrappers.
7
 *
8
 *
9
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
10
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11
 *
12
 * Licensed under The MIT License
13
 * Redistributions of files must retain the above copyright notice.
14
 *
15
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
16
 * @link          http://cakephp.org CakePHP(tm) Project
17
 * @since         DebugKit 0.1
18
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
19
 */
20
 
21
/* jshint jquery: true */
22
 
23
var DEBUGKIT = function () {
24
	var undef;
25
	return {
26
		module: function (newmodule) {
27
			if (this[newmodule] === undef) {
28
				this[newmodule] = {};
29
				return this[newmodule];
30
			}
31
			return this[newmodule];
32
		}
33
	};
34
}();
35
 
36
(function () {
37
	function versionGTE(a, b) {
38
		var len = Math.min(a.length, b.length);
39
		for (var i = 0; i < len; i++) {
40
			a[i] = parseInt(a[i], 10);
41
			b[i] = parseInt(b[i], 10);
42
			if (a[i] > b[i]) {
43
				return true;
44
			}
45
			if (a[i] < b[i]) {
46
				return false;
47
			}
48
		}
49
		return true;
50
	}
51
 
52
	function versionWithin(version, min, max) {
53
		version = version.split('.');
54
		min = min.split('.');
55
		max = max.split('.');
56
		return versionGTE(version, min) && versionGTE(max, version);
57
	}
58
 
59
	// Look for existing jQuery that matches the requirements.
60
	if (window.jQuery && versionWithin(jQuery.fn.jquery, "1.8", "2.1")) {
61
		DEBUGKIT.$ = window.jQuery;
62
	} else {
63
		// sync load the file. Using document.write() does not block
64
		// in recent versions of chrome.
65
		var req = new XMLHttpRequest();
66
		req.onload = function () {
67
			eval(this.responseText);
68
			// Restore both $ and jQuery to the original values.
69
			DEBUGKIT.$ = jQuery.noConflict(true);
70
		};
71
		req.open('get', window.DEBUGKIT_JQUERY_URL, false);
72
		req.send();
73
	}
74
})();
75
 
76
DEBUGKIT.loader = function () {
77
	return {
78
		// List of methods to run on startup.
79
		_startup: [],
80
 
81
		// Register a new method to be run on dom ready.
82
		register: function (method) {
83
			this._startup.push(method);
84
		},
85
 
86
		init: function () {
87
			for (var i = 0, callback; callback = this._startup[i]; i++) {
88
				callback.init();
89
			}
90
		}
91
	};
92
}();
93
 
94
DEBUGKIT.module('sqlLog');
95
DEBUGKIT.sqlLog = function () {
96
	var $ = DEBUGKIT.$;
97
 
98
	return {
99
		init : function () {
100
			var sqlPanel = $('#sql_log-tab');
101
			var buttons = sqlPanel.find('input');
102
 
103
			// Button handling code for explain links.
104
			// Performs XHR request to get explain query.
105
			var handleButton = function (event) {
106
				event.preventDefault();
107
				var form = $(this.form),
108
					data = form.serialize(),
109
					dbName = form.find('input[name*=ds]').val() || 'default';
110
 
111
				var fetch = $.ajax({
112
					url: this.form.action,
113
					data: data,
114
					type: 'POST',
115
					success : function (response) {
116
						$('#sql-log-explain-' + dbName).html(response);
117
					},
118
					error : function () {
119
						alert('Could not fetch EXPLAIN for query.');
120
					}
121
				});
122
			};
123
 
124
			buttons.filter('.sql-explain-link').on('click', handleButton);
125
		}
126
	};
127
}();
128
DEBUGKIT.loader.register(DEBUGKIT.sqlLog);
129
 
130
//
131
// NOTE DEBUGKIT.Util.Element is Deprecated.
132
//
133
// Util module and Element utility class.
134
DEBUGKIT.module('Util');
135
DEBUGKIT.Util.Element = {
136
 
137
	// Test if an element is a name node.
138
	nodeName: function (element, name) {
139
		return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();
140
	},
141
 
142
	// Return a boolean if the element has the classname
143
	hasClass: function (element, className) {
144
		if (!element.className) {
145
			return false;
146
		}
147
		return element.className.indexOf(className) > -1;
148
	},
149
 
150
	addClass: function (element, className) {
151
		if (!element.className) {
152
			element.className = className;
153
			return;
154
		}
155
		element.className = element.className.replace(/^(.*)$/, '$1 ' + className);
156
	},
157
 
158
	removeClass: function (element, className) {
159
		if (DEBUGKIT.Util.isArray(element)) {
160
			DEBUGKIT.Util.Collection.apply(element, function (element) {
161
				DEBUGKIT.Util.Element.removeClass(element, className);
162
			});
163
		}
164
		if (!element.className) {
165
			return false;
166
		}
167
		element.className = element.className.replace(new RegExp(' ?(' + className + ') ?'), '');
168
	},
169
 
170
	swapClass: function (element, removeClass, addClass) {
171
		if (!element.className) {
172
			return false;
173
		}
174
		element.className = element.className.replace(removeClass, addClass);
175
	},
176
 
177
	show: function (element) {
178
		element.style.display = 'block';
179
	},
180
 
181
	hide: function (element) {
182
		element.style.display = 'none';
183
	},
184
 
185
	// Go between hide() and show() depending on element.style.display
186
	toggle: function (element) {
187
		if (element.style.display === 'none') {
188
			this.show(element);
189
			return;
190
		}
191
		this.hide(element);
192
	},
193
 
194
	_walk: function (element, walk) {
195
		var sibling = element[walk];
196
		while (true) {
197
			if (sibling.nodeType == 1) {
198
				break;
199
			}
200
			sibling = sibling[walk];
201
		}
202
		return sibling;
203
	},
204
 
205
	getNext: function (element) {
206
		return this._walk(element, 'nextSibling');
207
	},
208
 
209
	getPrevious: function (element) {
210
		return this._walk(element, 'previousSibling');
211
	},
212
 
213
	// Get or set an element's height, omit value to get, add value (integer) to set.
214
	height: function (element, value) {
215
		// Get value
216
		if (value === undefined) {
217
			return parseInt(this.getStyle(element, 'height'), 10);
218
		}
219
		element.style.height = value + 'px';
220
	},
221
 
222
	// Gets the style in css format for property
223
	getStyle: function (element, property) {
224
		if (element.currentStyle) {
225
			property = property.replace(/-[a-z]/g, function (match) {
226
				return match.charAt(1).toUpperCase();
227
			});
228
			return element.currentStyle[property];
229
		}
230
		if (window.getComputedStyle) {
231
			return document.defaultView.getComputedStyle(element, null).getPropertyValue(property);
232
		}
233
	}
234
};
235
 
236
//
237
// NOTE DEBUGKIT.Util.Collection is Deprecated.
238
//
239
DEBUGKIT.Util.Collection = {
240
	/**
241
	 * Apply the passed function to each item in the collection.
242
	 * The current element in the collection will be `this` in the callback
243
	 * The callback is also passed the element and the index as arguments.
244
	 * Optionally you can supply a binding parameter to change `this` in the callback.
245
	 */
246
	apply: function (collection, callback, binding) {
247
		var name, thisVar, i = 0, len = collection.length;
248
 
249
		if (len === undefined) {
250
			for (name in collection) {
251
				thisVar = (binding === undefined) ? collection[name] : binding;
252
				callback.apply(thisVar, [collection[name], name]);
253
			}
254
		} else {
255
			for (; i < len; i++) {
256
				thisVar = (binding === undefined) ? collection[i] : binding;
257
				callback.apply(thisVar, [collection[i], i]);
258
			}
259
		}
260
	}
261
};
262
 
263
//
264
// NOTE DEBUGKIT.Util.Event is Deprecated.
265
//
266
// Event binding
267
DEBUGKIT.Util.Event = function () {
268
	var _listeners = {},
269
		_eventId = 0;
270
 
271
	var preventDefault = function () {
272
		this.returnValue = false;
273
	};
274
 
275
	var stopPropagation = function () {
276
		this.cancelBubble = true;
277
	};
278
 
279
	// Fixes IE's broken event object, adds in common methods + properties.
280
	var fixEvent = function (event) {
281
		if (!event.preventDefault) {
282
			event.preventDefault = preventDefault;
283
		}
284
		if (!event.stopPropagation) {
285
			event.stopPropagation = stopPropagation;
286
		}
287
		if (!event.target) {
288
			event.target = event.srcElement || document;
289
		}
290
		if (event.pageX === null && event.clientX !== null) {
291
			var doc = document.body;
292
			event.pageX = event.clientX + (doc.scrollLeft || 0) - (doc.clientLeft || 0);
293
			event.pageY = event.clientY + (doc.scrollTop || 0) - (doc.clientTop || 0);
294
		}
295
		return event;
296
	};
297
 
298
	return {
299
		// Bind an event listener of type to element, handler is your method.
300
		addEvent: function (element, type, handler, capture) {
301
			capture = (capture === undefined) ? false : capture;
302
 
303
			var callback = function (event) {
304
				event = fixEvent(event || window.event);
305
				handler.apply(element, [event]);
306
			};
307
 
308
			if (element.addEventListener) {
309
				element.addEventListener(type, callback, capture);
310
			} else if (element.attachEvent) {
311
				type = 'on' + type;
312
				element.attachEvent(type, callback);
313
			} else {
314
				type = 'on' + type;
315
				element[type] = callback;
316
			}
317
			_listeners[++_eventId] = {element: element, type: type, handler: callback};
318
		},
319
 
320
		// Destroy an event listener. requires the exact same function as was used for attaching
321
		// the event.
322
		removeEvent: function (element, type, handler) {
323
			if (element.removeEventListener) {
324
				element.removeEventListener(type, handler, false);
325
			} else if (element.detachEvent) {
326
				type = 'on' + type;
327
				element.detachEvent(type, handler);
328
			} else {
329
				type = 'on' + type;
330
				element[type] = null;
331
			}
332
		},
333
 
334
		// Bind an event to the DOMContentLoaded or other similar event.
335
		domready: function (callback) {
336
			if (document.addEventListener) {
337
				return document.addEventListener('DOMContentLoaded', callback, false);
338
			}
339
 
340
			if (document.all && !window.opera) {
341
				// Define a "blank" external JavaScript tag
342
				document.write(
343
					'<script type="text/javascript" id="__domreadywatcher" defer="defer" src="javascript:void(0)"><\/script>'
344
				);
345
				var contentloadtag = document.getElementById('__domreadywatcher');
346
				contentloadtag.onreadystatechange = function () {
347
					if (this.readyState === 'complete') {
348
						callback();
349
					}
350
				};
351
				contentloadtag = null;
352
				return;
353
			}
354
 
355
			if (/Webkit/i.test(navigator.userAgent)) {
356
				var _timer = setInterval(function () {
357
					if (/loaded|complete/.test(document.readyState)) {
358
						clearInterval(_timer);
359
						callback();
360
					}
361
				}, 10);
362
			}
363
		},
364
 
365
		// Unload all the events attached by DebugKit. Fix any memory leaks.
366
		unload: function () {
367
			var listener;
368
			for (var i in _listeners) {
369
				listener = _listeners[i];
370
				try {
371
					this.removeEvent(listener.element, listener.type, listener.handler);
372
				} catch (e) {}
373
				delete _listeners[i];
374
			}
375
			delete _listeners;
376
		}
377
	};
378
}();
379
 
380
// Cookie utility
381
DEBUGKIT.Util.Cookie = function () {
382
	var cookieLife = 60;
383
 
384
// Public methods
385
	return {
386
		/**
387
		 * Write to cookie.
388
		 *
389
		 * @param [string] name Name of cookie to write.
390
		 * @param [mixed] value Value to write to cookie.
391
		 */
392
		write: function (name, value) {
393
			var date = new Date();
394
			date.setTime(date.getTime() + (cookieLife * 24 * 60 * 60 * 1000));
395
			var expires = '; expires=' + date.toGMTString();
396
			document.cookie = name + '=' + value + expires + '; path=/';
397
			return true;
398
		},
399
 
400
		/**
401
		 * Read from the cookie.
402
		 *
403
		 * @param [string] name Name of cookie to read.
404
		 */
405
		read: function (name) {
406
			name = name + '=';
407
			var cookieJar = document.cookie.split(';');
408
			var cookieJarLength = cookieJar.length;
409
			for (var i = 0; i < cookieJarLength; i++) {
410
				var chips = cookieJar[i];
411
				// Trim leading spaces
412
				while (chips.charAt(0) === ' ') {
413
					chips = chips.substring(1, chips.length);
414
				}
415
				if (chips.indexOf(name) === 0) {
416
					return chips.substring(name.length, chips.length);
417
				}
418
			}
419
			return false;
420
		},
421
 
422
		/**
423
		 * Delete a cookie by name.
424
		 *
425
		 * @param [string] name of cookie to delete.
426
		 */
427
		del: function (name) {
428
			var date = new Date();
429
			date.setFullYear(2000, 0, 1);
430
			var expires = ' ; expires=' + date.toGMTString();
431
			document.cookie = name + '=' + expires + '; path=/';
432
		}
433
	};
434
}();
435
 
436
//
437
// NOTE DEBUGKIT.Util.merge is Deprecated.
438
//
439
 
440
/**
441
 * Object merge takes any number of arguments and glues them together.
442
 *
443
 * @param [Object] one first object
444
 * @return object
445
 */
446
DEBUGKIT.Util.merge = function () {
447
	var out = {};
448
	var argumentsLength = arguments.length;
449
	for (var i = 0; i < argumentsLength; i++) {
450
		var current = arguments[i];
451
		for (var prop in current) {
452
			if (current[prop] !== undefined) {
453
				out[prop] = current[prop];
454
			}
455
		}
456
	}
457
	return out;
458
};
459
 
460
//
461
// NOTE DEBUGKIT.Util.isArray is Deprecated.
462
//
463
 
464
/**
465
 * Check if the given object is an array.
466
 */
467
DEBUGKIT.Util.isArray = function (test) {
468
	return Object.prototype.toString.call(test) === '[object Array]';
469
};
470
 
471
//
472
// NOTE DEBUGKIT.Util.Request is Deprecated.
473
//
474
// Simple wrapper for XmlHttpRequest objects.
475
DEBUGKIT.Util.Request = function (options) {
476
	var _defaults = {
477
		onComplete : function () {},
478
		onRequest : function () {},
479
		onFail : function () {},
480
		method : 'GET',
481
		async : true,
482
		headers : {
483
			'X-Requested-With': 'XMLHttpRequest',
484
			'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
485
		}
486
	};
487
 
488
	var self = this;
489
	this.options = DEBUGKIT.Util.merge(_defaults, options);
490
	this.options.method = this.options.method.toUpperCase();
491
 
492
	var ajax = this.createObj();
493
	this.transport = ajax;
494
 
495
	// Event assignment
496
	this.onComplete = this.options.onComplete;
497
	this.onRequest = this.options.onRequest;
498
	this.onFail = this.options.onFail;
499
 
500
	this.send = function (url, data) {
501
		if (this.options.method === 'GET' && data) {
502
			url = url + ((url.charAt(url.length - 1) === '?') ? '&' : '?') + data; //check for ? at the end of the string
503
			data = null;
504
		}
505
		// Open connection
506
		this.transport.open(this.options.method, url, this.options.async);
507
 
508
		// Set statechange and pass the active XHR object to it. From here it handles all status changes.
509
		this.transport.onreadystatechange = function () {
510
			self.onReadyStateChange.apply(self, arguments);
511
		};
512
		for (var key in this.options.headers) {
513
			this.transport.setRequestHeader(key, this.options.headers[key]);
514
		}
515
		if (typeof data === 'object') {
516
			data = this.serialize(data);
517
		}
518
		if (data) {
519
			this.transport.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
520
		}
521
		this.onRequest();
522
		this.transport.send(data);
523
	};
524
};
525
 
526
DEBUGKIT.Util.Request.prototype.onReadyStateChange = function () {
527
	if (this.transport.readyState !== 4) {
528
		return;
529
	}
530
	if (this.transport.status === 200 || this.transport.status > 300 && this.transport.status < 400) {
531
		this.response = {
532
			xml: this.transport.responseXML,
533
			text: this.transport.responseText
534
		};
535
 
536
		if (typeof this.onComplete === 'function') {
537
			this.onComplete.apply(this, [this, this.response]);
538
		} else {
539
			return this.response;
540
		}
541
	} else if (this.transport.status > 400) {
542
		if (typeof this.onFail === 'function') {
543
			this.onFail.apply(this, []);
544
		} else {
545
			console.error('Request failed');
546
		}
547
	}
548
};
549
 
550
/**
551
 * Creates cross-broswer XHR object used for requests.
552
 * Tries using the standard XmlHttpRequest, then IE's wacky ActiveX Objects.
553
 */
554
DEBUGKIT.Util.Request.prototype.createObj = function () {
555
	var request = null;
556
	try {
557
		request = new XMLHttpRequest();
558
	} catch (MS) {
559
		try {
560
			request = new ActiveXObject('Msxml2.XMLHTTP');
561
		} catch (old_MS) {
562
			try {
563
				request = new ActiveXObject('Microsoft.XMLHTTP');
564
			} catch (failure) {
565
				request = null;
566
			}
567
		}
568
	}
569
	return request;
570
};
571
 
572
/**
573
 * Serializes an object literal into a querystring.
574
 */
575
DEBUGKIT.Util.Request.prototype.serialize = function (data) {
576
	var out = '';
577
	for (var name in data) {
578
		if (data.hasOwnProperty(name)) {
579
			out += name + '=' + data[name] + '&';
580
		}
581
	}
582
	return out.substring(0, out.length - 1);
583
};
584
 
585
 
586
// Basic toolbar module.
587
DEBUGKIT.toolbar = function () {
588
	// Shortcuts
589
	var Cookie = DEBUGKIT.Util.Cookie,
590
		$ = DEBUGKIT.$,
591
		toolbarHidden = false;
592
 
593
	return {
594
		elements: {},
595
		panels: {},
596
 
597
		init: function () {
598
			var i, element, lists, index, _this = this;
599
 
600
			this.elements.toolbar = $('#debug-kit-toolbar');
601
 
602
			if (this.elements.toolbar.length === 0) {
603
				throw new Error('Toolbar not found, make sure you loaded it.');
604
			}
605
 
606
			this.elements.panel = $('#panel-tabs');
607
			this.elements.panel.find('.panel-tab').each(function (i, panel) {
608
				_this.addPanel(panel);
609
			});
610
 
611
			lists = this.elements.toolbar.find('.depth-0');
612
 
613
			this.makeNeatArray(lists);
614
			this.deactivatePanel(true);
615
		},
616
 
617
		// Add a panel to the toolbar
618
		addPanel: function (tab) {
619
			var button, content, _this = this;
620
			var panel = {
621
				id : false,
622
				element : tab,
623
				button : undefined,
624
				content : undefined,
625
				active : false
626
			};
627
			tab = $(tab);
628
			button = tab.children('a');
629
 
630
			panel.id = button.attr('href').replace(/^#/, '');
631
			panel.button = button;
632
			panel.content = tab.find('.panel-content');
633
 
634
			if (!panel.id || panel.content.length === 0) {
635
				return false;
636
			}
637
			this.makePanelDraggable(panel);
638
			this.makePanelMinMax(panel);
639
 
640
			button.on('click', function (event) {
641
				event.preventDefault();
642
				_this.togglePanel(panel.id);
643
			});
644
 
645
			this.panels[panel.id] = panel;
646
			return panel.id;
647
		},
648
 
649
		// Find the handle element and make the panel drag resizable.
650
		makePanelDraggable: function (panel) {
651
 
652
			// Create a variable in the enclosing scope, for scope tricks.
653
			var currentElement = null;
654
 
655
			// Use the elements startHeight stored Event.pageY and current Event.pageY to
656
			// resize the panel.
657
			var mouseMoveHandler = function (event) {
658
				event.preventDefault();
659
				if (!currentElement) {
660
					return;
661
				}
662
				var newHeight = currentElement.data('startHeight') + (event.pageY - currentElement.data('startY'));
663
				currentElement.parent().height(newHeight);
664
			};
665
 
666
			// Handle the mouseup event, remove the other listeners so the panel
667
			// doesn't continue to resize.
668
			var mouseUpHandler = function (event) {
669
				currentElement = null;
670
				$(document).off('mousemove', mouseMoveHandler).off('mouseup', mouseUpHandler);
671
			};
672
 
673
			var mouseDownHandler = function (event) {
674
				event.preventDefault();
675
 
676
				currentElement = $(this);
677
				currentElement.data('startY', event.pageY);
678
				currentElement.data('startHeight', currentElement.parent().height());
679
 
680
				// Attach to document so mouse doesn't have to stay precisely on the 'handle'.
681
				$(document).on('mousemove', mouseMoveHandler)
682
					.on('mouseup', mouseUpHandler);
683
			};
684
 
685
			panel.content.find('.panel-resize-handle').on('mousedown', mouseDownHandler);
686
		},
687
 
688
		// Make the maximize button work on the panels.
689
		makePanelMinMax: function (panel) {
690
			var _oldHeight;
691
 
692
			var maximize = function () {
693
				if (!_oldHeight) {
694
					_oldHeight = this.parentNode.offsetHeight;
695
				}
696
				var windowHeight = window.innerHeight;
697
				var panelHeight = windowHeight - this.parentNode.offsetTop;
698
				$(this.parentNode).height(panelHeight);
699
				$(this).text('-');
700
			};
701
 
702
			var minimize = function () {
703
				$(this.parentNode).height(_oldHeight);
704
				$(this).text('+');
705
				_oldHeight = null;
706
			};
707
 
708
			var state = 1;
709
			var toggle = function (event) {
710
				event.preventDefault();
711
				if (state === 1) {
712
					maximize.call(this);
713
					state = 0;
714
				} else {
715
					state = 1;
716
					minimize.call(this);
717
				}
718
			};
719
 
720
			panel.content.find('.panel-toggle').on('click', toggle);
721
		},
722
 
723
		// Toggle a panel
724
		togglePanel: function (id) {
725
			if (this.panels[id] && this.panels[id].active) {
726
				this.deactivatePanel(true);
727
			} else {
728
				this.deactivatePanel(true);
729
				this.activatePanel(id);
730
			}
731
		},
732
 
733
		// Make a panel active.
734
		activatePanel: function (id, unique) {
735
			if (this.panels[id] !== undefined && !this.panels[id].active) {
736
				var panel = this.panels[id];
737
				if (panel.content.length > 0) {
738
					panel.content.css('display', 'block');
739
				}
740
 
741
				var contentHeight = panel.content.find('.panel-content-data').height() + 70;
742
				if (contentHeight <= (window.innerHeight / 2)) {
743
					panel.content.height(contentHeight);
744
				}
745
 
746
				panel.button.addClass('active');
747
				panel.active = true;
748
				return true;
749
			}
750
			return false;
751
		},
752
 
753
		// Deactivate a panel. use true to hide all panels.
754
		deactivatePanel: function (id) {
755
			if (id === true) {
756
				for (var i in this.panels) {
757
					this.deactivatePanel(i);
758
				}
759
				return true;
760
			}
761
			if (this.panels[id] !== undefined) {
762
				var panel = this.panels[id];
763
				if (panel.content !== undefined) {
764
					panel.content.hide();
765
				}
766
				panel.button.removeClass('active');
767
				panel.active = false;
768
				return true;
769
			}
770
			return false;
771
		},
772
 
773
		// Bind events for all the collapsible arrays.
774
		makeNeatArray: function (lists) {
775
			lists.find('ul').hide()
776
				.parent().addClass('expandable collapsed');
777
 
778
			lists.on('click', 'li', function (event) {
779
				event.stopPropagation();
780
				$(this).children('ul').toggle().toggleClass('expanded collapsed');
781
			});
782
		}
783
	};
784
}();
785
DEBUGKIT.loader.register(DEBUGKIT.toolbar);
786
 
787
DEBUGKIT.module('historyPanel');
788
DEBUGKIT.historyPanel = function () {
789
	var toolbar = DEBUGKIT.toolbar,
790
		$ = DEBUGKIT.$,
791
		historyLinks;
792
 
793
	// Private methods to handle JSON response and insertion of
794
	// new content.
795
	var switchHistory = function (response) {
796
 
797
		historyLinks.removeClass('loading');
798
 
799
		$.each(toolbar.panels, function (id, panel) {
800
			if (panel.content === undefined || response[id] === undefined) {
801
				return;
802
			}
803
 
804
			var regionDiv = panel.content.find('.panel-resize-region');
805
			if (!regionDiv.length) {
806
				return;
807
			}
808
 
809
			var regionDivs = regionDiv.children();
810
 
811
			regionDivs.filter('div').hide();
812
			regionDivs.filter('.panel-history').each(function (i, panelContent) {
813
				var panelId = panelContent.id.replace('-history', '');
814
				if (response[panelId]) {
815
					panelContent = $(panelContent);
816
					panelContent.html(response[panelId]);
817
					var lists = panelContent.find('.depth-0');
818
					toolbar.makeNeatArray(lists);
819
				}
820
				panelContent.show();
821
			});
822
		});
823
	};
824
 
825
	// Private method to handle restoration to current request.
826
	var restoreCurrentState = function () {
827
		var id, i, panelContent, tag;
828
 
829
		historyLinks.removeClass('loading');
830
 
831
		$.each(toolbar.panels, function (panel, id) {
832
			if (panel.content === undefined) {
833
				return;
834
			}
835
			var regionDiv = panel.content.find('.panel-resize-region');
836
			if (!regionDiv.length) {
837
				return;
838
			}
839
			var regionDivs = regionDiv.children();
840
			regionDivs.filter('div').show()
841
				.end()
842
				.filter('.panel-history').hide();
843
		});
844
	};
845
 
846
	function handleHistoryLink(event) {
847
		event.preventDefault();
848
 
849
		historyLinks.removeClass('active');
850
		$(this).addClass('active loading');
851
 
852
		if (this.id === 'history-restore-current') {
853
			restoreCurrentState();
854
			return false;
855
		}
856
 
857
		var xhr = $.ajax({
858
			url: this.href,
859
			type: 'GET',
860
			dataType: 'json'
861
		});
862
		xhr.success(switchHistory).fail(function () {
863
			alert('History retrieval failed');
864
		});
865
	}
866
 
867
	return {
868
		init : function () {
869
			if (toolbar.panels.history === undefined) {
870
				return;
871
			}
872
 
873
			historyLinks = toolbar.panels.history.content.find('.history-link');
874
			historyLinks.on('click', handleHistoryLink);
875
		}
876
	};
877
}();
878
DEBUGKIT.loader.register(DEBUGKIT.historyPanel);
879
 
880
//Add events + behaviors for toolbar collapser.
881
DEBUGKIT.toolbarToggle = function () {
882
	var toolbar = DEBUGKIT.toolbar,
883
		$ = DEBUGKIT.$,
884
		Cookie = DEBUGKIT.Util.Cookie,
885
		toolbarHidden = false;
886
 
887
	return {
888
		init: function () {
889
			var button = $('#hide-toolbar'),
890
				self = this;
891
 
892
			button.on('click', function (event) {
893
				event.preventDefault();
894
				self.toggleToolbar();
895
			});
896
 
897
			var toolbarState = Cookie.read('toolbarDisplay');
898
			if (toolbarState !== 'show') {
899
				toolbarHidden = false;
900
				this.toggleToolbar();
901
			}
902
		},
903
 
904
		toggleToolbar: function () {
905
			var display = toolbarHidden ? 'show' : 'hide';
906
			$.each(toolbar.panels, function (i, panel) {
907
				$(panel.element)[display]();
908
				Cookie.write('toolbarDisplay', display);
909
			});
910
			toolbarHidden = !toolbarHidden;
911
 
912
			if (toolbarHidden) {
913
				$('#debug-kit-toolbar').addClass('minimized');
914
			} else {
915
				$('#debug-kit-toolbar').removeClass('minimized');
916
			}
917
 
918
			return false;
919
		}
920
	};
921
}();
922
DEBUGKIT.loader.register(DEBUGKIT.toolbarToggle);
923
 
924
DEBUGKIT.$(document).ready(function () {
925
	DEBUGKIT.loader.init();
926
});