/* 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 . */ /* This is the scr_window class. It takes care of creating windows and editing windows. When a window has been created, it can be minimized, maximized and closed by the prototype functions of this class. */ function scr_window(title, icon, state, options, width, height, xpos, ypos, resizeable) { if (title == undefined) return // The title is the identifier - a must if (icon == undefined) var icon = false // Defaults to no icon if (state == undefined || state == -1) var state = 1 // 0 = minimized, 1 = normal, 2 = maximized if (options == undefined || options == -1) var options = [1, 1, 1] // Both minimizable, maximizeable and closeable if (width == undefined || width == -1) var width = 500 // Default width if (height == undefined || height == -1) var height = 350 // Default height if (xpos == undefined || xpos == -1) var xpos = (w - width) / 2 // Places it center if (ypos == undefined || ypos == -1) var ypos = (sh - height) / 2 // Places it in the middle if (resizeable == undefined || resizeable == -1) var resizeable = true // Resizable as default if (width < width_min) width = width_min // Limits if (height < height_min) height = height_min // Limits // Uniqueifyes the variables this.title = title this.icon = icon this.options = options this.width = width this.height = height this.resizeable = resizeable /* Creates two unique numbers. "num" will change if a window opened before this window is closed, while onum will never change */ this.num = scr.len this.onum = scr.olen // Creates the appbox in the appbox navbar this.appbox = document.createElement('div') this.appbox.rel = wnds.length // Accesible by JavaScript this.appbox.onclick = function() { // Minimize if visible and current // Change focus if visible but not current // Unminimize if not visible (the "un"-part happens automatically) if (wnds[this.rel].visible) { if (wnds[this.rel].appbox.className == 'current') wnds[this.rel].minimize(this.rel) else scr.change_focus(this.rel) } else wnds[this.rel].minimize(this.rel) } this.appbox.innerHTML = title // Appending it navi[posis['appboxes']].appboxes.appendChild(this.appbox) /* The following code creates all the neccesary elements for a window to exist. It's fairly straight-forward, but it takes up a lot of space */ var elems, belems, el, tmp, i, c this.elem = document.createElement('div') this.elem.className = 'window' el = 13 // The number of elements to be created if (icon) el++ tmp = 0 if (options[0]) tmp++ if (options[1]) tmp++ if (options[2]) tmp++ this.optboxes = tmp if (tmp > 0) el++ elems = new Array(el) belems = new Array(tmp) // Borders for (i = 0; i < 8; i++) { elems[i] = document.createElement('div') elems[i].className = global_directions_dt[i] if (i != 1) { if (resizeable) { elems[i].rel = i + '' elems[i].onmousedown = function() { if (wnds[this.parentNode.rel].normal) scr.adjust_start(this.parentNode.rel, this.rel) } elems[i].onmouseup = function() { scr.adjust_end() } } } } // Title + text + icon + options elems[8] = document.createElement('div') elems[8].className = 'title' elems[8].innerHTML = this.title elems[9] = document.createElement('div') elems[9].className = 'handle' elems[9].onmousedown = function() { if (wnds[this.parentNode.rel * 1].normal) { scr.move_start(this.parentNode.rel * 1) } } elems[9].onmouseup = function() { scr.move_end() } elems[9].ondblclick = function() { wnds[this.parentNode.rel * 1].maximize() } elems[10] = document.createElement('div') elems[10].className = 'resize_handle' if (resizeable) { elems[10].rel = '1' elems[10].onmousedown = function() { if (wnds[this.parentNode.rel * 1].normal) scr.adjust_start(this.parentNode.rel * 1, this.rel * 1) } elems[10].onmouseup = function() { scr.adjust_end() } } else this.elem.className += ' nrsz' // Seen by a css file if (!ie) { elems[11] = document.createElement('object') elems[11].data = 'pages/links.php?title=' + escape(title) + '&num=' + this.onum elems[11].type = 'text/html' } else { elems[11] = document.createElement('iframe') elems[11].src = 'pages/links.php?title=' + escape(title) + '&num=' + this.onum elems[11].frameBorder = '0' } elems[11].className = 'data' elems[12] = document.createElement('div') elems[12].className = 'data_overlay' if (icon) { elems[13] = document.createElement('div') elems[13].className = 'icon' elems[13].style.backgroundImage = 'url(\'pages/links.php?title=' + escape(title) + '&type=png\')' } if (this.optboxes > 0) { // If any options at all tmp = elems.length - 1 elems[tmp] = document.createElement('div') elems[tmp].className ='options' c = 0 for (i = 0; i < 3; i++) { if (options[i]) { belems[i] = document.createElement('div') belems[i].className = global_options[i] // Refer to onload.js if (global_options[i] == 'minimize') belems[i].onclick = function() { wnds[this.parentNode.parentNode.rel * 1].minimize() } else if (global_options[i] == 'maximize') belems[i].onclick = function() { wnds[this.parentNode.parentNode.rel * 1].maximize() } else belems[i].onclick = function() { wnds[this.parentNode.parentNode.rel * 1].close() } elems[tmp].appendChild(belems[i]) c++ } } } // All clickable elements need elem.rel to determine what window to change this.elem.rel = wnds.length this.elem.onmousedown = function() { scr.change_focus(this.rel * 1) } this.elem.style.left= xpos + 'px' this.elem.style.top = ypos + 'px' for (i = 0; i < el; i++) { // Append all created elements this.elem.appendChild(elems[i]) } this.len = this.elem.childNodes.length scr.elem.appendChild(this.elem) this.visible = true this.normal = true if (state == 0) this.minimize() this.update() // Adjust widths, heights, etc. this.update_appbox() // The same with the appbox if (state == 2) this.maximize() } scr_window.prototype.update = function() { /* This function updates the dimensions of the subelements of a window. scr holds standard information such as the general margin, while the window itself has some info about width, height, icons, etc. */ var tmp, el el = this.cn('tl') el.style.width = scr.margin_g + 'px' // margin_g is the general margin el.style.height = scr.hheight + 'px' // hheight is the header height el = this.cn('t') el.style.left = scr.margin_g + 'px' el.style.width = this.width - scr.margin_g * 2 + 'px' el.style.height = scr.hheight + 'px' el = this.cn('tr') el.style.left = this.width - scr.margin_g + 'px' el.style.width = scr.margin_g + 'px' el.style.height = scr.hheight + 'px' el = this.cn('r') el.style.top = scr.hheight + 'px' el.style.left = this.width - scr.margin_g + 'px' el.style.width = scr.margin_g + 'px' el.style.height = this.height - scr.hheight - scr.margin_g + 'px' el = this.cn('br') el.style.top = this.height - scr.margin_g + 'px' el.style.left = this.width - scr.margin_g + 'px' el.style.width = scr.margin_g + 'px' el.style.height = scr.margin_g + 'px' el = this.cn('b') el.style.top = this.height - scr.margin_g + 'px' el.style.left = scr.margin_g + 'px' el.style.width = this.width - scr.margin_g * 2 + 'px' el.style.height = scr.margin_g + 'px' el = this.cn('bl') el.style.top = this.height - scr.margin_g + 'px' el.style.width = scr.margin_g + 'px' el.style.height = scr.margin_g + 'px' el = this.cn('l') el.style.top = scr.hheight + 'px' el.style.width = scr.margin_g + 'px' el.style.height = this.height - scr.hheight - scr.margin_g + 'px' el = this.cn('title') el.style.top = scr.margin_g + 'px' el.style.height = scr.hheight - scr.margin_g + 'px' if (this.icon) tmp = scr.bw + scr.margin_t else tmp = 0 el.style.left = scr.margin_g + scr.margin_t + tmp + 'px' el.style.width = this.width - scr.margin_g * 2 - scr.margin_t * 2 - this.optboxes * (scr.bw + scr.margin_t) - tmp + 'px' el = this.cn('handle') el.style.top = scr.margin_g + 'px' el.style.height = scr.hheight - scr.margin_g + 'px' el.style.left = scr.margin_g + scr.bw + scr.margin_t + 'px' el.style.width = this.width - scr.margin_g * 2 - this.optboxes * (scr.bw + scr.margin_t) - tmp + 'px' el = this.cn('resize_handle') el.style.left = scr.margin_g + 'px' el.style.width = this.width - scr.margin_g * 2 + 'px' el.style.height = scr.margin_g + 'px' el = this.cn('data') el.style.top = scr.hheight + 'px' el.style.left = scr.margin_g + 'px' el.style.width = this.width - scr.margin_g * 2 + 'px' el.style.height = this.height - scr.hheight - scr.margin_g + 'px' el = this.cn('data_overlay') el.style.top = scr.hheight + 'px' el.style.left = scr.margin_g + 'px' el.style.width = this.width - scr.margin_g * 2 + 'px' el.style.height = this.height - scr.hheight - scr.margin_g + 'px' if (this.icon) { el = this.cn('icon') el.style.top = scr.margin_g + 'px' el.style.left = scr.margin_g + scr.margin_t + 'px' el.style.width = scr.bw + 'px' // bw is the box width el.style.height = scr.bh + 'px' // bh is the box height } el = this.cn('options') if (el) { el.style.top = scr.margin_g + 'px' el.style.left = this.width - this.optboxes * (scr.bw + scr.margin_t) - scr.margin_g + 'px' el.style.width = this.optboxes * (scr.bw + scr.margin_t) - scr.margin_t + 'px' // margin_t is the margin used in the top of the window el.style.height = scr.bh + 'px' var elc = el.childNodes var elcl = elc.length for (var i = 0; i < elcl; i++) { elc[i].style.left = i * (scr.bw + scr.margin_t) + 'px' elc[i].style.width = scr.bw + 'px' } } } scr_window.prototype.update_appbox = function() { this.appbox.style.height = navi[posis['appboxes']].height - appbox_padding * 2 - appbox_margin * 2 - appbox_border * 2 + 'px' } scr_window.prototype.cn = function(what) { /* This function is a smart one. It returns a pointer to the node which has the class specified by "what". If it's not found, the returned node is "fallback", which does nothing but at the same time makes sure no errors pop up. */ var i = 0 var ok = false var nodes = this.elem.childNodes var node = fallback while (i < this.len && !ok) { if (nodes[i].className == what) { node = nodes[i] ok = true } i++ } return node } scr_window.prototype.settitle = function(title) { // Sets the title of the window and the appbox associated with the window this.cn('title').innerHTML = title this.appbox.innerHTML = title } scr_window.prototype.minimize = function() { /* Minimizes if visible Unminimizes if not visible */ if (this.visible) { this.visible = false this.elem.style.display = 'none' scr.change_focus(this.num, 1) } else { this.visible = true this.elem.style.display = 'block' scr.change_focus(this.num) } } scr_window.prototype.maximize = function() { /* Maximizes if normal Unmaximizes if already maximized */ if (this.normal) { this.normal = false this.savedpos = [this.elem.offsetLeft, this.elem.offsetTop, this.width, this.height] this.elem.style.left = -scr.margin_g + 'px' this.elem.style.top = 0 this.width = w + scr.margin_g * 2 this.height = sh + scr.margin_g this.elem.className = 'window window_max' } else { this.normal = true this.elem.style.left = this.savedpos[0] + 'px' this.elem.style.top = this.savedpos[1] + 'px' this.width = this.savedpos[2] this.height = this.savedpos[3] this.elem.className = 'window' if (!this.resizeable) this.elem.className += ' nrsz' } this.update() } scr_window.prototype.close = function() { // Changes focus with det set to 2, which in turn removes the element scr.change_focus(this.num, 2) } scr_window.prototype.renum = function(n) { /* This function changes the "num" variable and the attributes that use it. The "num" variable will in some cases have to be changed when a window closes. */ this.num += n this.elem.rel = this.num this.appbox.rel = this.num }