From 8a083cf89492c0bb23b3321040b8d27d502f9bb1 Mon Sep 17 00:00:00 2001 From: "vincent@cubedesigners.com" Date: Mon, 12 Jan 2015 12:51:55 +0000 Subject: [PATCH] --- fluidbook/compile/_js/log4js.js | 4987 ++++++++--------- fluidbook/compile/index.html | 2 +- inc/ws/Controlleur/class.ws.flash.php | 1484 ++--- inc/ws/Controlleur/class.ws.maintenance.php | 25 +- inc/ws/DAO/class.ws.dao.book.php | 50 +- inc/ws/DAO/class.ws.dao.document.php | 911 ++- inc/ws/Metier/class.ws.document.php | 16 +- inc/ws/Util/class.ws.pdf.fontextractor.php | 6 +- .../Util/class.ws.pdf.fontextractor.php.php | 2 +- .../class.ws.pdf.fontextractor.php | 6 +- .../Util/packager/class.ws.packager.html.php | 6 +- inc/ws/Util/packager/class.ws.packager.v1.php | 6 +- 12 files changed, 3753 insertions(+), 3748 deletions(-) diff --git a/fluidbook/compile/_js/log4js.js b/fluidbook/compile/_js/log4js.js index d2c9dd6fe..a1154f1d8 100644 --- a/fluidbook/compile/_js/log4js.js +++ b/fluidbook/compile/_js/log4js.js @@ -1,2501 +1,2486 @@ -/* - * 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.getFlag(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 - */ - getFlag: 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.MozJSConsoleAppender(); - } - 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 +/* + * 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. + * + * <h3>Example:</h3> + * <pre> + * 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" ); + * </pre> + * + * @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.</p> + * 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: + * <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 {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("<!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN "); + doc.write(" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd>\n\n"); + doc.write("<html><head><title>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.getFlag(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 + */ + getFlag: 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.MozJSConsoleAppender(); + } + 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.setLevel(Log4js.Level.OFF); \ No newline at end of file diff --git a/fluidbook/compile/index.html b/fluidbook/compile/index.html index 63481e207..450d8a6fb 100644 --- a/fluidbook/compile/index.html +++ b/fluidbook/compile/index.html @@ -17,7 +17,6 @@ <title>$title - + $ga $redirectScript diff --git a/inc/ws/Controlleur/class.ws.flash.php b/inc/ws/Controlleur/class.ws.flash.php index d2313760f..afac29574 100644 --- a/inc/ws/Controlleur/class.ws.flash.php +++ b/inc/ws/Controlleur/class.ws.flash.php @@ -1,743 +1,743 @@ -con, $args); - - $droits = wsDroits::getDroits(); - $gateway->addAttribute('creation', $droits->creation ? '1' : '0'); - $gateway->addAttribute('revendeur', $droits->revendeur ? '1' : '0'); - $gateway->addAttribute('admin', $droits->admin ? '1' : '0'); - $gateway->addAttribute('grade', $core->user->ws_grade); - } - - public function saveConversionSettings() { - global $core; - $dao = new commonDAOUtilisateur($core->con); - $datas = array('resolution' => $this->args['resolution'], - 'objects' => $this->args['objects'], - 'method' => $this->args['method'], - 'quality' => $this->args['quality'], - 'version' => $this->args['version']); - $dao->sauveWSSettings($core->user->utilisateur_id, $datas); - } - - public function getConversionSettings() { - global $core; - $this->xml->addChild('resolution', $core->user->ws_settings['resolution']); - $this->xml->addChild('quality', $core->user->ws_settings['quality']); - $this->xml->addChild('method', $core->user->ws_settings['method']); - $this->xml->addChild('objects', $core->user->ws_settings['objects']); - $this->xml->addChild('version', $core->user->ws_settings['version']); - } - - public function uploadDocument() { - cubePHP::neverStop(); - global $core; - if (!isset($_SESSION['conversionSession'])) { - $_SESSION['conversionSession'] = array(); - } - $dao = new wsDAODocument($core->con); - foreach ($_FILES as $varname => $infos) { - if ($infos['error']) { - continue; - } - // Initialisation du document - $data = array(); - $data['proprietaire'] = $core->user->utilisateur_id; - $data['pages'] = 0; - $data['version'] = 2; - $data['file'] = cubeFiles::tidyName($infos['name']); - $li = new wsDocumentLocalInfos($this); - $li->fileName = $this->args['fileName']; - $li->fileSize = $this->args['fileSize']; - $li->creationDate = $this->args['creationDate']; - $li->modificationDate = $this->args['modificationDate']; - $data['localInfos'] = $li; - $data['conversionInfos'] = new wsDocumentConversionInfos($this->args['resolution'], $this->args['method'], $this->args['quality'], $this->args['objects'], $this->args['version']); - $document = $dao->sauve($data); - $document->copyOriginalFromUpload($infos['tmp_name']); - $this->xml->addChild('document_id', $document->document_id); - $_SESSION['conversionSession'][$document->document_id] = 'all'; - $_SESSION['conversionSessionReload'] = false; - } - } - - public function addDocument() { - $_SESSION['conversionSession'] = array(); - $_SESSION['conversionSession'][$this->args['document_id']] = 'all'; - $_SESSION['conversionSessionReload'] = false; - } - - public function reload() { - global $core; - - if ($this->args['reloadDocs'] == '1') { - foreach ($this->args['documents'] as $document_id => $pages) { - $this->args['documents'][$document_id] = 'all'; - } - } - - $dao = new wsDAODocument($core->con); - $_SESSION['conversionSession'] = $this->args['documents']; - $_SESSION['conversionSessionReload'] = true; - foreach ($this->args['documents'] as $id => $pages) { - $doc = $dao->selectById($id); - $doc->conversionInfos->updatePages($pages, $this->args['resolution'], $this->args['quality'], $this->args['method'], $this->args['objects'], $this->args['version']); - $dao->updateFromObject($doc); - } - } - - public function processConversionSession() { - $_SESSION['sessionConversionGUID'] = $sessionConversionGUID = uniqid('conversion_', true); - $session = new wsConversionSession($sessionConversionGUID); - $session->reload = $_SESSION['conversionSessionReload']; - $session->setDocuments($_SESSION['conversionSession']); - $session->setBook($this->args['book_id']); - unset($_SESSION['conversionSession']); - unset($_SESSION['conversionSessionReload']); - $session->serialize(); - - $php = new cubeCommandLine('php'); - $php->setPath(CONVERTER_PATH); - $php->setArg('f', ROOT . '/index.php'); - $php->setManualArg('--'); - $php->setArg('user_email', $_SESSION['user_email']); - $php->setArg('user_password', $_SESSION['user_password']); - $php->setArg('sessionConversionGUID', $sessionConversionGUID); - $php->setArg('PATH_INFO', '/flash/processConversionSessionAsync'); - $php->setArg('HTTP_HOST', $_SERVER['HTTP_HOST']); - $php->setNohup(true); - $php->execute('exec'); - - fb($php->commande); - fb($php->output); - - $this->xml->addChild('command', html::escapeHTML($php->command)); - exit; - } - - public function processConversionSessionAsync() { - cubePHP::neverStop(); - try { - $conversion = wsConversionSession::openFromGUID($_REQUEST['sessionConversionGUID']); - $conversion->process(); - } catch (Exception $e) { - file_put_contents(CACHE . '/conversionExceptions.txt', print_r($e, true), FILE_APPEND); - } - $conversion->destroy(); - } - - public function getConversionSessionProgress() { - set_time_limit(1); - $session = wsConversionSession::openFromGUID($_SESSION['sessionConversionGUID']); - $p = $session->getProgress(); - $this->xml->addChild('progress', $p['progress']); - $this->xml->addChild('processedDoc', $p['processedDoc']); - $this->xml->addChild('totalDoc', $p['totalDoc']); - $this->xml->addChild('currentDoc', $p['currentDoc']); - $this->xml->addChild('currentDocPage', $p['currentDocPage']); - $this->xml->addChild('totalDocPage', $p['totalDocPage']); - } - - public function uploadThemeFile() { - foreach ($_FILES as $varname => $infos) { - if ($infos['error']) { - continue; - } - $fname = cubeFiles::tidyName($infos['name']); - $dir = WS_THEMES . '/' . $this->args['theme_id'] . '/'; - $dest = $dir . $fname; - - - if (!file_exists(WS_THEMES . '/' . $this->args['theme_id'])) { - mkdir(WS_THEMES . '/' . $this->args['theme_id'], 0755, true); - } - - move_uploaded_file($infos['tmp_name'], $dest); - - if (isset($this->args['type']) && $this->args['type'] == 'favicon') { - $icotool = new cubeCommandLine('icotool'); - $icotool->setArg('c'); - $icotool->setArg('o', $dir . '/fluidbook.ico'); - - $sizes = array(256, 128, 64, 32, 16); - - foreach ($sizes as $s) { - $r = $dir . '/ico-' . $s . '.png'; - $it = new cubeImageTools(); - $it->loadImage($dest); - $it->resize($s, $s, 'crop', true, 'C', 'M', 'transparent'); - $it->output('png', $r); - $icotool->setArg(null, $r); - } - - $icotool->execute(); - } - - $this->xml->addChild('file', $fname); - return; - } - } - - public function uploadLinkContent() { - foreach ($_FILES as $varname => $infos) { - if ($infos['error']) { - continue; - } - - if (isset($_POST['dir'])) { - $dir = trim($_POST['dir'], '/\\ '); - } else { - $dir = ''; - } - - if ($dir != '') { - $dir = $dir . '/'; - } - - $fname = cubeFiles::tidyName($infos['name']); - $dir = WS_BOOKS . '/working/' . $this->args['book_id'] . '/' . $dir; - if (!file_exists($dir)) { - mkdir($dir, 0777, true); - } - $dest = $dir . $fname; - move_uploaded_file($infos['tmp_name'], $dest); - if (in_array(strtolower(files::getExtension($dest)), array('flv', 'f4v', 'mp4'))) { - // convert uploaded file as webvideo (ogv and mp4) - wsTools::encodeWebVideos($dest, null, true, false); - } - $this->xml->addChild('file', $fname); - return; - } - } - - public function testDocuments() { - global $core; - - $toload = $this->xml->addChild('toLoad'); - $alreadyLoaded = $this->xml->addChild('alreadyLoaded'); - - $hash = array(); - - foreach ($this->args['fileName'] as $k => $name) { - $o = new wsDocumentLocalInfos(); - $o->fileName = $name; - $o->fileSize = intval($this->args['fileSize'][$k]); - $o->modificationDate = intval($this->args['modificationDate'][$k]); - $o->creationDate = intval($this->args['creationDate'][$k]); - - $hash[$k] = md5(serialize($o)); - } - - $in = array(); - foreach ($hash as $h) { - $in[] = "'" . $h . "'"; - } - - $sql = 'SELECT document_id,localHash FROM documents WHERE localHash'; - if (count($in) == 1) { - $sql .= ' = ' . implode(',', $in); - } else { - $sql .= ' IN (' . implode(',', $in) . ')'; - } - - $al = array(); - $r = $core->con->select($sql); - while ($r->fetch()) { - $k = array_search($r->localHash, $hash); - - if (!file_exists(WS_DOCS . '/' . $r->document_id . '/original.pdf')) { - continue; - } - - $al[$k] = true; - $f = $alreadyLoaded->addChild('file', $this->args['fileName'][$k]); - $f->addAttribute('document_id', $r->document_id); - } - - foreach ($this->args['fileName'] as $k => $name) { - if (!isset($al[$k])) { - $toload->addChild('file', $name); - } - } - } - - public function getPagesOfBook() { - global $core; - - $this->json = true; - - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - $pages = $dao->getPagesOfBook($this->args['book_id'], false); - $this->jsonDatas['pages'] = array(); - $docs = array(); - $defaultNum = array(); - foreach ($pages as $page => $info) { - $file = WS_DOCS . '/' . $info['document_id'] . '/p' . $info['document_page'] . '.jpg'; - if (!file_exists($file)) { - $info['resolution'] = 150; - $info['method'] = 1; - $info['objects'] = 1800; - $info['quality'] = 85; - $info['version'] = 'stable'; - } elseif (!isset($this->jsonDatas['thumbWidth'])) { - $dim = getimagesize($file); - $this->jsonDatas['thumbWidth'] = $dim[0]; - $this->jsonDatas['thumbHeight'] = $dim[1]; - } - - $docs[] = $info['document_id']; - $defaultNum[] = $info['defaultNum']; - - $this->jsonDatas['pages'][] = array($info['document_id'], $info['document_page']); - } - $docs = array_unique($docs); - $this->jsonDatas['documents'] = array_unique($docs); - - if (is_null($book->numerotation) || !$book->numerotation || $book->numerotation == 'null') { - $this->jsonDatas['numerotation'] = $defaultNum; - } else { - $this->jsonDatas['numerotation'] = explode(',', $book->numerotation); - } - } - - public function getTheme() { - global $core; - $dao = new wsDAOTheme($core->con); - if (isset($this->args['theme_id'])) { - $theme = $dao->selectById($this->args['theme_id']); - } else { - $theme = $dao->getThemeOfBook($this->args['book_id']); - } - $this->_themeToXML($theme); - } - - public function saveTheme() { - global $core; - $dao = new wsDAOTheme($core->con); - $dao->sauve($this->args); - } - - public function getAllThemes() { - global $core; - - if (isset($this->args['book_id'])) { - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - } else { - $this->args['book_id'] = 0; - } - - $demos = array(1161, 1160); - $readOnly = array(1); - - $dao = new wsDAOTheme($core->con); - $themes = $dao->getAllThemes($core->user, 'ORDER BY FIELD (theme_id,' . $this->args['book_id'] . ',' . implode(',', $demos) . ') DESC, theme_id DESC', $demos); - foreach ($themes as $theme) { - $t = $this->xml->addChild('theme'); - $t->addAttribute('id', $theme->theme_id); - $t->addAttribute('nom', $theme->nom); - if (isset($book) && $theme->theme_id == $book->theme) { - $t->addAttribute('selected', '1'); - $mine = true; - } else { - $mine = false; - } - if (in_array($theme->theme_id, $demos)) { - $right = 'r'; - } elseif (wsDroits::admin()) { - $right = 'w'; - } elseif (in_array($theme->theme_id, $readOnly)) { - $right = 'r'; - } elseif (wsDroits::revendeur() && wsDroits::creation()) { - $right = 'w'; - } else { - $right = 'r'; - } - - - - $t->addAttribute('right', $right); - $t->addAttribute('proprietaire', $theme->proprietaire_nom); - $t->addAttribute('books', max(($theme->nbBooks) - ($mine ? 1 : 0), 0)); - } - } - - public function deleteTheme() { - global $core; - - $dao = new wsDAOTheme($core->con); - $dao->delete($this->args['theme_id']); - } - - public function renameTheme() { - global $core; - - $dao = new wsDAOTheme($core->con); - $dao->rename($this->args['theme_id'], $this->args['text']); - } - - public function duplicateTheme() { - global $core; - $dao = new wsDAOTheme($core->con); - $theme = $dao->duplicate($this->args['theme_id'], $core->user->utilisateur_id); - $this->xml->addChild('theme_id', $theme->theme_id); - if (isset($this->args['book_id'])) { - $dao = new wsDAOBook($core->con); - $data = array('book_id' => $this->args['book_id'], 'theme' => $theme->theme_id); - $dao->sauve($core->user->utilisateur_id, $data); - } - } - - public function setTheme() { - global $core; - $dao = new wsDAOBook($core->con); - $dao->setTheme($this->args['book_id'], $this->args['theme']); - } - - public function postThemeShot() { - file_put_contents(WS_THEMES . '/' . $this->args['theme_id'] . '.jpg', base64_decode($this->args['data'])); - } - - public function getAllIcones() { - global $core; - $dao = new wsDAOIcone($core->con); - $icones = $dao->selectAll('ORDER BY icone_id DESC'); - foreach ($icones as $icone) { - $i = $this->xml->addChild('icone'); - $i->addAttribute('id', $icone->icone_id); - $i->addAttribute('nom', $icone->nom); - $i->addAttribute('path', ICONS . $icone->icone_id . '.png'); - } - } - - protected function _themeToXML($theme) { - $t = $this->xml->addChild('theme'); - $t->addAttribute('theme_id', $theme->theme_id); - $t->addAttribute('icones_id', $theme->icones); - foreach ($theme->parametres as $k => $v) { - $t->addChild($k, $v); - } - } - - public function getThemeForms() { - global $core; - $dao = new wsDAOTheme($core->con); - $theme = $dao->selectById($this->args['theme_id']); - - foreach ($theme->parametres->getForms() as $name) { - $f = $this->xml->addChild('form', json_encode($theme->parametres->getForm($name))); - $f->addAttribute('name', $name); - } - } - - public function getFluidbookForms() { - global $core; - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - foreach ($book->parametres->getForms() as $name) { - $f = $this->xml->addChild('form', html::escapeHTML(json_encode($book->parametres->getForm($name)))); - $f->addAttribute('name', $name); - } - } - - public function saveSettings() { - global $core; - $dao = new wsDAOBook($core->con); - - $pages = $dao->getPagesOfBook($this->args['book_id']); - $nb_pages = count($pages); - - $daoDoc = new wsDAODocument($core->con); - $firstDoc = $daoDoc->selectById($pages[1]['document_id']); - $size = $firstDoc->generalInfos['size']; - - $settings = json_decode($this->args['settings'], false); - $settings->width=$size[0]; - $settings->height=$size[1]; - - $dao->setSettings($this->args['book_id'], $settings); - } - - public function setChapters() { - global $core; - $dao = new wsDAOBook($core->con); - $dao->setChapters($this->args['book_id'], $this->args['chapters']); - } - - public function getChapters() { - global $core; - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - $this->xml->addChild('chapters', html::escapeHTML(json_encode($book->chapters))); - } - - public function getLinks() { - global $core; - - set_time_limit(0); - - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - - - $pages = $dao->getPagesOfBook($this->args['book_id']); - $nb_pages = count($pages); - - $daoDoc = new wsDAODocument($core->con); - $firstDoc = $daoDoc->selectById($pages[1]['document_id']); - $size = $firstDoc->generalInfos['size']; - $daoDoc->getLinksAndRulers($this->args['book_id'], $links, $rulers); - - $this->json = false; - $this->json = true; - - $types = array(1, 2, 3, 4, 5, 6, 7, 11, 13, 14, 15, 16, 17); - if (wsDroits::revendeur()) { - $types = array(1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); - } - if (wsDroits::admin()) { - $types = range(1, 30); - } - - if ($this->json) { - $this->jsonDatas['types'] = $types; - $this->jsonDatas['pages'] = $nb_pages; - $this->jsonDatas['numerotation'] = $book->numerotation; - $this->jsonDatas['width'] = $size[0]; - $this->jsonDatas['height'] = $size[1]; - $this->jsonDatas['links'] = $links; - $this->jsonDatas['rulers'] = $rulers; - } else { - $l = json_encode($links); - $l = html::escapeHTML($l); - $this->xml->addChild('width', $size[0]); - $this->xml->addChild('height', $size[1]); - $this->xml->addChild('pages', $nb_pages); - $this->xml->addChild('numerotation', $book->numerotation); - $this->xml->addChild('links', $l); - $this->xml->addChild('rulers', json_encode($rulers)); - } - - $daoTheme = new wsDAOTheme($this->con); - $theme = $daoTheme->getThemeOfBook($this->args['book_id'], true); - - $specials = array('backgroundImage' => 'background', 'topBar' => 'topbar', 'afterSearch' => 'aftersearch', 'externalArchives' => 'archives'); - - foreach ($specials as $tparam => $sname) { - $this->_addSpecialInfos($book, $theme, $tparam, $sname); - } - } - - protected function _addSpecialInfos($book, $theme, $param, $specialName) { - if ($specialName == 'archives') { - $p = $book->parametres; - } else { - $p = $theme->parametres; - } - - - if ($p->$param != '') { - if ($specialName != 'archives') { - $themeRoot = WS_THEMES . '/' . $theme->theme_id . '/'; - $dim = getimagesize($themeRoot . $p->$param); - $url = 'http://' . $_SERVER['HTTP_HOST'] . WEBROOT . '/fluidbook/themes/' . $theme->theme_id . '/' . $p->$param; - } else { - $bookRoot = WS_BOOKS . '/working/' . $book->book_id . '/'; - $dim = getimagesize($bookRoot . $p->$param); - $url = 'http://' . $_SERVER['HTTP_HOST'] . WEBROOT . '/fluidbook/books/working/' . $book->book_id . '/' . $p->$param; - } - - if ($this->json) { - $p = array('width' => $dim[0], 'height' => $dim[1], 'url' => $url); - $this->jsonDatas[$specialName] = $p; - } else { - $b = $this->xml->addChild($specialName); - $b->addChild('width', $dim[0]); - $b->addChild('height', $dim[1]); - $b->addChild('url', $url); - } - } - } - - public function saveLinks() { - global $core; - - $comments = isset($this->args['comments']) ? $this->args['comments'] : 'Saved from editor'; - - $dao = new wsDAODocument($core->con); - $dao->setLinksAndRulers($this->args['book_id'], $this->args['links'], $this->args['rulers'], $comments, $core->user->utilisateur_id); - - $daoBook = new wsDAOBook($core->con); - $daoBook->setSpecialLinksAndRulers($this->args['book_id'], $this->args['specialLinks'], $this->args['specialRulers']); - - if (isset($this->args['getLinks'])) { - $this->getLinks(); - } - } - - public function formatSize($val) { - $str = files::size($val); - $str = str_replace('.', __(','), $str); - $str = str_replace('B', __('o'), $str); - return $str; - } - - public function getExtras() { - global $core; - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - if ($book->extras != '') { - $tidy = cubeXML::tidy('' . $book->extras . ''); - $tidy = str_replace('', '', $tidy); - $tidy = str_replace('', '', $tidy); - $tidy = str_replace('', '', $tidy); - $tidy = trim($tidy); - $e = explode("\n", $tidy); - foreach ($e as $k => $v) { - if (substr($v, 0, 2) == ' ') { - $v = substr($v, 2); - } - $e[$k] = $v; - } - - $extras = implode("\n", $e); - } else { - $extras = ''; - } - - $this->xml->addChild('extras', $extras); - } - - public function saveExtras() { - global $core; - $dao = new wsDAOBook($core->con); - $res = $dao->setExtras($this->args['book_id'], $this->args['extras']); - $this->xml->addChild('ok', $res ? '1' : '0'); - } - - public function getBookInfos() { - global $core; - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - $pages = $dao->getPagesOfBook($this->args['book_id'], false); - $daoDoc = new wsDAODocument($core->con); - $nb_pages = count($pages); - $this->xml->addChild('pages', $nb_pages); - $total_size = 0; - foreach ($pages as $page => $info) { - $file = WS_DOCS . '/' . $info['document_id'] . '/p' . $info['document_page'] . '.swf'; - $total_size += filesize($file); - } - $average_size = $total_size / $nb_pages; - $total = self::formatSize($total_size); - $average = self::formatSize($average_size); - $firstDoc = $daoDoc->selectById($pages[1]['document_id']); - $size = $firstDoc->generalInfos['size']; - $this->xml->addChild('width', $size[0]); - $this->xml->addChild('height', $size[1]); - $res = '' . __('Nombre de pages') . ' : '; - $res .= $nb_pages . ' ' . __('pages') . "\n"; - $res .= "\n"; - $res .= '' . __('Dimensions') . ' : ' . "\n"; - $res .= round($size[0], 3) . ' x ' . round($size[1], 3) . ' pts' . "\n"; - $res .= "\n"; - $res .= '' . __('Taille totale des pages') . ' : ' . "\n"; - $res .= $total . "\n"; - $res .= "\n"; - $res .= '' . __('Taille moyenne des pages') . ' : ' . "\n"; - $res .= $average . "\n"; - $res .= "\n"; - $this->xml->addChild('infos', $res); - } - - public function getLangs() { - global $core; - if (isset($this->args['book_id'])) { - $dao = new wsDAOBook($core->con); - $book = $dao->selectById($this->args['book_id']); - $book->traductions = wsLang::checkTranslations($book->traductions); - if ($book->traductions != array()) { - //$bookLang = $this->xml->addChild('book_lang', json_encode($book->traductions)); - $bookLang = (array) $book->traductions; - } - } - - if (isset($bookLang)) { - if (wsLang::compare($bookLang, $book->lang)) { - unset($bookLang); - } - } - - $dao = new wsDAOLang($core->con); - $langs = $dao->selectAll(); - foreach ($langs as $lang) { - $nom = cubeLang::getNameByCode($lang->lang_id, $core->user->lang); - $l = $this->xml->addChild('lang', json_encode($lang->traductions)); - $l->addAttribute('id', $lang->lang_id); - $l->addAttribute('nom', $nom); - if (isset($book) && $book->lang == $lang->lang_id) { - if (!isset($bookLang)) { - $l->addAttribute('selected', '1'); - } else { - $trad = array_merge($lang->traductions, $bookLang); - $bl = $this->xml->addChild('book_lang', json_encode($trad)); - $bl->addAttribute('id', $lang->lang_id); - $bl->addAttribute('nom', $nom . ' (' . __('modifié') . ')'); - $bl->addAttribute('selected', '1'); - } - } - } - } - - public function saveLang() { - global $core; - $dao = new wsDAOBook($core->con); - $dao->setLang($this->args['book_id'], $this->args['lang_id'], $this->args['traductions']); - } - - public function saveComposition() { - global $core; - $dao = new wsDAOBook($core->con); - $dao->setComposition($this->args['book_id'], json_decode($this->args['pages'])); - } - - public function getTexts() { - $this->xml->addChild('texts', json_encode($GLOBALS['__l10n'])); - } - - public function copyLinks() { - global $core; - $daoDocument = new wsDAODocument($core->con); - $daoDocument->copyLinks($this->args['fromDoc'], $this->args['toDoc']); - } - - public function compile() { - global $core; - wsSecureSWF::checkProtectedSWF(); - $dao = new wsDAOBook($core->con); - - $log = $dao->compile($this->args['book_id'], '2'); - - - $book = $dao->selectById($this->args['book_id']); - $viewer = 'viewer'; - if (wsDroits::admin()) { - $viewer = 'vieweru'; - } - - $absoluteURL = 'http://' . $_SERVER['HTTP_HOST'] . '/' . $viewer . '/' . $book->book_id . '_' . $book->hash . '_' . TIME . '/'; - $this->xml->addChild('compiledBook', $absoluteURL . 'index.swf?base=' . $absoluteURL); - } - -} - +con, $args); + + $droits = wsDroits::getDroits(); + $gateway->addAttribute('creation', $droits->creation ? '1' : '0'); + $gateway->addAttribute('revendeur', $droits->revendeur ? '1' : '0'); + $gateway->addAttribute('admin', $droits->admin ? '1' : '0'); + $gateway->addAttribute('grade', $core->user->ws_grade); + } + + public function saveConversionSettings() { + global $core; + $dao = new commonDAOUtilisateur($core->con); + $datas = array('resolution' => $this->args['resolution'], + 'objects' => $this->args['objects'], + 'method' => $this->args['method'], + 'quality' => $this->args['quality'], + 'version' => $this->args['version']); + $dao->sauveWSSettings($core->user->utilisateur_id, $datas); + } + + public function getConversionSettings() { + global $core; + $this->xml->addChild('resolution', $core->user->ws_settings['resolution']); + $this->xml->addChild('quality', $core->user->ws_settings['quality']); + $this->xml->addChild('method', $core->user->ws_settings['method']); + $this->xml->addChild('objects', $core->user->ws_settings['objects']); + $this->xml->addChild('version', $core->user->ws_settings['version']); + } + + public function uploadDocument() { + cubePHP::neverStop(); + global $core; + if (!isset($_SESSION['conversionSession'])) { + $_SESSION['conversionSession'] = array(); + } + $dao = new wsDAODocument($core->con); + foreach ($_FILES as $varname => $infos) { + if ($infos['error']) { + continue; + } + // Initialisation du document + $data = array(); + $data['proprietaire'] = $core->user->utilisateur_id; + $data['pages'] = 0; + $data['version'] = 2; + $data['file'] = cubeFiles::tidyName($infos['name']); + $li = new wsDocumentLocalInfos($this); + $li->fileName = $this->args['fileName']; + $li->fileSize = $this->args['fileSize']; + $li->creationDate = $this->args['creationDate']; + $li->modificationDate = $this->args['modificationDate']; + $data['localInfos'] = $li; + $data['conversionInfos'] = new wsDocumentConversionInfos($this->args['resolution'], $this->args['method'], $this->args['quality'], $this->args['objects'], $this->args['version']); + $document = $dao->sauve($data); + $document->copyOriginalFromUpload($infos['tmp_name']); + $this->xml->addChild('document_id', $document->document_id); + $_SESSION['conversionSession'][$document->document_id] = 'all'; + $_SESSION['conversionSessionReload'] = false; + } + } + + public function addDocument() { + $_SESSION['conversionSession'] = array(); + $_SESSION['conversionSession'][$this->args['document_id']] = 'all'; + $_SESSION['conversionSessionReload'] = false; + } + + public function reload() { + global $core; + + if ($this->args['reloadDocs'] == '1') { + foreach ($this->args['documents'] as $document_id => $pages) { + $this->args['documents'][$document_id] = 'all'; + } + } + + $dao = new wsDAODocument($core->con); + $_SESSION['conversionSession'] = $this->args['documents']; + $_SESSION['conversionSessionReload'] = true; + foreach ($this->args['documents'] as $id => $pages) { + $doc = $dao->selectById($id); + $doc->conversionInfos->updatePages($pages, $this->args['resolution'], $this->args['quality'], $this->args['method'], $this->args['objects'], $this->args['version']); + $dao->updateFromObject($doc); + } + } + + public function processConversionSession() { + $_SESSION['sessionConversionGUID'] = $sessionConversionGUID = uniqid('conversion_', true); + $session = new wsConversionSession($sessionConversionGUID); + $session->reload = $_SESSION['conversionSessionReload']; + $session->setDocuments($_SESSION['conversionSession']); + $session->setBook($this->args['book_id']); + unset($_SESSION['conversionSession']); + unset($_SESSION['conversionSessionReload']); + $session->serialize(); + + $php = new cubeCommandLine('php'); + $php->setPath(CONVERTER_PATH); + $php->setArg('f', ROOT . '/index.php'); + $php->setManualArg('--'); + $php->setArg('user_email', $_SESSION['user_email']); + $php->setArg('user_password', $_SESSION['user_password']); + $php->setArg('sessionConversionGUID', $sessionConversionGUID); + $php->setArg('PATH_INFO', '/flash/processConversionSessionAsync'); + $php->setArg('HTTP_HOST', $_SERVER['HTTP_HOST']); + $php->setNohup(true); + $php->execute('exec'); + + fb($php->commande); + fb($php->output); + + $this->xml->addChild('command', html::escapeHTML($php->command)); + exit; + } + + public function processConversionSessionAsync() { + cubePHP::neverStop(); + try { + $conversion = wsConversionSession::openFromGUID($_REQUEST['sessionConversionGUID']); + $conversion->process(); + } catch (Exception $e) { + file_put_contents(CACHE . '/conversionExceptions.txt', print_r($e, true), FILE_APPEND); + } + $conversion->destroy(); + } + + public function getConversionSessionProgress() { + set_time_limit(1); + $session = wsConversionSession::openFromGUID($_SESSION['sessionConversionGUID']); + $p = $session->getProgress(); + $this->xml->addChild('progress', $p['progress']); + $this->xml->addChild('processedDoc', $p['processedDoc']); + $this->xml->addChild('totalDoc', $p['totalDoc']); + $this->xml->addChild('currentDoc', $p['currentDoc']); + $this->xml->addChild('currentDocPage', $p['currentDocPage']); + $this->xml->addChild('totalDocPage', $p['totalDocPage']); + } + + public function uploadThemeFile() { + foreach ($_FILES as $varname => $infos) { + if ($infos['error']) { + continue; + } + $fname = cubeFiles::tidyName($infos['name']); + $dir = WS_THEMES . '/' . $this->args['theme_id'] . '/'; + $dest = $dir . $fname; + + + if (!file_exists(WS_THEMES . '/' . $this->args['theme_id'])) { + mkdir(WS_THEMES . '/' . $this->args['theme_id'], 0755, true); + } + + move_uploaded_file($infos['tmp_name'], $dest); + + if (isset($this->args['type']) && $this->args['type'] == 'favicon') { + $icotool = new cubeCommandLine('icotool'); + $icotool->setArg('c'); + $icotool->setArg('o', $dir . '/fluidbook.ico'); + + $sizes = array(256, 128, 64, 32, 16); + + foreach ($sizes as $s) { + $r = $dir . '/ico-' . $s . '.png'; + $it = new cubeImageTools(); + $it->loadImage($dest); + $it->resize($s, $s, 'crop', true, 'C', 'M', 'transparent'); + $it->output('png', $r); + $icotool->setArg(null, $r); + } + + $icotool->execute(); + } + + $this->xml->addChild('file', $fname); + return; + } + } + + public function uploadLinkContent() { + foreach ($_FILES as $varname => $infos) { + if ($infos['error']) { + continue; + } + + if (isset($_POST['dir'])) { + $dir = trim($_POST['dir'], '/\\ '); + } else { + $dir = ''; + } + + if ($dir != '') { + $dir = $dir . '/'; + } + + $fname = cubeFiles::tidyName($infos['name']); + $dir = WS_BOOKS . '/working/' . $this->args['book_id'] . '/' . $dir; + if (!file_exists($dir)) { + mkdir($dir, 0777, true); + } + $dest = $dir . $fname; + move_uploaded_file($infos['tmp_name'], $dest); + if (in_array(strtolower(files::getExtension($dest)), array('flv', 'f4v', 'mp4'))) { + // convert uploaded file as webvideo (ogv and mp4) + wsTools::encodeWebVideos($dest, null, true, false); + } + $this->xml->addChild('file', $fname); + return; + } + } + + public function testDocuments() { + global $core; + + $toload = $this->xml->addChild('toLoad'); + $alreadyLoaded = $this->xml->addChild('alreadyLoaded'); + + $hash = array(); + + foreach ($this->args['fileName'] as $k => $name) { + $o = new wsDocumentLocalInfos(); + $o->fileName = $name; + $o->fileSize = intval($this->args['fileSize'][$k]); + $o->modificationDate = intval($this->args['modificationDate'][$k]); + $o->creationDate = intval($this->args['creationDate'][$k]); + + $hash[$k] = md5(serialize($o)); + } + + $in = array(); + foreach ($hash as $h) { + $in[] = "'" . $h . "'"; + } + + $sql = 'SELECT document_id,localHash FROM documents WHERE localHash'; + if (count($in) == 1) { + $sql .= ' = ' . implode(',', $in); + } else { + $sql .= ' IN (' . implode(',', $in) . ')'; + } + + $al = array(); + $r = $core->con->select($sql); + while ($r->fetch()) { + $k = array_search($r->localHash, $hash); + + if (!file_exists(WS_DOCS . '/' . $r->document_id . '/crop.pdf')) { + continue; + } + + $al[$k] = true; + $f = $alreadyLoaded->addChild('file', $this->args['fileName'][$k]); + $f->addAttribute('document_id', $r->document_id); + } + + foreach ($this->args['fileName'] as $k => $name) { + if (!isset($al[$k])) { + $toload->addChild('file', $name); + } + } + } + + public function getPagesOfBook() { + global $core; + + $this->json = true; + + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + $pages = $dao->getPagesOfBook($this->args['book_id'], false); + $this->jsonDatas['pages'] = array(); + $docs = array(); + $defaultNum = array(); + foreach ($pages as $page => $info) { + $file = WS_DOCS . '/' . $info['document_id'] . '/p' . $info['document_page'] . '.jpg'; + if (!file_exists($file)) { + $info['resolution'] = 150; + $info['method'] = 1; + $info['objects'] = 1800; + $info['quality'] = 85; + $info['version'] = 'stable'; + } elseif (!isset($this->jsonDatas['thumbWidth'])) { + $dim = getimagesize($file); + $this->jsonDatas['thumbWidth'] = $dim[0]; + $this->jsonDatas['thumbHeight'] = $dim[1]; + } + + $docs[] = $info['document_id']; + $defaultNum[] = $info['defaultNum']; + + $this->jsonDatas['pages'][] = array($info['document_id'], $info['document_page']); + } + $docs = array_unique($docs); + $this->jsonDatas['documents'] = array_unique($docs); + + if (is_null($book->numerotation) || !$book->numerotation || $book->numerotation == 'null') { + $this->jsonDatas['numerotation'] = $defaultNum; + } else { + $this->jsonDatas['numerotation'] = explode(',', $book->numerotation); + } + } + + public function getTheme() { + global $core; + $dao = new wsDAOTheme($core->con); + if (isset($this->args['theme_id'])) { + $theme = $dao->selectById($this->args['theme_id']); + } else { + $theme = $dao->getThemeOfBook($this->args['book_id']); + } + $this->_themeToXML($theme); + } + + public function saveTheme() { + global $core; + $dao = new wsDAOTheme($core->con); + $dao->sauve($this->args); + } + + public function getAllThemes() { + global $core; + + if (isset($this->args['book_id'])) { + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + } else { + $this->args['book_id'] = 0; + } + + $demos = array(1161, 1160); + $readOnly = array(1); + + $dao = new wsDAOTheme($core->con); + $themes = $dao->getAllThemes($core->user, 'ORDER BY FIELD (theme_id,' . $this->args['book_id'] . ',' . implode(',', $demos) . ') DESC, theme_id DESC', $demos); + foreach ($themes as $theme) { + $t = $this->xml->addChild('theme'); + $t->addAttribute('id', $theme->theme_id); + $t->addAttribute('nom', $theme->nom); + if (isset($book) && $theme->theme_id == $book->theme) { + $t->addAttribute('selected', '1'); + $mine = true; + } else { + $mine = false; + } + if (in_array($theme->theme_id, $demos)) { + $right = 'r'; + } elseif (wsDroits::admin()) { + $right = 'w'; + } elseif (in_array($theme->theme_id, $readOnly)) { + $right = 'r'; + } elseif (wsDroits::revendeur() && wsDroits::creation()) { + $right = 'w'; + } else { + $right = 'r'; + } + + + + $t->addAttribute('right', $right); + $t->addAttribute('proprietaire', $theme->proprietaire_nom); + $t->addAttribute('books', max(($theme->nbBooks) - ($mine ? 1 : 0), 0)); + } + } + + public function deleteTheme() { + global $core; + + $dao = new wsDAOTheme($core->con); + $dao->delete($this->args['theme_id']); + } + + public function renameTheme() { + global $core; + + $dao = new wsDAOTheme($core->con); + $dao->rename($this->args['theme_id'], $this->args['text']); + } + + public function duplicateTheme() { + global $core; + $dao = new wsDAOTheme($core->con); + $theme = $dao->duplicate($this->args['theme_id'], $core->user->utilisateur_id); + $this->xml->addChild('theme_id', $theme->theme_id); + if (isset($this->args['book_id'])) { + $dao = new wsDAOBook($core->con); + $data = array('book_id' => $this->args['book_id'], 'theme' => $theme->theme_id); + $dao->sauve($core->user->utilisateur_id, $data); + } + } + + public function setTheme() { + global $core; + $dao = new wsDAOBook($core->con); + $dao->setTheme($this->args['book_id'], $this->args['theme']); + } + + public function postThemeShot() { + file_put_contents(WS_THEMES . '/' . $this->args['theme_id'] . '.jpg', base64_decode($this->args['data'])); + } + + public function getAllIcones() { + global $core; + $dao = new wsDAOIcone($core->con); + $icones = $dao->selectAll('ORDER BY icone_id DESC'); + foreach ($icones as $icone) { + $i = $this->xml->addChild('icone'); + $i->addAttribute('id', $icone->icone_id); + $i->addAttribute('nom', $icone->nom); + $i->addAttribute('path', ICONS . $icone->icone_id . '.png'); + } + } + + protected function _themeToXML($theme) { + $t = $this->xml->addChild('theme'); + $t->addAttribute('theme_id', $theme->theme_id); + $t->addAttribute('icones_id', $theme->icones); + foreach ($theme->parametres as $k => $v) { + $t->addChild($k, $v); + } + } + + public function getThemeForms() { + global $core; + $dao = new wsDAOTheme($core->con); + $theme = $dao->selectById($this->args['theme_id']); + + foreach ($theme->parametres->getForms() as $name) { + $f = $this->xml->addChild('form', json_encode($theme->parametres->getForm($name))); + $f->addAttribute('name', $name); + } + } + + public function getFluidbookForms() { + global $core; + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + foreach ($book->parametres->getForms() as $name) { + $f = $this->xml->addChild('form', html::escapeHTML(json_encode($book->parametres->getForm($name)))); + $f->addAttribute('name', $name); + } + } + + public function saveSettings() { + global $core; + $dao = new wsDAOBook($core->con); + + $pages = $dao->getPagesOfBook($this->args['book_id']); + $nb_pages = count($pages); + + $daoDoc = new wsDAODocument($core->con); + $firstDoc = $daoDoc->selectById($pages[1]['document_id']); + $size = $firstDoc->generalInfos['size']; + + $settings = json_decode($this->args['settings'], false); + $settings->width = $size[0]; + $settings->height = $size[1]; + + $dao->setSettings($this->args['book_id'], $settings); + } + + public function setChapters() { + global $core; + $dao = new wsDAOBook($core->con); + $dao->setChapters($this->args['book_id'], $this->args['chapters']); + } + + public function getChapters() { + global $core; + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + $this->xml->addChild('chapters', html::escapeHTML(json_encode($book->chapters))); + } + + public function getLinks() { + global $core; + + set_time_limit(0); + + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + + + $pages = $dao->getPagesOfBook($this->args['book_id']); + $nb_pages = count($pages); + + $daoDoc = new wsDAODocument($core->con); + $firstDoc = $daoDoc->selectById($pages[1]['document_id']); + $size = $firstDoc->generalInfos['size']; + $daoDoc->getLinksAndRulers($this->args['book_id'], $links, $rulers); + + $this->json = false; + $this->json = true; + + $types = array(1, 2, 3, 4, 5, 6, 7, 11, 13, 14, 15, 16, 17); + if (wsDroits::revendeur()) { + $types = array(1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); + } + if (wsDroits::admin()) { + $types = range(1, 30); + } + + if ($this->json) { + $this->jsonDatas['types'] = $types; + $this->jsonDatas['pages'] = $nb_pages; + $this->jsonDatas['numerotation'] = $book->numerotation; + $this->jsonDatas['width'] = $size[0]; + $this->jsonDatas['height'] = $size[1]; + $this->jsonDatas['links'] = $links; + $this->jsonDatas['rulers'] = $rulers; + } else { + $l = json_encode($links); + $l = html::escapeHTML($l); + $this->xml->addChild('width', $size[0]); + $this->xml->addChild('height', $size[1]); + $this->xml->addChild('pages', $nb_pages); + $this->xml->addChild('numerotation', $book->numerotation); + $this->xml->addChild('links', $l); + $this->xml->addChild('rulers', json_encode($rulers)); + } + + $daoTheme = new wsDAOTheme($this->con); + $theme = $daoTheme->getThemeOfBook($this->args['book_id'], true); + + $specials = array('backgroundImage' => 'background', 'topBar' => 'topbar', 'afterSearch' => 'aftersearch', 'externalArchives' => 'archives'); + + foreach ($specials as $tparam => $sname) { + $this->_addSpecialInfos($book, $theme, $tparam, $sname); + } + } + + protected function _addSpecialInfos($book, $theme, $param, $specialName) { + if ($specialName == 'archives') { + $p = $book->parametres; + } else { + $p = $theme->parametres; + } + + + if ($p->$param != '') { + if ($specialName != 'archives') { + $themeRoot = WS_THEMES . '/' . $theme->theme_id . '/'; + $dim = getimagesize($themeRoot . $p->$param); + $url = 'http://' . $_SERVER['HTTP_HOST'] . WEBROOT . '/fluidbook/themes/' . $theme->theme_id . '/' . $p->$param; + } else { + $bookRoot = WS_BOOKS . '/working/' . $book->book_id . '/'; + $dim = getimagesize($bookRoot . $p->$param); + $url = 'http://' . $_SERVER['HTTP_HOST'] . WEBROOT . '/fluidbook/books/working/' . $book->book_id . '/' . $p->$param; + } + + if ($this->json) { + $p = array('width' => $dim[0], 'height' => $dim[1], 'url' => $url); + $this->jsonDatas[$specialName] = $p; + } else { + $b = $this->xml->addChild($specialName); + $b->addChild('width', $dim[0]); + $b->addChild('height', $dim[1]); + $b->addChild('url', $url); + } + } + } + + public function saveLinks() { + global $core; + + $comments = isset($this->args['comments']) ? $this->args['comments'] : 'Saved from editor'; + + $dao = new wsDAODocument($core->con); + $dao->setLinksAndRulers($this->args['book_id'], $this->args['links'], $this->args['rulers'], $comments, $core->user->utilisateur_id); + + $daoBook = new wsDAOBook($core->con); + $daoBook->setSpecialLinksAndRulers($this->args['book_id'], $this->args['specialLinks'], $this->args['specialRulers']); + + if (isset($this->args['getLinks'])) { + $this->getLinks(); + } + } + + public function formatSize($val) { + $str = files::size($val); + $str = str_replace('.', __(','), $str); + $str = str_replace('B', __('o'), $str); + return $str; + } + + public function getExtras() { + global $core; + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + if ($book->extras != '') { + $tidy = cubeXML::tidy('' . $book->extras . ''); + $tidy = str_replace('', '', $tidy); + $tidy = str_replace('', '', $tidy); + $tidy = str_replace('', '', $tidy); + $tidy = trim($tidy); + $e = explode("\n", $tidy); + foreach ($e as $k => $v) { + if (substr($v, 0, 2) == ' ') { + $v = substr($v, 2); + } + $e[$k] = $v; + } + + $extras = implode("\n", $e); + } else { + $extras = ''; + } + + $this->xml->addChild('extras', $extras); + } + + public function saveExtras() { + global $core; + $dao = new wsDAOBook($core->con); + $res = $dao->setExtras($this->args['book_id'], $this->args['extras']); + $this->xml->addChild('ok', $res ? '1' : '0'); + } + + public function getBookInfos() { + global $core; + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + $pages = $dao->getPagesOfBook($this->args['book_id'], false); + $daoDoc = new wsDAODocument($core->con); + $nb_pages = count($pages); + $this->xml->addChild('pages', $nb_pages); + $total_size = 0; + foreach ($pages as $page => $info) { + $file = WS_DOCS . '/' . $info['document_id'] . '/p' . $info['document_page'] . '.swf'; + $total_size += filesize($file); + } + $average_size = $total_size / $nb_pages; + $total = self::formatSize($total_size); + $average = self::formatSize($average_size); + $firstDoc = $daoDoc->selectById($pages[1]['document_id']); + $size = $firstDoc->generalInfos['size']; + $this->xml->addChild('width', $size[0]); + $this->xml->addChild('height', $size[1]); + $res = '' . __('Nombre de pages') . ' : '; + $res .= $nb_pages . ' ' . __('pages') . "\n"; + $res .= "\n"; + $res .= '' . __('Dimensions') . ' : ' . "\n"; + $res .= round($size[0], 3) . ' x ' . round($size[1], 3) . ' pts' . "\n"; + $res .= "\n"; + $res .= '' . __('Taille totale des pages') . ' : ' . "\n"; + $res .= $total . "\n"; + $res .= "\n"; + $res .= '' . __('Taille moyenne des pages') . ' : ' . "\n"; + $res .= $average . "\n"; + $res .= "\n"; + $this->xml->addChild('infos', $res); + } + + public function getLangs() { + global $core; + if (isset($this->args['book_id'])) { + $dao = new wsDAOBook($core->con); + $book = $dao->selectById($this->args['book_id']); + $book->traductions = wsLang::checkTranslations($book->traductions); + if ($book->traductions != array()) { + //$bookLang = $this->xml->addChild('book_lang', json_encode($book->traductions)); + $bookLang = (array) $book->traductions; + } + } + + if (isset($bookLang)) { + if (wsLang::compare($bookLang, $book->lang)) { + unset($bookLang); + } + } + + $dao = new wsDAOLang($core->con); + $langs = $dao->selectAll(); + foreach ($langs as $lang) { + $nom = cubeLang::getNameByCode($lang->lang_id, $core->user->lang); + $l = $this->xml->addChild('lang', json_encode($lang->traductions)); + $l->addAttribute('id', $lang->lang_id); + $l->addAttribute('nom', $nom); + if (isset($book) && $book->lang == $lang->lang_id) { + if (!isset($bookLang)) { + $l->addAttribute('selected', '1'); + } else { + $trad = array_merge($lang->traductions, $bookLang); + $bl = $this->xml->addChild('book_lang', json_encode($trad)); + $bl->addAttribute('id', $lang->lang_id); + $bl->addAttribute('nom', $nom . ' (' . __('modifié') . ')'); + $bl->addAttribute('selected', '1'); + } + } + } + } + + public function saveLang() { + global $core; + $dao = new wsDAOBook($core->con); + $dao->setLang($this->args['book_id'], $this->args['lang_id'], $this->args['traductions']); + } + + public function saveComposition() { + global $core; + $dao = new wsDAOBook($core->con); + $dao->setComposition($this->args['book_id'], json_decode($this->args['pages'])); + } + + public function getTexts() { + $this->xml->addChild('texts', json_encode($GLOBALS['__l10n'])); + } + + public function copyLinks() { + global $core; + $daoDocument = new wsDAODocument($core->con); + $daoDocument->copyLinks($this->args['fromDoc'], $this->args['toDoc']); + } + + public function compile() { + global $core; + wsSecureSWF::checkProtectedSWF(); + $dao = new wsDAOBook($core->con); + + $log = $dao->compile($this->args['book_id'], '2'); + + + $book = $dao->selectById($this->args['book_id']); + $viewer = 'viewer'; + if (wsDroits::admin()) { + $viewer = 'vieweru'; + } + + $absoluteURL = 'http://' . $_SERVER['HTTP_HOST'] . '/' . $viewer . '/' . $book->book_id . '_' . $book->hash . '_' . TIME . '/'; + $this->xml->addChild('compiledBook', $absoluteURL . 'index.swf?base=' . $absoluteURL); + } + +} + ?> \ No newline at end of file diff --git a/inc/ws/Controlleur/class.ws.maintenance.php b/inc/ws/Controlleur/class.ws.maintenance.php index dd09eaf13..884fa78c2 100644 --- a/inc/ws/Controlleur/class.ws.maintenance.php +++ b/inc/ws/Controlleur/class.ws.maintenance.php @@ -11,6 +11,22 @@ class wsMaintenance { } } + public static function cleanOriginauxPDF() { + global $core; + cubePHP::neverStop(); + $r = $core->con->select('SELECT document_id FROM documents'); + while ($r->fetch()) { + $root = WS_DOCS . '/' . $r->document_id . '/'; + $original = $root . 'original.pdf'; + $crop = $root . 'crop.pdf'; + if (file_exists($original) && file_exists($crop) && filesize($original) == filesize($crop)) { + `rm $crop`; + `cd $root;ln -s original.pdf crop.pdf`; + echo $root . '
'; + } + } + } + public static function initCompositionVersions($args) { global $core; $dao = new wsDAOBook($core->con); @@ -882,6 +898,11 @@ class wsMaintenance { $dao->setLinksAndRulers($book_id, json_encode($newlinks), json_encode($rulers), 'Autobookmark links correction', $core->user->utilisateur_id); } + public static function compress() { + `gzip /home/extranet/www/fluidbook/docs/*/p*.csv`; + `gzip /home/extranet/www/fluidbook/docs/*/*.txt`; + } + public static function offsetLinksPos($args) { global $core; $book_id = $args[0]; @@ -951,9 +972,7 @@ class wsMaintenance { $files = array($ifilec, $tfilec); foreach ($files as $f) { - if (file_exists($f)) { - unlink($f); - } + CubeIT_Util_Gzip::unlink($f . '.gz'); } } diff --git a/inc/ws/DAO/class.ws.dao.book.php b/inc/ws/DAO/class.ws.dao.book.php index 5367d6927..e68f8ec5e 100644 --- a/inc/ws/DAO/class.ws.dao.book.php +++ b/inc/ws/DAO/class.ws.dao.book.php @@ -821,9 +821,9 @@ class wsDAOBook extends commonDAO { } $tfilec = $dir . '/' . $prefix . 'textes.json'; - if (file_exists($ifilec) && file_exists($tfilec) && (min(filemtime($ifilec), filemtime($tfilec)) >= $book->composition_update)) { - $index = file_get_contents($ifilec); - $textes = file_get_contents($tfilec); + if (CubeIT_Util_Gzip::file_exists($ifilec) && CubeIT_Util_Gzip::file_exists($tfilec) && (min(CubeIT_Util_Gzip::filemtime($ifilec), CubeIT_Util_Gzip::filemtime($tfilec)) >= $book->composition_update)) { + $index = CubeIT_Util_Gzip::file_get_contents($ifilec); + $textes = CubeIT_Util_Gzip::file_get_contents($tfilec); return; } @@ -852,8 +852,10 @@ class wsDAOBook extends commonDAO { foreach ($pages as $book_page => $infos) { $tfile = WS_DOCS . '/' . $infos['document_id'] . '/' . $prefix . 'p' . $infos['document_page'] . '.txt'; $ifile = WS_DOCS . '/' . $infos['document_id'] . '/' . $prefix . 'i' . $infos['document_page'] . '.txt'; - $text = file_get_contents($tfile); - $ipage = file_get_contents($ifile); + CubeIT_Util_Gzip::compressIfNotCompressed($tfile); + CubeIT_Util_Gzip::compressIfNotCompressed($ifile); + $text = CubeIT_Util_Gzip::file_get_contents($tfile); + $ipage = CubeIT_Util_Gzip::file_get_contents($ifile); if ($simple) { $this->fillIndexWithWordsSimple($index, $book_page, $ipage); @@ -867,8 +869,8 @@ class wsDAOBook extends commonDAO { $textes = json_encode($textes); $index = json_encode($index); - file_put_contents($tfilec, $textes); - file_put_contents($ifilec, $index); + CubeIT_Util_Gzip::file_put_contents($tfilec, $textes); + CubeIT_Util_Gzip::file_put_contents($ifilec, $index); } protected function _escapeIndex($str) { @@ -1490,27 +1492,27 @@ class wsDAOBook extends commonDAO { $htmlCompiler->compile(); } - public function indexPDF($book, $pages) { - $indexPath = WS_BOOKS . '/search/' . $book->book_id; + /* public function indexPDF($book, $pages) { + $indexPath = WS_BOOKS . '/search/' . $book->book_id; - Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()); + Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()); - if (file_exists($indexPath)) { - files::deltree($indexPath); - } - $index = Zend_Search_Lucene::create($indexPath); + if (file_exists($indexPath)) { + files::deltree($indexPath); + } + $index = Zend_Search_Lucene::create($indexPath); - foreach ($pages as $i => $infos) { - $doc = new Zend_Search_Lucene_Document(); - $doc->addField(Zend_Search_Lucene_Field::Text('url', '#' . $i)); - $doc->addField(Zend_Search_Lucene_Field::UnStored('contents', file_get_contents(WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'] . '.txt'))); - $index->addDocument($doc); - } + foreach ($pages as $i => $infos) { + $doc = new Zend_Search_Lucene_Document(); + $doc->addField(Zend_Search_Lucene_Field::Text('url', '#' . $i)); + $doc->addField(Zend_Search_Lucene_Field::UnStored('contents', file_get_contents(WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'] . '.txt'))); + $index->addDocument($doc); + } - $c = $this->con->openCursor('books'); - $c->lucene_time = TIME; - $c->update('WHERE book_id=' . $book->book_id); - } + $c = $this->con->openCursor('books'); + $c->lucene_time = TIME; + $c->update('WHERE book_id=' . $book->book_id); + } */ public function compilePDF($book, $pages) { if (substr($book->parametres->pdfName, 0, 4) == 'http') { diff --git a/inc/ws/DAO/class.ws.dao.document.php b/inc/ws/DAO/class.ws.dao.document.php index 9119db448..9120eaf90 100644 --- a/inc/ws/DAO/class.ws.dao.document.php +++ b/inc/ws/DAO/class.ws.dao.document.php @@ -1,456 +1,455 @@ -$k = $r->$k; - } - foreach (self::$complex as $k) { - if ($r->$k != '') { - $document->$k = unserialize($r->$k); - } - } - $document->init(); - return $document; - } - - public function setFluidbookLinksFromCSV($book_id) { - $daoBook = new wsDAOBook($this->con); - $pages = $daoBook->getPagesOfBook($book_id); - - foreach ($pages as $page => $infos) { - $docs[] = $infos['document_id']; - } - - $docs = array_unique($docs); - foreach ($docs as $document_id) { - $this->putLinksFromCSV($document_id); - } - } - - public function restoreLinksVersion($book_id, $update, $user = 0) { - - $daoBook = new wsDAOBook($this->con); - $pages = $daoBook->getPagesOfBookAt($book_id, $update); - - $docs = array(); - foreach ($pages as $infos) { - $docs[] = $infos['document_id']; - } - - $r = $this->con->select('SELECT document_id,links,rulers FROM document_links_versions WHERE `update`=' . $update . ' AND document_id IN (' . implode(',', $docs) . ')'); - - while ($r->fetch()) { - wsLinks::setDocumentLinks($r->document_id, $r->links, $r->rulers, $user, 'Links restored from ' . date('Y-m-d H:i:s', $update) . ' version', TIME); - } - - $r = $this->con->select('SELECT * FROM special_links_versions WHERE `update`=' . $update . ' AND book_id=\'' . $this->con->escape($book_id) . '\''); - if ($r->count()) { - $c = $this->con->openCursor('books'); - $c->specialLinks = $r->links; - $c->specialRulers = $r->rulers; - $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\''); - } - } - - public function putLinksFromCSV($document_id) { - $log = array('Copie des liens du PDF vers la base de données'); - $document = $this->selectById($document_id); - - $booleans = array('video_loop', 'video_auto_start', 'video_controls', 'video_sound_on'); - - $links = array(); - - for ($page = 1; $page <= $document->generalInfos['pages']; $page++) { - $links[$page] = array(); - - $csv = WS_DOCS . '/' . $document->document_id . '/p' . $page . '.csv'; - if (!file_exists($csv)) { - $log[] = 'Links file of page ' . $page . ' not found'; - continue; - } - - $newformat = (filemtime($csv) > 1363685416); - - $log[] = 'Links file of page ' . $page . ' found'; - - - $fp = fopen($csv, 'rb'); - - while (true) { - $line = fgetcsv($fp, 512, ';', '"'); - // End of file - if (!$line) { - break; - } - // Commentaire || ligne vide - if (substr($line[0], 0, 1) == '#' || is_null($line[0])) { - continue; - } - $link = array(); - if ($newformat) { - $cols = array('page' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'type' => '', 'to' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical'); - } else { - $cols = array('page' => '', 'type' => '', 'to' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical'); - } - $k = 0; - foreach ($cols as $col => $default) { - if (isset($line[$k])) { - if (in_array($k, $booleans)) { - $link[$col] = ($line[$k] == '1'); - } else { - $link[$col] = utf8_encode($line[$k]); - } - } else { - $link[$col] = $default; - } - $k++; - } - $link['page'] = $page; - $links[$page][] = $link; - } - - $log[] = 'Added ' . count($links) . ' links'; - } - - wsLinks::setDocumentLinks($document_id, json_encode($links), json_encode(array()), 0, 'Links imported from PDF', TIME); - - return implode("\n", $log); - } - - public function setLinksAndRulers($book_id, $links, $rulers, $comments = '', $user = 0) { - $daoBook = new wsDAOBook($this->con); - $pages = $daoBook->getPagesOfBook($book_id, false); - - if (is_array($links)) { - $links = json_encode($links); - } - if (is_array($rulers)) { - $rulers = json_encode($rulers); - } - $links = json_decode($links, false); - $rulers = json_decode($rulers, false); - - $t = array(); - - foreach ($links as $link) { - if (!isset($t[$link->page])) { - $t[$link->page] = array('links' => array(), 'rulers' => array()); - } - $t[$link->page]['links'][] = $link; - } - foreach ($rulers as $ruler) { - if (!isset($t[$ruler->page])) { - $t[$ruler->page] = array('links' => array(), 'rulers' => array()); - } - $t[$ruler->page]['rulers'][] = $ruler; - } - - $links = array(); - $rulers = array(); - - foreach ($pages as $p) { - if (!isset($links[$p['document_id']])) { - $links[$p['document_id']] = array(); - $rulers[$p['document_id']] = array(); - } - - if (!isset($links[$p['document_id']][$p['document_page']])) { - $links[$p['document_id']][$p['document_page']] = array(); - $rulers[$p['document_id']][$p['document_page']] = array(); - } - } - - $specialLinks = array(); - $specialRulers = array(); - - foreach ($t as $page => $tt) { - if (!is_int($page)) { - if (isset($tt['links'])) { - $specialLinks = array_merge($specialLinks, $tt['links']); - } - if (isset($tt['rulers'])) { - $specialRulers = array_merge($specialRulers, $tt['rulers']); - } - continue; - } - $infos = $pages[$page]; - $doc_id = $infos['document_id']; - $doc_page = $infos['document_page']; - - if (!isset($links[$doc_id])) { - $links[$doc_id] = array(); - $rulers[$doc_id] = array(); - } - if (!isset($links[$doc_id][$doc_page])) { - $links[$doc_id][$doc_page] = array(); - $rulers[$doc_id][$doc_page] = array(); - } - - foreach ($tt['links'] as $link) { - $links[$doc_id][$doc_page][] = $link; - } - - foreach ($tt['rulers'] as $ruler) { - $rulers[$doc_id][$doc_page][] = $ruler; - } - } - - foreach ($links as $document_id => $dummy) { - wsLinks::setDocumentLinks($document_id, json_encode($links[$document_id]), json_encode($rulers[$document_id]), $user, $comments, TIME); - } - - $daoBook->setSpecialLinksAndRulers($book_id, $specialLinks, $specialRulers); - - $c = $this->con->openCursor('books'); - $c->changedate = TIME; - $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\''); - } - - public function copyLinks($from, $to) { - $sql = 'REPLACE INTO document_links_versions (`document_id`,`links`,`rulers`,`update`) ' - . 'SELECT \'' . $to . '\',`links`,`rulers`,`update` FROM document_links_versions WHERE document_id=\'' . $from . '\''; - - $this->con->execute($sql); - } - - public function setLinksFromOldFluidbook($book_id) { - $daoBook = new wsDAOBook($this->con); - $pages = $daoBook->getPagesOfBook($book_id); - fb($pages); - $book = $daoBook->selectById($book_id); - $width = $book->parametres->width; - - $xml = simplexml_load_file('http://ws.fluidbook.com/books/' . $book_id . '/data/links.xml'); - echo $xml; - $links = $xml->xpath('//oneLink'); - - $res = array(); - $lpages = array(); - foreach ($links as $l) { - if ((string) $l->page == '') { - continue; - } - - $left = floatval((string) $l->startX); - $right = floatval((string) $l->endX); - $top = floatval((string) $l->startY); - $bottom = floatval((string) $l->endY); - - $lwidth = abs($right - $left); - $lheight = abs($bottom - $top); - - $left = min($left, $right); - $top = min($top, $bottom); - - $link = array(); - $link['page'] = (string) $l->page; - $link['numerotation'] = false; - $link['left'] = $left; - $link['width'] = $lwidth; - if ($link['left'] > $width) { - $link['page']++; - $link['left'] -= $width; - } - $page = $link['page']; - $link['top'] = $top; - $link['height'] = $lheight; - $link['infobulle'] = ''; - $link['target'] = '_blank'; - $link['to'] = (string) $l->linkTo; - $link['type'] = intval((string) $l->linkType); - $link['video_loop'] = ((string) $l->loopFlag == '1'); - $link['video_auto_start'] = true; - $link['video_controls'] = ((string) $l->playerActive == '1'); - $link['video_sound_on'] = ((string) $l->soundOn == '1'); - - $dir = WS_BOOKS . '/working/' . $book_id . '/'; - - if ($link['type'] == '4' || $link['type'] == '6') { - if (!stristr($link['to'], ':/')) { - if (!file_exists($dir)) { - mkdir($dir, 0755, true); - } - copy('http://ws.fluidbook.com/books/' . $book_id . '/data/' . $link['to'], $dir . '/' . $link['to']); - } - } - - if (!isset($lpages[$page])) { - $lpages[$page] = array(); - } - $lpages[$page][] = $link; - } - - - $links = array(); - foreach ($pages as $p => $infos) { - if (!isset($links[$infos['document_id']])) { - $links[$infos['document_id']] = array(); - } - if (isset($lpages[$p])) { - $links[$infos['document_id']][$infos['document_page']] = $lpages[$p]; - } - } - - krsort($links); - - foreach ($links as $document_id => $l) { - wsLinks::setDocumentLinks($document_id, json_encode($l), json_encode(array()), 0, 'Import from Fluidbook V1', TIME); - } - - $c = $this->con->openCursor('books'); - $c->changedate = TIME; - $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\''); - } - - public function getLinksAndRulers($book_id, &$links, &$rulers, $time = null) { - return wsLinks::getLinksAndRulers($book_id, $links, $rulers, $time); - } - - public function getLinksVersions($book_id) { - $r = $this->con->select('SELECT * FROM special_links_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\''); - $specials = array(); - while ($r->fetch()) { - $ll = json_decode($r->links); - $lr = json_decode($r->rulers); - $specials[$r->update] = array('links' => count($ll), 'rulers' => count($lr)); - } - - - // Get composition versions - $r = $this->con->select('SELECT * FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\''); - $docs = array(); - while ($r->fetch()) { - $c = unserialize($r->composition); - foreach ($c as $infos) { - $docs[] = $infos['document_id']; - } - } - - $res = array(); - $r = $this->con->select('SELECT l.*,u.prenom,u.nom FROM document_links_versions l LEFT JOIN utilisateurs u ON l.user=u.utilisateur_id WHERE document_id IN(' . implode(',', $docs) . ')'); - while ($r->fetch()) { - if (!isset($res[$r->update])) { - if (isset($specials[$r->update])) { - $res[$r->update] = $specials[$r->update]; - } else { - $res[$r->update] = array('links' => 0, 'rulers' => 0); - } - } - - - $ll = json_decode($r->links); - foreach ($ll as $lll) { - $res[$r->update]['links'] += count($lll); - } - $rr = json_decode($r->rulers); - foreach ($rr as $rrr) { - $res[$r->update]['rulers'] += count($rrr); - } - $res[$r->update]['comments'] = $r->comments; - if ($r->user > 0) { - $user = $r->prenom . ' ' . $r->nom; - } else { - $user = ''; - } - $res[$r->update]['user'] = $user; - } - return $res; - } - - public function getNextId() { - $r = $this->con->select('SELECT MAX(document_id) AS document_id FROM documents'); - if ($r->document_id < 100000) { - return 100000; - } - return $r->document_id + 1; - } - - public function selectById($document_id) { - $r = $this->con->select('SELECT * FROM documents WHERE document_id=\'' . $this->con->escape($document_id) . '\''); - return $this->singleton($r); - } - - public function selectByBookId($book_id) { - $r = $this->con->select('SELECT * FROM documents WHERE document_id IN(SELECT document_id FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\')'); - return $this->factory($r); - } - - public function selectInList($documents_id) { - $r = $this->con->select('SELECT * FROM documents WHERE document_id IN(' . implode(',', $documents_id) . ')'); - return $this->factory($r); - } - - public function cree() { - $document = new wsDocument(); - $document->document_id = 'new'; - $document->file = ''; - $document->proprietaire = 0; - $document->pages = 0; - $document->trim = array(); - $document->date = TIME; - $document->localInfos = new wsDocumentLocalInfos(); - return $document; - } - - public function sauve($data) { - if (!isset($data['document_id'])) { - $data['document_id'] = 'new'; - } - $c = $this->con->openCursor('documents'); - - foreach (self::$normal as $k) { - if (isset($data[$k])) { - $c->$k = $data[$k]; - } - } - foreach (self::$complex as $k) { - if (isset($data[$k])) { - $c->$k = serialize($data[$k]); - } - } - if (isset($data['localInfos'])) { - $c->localHash = md5($c->localInfos); - } - - if ($data['document_id'] == 'new') { - $document_id = $c->document_id = $this->getNextId(); - $c->date = TIME; - $c->insert(); - } else { - $document_id = $data['document_id']; - $c->update('WHERE document_id=\'' . $this->con->escape($data['document_id']) . '\''); - } - $doc = $this->selectById($document_id); - return $doc; - } - - public function updateField($document_id, $fieldName, $value) { - $c = $this->con->openCursor('documents'); - $c->$fieldName = $value; - $c->update('WHERE document_id=\'' . $this->con->escape($document_id) . '\''); - } - - public function updateFromObject($document) { - $data = array(); - foreach (self::$normal as $k) { - $data[$k] = $document->$k; - } - foreach (self::$complex as $k) { - $data[$k] = $document->$k; - } - return $this->sauve($data); - } - - public function getLinksAsExcel($links, $rulers) { - return wsLinks::linksToExcel($links, $rulers); - } - -} - -?> \ No newline at end of file +$k = $r->$k; + } + foreach (self::$complex as $k) { + if ($r->$k != '') { + $document->$k = unserialize($r->$k); + } + } + $document->init(); + return $document; + } + + public function setFluidbookLinksFromCSV($book_id) { + $daoBook = new wsDAOBook($this->con); + $pages = $daoBook->getPagesOfBook($book_id); + + foreach ($pages as $page => $infos) { + $docs[] = $infos['document_id']; + } + + $docs = array_unique($docs); + foreach ($docs as $document_id) { + $this->putLinksFromCSV($document_id); + } + } + + public function restoreLinksVersion($book_id, $update, $user = 0) { + + $daoBook = new wsDAOBook($this->con); + $pages = $daoBook->getPagesOfBookAt($book_id, $update); + + $docs = array(); + foreach ($pages as $infos) { + $docs[] = $infos['document_id']; + } + + $r = $this->con->select('SELECT document_id,links,rulers FROM document_links_versions WHERE `update`=' . $update . ' AND document_id IN (' . implode(',', $docs) . ')'); + + while ($r->fetch()) { + wsLinks::setDocumentLinks($r->document_id, $r->links, $r->rulers, $user, 'Links restored from ' . date('Y-m-d H:i:s', $update) . ' version', TIME); + } + + $r = $this->con->select('SELECT * FROM special_links_versions WHERE `update`=' . $update . ' AND book_id=\'' . $this->con->escape($book_id) . '\''); + if ($r->count()) { + $c = $this->con->openCursor('books'); + $c->specialLinks = $r->links; + $c->specialRulers = $r->rulers; + $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\''); + } + } + + public function putLinksFromCSV($document_id) { + $log = array('Copie des liens du PDF vers la base de données'); + $document = $this->selectById($document_id); + + $booleans = array('video_loop', 'video_auto_start', 'video_controls', 'video_sound_on'); + + $links = array(); + + for ($page = 1; $page <= $document->generalInfos['pages']; $page++) { + $links[$page] = array(); + + $csv = WS_DOCS . '/' . $document->document_id . '/p' . $page . '.csv'; + if (!file_exists($csv) && file_exists($csv . '.gz')) { + $csv = 'compress.zlib://' . $csv . '.gz'; + } elseif (!file_exists($csv)) { + $log[] = 'Links file of page ' . $page . ' not found'; + continue; + } + + $newformat = (filemtime($csv) > 1363685416); + + $log[] = 'Links file of page ' . $page . ' found'; + + $fp = fopen($csv, 'rb'); + + while (true) { + $line = fgetcsv($fp, 512, ';', '"'); + // End of file + if (!$line) { + break; + } + // Commentaire || ligne vide + if (substr($line[0], 0, 1) == '#' || is_null($line[0])) { + continue; + } + $link = array(); + if ($newformat) { + $cols = array('page' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'type' => '', 'to' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical'); + } else { + $cols = array('page' => '', 'type' => '', 'to' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical'); + } + $k = 0; + foreach ($cols as $col => $default) { + if (isset($line[$k])) { + if (in_array($k, $booleans)) { + $link[$col] = ($line[$k] == '1'); + } else { + $link[$col] = utf8_encode($line[$k]); + } + } else { + $link[$col] = $default; + } + $k++; + } + $link['page'] = $page; + $links[$page][] = $link; + } + + $log[] = 'Added ' . count($links) . ' links'; + } + + wsLinks::setDocumentLinks($document_id, json_encode($links), json_encode(array()), 0, 'Links imported from PDF', TIME); + + return implode("\n", $log); + } + + public function setLinksAndRulers($book_id, $links, $rulers, $comments = '', $user = 0) { + $daoBook = new wsDAOBook($this->con); + $pages = $daoBook->getPagesOfBook($book_id, false); + + if (is_array($links)) { + $links = json_encode($links); + } + if (is_array($rulers)) { + $rulers = json_encode($rulers); + } + $links = json_decode($links, false); + $rulers = json_decode($rulers, false); + + $t = array(); + + foreach ($links as $link) { + if (!isset($t[$link->page])) { + $t[$link->page] = array('links' => array(), 'rulers' => array()); + } + $t[$link->page]['links'][] = $link; + } + foreach ($rulers as $ruler) { + if (!isset($t[$ruler->page])) { + $t[$ruler->page] = array('links' => array(), 'rulers' => array()); + } + $t[$ruler->page]['rulers'][] = $ruler; + } + + $links = array(); + $rulers = array(); + + foreach ($pages as $p) { + if (!isset($links[$p['document_id']])) { + $links[$p['document_id']] = array(); + $rulers[$p['document_id']] = array(); + } + + if (!isset($links[$p['document_id']][$p['document_page']])) { + $links[$p['document_id']][$p['document_page']] = array(); + $rulers[$p['document_id']][$p['document_page']] = array(); + } + } + + $specialLinks = array(); + $specialRulers = array(); + + foreach ($t as $page => $tt) { + if (!is_int($page)) { + if (isset($tt['links'])) { + $specialLinks = array_merge($specialLinks, $tt['links']); + } + if (isset($tt['rulers'])) { + $specialRulers = array_merge($specialRulers, $tt['rulers']); + } + continue; + } + $infos = $pages[$page]; + $doc_id = $infos['document_id']; + $doc_page = $infos['document_page']; + + if (!isset($links[$doc_id])) { + $links[$doc_id] = array(); + $rulers[$doc_id] = array(); + } + if (!isset($links[$doc_id][$doc_page])) { + $links[$doc_id][$doc_page] = array(); + $rulers[$doc_id][$doc_page] = array(); + } + + foreach ($tt['links'] as $link) { + $links[$doc_id][$doc_page][] = $link; + } + + foreach ($tt['rulers'] as $ruler) { + $rulers[$doc_id][$doc_page][] = $ruler; + } + } + + foreach ($links as $document_id => $dummy) { + wsLinks::setDocumentLinks($document_id, json_encode($links[$document_id]), json_encode($rulers[$document_id]), $user, $comments, TIME); + } + + $daoBook->setSpecialLinksAndRulers($book_id, $specialLinks, $specialRulers); + + $c = $this->con->openCursor('books'); + $c->changedate = TIME; + $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\''); + } + + public function copyLinks($from, $to) { + $sql = 'REPLACE INTO document_links_versions (`document_id`,`links`,`rulers`,`update`) ' + . 'SELECT \'' . $to . '\',`links`,`rulers`,`update` FROM document_links_versions WHERE document_id=\'' . $from . '\''; + + $this->con->execute($sql); + } + + public function setLinksFromOldFluidbook($book_id) { + $daoBook = new wsDAOBook($this->con); + $pages = $daoBook->getPagesOfBook($book_id); + fb($pages); + $book = $daoBook->selectById($book_id); + $width = $book->parametres->width; + + $xml = simplexml_load_file('http://ws.fluidbook.com/books/' . $book_id . '/data/links.xml'); + echo $xml; + $links = $xml->xpath('//oneLink'); + + $res = array(); + $lpages = array(); + foreach ($links as $l) { + if ((string) $l->page == '') { + continue; + } + + $left = floatval((string) $l->startX); + $right = floatval((string) $l->endX); + $top = floatval((string) $l->startY); + $bottom = floatval((string) $l->endY); + + $lwidth = abs($right - $left); + $lheight = abs($bottom - $top); + + $left = min($left, $right); + $top = min($top, $bottom); + + $link = array(); + $link['page'] = (string) $l->page; + $link['numerotation'] = false; + $link['left'] = $left; + $link['width'] = $lwidth; + if ($link['left'] > $width) { + $link['page'] ++; + $link['left'] -= $width; + } + $page = $link['page']; + $link['top'] = $top; + $link['height'] = $lheight; + $link['infobulle'] = ''; + $link['target'] = '_blank'; + $link['to'] = (string) $l->linkTo; + $link['type'] = intval((string) $l->linkType); + $link['video_loop'] = ((string) $l->loopFlag == '1'); + $link['video_auto_start'] = true; + $link['video_controls'] = ((string) $l->playerActive == '1'); + $link['video_sound_on'] = ((string) $l->soundOn == '1'); + + $dir = WS_BOOKS . '/working/' . $book_id . '/'; + + if ($link['type'] == '4' || $link['type'] == '6') { + if (!stristr($link['to'], ':/')) { + if (!file_exists($dir)) { + mkdir($dir, 0755, true); + } + copy('http://ws.fluidbook.com/books/' . $book_id . '/data/' . $link['to'], $dir . '/' . $link['to']); + } + } + + if (!isset($lpages[$page])) { + $lpages[$page] = array(); + } + $lpages[$page][] = $link; + } + + + $links = array(); + foreach ($pages as $p => $infos) { + if (!isset($links[$infos['document_id']])) { + $links[$infos['document_id']] = array(); + } + if (isset($lpages[$p])) { + $links[$infos['document_id']][$infos['document_page']] = $lpages[$p]; + } + } + + krsort($links); + + foreach ($links as $document_id => $l) { + wsLinks::setDocumentLinks($document_id, json_encode($l), json_encode(array()), 0, 'Import from Fluidbook V1', TIME); + } + + $c = $this->con->openCursor('books'); + $c->changedate = TIME; + $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\''); + } + + public function getLinksAndRulers($book_id, &$links, &$rulers, $time = null) { + return wsLinks::getLinksAndRulers($book_id, $links, $rulers, $time); + } + + public function getLinksVersions($book_id) { + $r = $this->con->select('SELECT * FROM special_links_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\''); + $specials = array(); + while ($r->fetch()) { + $ll = json_decode($r->links); + $lr = json_decode($r->rulers); + $specials[$r->update] = array('links' => count($ll), 'rulers' => count($lr)); + } + + + // Get composition versions + $r = $this->con->select('SELECT * FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\''); + $docs = array(); + while ($r->fetch()) { + $c = unserialize($r->composition); + foreach ($c as $infos) { + $docs[] = $infos['document_id']; + } + } + + $res = array(); + $r = $this->con->select('SELECT l.*,u.prenom,u.nom FROM document_links_versions l LEFT JOIN utilisateurs u ON l.user=u.utilisateur_id WHERE document_id IN(' . implode(',', $docs) . ')'); + while ($r->fetch()) { + if (!isset($res[$r->update])) { + if (isset($specials[$r->update])) { + $res[$r->update] = $specials[$r->update]; + } else { + $res[$r->update] = array('links' => 0, 'rulers' => 0); + } + } + + + $ll = json_decode($r->links); + foreach ($ll as $lll) { + $res[$r->update]['links'] += count($lll); + } + $rr = json_decode($r->rulers); + foreach ($rr as $rrr) { + $res[$r->update]['rulers'] += count($rrr); + } + $res[$r->update]['comments'] = $r->comments; + if ($r->user > 0) { + $user = $r->prenom . ' ' . $r->nom; + } else { + $user = ''; + } + $res[$r->update]['user'] = $user; + } + return $res; + } + + public function getNextId() { + $r = $this->con->select('SELECT MAX(document_id) AS document_id FROM documents'); + if ($r->document_id < 100000) { + return 100000; + } + return $r->document_id + 1; + } + + public function selectById($document_id) { + $r = $this->con->select('SELECT * FROM documents WHERE document_id=\'' . $this->con->escape($document_id) . '\''); + return $this->singleton($r); + } + + public function selectByBookId($book_id) { + $r = $this->con->select('SELECT * FROM documents WHERE document_id IN(SELECT document_id FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\')'); + return $this->factory($r); + } + + public function selectInList($documents_id) { + $r = $this->con->select('SELECT * FROM documents WHERE document_id IN(' . implode(',', $documents_id) . ')'); + return $this->factory($r); + } + + public function cree() { + $document = new wsDocument(); + $document->document_id = 'new'; + $document->file = ''; + $document->proprietaire = 0; + $document->pages = 0; + $document->trim = array(); + $document->date = TIME; + $document->localInfos = new wsDocumentLocalInfos(); + return $document; + } + + public function sauve($data) { + if (!isset($data['document_id'])) { + $data['document_id'] = 'new'; + } + $c = $this->con->openCursor('documents'); + + foreach (self::$normal as $k) { + if (isset($data[$k])) { + $c->$k = $data[$k]; + } + } + foreach (self::$complex as $k) { + if (isset($data[$k])) { + $c->$k = serialize($data[$k]); + } + } + if (isset($data['localInfos'])) { + $c->localHash = md5($c->localInfos); + } + + if ($data['document_id'] == 'new') { + $document_id = $c->document_id = $this->getNextId(); + $c->date = TIME; + $c->insert(); + } else { + $document_id = $data['document_id']; + $c->update('WHERE document_id=\'' . $this->con->escape($data['document_id']) . '\''); + } + $doc = $this->selectById($document_id); + return $doc; + } + + public function updateField($document_id, $fieldName, $value) { + $c = $this->con->openCursor('documents'); + $c->$fieldName = $value; + $c->update('WHERE document_id=\'' . $this->con->escape($document_id) . '\''); + } + + public function updateFromObject($document) { + $data = array(); + foreach (self::$normal as $k) { + $data[$k] = $document->$k; + } + foreach (self::$complex as $k) { + $data[$k] = $document->$k; + } + return $this->sauve($data); + } + + public function getLinksAsExcel($links, $rulers) { + return wsLinks::linksToExcel($links, $rulers); + } + +} diff --git a/inc/ws/Metier/class.ws.document.php b/inc/ws/Metier/class.ws.document.php index a951cdc24..5db466c3b 100644 --- a/inc/ws/Metier/class.ws.document.php +++ b/inc/ws/Metier/class.ws.document.php @@ -213,6 +213,11 @@ class wsDocument extends cubeMetier { return cubeMath::compare($x[0], $y[0], $tolerance) && cubeMath::compare($x[1], $y[1], $tolerance); } + public function lnCrop() { + $root = dirname($this->cropped); + `cd $root;ln -s original.pdf crop.pdf`; + } + public function parseInfos($data) { // This function get general infos (pages sizes, boxes, number sections and // bookmarks @@ -277,13 +282,13 @@ class wsDocument extends cubeMetier { public function CropAndCut() { if (!$this->isCropped()) { - copy($this->in, $this->cropped); + $this->lnCrop(); return false; } if ($this->autocrop == 'trim') { $this->trimDocument(); } else { - copy($this->in, $this->cropped); + $this->lnCrop(); } if ($this->autocut) { @@ -330,9 +335,6 @@ class wsDocument extends cubeMetier { } public function optimizeSVG() { - - - $scour = new cubeCommandLine('scour.php'); $scour->setPath(CONVERTER_PATH); $scour->setNohup(true); @@ -344,7 +346,7 @@ class wsDocument extends cubeMetier { foreach ($pages as $i) { $this->processOnePage($i); } - $this->optimizeSVG(); + //$this->optimizeSVG(); } public function getLinksAndTexts() { @@ -572,7 +574,7 @@ class wsDocument extends cubeMetier { public function makeHTML5Files($page) { // Then make HD background shots - $resolutions = array(300 => 85, 150 => 85, 36 => 85); + $resolutions = array(300 => 85, 150 => 85); foreach ($resolutions as $r => $q) { $this->makeShotPNM($page, 'html/h' . $r . '-', $r, $q, 4, null, false); $this->makeShotPNM($page, 'html/t' . $r . '-', $r, $q, 4, null, true); diff --git a/inc/ws/Util/class.ws.pdf.fontextractor.php b/inc/ws/Util/class.ws.pdf.fontextractor.php index bc76aedd0..fcfcefaf6 100644 --- a/inc/ws/Util/class.ws.pdf.fontextractor.php +++ b/inc/ws/Util/class.ws.pdf.fontextractor.php @@ -11,9 +11,9 @@ class wsPDFFontExtractor { protected $descendantNames = array(); protected $doc; - public function __construct($in, $doc=null) { + public function __construct($in, $doc = null) { $this->doc = $doc; - $this->in = $in . '/original.pdf'; + $this->in = $in . '/crop.pdf'; $this->outpdf = $in . '/fonts/pdf'; $this->outweb = $in . '/fonts/web'; } @@ -162,7 +162,7 @@ class wsPDFFontExtractor { 0 740 0 0 0 0 0 0 0 0 536 ] >> endobj - * + * 10 0 obj << /BaseFont /FuturaLT-Bold--Identity-H diff --git a/inc/ws/Util/class.ws.pdf.fontextractor.php.php b/inc/ws/Util/class.ws.pdf.fontextractor.php.php index dcb4cfb4d..ef6837283 100644 --- a/inc/ws/Util/class.ws.pdf.fontextractor.php.php +++ b/inc/ws/Util/class.ws.pdf.fontextractor.php.php @@ -12,7 +12,7 @@ class wsPDFFontExtractor { public function __construct($in, $doc) { $this->doc = $doc; - $this->in = $in . '/original.pdf'; + $this->in = $in . '/crop.pdf'; $this->outpdf = $in . '/fonts/pdf'; $this->outweb = $in . '/fonts/web'; } diff --git a/inc/ws/Util/fontextractor/class.ws.pdf.fontextractor.php b/inc/ws/Util/fontextractor/class.ws.pdf.fontextractor.php index 3b53184b6..9c8cb86b9 100644 --- a/inc/ws/Util/fontextractor/class.ws.pdf.fontextractor.php +++ b/inc/ws/Util/fontextractor/class.ws.pdf.fontextractor.php @@ -11,9 +11,9 @@ class wsPDFFontExtractor { protected $descendantNames = array(); protected $doc; - public function __construct($in, $doc=null) { + public function __construct($in, $doc = null) { $this->doc = $doc; - $this->in = $in . '/original.pdf'; + $this->in = $in . '/crop.pdf'; $this->outpdf = $in . '/fonts/pdf'; $this->outweb = $in . '/fonts/web'; } @@ -115,7 +115,7 @@ class wsPDFFontExtractor { return $res; } - public function showObject($object, $binary=null) { + public function showObject($object, $binary = null) { $pdfshow = $this->getCommandLine('pdfshow'); $pdfshow->setArg(null, $this->in); $pdfshow->setArg(null, $object); diff --git a/inc/ws/Util/packager/class.ws.packager.html.php b/inc/ws/Util/packager/class.ws.packager.html.php index cbac22f02..06e28fb60 100644 --- a/inc/ws/Util/packager/class.ws.packager.html.php +++ b/inc/ws/Util/packager/class.ws.packager.html.php @@ -153,8 +153,8 @@ class wsPackagerHTML extends wsPackager { $htmlfile = WS_DOCS . '/' . $infos['document_id'] . '/h' . $infos['document_page'] . '.txt'; - if ($seoVersion && file_exists($htmlfile)) { - $html = file_get_contents($htmlfile); + if ($seoVersion && CubeIT_Util_Gzip::file_exists($htmlfile)) { + $html = CubeIT_Util_Gzip::file_get_contents($htmlfile); $alt .= "\n" . $html . "\n"; @@ -371,5 +371,3 @@ class wsPackagerHTML extends wsPackager { } } - -?> \ No newline at end of file diff --git a/inc/ws/Util/packager/class.ws.packager.v1.php b/inc/ws/Util/packager/class.ws.packager.v1.php index e6b88d9ab..39af64c92 100644 --- a/inc/ws/Util/packager/class.ws.packager.v1.php +++ b/inc/ws/Util/packager/class.ws.packager.v1.php @@ -24,7 +24,7 @@ class wsPackagerV1 extends wsPackagerHTML { } protected function compile() { - + } protected function copyFluidbookFiles() { @@ -52,7 +52,7 @@ class wsPackagerV1 extends wsPackagerHTML { foreach ($this->pages as $book_page => $infos) { $ftext = WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'] . '.txt'; if (file_exists($ftext)) { - $xml->addChild('pageText', htmlspecialchars(file_get_contents($ftext))); + $xml->addChild('pageText', htmlspecialchars(CubeIT_Util_Gzip::file_get_contents($ftext))); } else { $xml->addChild('pageText', ' '); } @@ -90,7 +90,7 @@ class wsPackagerV1 extends wsPackagerHTML { $link['type'] = intval($link['type']); if ($link['page'] % 2 == 1) { - $link['page']--; + $link['page'] --; $link['left'] = $link['left'] + $this->size[0]; } -- 2.39.5