/** * eGroupware JavaScript Framework * * @link http://www.egroupware.org * @author Andreas Stoeckel * @version $Id$ */ /** * Class: egw_fw * The egw_fw class is the base framework class. It wraps around all egw_fw_ui and * egw_fw_classes. It creates both, a side bar and a tab area and cares about linking. */ /** * The constructor of the egw_fw class. * * @param string _sidemenuId specifies the name of the div container which should contain the sidebar menu * @param string _tabsId specifies the name of the div container which should cotain the tab area * @param string _webserverUrl specifies the egroupware root url */ function egw_fw(_sidemenuId, _tabsId, _splitterId, _webserverUrl, _sideboxSizeCallback, _sideboxStartSize) { /* Get the base div */ this.sidemenuDiv = document.getElementById(_sidemenuId); this.tabsDiv = document.getElementById(_tabsId); this.splitterDiv = document.getElementById(_splitterId); this.webserverUrl = _webserverUrl; this.sideboxSizeCallback = _sideboxSizeCallback; window.egw_webserverUrl = _webserverUrl; this.sidemenuUi = null; this.tabsUi = null; this.categoryOpenCache = new Object(); this.applications = new Object(); this.activeApp = null; if (this.sidemenuDiv && this.tabsDiv && this.splitterDiv) { //Wrap a scroll area handler around the applications this.scrollAreaUi = new egw_fw_ui_scrollarea(this.sidemenuDiv); //Create the sidemenu, the tabs area and the splitter this.sidemenuUi = new egw_fw_ui_sidemenu(this.scrollAreaUi.contentDiv, this.sortCallback); this.tabsUi = new egw_fw_ui_tabs(this.tabsDiv); this.splitterUi = new egw_fw_ui_splitter(this.splitterDiv, EGW_SPLITTER_VERTICAL, this.splitterResize, [ { "size": _sideboxStartSize, "minsize": 225, "maxsize": 0 }, ], this); this.loadApplications("home.jdots_framework.ajax_navbar_apps"); } _sideboxSizeCallback(_sideboxStartSize); //Register the resize handler $(window).resize(function(){window.framework.resizeHandler()}); //Register the global alert handler window.egw_alertHandler = this.alertHandler; //Register the key press handler //$(document).keypress(this.keyPressHandler); //Override the old egw_openWindowCentered2 window.egw_openWindowCentered2 = this.egw_openWindowCentered2; //Override the app_window function window.egw_appWindow = this.egw_appWindow; } egw_fw.prototype.alertHandler = function(_message, _details) { alert('Error:\n ' + _message + '\n\nDetails:\n ' + _details); } /** * Function called whenever F1 is pressed inside the framework * @returns boolean true if the call manual function could be called, false if the manual is not available */ egw_fw.prototype.f1Handler = function() { if (typeof window.callManual != 'undefined') { window.callManual(); return true; } return false; } /** * Function called whenever a key is pressed * @param object event describes the key press event */ egw_fw.prototype.keyPressHandler = function(event) { switch (event.keyCode) { case 112: //F1 { event.preventDefault(); framework.f1Handler(); } } } /** * Sets the active framework application to the application specified by _app */ egw_fw.prototype.setActiveApp = function(_app) { //Only perform the following commands if a new application is activated if (_app != this.activeApp) { this.activeApp = _app; //Set the sidebox width if a application specific sidebox width is set if (_app.sideboxWidth !== false) { this.sideboxSizeCallback(_app.sideboxWidth); this.splitterUi.constraints[0].size = _app.sideboxWidth; } //Open the sidemenuUi that belongs to the app, if no sidemenu is attached //to the app, close the sidemenuUi if (_app.sidemenuEntry) { if (_app.hasSideboxMenuContent) { this.sidemenuUi.open(_app.sidemenuEntry); } } else { this.sidemenuUi.open(null); } //Set the website title if (_app.website_title) { document.title = _app.website_title; } //Show the application tab if (_app.tab) { this.tabsUi.showTab(_app.tab); } //Resize the scroll area... this.scrollAreaUi.update(); //...and scroll to the top this.scrollAreaUi.setScrollPos(0); } } /** * Function called whenever the sidemenu entries are sorted */ egw_fw.prototype.sortCallback = function(_entriesArray) { //Create an array with the names of the applications in their sort order var name_array = new Array(); for (var i = 0; i < _entriesArray.length; i++) { name_array.push(_entriesArray[i].tag.appName); } //Send the sort order to the server via ajax var req = new egw_json_request('home.jdots_framework.ajax_appsort', [name_array]); req.sendRequest(true); } /** * Function called whenever the sidebox is resized */ egw_fw.prototype.splitterResize = function(_width) { if (this.tag.activeApp) { app_name = this.tag.activeApp.appName; var req = new egw_json_request(app_name + '.jdots_framework.ajax_sideboxwidth', [app_name, _width]); req.sendRequest(true); //If there are no global application width values, set the sidebox width of //the application every time the splitter is resized if (this.tag.activeApp.sideboxWidth !== false) { this.tag.activeApp.sideboxWidth = _width; } } this.tag.sideboxSizeCallback(_width); } /** * tabCloseClickCallback is used internally by egw_fw in order to handle clicks * on the close button of every tab. * * @param egw_fw_ui_tab _sender specifies the tab ui object, the user has clicked */ egw_fw.prototype.tabCloseClickCallback = function(_sender) { //Save references to the application and the tabsUi as "this" will be deleted var app = this.tag; var tabsUi = this.parent; //At least one tab must stay open if (tabsUi.tabs.length > 1) { tabsUi.removeTab(this); app.tab = null; app.iframe = null; //Set the active application to the application of the currently active tab app.parentFw.setActiveApp(tabsUi.activeTab.tag); } tabsUi.setCloseable(tabsUi.tabs.length > 1); /* As a new tab might remove a row from the tab header, we have to resize all iframes */ this.tag.parentFw.resizeHandler(); } egw_fw.prototype.resizeHandler = function() { for (var app in this.applications) { if (this.applications[app].iframe != null) { this.applications[app].iframe.style.height = this.getIFrameHeight() + 'px'; } this.scrollAreaUi.update(); } } egw_fw.prototype.getIFrameHeight = function() { var height = $(window).height() - (this.tabsUi.contHeaderDiv.offsetTop + this.tabsUi.contHeaderDiv.offsetHeight + 30); /* 30 is the height of the footer */ return height; } /** * tabClickCallback is used internally by egw_fw in order to handle clicks on * a tab. * * @param egw_fw_ui_tab _sender specifies the tab ui object, the user has clicked */ egw_fw.prototype.tabClickCallback = function(_sender) { //Set the active application in the framework this.tag.parentFw.setActiveApp(this.tag); } /** * applicationClickCallback is used internally by egw_fw in order to handle clicks on * an application in the sidebox menu. * * @param egw_fw_ui_tab _sender specifies the tab ui object, the user has clicked */ egw_fw.prototype.applicationClickCallback = function(_sender) { this.tag.parentFw.applicationTabNavigate(this.tag, this.tag.execName); } /** * navigate to tab of an applications (opening the tab if not yet open) * * @param egw_fw_class_application _app * @param string _url optional url, default index page of app */ egw_fw.prototype.applicationTabNavigate = function(_app, _url) { //Create the tab if it isn't already there if ((_app.iframe == null) || (_app.tab == null)) { _app.tab = this.tabsUi.addTab(_app.icon, this.tabClickCallback, this.tabCloseClickCallback, _app); _app.tab.setTitle(_app.displayName); _app.iframe = document.createElement('iframe'); _app.iframe.style.width = "100%"; _app.iframe.style.borderWidth = 0; _app.iframe.style.height = this.getIFrameHeight() + 'px'; _app.iframe.frameBorder = 0; _app.tab.setContent(_app.iframe); this.tabsUi.setCloseable(this.tabsUi.tabs.length > 1); /* As a new tab might add a new row in the tab header, we have to resize all iframes */ this.resizeHandler(); } //Set the iframe location _app.iframe.src = typeof(_url) == "undefined" ? _app.execName : _url; _app.parentFw.setActiveApp(_app); } /** * loadApplicationsCallback is internally used by egw_fw in order to handle the * receiving of the application list. * * @param object apps contains the parsed JSON data describing the applications. * The JSON object should have the following structure * apps = array[ * { * string name (the internal name of the application) * string title (the name of the application how it should be viewed) * string icon (path to the icon of the application) * string url (path to the application) //TODO: Change this * [boolean isDefault] (whether this entry is the default entry which should be opened) * } * ] */ egw_fw.prototype.loadApplicationsCallback = function(apps) { var defaultApp = null; //Iterate through the application array returned for (var i = 0; i < apps.length; i++) { var app = apps[i]; appData = new egw_fw_class_application(this, app.name, app.title, app.icon, app.url, app.sideboxwidth); //Create a sidebox menu entry for each application if (!app.noNavbar) { appData.sidemenuEntry = this.sidemenuUi.addEntry( appData.displayName, appData.icon, this.applicationClickCallback, appData); } //If this entry is the default entry, show it using the click callback if (app.isDefault && (app.isDefault === true)) { defaultApp = appData; } this.applications[appData.appName] = appData; } // check if a menuaction or app is specified in the url --> display that var matches = location.search.match(/menuaction=([a-z0-9_-]+)\./i); var _app,_url; if (matches && (_app = this.getApplicationByName(matches[1])) || (matches = location.href.match(/\/([^\/]+)\/[^\/]+\.php/i)) && (_app = this.getApplicationByName(matches[1]))) { _url = window.location.href.replace(/&?cd=yes/,''); this.applicationTabNavigate(_app,_url); } // else display the default application else if (defaultApp) { this.applicationTabNavigate(defaultApp); } this.scrollAreaUi.update(); } /** * loadApplications refreshes the list of applications. Upon calling, all existing applications * will be deleted from the list, and all open tabs will be closed. Then an AJAX request to the * given URL will be send in order to obtain the application list with JSON encoding. * * @param string _menuaction specifies the menuaction */ egw_fw.prototype.loadApplications = function(_menuaction) { //Close all open tabs, remove all applications from the application list this.sidemenuUi.clean(); this.tabsUi.clean(); //Perform an AJAX request loading all available applications var req = new egw_json_request(_menuaction) req.sendRequest(true, this.loadApplicationsCallback, this); } /** * Goes through all applications and returns the application with the specified name. * @param string _name the name of the application which should be returned. * @return object or null if application is not found. */ egw_fw.prototype.getApplicationByName = function(_name) { if (typeof this.applications[_name] != 'undefined') { return this.applications[_name] } return null; } /** * Seperates all script tags from the given html code and returns the seperately * @param object _html object that the html code from which the script should be seperated. The html code has to be stored in _html.html, the result js will be written to _html.js */ egw_fw.prototype.seperateJavaScript = function(_html) { var html = _html.html; var in_pos = html.search(/ tag */ var js_str = html.substring(in_pos, out_pos+9); /*Remove the initial tag */ /*js_str = js_str.substring(js_str.search(/>/) + 1);*/ _html.js += js_str; html = html.substring(0, in_pos - 1) + html.substring(out_pos + 9); var in_pos = html.search(/