/* Algo: a dekstop environment look-a-like in your web browser Copyright (C) 2009 Niels Serup This file is part of Algo. Algo is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Algo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Algo. If not, see . */ /* The navbar class creates a navigation bar. Normally Algo features two navigation bars - one at the top of the page and one at the bottom of the page. Several obejcts can be added to a navigation bar after its creation, including dropdowns, appboxes (the boxes with text that you can click on, usually found in the bottom navigation bar) and a clock. The style of the navigation bar itself and the objects on the navigation bar is found in an external css themes file. */ function navbar(pos) { // navnum = the order in which it was created (0, 1, etc.) this.navnum = navi.length // If pos is undefined, set the navigation bar to be at the top if (pos == undefined || pos == -1) var pos = [[0, ''], -1, -1, [0, '']] // Save pos this.pos = pos // Create the actual navigation bar element this.menu = document.createElement('div') /* Makes it identifiable by a css file. By adding " navi" followed by the number of the navbar, each navbar can be independently changed by a css file */ this.menu.className = 'navbar navi' + this.navnum // Update the position of the navbar this.update() // Append the navbar to the wrapper wrapper.appendChild(this.menu) } navbar.prototype.update = function() { // Loop through the 4 global directions (top to right) for (var i = 0; i < global_directions_length; i++) { /* If the pos is not no-existant, style the navbar's menu element with the amount ([i][0]) followed by a unit ([i][1]) */ if (this.pos[i] != -1) this.menu.style[global_directions[i]] = this.pos[i][0] + this.pos[i][1] } } navbar.prototype.support = function(name) { /* When supporting objects, they will be linked to the supporting navbar to make them accesible later on via the global "posis" list */ posis[name] = this.navnum // Special cases if (name == 'dropdowns') this.drops = [] } navbar.prototype.unsupport = function(name) { // Cease support of a certain object if (posis[name] == undefined) return delete posis[name] // Special cases if (name == 'dropdowns') delete this.dropdowns else if (name == 'appboxes') delete this.appboxes } // DROPDOWN navbar.prototype.drop = function(name, list) { /* Adds a dropdown menu. Dropdowns will appear in the order they are created. "name" is the name of the dropdown menu, while "list" holds all the entries in an array-like format. */ var listlen = list.length var wrap = this.append_level(list, name) this.dropdowns.appendChild(wrap) // Adds a new dropdown object to the "drops" this.drops[this.drops.length] = [wrap, name, list] } navbar.prototype.append_level = function(list, first) { /* This function creates the elements of a dropdown menu, based on a list of strings and (eventually) more lists. This function will call itself if a list at level one has another list. That way, there are no factors that limit the number of levels in a dropdown menu. "first" is set to the name of the list when called from the original drop prototype function, while it is set to false when called from this function itself. */ var listlen = list.length var i, wrap, dtop, type, elem, elema, elemb, spl, title // Creates the temporary element that will hold everything wrap = document.createElement('div') if (first) { wrap.className = 'dropdown' // dtop = the header element dtop = document.createElement('div') // Adds two classes, one general and one special (" drop" + drops.length) dtop.className = 'top drop' + navi[posis['dropdowns']].drops.length dtop.innerHTML = first wrap.appendChild(dtop) } else { /* If it's not the first time the function is called, it will create a div with entries instead of a div with a header. */ wrap.className = 'entries' elem = document.createElement('div') elem.className = 'side' wrap.appendChild(elem) } /* This is the main loop. It looks at the list entries and evaluates them based on what they are. If a string is encountered, it is written to the dropdown menu. If an object (a list in this case) is encountered, this function is recalled with the sublist as the main list. */ for (i = 0; i < listlen; i++) { type = typeof(list[i]) if (type == 'string') { spl = [list[i], 'true'] if (list[i].indexOf('#') != -1) spl = list[i].split('#') elem = document.createElement('div') elem.className = 'entry' elem.rel = spl[1] elem.onmouseup = function() { navi[posis['dropdowns']].hide_drops() } elem.innerHTML = spl[0] elem.onclick = function() { eval('scr.setwindow(\'' + this.innerHTML + '\',' + this.rel + ')') } wrap.appendChild(elem) } else if (type == 'object') { elem = document.createElement('div') elem.className = 'group' elema = document.createElement('div') elema.className = 'header' elema.innerHTML = list[i][0] elem.appendChild(elema) elema = this.append_level(list[i][1]) elem.appendChild(elema) wrap.appendChild(elem) } } return wrap } navbar.prototype.hide_drops = function() { /* When clicking on an entry in a dropdown menu, the mouse will still hover the dropdown element, and the dropdown element will still be visible. By temporarily changing the class of the dropdown menu, this function makes the dropdown disappear. */ if (!hiding_drops) { hiding_drops = true var l = this.drops.length for (i = 0; i < l; i++) { this.drops[i][0].className = 'dropdownh dropdown' } // No need to wait for more than 0.1 seconds setTimeout('navi[posis[\'dropdowns\']].hide_drops()', 100) } else { hiding_drops = false var l = this.drops.length for (i = 0; i < l; i++) { this.drops[i][0].className = 'dropdown' } } } navbar.prototype.box = function(name, pos) { /* This function adds a box with an object to the navigation bar. "pos" is the css float property and is completely optional. For the most part it should in fact not be neccesary to use it, as the styles of most elements added by this function is defined in a css file. */ if (pos == undefined) pos = 'none' this[name] = document.createElement('div') this[name].className = name this[name].style.cssFloat = pos this.menu.appendChild(this[name]) // Special cases if (name == 'clock') { this.setclock() this.clockinterval = setInterval('navi[posis[\'clock\']].setclock()', 30000) } if (name == 'abs_scroller') { // abs_scroller appears when there is not enough space for all appboxes. this.abs_scroller.className = 'abs' var elem elem = document.createElement('div') elem.className = 'scrollup' elem.onclick = function() { // Scroll up navi[posis['appboxes']].abs_scroll(1) } this.abs_scroller.appendChild(elem) elem = document.createElement('div') elem.className = 'scrolldown' elem.onclick = function() { // Scroll down navi[posis['appboxes']].abs_scroll(-1) } this.abs_scroller.appendChild(elem) this.menu.style.overflow = 'hidden' } } navbar.prototype.check_abs_height = function(force) { /* This function checks if there is a need for a scroller, i.e. if there are too many appboxes to be shown in one line. */ var abs = navi[posis['appboxes']].height var rnum = navi[posis['appboxes']].appboxes.scrollHeight if (ie) { // Internet Explorer has some issues. This fix isn't perfect. if ((rnum / abs + '').indexOf('.') != -1) rnum += appbox_margin * 2 } var num = rnum / abs if (num > 1) { // If there are too many appboxes navi[posis['appboxes']].appboxes.style.marginRight = abs_scroller_width + 3 + 'px' navi[posis['appboxes']].abs_scroller.style.display = 'block' /* If the force is true, scroll to the place where the window linked with the appbox is */ if (force) this.abs_scroll(-Math.floor(wnds[scr.wndpos[0]].appbox.offsetTop / abs)) } else { navi[posis['appboxes']].appboxes.style.marginRight = '0' navi[posis['appboxes']].abs_scroller.style.display = 'none' this.abs_scroll(-abs_scrolled) } } navbar.prototype.abs_scroll = function(am) { var abam = abs_scrolled + am * 1 var abs = this.height var rnum = this.appboxes.scrollHeight if (ie) { // Internet Explorer has some issues. This fix isn't perfect. if ((rnum / abs + '').indexOf('.') != -1) rnum += appbox_margin * 2 } /* num = the actual height of the appboxes container divided with the displayed height */ var num = rnum / abs if (abs_scrolled + am < 1 && abam * -1 < num) { // Only do the scrolling if there's something to scroll to abs_scrolled = abam this.appboxes.style.marginTop = abs * abs_scrolled + 'px' } } navbar.prototype.setclock = function() { var time = new Date () var hours = time.getHours() var minutes = time.getMinutes() // "07" is nicer than just "7" hours = (hours < 10 ? "0" : "") + hours minutes = (minutes < 10 ? "0" : "") + minutes this.clock.innerHTML = hours + ':' + minutes }