3fe8045e1a427a12b5800a93d22d308f80ea6793
1 /***************************************************************
4 * (c) 2010-2011 Stefan Galinski <stefan.galinski@gmail.com>
7 * This script is part of the TYPO3 project. The TYPO3 project is
8 * free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * The GNU General Public License can be found at
14 * http://www.gnu.org/copyleft/gpl.html.
15 * A copy is found in the textfile GPL.txt and important notices to the license
16 * from the author is found in LICENSE.txt distributed with these scripts.
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
30 * Debug panel based upon the widget tab panel
32 * If you want to add a new tab, you can use the addTab or addTabWidget methods. The first one
33 * creates the widget itself. If you need the latter one, you must create the widget yourself.
35 * The drag&drop functionality introduced a new attribute for the widget that should be added
36 * as a tab. It's called "draggableTab" and needs to be set to true, if you want activated
37 * drag&drop for the new tab.
39 * Additional Features:
41 * - Close tabs with a simple wheel/middle click
42 * - utilization of the tabCloseMenu context menu (several closing options)
43 * - Grouping of tabs (Only one nested level allowed!)
45 * @author Stefan Galinski <stefan.galinski@gmail.com>
47 TYPO3
.DebugPanel
= Ext
.extend(Ext
.TabPanel
, {
51 * @var Ext.util.MixedCollection
53 tabGroups
: new Ext
.util
.MixedCollection(),
56 * Indicator if the debug panel is wrapped inside a debug panel
64 * Initializes the widget and merges our defaults with the user-defined ones. The
65 * user-defined settings are preferred.
69 initComponent: function(config
) {
70 config
= config
|| {};
71 Ext
.apply(this, config
, {
72 // activate general tab navigation with mouse wheel support
73 enableTabScroll
: true,
78 // add the context menu actions
79 plugins
: new Ext
.ux
.TabCloseMenu({
80 closeTabText
: TYPO3
.LLL
.core
.tabs_close
,
81 closeOtherTabsText
: TYPO3
.LLL
.core
.tabs_closeOther
,
82 closeAllTabsText
: TYPO3
.LLL
.core
.tabs_closeAll
,
86 itemId
: 'openInBrowserWindow',
87 text
: TYPO3
.LLL
.core
.tabs_openInBrowserWindow
,
90 var tab
= this.plugins
.active
;
91 var group
= '', content
= '';
93 if (tab
.ownerCt
.ownerCt
instanceof Ext
.TabPanel
) {
94 group
= tab
.ownerCt
.title
;
95 content
= tab
.body
.dom
.innerHTML
;
98 tab
.items
.each(function(item
) {
99 content
+= item
.body
.dom
.innerHTML
;
103 this.openBrowserWindow(
115 TYPO3
.DebugPanel
.superclass
.initComponent
.call(this);
119 * Create a drop arrow indicator for the tab drag&drop feature while rendering
124 onRender: function() {
125 this.arrow
= Ext
.DomHelper
.append(
127 '<div class="typo3-debugPanel-dragDropArrowDown"> </div>',
132 TYPO3
.DebugPanel
.superclass
.onRender
.apply(this, arguments
);
140 onCollapse: function() {
141 TYPO3
.DebugPanel
.superclass
.onCollapse
.apply(this, arguments
);
149 onExpand: function() {
150 TYPO3
.DebugPanel
.superclass
.onExpand
.apply(this, arguments
);
158 onDestroy: function() {
159 Ext
.destroy(this.arrow
);
160 TYPO3
.DebugPanel
.superclass
.onDestroy
.call(this);
164 * Adds a new tab inside a new debug console tab or inside a new browser window if the
165 * debugInWindow configuration variable is set.
167 * If you need more possibilites, you should use the addTabWidget method.
169 * @see addTabWidget()
170 * @param tabContent String content of the new tab
171 * @param header String tab header
172 * @param group String tab group
173 * @param position Integer position of the new tab
176 addTab: function(tabContent
, header
, group
, position
) {
177 if (TYPO3
.configuration
.debugInWindow
) {
178 this.openBrowserWindow(header
, tabContent
, group
);
180 var tabWidget
= new Ext
.Panel({
189 this.addTabWidget(tabWidget
, group
, position
);
194 * Adds a new tab to the widget
196 * You can inject any Ext component, but you need to create it yourself. If you just
197 * want to add some text into a new tab, you should use the addTab function.
200 * @param tabWidget Component the component that should be added as a new tab
201 * @param group String tab group
202 * @param position Integer position of the new tab
205 addTabWidget: function(tabWidget
, group
, position
) {
208 } else if (this.collapsed
) {
212 // Move the widget into a tab group?
214 if (typeof group
!== 'undefined' && group
!== '' && !this.isTabChildren
) {
215 if (this.tabGroups
.indexOfKey(group
) === -1) {
216 tabGroup
= new TYPO3
.DebugPanel({
225 this.addTabWidget(tabGroup
);
227 this.tabGroups
.add(group
, tabGroup
);
229 tabGroup
= this.tabGroups
.key(group
);
233 // recalculate position if necessary
234 if (typeof position
=== 'undefined') {
235 position
= tabGroup
.items
.getCount();
238 // hide the debug panel if the last element is closed
239 tabWidget
.on('destroy', function(element
) {
240 if (this.isTabChildren
) {
241 if (!this.items
.getCount()) {
242 this.tabParent
.remove(this.tabParent
.tabGroups
.key(this.title
));
245 if (!this.items
.getCount()) {
247 this.ownerCt
.doLayout();
249 this.tabGroups
.removeKey(element
.title
);
253 // add drag&drop and the wheel click functionality
254 tabWidget
.on('afterlayout', function(element
) {
255 Ext
.get(this.id
+ '__' + element
.id
).on('mousedown', function(event
) {
256 if (!Ext
.isIE6
&& !Ext
.isIE7
) {
257 if ((Ext
.isIE
&& event
.button
=== 1) ||
258 (!Ext
.isIE
&& event
.browserEvent
.button
=== 1)
261 this.remove(tabWidget
);
268 if (tabWidget
.draggableTab
) {
269 this.initDragAndDropForTab(tabWidget
);
273 // add the widget as a new tab
274 tabGroup
.insert(position
, tabWidget
).show();
275 tabGroup
.ownerCt
.doLayout();
279 * Extends the tab item with drag&drop functionality.
281 * @param item Component the tab widget
284 initDragAndDropForTab: function(item
) {
285 item
.tabDragZone
= new Ext
.dd
.DragZone(this.id
+ '__' + item
.id
, {
289 * Reintroduces the simple click event on a tab element.
293 b4MouseDown : function() {
295 Ext
.dd
.DragZone
.superclass
.b4MouseDown
.apply(this, arguments
);
299 * On receipt of a mousedown event, see if it is within a draggable element.
300 * Return a drag data object if so. The data object can contain arbitrary application
301 * data, but it should also contain a DOM element in the ddel property to provide
304 * @param event Ext.EventObject
307 getDragData: function(event
) {
308 var sourceElement
= event
.getTarget(item
.itemSelector
, 10);
310 var dragComponent
= sourceElement
.cloneNode(true);
311 dragComponent
.id
= Ext
.id();
314 sourceEl
: sourceElement
,
315 repairXY
: Ext
.fly(sourceElement
).getXY()
317 return item
.dragData
;
324 * Provide coordinates for the proxy to slide back to on failed drag.
325 * This is the original XY coordinates of the draggable element.
327 * @return x,y coordinations of the original component position
329 getRepairXY: function() {
330 return this.dragData
.repairXY
;
334 item
.tabDropZone
= new Ext
.dd
.DropZone(this.id
+ '__' + item
.id
, {
339 * If the mouse is over a tab element, return that node. This is
340 * provided as the "target" parameter in all "onNodeXXXX" node event
343 * @param event Ext.EventObject
344 * @return the tab element or boolean false
346 getTargetFromEvent: function(event
) {
347 var tabElement
= Ext
.get(event
.getTarget()).findParentNode('li');
348 if (tabElement
!== null) {
356 * On entry into a target node, highlight that node.
358 * @param target string id of the target element
361 onNodeEnter : function(target
) {
362 Ext
.get(target
).addClass('typo3-debugPanel-dragDropOver');
366 * On exit from a target node, unhighlight that node.
368 * @param target string id of the target element
371 onNodeOut : function(target
) {
372 Ext
.get(target
).removeClass('typo3-debugPanel-dragDropOver');
373 this.debugPanel
.arrow
.hide();
377 * While over a target node, return the default drop allowed class which
378 * places a "tick" icon into the drag proxy. Also the arrow position is
381 * @param target string id of the target element
382 * @param proxy Ext.dd.DDProxy proxy element
383 * @param event Ext.EventObject
384 * @return default dropAllowed class or a boolean false
386 onNodeOver : function(target
, proxy
, event
) {
387 // set arrow position
388 var element
= Ext
.get(target
);
390 var tabLeft
= element
.getX();
391 var tabMiddle
= tabLeft
+ element
.dom
.clientWidth
/ 2;
392 var tabRight
= tabLeft
+ element
.dom
.clientWidth
;
393 if (event
.getPageX() <= tabMiddle
) {
398 this.debugPanel
.arrow
.setTop(this.el
.getY() - 8).setLeft(left
- 9).show();
401 if (proxy
.handleElId
!== target
.id
) {
402 return Ext
.dd
.DropZone
.prototype.dropAllowed
;
409 * On node drop we move the dragged tab element at the position of
410 * the dropped element.
412 * @param target string id of the target element
413 * @param proxy Ext.dd.DDProxy proxy element
414 * @param event Ext.EventObject
415 * @return true or false
417 onNodeDrop : function(target
, proxy
, event
) {
418 if (proxy
.handleElId
=== target
.id
) {
422 var dropPanelId
= target
.id
.substring(this.debugPanel
.id
.length
+ 2);
423 var dragPanelId
= proxy
.handleElId
.substring(this.debugPanel
.id
.length
+ 2);
425 var dropPanelPosition
= this.debugPanel
.items
.indexOfKey(dropPanelId
);
426 var dragPanelPosition
= this.debugPanel
.items
.indexOfKey(dragPanelId
);
428 if (dropPanelPosition
!== undefined &&
429 dropPanelPosition
!== -1 &&
430 dropPanelPosition
<= this.debugPanel
.items
.getCount()
432 // calculate arrow position to decide if the elements needs
433 // to be inserted on the right or left
434 var element
= Ext
.get(target
);
435 var tabMiddle
= element
.getX() + element
.dom
.clientWidth
/ 2;
436 if (dragPanelPosition
> dropPanelPosition
) {
437 if (event
.getPageX() > tabMiddle
) {
438 dropPanelPosition
+= 1;
441 if (event
.getPageX() <= tabMiddle
) {
442 dropPanelPosition
-= 1;
446 var dropEl
= this.debugPanel
.remove(dragPanelId
, false);
447 this.debugPanel
.addTabWidget(dropEl
, '', dropPanelPosition
);
450 this.debugPanel
.arrow
.hide();
457 * Opens debug output in a new browser window
459 * @param title string
460 * @param content string
461 * @param group string
464 openBrowserWindow: function(title
, content
, group
) {
466 group
= group
.replace(' ', '_');
468 var newWindow
= window
.open('', 'TYPO3DebugWindow_' + group
,
469 'width=600,height=400,menubar=0,toolbar=1,status=0,scrollbars=1,resizable=1'
471 if (newWindow
.document
.body
.innerHTML
) {
472 Ext
.DomHelper
.insertHtml('beforeEnd', newWindow
.document
.body
, '<hr>' + content
);
474 newWindow
.document
.writeln(
475 '<html><head><title>Debug: ' + title
+ '(' + group
+ ')</title></head>'
476 + '<body bgcolor=white onLoad="self.focus()">'
481 newWindow
.document
.close()
485 * Wrapper for console.log
490 if (arguments
.length
) {
491 for (var i
= 0; i
< arguments
.length
; i
++) {
492 this.debug(arguments
[i
], 'Log', 'Javascript Console');
498 * Wrapper for console.info
503 if (arguments
.length
) {
504 for (var i
= 0; i
< arguments
.length
; i
++) {
505 this.debug(arguments
[i
], 'Info', 'Javascript Console');
511 * Wrapper for console.warn
516 if (arguments
.length
) {
517 for (var i
= 0; i
< arguments
.length
; i
++) {
518 this.debug(arguments
[i
], 'Warning', 'Javascript Console');
524 * Wrapper for console.error
529 if (arguments
.length
) {
530 for (var i
= 0; i
< arguments
.length
; i
++) {
531 this.debug(arguments
[i
], 'Error', 'Javascript Console');
537 * Debug output from javascript
539 * @param out mixed debug output
540 * @param header string
541 * @param group string
543 debug: function(out
, header
, group
) {
544 var output
= this.printObject(out
);
545 this.addTab(output
, header
, group
);
549 * Converts any string/array/object to a string for printing purposes
551 * @param object object
552 * @param level integer recursion level counter (max. 3 levels)
553 * @param prefix string internal use!
556 printObject: function(object
, level
, prefix
) {
559 prefix
= prefix
|| '';
565 var levelPadding
= '';
566 for(var j
= 0; j
< level
+ 1; ++j
) {
570 if (typeof(object
) === 'object') {
572 for (var item
in object
) {
573 var value
= object
[item
];
575 if (typeof(value
) === 'object') {
576 result
+= levelPadding
+ '"' + prefix
+ item
+ '" ...' + "\n";
577 result
+= this.printObject(value
, level
+ 1, prefix
+ item
+ '.');
579 result
+= levelPadding
+ '"' + prefix
+ item
+
580 '" => "' + value
+ '"' + "\n";
584 // Strings/Chars/Numbers etc.
585 result
= '[' + typeof(object
) + '] ' + object
;
588 return '<pre>' + result
+ '</pre>';
592 * Debug attached events of a given element (e.g. an Ext.Panel component)
594 * Note: This functionality should be used with an activated debug console like firebug!
596 * @param element object to fetch events from
599 debugEvents: function(element
) {
601 // debug events of element
602 Ext
.util
.Observable
.capture(element
, function() {
604 'event "' + arguments
[0] + '" was fired with the following arguments: '
607 for (var i
= 1; i
< arguments
.length
; ++i
) {
608 console
.log(' [' + i
+ '] ', arguments
[i
]);
613 Ext
.util
.Observable
.prototype.fireEvent
=
614 Ext
.util
.Observable
.prototype.fireEvent
.createInterceptor(function() {
615 console
.log(arguments
);
622 Ext
.reg('typo3DebugPanel', TYPO3
.DebugPanel
);