@class name="WinFrame">
A class that represents a floating window
(c) SAP AG 2003-2006. All rights reserved.
//////////////////////////////////////////////////////////////////////////////////////
// CLASS DECLARATION
// Window constructor
function WinFrame(settings, params, onCloseCallback) {
// add window to the windows collection
this.handle = WinFrame.lastHandle = POS(WinFrame.lastHandle)+1;
this.visible = true;
this._hasOwnSize = true;
this.setCloseCallback(onCloseCallback);
_allWindows[this.handle] = this;
_visWindows[this.handle] = this;
_currWindow = this;
_visCount++;
if(_visCount == 1)
$ENV.fireRefreshToolbar();
this.gripIndexis = {
NNW:4, N:0, NNE:5,
NWW:11, NEE:6,
W:3, E:1,
SWW:10, SEE:7,
SSW:9, S:2, SSE:8
};
// build frame based on initial settings
this.params = params || null;
this.loaded = false;
this.initSettings(settings);
this.margin = 4; //outer border width
this.padding = 3; //inner border width
this.buildFrame();
this.adjustFrame();
this.raise();
}
// Window destructor
WinFrame.prototype.dispose = function() {
if (this.contentsObj) this.contentsObj.src = 'about:blank';
if (this.glassObj) this.glassObj.removeNode(true);
for (var i=0, G1=this.sizeOutGrips,G2=this.sizeInGrips, len=G1 && G1.length; i
Gets the window contents url
This the url of an external file to be displayed in a secondary browser inside the window.
<@prop name="key:s" default="" access="RO" also="@reusable">
Gets the window key
The window key is used for identifying the window. In case the window is @reusable, at most one window instance
with the same key may exist. If the window is not reusable, then any number of windows with the same key exist.
If omitted, the window key will be set to the window url.
<@prop name="behavior:s:amodal" access="RO">
Gets the window behavioral mode
Value | Description
~modal | modal window
~amodal | amodal window
~lens | lens window
<@prop name="position:s:inside" access="RO">
Gets the window positioning mode
Value | Description
~inside | floating, inside canvas bounds
~unbound | floating, without bounds
~fill | fill entire canvas
~center | position on canvas center
~side | dock to canvas side (top, bottom, left, right)
<@prop name="movable:b:true" access="RO">Indicates whether the window can be moved
<@prop name="sizable:b:true" access="RO">Indicates whether the window can be resized
<@prop name="dockable:b:false" access="RO">Indicates whether the window can be docked
<@prop name="reusable:b:true" access="RO" also="@key">Indicates whether the window can be reused
<@prop name="board:s" access="RO">Gets the window board id, if the window is a board window
<@method name="open" scope="private">
Opens (reopens) the window
WinFrame.prototype.open = function(settings, params, onCloseCallback) {
this.setCloseCallback(onCloseCallback);
this.initSettings(settings);
if (this.btnMaxObj) setToggleButton(this.btnMaxObj, false)
this.glassObj.style.display = this.behavior == 'modal' ? 'block' : 'none';
for (var i=0, G1=this.sizeOutGrips, G2=this.sizeInGrips, sizable = this.sizable, len=G1 && G1.length; i
Notifies that the window has completed loading
WinFrame.prototype.notifyLoad = function() {
this.loaded = true;
}
<@method name="close">
Closes the window
WinFrame.prototype.close = function(force, skipWIN_HIDE) {
if (_currWindow == this) _currWindow = null;
if (this.visible) {
_visCount--;
delete _visWindows[this.handle];
}
this.visible = false;
this.z = -1;
if (!force && this.reusable) {
if (this.contentsObj && !skipWIN_HIDE) this.contentsObj.contentWindow.__WIN_HIDE();
this.frameObj.style.display = 'none';
this.glassObj.style.display = 'none';
for (var i=0, G1=this.sizeOutGrips, G2=this.sizeInGrips, len=G1 && G1.length; i= zmax) { _currWindow=win; zmax=win.z; }
}
var st = _currWindow.titleTextObj.parentElement.style;
st.background = _currWindow._titlePrimaryBGColor;
st.color = _currWindow._titlePrimaryColor;
setTimeout(_currWindow.getFocus);
}
if (this.board && this.oldboard) $WIN.switchBoard(this.oldboard);
//Keep context when closing floating window
// $ENV.context = this.params.root;
SIGNAL('BOARD->layoutSelection');
}
<@method name="reload">
Reloads the window
WinFrame.prototype.reload = function() {
if (!this.visible || !this.contentsObj) return;
this.contentsObj.src = this.url;
}
//////////////////////////////////////////////////////////////////////////////////////
// WINDOW STYLE
<@prop name="background:s:white" access="RO" group="Window Style" sortGroup="no">
Gets the window background color
Value | Description
~color | color name / rgb code
~none | no color (transparent)
<@prop name="border:s:thin" access="RO">
Gets the window border style
Value | Description
~thick | thick frame
~thin | thin frame
~dash | dashed frame
~double | double frame
~none | no frame
<@prop name="shadow:s:none" access="RO">
Gets the window shadow style
Value | Description
~none | no shadow
~drop | drop shadow
~gradient | gradient shadow
<@prop name="opacity:n:100" access="RO">Gets the window opacity, between 0 (transparent) and 100 (opaque)
//////////////////////////////////////////////////////////////////////////////////////
// WINDOW TITLEBAR
<@prop name="titlebar:s:raised" access="RO" group="Window Titlebar" sortGroup="no">
Gets the window titlebar style
Value | Description
~raised | raised titlebar (3D)
~flat | flat titlebar
~thin | thin flat titlebar
~text | text-only titlebar
~none | no titlebar
<@prop name="titleColor:s:auto" access="RO">
Gets the window titlebar color
Value | Description
~auto | color depends on titlebar style
~color | explicit color name / rgb code
~none | no color (transparent)
<@prop name="titleText:s" access="RO">Gets the window title text
<@prop name="btnClose:b:true" access="RO">Indicates whether to show the Close button
<@prop name="btnLock:b:false" access="RO">Indicates whether to show the Lock/Unlock button
<@prop name="btnMax:b:false" access="RO">Indicates whether to show the Maximize/Restore button
<@method name="setTitle">
Sets the window title
The title text
WinFrame.prototype.setTitle = function(text) {
if (!text) text = '';
this.titleText = text;
if (this.titleTextObj) this.titleTextObj.innerHTML = text;
}
//////////////////////////////////////////////////////////////////////////////////////
// WINDOW POSITIONING
<@prop name="x:n:auto" access="RO" group="Window Positioning" sortGroup="no">Gets the window y position (relative to the canvas origin)
<@prop name="y:n:auto" access="RO">Gets the window x position (relative to the canvas origin)
<@prop name="w:n:auto" access="RO">Gets the window width
<@prop name="h:n:auto" access="RO">Gets the window height
<@prop name="minw:n:100" access="RO">Gets the minimum window width
<@prop name="minh:n:50" access="RO">Gets the minimum window height
<@prop name="maxw:n:9999" access="RO">Gets the maximum window width
<@prop name="maxh:n:9999" access="RO">Gets the maximum window height
<@prop name="margin:n:0" access="RO">Gets the margin to leave around the window
<@method name="center">
Centers the window on a given point
The new window x center
The new window y center
If the center point is omitted, the window will be centered in the middle of the canvas.
WinFrame.prototype.centerOn = function(x,y) {
if (arguments.length == 0) {
this.moveTo((clientWidth-this.w)/2, (clientHeight-this.h)/2);
} else {
this.moveTo(x-this.w/2, y-this.h/2);
}
}
<@method name="moveTo">
Moves the window
The new window x position
The new window y position
WinFrame.prototype.moveTo = function(x,y) {
if ('|inside|unbound|'.indexOf(this.position) < 0) return;
if (x == this.x && y == this.y) return;
var st=this.frameObj.style;
st.left = this.x = x;
st.top = this.y = y;
this.adjustGrips();
}
<@method name="resizeTo">
Resizes the window
The new window width
The new window height
WinFrame.prototype.resizeTo = function(w,h) {
if (!this._hasOwnSize) {
this._hasOwnSize = true;
this.glassObj.style.visibility = 'visible';
this.frameObj.style.visibility = 'visible';
}
var w = LIMIT(this.minw, POS(w), this.maxw);
var h = LIMIT(this.minh, POS(h), this.maxh);
if (w == this.w && h == this.h) return;
this.w = w;
this.h = h;
if (this.position == 'fill') return;
this.position = 'inside';
this.adjustFrame();
}
<@method name="raise">
Raises the window to the front
WinFrame.prototype.raise = function() {
if (!this.visible) return;
// increase z-index, if needed
if (this.z < _maxZIndex) {
this.setZIndex(_maxZIndex+3);
$MAINMENU.showFocusEffect(false);
}
_currWindow = this;
// change title's background
// and compact all z-indexes, once in a while
var updateZIndex = _maxZIndex > _visCount*10;
var V=[];
for (var k in _visWindows) V.push(_visWindows[k]);
SORTN(V, 'z');
for (var i=0; i<_visCount; i++) {
if (updateZIndex) V[i].setZIndex((i+1)*3);
if (V[i] != _currWindow) {
var st = V[i].titleTextObj.parentElement.style;
st.background = V[i]._titleSecondaryBGColor;
st.color = V[i]._titleSecondaryColor;
}
}
var st = _currWindow.titleTextObj.parentElement.style;
st.background = _currWindow._titlePrimaryBGColor;
st.color = _currWindow._titlePrimaryColor;
}
<@method name="maximize">
Maximizes the window to fill the entire canvas
WinFrame.prototype.maximize = function() {
this.position = 'fill';
if (this.btnMaxObj) setToggleButton(this.btnMaxObj, true)
this.adjustFrame();
}
<@method name="restore">
Restores the window to its last position
WinFrame.prototype.restore = function() {
this.position = 'inside';
if (this.btnMaxObj) setToggleButton(this.btnMaxObj, false)
this.adjustFrame();
}
//////////////////////////////////////////////////////////////////////////////////////
// WINDOW BUILDING METHODS
// PRIVATE: initializes the window settings
WinFrame.prototype.initSettings = function(settings) {
var win=this;
// window control properties
pstr ('url', '');
pstr ('key', this.url);
pstr ('behavior', 'amodal', 'modal amodal lens');
pstr ('position', 'inside', 'inside unbound fill center top bottom left right');
pbool('movable', true);
pbool('sizable', true);
pbool('dockable', false);
pbool('reusable', true);
pstr ('board', '');
// window style properties
pstr ('border', 'thin', 'vc_editor thick thin dash double none');
pstr ('background', 'white');
pnum ('opacity', 100);
pstr ('shadow', 'none', 'none drop gradient');
// window titlebar properties
pstr ('titlebar', 'raised', 'vc_editor raised flat thin text none');
pstr ('titleColor', 'auto');
pstr ('titleText', '');
pbool('btnClose', true);
pbool('btnLock', false);
pbool('btnMax', false);
// window positioning properties
pnum ('x', 'auto');
pnum ('y', 'auto');
pnum ('w', 'auto');
pnum ('h', 'auto');
pnum ('minw', 100);
pnum ('minh', 50);
pnum ('maxw', 9999);
pnum ('maxh', 9999);
pbool('islayoutBoard', false);
// set window position and size
var W=clientWidth, H=clientHeight;
if (this.w <= 0 || this.w == 'auto') {
this.w = 200;
this._hasOwnSize = false;
}
if (this.h <= 0 || this.h == 'auto') {
this.h = 150;
this._hasOwnSize = false;
}
if (this.x == 'auto') this.x = (W-this.w)/2;
if (this.y == 'auto') this.y = (H-this.h)/2;
this.z = -1;
function pnum(name, dflt) {
win[name] = (settings && (name in settings)) ? FLOAT(settings[name]) : dflt;
}
function pbool(name, dflt) {
win[name] = (settings && (name in settings)) ? BOOL(settings[name]) : dflt;
}
function pstr(name, dflt, domain) {
win[name] = (settings && (name in settings)) ? settings[name] : dflt;
if (!domain) return;
win[name] = LOWER(win[name]);
for (var i=0, V=SPLIT(domain), len=V.length; i W) {
this.w = w = W - 2*mr;
this.x = x = mr;
}
else {
this.x = x = MAX(W - w, mr);
this.w = w = W - x;
}
}
if (H < y + h + mr) {
if (h +2*mr > H) {
this.h = h = H - 2*mr;
this.y = y = mr;
}
else {
this.y = y = MAX(H - h, mr);
this.h = h = H - y;
}
}
setBBox(frm,x,y,w,h);
if (this.sizable) this.adjustGrips();
if (this.titleBarObj) {
var ch = this.titleBarObj.children;
var dx = (this.titlebar == 'raised' ? -2 : -1) - INT(this.titleBarObj.paddingRight, 0);
var fw = frm.clientWidth;
for (var i=ch.length-1; i>=1; i--) {
dx -= 13;
ch(i).style.left = fw+dx;
}
ch(i).style.width = fw+dx;
}
if (this.contentsObj) {
var cy = this.titleBarObj ? this.titleBarObj.offsetHeight : 0;
var cw = frm.clientWidth;
var ch = POS(frm.clientHeight - cy);
setBBox(this.contentsObj, 0, cy, cw-1, ch-1);
}
}
// PRIVATE: adjusts the window grips after move or resize
WinFrame.prototype.adjustGrips = function(resizing, x,y,w,h) {
if (!this.sizeOutGrips) return;
var G1=this.sizeOutGrips, G2=this.sizeInGrips, frm=this.frameObj, br=POS(this.borderWidth);
var d1=this.margin, d2=this.padding, c=MAX(d1+d2, 10), dc=MAX(d1+d2, 10);
var gi = this.gripIndexis;
if (arguments.length == 0) {
x = frm.offsetLeft;
y = frm.offsetTop;
w = frm.clientWidth;
h = frm.clientHeight;
}
switch (this.position) {
case 'fill': break;
case 'top': break;
case 'left': break;
case 'bottom': y+=br; break;
case 'right': x+=br; break;
default: x+=br; y+=br; break;
}
/*
-----NNW------N------NNE-----
-NWW NEE-
-W E-
-SWW SEE-
-----SSW------S------SSE-----
*/
setBBox(G1[gi['N']], x+c, y-d1, w-2*c, d1);
setBBox(G2[gi['N']], x+c, y, w-2*c, d2);
setBBox(G1[gi['E']], x+w, y+c, d1, h-c-dc);
setBBox(G2[gi['E']], x+w-d2, y+c, d2, h-c-dc);
setBBox(G1[gi['S']], x+c, y+h, w-c-dc, d1);
setBBox(G2[gi['S']], x+c, y+h-d2, w-c-dc, d2);
setBBox(G1[gi['W']], x-d1, y+c, d1, h-2*c);
setBBox(G2[gi['W']], x, y+c, d2, h-2*c);
setBBox(G1[gi['NNW']], x-d1, y-d1, d1+c, d1);
setBBox(G2[gi['NNW']], x, y, c, d2);
setBBox(G1[gi['NNE']], x+w-c, y-d1, d1+c, d1);
setBBox(G2[gi['NNE']], x+w-c, y, c, d2);
setBBox(G1[gi['NEE']], x+w, y, d1, c);
setBBox(G2[gi['NEE']], x+w-d2, y, d2, c);
setBBox(G1[gi['SEE']], x+w, y+h-dc, d1, dc);
setBBox(G2[gi['SEE']], x+w-d2, y+h-dc, d2, dc);
setBBox(G1[gi['SSE']], x+w-dc, y+h, d1+dc, d1);
setBBox(G2[gi['SSE']], x+w-dc, y+h-d2, dc, d2);
setBBox(G1[gi['SSW']], x-d1, y+h, d1+c, d1);
setBBox(G2[gi['SSW']], x, y+h-d2, c, d2);
setBBox(G1[gi['SWW']], x-d1, y+h-c, d1, c);
setBBox(G2[gi['SWW']], x, y+h-c, d2, c);
setBBox(G1[gi['NWW']], x-d1, y, d1, c);
setBBox(G2[gi['NWW']], x, y, d2, c);
if (!resizing) //do nothing while resizing
setBBox(this.cornerObj, x+w-dc, y+h-dc, dc, dc);
var hide = !this._hasOwnSize || this.position == 'fill';
for (var i=0, len=G1.length; i 0 && !win.dockable) return;
var frm=win.frameObj;
if (!win.islayoutBoard) {
_moveFrame = frm.cloneNode(true);
_moveFrame.children[frm.children.length - 1].removeNode(true); //remove IFrame
_canvas.appendChild(_moveFrame);
frm = _moveFrame;
win.frameObj.style.visibility = 'hidden';
win.cornerObj.style.visibility = 'hidden';
frm.style.filter = 'alpha(opacity=50)';
}
frm.onmousemove = win.doMove;
frm.onmouseup = win.endMove;
frm.onlosecapture = win.endMove;
_moveWin = win;
_moveX = event.x - frm.offsetLeft;
_moveY = event.y - frm.offsetTop;
frm.setCapture(true);
}
WinFrame.prototype.doMove = function() {
if (!_moveWin) return;
var win=_moveWin, frm=_moveFrame||_moveWin.frameObj;
var W=clientWidth, H=clientHeight, mr=win.margin;
var x = event.x - _moveX;
var y = event.y - _moveY;
if (win.position != 'unbound') {
var x0=mr, x1=W-mr-win.w;
var y0=mr, y1=H-mr-win.h;
if (win.dockable) {
var pos = (yy1) ? 'bottom' : (xx1) ? 'right' : 'inside';
if (pos != win.position) {
if (_moveX > win.w) {
_moveX = win.w/2;
x = LIMIT(x0, event.x-_moveX, x1);
}
if (_moveY > win.h) {
_moveY = win.h/2;
y = LIMIT(y0, event.y-_moveY, y1);
}
win.position = pos;
win.adjustFrame();
}
if (pos != 'inside') {
x = frm.offsetLeft;
y = frm.offsetTop;
}
}
x = LIMIT(x0, x, x1);
y = LIMIT(y0, y, y1);
}
frm.style.left = win.x = x;
frm.style.top = win.y = y;
}
WinFrame.prototype.endMove = function() {
if (!_moveWin) return;
var win=_moveWin, frm=_moveFrame||_moveWin.frameObj;
win.doMove();
_moveWin = null;
frm.releaseCapture();
frm.onmousemove = frm.onmouseup = frm.onlosecapture = null;
if (win.sizable) win.adjustGrips(false, frm.offsetLeft, frm.offsetTop, frm.clientWidth, frm.clientHeight);
if (!win.islayoutBoard) {
st = win.frameObj.style;
st.visibility = 'visible';
st.left = frm.offsetLeft;
st.top = frm.offsetTop;
win.cornerObj.style.visibility = 'visible';
if (_moveFrame) _moveFrame.removeNode(true);
_moveFrame = null;
}
win.getFocus();
}
WinFrame.prototype.doDblClick = function() {
var win = getEventWindow();
if (!win || !win.sizable) return;
if (win.position == 'fill') win.restore(); else win.maximize();
}
//////////////////////////////////////////////////////////////////////////////////////
// WINDOW RESIZE HANDLER
var _resizeWin, _resizeOx, _resizeOy, _resizeDx, _resizeDy;
WinFrame.prototype.attachResizeHandler = function(obj) {
obj.win = this;
obj.onmousedown = this.startResize;
}
WinFrame.prototype.startResize = function() {
if (event.button == 2) return;
var win=getEventWindow(), G=win.sizeOutGrips;
if (!win) return;
win.raise();
if (!G || !win.sizable || win.position == 'fill') return;
var frm=win.frameObj;
frm.onmousemove = win.doResize;
frm.onmouseup = win.endResize;
frm.onlosecapture = win.endResize;
_resizeWin = win;
_resizeOx = event.x;
_resizeOy = event.y;
_resizeDx = event.srcElement.dx;
_resizeDy = event.srcElement.dy;
for (var i=0, len=G.length; i win.maxw) dw=win.maxw-w;
if (h+dh < win.minh) dh=win.minh-h; else if (h+dh > win.maxh) dh=win.maxh-h;
var dx = (_resizeDx < 0 ? -dw : 0);
var dy = (_resizeDy < 0 ? -dh : 0);
var W=clientWidth-mr, H=clientHeight-mr, X=frameElement.offsetTop+mr, Y=frameElement.offsetLeft+mr;
var nx = x+dx;
if (nx < X) {
dw -= X-nx;
nx = X;
}
var ny = y+dy;
if (ny < Y) {
dh -= Y-ny;
ny = Y;
}
var nw = w+dw > W-nx ? W-nx : w+dw;
var nh = h+dh > H-ny ? H-ny : h+dh;
win.adjustGrips(true, nx, ny, nw, nh);
}
WinFrame.prototype.endResize = function() {
if (!_resizeWin) return;
var win=_resizeWin, frm=_resizeWin.frameObj;
var G=win.sizeOutGrips, mr=win.margin, br=win.borderWidth;
if (event.type == 'mouseup') {
win.doResize();
if (_resizeDx != 0) {
win.x = G[3].offsetLeft+mr-br;
win.w = G[1].offsetLeft-win.x+br;
}
if (_resizeDy != 0) {
win.y = G[0].offsetTop+mr-br;
win.h = G[2].offsetTop-win.y+br;
}
}
for (var i=0, len=G.length; i