metanohi-misc-subsites/projects/algo/js/scr_window.js

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
}