| Conditions | 1 |
| Paths | 2304 |
| Total Lines | 445 |
| Code Lines | 178 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | /** |
||
| 24 | (function(window) |
||
| 25 | { |
||
| 26 | "use strict"; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * |
||
| 30 | * @type @exp;fw_ui_sidemenu_entry@call;extend |
||
| 31 | */ |
||
| 32 | var desktop_ui_sidemenu_entry = fw_ui_sidemenu_entry.extend({ |
||
| 33 | |||
| 34 | /** |
||
| 35 | * Override fw_ui_sidemenu_entry class constructor |
||
| 36 | * |
||
| 37 | * @returns {undefined} |
||
| 38 | */ |
||
| 39 | init: function() |
||
| 40 | { |
||
| 41 | this._super.apply(this,arguments); |
||
| 42 | |||
| 43 | this.setBottomLine(this.parent.entries); |
||
| 44 | //Make the base Div sortable. Set all elements with the style "egw_fw_ui_sidemenu_entry_header" |
||
| 45 | //as handle |
||
| 46 | if(jQuery(this.elemDiv).data('uiSortable')) |
||
| 47 | { |
||
| 48 | jQuery(this.elemDiv).sortable("destroy"); |
||
| 49 | } |
||
| 50 | jQuery(this.elemDiv).sortable({ |
||
| 51 | handle: ".egw_fw_ui_sidemenu_entry_header", |
||
| 52 | distance: 15, |
||
| 53 | start: function(event, ui) |
||
| 54 | { |
||
| 55 | var parent = ui.item.context._parent; |
||
| 56 | parent.isDraged = true; |
||
| 57 | parent.parent.startDrag.call(parent.parent); |
||
| 58 | }, |
||
| 59 | stop: function(event, ui) |
||
| 60 | { |
||
| 61 | var parent = ui.item.context._parent; |
||
| 62 | parent.parent.stopDrag.call(parent.parent); |
||
| 63 | parent.parent.refreshSort.call(parent.parent); |
||
| 64 | }, |
||
| 65 | opacity: 0.7, |
||
| 66 | axis: 'y' |
||
| 67 | }); |
||
| 68 | }, |
||
| 69 | |||
| 70 | /** |
||
| 71 | * setBottomLine marks this element as the bottom element in the application list. |
||
| 72 | * This adds the egw_fw_ui_sidemenu_entry_content_bottom/egw_fw_ui_sidemenu_entry_header_bottom CSS classes |
||
| 73 | * which should care about adding an closing bottom line to the sidemenu. These classes are removed from |
||
| 74 | * all other entries in the side menu. |
||
| 75 | * @param {type} _entryList is a reference to the list which contains the sidemenu_entry entries. |
||
| 76 | */ |
||
| 77 | setBottomLine: function(_entryList) |
||
| 78 | { |
||
| 79 | //If this is the last tab in the tab list, the bottom line must be closed |
||
| 80 | for (var i = 0; i < _entryList.length; i++) |
||
| 81 | { |
||
| 82 | jQuery(_entryList[i].contentDiv).removeClass("egw_fw_ui_sidemenu_entry_content_bottom"); |
||
| 83 | jQuery(_entryList[i].headerDiv).removeClass("egw_fw_ui_sidemenu_entry_header_bottom"); |
||
| 84 | } |
||
| 85 | jQuery(this.contentDiv).addClass("egw_fw_ui_sidemenu_entry_content_bottom"); |
||
| 86 | jQuery(this.headerDiv).addClass("egw_fw_ui_sidemenu_entry_header_bottom"); |
||
| 87 | } |
||
| 88 | }); |
||
| 89 | |||
| 90 | /** |
||
| 91 | * |
||
| 92 | * @type @exp;fw_ui_sidemenu@call;extend |
||
| 93 | */ |
||
| 94 | var desktop_ui_sidemenu = fw_ui_sidemenu.extend( |
||
| 95 | { |
||
| 96 | init: function(_baseDiv, _sortCallback) |
||
| 97 | { |
||
| 98 | this._super.apply(this,arguments); |
||
| 99 | this.sortCallback = _sortCallback; |
||
| 100 | }, |
||
| 101 | /** |
||
| 102 | * |
||
| 103 | * @returns {undefined} |
||
| 104 | */ |
||
| 105 | startDrag: function() |
||
| 106 | { |
||
| 107 | if (this.activeEntry) |
||
| 108 | { |
||
| 109 | jQuery(this.activeEntry.marker).show(); |
||
| 110 | jQuery(this.elemDiv).sortable("refresh"); |
||
| 111 | } |
||
| 112 | }, |
||
| 113 | |||
| 114 | /** |
||
| 115 | * |
||
| 116 | * @returns {undefined} |
||
| 117 | */ |
||
| 118 | stopDrag: function() |
||
| 119 | { |
||
| 120 | if (this.activeEntry) |
||
| 121 | { |
||
| 122 | jQuery(this.activeEntry.marker).hide(); |
||
| 123 | jQuery(this.elemDiv).sortable("refresh"); |
||
| 124 | } |
||
| 125 | }, |
||
| 126 | |||
| 127 | /** |
||
| 128 | * Called by the sidemenu elements whenever they were sorted. An array containing |
||
| 129 | * the sidemenu_entries ui-objects is generated and passed to the sort callback |
||
| 130 | */ |
||
| 131 | refreshSort: function() |
||
| 132 | { |
||
| 133 | //Step through all children of elemDiv and add all markers to the result array |
||
| 134 | var resultArray = new Array(); |
||
| 135 | this._searchMarkers(resultArray, this.elemDiv.childNodes); |
||
| 136 | |||
| 137 | //Call the sort callback with the array containing the sidemenu_entries |
||
| 138 | this.sortCallback(resultArray); |
||
| 139 | }, |
||
| 140 | |||
| 141 | /** |
||
| 142 | * Adds an entry to the sidemenu. |
||
| 143 | * @param {type} _name specifies the title of the new sidemenu entry |
||
| 144 | * @param {type} _icon specifies the icon displayed aside the title |
||
| 145 | * @param {type} _callback specifies the function which should be called when a callback is clicked |
||
| 146 | * @param {type} _tag extra data |
||
| 147 | * @param {type} _app application name |
||
| 148 | * |
||
| 149 | * @returns {desktop_ui_sidemenu_entry} |
||
| 150 | */ |
||
| 151 | addEntry: function(_name, _icon, _callback, _tag, _app) |
||
| 152 | { |
||
| 153 | //Create a new sidemenu entry and add it to the list |
||
| 154 | var entry = new desktop_ui_sidemenu_entry(this, this.baseDiv, this.elemDiv, _name, _icon, |
||
| 155 | _callback, _tag, _app); |
||
| 156 | this.entries[this.entries.length] = entry; |
||
| 157 | |||
| 158 | return entry; |
||
| 159 | } |
||
| 160 | }); |
||
| 161 | |||
| 162 | /** |
||
| 163 | * jdots framework object defenition |
||
| 164 | * here we can add framework methods and also override fw_base methods if it is neccessary |
||
| 165 | * @type @exp;fw_base@call;extend |
||
| 166 | */ |
||
| 167 | window.fw_desktop = fw_base.extend({ |
||
| 168 | /** |
||
| 169 | * jdots framework constructor |
||
| 170 | * |
||
| 171 | * @param {string} _sidemenuId sidebar menu div id |
||
| 172 | * @param {string} _tabsId tab area div id |
||
| 173 | * @param {string} _splitterId splitter div id |
||
| 174 | * @param {string} _webserverUrl specifies the egroupware root url |
||
| 175 | * @param {function} _sideboxSizeCallback |
||
| 176 | * @param {int} _sideboxStartSize sidebox start size |
||
| 177 | * @param {int} _sideboxMinSize sidebox minimum size |
||
| 178 | */ |
||
| 179 | init:function (_sidemenuId, _tabsId, _webserverUrl, _sideboxSizeCallback, _splitterId, _sideboxStartSize, _sideboxMinSize) |
||
| 180 | { |
||
| 181 | // call fw_base constructor, in order to build basic DOM elements |
||
| 182 | this._super.apply(this,arguments); |
||
| 183 | |||
| 184 | this.splitterDiv = document.getElementById(_splitterId); |
||
| 185 | if (this.sidemenuDiv && this.tabsDiv && this.splitterDiv) |
||
| 186 | { |
||
| 187 | //Wrap a scroll area handler around the applications |
||
| 188 | this.scrollAreaUi = new egw_fw_ui_scrollarea(this.sidemenuDiv); |
||
| 189 | |||
| 190 | // Create toggleSidebar menu |
||
| 191 | this.toggleSidebarUi = new egw_fw_ui_toggleSidebar('#egw_fw_basecontainer', this._toggleSidebarCallback,this); |
||
| 192 | |||
| 193 | //Create the sidemenu, the tabs area and the splitter |
||
| 194 | this.sidemenuUi = new desktop_ui_sidemenu(this.scrollAreaUi.contentDiv, |
||
| 195 | this.sortCallback); |
||
| 196 | this.tabsUi = new egw_fw_ui_tabs(this.tabsDiv); |
||
| 197 | this.splitterUi = new egw_fw_ui_splitter(this.splitterDiv, |
||
| 198 | EGW_SPLITTER_VERTICAL, this.splitterResize, |
||
| 199 | [ |
||
| 200 | { |
||
| 201 | "size": _sideboxStartSize, |
||
| 202 | "minsize": _sideboxMinSize, |
||
| 203 | "maxsize": screen.availWidth - 50 |
||
| 204 | } |
||
| 205 | ], this); |
||
| 206 | |||
| 207 | var egw_script = document.getElementById('egw_script_id'); |
||
| 208 | var apps = egw_script ? egw_script.getAttribute('data-navbar-apps') : null; |
||
| 209 | this.loadApplications(JSON.parse(apps)); |
||
| 210 | } |
||
| 211 | |||
| 212 | _sideboxSizeCallback(_sideboxStartSize); |
||
| 213 | |||
| 214 | // warn user about using IE not compatibilities |
||
| 215 | // we need to wait until common translations are loaded |
||
| 216 | egw.langRequireApp(window, 'common', function() |
||
| 217 | { |
||
| 218 | if (navigator && navigator.userAgent.match(/Trident|msie/ig)) |
||
| 219 | { |
||
| 220 | egw.message(egw.lang('Browser %1 %2 is not recommended. You may experience issues and not working features. Please use the latest version of Chrome, Firefox or Edge. Thank You!', 'IE',''), 'info', 'browser:ie:warning'); |
||
| 221 | } |
||
| 222 | }); |
||
| 223 | }, |
||
| 224 | |||
| 225 | /** |
||
| 226 | * |
||
| 227 | * @param {array} apps |
||
| 228 | */ |
||
| 229 | loadApplications: function (apps) |
||
| 230 | { |
||
| 231 | var restore = this._super.apply(this, arguments); |
||
| 232 | |||
| 233 | //Generate an array with all tabs which shall be restored sorted in by |
||
| 234 | //their active state |
||
| 235 | |||
| 236 | //Fill in the sorted_restore array... |
||
| 237 | var sorted_restore = []; |
||
| 238 | for (this.appName in restore) |
||
| 239 | sorted_restore[sorted_restore.length] = restore[this.appName]; |
||
| 240 | |||
| 241 | //...and sort it |
||
| 242 | sorted_restore.sort(function (a, b) { |
||
| 243 | return ((a.active < b.active) ? 1 : ((a.active == b.active) ? 0 : -1)); |
||
| 244 | }); |
||
| 245 | |||
| 246 | //Now actually restore the tabs by passing the application, the url, whether |
||
| 247 | //this is an legacyApp (null triggers the application default), whether the |
||
| 248 | //application is hidden (only the active tab is shown) and its position |
||
| 249 | //in the tab list. |
||
| 250 | for (var i = 0; i < sorted_restore.length; i++) |
||
| 251 | this.applicationTabNavigate( |
||
| 252 | sorted_restore[i].app, sorted_restore[i].url, i != 0, |
||
| 253 | sorted_restore[i].position, sorted_restore[i]['status']); |
||
| 254 | |||
| 255 | //Set the current state of the tabs and activate TabChangeNotification. |
||
| 256 | this.serializedTabState = egw.jsonEncode(this.assembleTabList()); |
||
| 257 | this.notifyTabChangeEnabled = true; |
||
| 258 | |||
| 259 | this.scrollAreaUi.update(); |
||
| 260 | // Disable loader, if present |
||
| 261 | jQuery('#egw_fw_loading').hide(); |
||
| 262 | |||
| 263 | }, |
||
| 264 | |||
| 265 | /** |
||
| 266 | * |
||
| 267 | * @param {type} _app |
||
| 268 | * @returns {undefined} |
||
| 269 | */ |
||
| 270 | setActiveApp: function(_app) |
||
| 271 | { |
||
| 272 | var result = this._super.apply(this, arguments); |
||
| 273 | |||
| 274 | if (_app == _app.parentFw.activeApp) |
||
| 275 | { |
||
| 276 | //Set the sidebox width if a application specific sidebox width is set |
||
| 277 | // do not trigger resize if the sidebar is already in toggle on mode and |
||
| 278 | // the next set state is the same |
||
| 279 | if (_app.sideboxWidth !== false && egw.preference('toggleSidebar',_app.appName) == 'off') |
||
| 280 | { |
||
| 281 | this.sideboxSizeCallback(_app.sideboxWidth); |
||
| 282 | this.splitterUi.constraints[0].size = _app.sideboxWidth; |
||
| 283 | } |
||
| 284 | _app.parentFw.scrollAreaUi.update(); |
||
| 285 | _app.parentFw.scrollAreaUi.setScrollPos(0); |
||
| 286 | } |
||
| 287 | //Resize the scroll area... |
||
| 288 | this.scrollAreaUi.update(); |
||
| 289 | |||
| 290 | //...and scroll to the top |
||
| 291 | this.scrollAreaUi.setScrollPos(0); |
||
| 292 | |||
| 293 | // Handles toggleSidebar initialization |
||
| 294 | if (typeof framework != 'undefined') |
||
| 295 | { |
||
| 296 | framework.getToggleSidebarState(); |
||
| 297 | framework.activeApp.browser.callResizeHandler(); |
||
| 298 | } |
||
| 299 | |||
| 300 | return result; |
||
| 301 | }, |
||
| 302 | |||
| 303 | /** |
||
| 304 | * Function called whenever the sidemenu entries are sorted |
||
| 305 | * @param {type} _entriesArray |
||
| 306 | */ |
||
| 307 | sortCallback: function(_entriesArray) |
||
| 308 | { |
||
| 309 | //Create an array with the names of the applications in their sort order |
||
| 310 | var name_array = []; |
||
| 311 | for (var i = 0; i < _entriesArray.length; i++) |
||
| 312 | { |
||
| 313 | name_array.push(_entriesArray[i].tag.appName); |
||
| 314 | } |
||
| 315 | |||
| 316 | //Send the sort order to the server via ajax |
||
| 317 | var req = egw.jsonq('EGroupware\\Api\\Framework\\Ajax::ajax_appsort', [name_array]); |
||
| 318 | }, |
||
| 319 | |||
| 320 | /** |
||
| 321 | * Splitter resize callback |
||
| 322 | * @param {type} _width |
||
| 323 | * @param {string} _toggleMode if mode is "toggle" then resize happens without changing splitter preference |
||
| 324 | * @returns {undefined} |
||
| 325 | */ |
||
| 326 | splitterResize: function(_width, _toggleMode) |
||
| 327 | { |
||
| 328 | if (this.tag.activeApp) |
||
| 329 | { |
||
| 330 | |||
| 331 | if (_toggleMode !== "toggle") |
||
| 332 | { |
||
| 333 | egw.set_preference(this.tag.activeApp.internalName, 'jdotssideboxwidth', _width); |
||
| 334 | |||
| 335 | //If there are no global application width values, set the sidebox width of |
||
| 336 | //the application every time the splitter is resized |
||
| 337 | if (this.tag.activeApp.sideboxWidth !== false) |
||
| 338 | { |
||
| 339 | this.tag.activeApp.sideboxWidth = _width; |
||
| 340 | } |
||
| 341 | } |
||
| 342 | } |
||
| 343 | this.tag.sideboxSizeCallback(_width); |
||
| 344 | |||
| 345 | // Notify app about change |
||
| 346 | if(this.tag.activeApp && this.tag.activeApp.browser != null) |
||
| 347 | { |
||
| 348 | this.tag.activeApp.browser.callResizeHandler(); |
||
| 349 | } |
||
| 350 | }, |
||
| 351 | |||
| 352 | /** |
||
| 353 | * |
||
| 354 | */ |
||
| 355 | resizeHandler: function() |
||
| 356 | { |
||
| 357 | // Tabs overflow needs to be checked again |
||
| 358 | this.checkTabOverflow(); |
||
| 359 | //Resize the browser area of the applications |
||
| 360 | for (var app in this.applications) |
||
| 361 | { |
||
| 362 | if (this.applications[app].browser != null) |
||
| 363 | { |
||
| 364 | this.applications[app].browser.resize(); |
||
| 365 | } |
||
| 366 | } |
||
| 367 | //Update the scroll area |
||
| 368 | this.scrollAreaUi.update(); |
||
| 369 | }, |
||
| 370 | /** |
||
| 371 | * Sets the sidebox data of an application |
||
| 372 | * @param {object} _app the application whose sidebox content should be set. |
||
| 373 | * @param {object} _data an array/object containing the data of the sidebox content |
||
| 374 | * @param {string} _md5 an md5 hash of the sidebox menu content: Only if this hash differs between two setSidebox calles, the sidebox menu will be updated. |
||
| 375 | */ |
||
| 376 | setSidebox: function(_app, _data, _md5) |
||
| 377 | { |
||
| 378 | this._super.apply(this,arguments); |
||
| 379 | |||
| 380 | if (typeof _app == 'string') _app = this.getApplicationByName(_app); |
||
| 381 | //Set the sidebox width if a application specific sidebox width is set |
||
| 382 | if (_app && _app == _app.parentFw.activeApp && _app.sideboxWidth !== false ) |
||
| 383 | { |
||
| 384 | this.splitterUi.constraints[0].size = _app.sideboxWidth; |
||
| 385 | } |
||
| 386 | this.getToggleSidebarState(); |
||
| 387 | }, |
||
| 388 | |||
| 389 | /** |
||
| 390 | * |
||
| 391 | * @param {app object} _app |
||
| 392 | * @param {int} _pos |
||
| 393 | * Checks whether the application already owns a tab and creates one if it doesn't exist |
||
| 394 | */ |
||
| 395 | createApplicationTab: function(_app, _pos) |
||
| 396 | { |
||
| 397 | this._super.apply(this, arguments); |
||
| 398 | this.checkTabOverflow(); |
||
| 399 | |||
| 400 | }, |
||
| 401 | |||
| 402 | /** |
||
| 403 | * Check to see if the tab header will overflow and want to wrap. |
||
| 404 | * Deal with it by setting some smaller widths on the tabs. |
||
| 405 | */ |
||
| 406 | checkTabOverflow: function() |
||
| 407 | { |
||
| 408 | var width = 0; |
||
| 409 | var outer_width = jQuery(this.tabsUi.contHeaderDiv).width(); |
||
| 410 | var spans = jQuery(this.tabsUi.contHeaderDiv).children('span'); |
||
| 411 | spans.css('max-width',''); |
||
| 412 | spans.each(function() { width += jQuery(this).outerWidth(true);}); |
||
| 413 | if(width > outer_width) |
||
| 414 | { |
||
| 415 | var max_width = Math.floor(outer_width / this.tabsUi.contHeaderDiv.childElementCount) - |
||
| 416 | (spans.outerWidth(true) - spans.width()); |
||
| 417 | spans.css('max-width',max_width + 'px'); |
||
| 418 | } |
||
| 419 | }, |
||
| 420 | |||
| 421 | /** |
||
| 422 | * @param {function} _opened |
||
| 423 | * Sends sidemenu entry category open/close information to the server using an AJAX request |
||
| 424 | */ |
||
| 425 | categoryOpenCloseCallback: function(_opened) |
||
| 426 | { |
||
| 427 | egw.set_preference(this.tag.appName, 'jdots_sidebox_'+this.catName, _opened); |
||
| 428 | }, |
||
| 429 | |||
| 430 | categoryAnimationCallback: function() |
||
| 431 | { |
||
| 432 | this.tag.parentFw.scrollAreaUi.update(); |
||
| 433 | }, |
||
| 434 | |||
| 435 | /** |
||
| 436 | * toggleSidebar callback function, handles preference and resize |
||
| 437 | * @param {string} _state state can be on/off |
||
| 438 | */ |
||
| 439 | _toggleSidebarCallback: function (_state) |
||
| 440 | { |
||
| 441 | var splitterWidth = egw.preference('jdotssideboxwidth',this.activeApp.appName) || this.activeApp.sideboxWidth; |
||
| 442 | if (_state === "on") |
||
| 443 | { |
||
| 444 | this.splitterUi.resizeCallback(70,'toggle'); |
||
| 445 | egw.set_preference(this.activeApp.appName, 'toggleSidebar', 'on'); |
||
| 446 | } |
||
| 447 | else |
||
| 448 | { |
||
| 449 | this.splitterUi.resizeCallback(splitterWidth); |
||
| 450 | egw.set_preference(this.activeApp.appName, 'toggleSidebar', 'off'); |
||
| 451 | } |
||
| 452 | }, |
||
| 453 | |||
| 454 | /** |
||
| 455 | * function to get the stored toggleSidebar state and set the sidebar accordingly |
||
| 456 | */ |
||
| 457 | getToggleSidebarState: function() |
||
| 458 | { |
||
| 459 | var toggleSidebar = egw.preference('toggleSidebar',this.activeApp.appName); |
||
| 460 | this.toggleSidebarUi.set_toggle(toggleSidebar?toggleSidebar:"off", this._toggleSidebarCallback, this); |
||
| 461 | }, |
||
| 462 | |||
| 463 | toggle_avatar_menu: function () |
||
| 464 | { |
||
| 465 | jQuery('#egw_fw_topmenu').toggle(); |
||
| 466 | } |
||
| 467 | }); |
||
| 468 | })(window); |
||
| 469 |