407 lines
13 KiB
JavaScript
407 lines
13 KiB
JavaScript
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
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
|
|
} |