/** * WJAeroplane is the main Aeroplane Javascript, this should be used to access Aeroplane functions * * @since Fri Jul 04 2008 * @author Ron Rademaker **/ var WJAeroplane = Class.create({ /** * initialize * * Creates a new WJAeroplane * * @since Fri Jul 04 2008 * @access public * @return WJAeroplane **/ initialize: function() { this.menu = null; this.contextmenu = null; this.spinErrorHandlers = {}; this.windowmanager = new WJWindowManager(); if (window.WJProgressNotifier) { this.progressnotifier = new WJProgressNotifier(); } this.unloadmanager = new WJUnloadManager(this.allowUnload.bind(this) ); this.topbarId = "aeroplane_topbar"; this.contentId = "aeroplane_main"; this.contentClass = "aeroplane_sitemaincontent"; this.contentBlockContainers = {}; this.dbtables = {}; this.layers = []; this.translateGui = WJAeroplane.translate.bind(this); new WJImageloader(); }, /** * aeroplaneSpinError * * Fallback function to handle unhandled spin (ajax) errors * * @since Wed Jan 07 2009 * @access public * @param response response * @return void **/ aeroplaneSpinError: function(response, lastSpin) { for (code in this.spinErrorHandlers) { if (code == response.status && typeof(this.spinErrorHandlers[code])=="function") { this.spinErrorHandlers[code](response, lastSpin); return; } } if (document.location.pathname == "/aeroplaneapplication") { var reload = function() { this.unloadmanager.suspend(); document.location.reload(); }.bind(this); WJWindow.alert("Er heeft zich een fout voorgedaan, Windmill CMS zal automatisch worden herladen. Neem contact op met Connectholland wanneer dit probleem zich blijft voordoen.", reload, aeroplane.translateGui); } }, /** * selectLanguage * * Sets Aeroplane to the given language * * @since Fri May 15 2009 * @access public * @param string language * @return void **/ selectLanguage: function(language, force) { var force = !!force; if (this.allowUnload() || force) { this.unloadmanager.suspend(true); var href = document.location.href.replace(document.location.hash, "").replace(/#$/, ""); if (href.match(/uilanguage=/) ) { href = href.replace(/(uilanguage=)[^&]*/, "$1" + language); } else if (href.match(/\?/) ) { href = href + "&uilanguage=" + language; } else { href = href + "?uilanguage=" + language; } document.location.href = href; } else { WJWindow.booleanConfirm("Mogelijk zijn er nog niet opgeslagen gegevens."+ "\n" + "Wanneer de taalinstelling gewijzigd wordt zullen alle applicaties gesloten worden."+ "\n\n" + "Weet je zeker dat je de taalinstelling wilt wijzigen?", this.selectLanguage.bind(this, language, true), aeroplane.translateGui); } }, /** * registerSpinErrorHandler * * Registers a callback to the error status * * @since Thu Feb 12 2009 * @access public * @param integer code * @param Function callback * @return void **/ registerSpinErrorHandler: function(code, callback) { this.spinErrorHandlers[code] = callback; }, /** * addMainMenuItem * * Adds an item to the main menu, these are used only to access the submenu's * * @since Fri Jul 04 2008 * @access public * @param string id * @param WJMenu menu **/ addMainMenuItem: function(id, menu) { if (this.menu == null) { this.menu = new WJMenu("main", -1); } this.menu.addItem(id, menu); }, /** * addMenuItem * * Adds a menu item to a main menu item, these contain the actual actions * * @since Fri Jul 04 2008 * @access public * @param string mainid * @param string id * @param WJMenu menu **/ addMenuItem: function(mainid, id, menu) { this.menu.getItem(mainid).addItem(id, menu); }, /** * openApplication * * Creates an application interface and lets the window manager run the application * * @since Fri Jul 04 2008 * @access public * @param string application * @param mixed applicationargs (not in declaration) * @return WJApplicationInterface **/ openApplication: function(application) { var applicationInterface = window["WJ" + application + "Interface"].construct(arguments); this.windowmanager.startApplication(applicationInterface); if (applicationInterface.showProgress() ) { this.progressnotifier.show(applicationInterface, "Applicatie wordt opgestart"); } return applicationInterface; }, /** * closeMotd * * Closes the current motd and makes sure it won't be back * * @since Tue Sep 22 2009 * @access public * @return void **/ closeMotd: function() { if ($("motd") ) { $("motd").hide(); var spin = new WJSpin(); spin.update(new WJUrl({"ct": "wmdynamic", "module": "Wmcb"}), "Wmcb", "readMotd", {}, []); } }, /** * createTopBar * * Creates the html elements for the topbar * Uses dom manipulation to keep references made by other scripts intact * * @since Mon Jul 07 2008 * @access public * @return void **/ createTopBar: function() { var bodyChildren = Element.extend(document.body).childElements(); var topbarDiv = document.body.appendChild(new Element("div", {id: this.topbarId} ) ); var mainDiv = document.body.appendChild(new Element("div", {"class": this.contentClass, id: this.contentId} ) ); for (i=0; i < bodyChildren.length; i++) { if (bodyChildren[i].tagName != "script") { mainDiv.appendChild(bodyChildren[i] ); } } }, /** * printPage * * Interface to native window print because 'Nightmare from Redmond 7' can't bind natives * * @since Fri Feb 27 2009 * @access public * @return void **/ printPage: function() { window.print(); }, /** * showTopBar * * Fills the topbar element from the temporary topbar and shows it * * @since Mon Jul 07 2008 * @access public * @param string temporaryid * @return void **/ showTopBar: function(temporaryid) { // remove empty menus $(temporaryid).select(".aeroplane_mainmenu").each(function(s) { if ( (s.select("li").length == 0) && (!s.hasClassName("aeroplane_mainmenu_singleclick") ) ) { s.remove(); } }); // prevent a scrollbars on the page when in CMS mode, if needed it should be in the div document.body.setStyle({"overflow": "hidden"}); Element.extend(document.documentElement).setStyle({"overflow": "hidden"}); var tempTop = $(temporaryid); var topbar = $(this.topbarId); topbar.innerHTML = tempTop.innerHTML; topbar.className = tempTop.className; tempTop.remove(); var fixMainDivHeight = function(mainDiv, topbar) { $(mainDiv).setStyle({"height": ($(document).viewport.getHeight() - $(topbar).getHeight() ) + "px"}); }.bind(window, this.getContentElement(), this.getTopbar() ); Event.observe(window, "resize", fixMainDivHeight); fixMainDivHeight(); }, /** * getContentElement * * Gets the main content element * * @since Mon Jul 07 2008 * @access public * @return DOMElement **/ getContentElement: function() { return document.getElementById(this.contentId); }, /** * getTopbar * * Gets the topbar element * * @since Mon Jul 07 2008 * @access public * @return DOMElement **/ getTopbar: function() { return document.getElementById(this.topbarId); }, /** * registerContentBlock * * Registers a content block on the page * * @since Mon Aug 04 2008 * @access public * @param string id * @param string identifier * @param string module * @param string basemodule * @param object properties * @return void **/ registerContentBlock: function(id, cbcid, identifier, module, basemodule, properties) { var properties = properties || {}; var cblock = new WJContentBlock(id, module, properties); cblock.setIdentifier(identifier); this.contentBlockContainers[cbcid].registerContentBlock(cblock); }, /** * registerDBTable * * Registers a dbtable record (with contentblocks) on the page * * @since Tue Mar 31 2009 * @access public * @param string htmlid * @param string module * @param string collection * @return void **/ registerDBTable: function(htmlid, module, collection, saveAndLogout) { if (!(htmlid in this.dbtables) ) { this.dbtables[htmlid] = new WJDBTable(htmlid, module, collection, saveAndLogout); } }, /** * registerContentBlockContainer * * Registers a content block container, a cbc contains (or is able to contain) content blocks * * @since Mon Sep 22 2008 * @access public * @param string id * @param string identifier * @param string module * @param string basemodule * @param object properties * @return void **/ registerContentBlockContainer: function(id, identifier, module, basemodule, properties) { var properties = properties || {}; var cbc = new WJContentBlockContainer(id, identifier, module, properties); this.contentBlockContainers[identifier] = cbc; }, /** * editContentBlock * * Opens an editor to edit the content block in the html element with id * * @since Mon Aug 04 2008 * @access public * @param string cbcid * @param string blockid * @return void **/ editContentBlock: function(cbcid, blockid) { WJDebugger.log(WJDebugger.NOTICE, "Edit content block", cbcid, blockid); var contentBlock = this.getContentBlock(cbcid, blockid); if (contentBlock) { var application = this.openApplication(contentBlock.getApplicationName(), contentBlock.getModule(), contentBlock.getIdentifier(), contentBlock.getProperties() ); application.setCBC(this.contentBlockContainers[cbcid]); } }, /** * getCBCs * * Gets all active cbcs for module * * @since Tue Sep 23 2008 * @access public * @param string module * @return void **/ getCBCs: function(module) { var cbcs = new Array(); for (var key in this.contentBlockContainers) { if (this.contentBlockContainers[key].getModule() == module) { cbcs.push(this.contentBlockContainers[key]); } } return cbcs; }, /** * getContentBlock * * Returns the block identified by id * * @since Wed Aug 6 2008 * @access public * @param string cbcid * @param string blockid * @return WJContentBlock **/ getContentBlock: function(cbcid, blockid) { return (this.contentBlockContainers[cbcid]) ? this.contentBlockContainers[cbcid].getContentBlock(blockid) : false; }, /** * isContentBlock * * Tells if the given id identifies a contentBlock * * @since Mon Sep 8 2008 * @access public * @param string cbcid * @param string blockid * @return boolean **/ isContentBlock: function(cbcid, blockid) { return (this.contentBlockContainers[cbcid] && this.contentBlockContainers[cbcid].getContentBlock(blockid) ); }, /** * openDatabaseContentEditor * * Opens the content editor identified by cbcid * * @since Wed May 20 2009 * @access public * @param string cbcid * @return void **/ openDatabaseContentEditor: function(cbcid) { this.dbtables[cbcid].openContentEditor(); }, /** * contextMenu * * Handles the case a contextmenu fires an event * * @since Fri Aug 8 2008 * @access public * @param Event event * @param string blockid * @return void **/ contextMenu: function(cbcid, blockid, action) { if (blockid == "dbtable") { switch (action) { case "update": this.openDatabaseContentEditor(cbcid); break; case "delete": this.dbtables[cbcid].deleteRecord(); break; case "moveUp": case "moveDown": this.dbtables[cbcid].dbTableFunction(action); break; } } else { switch (action) { case "update": this.editContentBlock(cbcid, blockid); break; case "delete": this.deleteContentBlock(cbcid, blockid); break; case "online": this.setContentBlockOnline(true, cbcid, blockid); break; case "offline": this.setContentBlockOnline(false, cbcid, blockid); break; case "moveUp": case "moveDown": this.contentBlockFunction(action, cbcid, blockid); break; } } }, /** * contentBlockFunction * * Calls action on the contentblock with blockid in cbcid * * @since Mon Feb 16 2009 * @access public * @param string action * @param string cbcid * @param string blockid * @return void **/ contentBlockFunction: function(action, cbcid, blockid) { var spin = new WJSpin(); var contentBlock = this.getContentBlock(cbcid, blockid); var contentBlockContainer = this.contentBlockContainers[cbcid]; spin.update(new WJUrl({"ct": "wmdynamic", "module": "Wmcb", "collections": contentBlock.properties.collection}), "Wmcb", action, {objid: contentBlock.getIdentifier()}, [contentBlock.postActionHandler.bind(contentBlock, action), contentBlockContainer.postActionHandler.bind(contentBlockContainer, contentBlock, action)]); }, /** * deleteContentBlock * * Deletes a contentblock (used from the context menu * todo: dry this with WJContentEditorInterface's delete contentblock * * @since Fri Jan 09 2009 * @access public * @param string cbcid * @param string blockid * @return void **/ deleteContentBlock: function(cbcid, blockid) { WJWindow.booleanConfirm("Weet je zeker dat je dit contentblok wilt verwijderen?", function(cbcid, blockid, window, e, confirm) { if (!confirm) { return; } var spin = new WJSpin(); var contentBlock = this.getContentBlock(cbcid, blockid); var cbcon = this.contentBlockContainers[cbcid]; spin.update(new WJUrl({"ct": "wmdynamic", "module": "Wmcb", "collections": contentBlock.properties.collection}), "Wmcb", "delete", {objid: contentBlock.getIdentifier() }, [contentBlock.removeContextMenu.bind(contentBlock), contentBlock.getElement().remove.bind(contentBlock.getElement() ), cbcon.refreshContextMenuButtons.bind(cbcon)]); }.bind(this, cbcid, blockid), aeroplane.translateGui); }, /** * setContentBlockOnline * * Sets a contentBlock online / offline * * @since Fri Jan 09 2009 * @access public * @param boolean online * @param string cbcid * @param string blockid * @return void **/ setContentBlockOnline: function(online, cbcid, blockid) { var spin = new WJSpin(); var contentBlock = this.getContentBlock(cbcid, blockid); var func = online ? "online" : "offline"; var message = online ? "Het contentblok staat nu online": "Het contentblok staat nu offline"; var updateClassname = online ? function() { this.removeClassName("offline"); }.bind(contentBlock.getElement() ) : function() { this.addClassName("offline"); }.bind(contentBlock.getElement() ); spin.update(new WJUrl({"ct": "wmdynamic", "module": "Wmcb", "collections": contentBlock.properties.collection}), "Wmcb", func, {objid: contentBlock.getIdentifier() }, [WJWindow.notice.bind(WJWindow, message, null, aeroplane.translateGui), updateClassname]); }, /** * registerContextMenu * * Binds a listener to the contextmenu * * @since Fri Aug 8 2008 * @access public * @param string menuid * @param string cbcid * @param string blockid * @return void **/ registerContextMenu: function(menuid, cbcid, blockid) { if (!this.contextmenu) { this.contextmenu = new WJContextMenu(); } this.contextmenu.register(menuid, cbcid, blockid); }, /** * registerDBTableContextMenu * * Binds a listener to the contextmenu * * @since Tue Mar 31 2009 * @access public * @param string menuid * @param string htmlid * @param string id * @return void **/ registerDBTableContextMenu: function(menuid, htmlid, id) { if (!this.contextmenu) { this.contextmenu = new WJContextMenu(); } this.contextmenu.registerDBTable(menuid, htmlid, id); }, /** * hideAllContextMenus * * Calls the hideAll method on the contextmenu handler * * @since Fri Aug 8 2008 * @access public * @return void **/ hideAllContextMenus: function() { this.contextmenu.hideAll(); }, /** * logout * * Logs the user out * * @since Fri Jul 04 2008 * @access public * @param string logouturl * @return void **/ logout: function(logouturl) { if (logouturl == null) { document.location.href = "/?useraction=logout"; } else { document.location.href = logouturl; } }, /** * loadingCursor * * Changes the current cursor to a loader or back to normal * * @since Thu Sep 25 2008 * @access public * @param boolean loading * @param wjwindow wjwindow * @param function callback * @return void **/ loadingCursor: function(loading, wjwindow, callback) { var wjwindow = wjwindow || false; var callback = callback || false; if (wjwindow) { wjwindow.setLoading(loading, callback); } if (loading) { this.layers.push(new WJModalLayer() ); $(document.body).setStyle({"cursor": "wait"}); $$(".aeroplane_button").each(function(s) { $(s).setStyle({"cursor": "wait"}); } ); $$(".dijitTab").each(function(s) { $(s).setStyle({"cursor": "wait"}); } ); } else { this.layers.each(function(l) { l.destroy(); }); this.layers = []; $(document.body).setStyle({"cursor": "auto"}); $$(".aeroplane_button").each(function(s) { $(s).setStyle({"cursor": "default"}); } ); $$(".dijitTab").each(function(s) { $(s).setStyle({"cursor": "pointer"}); } ); } }, /** * respinMain * * Executes a spin request to replace the entire main div with the latest info from the database (use this when local ajax updates can't be used to show updated information) * * @since Wed Feb 25 2009 * @access public * @return void **/ respinMain: function(callback) { var callback = Object.isFunction(callback) ? callback : function() {}; var baseUrl = document.location.href.replace("#", ""); var url = (baseUrl.indexOf("?") == -1) ? baseUrl + "?wmtrigger[]=requestufts&wmtrigger[]=spin" : baseUrl + "&wmtrigger[]=requestufts&wmtrigger[]=spin"; url = (url.indexOf("dt=") == -1) ? url + "&dt=default" : url; var spin = new WJSpin(); if (!$("aeroplane_main") ) { aeroplane.loadingCursor(false); return; } spin.content(new WJUrl({}, url), [function(response) { if (!response.documentElement) { return; } var newcontent = response.documentElement.getElementsByTagName("body")[0]; if (document.importNode) { var stub = new Element("div"); stub.appendChild($("aeroplane_main").ownerDocument.importNode(newcontent, true) ); stub.innerHTML += ""; var newdoc = stub.firstDescendant(); var origdoc = $("aeroplane_main"); for (var i = 0; i < origdoc.childNodes.length; i++) { if ( (origdoc.childNodes[i].nodeName == newdoc.nodeName) && (origdoc.childNodes[i].className == newdoc.className) ) { $(origdoc.childNodes[i]).update(newdoc); } } } else { var origdoc = $("aeroplane_main"); for (var i = 0; i < origdoc.childNodes.length; i++) { if ( (origdoc.childNodes[i].nodeName == newcontent.nodeName) && (origdoc.childNodes[i].className == newcontent.className) ) { $(origdoc.childNodes[i]).update(newcontent); } } origdoc.innerHTML = origdoc.innerHTML; } aeroplane.loadingCursor(false); }, callback]); }, /** * allowUnload * * Does a check to tell if an unload is allowed (says it is not allowed if any application that is not readonly is open) * * @since Tue Feb 17 2009 * @access public * @return boolean **/ allowUnload: function() { var apps = this.windowmanager.getRunningApplication(); for (var i = 0; i < apps.length; i++) { if (!apps[i].readonly && (apps[i].state != "closed") ) { return false; } } return true; } }); /** * Aeroplane translations * * @since Thu Jun 18 2009 * @access public * @param string key * @return string **/ WJAeroplane._translations = {OK: "Ok", CANCEL: "Annuleren", YES: "Ja", NO: "Nee", CLOSE_WINDOW: "Venster sluiten"}; WJAeroplane.translate = function(key) { if (WJAeroplane._translations[key] ) { return WJAeroplane._translations[key]; } return key.charAt(0).toUpperCase() + key.replace("_", " ").substr(1).toLowerCase(); }; /** * WJWindowManager manages all windows (javascript WJWindows) for Aeroplane * * @since Fri Jul 04 2008 * @author Ron Rademaker **/ var WJWindowManager = Class.create({ /** * initialize * * Creates a new WJWindowManager * * @since Fri Jul 04 2008 * @access public * @return void **/ initialize: function() { this.applications = new Array(); // Currently running applications (javascript interfaces to the application) this.windows = {}; // Current windows, showing or hidden. Each window must be associated with an application this.applicationRunner.bind(this).repeat(0.25); this.applicationRun = false; this.pid = 0; // give all running applications a unique process id dojo.require("dojo.parser"); Event.observe(document, "keydown", this.observeKey.bindAsEventListener(this) ); }, /** * getByPid * * Gets a running application by pid * * @since Tue May 12 2009 * @access public * @param integer pid * @return WJApplicationInterface **/ getByPid: function(pid) { for (var i = 0; i < this.applications.length; i++) { if (this.applications[i].getPid() == pid) { return this.applications[i]; } } }, /** * observeKey * * Passes the key event to the currently open application (ie. the last application) * * @since Wed Apr 22 2009 * @access public * @param event e * @return void **/ observeKey: function(e) { if (this.applications.length > 0) { this.applications[this.applications.length - 1].handleKeyEvent(e); } }, /** * getMaxZIndex * * Gets the highest used z-index is the current dom * * @since Wed Nov 19 2008 * @access public * @return int **/ getMaxZIndex: function() { var nodes = $$("."); var lenght = nodes.lenght; var z = 0; for (var i = 0; i < lenght; i++) { z = Math.max(z, nodes[i].getStyle("z-index") ); } return z; }, /** * startApplication * * Starts an application from the application interfaces * * @since Fri Jul 04 2008 * @access public * @param WJApplicationInterface application * @return void **/ startApplication: function(application) { if ($("motd") ) { $("motd").hide(); } this.pid++; application.setPid(this.pid); var pid = application.getPid(); this.windows["application" + pid] = {}; this.applications.push(application); application.wakeUp(); }, /** * applicationRunner * * Wakes all running applications up and lets the do something (if they need to do something) * * @since Fri Jul 04 2008 * @access public * @return void **/ applicationRunner: function() { if (!this.applicationRun) { this.applicationRun = true; for (var i = 0; i < this.applications.length; i++) { this.applications[i].wakeUp(); } for (var i = 0; i < this.applications.length; i++) { if (this.applications[i].closed() ) { this.closeApplication(this.applications[i], i); } } this.applicationRun = false; } }, /** * getRunningApplication * * Returns the running applications * * @since Wed Feb 18 2009 * @access public * @return Array **/ getRunningApplication: function() { return this.applications; }, /** * cleanUpDijitWidgets * * Destroys all dijit widgets that are no longer in the dom * * @since Tue Nov 04 2008 * @access public * @return void **/ cleanUpDijitWidgets: function() { dijit.registry.forEach(function(widget) { if (!$(widget.domNode).descendantOf(widget.domNode.ownerDocument.documentElement) ) { WJDebugger.log(WJDebugger.INFO, "Destroying dijit widget", widget); widget.destroyRecursive(false); } }); }, /** * closeApplication * * Closes the main window of this application and removes the application from the applications array * * @since Wed Jul 16 2008 * @access public * @param WJApplicationInterface application * @param integer index * @return void **/ closeApplication: function(application, index) { var wjwindow = this.getMainWindow(application); wjwindow.hide(); this.applications.splice(index, 1); }, /** * destroyMainWindow * * Destroy the main window of the given application * * @since Tue Aug 19 2008 * @access public * @param WJApplicationInterface application * @return void **/ destroyMainWindow: function(application) { WJDebugger.log(WJDebugger.INFO, "Destroy main window", this); this.getMainWindow(application).destroy(); }, /** * getMainWindow * * Gets the main window for application * Creates a window if there is no window * * @since Mon Jul 07 2008 * @access public * @param WJApplicationInterface application * @return DOMElement **/ getMainWindow: function(application) { return this.getWindow(application, "main"); }, /** * applicationResponse * * Handles according to the response inside the application * * @since Tue Aug 19 2008 * @access public * @param WJApplicationInterface application * @param WJWindow wjwindow * @param Event event * @return void **/ applicationResponse: function(application, wjwindow, event) { WJDebugger.log(WJDebugger.NOTICE, "Application response", application, wjwindow, event); switch (event.eventName) { case "wjgui:save": application.save(); break; case "wjgui:close": case "wjgui:false": case "wjgui:cancel": application.close(); break; default: var eventName = event.eventName.sub("wjgui:", ""); application.handleWindowEvent(eventName); break; } }, /** * getWindow * * Gets a window of tyoe for application * Creates a window if there is no window * * @since Mon Jul 28 2008 * @access public * @param WJApplicationInterface application * @param string type * @return DOMElement **/ getWindow: function(application, type) { var pid = application.getPid(); if (this.windows["application" + pid]) { if (this.windows["application" + pid][type]) { return this.windows["application" + pid][type]; } } if (type == "main") { this.windows["application" + pid][type] = application.createMainWindow(); } else { this.windows["application" + pid][type] = application.createWindow(type); } return this.windows["application" + pid][type]; }, /** * destroyWindow * * Destroys the type window for application * * @since Wed May 27 2009 * @access public * @param WJApplicationInterface application * @param string type * @return void **/ destroyWindow: function(application, type) { var pid = application.getPid(); if (this.windows["application" + pid]) { if (this.windows["application" + pid][type]) { delete this.windows["application" + pid][type]; } } }, /** * getMainWindowWidth * * Gets the width for main windows (ie. full apps) * * @since Mon Jul 07 2008 * @access public * @return integer **/ getMainWindowWidth: function() { return (document.viewport.getWidth() - (this.getMainWindowLeft() + this.getMainWindowRight() ) ); }, /** * getMainWindowHeight * * Gets the height for main windows (ie. full apps) * * @since Mon Jul 07 2008 * @access public * @return integer **/ getMainWindowHeight: function() { return (document.viewport.getHeight() - (this.getMainWindowTop() + this.getMainWindowBottom() ) ); }, /** * getMainWindowTop * * Gets the Y position for main windows (ie. full apps) * * @since Mon Jul 07 2008 * @access public * @return integer **/ getMainWindowTop: function() { return 2; if (aeroplane.menu) { return 42; } else { return 2; } }, /** * getMainWindowBottom * * Gets the Y position for the bottom of main windows (ie. full apps) * * @since Fri Aug 08 2008 * @access public * @return integer **/ getMainWindowBottom: function() { return 2; }, /** * getMainWindowLeft * * Gets the X position for main windows (ie. full apps) * * @since Mon Jul 07 2008 * @access public * @return integer **/ getMainWindowLeft: function() { return 5; }, /** * getMainWindowRight * * Gets the X position for the right of main windows (ie. full apps) * * @since Fri Aug 08 2008 * @access public * @return integer **/ getMainWindowRight: function() { return 5; }, /** * maximize * * Maximizes the given window according to the padding set in this manager * * @since Fri Aug 8 2008 * @access public * @param WJWindow window * @return void **/ maximize: function(window) { window.maximize(this.getMainWindowTop(), this.getMainWindowRight(), this.getMainWindowBottom(), this.getMainWindowLeft() ); } }); /** * WJApplicationInterface is the base interface to applications. Manages communication with the server through WJSpin * * @since Fri Jul 04 2008 * @author Ron Rademaker **/ var WJApplicationInterface = Class.create({ /** * WJApplicationInterface keeps track of the current state of the running application. Possible states are: * starting: the application is starting up * running: the application is running fine * waiting: the application is waiting for a server response or for user input * busy: the application is running slowly * crashed: the application has crashed (of course, being able to determine this is rare) * closing: the application is closing down * closed: the application has been closed and others may forget about it **/ /** * initialize * * Creates a new WJApplicationInterface * * @since Fri Jul 04 2008 * @access public * @param string appname * @return void **/ initialize: function(appname) { this.appname = appname; this.state = "starting"; this.pid = null; this.readonly = false; this._showprogress = false; this._closeurl = null; // URL to return to when the app closes }, /** * setCloseUrl * * Sets the apps close url * * @since Fri Jan 29 2010 * @access public * @param string url * @return void **/ setCloseUrl: function(url) { this._closeurl = url; }, /** * callCMSFunction * * Calls a CMS function and then calls the cmsCallback * * @since Mon Jun 08 2009 * @access public * @param string func * @param string module * @param object data * @return void **/ callCMSFunction: function(func, module, data) { var spin = new WJSpin(); var url = new WJUrl(); url.setCt("wmdynamic"); url.addParameter("module", module); url.addParameter("type", "xml"); url.addParameter("wmtrigger[]", ["requestufts"]); spin.update(url, module, func, data, [this.cmsCallback.bind(this, func)]); aeroplane.loadingCursor(true); }, /** * cmsCallback * * Callback function called after executing cmsfunction * * @since Mon Jun 08 2009 * @access public * @param string cmsfunction * @param object response * @return void **/ cmsCallback: function(cmsfunction, response) { aeroplane.loadingCursor(false); }, /** * setReloadCallback * * Sets a reload callback, reloads the page part with the content being edited in this application * * @since Mon Aug 04 2008 * @access public * @param function callback * @return void **/ setReloadCallback: function(callback) { this.reloadCallback = callback; }, /** * buildGui * * Creates a WJGui for this application * * @since Tue Jul 15 2008 * @access public * @return WJGui **/ buildGui: function() { return new WJGui(this); // easy to extend to e.g. WJEditorGui }, /** * closed * * Returns true if this application is closed * * @since Mon Jul 07 2008 * @access public * @return boolean **/ closed: function() { return (this.state == "closed"); }, /** * wakeUp * * Gives the application the chance to do whatever it is they want to do * * @since Mon Jul 07 2008 * @access public * @return void **/ wakeUp: function() { WJDebugger.log(WJDebugger.DEBUG, "Application wakeup", this, this.state); switch (this.state) { case "starting": this.startApplication(); break; case "running": this.pingApplication(); break; case "waiting": this.testTimeout(); break; case "busy": this.handleBusy(); break; case "crashed": this.reportCrash(); break; case "closing": WJDebugger.log(WJDebugger.DEBUG, "Go cleanup application", this); this.cleanUp(); break; case "closed": break; } }, /** * setPid * * Sets a PID for this application * * @since Mon Jul 07 2008 * @access public * @param integer pid * @return void **/ setPid: function(pid) { this.pid = pid; }, /** * getPid * * Gets the PID for this application * * @since Mon Jul 07 2008 * @access public * @return integer **/ getPid: function() { return this.pid; }, /** * createMainWindow * * Creates the main WJWindow for this application * * @since Mon Jul 07 2008 * @access public * @return WJWindow **/ createMainWindow: function() { var window = new WJWindow(aeroplane.windowmanager.applicationResponse.bind(aeroplane.windowmanager, this), aeroplane.getTopbar(), aeroplane.translateGui); window.getWindowElement().addClassName("aeroplane_window_applicationwindow").addClassName("aeroplane_window_applicationwindow_" + this.appname.toLowerCase() ).addClassName("aeroplane_reset"); window.setTitle(this.getWindowTitle() ); aeroplane.windowmanager.maximize(window); window.hide(); return window; }, /** * getWindowTitle * * Tells what title to put on the window * * @since Mon Sep 22 2008 * @access public * @return string **/ getWindowTitle: function() { return ""; }, /** * closeMainWindow * * Callback for closing the main window (ie. sets the state to closing) * * @since Mon Jul 07 2008 * @access public * @return void **/ close: function() { WJDebugger.log(WJDebugger.NOTICE, "Requesting application close", this); // allow a last processing of normal operations this.wakeUp(); // make sure the app will close down on next wakeup this.state = "closing"; }, /** * startApplication * * Starts this application, should end up with a state different from starting * * @since Mon Jul 07 2008 * @access public * @return void **/ startApplication: function() { if (this.pid == null) { throw "Trying to start an application without a pid"; } this.currentComponent = aeroplane.windowmanager.getMainWindow(this).getContentElement("main"); this.gui = this.buildGui(); this.gui.show(aeroplane.windowmanager.getMainWindow(this), this.currentComponent, new WJSpin(), this.contentUpdated.bind(this) ); }, /** * createWindow * * Creates a helper window for type * * @since Mon Jul 28 2008 * @access public * @param string type * @return WJWindow **/ createWindow: function(type) { var wjwindow = new WJWindow(null, aeroplane.getTopbar(), aeroplane.translateGui); wjwindow.setWidth(aeroplane.windowmanager.getMainWindowWidth() ); wjwindow.setHeight(aeroplane.windowmanager.getMainWindowHeight() ); wjwindow.setX(aeroplane.windowmanager.getMainWindowLeft() ); wjwindow.setY(aeroplane.windowmanager.getMainWindowTop() ); return wjwindow; }, /** * contentUpdated * * Callback to notify the editor interface that the content has been updated * * @since Mon Jul 07 2008 * @access public * @return void **/ contentUpdated: function() { WJDebugger.log(WJDebugger.INFO, "Content updated", this); this.state = "running"; var loaderWnd = aeroplane.windowmanager.getWindow(this, "Loader"); loaderWnd.destroy.bind(loaderWnd).delay(2.1); // should be ready in 2 sec so 2.1 is 0.1 sec. safe aeroplane.windowmanager.getMainWindow(this).evalContentElement("main"); if (this.showProgress() ) { aeroplane.progressnotifier.hide(this, "Applicatie wordt opgestart"); aeroplane.progressnotifier.hide(this, "De inhoud van de applicatie is aan het laden"); } }, /** * pingApplication * * Gives this application the chance to do /something/, should end up with a state different from starting * * @since Mon Jul 07 2008 * @access public * @return void **/ pingApplication: function() { }, /** * testTimeout * * The application is currently waiting for something, this function gives the possibility to detect a timeout and deal with it * * @since Mon Jul 07 2008 * @access public * @return void **/ testTimeout: function() { }, /** * handleBusy * * The application is currently not keeping up, this function can be used to close non essential stuff and get the application out of the busy state * * @since Mon Jul 07 2008 * @access public * @return void **/ handleBusy: function() { }, /** * reportCrash * * The application has actually told us it has crashed (:D), this function deals with the crash (ie. report it per mail to the windmill maintainer) * * @since Mon Jul 07 2008 * @access public * @return void **/ reportCrash: function() { }, /** * cleanUp * * The application wants to stop running, clean up anything open and move state to closed * * @since Mon Jul 07 2008 * @access public * @return void **/ cleanUp: function() { WJDebugger.log(WJDebugger.NOTICE, "Cleaning up application", this); aeroplane.windowmanager.destroyMainWindow(this); aeroplane.loadingCursor(false); this.state = "closed"; if (this._closeurl) { document.location.href = this._closeurl; } }, /** * handleKeyEvent * * Function stub to overwrite to implement key events * * @since Wed Apr 22 2009 * @access public * @param event e * @return void **/ handleKeyEvent: function(e) { }, /** * handleWindowEvent * * Get's called by the windowmanager if an event occured in the window that has no default call to the application * * @since Thu Aug 21 2008 * @access public * @param string eventName * @return void **/ handleWindowEvent: function(eventName) { }, /** * showProgress * * * * @since Mon Apr 27 2009 * @access public * @return boolean **/ showProgress: function() { return this._showprogress; }, /** * getApplicationState * * Reads the current app state from the location hash * * @since Wed Mar 17 2010 * @access public * @return object **/ getApplicationState: function() { var state = {}; document.location.hash.replace(/#/, "").split("&").invoke("split", "=").each(function(s) { this[s[0] ] = s[1]; }.bind(state) ); return state; }, /** * toString * * Gives a string representation of this application * * @since Wed Apr 22 2009 * @access public * @return string **/ toString: function() { if (this.appname === null) { return "Uninitialized WJApplicationInterface"; } return this.appname + " instance '" + this.pid + "'"; } }); /** * Base GUI class (fallback / defaults for everything not configured / overwritten) * * @since Tue Jul 15 2008 * @author Ron Rademaker **/ var WJGui = Class.create({ /** * __construct * * Creates a new WJGui * * @since Tue Jul 15 2008 * @access public * @return WJGui **/ initialize: function(application) { WJDebugger.log(WJDebugger.INFO, "create gui"); this.application = application; this.loadingCallback = false; this.componentCache = {}; // quick access object for all components, speeds stuff up WJDebugger.log(WJDebugger.INFO, "finished creating gui", this); }, /** * getComponentForField * * Gets the WJComponent in this gui for a field with the name name * * @since Tue Aug 05 2008 * @access public * @param string name * @param object component * @return WJComponent **/ getComponentForField: function(name, component) { return this.componentCache[name]; }, /** * show * * Loads this GUI into wnd * * @since Tue Jul 15 2008 * @access public * @param WJWindow wjwindow * @param DomNode elem * @param WJSpin spin * @param function finished * @param WJUrl url - optional * @return void **/ show: function(wjwindow, elem, spin, finished, url) { if (!url) { var url = this._getUrl(); } this.addButtons(wjwindow); wjwindow.show(); this.updateContent(wjwindow, elem, spin, finished, url); this.application.state = "waiting"; }, /** * updateContent * * Updates the content of elem and calls gui parsing functions * * @since Tue May 12 2009 * @access public * @param wjwindow wjwindow * @param DomNode elem * @param WJSpin spin * @param function finished * @param WJUrl url **/ updateContent: function(wjwindow, elem, spin, finished, url) { this.preCleanUp(elem); if (dijit.byNode(elem) ) { this._updateContentTab(wjwindow, dijit.byNode(elem), spin, finished, url); } else { this.parseDojo = true; spin.content(url, [elem, finished, this.parseGUI.bind(this, elem, wjwindow) ]); } }, /** * updateContentCMS * * Update content function that includes a CMS call * * @since Thu Sep 03 2009 * @access public * @param wjwindow wjwindow * @param DomNode elem * @param WJSpin spin * @param function finished * @param WJUrl url * @param string module * @param string function * @param object data **/ updateContentCMS: function(wjwindow, elem, spin, finished, url, module, func, data) { var parameters = {}; Object.extend(parameters, url.getParameters() || { }); var _url = new WJUrl(parameters, url.getUrl() ); _url.addParameter("__cms_" + module, "true"); _url.addParameter("__function_" + module, func); for (var key in data) { _url.addParameter(key, data[key]); } this.updateContent(wjwindow, elem, spin, finished, _url); }, /** * _updateContentTab * * Updates the content of a dijit tab by setting its href attribute * * @since Wed Sep 02 2009 * @access public * @param wjwindow wjwindow * @param DijitTab elem * @param WJSpin spin * @param function finished * @param WJUrl url * @return void **/ _updateContentTab: function(wjwindow, tab, spin, finished, url) { var href = url.getUrl() + "?" + Object.toQueryString(url.getParameters() ); if (tab.attr("href") != href) { this.parseDojo = false; tab.attr("onDownloadEnd", function(elem, wjwindow, finished) { this.parseGUI(elem, wjwindow); finished(); }.bind(this, tab.domNode, wjwindow, finished) ); tab.attr("href", href); aeroplane.windowmanager.cleanUpDijitWidgets(); } else { aeroplane.loadingCursor(false, wjwindow, this.loadingCallback); } }, /** * _getUrl * * Gets the WJUrl to get the GUI * * @since Tue May 12 2009 * @access protected * @return WJUrl **/ _getUrl: function() { var url = new WJUrl({}, "/index.php"); url.setCt("wmdynamic"); url.setDt(this.getDt() ); url.addParameter("mode", "datacollector"); url.addParameter("state", this.application.state); url.addParameter("uft[]", this.getUfts() ); url.addParameter("wmtrigger[]", ["requestufts"]); url.addParameter("module", this.application.module); url.addParameter("pid", this.application.getPid() ); return url; }, /** * preCleanUp * * Cleans up the gui before spinning for content * * @since Tue Dec 16 2008 * @access public * @param DomNode elem * @return void **/ preCleanUp: function(elem) { var tinyMCELoaded = (typeof(tinyMCE) != "undefined") ? true : false; if (tinyMCELoaded) { $H(tinyMCE.editors).keys().each(function(id) { if (!$(id) || $(id).descendantOf(this) ) { WJDebugger.log(WJDebugger.NOTICE, "Removing tinyMCE editor: ", id); tinymce.EditorManager.execCommand("mceRemoveControl", false, id) } }.bind(elem) ); } }, /** * parseGUI * * Parses the GUI * * @since Wed Sep 3 2008 * @access public * @param Element context * @return void **/ parseGUI: function(context, wjwindow) { WJDebugger.log(WJDebugger.DEBUG, "Parse GUI", context, wjwindow); if (dojo && dojo.parser) { WJDebugger.log(WJDebugger.DEBUG, "Ready to parse GUI"); this._parseGUI(context, wjwindow); this.application.state = "running"; } else { arguments.callee.bind(this, context, wjwindow).delay(0.5); // try it later, because the content is not ready yet } }, /** * _parseGui * * Parses and handles the GUI * * @since Fri Sep 12 2008 * @access protected * @param Element context * @return array **/ _parseGUI: function(context, wjwindow) { WJDebugger.log(WJDebugger.INFO, "Dojo parsing new Gui", context, wjwindow); try { if (this.parseDojo) { aeroplane.windowmanager.cleanUpDijitWidgets(); var widgets = dojo.parser.parse(context); } else { context.innerHTML.evalScripts(); } } catch (e) { WJDebugger.log(WJDebugger.ERROR, "Dojo parsing new Gui failed", e); WJWindow.alert("De grafische gebruikersinterface kon niet correct worden opgebouwd."+ "\n" + "Neem contact op met Connectholland."+ "\n" + "De applicatie zal worden gesloten.", this.application.close.bind(this.application), aeroplane.translateGui); } this._handleGUILoad(context, wjwindow); return widgets; }, /** * handleGUILoad * * Does actions after the gui is loaded and parsed * * @since Thu Sep 4 2008 * @access protected * @param Element context * @param WJWindow wjwindow * @return void **/ _handleGUILoad: function(context, wjwindow) { this.focusElement(context); aeroplane.loadingCursor(false, wjwindow, this.loadingCallback); }, /** * focusElement * * Gives the possibility to focus a preferred element (as default tries to find a first element) * * @since Wed Sep 3 2008 * @access public * @param context * @return void **/ focusElement: function(context) { if (!context) { return; } var element = context.select("input:not([type=hidden])").first(); if (Object.isElement(element) ) { try { (function() { element.focus(); element.focus(); // doing it twice helps IE8 }).defer(); } catch (err) { // ie gets here... don't crash } } }, /** * getDt * * Returns the dt for gui-building - makes it possible to use another dt in a subclass * * @since Fri Aug 22 2008 * @access public * @return string **/ getDt: function() { return "gui"; }, /** * getUfts * * Returns the ufts for gui-building - makes it possible to use other uft's in a subclass * * @since Fri Aug 22 2008 * @access public * @return Array **/ getUfts: function() { return ["components"]; }, /** * addButtons * * Gives the possibility to add buttons to the window * * @since Thu Aug 14 2008 * @access public * @param WJWindow window * @return void **/ addButtons: function(window) { // here for extending purposes only }, /** * getComponentId * * Gets the html id of a component with id id (actual id depends on pid to avoid double ids) * * @since Tue Dec 30 2008 * @access public * @param string id * @return string **/ getComponentId: function(id) { if ($(id + "_" + this.application.pid) ) { return id + "_" + this.application.pid; } else { return id; } }, /** * setComponents * * Sets the WJ Components and couples them to input elements (if any) * * @since Tue May 12 2009 * @access public * @param array components * @return void **/ setComponents: function(components) { this.components = components; this._coupleComponents(this.components); }, /** * getData * * Retrieves an object with all key - value pairs for this gui's components * * @since Wed Feb 17 2010 * @access public * @param string prefix * @param object components * @return object **/ getData: function(prefix, data, component, noIdForGroups) { var prefix = prefix || ""; var component = component || this.components; var data = data || {}; var noIdForGroups = !!noIdForGroups; for (var cmp in component) { if (cmp == "id") { var value = component.getValue(); if (component.componentType == "WJExtendibleGroup") { for (var key in value) { propname = key; if (propname.match(/([^\[]*)(\[.*)/) ) { propname = propname.replace(/([^\[]*)(\[.*)/, "[$1]$2"); } else { propname = "_" + propname; } data[prefix + component[cmp] + propname] = value[key]; } return data; } else if (Object.isArray(value) ) { var length = value.length; if (length === 0) { data[prefix + component[cmp] + "[]" ] = ""; } else { for (var i = 0; i < length; i++) { data[prefix + component[cmp] + "[" + i + "]" ] = value[i]; } } } else if (typeof(value) == "object") { for (var key in value) { data[prefix + component[cmp] + "[" + key + "]" ] = value[key]; } } else { data[prefix + component[cmp] ] = component.getValue(); } } if (cmp == "component") { data = this.getData(prefix, data, component[cmp], noIdForGroups); } if (cmp == "components" && component.componentType != "WJExtendibleGroup") { if (component[cmp].each) { $A(component[cmp]).each(function(comp) { if (component["id"] && !noIdForGroups) { var id = component["id"].replace(/\[.*$/, ""); data = this.getData(prefix + id + "_", data, comp, noIdForGroups); } else { data = this.getData(prefix, data, comp, noIdForGroups); } }.bind(this) ); } } } return data; }, /** * _coupleComponents * * Couples the javascript components with HTML form elements (the visual representations of the components) * By now there should be input elements for all components * * @since Mon Jul 21 2008 * @access protected * @param object component * @return void **/ _coupleComponents: function(component) { WJDebugger.log(WJDebugger.INFO, "coupling", component); for (var cmp in component) { if (cmp == "id") { this.componentCache[component[cmp] ] = component; if ($(this.getComponentId(component[cmp]) ) ) { component.setHtmlelement($(this.getComponentId(component[cmp]) ), this); } else { var possibles = document.getElementsByName(component[cmp]); $A(possibles).each(component.setHtmlelement.bind(component) ); } } if (cmp == "component") { this._coupleComponents(component[cmp]); } if (cmp == "components") { if (component[cmp].each) { $A(component[cmp]).each(this._coupleComponents.bind(this) ); } } } }, /** * toString * * Gives a string representation of this gui * * @since Wed Apr 22 2009 * @access public * @return string **/ toString: function() { if (this.application === null) { return "Uninitialized WJGui"; } return "WJGui for \"" + this.application + "\""; } }); /** * WJLoginInterface is the interface to the user module for the login process. * * @since Tue Aug 12 2008 * @author Giso Stallenberg **/ WJLoginInterface = Class.create(WJApplicationInterface, { /** * initialize * * Initializes a WJLoginInterface * * @since Tue Aug 12 2008 * @access public * @param string appname * @return WJLoginInterface **/ initialize: function($super, appname, module, loggedIn, uiLanguage) { $super(appname); this.module = module; this.readonly = true; this.loggedIn = loggedIn; this.uiLanguage = uiLanguage || "nl_NL"; this.state = "background"; this.spinQueue = []; aeroplane.registerSpinErrorHandler(403, this.handleAccessDenied.bind(this) ); }, /** * handleKeyEvent * * Listens for CTRL+L to open its gui * * @since Wed Apr 22 2009 * @access public * @param event e * @return void **/ handleKeyEvent: function($super, e) { $super(e); if (!this.loggedIn) { if ( (this.state == "background") && (e.keyCode == 76) ) { // L if (e.ctrlKey && !e.shiftKey) { Event.stop(e); // Somehow Event.stop(event) doesn't work full in FF if (e.preventDefault) { e.preventDefault(); } this.state = "starting"; } } } }, /** * cleanUp * * Starts a new Login app after closing this one * * @since Wed May 13 2009 * @access public * @return void **/ cleanUp: function($super) { $super(); aeroplane.openApplication("Login", this.module, this.loggedIn, this.uiLanguage); }, /** * handleAccessDenied * * Hanles an AD spin response * * @since Thu Feb 12 2009 * @access * @param * @return **/ handleAccessDenied: function(response, spinCall) { if (typeof(spinCall) == "function") { this.spinQueue.push(spinCall); } this.state = "starting"; this.setLoginCorrectHandler(this.invokeSpinQueue.bind(this) ); }, /** * invokeSpinQueue * * Invokes all stacked spins * * @since Thu Feb 12 2009 * @access public * @return void **/ invokeSpinQueue: function(response) { if (typeof(this.spinQueue[0] ) == "function") { this.spinQueue[0](); delete this.spinQueue[0]; this.invokeSpinQueue(response); } }, /** * buildGui * * Creates a WJLoginGui for the app * * @since Tue Aug 12 2008 * @access public * @return WJLoginGui **/ buildGui: function() { return new WJLoginGui(this); }, /** * closeMainWindow * * * * @since Thu Aug 14 2008 * @access * @param * @return **/ handleWindowEvent: function(eventName) { if (eventName == "true") { this.login(); } else { aeroplane.windowmanager.getMainWindow(this).hide(); } }, /** * login * * Attempts a login at windmill CMS * * @since Mon Aug 11 2008 * @access public * @return void **/ login: function() { var wjwindow = aeroplane.windowmanager.getMainWindow(this); aeroplane.loadingCursor(true); var spin = new WJSpin(); var url = new WJUrl({}, "/index.php"); url.setCt("wmdynamic"); url.addParameter("application", this.appname); url.addParameter("module", this.module); var loginData = this.gui.getData(); url.addParameter("username", loginData.loginfields_username); url.addParameter("password", loginData.loginfields_password); spin.content(url, [this.loginCorrect.bind(this)], {"401": this.loginIncorrect.bind(this), "403": this.accessDenied.bind(this) }); }, /** * loginCorrect * * Handles the case a login was succesful * * @since Wed Aug 13 2008 * @access public * @param XMLHTTPRequest response * @return void **/ loginCorrect: function(response) { if (typeof(this.loginCorrectHandler) == "function") { this.loginCorrectHandler(response); aeroplane.windowmanager.destroyMainWindow(this); } else { if (response.loginforward) { this._forward(response.loginforward); } else if (response.xmlVersion && response.getElementsByTagName(this.module.toLowerCase() )[0] && response.getElementsByTagName(this.module.toLowerCase() )[0].getElementsByTagName("loginforward")[0] && (response.getElementsByTagName(this.module.toLowerCase() )[0].getElementsByTagName("loginforward")[0].textContent || response.getElementsByTagName(this.module.toLowerCase() )[0].getElementsByTagName("loginforward")[0].innerHTML) ) { if (response.getElementsByTagName(this.module.toLowerCase() )[0].getElementsByTagName("loginforward")[0].textContent) { var url = response.getElementsByTagName(this.module.toLowerCase() )[0].getElementsByTagName("loginforward")[0].textContent; } else { var url = response.getElementsByTagName(this.module.toLowerCase() )[0].getElementsByTagName("loginforward")[0].innerHTML; } this._forward(url); } else { this._reload(); } } }, /** * setLoginCorrectHandler * * Sets the handler to use for a correct login * * @since Thu Feb 12 2009 * @access public * @param Function callback * @return void **/ setLoginCorrectHandler: function(callback) { this.loginCorrectHandler = callback; }, /** * _forward * * Forwards to the given url * * @since Thu Aug 14 2008 * @access protected * @param string url * @return void **/ _forward: function(url) { document.location.href = url; }, /** * _reload * * Reloads the document (but makes sure there's no useraction=logout, otherwise uses _forward to the stripped url) * * @since Thu Aug 14 2008 * @access protected * @return void **/ _reload: function() { var loc = document.location; if (loc.href.indexOf("useraction=logout") != -1) { var url = loc.href.replace("useraction=logout&", ""); url = url.replace("useraction=logout", ""); if (url.endsWith("?") ) { url = url.replace("?", ""); } this._forward(url); } else { document.location.reload(); } }, /** * loginIncorrect * * Handles the case a login was incorrect * * @since Wed Aug 13 2008 * @access public * @param XMLHTTPRequest response * @return void **/ loginIncorrect: function(response) { aeroplane.loadingCursor(false); WJWindow.alert("De door u opgegeven gebruikersnaam/wachtwoord combinatie is onbekend", this.showWindow.bind(this), aeroplane.translateGui); }, /** * showWindow * * Shows the window * * @since Thu Aug 14 2008 * @access public * @return void **/ showWindow: function() { var win = aeroplane.windowmanager.getMainWindow(this); win.show(); }, /** * accessDenied * * Handles the case a login was not ok for aeroplane * * @since Wed Aug 13 2008 * @access public * @param XMLHTTPRequest response * @return void **/ accessDenied: function(response) { var win = aeroplane.windowmanager.getMainWindow(this); aeroplane.loadingCursor(false); WJWindow.alert("U heeft geen toegang tot dit deel van het systeem, maar bent wel succesvol aangemeld.", this._reload.bind(this), aeroplane.translateGui); } }); /** * GUI class for the paragraph editor * * @since Wed Aug 13 2008 * @author Giso Stallenberg **/ var WJLoginGui = Class.create(WJGui, { /** * show * * Loads this GUI into wnd * * @since Tue Jul 15 2008 * @access public * @param WJWindow wnd * @param WJSpin spin * @param function finished * @return void **/ show: function($super, wjwindow, spin, finished) { $super(wjwindow, spin, finished); wjwindow.getWindowElement().addClassName("aeroplane_reset"); wjwindow.insertWindowRowBefore("main", "intro"); wjwindow.setWidth(400); wjwindow.setHeight(510, wjwindow.getContentElement("main"), false); wjwindow.setZ(1000); wjwindow.center(); wjwindow.keepCentered(); }, /** * addButtons * * Adds buttons to the window * * @since Thu Aug 14 2008 * @access public * @param WJWindow window * @return void **/ addButtons: function(wjwindow) { wjwindow.addButton("Aanmelden", "true", true); }, /** * _parseGui * * Parses and handles the GUI * * @since Wed Feb 18 2009 * @access protected * @param Element context * @return array **/ _parseGUI: function($super, context, wjwindow) { var widgets = $super(context, wjwindow); wjwindow.getContentElement("intro").appendChild(wjwindow.getContentElement("main").down(".aeroplane_wjhtml") ); return widgets; }, /** * _handleGUILoad * * Scrolls the window into view if it's not * * @since Mon Mar 15 2010 * @access protected * @param Element context * @param WJWindow wjwindow * @return void **/ _handleGUILoad: function($super, context, wjwindow) { if (document.viewport.getScrollOffsets().top > wjwindow.getY() ) { wjwindow.getWindowElement().scrollTo(); } return $super(context, wjwindow); }, /** * getDt * * Returns the dt for login application gui-building. Specific dt to disable content panes * * @since Tue Feb 02 2010 * @access public * @return string **/ getDt: function() { return "logingui"; }, /** * _getUrl * * Gets the WJUrl to get the GUI * * @since Tue May 12 2009 * @access protected * @return WJUrl **/ _getUrl: function($super) { var url = $super(); url.addParameter("uilanguage", this.application.uiLanguage); return url; } }); /** * WJUnloadManager makes sure no data get lost when an unload takes place * * @since Tue Feb 17 2009 * @revision $Revision$ * @author Giso Stallenberg * @package Windmill.Aeroplane.Javascript **/ var WJUnloadManager = Class.create({ /** * initialize * * Creates a new WJUnloadManager * * @since Tue Feb 17 2009 * @access public * @return WJUnloadManager **/ initialize: function(checker) { this._checker = checker || function() {return false;}; this.suspend(false); this._asking = false; Event.observe(window, "keydown", this.handleKeyUnload.bindAsEventListener(this) ); Event.observe(window, "beforeunload", this.handleUnload.bindAsEventListener(this) ); }, /** * handleUnload * * Handles the case where no keys were detected, but the page is about to unload * * @since Tue Feb 17 2009 * @access public * @param Event event * @return void **/ handleUnload: function(event) { if (!this._checker() && !this.isSuspended() ) { event.returnValue = this._getMessage(true); } }, /** * handleKeyUnload * * Handles the case where a user might unload the page because of a key (combination) * * @since Tue Feb 17 2009 * @access public * @param Event event * @return void **/ handleKeyUnload: function(event) { var modKs = (event.altKey ? 1 : 0) + (event.shiftKey ? 2 : 0) + (event.ctrlKey ? 4 : 0); var key = event.keyCode; if (!this._checker() && !this.isSuspended() ) { if ((modKs==4 || modKs==6) && key == 82) { // CTRL+R this._showMessage(this.doReload.bind(this) ); } if (modKs==1 && (key == Event.KEY_LEFT || key == Event.KEY_RIGHT) ) { // ALT + (LEFT|RIGHT) this._showMessage(this.doHistory.bind(this, ( (key == Event.KEY_LEFT) ? -1 : +1) ) ); } if ((modKs==0 || modKs==4) && key == 116) { // (CTRL+)F5 this._showMessage(this.doReload.bind(this) ); } /** * Other options might be * - CTRL+F4 * - ALT+F4 * - CTRL+W * - CTRL+SHIFT+W * * But it needs to be possible to reproduce them through script. For now they're handled by handleUnload **/ } if (this._asking) { return this._stop(event); } }, /** * _stop * * Stops the event * * @since Tue Feb 17 2009 * @access protected * @param Event event * @return boolean **/ _stop: function(event) { if (event.stopPropagation) { event.stopPropagation(); } event.stop(); event.returnValue = false; return false; }, /** * doReload * * Performs the actual reload (as requested by the user) * * @since Tue Feb 17 2009 * @access public * @param WJWindow wjwindow * @param Event event * @param boolean doReload * @return void **/ doReload: function(wjwindow, event, doReload) { if (doReload) { this.suspend(); document.location.reload(); } else { this._asking = false; } }, /** * doHistory * * Performs the actual history change (as requested by the user) * * @since Tue Feb 17 2009 * @access public * @param WJWindow wjwindow * @param Event event * @param integer direction * @param boolean doHistory * @return void **/ doHistory: function(direction, wjwindow, event, doHistory) { if (doHistory) { this.suspend(); window.history.go(direction); } else { this._asking = false; } }, /** * suspend * * Makes this class skip the observers * * @since Mon Feb 23 2009 * @access public * @param boolean doSuspend * @return void **/ suspend: function(doSuspend) { var doSuspend = (doSuspend != false); this._suspended = doSuspend; }, /** * isSuspended * * Tells if this class is suspended * * @since Mon Feb 23 2009 * @access public * @return boolean **/ isSuspended: function() { return this._suspended; }, /** * _showMessage * * Shows the message * * @since Tue Feb 17 2009 * @access protected * @param Function callback * @return void **/ _showMessage: function(callback) { if (!this._asking) { WJWindow.booleanConfirm(this._getMessage(false, true), callback, aeroplane.translateGui); this._asking = true; } }, /** * getMessage * * Returns the message to show to the user * * @since Tue Feb 17 2009 * @access protected * @param boolean useBrowserLang * @return string **/ _getMessage: function(useBrowserLang, full) { var useBrowserLang = (useBrowserLang === true); var full = (full === true); if (useBrowserLang) { var lang = this._getBrowserLanguage(); if (full) { return this._messages.body[lang] + "\n\n" + this._messages.question[lang]; } else { return this._messages.body[lang]; } } else { if (full) { // for now we use "might be" because this is not verified in any way return "Mogelijk zijn er nog niet opgeslagen gegevens."+ "\n\n" + "Weet je zeker dat u deze pagina wilt verlaten?"; } else { // for now we use "might be" because this is not verified in any way return "Mogelijk zijn er nog niet opgeslagen gegevens."; } return ; } }, /** * _getBrowserLanguage * * Returns the language used in this browser * * @since Tue Feb 17 2009 * @access protected * @return string **/ _getBrowserLanguage: function() { var lang = window.navigator["language"] || window.navigator["browserLanguage"]; switch (lang) { case "nl": case "nl-NL": case "nl_NL": case "nl-be": case "nl-BE": case "nl_BE": return "nl_NL"; default: return "default"; } }, /** * The various messages * * @since Tue Feb 17 2009 * @access protected * @var Object **/ _messages: { body: { // for now we use "might be" because this is not verified in any way nl_NL: "Mogelijk zijn er nog niet opgeslagen gegevens.", "default": "There might be unsaved data." }, question: { nl_NL: "Weet u zeker dat u deze pagina wilt verlaten?", "default": "Are you sure you want to navigate away?" } } });/** * WJImageloader loads any non existing image from the mediamanager * Allows creating images on a need-for-usage base, which is especially useful when using aeroplane in the cloud * Known NOT to work with Opera (tested working in IE6, IE7, IE8, FF3.5, FF3.6, Chrome) * * @since Fri Mar 19 2010 * @author Ron Rademaker **/ var WJImageloader = Class.create({ /** * initialize * * Creates a new WJImageloader and starts checking * * @since Fri Mar 19 2010 * @access public * @return WJImageloader **/ initialize: function() { this.images = $A(document.images); this.checkImages(); }, /** * checkImages * * Checks all images and loads any empty image from the mediamanager (empty means width and height are both 0) * Only attempts to load /images/thumbs images * Stops checking if all images are succesfully loaded * * @since Fri Mar 19 2010 * @access public * @return void **/ checkImages: function() { this.images.each(this._checkImage.bind(this, 10) ); // try max 10 times per image }, /** * checkImage * * Checks an individual image * * @since Fri Apr 2 2010 * @access protected * @param Image img * @return void **/ _checkImage: function(loop, img) { if (loop < 1) { return; } var done = true; if (!img.complete) { done = false; } if ( ( ("naturalHeight" in img) && (img.naturalHeight == 0) ) || ( (img.fileSize == -1) && (img.height > 0) ) ) { if (img.src.match(/\/images\/thumbs\//) && !(img.src.match(/orig_uri/) ) ) { img.src = "/index.php?ct=wmdynamic&module=Wmmediamanager&mode=thumbnail&orig_uri=" + img.src.replace(/https?:\/\/[^\/]*\//, "/"); } } if (!done) { loop = loop-1; this._checkImage.bind(this, loop, img).delay(0.5); } } }); /** * WJComponent * * Base Component class * * @since Wed Jul 16 2008 * @revision $Revision$ * @author Ron Rademaker * @package Windmill.Javascript.Component **/ var WJComponent = Class.create({ /** * Properties of WJComponent * * string id * string value * boolean disabled * boolean readonly * event focusEvent * event blurEvent * event changeEvent **/ /** * initialize * * Creates a new WJComponent * * @since * @access public * @param string id * @return **/ initialize: function(id) { this.id = id; this.value = null; this.componentType = "WJComponent"; this.components = new Array(); this.label = null; this.group = false; }, /** * setHtmlelement * * Sets the html element for this component * * @since Mon Jul 21 2008 * @access public * @param htmlelement element * @return void **/ setHtmlelement: function(element) { this.htmlelement = element; if (this.htmlelement.value) { this.value = this.htmlelement.value; } else if ($("hidden_" + this.htmlelement.id) ) { this.value = $("hidden_" + this.htmlelement.id).value; } }, /** * observe * * Adds an observer to this component's htmlelement * * @since Fri Nov 06 2009 * @access public * @param string event * @param function callback * @return void **/ observe: function(event, callback) { if (Object.isArray(this.htmlelement) ) { this.htmlelement.each(function(s) { s.observe(event, callback); }); } else if (this.htmlelement) { this.htmlelement.observe(event, callback); } }, /** * addComponent * * Adds a component to this component group * * @since Tue Aug 19 2008 * @access public * @param WJComponent comp * @return void **/ addComponent: function(comp) { WJDebugger.log(WJDebugger.DEBUG, "Adding component to " + this.componentType + " " + this.id, comp); this.components.push(comp); }, /** * getComponents * * Gets the components in this group * * @since Tue Aug 19 2008 * @access public * @return Array **/ getComponents: function() { return this.components; }, /** * valueChanged * * Returns true if the value of this component has changed * * @since Tue May 19 2009 * @access public * @return boolean **/ valueChanged: function() { var oldValue = this.value; this.getValue(); var changed = (oldValue == null && this.value == null) ? false : (oldValue != this.getValue() ); // extra null check is because null != null is true since null means unknown (and it is more likely that two unknowns would differ than that two unknowns are equal) this.value = oldValue; return changed; }, /** * getValue * * Gets the value of this component * * @since * @access public * @param boolean nochange * @return **/ getValue: function(nochange) { var usesDijit = (typeof(dijit) != "undefined") ? true : false; var nochange = nochange || false; var oldvalue = this.value; if (this.htmlelement && usesDijit && dijit.byId(this.htmlelement.id) && dijit.byId(this.htmlelement.id).getValue) { this.value = dijit.byId(this.htmlelement.id).attr("value"); // IE doesn't support getValue, FF doesn't (fully) support .value } else if (this.htmlelement && (this.htmlelement.value != null) ) { this.value = this.htmlelement.value; } if (nochange) { var newval = this.value; this.value = oldvalue; return newval; } else { return this.value; } }, /** * setValue * * Sets the value of this component * * @since Tue Nov 04 2008 * @access public * @return void **/ setValue: function(value) { var usesDijit = (typeof(dijit) != "undefined") ? true : false; this.value = value; if (this.htmlelement && usesDijit && dijit.byId(this.htmlelement.id) && dijit.byId(this.htmlelement.id).setValue) { dijit.byId(this.htmlelement.id).setValue(this.value); } else if (this.htmlelement && this.htmlelement.value) { this.htmlelement.value = this.value; } }, /** * getId * * Gets this component's id * * @since * @access public * @return **/ getId: function() { return this.id; }, /** * toString * * Gives a string representation of this component * * @since Tue Apr 14 2009 * @access public * @return string **/ toString: function() { if (this.componentType === null) { return "Uninitialized WJComponent"; } return this.componentType + " instance '" + this.id + "'"; } }); /** * WJText * * Textbox input component * * @since Wed Jul 16 2008 * @revision $Revision$ * @author Ron Rademaker * @package Windmill.Javascript.Component **/ var WJText = Class.create(WJComponent, { /** * initialize * * Initialize this WJText * * @since Mon Jul 28 2008 * @access public * @return void **/ initialize: function($super, id) { $super(id); this.componentType = "WJText"; } }); /** * WJPassword * * Textbox for password input * * @since Wed Jul 16 2008 * @revision $Revision$ * @author Ron Rademaker * @package Windmill.Javascript.Component **/ var WJPassword = Class.create(WJText, { /** * initialize * * Initialize this WJPassword * * @since Fri Aug 22 2008 * @access public * @return void **/ initialize: function($super, id) { $super(id); this.componentType = "WJPassword"; } }); /** * WJLabel * * A label, the text that is usually found near an input component. * * @since Wed Jul 16 2008 * @revision $Revision$ * @author Ron Rademaker * @package Windmill.Javascript.Component **/ WJLabel = Class.create(WJComponent, { /** * initialize * * Creates a new Label * * @since * @access public * @param string id * @param string text (default: null) * @param string image (default: null) * @return **/ initialize: function($super, id, text, image) { $super(id); this.componentType = "WJLabel", this.text = text; this.image = image; } }); /** * WJGroup * * A group of components * * @since Wed Jul 16 2008 * @revision $Revision$ * @author Ron Rademaker * @package Windmill.Javascript.Component **/ WJGroup = Class.create(WJComponent, { /** * initialize * * Initializes a new WJGroup * * @since Tue Aug 19 2008 * @access public * @param string id * @return void **/ initialize: function($super, id) { $super(id); this.componentType = "WJGroup"; this.region = "center"; this.group = true; }, /** * setRegion * * Sets the region where to show this group * * @since Wed Nov 12 2008 * @access public * @param string region * @return void **/ setRegion: function(region) { this.region = region; } }); /** * WJHtml * * A html component, used to be able to use contentblocks with components without contentpanes * * @since Mon Jan 19 2009 * @revision $Revision$ * @author Ron Rademaker * @package Windmill.Javascript.Component **/ var WJHtml = Class.create(WJGroup, { /** * initialize * * Initialize this WJHtml * * @since Mon Jan 19 2009 * @access public * @return WJHtml **/ initialize: function($super, id) { $super(id); this.componentType = "WJHtml"; this.group = 0; // WJHtml has a lot of group properties but it isn't really a group (like WJLink). This makes sure it isn't treated as a group on the XSL level. } }); /** * class WJWindow * * The base window class * * @since Fri Jun 27 2008 * @revision $Revision$ * @author Giso Stallenberg * @package Windmill.Javascript.Aeroplane **/ var WJWindow = Class.create({ /** * Properties of Window * * string _title * string _type * DOMElement _content * mixed _contenttype * Function _callbackFunction * boolean _visible * integer _x * integer _y * integer _z * integer _w * integer _h **/ DEFAULT_PARENT: document.body, /** * initialize * * Creates a new WJWindow * * @since Fri Jun 27 2008 * @access public * @param Function callback * @param DOMElement parent (default: document.body) * @return WJWindow **/ initialize: function(callback, parent, translate) { this._loading = false; this._basetitle = this._title = ""; this._theme = "default"; this._parent = parent || WJWindow.DEFAULT_PARENT || document.body; this._listeners = new Hash(); this.translate = translate || this.translate; this._createWindow(); this._addDefaultListeners(); this._addCloseButton(); this.setCallback(callback); this.setBaseTitle(WJGuiSettings.windowBaseTitle); }, /** * _createWindow * * Creates a new window DOMElement * * @since Fri Jun 27 2008 * @access protected * @return void **/ _createWindow: function() { var classname = this._getBaseClassname(); this._windowElement = new Element("div"); this._windowElement.addClassName(classname); this._windowElement.setStyle({"display": "none"}); this._createWindowRows(["title", "main", "buttons", "bottom"], classname); this._windowElementId = this._windowElement.identify(); this._parent.insert(this._windowElement); this._absolutizeTopLeft(); this.hide(); this._outerElement = this._windowElement; this.setTheme(); }, /** * insertWindowRowBefore * * Inserts a new row before given rowname with name newrowname * * @since Tue Sep 23 2008 * @access public * @param string rowname * @param string newrowname * @return DOMElement **/ insertWindowRowBefore: function(rowname, newrowname) { if (rowname === "title") { return; } var classname = this._getBaseClassname(); var row = this._windowElement.select("." + classname + "_" + rowname) row = row.first(); var newrowhtml = this._createRow(newrowname, classname, " " + classname + "_body"); var div = new Element("div"); div.update(newrowhtml); var toprow = row.parentNode; var newrow = toprow.insertBefore(div.firstChild, row ); newrow = Element.extend(newrow); newrow = newrow.select("." + classname + "_content"); this._contentElements[newrowname] = newrow.first(); return newrow; }, /** * replaceWindowRow * * Replaces windowrow old with new, keeps references to old alive (they'll return the new rows) * Returns the removed row * * @since Thu Feb 12 2009 * @access public * @param string oldrow * @param string newrow * @return htmlelement **/ replaceWindowRow: function(oldrow, newrow) { var inserted = this.insertWindowRowBefore(oldrow, newrow); var toremove = this.getContentElement(oldrow); this._contentElements[oldrow] = this._contentElements[newrow]; return toremove.remove(); }, /** * removeWindowRow * * Removes windowrow * Returns the removed row * * @since Tue Dec 8 2009 * @access public * @param string oldrow * @return htmlelement **/ removeWindowRow: function(oldrow) { var toremove = this.getContentElement(oldrow); delete(this._contentElements[oldrow]); return toremove.remove(); }, /** * _addCloseButton * * Adds a button to close the window * * @since Mon Jul 7 2008 * @access protected * @return void **/ _addCloseButton: function() { var title = this.getContentElement("title"); var titlediv = new Element("div", {"onclick": "this.parentNode.getWJWindowObject().fireClose(this)", "title": this.translate("CLOSE_WINDOW") } ); titlediv.addClassName(this._getBaseClassname() + "_closebutton"); title.insert(titlediv); }, /** * fireClose * * Fires the close event from the given element * * @since Thu Oct 16 2008 * @access public * @param Element element * @return void **/ fireClose: function(element) { element = $(element); /* Observe once function */ var func = function() { this.destroy(); Event.stopObserving(document, "wjgui:close", arguments.callee.observerFunction); } var bound = func.bindAsEventListener(this); func.observerFunction = bound; /* End observe once function */ Event.observe(document, "wjgui:close", bound); element.fire("wjgui:close"); Event.stopObserving.defer(document, "wjgui:close", bound); }, /** * _addDefaultListeners * * Adds custom event listeners to the window * * @since Mon Jul 7 2008 * @access protected * @return void **/ _addDefaultListeners: function(element) { this.addListener("true", this.windowResult.bindAsEventListener(this, true) ); this.addListener("false", this.windowResult.bindAsEventListener(this, false) ); this.addListener("close", this.windowResult.bindAsEventListener(this, false) ); this.addListener("save", this.windowResult.bindAsEventListener(this) ); this.addListener("delete", this.windowResult.bindAsEventListener(this) ); this.addListener("cancel", this.windowResult.bindAsEventListener(this) ); this._addDefaultKeyListener(); }, /** * _addDefaultKeyListener * * Adds a listener for key's like return and esc * * @since Fri Sep 5 2008 * @access protected * @return void **/ _addDefaultKeyListener: function() { // here for extending purposes only var element = element || this._windowElement; Event.observe(element, "keydown", this.keyHandle.bindAsEventListener(this) ); }, /** * keyHandle * * Handles pressing enter or esc * * @since Fri Sep 5 2008 * @access public * @param Event event * @return void **/ keyHandle: function(event) { var element = event.element(); if (Object.isElement(element.up(".wjgui_window") ) ) { switch (event.keyCode) { case Event.KEY_RETURN: if (this.isVisible() ) { element.fire("wjgui:true"); } break; case Event.KEY_ESC: if (this.isVisible() ) { element.fire("wjgui:close"); } break; default: return; } } }, /** * addListener * * Adds a listener for a custom event that calls the given callback or the default callback of this window * * @since Tue Aug 12 2008 * @access * @param * @return WJWindow **/ addListener: function(eventName, callback, element) { WJDebugger.log(WJDebugger.INFO, "Adding listener in WJWindow", eventName, callback); var callback = callback || this.windowResult.bindAsEventListener(this); var element = element || this._windowElement; Event.observe(element, "wjgui:" + eventName, callback); this._setListener(eventName, {"element": element, "callback": callback} ); return this; }, /** * _setListener * * Registers a listener function * * @since Wed Jul 9 2008 * @access public * @param string key * @param Object elementAndCallback * @return void **/ _setListener: function(key, elementAndCallback) { this._listeners.set(key, elementAndCallback); }, /** * removeListener * * Removes the listener set for key * * @since Tue Aug 12 2008 * @access * @param * @return WJWindow **/ removeListener: function(key) { var listener = this.getListener(key); Event.stopObserving(listener.element, "wjgui:" + key, listener.callback); this._listeners.unset(key); return this; }, /** * removeListeners * * Removes all listeners * * @since Tue Aug 12 2008 * @access public * @return WJWindow **/ removeListeners: function() { this._listeners.each(function(info) { this.removeListener(info.key); }.bind(this) ); return this; }, /** * windowResult * * Handles the window result event * * @since Wed Jul 9 2008 * @access protected * @param Event event * @return void **/ windowResult: function(event) { this._callback.apply(this, arguments); }, /** * getListeners * * Returns the listeners hash * * @since Mon Jul 7 2008 * @access public * @return Hash **/ getListeners: function() { return this._listeners; }, /** * getListener * * Returns the listener info set for key * * @since Tue Aug 12 2008 * @access * @param * @return **/ getListener: function(key) { return this._listeners.get(key); }, /** * _getBaseClassname * * Returns the base classname used for windows * * @since Fri Jun 27 2008 * @access protected * @return string **/ _getBaseClassname: function() { return "wjgui_window"; }, /** * _getWindowRowTemplate * * Returns a template that can be used to create rows in windows * * @since Fri Jun 27 2008 * @access protected * @return Template **/ _getWindowRowTemplate: function() { return new Template("