r21325: delete children in reverse order since the array is manipulated during the...
[samba.git] / webapps / qooxdoo-0.6.3-sdk / frontend / framework / source / class / qx / dev / log / WindowAppender.js
1 /* ************************************************************************
2
3    qooxdoo - the new era of web development
4
5    http://qooxdoo.org
6
7    Copyright:
8      2006 by STZ-IDA, Germany, http://www.stz-ida.de
9
10    License:
11      LGPL 2.1: http://www.gnu.org/licenses/lgpl.html
12
13    Authors:
14      * Til Schneider (til132)
15
16 ************************************************************************ */
17
18 /* ************************************************************************
19
20 #module(core)
21 #module(log)
22
23 ************************************************************************ */
24
25 /**
26  * An appender that writes all messages to a log window.
27  * <p>
28  * This class does not depend on qooxdoo widgets, so it also works when there
29  * are problems with widgets or when the widgets are not yet initialized.
30  *
31  * @param name {string ? "qx_log"} the name of the log window.
32  */
33 qx.OO.defineClass("qx.dev.log.WindowAppender", qx.dev.log.Appender,
34 function(name) {
35   qx.dev.log.Appender.call(this);
36
37   this._id = qx.dev.log.WindowAppender.register(this);
38   this._name = (name == null) ? "qx_log" : name;
39
40   this._logWindowOpened = false;
41 });
42
43
44 /**
45  * The maximum number of messages to show. If null the number of messages is not
46  * limited.
47  */
48 qx.OO.addProperty({ name:"maxMessages", type:"number", defaultValue:500 });
49
50 /** Whether the window should appear under the main window. */
51 qx.OO.addProperty({ name:"popUnder", type:"boolean", defaultValue:false, allowNull:false });
52
53
54 /**
55  * Creates and opens the log window if it doesn't alread exist.
56  */
57 qx.Proto.openWindow = function() {
58   if (this._logWindowOpened) {
59     // The window is already open -> Nothing to do
60     return;
61   }
62
63   // Open the logger window
64   var winWidth = 600;
65   var winHeight = 350;
66   var winLeft = window.screen.width - winWidth;
67   var winTop = window.screen.height - winHeight;
68   var params = "toolbar=no,scrollbars=yes,resizable=yes,"
69     + "width=" + winWidth + ",height=" + winHeight
70     + ",left=" + winLeft + ",top=" + winTop;
71
72   // NOTE: In window.open the browser will process the event queue.
73   //     Which means that other log events may arrive during this time.
74   //     The log window is then in an inconsistent state, because the
75   //     this._logElem is not created yet. These events will be added to the
76   //     this._logEventQueue and logged after this._logElem is created.
77   this._logWindow = window.open("", this._name, params);
78
79   if (!this._logWindow || this._logWindow.closed)
80   {
81     if (!this._popupBlockerWarning) {
82       alert("Couldn't open debug window. Please disable your popup blocker!");
83     }
84
85     this._popupBlockerWarning = true;
86     return;
87   }
88
89   // Seems to be OK now.
90   this._popupBlockerWarning = false;
91
92   // Store that window is open
93   this._logWindowOpened = true;
94
95   if (this.getPopUnder()) {
96     this._logWindow.blur();
97     window.focus();
98   }
99
100   var logDocument = this._logWindow.document;
101   // NOTE: We have to use a static onunload handler, because an onunload
102   //     that is set later using DOM is ignored completely.
103   //     (at least in Firefox, but maybe in IE, too)
104   logDocument.open();
105   logDocument.write("<html><head><title>" + this._name + "</title></head>"
106     + '<body onload="qx = opener.qx;" onunload="try{qx.dev.log.WindowAppender._registeredAppenders[' + this._id + '].closeWindow()}catch(e){}">'
107     + '<pre id="log" wrap="wrap" style="font-size:11"></pre></body></html>');
108   logDocument.close();
109
110   this._logElem = logDocument.getElementById("log");
111
112   // Log the events from the queue
113   if (this._logEventQueue != null) {
114     for (var i = 0; i < this._logEventQueue.length; i++) {
115       this.appendLogEvent(this._logEventQueue[i]);
116     }
117     this._logEventQueue = null;
118   }
119 }
120
121
122 /**
123  * Closes the log window.
124  */
125 qx.Proto.closeWindow = function() {
126   if (this._logWindow != null) {
127     this._logWindow.close();
128     this._logWindow = null;
129     this._logElem = null;
130     this._logWindowOpened = false;
131   }
132 }
133
134
135 // overridden
136 qx.Proto.appendLogEvent = function(evt) {
137   if (!this._logWindowOpened) {
138     this._logEventQueue = [];
139     this._logEventQueue.push(evt);
140
141     this.openWindow();
142
143     // Popup-Blocker was active!
144     if (!this._logWindowOpened) {
145       return;
146     }
147   } else if (this._logElem == null) {
148     // The window is currenlty opening, but not yet finished
149     // -> Put the event in the queue
150     this._logEventQueue.push(evt);
151   } else {
152     var divElem = this._logWindow.document.createElement("div");
153     if (evt.level == qx.dev.log.Logger.LEVEL_ERROR) {
154       divElem.style.backgroundColor = "#FFEEEE";
155     } else if (evt.level == qx.dev.log.Logger.LEVEL_DEBUG) {
156       divElem.style.color = "gray";
157     }
158     divElem.innerHTML = this.formatLogEvent(evt).replace(/&/g, "&amp;")
159       .replace(/</g, "&lt;").replace(/  /g, " &#160;").replace(/[\n]/g, "<br>");
160     this._logElem.appendChild(divElem);
161
162     while (this._logElem.childNodes.length > this.getMaxMessages()) {
163       this._logElem.removeChild(this._logElem.firstChild);
164
165       if (this._removedMessageCount == null) {
166         this._removedMessageCount = 1;
167       } else {
168         this._removedMessageCount++;
169       }
170     }
171
172     if (this._removedMessageCount != null) {
173       this._logElem.firstChild.innerHTML = "(" + this._removedMessageCount
174         + " messages removed)";
175     }
176
177     // Scroll to bottom
178     this._logWindow.scrollTo(0, this._logElem.offsetHeight);
179   }
180 }
181
182
183 // overridden
184 qx.Proto.dispose = function() {
185   if (this.getDisposed()) {
186     return true;
187   }
188
189   this.closeWindow();
190
191   return qx.dev.log.Appender.prototype.dispose.call(this);
192 }
193
194
195 qx.Class._nextId = 1;
196 qx.Class._registeredAppenders = {};
197
198
199 /**
200  * Registers a WindowAppender. This is used by the WindowAppender internally.
201  * You don't have to call this.
202  *
203  * @param appender {WindowAppender} the WindowAppender to register.
204  * @return {int} the ID.
205  */
206 qx.Class.register = function(appender) {
207   var WindowAppender = qx.dev.log.WindowAppender;
208
209   var id = WindowAppender._nextId++;
210   WindowAppender._registeredAppenders[id] = appender;
211
212   return id;
213 }
214
215
216 /**
217  * Returns a prviously registered WindowAppender.
218  *
219  * @param id {int} the ID of the wanted WindowAppender.
220  * @return {WindowAppender} the WindowAppender or null if no
221  *     WindowAppender with this ID is registered.
222  */
223 qx.Class.getAppender = function(id) {
224   return qx.dev.log.WindowAppender._registeredAppenders[id];
225 }