From 3114b448eaf179814ecbd6b21155ee2dac98b58a Mon Sep 17 00:00:00 2001 From: Paulo Veiga Date: Thu, 11 Jun 2009 17:43:45 +0000 Subject: [PATCH] - Improve logging mechanism - Manage errors on editor loading. --- trunk/ToDo.txt | 2 - trunk/core-js/pom.xml | 2 +- trunk/core-js/src/main/javascript/Logger.js | 129 - .../core-js/src/main/javascript/UserAgent.js | 42 +- trunk/core-js/src/main/javascript/Utils.js | 54 +- .../core-js/src/main/javascript/WaitDialog.js | 229 +- trunk/core-js/src/main/javascript/footer.js | 107 +- trunk/core-js/src/main/javascript/header.js | 2 +- trunk/core-js/src/main/javascript/log4js.js | 2501 +++++++++++++++++ .../src/main/javascript/MindmapDesigner.js | 7 + .../src/main/javascript/PersistanceManager.js | 46 +- .../src/main/javascript/peer/svg/GroupPeer.js | 39 +- .../com/wisemapping/filter/UserAgent.java | 3 +- .../WEB-INF/classes/messages.properties | 1 + .../src/main/webapp/css/editor.css | 222 +- .../src/main/webapp/images/errorIcon.png | Bin 0 -> 14469 bytes .../wise-webapp/src/main/webapp/js/editor.js | 79 +- .../src/main/webapp/js/embedded.js | 80 +- .../main/webapp/jsp/browserNotSupported.jsp | 4 +- .../src/main/webapp/jsp/embeddedView.jsp | 15 +- .../src/main/webapp/jsp/mindmapEditor.jsp | 328 +-- 21 files changed, 3118 insertions(+), 774 deletions(-) delete mode 100644 trunk/core-js/src/main/javascript/Logger.js create mode 100644 trunk/core-js/src/main/javascript/log4js.js create mode 100644 trunk/wise-webapp/src/main/webapp/images/errorIcon.png diff --git a/trunk/ToDo.txt b/trunk/ToDo.txt index a89f863a..7db2465f 100644 --- a/trunk/ToDo.txt +++ b/trunk/ToDo.txt @@ -1,3 +1 @@ -- Check mail jars - Google Tracking -- Customizable JSP Replacements \ No newline at end of file diff --git a/trunk/core-js/pom.xml b/trunk/core-js/pom.xml index 1e11e749..f899e925 100644 --- a/trunk/core-js/pom.xml +++ b/trunk/core-js/pom.xml @@ -51,7 +51,7 @@ ${basedir}/target/tmp/header-min.js ${basedir}/target/tmp/ColorPicker-min.js ${basedir}/target/tmp/Loader-min.js - ${basedir}/target/tmp/Logger-min.js + ${basedir}/target/tmp/log4js-min.js ${basedir}/target/tmp/Monitor-min.js ${basedir}/target/tmp/Point-min.js ${basedir}/target/tmp/UserAgent-min.js diff --git a/trunk/core-js/src/main/javascript/Logger.js b/trunk/core-js/src/main/javascript/Logger.js deleted file mode 100644 index 1754686c..00000000 --- a/trunk/core-js/src/main/javascript/Logger.js +++ /dev/null @@ -1,129 +0,0 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ - -core.Logger = -{ - _enabled: false, - setEnabled: function (enabled) { - this._enabled = enabled; - },init: function(serverLogger) -{ - this._serverLogger = serverLogger; - if (window.onerror) { - // Save any previously defined handler to call - core.Logger._origOnWindowError = window.onerror; - } - window.onerror = core.Logger._onWindowError; -}, - log: function(message, severity, src) - { - if (!severity) - { - severity = core.LoggerSeverity.DEBUG; - } - - // Error messages must be loggued in the server ... - if (severity >= core.LoggerSeverity.ERROR) - { - if (this._serverLogger) - { - try - { - this._serverLogger.logError(core.LoggerSeverity.ERROR, message); - } catch(e) - { - } - } - } - - // // Finally, log the error in debug console if it's enabled. - if (this._enabled) - { - this._browserLogger(message); - } - }, - _browserLogger: function(message) { - // Firebug is not enabled. - - if (core.Logger._origOnWindowError) { - core.Logger._origOnWindowError(); - } - - if (!console) - { - if (!this._isInitialized) - { - this._console = window.document.createElement("div"); - this._console.style.position = "absolute"; - this._console.style.width = "300px"; - this._console.style.height = "200px"; - this._console.style.bottom = 0; - this._console.style.right = 0; - this._console.style.border = '1px solid black'; - this._console.style.background = 'yellow'; - this._console.style.zIndex = 60000; - - this._textArea = window.document.createElement("textarea"); - this._textArea.cols = "40"; - this._textArea.rows = "10"; - this._console.appendChild(this._textArea); - - window.document.body.appendChild(this._console); - this._isInitialized = true; - } - this._textArea.value = this._textArea.value + "\n" + msg; - - } else - { - // Firebug console... - console.log(message); - } - }, -/** - * Handles logging of messages due to window error events. - * - * @method _onWindowError - * @param sMsg {String} The error message. - * @param sUrl {String} URL of the error. - * @param sLine {String} Line number of the error. - * @private - */ - _onWindowError: function(sMsg, sUrl, sLine) { - // Logger is not in scope of this event handler - // http://cfis.savagexi.com/articles/2007/05/08/what-went-wrong-with-my-javascript - try { - core.Logger.log(sMsg + ' (' + sUrl + ', line ' + sLine + ')', core.LoggerSeverity.ERROR, "window"); - } - catch(e) { - return false; - } - return true; - }, - logError: function(msg) { - core.Logger.log(msg, core.LoggerSeverity.ERROR, "code"); - } -}; - -core.LoggerSeverity = -{ - DEBUG: 1, - WARNING: 2, - ERROR: 3, - WINDOW: 4 -}; \ No newline at end of file diff --git a/trunk/core-js/src/main/javascript/UserAgent.js b/trunk/core-js/src/main/javascript/UserAgent.js index c6586eff..43bb9d29 100644 --- a/trunk/core-js/src/main/javascript/UserAgent.js +++ b/trunk/core-js/src/main/javascript/UserAgent.js @@ -1,22 +1,22 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ - +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* $Id: file 64488 2006-03-10 17:32:09Z paulo $ +*/ + core.UserAgent = { _isVMLSupported:null, isVMLSupported: function() @@ -31,10 +31,6 @@ core.UserAgent = { { return !core.UserAgent.isVMLSupported(); }, - isIframeWorkaroundRequired: function() - { - return core.UserAgent.OS == "Mac" && core.UserAgent.browser == "Firefox" && core.UserAgent.version < 3; - }, isMozillaFamily: function() { return this.browser == "Netscape" || this.browser == "Firefox"; diff --git a/trunk/core-js/src/main/javascript/Utils.js b/trunk/core-js/src/main/javascript/Utils.js index 3179e3d5..36acc802 100644 --- a/trunk/core-js/src/main/javascript/Utils.js +++ b/trunk/core-js/src/main/javascript/Utils.js @@ -1,22 +1,22 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ - +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* $Id: file 64488 2006-03-10 17:32:09Z paulo $ +*/ + core.Utils = { isDefined: function(val) @@ -70,21 +70,7 @@ core.assert = function(assert, message) core.findElement = function(name) { - var result; - if (core.UserAgent.isIframeWorkaroundRequired()) - { - var iframe = $('mindplotIFrame'); - var doc = iframe.contentDocument; - if (doc == undefined || doc == null) - doc = iframe.contentWindow.document; - result = $(doc.getElementById(name)); - } - if (!result) - { - result = $(name); - } - - return result; + return $(name); } Math.sign = function(value) diff --git a/trunk/core-js/src/main/javascript/WaitDialog.js b/trunk/core-js/src/main/javascript/WaitDialog.js index 9ab35f10..3bc08710 100644 --- a/trunk/core-js/src/main/javascript/WaitDialog.js +++ b/trunk/core-js/src/main/javascript/WaitDialog.js @@ -1,96 +1,47 @@ /* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Id: file 64488 2006-03-10 17:32:09Z paulo $ + */ /* -Created By: Chris Campbell -Website: http://particletree.com -Date: 2/1/2006 + Created By: Chris Campbell + Website: http://particletree.com + Date: 2/1/2006 -Inspired by the lightbox implementation found at http://www.huddletogether.com/projects/lightbox/ -*/ + Inspired by the lightbox implementation found at http://www.huddletogether.com/projects/lightbox/ + /*-----------------------------------------------------------------------------------------------*/ -/*-------------------------------GLOBAL VARIABLES------------------------------------*/ - -var detect = navigator.userAgent.toLowerCase(); -var OS,browser,version,total,thestring; - -/*-----------------------------------------------------------------------------------------------*/ - -//Browser detect script origionally created by Peter Paul Koch at http://www.quirksmode.org/ - -function getBrowserInfo(evt) { - if (checkIt('konqueror')) { - browser = "Konqueror"; - OS = "Linux"; - } - else if (checkIt('safari')) browser = "Safari" - else if (checkIt('omniweb')) browser = "OmniWeb" - else if (checkIt('opera')) browser = "Opera" - else if (checkIt('webtv')) browser = "WebTV"; - else if (checkIt('icab')) browser = "iCab" - else if (checkIt('msie')) browser = "Internet Explorer" - else if (!checkIt('compatible')) { - browser = "Netscape Navigator" - version = detect.charAt(8); - } - else browser = "An unknown browser"; - - if (!version) version = detect.charAt(place + thestring.length); - - if (!OS) { - if (checkIt('linux')) OS = "Linux"; - else if (checkIt('x11')) OS = "Unix"; - else if (checkIt('mac')) OS = "Mac" - else if (checkIt('win')) OS = "Windows" - else OS = "an unknown operating system"; - } -} - -function checkIt(string) { - place = detect.indexOf(string) + 1; - thestring = string; - return place; -} - -/*-----------------------------------------------------------------------------------------------*/ - -$(window).addEvent('load', getBrowserInfo); core.WaitDialog = new Class({ - initialize: function(contentId) { - this.content = $(contentId); - }, yPos : 0, - xPos : 0, -// Turn everything on - mainly the IE fixes - activate: function(changeCursor) + initialize: function() { + }, + // Turn everything on - mainly the IE fixes + activate: function(changeCursor, dialogContent) { - // if (browser == 'Internet Explorer'){ - //// this.getScroll(); - // this.prepareIE('100%', 'hidden'); - //// this.setScroll(0,0); - //// this.hideSelects('hidden'); - // } + + this.content = dialogContent; + + this._initLightboxMarkup(); + this.displayLightbox("block"); // Change to loading cursor. @@ -99,41 +50,27 @@ core.WaitDialog = new Class({ window.document.body.style.cursor = "wait"; } }, + changeContent: function(dialogContent, changeCursor) + { + this.content = dialogContent; + if (!$('lbContent')) + { + // Dialog is not activated. Nothing to do ... + window.document.body.style.cursor = "pointer"; + return; + } -// Ie requires height to 100% and overflow hidden or else you can scroll down past the lightbox - prepareIE: function(height, overflow) { - bod = document.getElementsByTagName('body')[0]; - bod.style.height = height; - bod.style.overflow = overflow; + this.processInfo(); - htm = document.getElementsByTagName('html')[0]; - htm.style.height = height; - htm.style.overflow = overflow; - }, - -// In IE, select elements hover on top of the lightbox - hideSelects: function(visibility) { - selects = document.getElementsByTagName('select'); - for (i = 0; i < selects.length; i++) { - selects[i].style.visibility = visibility; + // Change to loading cursor. + if (changeCursor) + { + window.document.body.style.cursor = "wait"; + }else + { + window.document.body.style.cursor = "auto"; } }, - -// Taken from lightbox implementation found at http://www.huddletogether.com/projects/lightbox/ - getScroll: function() { - if (self.pageYOffset) { - this.yPos = self.pageYOffset; - } else if (document.documentElement && document.documentElement.scrollTop) { - this.yPos = document.documentElement.scrollTop; - } else if (document.body) { - this.yPos = document.body.scrollTop; - } - }, - - setScroll: function(x, y) { - window.scrollTo(x, y); - }, - displayLightbox: function(display) { $('overlay').style.display = display; $('lightbox').style.display = display; @@ -141,15 +78,19 @@ core.WaitDialog = new Class({ this.processInfo(); }, -// Display Ajax response + // Display dialog content ... processInfo: function() { - var info = new Element('div').setProperty('id', 'lbContent'); - info.setHTML(this.content.innerHTML); - info.injectBefore($('lbLoadMessage')); + if ($('lbContent')) + $('lbContent').remove(); + + var lbContentElement = new Element('div').setProperty('id', 'lbContent'); + lbContentElement.setHTML(this.content.innerHTML); + + lbContentElement.injectBefore($('lbLoadMessage')); $('lightbox').className = "done"; }, -// Search through new links within the lightbox, and attach click event + // Search through new links within the lightbox, and attach click event actions: function() { lbActions = document.getElementsByClassName('lbAction'); @@ -164,53 +105,31 @@ core.WaitDialog = new Class({ }, -// Example of creating your own functionality once lightbox is initiated - insert: function(e) { - var event = new Event(e); - link = event.target; - if ($('lbContent')) - $('lbContent').remove(); - - var myAjax = new Ajax.Request( - link.href, - {method: 'post', parameters: "", onComplete: this.processInfo.pass(this)} - ); - - }, - -// Example of creating your own functionality once lightbox is initiated + // Example of creating your own functionality once lightbox is initiated deactivate: function(time) { if ($('lbContent')) $('lbContent').remove(); - // - // if (browser == "Internet Explorer"){ - // this.setScroll(0,this.yPos); - // this.prepareIE("auto", "auto"); - // this.hideSelects("visible"); - // } + this.displayLightbox("none"); window.document.body.style.cursor = "default"; } -}); + , _initLightboxMarkup:function() + { + // Add overlay element inside body ... + var bodyElem = document.getElementsByTagName('body')[0]; + var overlayElem = new Element('div').setProperty('id', 'overlay'); + overlayElem.injectInside(bodyElem); -/*-----------------------------------------------------------------------------------------------*/ + // Add lightbox element inside body ... + var lightboxElem = new Element('div').setProperty('id', 'lightbox'); + lightboxElem.addClass('loading'); -// Onload, make all links that need to trigger a lightbox active -function initialize() { - addLightboxMarkup(); - valid = new core.WaitDialog($('sampleDialog')); -} + var lbLoadMessageElem = new Element('div').setProperty('id', 'lbLoadMessage'); + lbLoadMessageElem.injectInside(lightboxElem); -// Add in markup necessary to make this work. Basically two divs: -// Overlay holds the shadow -// Lightbox is the centered square that the content is put into. -function addLightboxMarkup() { - var body = document.getElementsByTagName('body')[0]; - overlay = new Element('div').setProperty('id', 'overlay').injectInside(document.body); - var lb = new Element('div').setProperty('id', 'lightbox'); - lb.addClass('loading'); - var tmp = new Element('div').setProperty('id', 'lbLoadMessage').injectInside(lb); - lb.injectInside(document.body); -} \ No newline at end of file + lightboxElem.injectInside(bodyElem); + + } +}); \ No newline at end of file diff --git a/trunk/core-js/src/main/javascript/footer.js b/trunk/core-js/src/main/javascript/footer.js index b68760ab..3e73abfb 100644 --- a/trunk/core-js/src/main/javascript/footer.js +++ b/trunk/core-js/src/main/javascript/footer.js @@ -1,21 +1,94 @@ /* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Id: file 64488 2006-03-10 17:32:09Z paulo $ + */ + +// Init default logger level ... +var wLogger = new Log4js.getLogger("WiseMapping"); +wLogger.setLevel(Log4js.Level.ALL); +wLogger.addAppender(new Log4js.BrowserConsoleAppender()); + +// Is logger service available ? +if (window.LoggerService) +{ + Log4js.WiseServerAppender = function() + { + this.layout = new Log4js.SimpleLayout(); + }; + + Log4js.WiseServerAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + try { + var message = this.layout.format(loggingEvent); + var level = this.levelCode(loggingEvent); + + window.LoggerService.logError(level, message); + + } catch (e) { + alert(e); + } + }, + + /** + * toString + */ + toString: function() { + return "Log4js.WiseServerAppender"; + }, + + levelCode: function(loggingEvent) + { + var retval; + switch (loggingEvent.level) { + case Log4js.Level.FATAL: + retval = 3; + break; + case Log4js.Level.ERROR: + retval = 3; + break; + case Log4js.Level.WARN: + retval = 2; + break; + default: + retval = 1; + break; + } + + return retval; + } + }); + + wLogger.addAppender(new Log4js.WiseServerAppender()); + +} + + +// Handle error events ... +window.onerror = function(sMsg, sUrl, sLine) +{ + window.hasUnexpectedErrors = true; + var msg = sMsg + ' (' + sUrl + ', line ' + sLine + ')'; + wLogger.fatal(msg); + + return true; +}; window.__coreLoad = function() { diff --git a/trunk/core-js/src/main/javascript/header.js b/trunk/core-js/src/main/javascript/header.js index 9208f24c..3d4560b6 100644 --- a/trunk/core-js/src/main/javascript/header.js +++ b/trunk/core-js/src/main/javascript/header.js @@ -17,4 +17,4 @@ * $Id: file 64488 2006-03-10 17:32:09Z paulo $ */ -var core = {}; \ No newline at end of file +var core = {}; diff --git a/trunk/core-js/src/main/javascript/log4js.js b/trunk/core-js/src/main/javascript/log4js.js new file mode 100644 index 00000000..29000f95 --- /dev/null +++ b/trunk/core-js/src/main/javascript/log4js.js @@ -0,0 +1,2501 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*jsl:option explicit*/ + +/** + * @fileoverview log4js is a library to log in JavaScript in similar manner + * than in log4j for Java. The API should be nearly the same. + * + * This file contains all log4js code and is the only file required for logging. + * + *

Example:

+ *
+ *  var log = new Log4js.getLogger("some-category-name"); //create logger instance
+ *  log.setLevel(Log4js.Level.TRACE); //set the Level
+ *  log.addAppender(new ConsoleAppender(log, false)); // console that launches in new window
+ 
+ *  // if multiple appenders are set all will log
+ *  log.addAppender(new ConsoleAppender(log, true)); // console that is in-line in the page
+ *  log.addAppender(new FileAppender("C:\\somefile.log")); // file appender logs to C:\\somefile.log
+ * 
+ *  ...
+ * 
+ *  //call the log
+ *  log.trace("trace me" );
+ * 
+ * + * @version 0.3 + * @author Stephan Strittmatter - http://jroller.com/page/stritti + * @author Seth Chisamore - http://www.chisamore.com + * @since 2005-05-20 + * Website: http://log4js.berlios.de + */ +var Log4js = { + + /** + * Current version of log4js. + * @static + * @final + */ + version: "1.0", + + /** + * Date of logger initialized. + * @static + * @final + */ + applicationStartDate: new Date(), + + /** + * Hashtable of loggers. + * @static + * @final + * @private + */ + loggers: {}, + + /** + * Get a logger instance. Instance is cached on categoryName level. + * @param {String} categoryName name of category to log to. + * @return {Logger} instance of logger for the category + * @static + */ + getLogger: function(categoryName) { + + // Use default logger if categoryName is not specified or invalid + if (!(typeof categoryName == "string")) { + categoryName = "[default]"; + } + + if (!Log4js.loggers[categoryName]) { + // Create the logger for this name if it doesn't already exist + Log4js.loggers[categoryName] = new Log4js.Logger(categoryName); + } + + return Log4js.loggers[categoryName]; + }, + + /** + * Get the default logger instance. + * @return {Logger} instance of default logger + * @static + */ + getDefaultLogger: function() { + return Log4js.getLogger("[default]"); + }, + + /** + * Atatch an observer function to an elements event browser independent. + * + * @param element element to attach event + * @param name name of event + * @param observer observer method to be called + * @private + */ + attachEvent: function (element, name, observer) { + if (element.addEventListener) { //DOM event model + element.addEventListener(name, observer, false); + } else if (element.attachEvent) { //M$ event model + element.attachEvent('on' + name, observer); + } + } + + /** + * Load a JS-script dynamically. + * @param {String} src + */ +/* $import: function (src) { + var documentScripts = document.getElementsByTagName("script"); + + for (index = 0; index < documentScripts.length; ++index) + { + var documentScript = documentScripts[index]; + if (documentScript.src == src) { + return false; + } + } + + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = src; + document.getElementsByTagName('head')[0].appendChild(script); + + return true; + } + */ +}; + +/** + * Internal object extension (OO) methods. + * + * @private + * @ignore + */ +Log4js.extend = function(destination, source) { + for (property in source) { + destination[property] = source[property]; + } + return destination; +} + +/** + * Functions taken from Prototype library, + * didn't want to require for just few functions. + * More info at {@link http://prototype.conio.net/} + * @private + */ +Log4js.bind = function(fn, object) { + return function() { + return fn.apply(object, arguments); + }; +}; + +/** + * Log4js.Level Enumeration. Do not use directly. Use static objects instead. + * @constructor + * @param {Number} level number of level + * @param {String} levelString String representation of level + * @private + */ +Log4js.Level = function(level, levelStr) { + this.level = level; + this.levelStr = levelStr; +}; + +Log4js.Level.prototype = { + /** + * converts given String to corresponding Level + * @param {String} sArg String value of Level + * @param {Log4js.Level} defaultLevel default Level, if no String representation + * @return Level object + * @type Log4js.Level + */ + toLevel: function(sArg, defaultLevel) { + + if(sArg === null) { + return defaultLevel; + } + + if(typeof sArg == "string") { + var s = sArg.toUpperCase(); + if(s == "ALL") {return Log4js.Level.ALL;} + if(s == "DEBUG") {return Log4js.Level.DEBUG;} + if(s == "INFO") {return Log4js.Level.INFO;} + if(s == "WARN") {return Log4js.Level.WARN;} + if(s == "ERROR") {return Log4js.Level.ERROR;} + if(s == "FATAL") {return Log4js.Level.FATAL;} + if(s == "OFF") {return Log4js.Level.OFF;} + if(s == "TRACE") {return Log4js.Level.TRACE;} + return defaultLevel; + } else if(typeof sArg == "number") { + switch(sArg) { + case ALL_INT: return Log4js.Level.ALL; + case DEBUG_INT: return Log4js.Level.DEBUG; + case INFO_INT: return Log4js.Level.INFO; + case WARN_INT: return Log4js.Level.WARN; + case ERROR_INT: return Log4js.Level.ERROR; + case FATAL_INT: return Log4js.Level.FATAL; + case OFF_INT: return Log4js.Level.OFF; + case TRACE_INT: return Log4js.Level.TRACE; + default: return defaultLevel; + } + } else { + return defaultLevel; + } + }, + /** + * @return converted Level to String + * @type String + */ + toString: function() { + return this.levelStr; + }, + /** + * @return internal Number value of Level + * @type Number + */ + valueOf: function() { + return this.level; + } +}; + +// Static variables +/** + * @private + */ +Log4js.Level.OFF_INT = Number.MAX_VALUE; +/** + * @private + */ +Log4js.Level.FATAL_INT = 50000; +/** + * @private + */ +Log4js.Level.ERROR_INT = 40000; +/** + * @private + */ +Log4js.Level.WARN_INT = 30000; +/** + * @private + */ +Log4js.Level.INFO_INT = 20000; +/** + * @private + */ +Log4js.Level.DEBUG_INT = 10000; +/** + * @private + */ +Log4js.Level.TRACE_INT = 5000; +/** + * @private + */ +Log4js.Level.ALL_INT = Number.MIN_VALUE; + +/** + * Logging Level OFF - all disabled + * @type Log4js.Level + * @static + */ +Log4js.Level.OFF = new Log4js.Level(Log4js.Level.OFF_INT, "OFF"); +/** + * Logging Level Fatal + * @type Log4js.Level + * @static + */ +Log4js.Level.FATAL = new Log4js.Level(Log4js.Level.FATAL_INT, "FATAL"); +/** + * Logging Level Error + * @type Log4js.Level + * @static + */ +Log4js.Level.ERROR = new Log4js.Level(Log4js.Level.ERROR_INT, "ERROR"); +/** + * Logging Level Warn + * @type Log4js.Level + * @static + */ +Log4js.Level.WARN = new Log4js.Level(Log4js.Level.WARN_INT, "WARN"); +/** + * Logging Level Info + * @type Log4js.Level + * @static + */ +Log4js.Level.INFO = new Log4js.Level(Log4js.Level.INFO_INT, "INFO"); +/** + * Logging Level Debug + * @type Log4js.Level + * @static + */ +Log4js.Level.DEBUG = new Log4js.Level(Log4js.Level.DEBUG_INT, "DEBUG"); +/** + * Logging Level Trace + * @type Log4js.Level + * @static + */ +Log4js.Level.TRACE = new Log4js.Level(Log4js.Level.TRACE_INT, "TRACE"); +/** + * Logging Level All - All traces are enabled + * @type Log4js.Level + * @static + */ +Log4js.Level.ALL = new Log4js.Level(Log4js.Level.ALL_INT, "ALL"); + +/** + * Log4js CustomEvent + * @constructor + * @author Corey Johnson - original code in Lumberjack (http://gleepglop.com/javascripts/logger/) + * @author Seth Chisamore - adapted for Log4js + * @private + */ +Log4js.CustomEvent = function() { + this.listeners = []; +}; + +Log4js.CustomEvent.prototype = { + + /** + * @param method method to be added + */ + addListener : function(method) { + this.listeners.push(method); + }, + + /** + * @param method method to be removed + */ + removeListener : function(method) { + var foundIndexes = this.findListenerIndexes(method); + + for(var i = 0; i < foundIndexes.length; i++) { + this.listeners.splice(foundIndexes[i], 1); + } + }, + + /** + * @param handler + */ + dispatch : function(handler) { + for(var i = 0; i < this.listeners.length; i++) { + try { + this.listeners[i](handler); + } + catch (e) { + log4jsLogger.warn("Could not run the listener " + this.listeners[i] + ". \n" + e); + } + } + }, + + /** + * @private + * @param method + */ + findListenerIndexes : function(method) { + var indexes = []; + for(var i = 0; i < this.listeners.length; i++) { + if (this.listeners[i] == method) { + indexes.push(i); + } + } + + return indexes; + } +}; + +/** + * Models a logging event. + * @constructor + * @param {String} categoryName name of category + * @param {Log4js.Level} level level of message + * @param {String} message message to log + * @param {Log4js.Logger} logger the associated logger + * @author Seth Chisamore + */ +Log4js.LoggingEvent = function(categoryName, level, message, exception, logger) { + /** + * the timestamp of the Logging Event + * @type Date + * @private + */ + this.startTime = new Date(); + /** + * category of event + * @type String + * @private + */ + this.categoryName = categoryName; + /** + * the logging message + * @type String + * @private + */ + this.message = message; + /** + * the logging exception + * @type Exception + * @private + */ + this.exception = exception; + /** + * level of log + * @type Log4js.Level + * @private + */ + this.level = level; + /** + * reference to logger + * @type Log4js.Logger + * @private + */ + this.logger = logger; +}; + +Log4js.LoggingEvent.prototype = { + /** + * get the timestamp formatted as String. + * @return {String} formatted timestamp + * @see Log4js#setDateFormat() + */ + getFormattedTimestamp: function() { + if(this.logger) { + return this.logger.getFormattedTimestamp(this.startTime); + } else { + return this.startTime.toGMTString(); + } + } +}; + +/** + * Logger to log messages to the defined appender.

+ * Default appender is Appender, which is ignoring all messages. Please + * use setAppender() to set a specific appender (e.g. WindowAppender). + * use {@see Log4js#getLogger(String)} to get an instance. + * @constructor + * @param name name of category to log to + * @author Stephan Strittmatter + */ +Log4js.Logger = function(name) { + this.loggingEvents = []; + this.appenders = []; + /** category of logger */ + this.category = name || ""; + /** level to be logged */ + this.level = Log4js.Level.FATAL; + + this.dateformat = Log4js.DateFormatter.DEFAULT_DATE_FORMAT; + this.dateformatter = new Log4js.DateFormatter(); + + this.onlog = new Log4js.CustomEvent(); + this.onclear = new Log4js.CustomEvent(); + + /** appender to write in */ + this.appenders.push(new Log4js.Appender(this)); + + // if multiple log objects are instantiated this will only log to the log + // object that is declared last can't seem to get the attachEvent method to + // work correctly + try { + window.onerror = this.windowError.bind(this); + } catch (e) { + //log4jsLogger.fatal(e); + } +}; + +Log4js.Logger.prototype = { + + /** + * add additional appender. DefaultAppender always is there. + * @param appender additional wanted appender + */ + addAppender: function(appender) { + if (appender instanceof Log4js.Appender) { + appender.setLogger(this); + this.appenders.push(appender); + } else { + throw "Not instance of an Appender: " + appender; + } + }, + + /** + * set Array of appenders. Previous Appenders are cleared and removed. + * @param {Array} appenders Array of Appenders + */ + setAppenders: function(appenders) { + //clear first all existing appenders + for(var i = 0; i < this.appenders.length; i++) { + this.appenders[i].doClear(); + } + + this.appenders = appenders; + + for(var j = 0; j < this.appenders.length; j++) { + this.appenders[j].setLogger(this); + } + }, + + /** + * Set the Loglevel default is LogLEvel.TRACE + * @param level wanted logging level + */ + setLevel: function(level) { + this.level = level; + }, + + /** + * main log method logging to all available appenders + * @private + */ + log: function(logLevel, message, exception) { + var loggingEvent = new Log4js.LoggingEvent(this.category, logLevel, + message, exception, this); + this.loggingEvents.push(loggingEvent); + this.onlog.dispatch(loggingEvent); + }, + + /** clear logging */ + clear : function () { + try{ + this.loggingEvents = []; + this.onclear.dispatch(); + } catch(e){} + }, + /** checks if Level Trace is enabled */ + isTraceEnabled: function() { + if (this.level.valueOf() <= Log4js.Level.TRACE.valueOf()) { + return true; + } + return false; + }, + /** + * Trace messages + * @param message {Object} message to be logged + */ + trace: function(message) { + if (this.isTraceEnabled()) { + this.log(Log4js.Level.TRACE, message, null); + } + }, + /** checks if Level Debug is enabled */ + isDebugEnabled: function() { + if (this.level.valueOf() <= Log4js.Level.DEBUG.valueOf()) { + return true; + } + return false; + }, + /** + * Debug messages + * @param message {Object} message to be logged + */ + debug: function(message) { + if (this.isDebugEnabled()) { + this.log(Log4js.Level.DEBUG, message, null); + } + }, + /** + * Debug messages + * @param {Object} message message to be logged + * @param {Throwable} throwable + */ + debug: function(message, throwable) { + if (this.isDebugEnabled()) { + this.log(Log4js.Level.DEBUG, message, throwable); + } + }, + /** checks if Level Info is enabled */ + isInfoEnabled: function() { + if (this.level.valueOf() <= Log4js.Level.INFO.valueOf()) { + return true; + } + return false; + }, + /** + * logging info messages + * @param {Object} message message to be logged + */ + info: function(message) { + if (this.isInfoEnabled()) { + this.log(Log4js.Level.INFO, message, null); + } + }, + /** + * logging info messages + * @param {Object} message message to be logged + * @param {Throwable} throwable + */ + info: function(message, throwable) { + if (this.isInfoEnabled()) { + this.log(Log4js.Level.INFO, message, throwable); + } + }, + /** checks if Level Warn is enabled */ + isWarnEnabled: function() { + if (this.level.valueOf() <= Log4js.Level.WARN.valueOf()) { + return true; + } + return false; + }, + + /** logging warn messages */ + warn: function(message) { + if (this.isWarnEnabled()) { + this.log(Log4js.Level.WARN, message, null); + } + }, + /** logging warn messages */ + warn: function(message, throwable) { + if (this.isWarnEnabled()) { + this.log(Log4js.Level.WARN, message, throwable); + } + }, + /** checks if Level Error is enabled */ + isErrorEnabled: function() { + if (this.level.valueOf() <= Log4js.Level.ERROR.valueOf()) { + return true; + } + return false; + }, + /** logging error messages */ + error: function(message) { + if (this.isErrorEnabled()) { + this.log(Log4js.Level.ERROR, message, null); + } + }, + /** logging error messages */ + error: function(message, throwable) { + if (this.isErrorEnabled()) { + this.log(Log4js.Level.ERROR, message, throwable); + } + }, + /** checks if Level Fatal is enabled */ + isFatalEnabled: function() { + if (this.level.valueOf() <= Log4js.Level.FATAL.valueOf()) { + return true; + } + return false; + }, + /** logging fatal messages */ + fatal: function(message) { + if (this.isFatalEnabled()) { + this.log(Log4js.Level.FATAL, message, null); + } + }, + /** logging fatal messages */ + fatal: function(message, throwable) { + if (this.isFatalEnabled()) { + this.log(Log4js.Level.FATAL, message, throwable); + } + }, + /** + * Capture main window errors and log as fatal. + * @private + */ + windowError: function(msg, url, line){ + var message = "Error in (" + (url || window.location) + ") on line "+ line +" with message (" + msg + ")"; + this.log(Log4js.Level.FATAL, message, null); + }, + + /** + * Set the date format of logger. Following switches are supported: + * + * @param {String} format format String for the date + * @see #getTimestamp + */ + setDateFormat: function(format) { + this.dateformat = format; + }, + + /** + * Generates a timestamp using the format set in {Log4js.setDateFormat}. + * @param {Date} date the date to format + * @see #setDateFormat + * @return A formatted timestamp with the current date and time. + */ + getFormattedTimestamp: function(date) { + return this.dateformatter.formatDate(date, this.dateformat); + } +}; + +/** + * Abstract base class for other appenders. + * It is doing nothing. + * + * @constructor + * @param {Log4js.Logger} logger log4js instance this appender is attached to + * @author Stephan Strittmatter + */ +Log4js.Appender = function () { + /** + * Reference to calling logger + * @type Log4js.Logger + * @private + */ + this.logger = null; +}; + +Log4js.Appender.prototype = { + /** + * appends the given loggingEvent appender specific + * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to append + */ + doAppend: function(loggingEvent) { + return; + }, + /** + * clears the Appender + */ + doClear: function() { + return; + }, + + /** + * Set the Layout for this appender. + * @param {Log4js.Layout} layout Layout for formatting loggingEvent + */ + setLayout: function(layout){ + this.layout = layout; + }, + /** + * Set reference to the logger. + * @param {Log4js.Logger} the invoking logger + */ + setLogger: function(logger){ + // add listener to the logger methods + logger.onlog.addListener(Log4js.bind(this.doAppend, this)); + logger.onclear.addListener(Log4js.bind(this.doClear, this)); + + this.logger = logger; + } +}; + +/** + * Interface for Layouts. + * Use this Layout as "interface" for other Layouts. It is doing nothing. + * + * @constructor + * @author Stephan Strittmatter + */ +Log4js.Layout = function(){return;}; +Log4js.Layout.prototype = { + /** + * Implement this method to create your own layout format. + * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to format + * @return formatted String + * @type String + */ + format: function(loggingEvent) { + return ""; + }, + /** + * Returns the content type output by this layout. + * @return The base class returns "text/plain". + * @type String + */ + getContentType: function() { + return "text/plain"; + }, + /** + * @return Returns the header for the layout format. The base class returns null. + * @type String + */ + getHeader: function() { + return null; + }, + /** + * @return Returns the footer for the layout format. The base class returns null. + * @type String + */ + getFooter: function() { + return null; + }, + + /** + * @return Separator between events + * @type String + */ + getSeparator: function() { + return ""; + } +}; + +/** + * Console Appender writes the logs to a console. If "inline" is + * set to "false" the console launches in another window otherwise + * the window is inline on the page and toggled on and off with "Alt-D". + * Note: At FireFox &gb; 2.0 the keystroke is little different now: "SHIFT+ALT+D". + * + * @constructor + * @extends Log4js.Appender + * @param {boolean} isInline boolean value that indicates whether the console be placed inline, default is to launch in new window + * + * @author Corey Johnson - original console code in Lumberjack (http://gleepglop.com/javascripts/logger/) + * @author Seth Chisamore - adapted for use as a log4js appender + */ +Log4js.ConsoleAppender = function(isInline) { + + /** + * @type Log4js.Layout + * @private + */ + this.layout = new Log4js.PatternLayout(Log4js.PatternLayout.TTCC_CONVERSION_PATTERN); + /** + * @type boolean + * @private + */ + this.inline = isInline; + + /** + * @type String + * @private + */ + this.accesskey = "d"; + + /** + * @private + */ + this.tagPattern = null; + + this.commandHistory = []; + this.commandIndex = 0; + + /** + * true if popup is blocked. + */ + this.popupBlocker = false; + + /** + * current output div-element. + */ + this.outputElement = null; + + this.docReference = null; + this.winReference = null; + + if(this.inline) { + Log4js.attachEvent(window, 'load', Log4js.bind(this.initialize, this)); + } +}; + +Log4js.ConsoleAppender.prototype = Log4js.extend(new Log4js.Appender(), { + + /** + * Set the access key to show/hide the inline console (default "e;d"e;) + * @param key access key to show/hide the inline console + */ + setAccessKey : function(key) { + this.accesskey = key; + }, + + /** + * @private + */ + initialize : function() { + + if(!this.inline) { + var doc = null; + var win = null; + window.top.consoleWindow = window.open("", this.logger.category, + "left=0,top=0,width=700,height=700,scrollbars=no,status=no,resizable=yes;toolbar=no"); + window.top.consoleWindow.opener = self; + win = window.top.consoleWindow; + + if (!win) { + this.popupBlocker=true; + alert("Popup window manager blocking the Log4js popup window to bedisplayed.\n\n" + + "Please disabled this to properly see logged events."); + } else { + + doc = win.document; + doc.open(); + doc.write("\n\n"); + doc.write("Log4js - " + this.logger.category + "\n"); + doc.write("\n"); + win.blur(); + win.focus(); + } + + this.docReference = doc; + this.winReference = win; + } else { + this.docReference = document; + this.winReference = window; + } + + this.outputCount = 0; + this.tagPattern = ".*"; + + // I hate writing javascript in HTML... but what's a better alternative + this.logElement = this.docReference.createElement('div'); + this.docReference.body.appendChild(this.logElement); + this.logElement.style.display = 'none'; + + this.logElement.style.position = "absolute"; + this.logElement.style.left = '0px'; + this.logElement.style.width = '100%'; + + this.logElement.style.textAlign = "left"; + this.logElement.style.fontFamily = "lucida console"; + this.logElement.style.fontSize = "100%"; + this.logElement.style.backgroundColor = 'darkgray'; + this.logElement.style.opacity = 0.9; + this.logElement.style.zIndex = 2000; + + // Add toolbarElement + this.toolbarElement = this.docReference.createElement('div'); + this.logElement.appendChild(this.toolbarElement); + this.toolbarElement.style.padding = "0 0 0 2px"; + + // Add buttons + this.buttonsContainerElement = this.docReference.createElement('span'); + this.toolbarElement.appendChild(this.buttonsContainerElement); + + if(this.inline) { + var closeButton = this.docReference.createElement('button'); + closeButton.style.cssFloat = "right"; + closeButton.style.styleFloat = "right"; // IE dom bug...doesn't understand cssFloat + closeButton.style.color = "black"; + closeButton.innerHTML = "close"; + closeButton.onclick = Log4js.bind(this.toggle, this); + this.buttonsContainerElement.appendChild(closeButton); + } + + var clearButton = this.docReference.createElement('button'); + clearButton.style.cssFloat = "right"; + clearButton.style.styleFloat = "right"; // IE dom bug...doesn't understand cssFloat + clearButton.style.color = "black"; + clearButton.innerHTML = "clear"; + clearButton.onclick = Log4js.bind(this.logger.clear, this.logger); + this.buttonsContainerElement.appendChild(clearButton); + + + //Add CategoryName and Level Filter + this.tagFilterContainerElement = this.docReference.createElement('span'); + this.toolbarElement.appendChild(this.tagFilterContainerElement); + this.tagFilterContainerElement.style.cssFloat = 'left'; + + this.tagFilterContainerElement.appendChild(this.docReference.createTextNode("Log4js - " + this.logger.category)); + this.tagFilterContainerElement.appendChild(this.docReference.createTextNode(" | Level Filter: ")); + + this.tagFilterElement = this.docReference.createElement('input'); + this.tagFilterContainerElement.appendChild(this.tagFilterElement); + this.tagFilterElement.style.width = '200px'; + this.tagFilterElement.value = this.tagPattern; + this.tagFilterElement.setAttribute('autocomplete', 'off'); // So Firefox doesn't flip out + + Log4js.attachEvent(this.tagFilterElement, 'keyup', Log4js.bind(this.updateTags, this)); + Log4js.attachEvent(this.tagFilterElement, 'click', Log4js.bind( function() {this.tagFilterElement.select();}, this)); + + // Add outputElement + this.outputElement = this.docReference.createElement('div'); + this.logElement.appendChild(this.outputElement); + this.outputElement.style.overflow = "auto"; + this.outputElement.style.clear = "both"; + this.outputElement.style.height = (this.inline) ? ("200px"):("650px"); + this.outputElement.style.width = "100%"; + this.outputElement.style.backgroundColor = 'black'; + + this.inputContainerElement = this.docReference.createElement('div'); + this.inputContainerElement.style.width = "100%"; + this.logElement.appendChild(this.inputContainerElement); + + this.inputElement = this.docReference.createElement('input'); + this.inputContainerElement.appendChild(this.inputElement); + this.inputElement.style.width = '100%'; + this.inputElement.style.borderWidth = '0px'; // Inputs with 100% width always seem to be too large (I HATE THEM) they only work if the border, margin and padding are 0 + this.inputElement.style.margin = '0px'; + this.inputElement.style.padding = '0px'; + this.inputElement.value = 'Type command here'; + this.inputElement.setAttribute('autocomplete', 'off'); // So Firefox doesn't flip out + + Log4js.attachEvent(this.inputElement, 'keyup', Log4js.bind(this.handleInput, this)); + Log4js.attachEvent(this.inputElement, 'click', Log4js.bind( function() {this.inputElement.select();}, this)); + + if(this.inline){ + window.setInterval(Log4js.bind(this.repositionWindow, this), 500); + this.repositionWindow(); + // Allow acess key link + var accessElement = this.docReference.createElement('button'); + accessElement.style.position = "absolute"; + accessElement.style.top = "-100px"; + accessElement.accessKey = this.accesskey; + accessElement.onclick = Log4js.bind(this.toggle, this); + this.docReference.body.appendChild(accessElement); + } else { + this.show(); + } + }, + /** + * shows/hide an element + * @private + * @return true if shown + */ + toggle : function() { + if (this.logElement.style.display == 'none') { + this.show(); + return true; + } else { + this.hide(); + return false; + } + }, + /** + * @private + */ + show : function() { + this.logElement.style.display = ''; + this.outputElement.scrollTop = this.outputElement.scrollHeight; // Scroll to bottom when toggled + this.inputElement.select(); + }, + /** + * @private + */ + hide : function() { + this.logElement.style.display = 'none'; + }, + /** + * @private + * @param message + * @style + */ + output : function(message, style) { + + // If we are at the bottom of the window, then keep scrolling with the output + var shouldScroll = (this.outputElement.scrollTop + (2 * this.outputElement.clientHeight)) >= this.outputElement.scrollHeight; + + this.outputCount++; + style = (style ? style += ';' : ''); + style += 'padding:1px;margin:0 0 5px 0'; + + if (this.outputCount % 2 === 0) { + style += ";background-color:#101010"; + } + + message = message || "undefined"; + message = message.toString(); + + this.outputElement.innerHTML += "
" + message + "
"; + + if (shouldScroll) { + this.outputElement.scrollTop = this.outputElement.scrollHeight; + } + }, + + /** + * @private + */ + updateTags : function() { + + var pattern = this.tagFilterElement.value; + + if (this.tagPattern == pattern) { + return; + } + + try { + new RegExp(pattern); + } catch (e) { + return; + } + + this.tagPattern = pattern; + + this.outputElement.innerHTML = ""; + + // Go through each log entry again + this.outputCount = 0; + for (var i = 0; i < this.logger.loggingEvents.length; i++) { + this.doAppend(this.logger.loggingEvents[i]); + } + }, + + /** + * @private + */ + repositionWindow : function() { + var offset = window.pageYOffset || this.docReference.documentElement.scrollTop || this.docReference.body.scrollTop; + var pageHeight = self.innerHeight || this.docReference.documentElement.clientHeight || this.docReference.body.clientHeight; + this.logElement.style.top = (offset + pageHeight - this.logElement.offsetHeight) + "px"; + }, + + /** + * @param loggingEvent event to be logged + * @see Log4js.Appender#doAppend + */ + doAppend : function(loggingEvent) { + + if(this.popupBlocker) { + //popup blocked, we return in this case + return; + } + + if ((!this.inline) && (!this.winReference || this.winReference.closed)) { + this.initialize(); + } + + if (this.tagPattern !== null && + loggingEvent.level.toString().search(new RegExp(this.tagPattern, 'igm')) == -1) { + return; + } + + var style = ''; + + if (loggingEvent.level.toString().search(/ERROR/) != -1) { + style += 'color:red'; + } else if (loggingEvent.level.toString().search(/FATAL/) != -1) { + style += 'color:red'; + } else if (loggingEvent.level.toString().search(/WARN/) != -1) { + style += 'color:orange'; + } else if (loggingEvent.level.toString().search(/DEBUG/) != -1) { + style += 'color:green'; + } else if (loggingEvent.level.toString().search(/INFO/) != -1) { + style += 'color:white'; + } else { + style += 'color:yellow'; + } + + this.output(this.layout.format(loggingEvent), style); + }, + + /** + * @see Log4js.Appender#doClear + */ + doClear : function() { + this.outputElement.innerHTML = ""; + }, + /** + * @private + * @param e + */ + handleInput : function(e) { + if (e.keyCode == 13 ) { + var command = this.inputElement.value; + + switch(command) { + case "clear": + this.logger.clear(); + break; + + default: + var consoleOutput = ""; + + try { + consoleOutput = eval(this.inputElement.value); + } catch (e) { + this.logger.error("Problem parsing input <" + command + ">" + e.message); + break; + } + + this.logger.trace(consoleOutput); + break; + } + + if (this.inputElement.value !== "" && this.inputElement.value !== this.commandHistory[0]) { + this.commandHistory.unshift(this.inputElement.value); + } + + this.commandIndex = 0; + this.inputElement.value = ""; + } else if (e.keyCode == 38 && this.commandHistory.length > 0) { + this.inputElement.value = this.commandHistory[this.commandIndex]; + + if (this.commandIndex < this.commandHistory.length - 1) { + this.commandIndex += 1; + } + } else if (e.keyCode == 40 && this.commandHistory.length > 0) { + if (this.commandIndex > 0) { + this.commandIndex -= 1; + } + + this.inputElement.value = this.commandHistory[this.commandIndex]; + } else { + this.commandIndex = 0; + } + }, + + /** + * toString + */ + toString: function() { + return "Log4js.ConsoleAppender[inline=" + this.inline + "]"; + } +}); + +/** + * Metatag Appender writing the logs to meta tags + * + * @extends Log4js.Appender + * @constructor + * @param logger log4js instance this appender is attached to + * @author Stephan Strittmatter + */ +Log4js.MetatagAppender = function() { + this.currentLine = 0; +}; +Log4js.MetatagAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @param loggingEvent event to be logged + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + var now = new Date(); + var lines = loggingEvent.message.split("\n"); + var headTag = document.getElementsByTagName("head")[0]; + + for (var i = 1; i <= lines.length; i++) { + var value = lines[i - 1]; + if (i == 1) { + value = loggingEvent.level.toString() + ": " + value; + } else { + value = "> " + value; + } + + var metaTag = document.createElement("meta"); + metaTag.setAttribute("name", "X-log4js:" + this.currentLine); + metaTag.setAttribute("content", value); + headTag.appendChild(metaTag); + this.currentLine += 1; + } + }, + + /** + * toString + */ + toString: function() { + return "Log4js.MetatagAppender"; + } +}); + +/** + * AJAX Appender sending {@link Log4js.LoggingEvent}s asynchron via + * XMLHttpRequest to server.
+ * The {@link Log4js.LoggingEvent} is POSTed as response content and is + * formatted by the accociated layout. Default layout is {@link Log4js.XMLLayout}. + * The threshold defines when the logs + * should be send to the server. By default every event is sent on its + * own (threshold=1). If it is set to 10, then the events are send in groups of + * 10 events. + * + * @extends Log4js.Appender + * @constructor + * @param {Log4js.Logger} logger log4js instance this appender is attached to + * @param {String} loggingUrl url where appender will post log messages to + * @author Stephan Strittmatter + */ +Log4js.AjaxAppender = function(loggingUrl) { + + /** + * is still esnding data to server + * @type boolean + * @private + */ + this.isInProgress = false; + + /** + * @type String + * @private + */ + this.loggingUrl = loggingUrl || "logging.log4js"; + + /** + * @type Integer + * @private + */ + this.threshold = 1; + + /** + * timeout when request is aborted. + * @private + */ + this.timeout = 2000; + + /** + * List of LoggingEvents which should be send after threshold is reached. + * @type Map + * @private + */ + this.loggingEventMap = new Log4js.FifoBuffer(); + + /** + * @type Log4js.Layout + * @private + */ + this.layout = new Log4js.XMLLayout(); + /** + * @type XMLHttpRequest + * @private + */ + this.httpRequest = null; +}; + +Log4js.AjaxAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * sends the logs to the server + * @param loggingEvent event to be logged + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + log4jsLogger.trace("> AjaxAppender.append"); + + if (this.loggingEventMap.length() <= this.threshold || this.isInProgress === true) { + this.loggingEventMap.push(loggingEvent); + } + + if(this.loggingEventMap.length() >= this.threshold && this.isInProgress === false) { + //if threshold is reached send the events and reset current threshold + this.send(); + } + + log4jsLogger.trace("< AjaxAppender.append"); + }, + + /** @see Appender#doClear */ + doClear: function() { + log4jsLogger.trace("> AjaxAppender.doClear" ); + if(this.loggingEventMap.length() > 0) { + this.send(); + } + log4jsLogger.trace("< AjaxAppender.doClear" ); + }, + + /** + * Set the threshold when logs have to be send. Default threshold is 1. + * @praram {int} threshold new threshold + */ + setThreshold: function(threshold) { + log4jsLogger.trace("> AjaxAppender.setThreshold: " + threshold ); + this.threshold = threshold; + log4jsLogger.trace("< AjaxAppender.setThreshold" ); + }, + + /** + * Set the timeout in milli seconds until sending request is aborted. + * Default is 2000 ms. + * @param {int} milliseconds the new timeout + */ + setTimeout: function(milliseconds) { + this.timeout = milliseconds; + }, + + /** + * send the request. + */ + send: function() { + if(this.loggingEventMap.length() >0) { + + log4jsLogger.trace("> AjaxAppender.send"); + + + this.isInProgress = true; + var a = []; + + for(var i = 0; i < this.loggingEventMap.length() && i < this.threshold; i++) { + a.push(this.layout.format(this.loggingEventMap.pull())); + } + + var content = this.layout.getHeader(); + content += a.join(this.layout.getSeparator()); + content += this.layout.getFooter(); + + var appender = this; + if(this.httpRequest === null){ + this.httpRequest = this.getXmlHttpRequest(); + } + this.httpRequest.onreadystatechange = function() { + appender.onReadyStateChanged.call(appender); + }; + + this.httpRequest.open("POST", this.loggingUrl, true); + // set the request headers. + //this.httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + this.httpRequest.setRequestHeader("Content-type", this.layout.getContentType()); + //REFERER will be the top-level + // URI which may differ from the location of the error if + // it occurs in an included .js file + this.httpRequest.setRequestHeader("REFERER", location.href); + this.httpRequest.setRequestHeader("Content-length", content.length); + this.httpRequest.setRequestHeader("Connection", "close"); + this.httpRequest.send( content ); + + appender = this; + + try { + window.setTimeout(function(){ + log4jsLogger.trace("> AjaxAppender.timeout"); + appender.httpRequest.onreadystatechange = function(){return;}; + appender.httpRequest.abort(); + //this.httpRequest = null; + appender.isInProgress = false; + + if(appender.loggingEventMap.length() > 0) { + appender.send(); + } + log4jsLogger.trace("< AjaxAppender.timeout"); + }, this.timeout); + } catch (e) { + log4jsLogger.fatal(e); + } + log4jsLogger.trace("> AjaxAppender.send"); + } + }, + + /** + * @private + */ + onReadyStateChanged: function() { + log4jsLogger.trace("> AjaxAppender.onReadyStateChanged"); + var req = this.httpRequest; + if (this.httpRequest.readyState != 4) { + log4jsLogger.trace("< AjaxAppender.onReadyStateChanged: readyState " + req.readyState + " != 4"); + return; + } + + var success = ((typeof req.status === "undefined") || req.status === 0 || (req.status >= 200 && req.status < 300)); + + if (success) { + log4jsLogger.trace(" AjaxAppender.onReadyStateChanged: success"); + + //ready sending data + this.isInProgress = false; + + } else { + var msg = " AjaxAppender.onReadyStateChanged: XMLHttpRequest request to URL " + this.loggingUrl + " returned status code " + this.httpRequest.status; + log4jsLogger.error(msg); + } + + log4jsLogger.trace("< AjaxAppender.onReadyStateChanged: readyState == 4"); + }, + /** + * Get the XMLHttpRequest object independent of browser. + * @private + */ + getXmlHttpRequest: function() { + log4jsLogger.trace("> AjaxAppender.getXmlHttpRequest"); + + var httpRequest = false; + + try { + if (window.XMLHttpRequest) { // Mozilla, Safari, IE7... + httpRequest = new XMLHttpRequest(); + if (httpRequest.overrideMimeType) { + httpRequest.overrideMimeType(this.layout.getContentType()); + } + } else if (window.ActiveXObject) { // IE + try { + httpRequest = new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); + } + } + } catch (e) { + httpRequest = false; + } + + if (!httpRequest) { + log4jsLogger.fatal("Unfortunatelly your browser does not support AjaxAppender for log4js!"); + } + + log4jsLogger.trace("< AjaxAppender.getXmlHttpRequest"); + return httpRequest; + }, + + /** + * toString + */ + toString: function() { + return "Log4js.AjaxAppender[loggingUrl=" + this.loggingUrl + ", threshold=" + this.threshold + "]"; + } +}); + +/** + * File Appender writing the logs to a text file. + * PLEASE NOTE - Only works in IE and Mozilla + * use ActiveX to write file on IE + * use XPCom components to write file on Mozilla + * + * @extends Log4js.Appender + * @constructor + * @param logger log4js instance this appender is attached to + * @param file file log messages will be written to + * @author Seth Chisamore + * @author Nicolas Justin njustin@idealx.com + * @author Gregory Kokanosky gkokanosky@idealx.com + */ +Log4js.FileAppender = function(file) { + + this.layout = new Log4js.SimpleLayout(); + this.isIE = 'undefined'; + + this.file = file || "log4js.log"; + + try{ + this.fso = new ActiveXObject("Scripting.FileSystemObject"); + this.isIE = true; + } catch(e){ + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + this.fso = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + this.isIE = false; //mozilla & co + } catch (e) { + log4jsLogger.error(e); + } + } +}; + +Log4js.FileAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @param loggingEvent event to be logged + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + try { + var fileHandle = null; + + if( this.isIE === 'undefined') { + log4jsLogger.error("Unsupported ") + } + else if( this.isIE ){ + // try opening existing file, create if needed + fileHandle = this.fso.OpenTextFile(this.file, 8, true); + // write out our data + fileHandle.WriteLine(this.layout.format(loggingEvent)); + fileHandle.close(); + } else { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + this.fso.initWithPath(this.file); + if(!this.fso.exists()) { + //create file if needed + this.fso.create(0x00, 0600); + } + + fileHandle = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); + fileHandle.init( this.fso, 0x04 | 0x08 | 0x10, 064, 0); + var line = this.layout.format(loggingEvent); + fileHandle.write(line, line.length); //write data + fileHandle.close(); + } + } catch (e) { + log4jsLogger.error(e); + } + }, + /* + * @see Log4js.Appender#doClear + */ + doClear: function() { + try { + if( this.isIE ){ + var fileHandle = this.fso.GetFile(this.file); + fileHandle.Delete(); + } else { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + this.fso.initWithPath(this.file); + if(this.fso.exists()) { + this.fso.remove(false); + } + } + } catch (e) { + log4jsLogger.error(e); + } + }, + + /** + * toString + */ + toString: function() { + return "Log4js.FileAppender[file=" + this.file + "]"; + } +}); + +/** + * Windows Event Appender writes the logs to the Windows Event log. + * PLEASE NOTE - Only works in IE..uses ActiveX to write to Windows Event log + * + * @extends Log4js.Appender + * @constructor + * @param logger log4js instance this appender is attached to + * @author Seth Chisamore + */ +Log4js.WindowsEventAppender = function() { + + this.layout = new Log4js.SimpleLayout(); + + try { + this.shell = new ActiveXObject("WScript.Shell"); + } catch(e) { + log4jsLogger.error(e); + } +}; + +Log4js.WindowsEventAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @param loggingEvent event to be logged + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + var winLevel = 4; + + // Map log level to windows event log level. + // Windows events: - SUCCESS: 0, ERROR: 1, WARNING: 2, INFORMATION: 4, AUDIT_SUCCESS: 8, AUDIT_FAILURE: 16 + switch (loggingEvent.level) { + case Log4js.Level.FATAL: + winLevel = 1; + break; + case Log4js.Level.ERROR: + winLevel = 1; + break; + case Log4js.Level.WARN: + winLevel = 2; + break; + default: + winLevel = 4; + break; + } + + try { + this.shell.LogEvent(winLevel, this.level.format(loggingEvent)); + } catch(e) { + log4jsLogger.error(e); + } + }, + + /** + * toString + */ + toString: function() { + return "Log4js.WindowsEventAppender"; + } +}); + +/** + * JS Alert Appender writes the logs to the JavaScript alert dialog box + * @constructor + * @extends Log4js.Appender + * @param logger log4js instance this appender is attached to + * @author Sébastien LECACHEUR + */ +Log4js.JSAlertAppender = function() { + + this.layout = new Log4js.SimpleLayout(); +}; + +Log4js.JSAlertAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + alert(this.layout.getHeader() + this.layout.format(loggingEvent) + this.layout.getFooter()); + }, + + /** + * toString + */ + toString: function() { + return "Log4js.JSAlertAppender"; + } +}); + +/** + * Appender writes the logs to the JavaScript console of Mozilla browser + * More infos: http://kb.mozillazine.org/index.php?title=JavaScript_Console&redirect=no + * PLEASE NOTE - Only works in Mozilla browser + * @constructor + * @extends Log4js.Appender + * @param logger log4js instance this appender is attached to + * @author Stephan Strittmatter + */ +Log4js.MozillaJSConsoleAppender = function() { + this.layout = new Log4js.SimpleLayout(); + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + this.jsConsole = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService); + this.scriptError = Components.classes["@mozilla.org/scripterror;1"].createInstance(Components.interfaces.nsIScriptError); + } catch (e) { + log4jsLogger.error(e); + } +}; + +Log4js.MozillaJSConsoleAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + this.scriptError.init(this.layout.format(loggingEvent), null, null, null, null, this.levelCode(loggingEvent), loggingEvent.categoryName); + this.jsConsole.logMessage(this.scriptError); + } catch (e) { + log4jsLogger.error(e); + } + }, + + /** + * toString + */ + toString: function() { + return "Log4js.MozillaJSConsoleAppender"; + }, + + /** + * Map Log4js.Level to jsConsole Flags: + * + * @private + */ + levelCode: function(loggingEvent) + { + var retval; + switch (loggingEvent.level) { + case Log4js.Level.FATAL: + retval = 2;//nsIScriptError.exceptionFlag = 2 + break; + case Log4js.Level.ERROR: + retval = 0;//nsIScriptError.errorFlag + break; + case Log4js.Level.WARN: + retval = 1;//nsIScriptError.warningFlag = 1 + break; + default: + retval = 1;//nsIScriptError.warningFlag = 1 + break; + } + + return retval; + } +}); + +/** + * Appender writes the logs to the JavaScript console of Opera browser + * PLEASE NOTE - Only works in Opera browser + * @constructor + * @extends Log4js.Appender + * @param logger log4js instance this appender is attached to + * @author Stephan Strittmatter + */ +Log4js.OperaJSConsoleAppender = function() { + this.layout = new Log4js.SimpleLayout(); +}; + +Log4js.OperaJSConsoleAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + opera.postError(this.layout.format(loggingEvent)); + }, + + /** + * toString + */ + toString: function() { + return "Log4js.OperaJSConsoleAppender"; + } +}); + +/** + * Appender writes the logs to the JavaScript console of Safari browser + * PLEASE NOTE - Only works in Safari browser + * @constructor + * @extends Log4js.Appender + * @param logger log4js instance this appender is attached to + * @author Stephan Strittmatter + */ +Log4js.SafariJSConsoleAppender = function() { + this.layout = new Log4js.SimpleLayout(); +}; + +Log4js.SafariJSConsoleAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + window.console.log(this.layout.format(loggingEvent)); + }, + + /** + * toString + */ + toString: function() { + return "Log4js.SafariJSConsoleAppender"; + } +}); + +/** + * JavaScript Console Appender which is browser independent. + * It checks internally for the current browser and adds delegate to + * specific JavaScript Console Appender of the browser. + * + * @author Stephan Strittmatter + * @since 1.0 + */ +Log4js.BrowserConsoleAppender = function() { + /** + * Delegate for browser specific implementation + * @type Log4js.Appender + * @private + */ + this.consoleDelegate = null; + + if (window.console) { + this.consoleDelegate = new Log4js.SafariJSConsoleAppender(); + } + else if (window.opera) { + this.consoleDelegate = new Log4js.OperaJSConsoleAppender(); + } + else if(netscape) { + this.consoleDelegate = new Log4js.MozillaJSConsoleAppender(); + } + else { + //@todo + log4jsLogger.error("Unsupported Browser"); + } +}; + +Log4js.BrowserConsoleAppender.prototype = Log4js.extend(new Log4js.Appender(), { + /** + * @see Log4js.Appender#doAppend + */ + doAppend: function(loggingEvent) { + this.consoleDelegate.doAppend(loggingEvent); + }, + /** + * @see Log4js.Appender#doClear + */ + doClear: function() { + this.consoleDelegate.doClear(); + }, + /** + * @see Log4js.Appender#setLayout + */ + setLayout: function(layout){ + this.consoleDelegate.setLayout(layout); + }, + + /** + * toString + */ + toString: function() { + return "Log4js.BrowserConsoleAppender: " + this.consoleDelegate.toString(); + } +}); + +/** + * SimpleLayout consists of the level of the log statement, followed by " - " + * and then the log message itself. For example, + * DEBUG - Hello world + * + * @constructor + * @extends Log4js.Layout + * @extends Layout + * @author Stephan Strittmatter + */ +Log4js.SimpleLayout = function() { + this.LINE_SEP = "\n"; + this.LINE_SEP_LEN = 1; +}; + +Log4js.SimpleLayout.prototype = Log4js.extend(new Log4js.Layout(), { + /** + * Implement this method to create your own layout format. + * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to format + * @return formatted String + * @type String + */ + format: function(loggingEvent) { + return loggingEvent.level.toString() + " - " + loggingEvent.message + this.LINE_SEP; + }, + /** + * Returns the content type output by this layout. + * @return The base class returns "text/plain". + * @type String + */ + getContentType: function() { + return "text/plain"; + }, + /** + * @return Returns the header for the layout format. The base class returns null. + * @type String + */ + getHeader: function() { + return ""; + }, + /** + * @return Returns the footer for the layout format. The base class returns null. + * @type String + */ + getFooter: function() { + return ""; + } +}); + +/** + * BasicLayout is a simple layout for storing the loggs. The loggs are stored + * in following format: + *
+ * categoryName~startTime [logLevel] message\n
+ * 
+ * + * @constructor + * @extends Log4js.Layout + * @author Stephan Strittmatter + */ +Log4js.BasicLayout = function() { + this.LINE_SEP = "\n"; +}; + +Log4js.BasicLayout.prototype = Log4js.extend(new Log4js.Layout(), { + /** + * Implement this method to create your own layout format. + * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to format + * @return formatted String + * @type String + */ + format: function(loggingEvent) { + return loggingEvent.categoryName + "~" + loggingEvent.startTime.toLocaleString() + " [" + loggingEvent.level.toString() + "] " + loggingEvent.message + this.LINE_SEP; + }, + /** + * Returns the content type output by this layout. + * @return The base class returns "text/plain". + * @type String + */ + getContentType: function() { + return "text/plain"; + }, + /** + * @return Returns the header for the layout format. The base class returns null. + * @type String + */ + getHeader: function() { + return ""; + }, + /** + * @return Returns the footer for the layout format. The base class returns null. + * @type String + */ + getFooter: function() { + return ""; + } +}); + +/** + * HtmlLayout write the logs in Html format. + * + * @constructor + * @extends Log4js.Layout + * @author Stephan Strittmatter + */ +Log4js.HtmlLayout = function() {return;}; + +Log4js.HtmlLayout.prototype = Log4js.extend(new Log4js.Layout(), { + /** + * Implement this method to create your own layout format. + * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to format + * @return formatted String + * @type String + */ + format: function(loggingEvent) { + return "
" + loggingEvent.getFormattedTimestamp() + " - " + loggingEvent.level.toString() + " - " + loggingEvent.message + "
\n"; + }, + /** + * Returns the content type output by this layout. + * @return The base class returns "text/html". + * @type String + */ + getContentType: function() { + return "text/html"; + }, + /** + * @return Returns the header for the layout format. The base class returns null. + * @type String + */ + getHeader: function() { + return "log4js</head><body>"; + }, + /** + * @return Returns the footer for the layout format. The base class returns null. + * @type String + */ + getFooter: function() { + return "</body></html>"; + }, + + getStyle: function(loggingEvent) + { + var style; + if (loggingEvent.level.toString().search(/ERROR/) != -1) { + style = 'color:red'; + } else if (loggingEvent.level.toString().search(/FATAL/) != -1) { + style = 'color:red'; + } else if (loggingEvent.level.toString().search(/WARN/) != -1) { + style = 'color:orange'; + } else if (loggingEvent.level.toString().search(/DEBUG/) != -1) { + style = 'color:green'; + } else if (loggingEvent.level.toString().search(/INFO/) != -1) { + style = 'color:white'; + } else { + style = 'color:yellow'; + } + return style; + } +}); + +/** + * XMLLayout write the logs in XML format. + * Layout is simmilar to log4j's XMLLayout: + * <pre> + * <log4js:event category="category" level="Level" client="Client" referer="ref" timestam="Date"> + * <log4js:message>Logged message</log4js:message> + * </log4js:event> + * </pre> + * @constructor + * @extends Layout + * @author Stephan Strittmatter + */ +Log4js.XMLLayout = function(){return;}; +Log4js.XMLLayout.prototype = Log4js.extend(new Log4js.Layout(), { + /** + * Implement this method to create your own layout format. + * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to format + * @return formatted String + * @type String + */ + format: function(loggingEvent) { + var useragent = "unknown"; + try { + useragent = navigator.userAgent; + } catch(e){ + useragent = "unknown"; + } + + var referer = "unknown"; + try { + referer = location.href; + } catch(e){ + referer = "unknown"; + } + + var content = "<log4js:event logger=\""; + content += loggingEvent.categoryName + "\" level=\""; + content += loggingEvent.level.toString() + "\" useragent=\""; + content += useragent + "\" referer=\""; + content += referer.replace(/&/g, "&") + "\" timestamp=\""; + content += loggingEvent.getFormattedTimestamp() + "\">\n"; + content += "\t<log4js:message><![CDATA[" + this.escapeCdata(loggingEvent.message) + "]]></log4js:message>\n"; + + if (loggingEvent.exception) { + content += this.formatException(loggingEvent.exception) ; + } + content += "</log4js:event>\n"; + + return content; + }, + /** + * Returns the content type output by this layout. + * @return The base class returns "text/xml". + * @type String + */ + getContentType: function() { + return "text/xml"; + }, + /** + * @return Returns the header for the layout format. The base class returns null. + * @type String + */ + getHeader: function() { + return "<log4js:eventSet version=\"" + Log4js.version + + "\" xmlns:log4js=\"http://log4js.berlios.de/2007/log4js/\">\n"; + }, + /** + * @return Returns the footer for the layout format. The base class returns null. + * @type String + */ + getFooter: function() { + return "</log4js:eventSet>\n"; + }, + + getSeparator: function() { + return "\n"; + }, + + /** + * better readable formatted Exceptions. + * @param ex {Exception} the exception to be formatted. + * @return {String} the formatted String representation of the exception. + * @private + */ + formatException: function(ex) { + if (ex) { + var exStr = "\t<log4js:throwable>"; + if (ex.message) { + exStr += "\t\t<log4js:message><![CDATA[" + this.escapeCdata(ex.message) + "]]></log4js:message>\n"; + } + if (ex.description) { + exStr += "\t\t<log4js:description><![CDATA[" + this.escapeCdata(ex.description) + "]]></log4js:description>\n"; + } + + exStr += "\t\t<log4js:stacktrace>"; + exStr += "\t\t\t<log4js:location fileName=\""+ex.fileName+"\" lineNumber=\""+ex.lineNumber+"\" />"; + exStr += "\t\t</log4js:stacktrace>"; + exStr = "\t</log4js:throwable>"; + return exStr; + } + return null; + }, + /** + * Escape Cdata messages + * @param str {String} message to escape + * @return {String} the escaped message + * @private + */ + escapeCdata: function(str) { + return str.replace(/\]\]>/, "]]>]]><![CDATA["); + } +}); + +/** + * JSONLayout write the logs in JSON format. + * JSON library is required to use this Layout. See also {@link http://www.json.org} + * @constructor + * @extends Log4js.Layout + * @author Stephan Strittmatter + */ +Log4js.JSONLayout = function() { + this.df = new Log4js.DateFormatter(); +}; +Log4js.JSONLayout.prototype = Log4js.extend(new Log4js.Layout(), { + /** + * Implement this method to create your own layout format. + * @param {Log4js.LoggingEvent} loggingEvent loggingEvent to format + * @return formatted String + * @type String + */ + format: function(loggingEvent) { + + var useragent = "unknown"; + try { + useragent = navigator.userAgent; + } catch(e){ + useragent = "unknown"; + } + + var referer = "unknown"; + try { + referer = location.href; + } catch(e){ + referer = "unknown"; + } + + var jsonString = "{\n \"LoggingEvent\": {\n"; + + jsonString += "\t\"logger\": \"" + loggingEvent.categoryName + "\",\n"; + jsonString += "\t\"level\": \"" + loggingEvent.level.toString() + "\",\n"; + jsonString += "\t\"message\": \"" + loggingEvent.message + "\",\n"; + jsonString += "\t\"referer\": \"" + referer + "\",\n"; + jsonString += "\t\"useragent\": \"" + useragent + "\",\n"; + jsonString += "\t\"timestamp\": \"" + this.df.formatDate(loggingEvent.startTime, "yyyy-MM-ddThh:mm:ssZ") + "\",\n"; + jsonString += "\t\"exception\": \"" + loggingEvent.exception + "\"\n"; + jsonString += "}}"; + + return jsonString; + }, + /** + * Returns the content type output by this layout. + * @return The base class returns "text/xml". + * @type String + */ + getContentType: function() { + return "text/json"; + }, + /** + * @return Returns the header for the layout format. The base class returns null. + * @type String + */ + getHeader: function() { + return "{\"Log4js\": [\n"; + }, + /** + * @return Returns the footer for the layout format. The base class returns null. + * @type String + */ + getFooter: function() { + return "\n]}"; + }, + + getSeparator: function() { + return ",\n"; + } +}); + +/** + * PatternLayout + */ +Log4js.PatternLayout = function(pattern) { + if (pattern) { + this.pattern = pattern; + } else { + this.pattern = Log4js.PatternLayout.DEFAULT_CONVERSION_PATTERN; + } +}; + +Log4js.PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n"; +Log4js.PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n"; +Log4js.PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS"; +Log4js.PatternLayout.DATETIME_DATEFORMAT = "dd MMM YYYY HH:mm:ss,SSS"; +Log4js.PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS"; + +Log4js.PatternLayout.prototype = Log4js.extend(new Log4js.Layout(), { + /** + * Returns the content type output by this layout. + * @return "text/plain". + * @type String + */ + getContentType: function() { + return "text/plain"; + }, + /** + * @return Returns the header for the layout format. + * @type String + */ + getHeader: function() { + return null; + }, + /** + * @return Returns the footer for the layout format. + * @type String + */ + getFooter: function() { + return null; + }, + + format: function(loggingEvent) { + var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([cdmnpr%])(\{([^\}]+)\})?|([^%]+)/; + var formattedString = ""; + var result; + var searchString = this.pattern; + + // Cannot use regex global flag since it doesn't work in IE5 + while ((result = regex.exec(searchString))) { + var matchedString = result[0]; + var padding = result[1]; + var truncation = result[2]; + var conversionCharacter = result[3]; + var specifier = result[5]; + var text = result[6]; + + // Check if the pattern matched was just normal text + if (text) { + formattedString += "" + text; + } else { + // Create a raw replacement string based on the conversion + // character and specifier + var replacement = ""; + switch(conversionCharacter) { + case "c": + var loggerName = loggingEvent.categoryName; + if (specifier) { + var precision = parseInt(specifier, 10); + var loggerNameBits = loggingEvent.categoryName.split("."); + if (precision >= loggerNameBits.length) { + replacement = loggerName; + } else { + replacement = loggerNameBits.slice(loggerNameBits.length - precision).join("."); + } + } else { + replacement = loggerName; + } + break; + case "d": + var dateFormat = Log4js.PatternLayout.ISO8601_DATEFORMAT; + if (specifier) { + dateFormat = specifier; + // Pick up special cases + if (dateFormat == "ISO8601") { + dateFormat = Log4js.PatternLayout.ISO8601_DATEFORMAT; + } else if (dateFormat == "ABSOLUTE") { + dateFormat = Log4js.PatternLayout.ABSOLUTETIME_DATEFORMAT; + } else if (dateFormat == "DATE") { + dateFormat = Log4js.PatternLayout.DATETIME_DATEFORMAT; + } + } + // Format the date + replacement = (new Log4js.SimpleDateFormat(dateFormat)).format(loggingEvent.startTime); + break; + case "m": + replacement = loggingEvent.message; + break; + case "n": + replacement = "\n"; + break; + case "p": + replacement = loggingEvent.level.toString(); + break; + case "r": + replacement = "" + loggingEvent.startTime.toLocaleTimeString(); //TODO: .getDifference(Log4js.applicationStartDate); + break; + case "%": + replacement = "%"; + break; + default: + replacement = matchedString; + break; + } + // Format the replacement according to any padding or + // truncation specified + + var len; + + // First, truncation + if (truncation) { + len = parseInt(truncation.substr(1), 10); + replacement = replacement.substring(0, len); + } + // Next, padding + if (padding) { + if (padding.charAt(0) == "-") { + len = parseInt(padding.substr(1), 10); + // Right pad with spaces + while (replacement.length < len) { + replacement += " "; + } + } else { + len = parseInt(padding, 10); + // Left pad with spaces + while (replacement.length < len) { + replacement = " " + replacement; + } + } + } + formattedString += replacement; + } + searchString = searchString.substr(result.index + result[0].length); + } + return formattedString; + } +}); + +/** + * @private + * @ignore + */ +if (!Array.prototype.push) { + /** + * Functions taken from Prototype library, didn't want to require for just few + * functions. + * More info at {@link http:// + * prototype.conio.net/} + * @private + */ + Array.prototype.push = function() { + var startLength = this.length; + for (var i = 0; i < arguments.length; i++) { + this[startLength + i] = arguments[i]; + } + return this.length; + }; +} + +/** + * FIFO buffer + * @private + */ +Log4js.FifoBuffer = function() +{ + this.array = new Array(); +}; + +Log4js.FifoBuffer.prototype = { + + /** + * @param {Object} obj any object added to buffer + */ + push : function(obj) { + this.array[this.array.length] = obj; + return this.array.length; + }, + + /** + * @return first putted in Object + */ + pull : function() { + if (this.array.length > 0) { + var firstItem = this.array[0]; + for (var i = 0; i < this.array.length - 1; i++) { + this.array[i] = this.array[i + 1]; + } + this.array.length = this.array.length - 1; + return firstItem; + } + return null; + }, + + length : function() { + return this.array.length; + } +}; + + + +/** + * Date Formatter + * addZero() and formatDate() are courtesy of Mike Golding: + * http://www.mikezilla.com/exp0015.html + * @private + */ +Log4js.DateFormatter = function() { + return; +}; +/** + * default format of date (ISO-8601) + * @static + * @final + */ +Log4js.DateFormatter.DEFAULT_DATE_FORMAT = "yyyy-MM-ddThh:mm:ssO"; + + +Log4js.DateFormatter.prototype = { + /** + * Formats the given date by the given pattern.<br /> + * Following switches are supported: + * <ul> + * <li>yyyy: The year</li> + * <li>MM: the month</li> + * <li>dd: the day of month<li> + * <li>hh: the hour<li> + * <li>mm: minutes</li> + * <li>O: timezone offset</li> + * </ul> + * @param {Date} vDate the date to format + * @param {String} vFormat the format pattern + * @return {String} formatted date string + * @static + */ + formatDate : function(vDate, vFormat) { + var vDay = this.addZero(vDate.getDate()); + var vMonth = this.addZero(vDate.getMonth()+1); + var vYearLong = this.addZero(vDate.getFullYear()); + var vYearShort = this.addZero(vDate.getFullYear().toString().substring(3,4)); + var vYear = (vFormat.indexOf("yyyy")>-1?vYearLong:vYearShort); + var vHour = this.addZero(vDate.getHours()); + var vMinute = this.addZero(vDate.getMinutes()); + var vSecond = this.addZero(vDate.getSeconds()); + var vTimeZone = this.O(vDate); + var vDateString = vFormat.replace(/dd/g, vDay).replace(/MM/g, vMonth).replace(/y{1,4}/g, vYear); + vDateString = vDateString.replace(/hh/g, vHour).replace(/mm/g, vMinute).replace(/ss/g, vSecond); + vDateString = vDateString.replace(/O/g, vTimeZone); + return vDateString; + }, + + /** + * @private + * @static + */ + addZero : function(vNumber) { + return ((vNumber < 10) ? "0" : "") + vNumber; + }, + + /** + * Formates the TimeOffest + * Thanks to http://www.svendtofte.com/code/date_format/ + * @private + */ + O : function (date) { + // Difference to Greenwich time (GMT) in hours + var os = Math.abs(date.getTimezoneOffset()); + var h = String(Math.floor(os/60)); + var m = String(os%60); + h.length == 1? h = "0"+h:1; + m.length == 1? m = "0"+m:1; + return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m; + } +}; + + +/** + * internal Logger to be used + * @private + */ +var log4jsLogger = Log4js.getLogger("Log4js"); +log4jsLogger.addAppender(new Log4js.ConsoleAppender()); +log4jsLogger.setLevel(Log4js.Level.ALL); \ No newline at end of file diff --git a/trunk/mindplot/src/main/javascript/MindmapDesigner.js b/trunk/mindplot/src/main/javascript/MindmapDesigner.js index d4b7c9d3..e781f953 100644 --- a/trunk/mindplot/src/main/javascript/MindmapDesigner.js +++ b/trunk/mindplot/src/main/javascript/MindmapDesigner.js @@ -426,6 +426,9 @@ mindplot.MindmapDesigner.prototype.loadFromXML = function(mapId, xmlContent) // Place the focus on the Central Topic var centralTopic = this.getCentralTopic(); this._goToNode.attempt(centralTopic, this); + + this._fireEvent("loadsuccess"); + }; mindplot.MindmapDesigner.prototype.load = function(mapId) @@ -444,6 +447,8 @@ mindplot.MindmapDesigner.prototype.load = function(mapId) // Place the focus on the Central Topic var centralTopic = this.getCentralTopic(); this._goToNode.attempt(centralTopic, this); + + this._fireEvent("loadsuccess"); }; mindplot.MindmapDesigner.prototype._loadMap = function(mapId, mindmapModel) @@ -466,6 +471,8 @@ mindplot.MindmapDesigner.prototype._loadMap = function(mapId, mindmapModel) nodeGraph.setBranchVisibility(true); } } + this._fireEvent("loadsuccess"); + }; diff --git a/trunk/mindplot/src/main/javascript/PersistanceManager.js b/trunk/mindplot/src/main/javascript/PersistanceManager.js index 2b53bf9c..eb29548b 100644 --- a/trunk/mindplot/src/main/javascript/PersistanceManager.js +++ b/trunk/mindplot/src/main/javascript/PersistanceManager.js @@ -1,22 +1,22 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ - +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* $Id: file 64488 2006-03-10 17:32:09Z paulo $ +*/ + mindplot.PersistanceManager = function(editorService) { this._editorService = editorService; @@ -43,7 +43,7 @@ mindplot.PersistanceManager.prototype.save = function(mindmap, chartType, xmlCha if (response.msgCode != "OK") { monitor.logError("Save could not be completed. Please,try again in a couple of minutes."); - core.Logger.logError(response.msgDetails); + wLogger.error(response.msgDetails); } else { // Execute on success handler ... @@ -56,7 +56,7 @@ mindplot.PersistanceManager.prototype.save = function(mindmap, chartType, xmlCha errorHandler:function(message) { var monitor = core.Monitor.getInstance(); monitor.logError("Save could not be completed. Please,try again in a couple of minutes."); - core.Logger.logError(message); + wLogger.error(message); }, verb:"POST", async: false @@ -89,7 +89,7 @@ mindplot.PersistanceManager.prototype.load = function(mapId) var msg = response.msgDetails; var monitor = core.Monitor.getInstance(); monitor.logFatal("We're sorry, an error has occurred and we can't load your map. Please try again in a few minutes."); - core.Logger.logError(msg); + wLogger.error(msg); } }, verb:"GET", @@ -97,7 +97,7 @@ mindplot.PersistanceManager.prototype.load = function(mapId) errorHandler:function(msg) { var monitor = core.Monitor.getInstance(); monitor.logFatal("We're sorry, an error has occurred and we can't load your map. Please try again in a few minutes."); - core.Logger.logError(msg); + wLogger.error(msg); } }); diff --git a/trunk/web2d/src/main/javascript/peer/svg/GroupPeer.js b/trunk/web2d/src/main/javascript/peer/svg/GroupPeer.js index 879584b7..eef85194 100644 --- a/trunk/web2d/src/main/javascript/peer/svg/GroupPeer.js +++ b/trunk/web2d/src/main/javascript/peer/svg/GroupPeer.js @@ -1,22 +1,22 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ - +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* $Id: file 64488 2006-03-10 17:32:09Z paulo $ +*/ + web2d.peer.svg.GroupPeer = function() { var svgElement = window.document.createElementNS(this.svgNamespace, 'g'); @@ -77,7 +77,6 @@ web2d.peer.svg.GroupPeer.prototype.updateTransform = function() var cx = this._position.x - this._coordOrigin.x * sx; var cy = this._position.y - this._coordOrigin.y * sy; - //Logger.logMsg("Group.updateTrasform:"+"translate("+ cx + "," + cy+ ") scale("+ sx + "," + sy + ")"); this._native.setAttribute("transform", "translate(" + cx + "," + cy + ") scale(" + sx + "," + sy + ")"); }; diff --git a/trunk/wise-webapp/src/main/java/com/wisemapping/filter/UserAgent.java b/trunk/wise-webapp/src/main/java/com/wisemapping/filter/UserAgent.java index 915eb7c6..d1c20b1c 100644 --- a/trunk/wise-webapp/src/main/java/com/wisemapping/filter/UserAgent.java +++ b/trunk/wise-webapp/src/main/java/com/wisemapping/filter/UserAgent.java @@ -312,7 +312,8 @@ public class UserAgent implements Serializable { public boolean isBrowserSupported() { // Is it a supported browser ?. final UserAgent.Product product = this.getProduct(); - boolean result = product == UserAgent.Product.FIREFOX && this.isVersionGreatedOrEqualThan(1, 5); + boolean result = product == UserAgent.Product.FIREFOX && ((this.isVersionGreatedOrEqualThan(1, 5) && this.getOs() != UserAgent.OS.MAC) || (this.isVersionGreatedOrEqualThan(3, 0) && this.getOs() == UserAgent.OS.MAC)); + result = result || product == UserAgent.Product.EXPLORER && this.isVersionGreatedOrEqualThan(6, 0) && this.getOs() == UserAgent.OS.WINDOWS; result = result || product == UserAgent.Product.OPERA && this.isVersionGreatedOrEqualThan(9, 2); return result; diff --git a/trunk/wise-webapp/src/main/webapp/WEB-INF/classes/messages.properties b/trunk/wise-webapp/src/main/webapp/WEB-INF/classes/messages.properties index 0edb1166..21bf2fd7 100644 --- a/trunk/wise-webapp/src/main/webapp/WEB-INF/classes/messages.properties +++ b/trunk/wise-webapp/src/main/webapp/WEB-INF/classes/messages.properties @@ -70,6 +70,7 @@ YES=yes NO=no EDITOR.LOADING=Loading ... +EDITOR.ERROR_LOADING=An unexpected error has occurred initializing this page. <br/>We'll solve this problem as soon as possible. Please, click <a href="mymaps.htm">here</a> to return to your mindmap list. SITE.TITLE=WiseMapping SITE.SLOGAN=Visual Thinking Evolution SAVE=Save diff --git a/trunk/wise-webapp/src/main/webapp/css/editor.css b/trunk/wise-webapp/src/main/webapp/css/editor.css index 8a716d83..7c3d8429 100644 --- a/trunk/wise-webapp/src/main/webapp/css/editor.css +++ b/trunk/wise-webapp/src/main/webapp/css/editor.css @@ -24,7 +24,7 @@ html { top: 30px; } -#loadingContainer { +#waitingContainer,#errorContainer { position: relative; top: 80px; height: 120px; /*background: whitesmoke;*/ @@ -36,7 +36,12 @@ html { } -#loadingContainer .loadingText { +#errorContainer { + width: 400px; + border: 1px solid red; +} + +#waitingContainer .loadingText { position: relative; top: 50%; margin-top: -35px; @@ -47,9 +52,32 @@ html { float: left; } -#loadingContainer .loadingIcon { +#errorContainer .loadingText { position: relative; - background: url( ../images/loadingIcon.gif ) no-repeat; + top: 50%; + margin-top: -80px; + font-size: 15px; + font-weight: bold; + vertical-align: text-bottom; + height: 30px; + float: right; + padding-left:120px; +} + +#waitingContainer .loadingIcon { + position: relative; + background: url(../images/loadingIcon.gif) no-repeat; + top: 50%; + margin-top: -65px; + height: 100px; + width: 121px; + float: left; + clear: both; +} + +#errorContainer .loadingIcon { + position: relative; + background: url(../images/errorIcon.png) no-repeat; top: 50%; margin-top: -65px; height: 100px; @@ -107,7 +135,7 @@ div#toolbar .buttonContainer { border: 1px solid #BBB4D6; padding: 2px; margin: 1px; - padding-bottom:4px; + padding-bottom: 4px; } .buttonContainer legend { @@ -118,8 +146,8 @@ div#toolbar .buttonContainer { font-size: 11px; text-align: right; margin: 0px; - -moz-margin-start:7px; - -moz-margin-end:7px; + -moz-margin-start: 7px; + -moz-margin-end: 7px; } div#toolbar .button { @@ -128,7 +156,7 @@ div#toolbar .button { float: left; margin: 0px 2px 2px 2px; cursor: pointer; - text-align:center; + text-align: center; } div#toolbar .comboButton { @@ -150,22 +178,21 @@ div#toolbar .comboButton:hover { width: 34px; } -div#toolbar .button img{ +div#toolbar .button img { width: 30px; height: 30px; - border:0; + border: 0; } -div#toolbar .toolbarLabel{ - position:relative; - top:55%; - text-align:center; - width:34px; - height:36px; - font-size:10px; +div#toolbar .toolbarLabel { + position: relative; + top: 55%; + text-align: center; + width: 34px; + height: 36px; + font-size: 10px; } - .mapSeparator { width: 1px; height: 20px; @@ -175,151 +202,149 @@ div#toolbar .toolbarLabel{ } div#file, div#zoom, div#node, div#font, div#share { - position:absolute; - top:-6px; - left:3px; + position: absolute; + top: -6px; + left: 3px; } div#zoom { - left:229px; + left: 229px; } div#node { - left:311px; + left: 311px; } div#font { - left:619px; - /*left:581px;*/ + left: 619px; /*left:581px;*/ } div#share { - left:815px; - /*left:777px;*/ + left: 815px; /*left:777px;*/ } div#saveButton { - background: url( ../images/save.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/save.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#discardButton { - background: url( ../images/close.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/close.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#history { - background: url( ../images/history.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/history.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#print { - background: url( ../images/file_printer.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/file_printer.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#undoEdition { - background: url( ../images/file_undo_dis.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/file_undo_dis.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#redoEdition { - background: url( ../images/file_redo_dis.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/file_redo_dis.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #export { - background: url( ../images/file_export.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/file_export.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#zoomIn { - background: url( ../images/zoom_in.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/zoom_in.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #zoomOut { - background: url( ../images/zoom_out.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/zoom_out.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #addTopic { - background: url( ../images/topic_add.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/topic_add.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #deleteTopic { - background: url( ../images/topic_delete.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/topic_delete.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#topicColor { - background: url( ../images/topic_bgcolor.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/topic_bgcolor.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); z-index: 4; } div#topicIcon { - background: url( ../images/topic_icon.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/topic_icon.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); z-index: 4; } div#topicNote { - background: url( ../images/note.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/note.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); z-index: 4; } div#topicLink { - background: url( ../images/topic_link.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/topic_link.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); z-index: 4; } div#topicNote { - background-image: url( ../images/note.png ); - behavior: url( ../css/iepngfix.htc ); + background-image: url(../images/note.png); + behavior: url(../css/iepngfix.htc); z-index: 4; } #topicBorder { - background: url( ../images/topic_border.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/topic_border.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); width: 30px; } #fontFamily { - background: url( ../images/font_type.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/font_type.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #topicShape { - background: url( ../images/topic_shape.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/topic_shape.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); width: 30px; } #fontBold { - background: url( ../images/font_bold.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/font_bold.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #fontItalic { - background: url( ../images/font_italic.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/font_italic.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } div#fontColor { - background: url( ../images/font_color.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/font_color.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); z-index: 4; } #fontSize { float: left; - background: url( ../images/font_size.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/font_size.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #font-size { @@ -336,19 +361,19 @@ div#fontColor { } #shareIt { - background: url( ../images/collab_share.png ) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/collab_share.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #publishIt { - background: url( ../images/collab_publish.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/collab_publish.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #tagIt { - background: url( ../images/collab_tag.png) no-repeat center top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/collab_tag.png) no-repeat center top; + behavior: url(../css/iepngfix.htc); } #colorPalette { @@ -414,7 +439,7 @@ div#actionsContainer { width: 190px; right: 0; margin: 10px; - float:left; + float: left; } #actionsContainer .button { @@ -447,17 +472,16 @@ div#actionsContainer { text-decoration: none; } - #actionsContainer .buttonStart { width: 6px; height: 25px; - background: url( ../images/btnStart2.png ) no-repeat left top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/btnStart2.png) no-repeat left top; + behavior: url(../css/iepngfix.htc); float: left; } #actionsContainer .buttonBody { - background: url( ../images/btnBody2.png ); + background: url(../images/btnBody2.png); float: left; height: 18px; padding: 0px 5px; @@ -469,8 +493,8 @@ div#actionsContainer { #actionsContainer .buttonEnd { width: 7px; height: 23px; - background: url( ../images/btnEnd2.png ) no-repeat right top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/btnEnd2.png) no-repeat right top; + behavior: url(../css/iepngfix.htc); float: left; } @@ -489,8 +513,8 @@ div#footerEditor { width: 80px; float: right; margin: 5px; - background: url( ../images/logo-vsmall.png ) no-repeat right top; - behavior: url( ../css/iepngfix.htc ); + background: url(../images/logo-vsmall.png) no-repeat right top; + behavior: url(../css/iepngfix.htc); } #footerEditor .msgLoggerContainer { @@ -508,14 +532,14 @@ div#msgStart { float: left; height: 36px; width: 16px; - background: url( ../images/footerStart.png ) no-repeat right top; + background: url(../images/footerStart.png) no-repeat right top; } div#msgEnd { float: left; height: 36px; width: 16px; - background: url( ../images/footerEnd.png ) no-repeat right top; + background: url(../images/footerEnd.png) no-repeat right top; } @@ -523,7 +547,7 @@ div#msgLogger { float: left; height: 36px; width: 500px; - background: url( ../images/footerBody.png ) repeat-x right top; + background: url(../images/footerBody.png) repeat-x right top; text-align: center; white-space: nowrap; padding: 5px; @@ -567,7 +591,7 @@ ol#toc li { } ol#toc a { - background: #fff url( ../images/tab4.png ); + background: #fff url(../images/tab4.png); color: #008; display: block; float: left; @@ -597,7 +621,7 @@ ol#toc li.current span { } ol#toc span { - background: #fff url( ../images/tab4.png ) 100% 0; + background: #fff url(../images/tab4.png) 100% 0; display: block; line-height: 2em; padding-right: 10px; @@ -612,7 +636,7 @@ ol#toc span { } #workspaceContainer { - background: url( ../images/grid.gif ) bottom left repeat !important; + background: url(../images/grid.gif) bottom left repeat !important; } @@ -653,8 +677,8 @@ span#lastSaved { opacity: 0.9; cursor: move; background-color: #69686F; - filter: alpha( opacity = 90 ); - color:#000c8f; + filter: alpha(opacity = 90); + color: #000c8f; } #tryEditorWarning a { @@ -681,7 +705,7 @@ div#helpContainer { padding: 20px; cursor: move; background-color: #69686F; - filter: alpha( opacity = 90 ); + filter: alpha(opacity = 90); } div#helpContent h1 { @@ -703,7 +727,7 @@ div.close { top: 7px; right: 10px; cursor: pointer; - background: url( ../images/close12_1.gif ) bottom left no-repeat !important; + background: url(../images/close12_1.gif) bottom left no-repeat !important; } div#helpContent li { @@ -716,5 +740,5 @@ div#helpContent li { div#small_error_icon { padding-left: 18px; min-height: 16px; - background: url( ../images/error_icon.png ) bottom left no-repeat !important; + background: url(../images/error_icon.png) bottom left no-repeat !important; } \ No newline at end of file diff --git a/trunk/wise-webapp/src/main/webapp/images/errorIcon.png b/trunk/wise-webapp/src/main/webapp/images/errorIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..bc396479b3622b179e147dba12e4b7c5b5304a88 GIT binary patch literal 14469 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 Xo_GP`sP$qM00000NkvXXu0mjfz(0M7 literal 0 HcmV?d00001 diff --git a/trunk/wise-webapp/src/main/webapp/js/editor.js b/trunk/wise-webapp/src/main/webapp/js/editor.js index a267f11d..745f12f0 100644 --- a/trunk/wise-webapp/src/main/webapp/js/editor.js +++ b/trunk/wise-webapp/src/main/webapp/js/editor.js @@ -1,22 +1,22 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ - +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Id: file 64488 2006-03-10 17:32:09Z paulo $ + */ + /*Extend mootools known keys*/ ExtendedKeys = { 'insert': 45, @@ -443,8 +443,14 @@ function afterWisemapLoading() shapeTypePanel(); fontSizePanel(); - // Disable loading dialog ... - setTimeout("loadingDialog.deactivate();", 500); + // If not problem has occured, I close the dialod ... + var closeDialog = function(){ + + if(!window.hasUnexpectedErrors) + { + waitDialog.deactivate(); + } + }.delay(500); } function buildIconChooser() { @@ -497,36 +503,7 @@ function buildMindmapDesigner() var monitor = new core.Monitor($('msgLoggerContainer'), $('msgLogger')); core.Monitor.setInstance(monitor); - // Initialize logger... - core.Logger.init(window.LoggerService); - var container = $('mindplot'); - var footer = $('footerEditor'); - if (core.UserAgent.isIframeWorkaroundRequired()) - { - var iframe = document.createElement('iframe'); - iframe.id = "mindplotIFrame"; - var top = container.offsetTop; - var bottom = footer.offsetTop; - iframe.setStyle('width', "100%"); - iframe.setStyle('height', bottom - top + "px"); - iframe.setStyle('overflow', "hidden"); - iframe.setStyle('border', "none"); - container.appendChild(iframe); - var mapContainer = "<div id='mindplot' style='background: url( ../images/grid.gif ) bottom left repeat !important;'></div><script>function styleMe() {" + - "var small_head = document.getElementsByTagName('head').item(0);" + - "var thestyle = document.createElement('link');" + - "thestyle.setAttribute('rel', 'stylesheet');thestyle.setAttribute('type', 'text/css');thestyle.setAttribute('href', '../css/bubble.css');small_head.appendChild(thestyle);}; styleMe();</script>"; - var doc = iframe.contentDocument; - if (doc == undefined || doc == null) - doc = iframe.contentWindow.document; - doc.open(); - doc.write(mapContainer); - doc.close(); - $(doc.body).setStyle('margin', '0px'); - container = doc.getElementById('mindplot'); - - } // Initialize Editor ... var persistantManager = new mindplot.PersistanceManager(window.MapEditorService); @@ -534,7 +511,7 @@ function buildMindmapDesigner() var screenWidth = window.getWidth(); var screenHeight = window.getHeight(); - // Positionate node ... h + // Positionate node ... // header - footer screenHeight = screenHeight - 90 - 61; diff --git a/trunk/wise-webapp/src/main/webapp/js/embedded.js b/trunk/wise-webapp/src/main/webapp/js/embedded.js index 1a517c6a..dcb9faa7 100644 --- a/trunk/wise-webapp/src/main/webapp/js/embedded.js +++ b/trunk/wise-webapp/src/main/webapp/js/embedded.js @@ -1,21 +1,21 @@ /* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* $Id: file 64488 2006-03-10 17:32:09Z paulo $ -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Id: file 64488 2006-03-10 17:32:09Z paulo $ + */ function afterCoreLoading() { @@ -34,7 +34,6 @@ function afterWisemapLoading() { buildMindmapDesigner(); - $('zoomIn').addEvent('click', function(event) { designer.zoomIn(); }); @@ -43,8 +42,16 @@ function afterWisemapLoading() designer.zoomOut(); }); - // Disable loading dialog ... - setTimeout("loadingDialog.deactivate();", 500); + + // If not problem has occured, I close the dialod ... + var closeDialog = function() { + + if (!window.hasUnexpectedErrors) + { + waitDialog.deactivate(); + } + }.delay(500); + } function setCurrentColorPicker(colorPicker) @@ -56,36 +63,7 @@ function setCurrentColorPicker(colorPicker) function buildMindmapDesigner() { - // Initialize logger... - core.Logger.init(window.LoggerService); - var container = $('mindplot'); - var footer = $('embFooter'); - if (core.UserAgent.isIframeWorkaroundRequired()) - { - var iframe = document.createElement('iframe'); - iframe.id = "mindplotIFrame"; - var top = container.offsetTop; - var bottom = footer.offsetTop; - iframe.setStyle('width', "100%"); - iframe.setStyle('height', bottom - top + "px"); - iframe.setStyle('overflow', "hidden"); - iframe.setStyle('border', "none"); - container.appendChild(iframe); - var mapContainer = "<div id='mindplot' style='background: url( ../images/grid.gif ) bottom left repeat !important;'></div><script>function styleMe() {" + - "var small_head = document.getElementsByTagName('head').item(0);" + - "var thestyle = document.createElement('link');" + - "thestyle.setAttribute('rel', 'stylesheet');thestyle.setAttribute('type', 'text/css');thestyle.setAttribute('href', '../css/bubble.css');small_head.appendChild(thestyle);}; styleMe();</script>"; - var doc = iframe.contentDocument; - if (doc == undefined || doc == null) - doc = iframe.contentWindow.document; - doc.open(); - doc.write(mapContainer); - doc.close(); - $(doc.body).setStyle('margin', '0px'); - container = doc.getElementById('mindplot'); - - } // Initialize Editor ... var persistantManager = new mindplot.PersistanceManager(window.MapEditorService); @@ -93,10 +71,6 @@ function buildMindmapDesigner() var screenWidth = window.getWidth(); var screenHeight = window.getHeight(); - // Positionate node ... - // header - footer - screenHeight = screenHeight; - // body margin ... editorProperties.width = screenWidth; editorProperties.height = screenHeight; diff --git a/trunk/wise-webapp/src/main/webapp/jsp/browserNotSupported.jsp b/trunk/wise-webapp/src/main/webapp/jsp/browserNotSupported.jsp index 7eebddeb..6746b5fd 100644 --- a/trunk/wise-webapp/src/main/webapp/jsp/browserNotSupported.jsp +++ b/trunk/wise-webapp/src/main/webapp/jsp/browserNotSupported.jsp @@ -9,8 +9,8 @@ <p>Although you can use our site with that browser, some features may not be functional.</p> WiseMapping is optimized for use with: <ul> - <li>Internet Explorer 6.0 or greater</li> - <li>Firefox 1.5 or greater</li> + <li>Internet Explorer 7.0 or greater</li> + <li>Firefox 3.0 or greater</li> <li>Opera 9.21 or greater</li> </ul> diff --git a/trunk/wise-webapp/src/main/webapp/jsp/embeddedView.jsp b/trunk/wise-webapp/src/main/webapp/jsp/embeddedView.jsp index e5cc0de6..751c0c37 100644 --- a/trunk/wise-webapp/src/main/webapp/jsp/embeddedView.jsp +++ b/trunk/wise-webapp/src/main/webapp/jsp/embeddedView.jsp @@ -23,10 +23,19 @@ </div> </div> <script type="text/javascript"> + //Dialog box display ... - var loadingDialog = new core.WaitDialog('waitDialog'); - addLightboxMarkup(); - loadingDialog.activate(true); + var waitDialog = new core.WaitDialog(); + waitDialog.activate(true, $("waitDialog")); + + $(window).addEvent("error", function(event) { + + // Show error dialog ... + waitDialog.changeContent($("errorDialog"), false); + return false; + }); + + var mapId = '${mindmap.id}'; var mapXml = '${mapXml}'; var editorProperties = {zoom:${zoom}}; diff --git a/trunk/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp b/trunk/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp index 36c47664..b331fed7 100644 --- a/trunk/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp +++ b/trunk/wise-webapp/src/main/webapp/jsp/mindmapEditor.jsp @@ -20,6 +20,9 @@ <link rel="stylesheet" type="text/css" href="../css/bubble.css"> <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/thirdparty.css"> + <script type="text/javascript" src="../dwr/engine.js"></script> + <script type="text/javascript" src="../dwr/interface/LoggerService.js"></script> + <script type='text/javascript' src='../js/wiseLibrary.js'></script> <script type='text/javascript' src='../js/core.js'></script> @@ -38,18 +41,35 @@ </form> <div id="waitDialog" style="display:none"> - <div id="loadingContainer"> + <div id="waitingContainer"> <div class="loadingIcon"></div> <div class="loadingText"> <spring:message code="EDITOR.LOADING"/> </div> </div> </div> + +<div id="errorDialog" style="display:none"> + <div id="errorContainer"> + <div class="loadingIcon"></div> + <div class="loadingText"> + <spring:message code="EDITOR.ERROR_LOADING"/> + </div> + </div> +</div> + <script type="text/javascript"> - //Dialog box display ... - var loadingDialog = new core.WaitDialog('waitDialog'); - addLightboxMarkup(); - loadingDialog.activate(true); + + var waitDialog = new core.WaitDialog(); + waitDialog.activate(true, $("waitDialog")); + $(window).addEvent("error", function(event) { + + // Show error dialog ... + waitDialog.changeContent($("errorDialog"), false); + return false; + }); + + var mapId = '${mindmap.id}'; var mapXml = '${mapXml}'; var editorProperties = ${mindmap.properties}; @@ -100,162 +120,163 @@ </div> <div id="toolbar"> -<div id="editTab" class="tabContent"> -<div id="file" class="buttonContainer" title="<spring:message code="FILE"/>"> - <fieldset> - <legend> - <spring:message code="FILE"/> - </legend> - <div id="saveButton" class="button" title="<spring:message code="SAVE"/>"> - <div class="toolbarLabel"><p><spring:message code="SAVE"/></p></div> - </div> - <div id="discardButton" class="button" title="<spring:message code="CLOSE"/>"> - <div class="toolbarLabel"><p><spring:message code="CLOSE"/></p></div> - </div> - <div id="undoEdition" class="button" title="<spring:message code="UNDO_EDITION"/>"> - <div class="toolbarLabel"><p><spring:message code="UNDO"/></p></div> - </div> - <div id="redoEdition" class="button" title="<spring:message code="REDO_EDITION"/>"> - <div class="toolbarLabel"><p><spring:message code="REDO"/></p></div> - </div> - <a id="printAnchor" href="javascript:printMap();" title="<spring:message code="PRINT"/>"> - <div id="print" class="button" title="<spring:message code="PRINT"/>"> - <div class="toolbarLabel"><p><spring:message code="PRINT"/></p></div> - </div> - </a> - <a id="exportAnchor" href="export.htm?mapId=${mindmap.id}" rel="moodalbox 600px 400px" - title="<spring:message code="EXPORT_DETAILS"/>"> - <div id="export" class="button" title="<spring:message code="EXPORT"/>"> - <div class="toolbarLabel"><p><spring:message code="EXPORT"/></p></div> - </div> - </a> - </fieldset> -</div> -<div id="zoom" class="buttonContainer" title="Zoom In"> - <fieldset> - <legend> - <spring:message code="ZOOM"/> - </legend> - <div id="zoomIn" class="button" title="<spring:message code="ZOOM_IN"/>"> - <div class="toolbarLabel"><p><spring:message code="IN"/></p></div> - </div> - <div id="zoomOut" class="button" title="<spring:message code="ZOOM_OUT"/>"> - <div class="toolbarLabel"><p><spring:message code="OUT"/></p></div> - </div> - </fieldset> -</div> -<div id="node" class="buttonContainer" title="Node Properties"> - <fieldset> - <legend> - <spring:message code="TOPIC"/> - </legend> - <div id="topicShape" class="button comboButton" title="<spring:message code="TOPIC_SHAPE"/>"> - <div class="toolbarLabel"><p><spring:message code="SHAPE"/></p></div> - </div> - <div id="addTopic" class="button" title="<spring:message code="TOPIC_ADD"/>"> - <div class="toolbarLabel"><p><spring:message code="ADD"/></p></div> - </div> - <div id="deleteTopic" class="button" title="<spring:message code="TOPIC_DELETE"/>"> - <div class="toolbarLabel"><p><spring:message code="DELETE"/></p></div> - </div> - <div id="topicBorder" class="button comboButton" title="<spring:message code="TOPIC_BORDER_COLOR"/>"> - <div class="toolbarLabel"><p><spring:message code="BORDER"/></p></div> - </div> - <div id="topicColor" class="button comboButton" title="<spring:message code="TOPIC_BACKGROUND_COLOR"/>"> - <div class="toolbarLabel"><p><spring:message code="COLOR"/></p></div> - </div> - <div id="topicIcon" class="button comboButton" title="<spring:message code="TOPIC_ICON"/>"> - <div class="toolbarLabel"><p><spring:message code="ICON"/></p></div> - </div> - <div id="topicNote" class="button comboButton" title="<spring:message code="TOPIC_NOTE"/>"> - <div class="toolbarLabel"><p><spring:message code="NOTE"/></p></div> - </div> - <div id="topicLink" class="button" title="<spring:message code="TOPIC_LINK"/>"> - <div class="toolbarLabel"><p><spring:message code="LINK"/></p></div> - </div> - </fieldset> -</div> -<div id="font" class="buttonContainer" title="Font Properties"> - <fieldset> - <legend> - <spring:message code="FONT"/> - </legend> - <div id="fontFamily" class="button comboButton" title="<spring:message code="FONT_TYPE"/>"> - <div class="toolbarLabel"><p><spring:message code="TYPE"/></p></div> - </div> - <div id="fontSize" class="button comboButton" title="<spring:message code="FONT_SIZE"/>"> - <div class="toolbarLabel"><p><spring:message code="SIZE"/></p></div> - </div> - <div id="fontBold" class="button" title="<spring:message code="FONT_BOLD"/>"> - <div class="toolbarLabel"><p><spring:message code="BOLD"/></p></div> - </div> - <div id="fontItalic" class="button" title="<spring:message code="FONT_ITALIC"/>"> - <div class="toolbarLabel"><p><spring:message code="ITALIC"/></p></div> - </div> - <div id="fontColor" class="button comboButton" title="<spring:message code="FONT_COLOR"/>"> - <div class="toolbarLabel"><p><spring:message code="COLOR"/></p></div> - </div> - </fieldset> -</div> -<div id="share" class="buttonContainer" title="Share Properties"> - <c:choose> - <c:when test="${editorTryMode==false}"> + <div id="editTab" class="tabContent"> + <div id="file" class="buttonContainer" title="<spring:message code="FILE"/>"> <fieldset> <legend> - <spring:message code="COLLABORATION"/> + <spring:message code="FILE"/> </legend> - <a id="tagAnchor" href="tags.htm?mapId=${mindmap.id}" rel="moodalbox 400px 200px wizard" - title="<spring:message code="TAGS_DETAILS"/>"> - <div id="tagIt" class="button" title="<spring:message code="TAG"/>"> - <div class="toolbarLabel"><p><spring:message code="TAG"/></p></div> + <div id="saveButton" class="button" title="<spring:message code="SAVE"/>"> + <div class="toolbarLabel"><p><spring:message code="SAVE"/></p></div> + </div> + <div id="discardButton" class="button" title="<spring:message code="CLOSE"/>"> + <div class="toolbarLabel"><p><spring:message code="CLOSE"/></p></div> + </div> + <div id="undoEdition" class="button" title="<spring:message code="UNDO_EDITION"/>"> + <div class="toolbarLabel"><p><spring:message code="UNDO"/></p></div> + </div> + <div id="redoEdition" class="button" title="<spring:message code="REDO_EDITION"/>"> + <div class="toolbarLabel"><p><spring:message code="REDO"/></p></div> + </div> + <a id="printAnchor" href="javascript:printMap();" title="<spring:message code="PRINT"/>"> + <div id="print" class="button" title="<spring:message code="PRINT"/>"> + <div class="toolbarLabel"><p><spring:message code="PRINT"/></p></div> </div> </a> - <c:choose> - <c:when test="${mindmap.owner==user}"> - <a id="shareAnchor" href="<c:out value="${shareMap}"/>&mapId=${mindmap.id}" - rel="moodalbox 780px 530px wizard" title="<spring:message code="SHARE_DETAILS"/>"> - <div id="shareIt" class="button" title="<spring:message code="COLLABORATION"/>"> - <div class="toolbarLabel"><p><spring:message code="SHARE"/></p></div> - </div> - </a> - <a id="publishAnchor" href="publish.htm?mapId=${mindmap.id}" rel="moodalbox 600px 400px wizard" - title="<spring:message code="PUBLISH_MSG"/>"> - <div id="publishIt" class="button" title="<spring:message code="PUBLISH"/>"> - <div class="toolbarLabel"><p><spring:message code="PUBLISH"/></p></div> - </div> - </a> - </c:when> - </c:choose> - <a id="historyAnchor" href="history.htm?action=list&mapId=${mindmap.id}" - rel="moodalbox 600px 400px wizard" title="<spring:message code="HISTORY_MSG"/>"> - <div id="history" class="button" title="<spring:message code="HISTORY_MSG"/>"> - <div class="toolbarLabel"><p><spring:message code="HISTORY"/></p></div> + <a id="exportAnchor" href="export.htm?mapId=${mindmap.id}" rel="moodalbox 600px 400px" + title="<spring:message code="EXPORT_DETAILS"/>"> + <div id="export" class="button" title="<spring:message code="EXPORT"/>"> + <div class="toolbarLabel"><p><spring:message code="EXPORT"/></p></div> </div> </a> </fieldset> - </c:when> - <c:otherwise> + </div> + <div id="zoom" class="buttonContainer" title="Zoom In"> <fieldset> <legend> - <spring:message code="COLLABORATION"/> + <spring:message code="ZOOM"/> </legend> - <div id="tagIt" class="button" title="<spring:message code="TAG"/>"> - <div class="toolbarLabel"><p><spring:message code="TAG"/></p></div> + <div id="zoomIn" class="button" title="<spring:message code="ZOOM_IN"/>"> + <div class="toolbarLabel"><p><spring:message code="IN"/></p></div> </div> - <div id="shareIt" class="button" title="<spring:message code="COLLABORATE"/>"> - <div class="toolbarLabel"><p><spring:message code="SHARE"/></p></div> - </div> - <div id="publishIt" class="button" title="<spring:message code="PUBLISH"/>"> - <div class="toolbarLabel"><p><spring:message code="PUBLISH"/></p></div> - </div> - <div id="history" class="button" title="<spring:message code="HISTORY_MSG"/>"> - <div class="toolbarLabel"><p><spring:message code="HISTORY"/></p></div> + <div id="zoomOut" class="button" title="<spring:message code="ZOOM_OUT"/>"> + <div class="toolbarLabel"><p><spring:message code="OUT"/></p></div> </div> </fieldset> - </c:otherwise> - </c:choose> -</div> -</div> + </div> + <div id="node" class="buttonContainer" title="Node Properties"> + <fieldset> + <legend> + <spring:message code="TOPIC"/> + </legend> + <div id="topicShape" class="button comboButton" title="<spring:message code="TOPIC_SHAPE"/>"> + <div class="toolbarLabel"><p><spring:message code="SHAPE"/></p></div> + </div> + <div id="addTopic" class="button" title="<spring:message code="TOPIC_ADD"/>"> + <div class="toolbarLabel"><p><spring:message code="ADD"/></p></div> + </div> + <div id="deleteTopic" class="button" title="<spring:message code="TOPIC_DELETE"/>"> + <div class="toolbarLabel"><p><spring:message code="DELETE"/></p></div> + </div> + <div id="topicBorder" class="button comboButton" title="<spring:message code="TOPIC_BORDER_COLOR"/>"> + <div class="toolbarLabel"><p><spring:message code="BORDER"/></p></div> + </div> + <div id="topicColor" class="button comboButton" title="<spring:message code="TOPIC_BACKGROUND_COLOR"/>"> + <div class="toolbarLabel"><p><spring:message code="COLOR"/></p></div> + </div> + <div id="topicIcon" class="button comboButton" title="<spring:message code="TOPIC_ICON"/>"> + <div class="toolbarLabel"><p><spring:message code="ICON"/></p></div> + </div> + <div id="topicNote" class="button comboButton" title="<spring:message code="TOPIC_NOTE"/>"> + <div class="toolbarLabel"><p><spring:message code="NOTE"/></p></div> + </div> + <div id="topicLink" class="button" title="<spring:message code="TOPIC_LINK"/>"> + <div class="toolbarLabel"><p><spring:message code="LINK"/></p></div> + </div> + </fieldset> + </div> + <div id="font" class="buttonContainer" title="Font Properties"> + <fieldset> + <legend> + <spring:message code="FONT"/> + </legend> + <div id="fontFamily" class="button comboButton" title="<spring:message code="FONT_TYPE"/>"> + <div class="toolbarLabel"><p><spring:message code="TYPE"/></p></div> + </div> + <div id="fontSize" class="button comboButton" title="<spring:message code="FONT_SIZE"/>"> + <div class="toolbarLabel"><p><spring:message code="SIZE"/></p></div> + </div> + <div id="fontBold" class="button" title="<spring:message code="FONT_BOLD"/>"> + <div class="toolbarLabel"><p><spring:message code="BOLD"/></p></div> + </div> + <div id="fontItalic" class="button" title="<spring:message code="FONT_ITALIC"/>"> + <div class="toolbarLabel"><p><spring:message code="ITALIC"/></p></div> + </div> + <div id="fontColor" class="button comboButton" title="<spring:message code="FONT_COLOR"/>"> + <div class="toolbarLabel"><p><spring:message code="COLOR"/></p></div> + </div> + </fieldset> + </div> + <div id="share" class="buttonContainer" title="Share Properties"> + <c:choose> + <c:when test="${editorTryMode==false}"> + <fieldset> + <legend> + <spring:message code="COLLABORATION"/> + </legend> + <a id="tagAnchor" href="tags.htm?mapId=${mindmap.id}" rel="moodalbox 400px 200px wizard" + title="<spring:message code="TAGS_DETAILS"/>"> + <div id="tagIt" class="button" title="<spring:message code="TAG"/>"> + <div class="toolbarLabel"><p><spring:message code="TAG"/></p></div> + </div> + </a> + <c:choose> + <c:when test="${mindmap.owner==user}"> + <a id="shareAnchor" href="<c:out value="${shareMap}"/>&mapId=${mindmap.id}" + rel="moodalbox 780px 530px wizard" title="<spring:message code="SHARE_DETAILS"/>"> + <div id="shareIt" class="button" title="<spring:message code="COLLABORATION"/>"> + <div class="toolbarLabel"><p><spring:message code="SHARE"/></p></div> + </div> + </a> + <a id="publishAnchor" href="publish.htm?mapId=${mindmap.id}" + rel="moodalbox 600px 400px wizard" + title="<spring:message code="PUBLISH_MSG"/>"> + <div id="publishIt" class="button" title="<spring:message code="PUBLISH"/>"> + <div class="toolbarLabel"><p><spring:message code="PUBLISH"/></p></div> + </div> + </a> + </c:when> + </c:choose> + <a id="historyAnchor" href="history.htm?action=list&mapId=${mindmap.id}" + rel="moodalbox 600px 400px wizard" title="<spring:message code="HISTORY_MSG"/>"> + <div id="history" class="button" title="<spring:message code="HISTORY_MSG"/>"> + <div class="toolbarLabel"><p><spring:message code="HISTORY"/></p></div> + </div> + </a> + </fieldset> + </c:when> + <c:otherwise> + <fieldset> + <legend> + <spring:message code="COLLABORATION"/> + </legend> + <div id="tagIt" class="button" title="<spring:message code="TAG"/>"> + <div class="toolbarLabel"><p><spring:message code="TAG"/></p></div> + </div> + <div id="shareIt" class="button" title="<spring:message code="COLLABORATE"/>"> + <div class="toolbarLabel"><p><spring:message code="SHARE"/></p></div> + </div> + <div id="publishIt" class="button" title="<spring:message code="PUBLISH"/>"> + <div class="toolbarLabel"><p><spring:message code="PUBLISH"/></p></div> + </div> + <div id="history" class="button" title="<spring:message code="HISTORY_MSG"/>"> + <div class="toolbarLabel"><p><spring:message code="HISTORY"/></p></div> + </div> + </fieldset> + </c:otherwise> + </c:choose> + </div> + </div> </div> <div id="mindplot"></div> @@ -272,14 +293,6 @@ <div id="msgEnd"></div> </div> </div> - <%if (userAgent != null && !(userAgent.getOs() == UserAgent.OS.MAC && userAgent.getProduct() == UserAgent.Product.FIREFOX && userAgent.getVersionMajor() < 3)) { %> - <div id="helpButton" - style="text-align:center; width:90px; height:20px; background-color:#f5f5f5; border: 1px solid #BBB6D6; cursor:pointer; padding-left:5px; margin-left:3px;"> - <div style="float:left; position:relative; top:50%; margin-top:-8px; margin-left:15px;"><img - src="../images/help.png"/></div> - <div style="float:left; position:relative; top:50%; margin-top:-8px; margin-left:4px;">Help</div> - </div> - <% } else {%> <div id="helpButtonFirstSteps" style="text-align:center; width:90px; height:20px; background-color:#f5f5f5; border: 1px solid #BBB6D6; cursor:pointer; padding-left:5px; margin-left:3px;float:left;"> <div style="float:left; position:relative; top:50%; margin-top:-8px; margin-left:5px;"><img @@ -292,7 +305,6 @@ src="../images/help.png"/></div> <div style="float:left; position:relative; top:50%; margin-top:-8px; margin-left:4px;">Shortcuts</div> </div> - <% } %> </div> <c:if test="${editorTryMode==true}"> <div id="tryEditorWarning" class="sb"> @@ -308,8 +320,6 @@ </div> <script type="text/javascript"> // Register close event ... - //$('tryEditorWarning').makeRounded({radius: 8,borderColor: '#69686F',backgroundColor: '#69686F'}); - var tryElem = $('tryEditorWarning'); tryElem.addClass('drag').makeDraggable(); $('tryClose').addEvent('click', function(event) { @@ -319,11 +329,9 @@ </script> </c:if> <div id="ffoxworkarround" style="display:none;"><input id="ffoxWorkarroundInput" type="text"></div> -<script type="text/javascript" src="../dwr/engine.js"></script> <c:if test="${editorTryMode==false}"> <script type="text/javascript" src="../dwr/interface/MapEditorService.js"></script> </c:if> -<script type="text/javascript" src="../dwr/interface/LoggerService.js"></script> <script type="text/javascript" src="../js/editor.js"></script> <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"> </script>