JavaXT
|
|
Window Classif(!javaxt) var javaxt={}; if(!javaxt.dhtml) javaxt.dhtml={}; //****************************************************************************** //** Window //****************************************************************************** /** * Simple window control that can be used to create dialogs, alert, messages, * etc. Window consists of a header, body, footer, and mask. All elements * are optional. * ******************************************************************************/ javaxt.dhtml.Window = function(parent, config) { this.className = "javaxt.dhtml.Window"; var me = this; var defaultConfig = { title: false, body: null, footer: null, width: null, height: null, modal: false, resizable: true, closable: true, shrinkToFit: false, valign: "middle", /** Style for individual elements within the component. Note that you can * provide CSS class names instead of individual style definitions. */ style: { //Panel Style panel: { fontFamily: "helvetica,arial,verdana,sans-serif", //"tahoma,arial,verdana,sans-serif", background: "#ffffff", border: "1px solid #b4cbdd", borderRadius: "5px", display: "inline-block", boxShadow: "0 12px 14px 0 rgba(0, 0, 0, 0.2), 0 13px 20px 0 rgba(0, 0, 0, 0.2)", minWidth: "50px" //rgba(0, 0, 0, 0.2) 0px 2px 4px 0px, rgba(0, 0, 0, 0.2) 0px 3px 2px 0px }, //Window header header: { background: "#d9e7f8", height: "28px", borderRadius: "4px 4px 0 0", //top left and righ radius should match the panel radius border: "1px solid #ecf2fb", borderBottom: "1px solid #b4cbdd" }, //Title (header) title: { position: "absolute", width: "100%", whiteSpace: "nowrap", fontSize: "14px", fontWeight: "bold", color: "#04468C", textAlign: "left", cursor: "default", padding: "5px" }, //App icon (header) icon: { float: "left" }, //Container for buttons in the header buttonBar: { //float: "right", position: "absolute", right: 0, padding: "5px" }, //Style for individual buttons in the header button: { width: "16px", height: "16px", border: "1px solid #cccccc", borderRadius: "3px", background: "#F6F6F6", color: "#6f6f6f", cursor: "default" }, closeIcon: { //content: "✖", content: "✕", lineHeight: "16px", textAlign: "center" }, body: { padding: "7px", verticalAlign: "top", color: "#484848" }, footer: { }, resizeHandle: { //should be about 20x20 px with rounded corner to match window }, mask: { background: "rgba(0,0,0,0.1)" } }, renderers: { headerButtons: createHeaderButtons } }; var mainDiv, header, body, footer, mask; var titleDiv, iconDiv, buttonDiv; //header elements var recenter = true; var visible = false; var seen = false; var overflow; var resizeListener; //************************************************************************** //** Constructor //************************************************************************** /** Creates a new instance of this class. */ var init = function(){ if (typeof parent === "string"){ parent = document.getElementById(parent); } if (!parent) return; //Clone the config so we don't modify the original config object var clone = {}; merge(clone, config); //Merge clone with default config merge(clone, defaultConfig); config = clone; //Create container mainDiv = createElement('div', parent, config.style.panel); mainDiv.style.position = "absolute"; mainDiv.style.left = "0px"; mainDiv.style.top = "0px"; mainDiv.style.display = "none"; mainDiv.style.visibility = "hidden"; //mainDiv.style.overflow = "hidden"; mainDiv.tabIndex = -1; //allows the div to have focus me.setWidth(config.width); me.setHeight(config.height); me.el = mainDiv; if (config.resizable===true){ addResizeHandle(mainDiv); } //Create table with 3 rows: header, body, and footer var table = createTable(mainDiv); table.style.fontFamily = "inherit"; table.style.textAlign = "inherit"; table.style.color = "inherit"; header = table.addRow().addColumn(); body = table.addRow().addColumn(config.style.body); body.style.width = "100%"; body.style.height = "100%"; footer = table.addRow().addColumn(config.style.footer); //Populate header var headerDiv = createElement('div', header, config.style.header); headerDiv.style.position = "relative"; var dragHandle = createElement('div', headerDiv); dragHandle.style.position = "absolute"; dragHandle.style.width = "100%"; dragHandle.style.height = "100%"; dragHandle.style.zIndex = 1; titleDiv = createElement('div', headerDiv, config.style.title); if (config.title) titleDiv.innerHTML = config.title; titleDiv.onclick = function(e){ me.onHeaderClick(headerDiv, e); }; iconDiv = createElement('div', headerDiv, config.style.icon); buttonDiv = createElement('div', headerDiv, config.style.buttonBar); buttonDiv.style.zIndex = 2; if (config.renderers.headerButtons){ config.renderers.headerButtons(buttonDiv); } else{ createHeaderButtons(buttonDiv); } me.setContent(config.body); me.setFooter(config.footer); //Create mask (used for modal dialogs and resize) mask = createElement('div', parent); if (config.modal===true){ addStyle(mask, "mask"); } mask.style.position = "absolute"; mask.style.left = "0px"; mask.style.top = "0px"; mask.style.width = "100%"; mask.style.height = "100%"; mask.style.display = "none"; mask.style.visibility = "hidden"; //parent.insertBefore(mask, parent.firstChild); //Initialize drag initDrag(dragHandle, { onDragStart: function(x,y){ var div = mainDiv; var rect = _getRect(div); var rect2 = _getRect(parent); var xOffset = x-rect.x; var yOffset = (y-rect.y)+rect2.y; div.xOffset = xOffset; div.yOffset = yOffset; div.width = rect.width; div.height = rect.height; div.style.left = rect.x + 'px'; div.style.top = (y-yOffset) + 'px'; dragHandle.style.cursor = 'move'; }, onDrag: function(x,y){ var div = mainDiv; var left = (x-div.xOffset); if (left<0) left = 0; if (left+div.width>parent.offsetWidth) left=parent.offsetWidth-div.width; var top = (y-div.yOffset); if (top<0) top = 0; if (top+div.height>parent.offsetHeight) top=parent.offsetHeight-div.height; div.style.left = left + 'px'; div.style.top = top + 'px'; }, onDragEnd: function(){ this.style.cursor = 'default'; } }); //Watch for resize events if (config.shrinkToFit===true){ addResizeListener(shrinkToFit); } }; //************************************************************************** //** destroy //************************************************************************** /** Used to destroy the window and remove it from the DOM */ this.destroy = function(){ if (resizeListener){ resizeListener.listeners = []; resizeListener.destroy(); } me.close(); if (mask){ mask.innerHTML = ""; var parent = mask.parentNode; if (parent) parent.removeChild(mask); mask = null; } destroy(me); me = null; return me; }; //************************************************************************** //** createHeaderButtons //************************************************************************** /** Default renderer for header buttons. */ var createHeaderButtons = function(buttonDiv){ if (config.closable===true){ buttonDiv.appendChild(createButton(config.style.closeIcon, me.close)); } }; //************************************************************************** //** createButton //************************************************************************** var createButton = function(icon, onclick){ var div = createElement('div', config.style.button); div.onclick = onclick; createElement('div', div, icon); return div; }; //************************************************************************** //** getTitle //************************************************************************** /** Returns the content of the window's header/title area */ this.getTitle = function(){ return titleDiv.innerHTML; }; //************************************************************************** //** setTitle //************************************************************************** /** Used to update the content of the window's header/title area */ this.setTitle = function(obj){ if (obj==null) titleDiv.innerHTML = ""; else{ if (isElement(obj)){ titleDiv.innerHTML = ""; body.appendChild(obj); } else{ if (typeof obj === "string"){ titleDiv.innerHTML = obj; } } } }; //************************************************************************** //** onHeaderClick //************************************************************************** /** Override to capture this header click events. */ this.onHeaderClick = function(){}; //************************************************************************** //** onResize //************************************************************************** /** Override to capture resize events. */ this.onResize = function(){}; //************************************************************************** //** getBody //************************************************************************** /** Returns the window's body (main content panel) as a DOM element */ this.getBody = function(){ return body; }; //************************************************************************** //** setBody //************************************************************************** /** Used to update/replace window's body (main content panel) * @param obj Accepts strings, DOM elements, and nulls */ this.setBody = this.setContent = function(obj){ if (obj==null) body.innerHTML = ""; else{ if (isElement(obj)){ body.innerHTML = ""; var p = obj.parentNode; if (p) p.removeChild(obj); body.appendChild(obj); } else{ if (typeof obj === "string"){ body.innerHTML = obj; } } } }; //************************************************************************** //** getFooter //************************************************************************** this.getFooter = function(){ return footer; }; //************************************************************************** //** setFooter //************************************************************************** this.setFooter = function(obj){ if (obj==null) footer.innerHTML = ""; else{ if (isElement(obj)){ var p = obj.parentNode; if (p) p.removeChild(obj); footer.appendChild(obj); } else{ if (typeof obj === "string"){ footer.innerHTML = obj; } } } }; //************************************************************************** //** show/open //************************************************************************** /** Used to make the window visible. */ this.show = this.open = function(animation){ me.showAt(null,null,animation); }; //************************************************************************** //** showAt //************************************************************************** /** Used to make the window visible at a given location on the screen. */ this.showAt = function(x, y){ //Set zIndex var highestElements = getHighestElements(); var zIndex = highestElements.zIndex; if (!highestElements.contains(mask)) zIndex++; //Update mask overflow = mask.parentNode.style.overflow; mask.parentNode.style.overflow = "hidden"; mask.style.zIndex = zIndex; if (config.modal===true){ mask.style.display = ''; mask.style.visibility = ''; } //Update window mainDiv.style.zIndex = zIndex+1; mainDiv.style.display = ''; mainDiv.style.visibility = ''; if (x!=null & y!=null){ mainDiv.style.left = x + "px"; mainDiv.style.top = y + "px"; recenter = false; } else{ if (recenter) me.center(); } if (!seen){ if (recenter){ addResizeListener(function(){ if (recenter) me.center(); }); } seen = true; } if (!visible){ me.update(); visible = true; me.onOpen(); if (config.shrinkToFit===true){ shrinkToFit(); } } }; //************************************************************************** //** hide //************************************************************************** /** Used to close/hide the window * @param silent If true, will not fire the onClose event */ this.hide = this.close = function(silent){ if (visible){ if (overflow) mask.parentNode.style.overflow = overflow; if (config.modal===true){ mask.style.display = "none"; mask.style.visibility = "hidden"; } mask.style.zIndex = ''; mainDiv.style.display = "none"; mainDiv.style.visibility = "hidden"; mainDiv.style.zIndex = ''; visible = false; if (silent!==true) me.onClose(); } }; //************************************************************************** //** isOpen //************************************************************************** /** Returns true if the window is open. */ this.isOpen = function(){ return visible; }; //************************************************************************** //** onOpen //************************************************************************** /** Called whenever the window is opened or made visible. */ this.onOpen = function(){}; //************************************************************************** //** onClose //************************************************************************** /** Called whenever the window is closed or hidden from view. */ this.onClose = function(){}; //************************************************************************** //** getWidth //************************************************************************** /** Returns the current width of the window in pixels (number) */ this.getWidth = function(){ return mainDiv.offsetWidth; }; //************************************************************************** //** setWidth //************************************************************************** /** Used to set the width of the window * @param width Accepts numbers or strings with valid CSS values ("1px, "1%") */ this.setWidth = function(width){ if (isNaN(width)){ if (typeof width === "string"){ mainDiv.style.width = width; } } else{ mainDiv.style.width = width + "px"; } me.update(); me.onResize(); }; //************************************************************************** //** getHeight //************************************************************************** /** Returns the current height of the window in pixels (number) */ this.getHeight = function(){ return mainDiv.offsetHeight; }; //************************************************************************** //** setHeight //************************************************************************** /** Used to set the height of the window * @param height Accepts numbers or strings with valid CSS values ("1px, "1%") */ this.setHeight = function(height){ if (isNaN(height)){ if (typeof height === "string"){ mainDiv.style.height = height; } } else{ mainDiv.style.height = height + "px"; } me.update(); me.onResize(); }; //************************************************************************** //** update //************************************************************************** /** Used to update the size of the window. Called internally whenever the * window is resized to insure that the window contents fit inside the * window. If you are updating DOM elements within the window dynamically, * you may need to call this method. */ this.update = function(){ setTimeout(function(){ try{ var minWidth = Math.max(header.offsetWidth, body.offsetWidth, footer.offsetWidth); if (mainDiv.offsetWidth<minWidth){ mainDiv.style.width = minWidth+"px"; } } catch(e){} try{ var minHeight = header.offsetHeight + body.offsetHeight + footer.offsetHeight; if (mainDiv.offsetHeight<minHeight){ mainDiv.style.height = minHeight+"px"; } } catch(e){} }, 0); }; //************************************************************************** //** center //************************************************************************** /** Moves the window to the center of the screen. */ this.center = function(){ var w = mainDiv.offsetWidth; var h = mainDiv.offsetHeight; var x = document.body.clientWidth; var y = document.body.clientHeight; //Update x if >1 monitor in use if (screen.width>(2*screen.height)) x=x/2; //Set x value to the middle of the screen x = (x/2)-(w/2); //Compute y value switch(config.valign){ case "top": y = (y/4)-(h/2); break; default: y = (y/2)-(h/2); } if (y<0) y=0; if (x<0) x=0; //Move form mainDiv.style.left = x + "px"; mainDiv.style.top = y + "px"; }; //************************************************************************** //** addResizeHandle //************************************************************************** var addResizeHandle = function(parent){ var xOffset, yOffset; var orgHeight, orgWidth; var dx, dy; var onDragStart = function(x,y){ var div = this; mask.style.cursor = div.style.cursor; mask.style.display = ""; mask.style.visibility = ""; var rect = _getRect(div); var rect2 = _getRect(parent); xOffset = (x-rect.x)+rect2.x; yOffset = (y-rect.y)+rect2.y; orgHeight = rect2.height; orgWidth = rect2.width; dx = parseFloat(parent.style.width); if (dx<orgWidth) dx = orgWidth-dx; else dx = 0; dy = parseFloat(parent.style.height); if (dy<orgHeight) dy = orgHeight-dy; else dy = 0; }; var onDragEnd = function(){ if (config.modal!==true){ mask.style.display = "none"; mask.style.visibility = "hidden"; } mask.style.cursor = ""; mainDiv.focus(); }; var setWidth = function(w){ parent.style.width = w + "px"; var minWidth = Math.max(header.offsetWidth, body.offsetWidth, footer.offsetWidth); if (parent.offsetWidth<minWidth){ parent.style.width = minWidth+"px"; } }; var setHeight = function(h){ parent.style.height = h + "px"; var minHeight = header.offsetHeight + body.offsetHeight + footer.offsetHeight; if (parent.offsetHeight<minHeight){ parent.style.height = minHeight+"px"; } }; //Add vertical resizer to the top of the window (buggy!) var resizeHandle = createElement("div", parent); resizeHandle.style.position = "absolute"; resizeHandle.style.width = "100%"; resizeHandle.style.height = "10px"; resizeHandle.style.top = "-5px"; resizeHandle.style.cursor = "ns-resize"; //resizeHandle.style.backgroundColor = "#ff0000"; resizeHandle.style.zIndex = 2; javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var top = (yOffset-y); parent.style.top = (y) + "px"; setHeight((orgHeight+top)-dy); me.onResize(); }, onDragEnd: onDragEnd }); //Add vertical resizer to the bottom of the window resizeHandle = resizeHandle.cloneNode(); resizeHandle.style.top = ""; resizeHandle.style.bottom = "-5px"; parent.appendChild(resizeHandle); javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var top = -(yOffset-y); setHeight(top+dy); me.onResize(); }, onDragEnd: onDragEnd }); //Add horizontal resizer to the left of the window resizeHandle = resizeHandle.cloneNode(); resizeHandle.style.top = "0px"; resizeHandle.style.bottom = ""; resizeHandle.style.left = "-5px"; resizeHandle.style.height = "100%"; resizeHandle.style.width = "10px"; resizeHandle.style.cursor = "ew-resize"; parent.appendChild(resizeHandle); javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var top = (xOffset-x); parent.style.left = x + 'px'; setWidth((orgWidth+top)); me.onResize(); }, onDragEnd: onDragEnd }); //Add nw resizer resizeHandle = resizeHandle.cloneNode(); resizeHandle.style.top = "-5px"; resizeHandle.style.right = ""; resizeHandle.style.height = "10px"; resizeHandle.style.cursor = "se-resize"; parent.appendChild(resizeHandle); javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var top = (xOffset-x); parent.style.left = x + 'px'; setWidth((orgWidth+top)); var top = (yOffset-y); parent.style.top = (y) + "px"; setHeight((orgHeight+top)-dy); me.onResize(); }, onDragEnd: onDragEnd }); //Add sw resizer resizeHandle = resizeHandle.cloneNode(); resizeHandle.style.top = ""; resizeHandle.style.bottom = "-5px"; resizeHandle.style.cursor = "ne-resize"; parent.appendChild(resizeHandle); javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var top = (xOffset-x); parent.style.left = x + 'px'; setWidth((orgWidth+top)); var top = -(yOffset-y); setHeight(top+dy); me.onResize(); }, onDragEnd: onDragEnd }); //Add horizontal resizer to the right of the window resizeHandle = resizeHandle.cloneNode(); resizeHandle.style.left = ""; resizeHandle.style.right = "-5px"; resizeHandle.style.top = "0px"; resizeHandle.style.height = "100%"; resizeHandle.style.cursor = "ew-resize"; parent.appendChild(resizeHandle); javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var d = -(xOffset-x); setWidth(d+dx); me.onResize(); }, onDragEnd: onDragEnd }); //Add ne resizer resizeHandle = resizeHandle.cloneNode(); resizeHandle.style.top = "-5px"; resizeHandle.style.height = "10px"; resizeHandle.style.cursor = "ne-resize"; parent.appendChild(resizeHandle); javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var d = -(xOffset-x); setWidth(d+dx); var top = (yOffset-y); parent.style.top = (y) + "px"; setHeight((orgHeight+top)-dy); me.onResize(); }, onDragEnd: onDragEnd }); //Add se resizer resizeHandle = resizeHandle.cloneNode(); resizeHandle.style.top = ""; resizeHandle.style.cursor = "se-resize"; if (config.style.resizeHandle==null || isEmpty(config.style.resizeHandle)){ resizeHandle.style.bottom = "-5px"; javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var d = -(xOffset-x); setWidth(d+dx); var top = -(yOffset-y); setHeight(top+dy); me.onResize(); }, onDragEnd: onDragEnd }); } else{ resizeHandle.style.width = "25px"; resizeHandle.style.height = "25px"; createElement("div", resizeHandle, config.style.resizeHandle); javaxt.dhtml.utils.initDrag(resizeHandle, { onDragStart: onDragStart, onDrag: function(x,y){ var d = -(xOffset-x)+20; setWidth(d+dx); var top = -(yOffset-y)+20; setHeight(top+dy); me.onResize(); }, onDragEnd: onDragEnd }); } parent.appendChild(resizeHandle); }; //************************************************************************** //** shrinkToFit //************************************************************************** /** Resize window if it is larger that the parent */ var shrinkToFit = function(){ var width = me.getWidth(); var height = me.getHeight(); var w = parent.offsetWidth; var h = parent.offsetHeight; if (width>w){ me.setWidth(w); } if (height>h){ me.setHeight(h); } }; //************************************************************************** //** addResizeListener //************************************************************************** var addResizeListener = function(fn){ if (!resizeListener){ resizeListener = javaxt.dhtml.utils.addResizeListener(parent, function(){ var listeners = resizeListener.listeners; for (var i=0; i<listeners.length; i++){ listeners[i].apply(me, []); } }); resizeListener.listeners = []; } resizeListener.listeners.push(fn); }; //************************************************************************** //** Utils //************************************************************************** var _getRect = javaxt.dhtml.utils.getRect; var merge = javaxt.dhtml.utils.merge; var destroy = javaxt.dhtml.utils.destroy; var isEmpty = javaxt.dhtml.utils.isEmpty; var isElement = javaxt.dhtml.utils.isElement; var getHighestElements = javaxt.dhtml.utils.getHighestElements; var createElement = javaxt.dhtml.utils.createElement; var createTable = javaxt.dhtml.utils.createTable; var initDrag = javaxt.dhtml.utils.initDrag; var addStyle = function(el, style){ javaxt.dhtml.utils.addStyle(el, config.style[style]); }; init(); }; |