/** * jQuery Window Plugin - To Popup A Beautiful Window-like Dialog * http://fstoke.me/jquery/window/ * Copyright(c) 2010 David Hung * Dual licensed under the MIT and GPL licenses * Version: 5.01a * Last Revision: 2010-11-19 * * The window status is defined as: cascade(default), minimized, maxmized * * The code style is reference from javascript Singleton design pattern. Please see: * http://fstoke.me/blog/?page_id=1610 * * Join the facebook fans page to discuss there and get latest information. * http://www.facebook.com/pages/jQuery-Window-Plugin/116769961667138 * * This jQuery plugin has been tested in the following browsers: * - IE 7, 8 * - Firefox 3.5+ * - Opera 9, 10+ * - Safari 4.0+ * - Chrome 2.0+ * * Required jQuery Libraries: * jquery.js (v1.3.2) * jquery-ui.js (v1.7.2) * * Customized Button JSON Array Sample: var myButtons = [ // facebook button { id: "btn_facebook", // required, it must be unique in this array data title: "share to facebook", // optional, it will popup a tooltip by browser while mouse cursor over it clazz: "my_button", // optional, don't set border, padding, margin or any style which will change element position or size style: "", // optional, don't set border, padding, margin or any style which will change element position or size image: "img/facebook.gif", // optional, the image url of button icon(16x16 pixels) callback: // required, the callback function while click it function(btn, wnd) { wnd.getContainer().find("#demo_text").text("Share to facebook!"); wnd.getContainer().find("#demo_logo").attr("src", "img/facebook_300x100.png"); } }, // twitter button { id: "btn_twitter", title: "share to twitter", clazz: "my_button", style: "background:#eee;", image: "img/twitter.png", callback: function(btn, wnd) { wnd.getContainer().find("#demo_text").text("Share to twitter!"); wnd.getContainer().find("#demo_logo").attr("src", "img/twitter_300x100.jpg"); } } ]; */ // Get window instance via jQuery call // create window on html body $.window = function(options) { return $.Window.getInstance(null, options); }; // create window on caller element $.fn.window = function(options) { return $.Window.getInstance($(this), options); } // Creating Window Dialog Module $.Window = (function() { // static private methods // static constants var VERSION = "5.01a"; // the version of current plugin var ICON_WH = 16; // window icon button width/height, in pixels. check "window_icon_button" style in css var ICON_MARGIN = 4; // window icon button margin, in pixels. check "window_icon_button" style in css var ICON_OFFSET = ICON_WH + ICON_MARGIN; // window icon button offset for decide function bar width in header panel var OPACITY_MINIMIZED = 0.7; // css opacity while window minimized or doing animation var MINIMIZED_NARROW = 24; var MINIMIZED_LONG = 120; var RESIZE_EVENT_DELAY = 200; var ua = navigator.userAgent.toLowerCase(); // browser useragent // static variables var windowIndex = 0; // index to create window instance id var lastSelectedWindow = null; // to remember last selected window instance var windowStorage = []; // a array to store created window instance var initialized = false; // a boolean flag to check is it initialized? var resizeTimer = null; // a timer to avoid doing duplicated routine while receiving browser window resize event var parentCallers = []; var minWinData = { long: MINIMIZED_LONG, storage: [] // a array to store minimized window instance }; // the static setting var setting = { dock: 'left', // [string:"left"] the direction of minimized window dock at. the available values are [left, right, top, bottom] animationSpeed: 400, // [number:400] the speed of animations: maximize, minimize, restore, shift, in milliseconds minWinNarrow: MINIMIZED_NARROW, // [number:24] the narrow dimension of minimized window minWinLong: MINIMIZED_LONG, // [number:120] the long dimension of minimized window handleScrollbar: true, // [boolean:true] to handle browser scrollbar when window status changed(maximize, minimize, cascade) showLog: false // [boolean:false] to decide show log in firebug, IE8, chrome console }; // select the current clicked window instance, concurrently, unselect last selected window instance function selectWindow(parent, wnd) { if( parent == null ) { if( lastSelectedWindow != null && lastSelectedWindow != wnd ) { lastSelectedWindow.unselect(); wnd.select(); } else if( lastSelectedWindow == null ) { wnd.select(); } lastSelectedWindow = wnd; } else if( parent != null ) { if( parent.get(0)._lastSelectedWindow != null && parent.get(0)._lastSelectedWindow != wnd ) { parent.get(0)._lastSelectedWindow.unselect(); wnd.select(); } else if( parent.get(0)._lastSelectedWindow == null ) { wnd.select(); } parent.get(0)._lastSelectedWindow = wnd; } } // get the window instance function getWindow(windowId) { for( var i=0, len=windowStorage.length; i rect.height ) { mwdata.long = rect.height/(count+1); adjustAllMinWindows(parent); } } else if( mwdata.long < setting.minWinLong ) { if( (count * setting.minWinLong) < rect.height ) { mwdata.long = setting.minWinLong; } else { mwdata.long = rect.height/count; } } } else if( setting.dock == 'top' || setting.dock == 'bottom' ) { if( bPush ) { if( ((count+1) * mwdata.long) > rect.width ) { mwdata.long = rect.width/(count+1); adjustAllMinWindows(parent); } } else if( mwdata.long < setting.minWinLong ) { if( (count * setting.minWinLong) < rect.width ) { mwdata.long = setting.minWinLong; } else { mwdata.long = rect.width/count; } } } } function adjustAllMinWindows(parent) { var storage = (parent != null)? parent.get(0)._minWinData.storage:minWinData.storage; for( var i=0; i= 0 ) { // fix IE7 $("body").attr("scroll", "no"); } else { document.body.style.overflow = "hidden"; } } } // show browser scroll bar function showBrowserScrollbar() { if( setting.handleScrollbar ) { if( ua.indexOf("msie 7") >= 0 ) { // fix IE7 $("body").removeAttr("scroll"); } else { document.body.style.overflow = "auto"; } } } function getBrowserScreenWH() { var width = document.documentElement.clientWidth; var height = document.documentElement.clientHeight; return {width:width, height:height}; } function getBrowserScrollXY() { var scrOfX = 0, scrOfY = 0; if( typeof( window.pageYOffset ) == 'number' ) { //Netscape compliant scrOfY = window.pageYOffset; scrOfX = window.pageXOffset; } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) { //DOM compliant scrOfY = document.body.scrollTop; scrOfX = document.body.scrollLeft; } else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) { //IE6 standards compliant mode scrOfY = document.documentElement.scrollTop; scrOfX = document.documentElement.scrollLeft; } return {left:scrOfX, top:scrOfY}; } function getCssStyleByDock(parent, miniIndex) { var targetCss = {}; var screenWH = getBrowserScreenWH(); var cpos = null; var bTop = 0; var bLeft = 0; var narrow = setting.minWinNarrow; var long = minWinData.long; if( parent != null ) { cpos = parent.offset(); bTop = parseInt( parent.css('borderTopWidth') ); bLeft = parseInt( parent.css('borderLeftWidth') ); long = parent.get(0)._minWinData.long; } if( setting.dock == 'left' || setting.dock == 'right' ) { targetCss.width = narrow; targetCss.height = long - 1; targetCss.top = miniIndex * long; if( setting.dock == 'left' ) { if( parent != null ) { targetCss.top += cpos.top + bTop; targetCss.left = cpos.left + bLeft; } else { targetCss.left = 0; } } else if( setting.dock == 'right' ) { if( parent != null ) { targetCss.top += cpos.top + bTop; targetCss.left = cpos.left + parent.width() + bLeft - narrow - 2; } else { targetCss.left = screenWH.width - narrow; } } } else if( setting.dock == 'top' || setting.dock == 'bottom' ) { targetCss.width = long - 1; targetCss.height = narrow; targetCss.left = miniIndex * long; if( setting.dock == 'top' ) { if( parent != null ) { targetCss.top = cpos.top + bTop; targetCss.left += cpos.left + bLeft; } else { targetCss.top = 0; } } else if( setting.dock == 'bottom' ) { if( parent != null ) { targetCss.top = cpos.top + parent.height() + bTop - narrow - 2; targetCss.left += cpos.left + bLeft; } else { targetCss.top = screenWH.height - narrow; } } } //log( 'getCssStyleByDock: '+ screenWH.height ); return targetCss; } function log(msg) { if(setting.showLog && window.console != null) { console.log(msg); } } function constructor(caller, options) { // instance private methods // flag & variables var _this = null; // to remember current window instance var windowId = "window_" + (windowIndex++); // the window's id var minimized = false; // a boolean flag to tell the window is minimized var maximized = false; // a boolean flag to tell the window is maximized var selected = false; // a boolean flag to tell the window is selected var redirectCheck = false; // a boolean flag to control popup message while browser is going to leave this page var pos = new Object(); // to save cascade mode current position var wh = new Object(); // to save cascade mode current width & height var orgPos = new Object(); // to save position before minimize var orgWh = new Object(); // to save width & height before minimize var targetCssStyle = {}; // to save target css style json object var headerFuncPanel = null; // header function bar element object var funcBarWidth = 0; // the width of header function bar var miniStackIndex = -1; // the index of window in minimized stack var animating = false; // a boolean flag to indicate the window is doing animate // element var container = null; // whole window container element var header = null; // the header panel of window. it includes title text and buttons var frame = null; // the content panel of window. it could be a iframe or a div element, depending on which way you create it var footer = null; // the footer panel of window. currently, it got nothing, but maybe a status bar or something will be added in the future // the instance options var options = $.extend({ title: "", // [string:""] the title text of window url: "", // [string:""] the target url of iframe ready to load. content: "", // [html string, jquery object, element:""] this attribute only works when url is null. when passing a jquery object or a element, it will clone the original one to append. footerContent: "", // [html string, jquery object, element:""] same as content attribute, but it's put on footer panel. containerClass: "", // [string:""] container extra class headerClass: "", // [string:""] header extra class frameClass: "", // [string:""] frame extra class footerClass: "", // [string:""] footer extra class selectedHeaderClass: "", // [string:""] selected header extra class x: -1, // [number:-1] the x-axis value on screen(or caller element), if -1 means put on screen(or caller element) center y: -1, // [number:-1] the y-axis value on screen(or caller element), if -1 means put on screen(or caller element) center z: 2000, // [number:2000] the css z-index value width: 400, // [number:400] window width height: 300, // [number:300] window height minWidth: 200, // [number:200] the minimum width, if -1 means no checking minHeight: 150, // [number:150] the minimum height, if -1 means no checking maxWidth: 800, // [number:800] the maximum width, if -1 means no checking maxHeight: 600, // [number:600] the maximum height, if -1 means no checking showFooter: true, // [boolean:true] to control show footer panel showRoundCorner: false, // [boolean:true] to control display window as round corner closable: true, // [boolean:true] to control window closable minimizable: true, // [boolean:true] to control window minimizable maximizable: true, // [boolean:true] to control window maximizable bookmarkable: true, // [boolean:true] to control window with remote url could be bookmarked draggable: true, // [boolean:true] to control window draggable resizable: true, // [boolean:true] to control window resizable scrollable: true, // [boolean:true] to control show scroll bar or not checkBoundary: false, // [boolean:false] to check window dialog overflow html body or caller element custBtns: null, // [json array:null] to describe the customized button display & callback function onOpen: null, // [function:null] a callback function while container is added into body onShow: null, // [function:null] a callback function while whole window display routine is finished onClose: null, // [function:null] a callback function while user click close button onSelect: null, // [function:null] a callback function while user select the window onUnselect: null, // [function:null] a callback function while window unselected onDrag: null, // [function:null] a callback function while window is going to drag afterDrag: null, // [function:null] a callback function after window dragged onResize: null, // [function:null] a callback function while window is going to resize afterResize: null, // [function:null] a callback function after window resized onMinimize: null, // [function:null] a callback function while window is going to minimize afterMinimize: null, // [function:null] a callback function after window minimized onMaximize: null, // [function:null] a callback function while window is going to maximize afterMaximize: null, // [function:null] a callback function after window maximized onCascade: null, // [function:null] a callback function while window is going to cascade afterCascade: null, // [function:null] a callback function after window cascaded onIframeStart: null, // [function:null] a callback function while iframe ready to connect remoting url. this attribute only works while url attribute is given onIframeEnd: null, // [function:null] a callback function while iframe load finished. this attribute only works while url attribute is given iframeRedirectCheckMsg: null, // [string:null] if null means no check, or pass a string to show warning message while iframe is going to redirect createRandomOffset: {x:0, y:0} // [json object:{x:0, y:0}] random the new created window position, it only works when options x,y value both are -1 }, options); function initialize(instance) { _this = instance; // build html var realCaller = caller != null? caller:$("body"); var cornerClass = options.showRoundCorner? "ui-corner-all ":""; realCaller.append("
"); container = realCaller.children("div#"+windowId); // onOpen call back if( $.isFunction(options.onOpen) ) { options.onOpen(_this); } wh.w = options.width; wh.h = options.height; container.width(options.width); container.height(options.height); container.css("z-index", options.z); if( $.browser.msie ) { // To fix the right or bottom edge of window can't be trigger to resize while scrollbar appears on IE browser container.css({ paddingRight: 1, paddingBottom: 1 }); } if( options.x >= 0 || options.y >= 0 ) { var scrollPos = getBrowserScrollXY(); // set position x if( options.x >= 0 ) { var pLeft = 0; if( caller != null ) { pLeft = options.x + caller.offset().left; } else { pLeft = options.x + scrollPos.left; } container.css("left", pLeft); } else { // put on center alignHorizontalCenter(); } // set position y if( options.y >= 0 ) { var pTop = 0; if( caller != null ) { pTop = options.y + caller.offset().top; } else { pTop = options.y + scrollPos.top; } container.css("top", pTop); } else { // put on middle alignVerticalCenter(); } } else { alignCenter(); } // feed x,y with real pixel value(not a percentage), to avoid "JUMPING" while window restore from minized status var currPos = container.position(); container.css({ left: currPos.left, top: currPos.top }); // build header html cornerClass = options.showRoundCorner? "ui-corner-top ":""; var headerHtml = "
"+ "
"+options.title+"
"+ "
"+ "
"; container.append(headerHtml); header = container.children("div.window_header"); // bind double click event with doing maximize action if( options.maximizable ) { header.dblclick(function() { if( maximized ) { restore(); } else { maximize(); } }); } headerFuncPanel = header.children("div.window_function_bar"); // add close button if( options.closable ) { headerFuncPanel.append( "
" ); headerFuncPanel.children(".closeImg").click(function() { close(); }); funcBarWidth += ICON_OFFSET; } // add maximize button if( options.maximizable ) { headerFuncPanel.append( "
" ); headerFuncPanel.append( "" ); headerFuncPanel.children(".maximizeImg").click(function() { maximize(); }); headerFuncPanel.children(".cascadeImg").click(function() { restore(); }); funcBarWidth += ICON_OFFSET; } // add minimize button if( options.minimizable ) { headerFuncPanel.append( "
" ); headerFuncPanel.children(".minimizeImg").click(function() { minimize(); }); funcBarWidth += ICON_OFFSET; } // add bookmark button if( options.bookmarkable && options.url != null && $.trim(options.url) != "" ) { headerFuncPanel.append( "
" ); headerFuncPanel.children(".bookmarkImg").click(function() { doBookmark(options.title, options.url); }); funcBarWidth += ICON_OFFSET; } // add customized buttons addCustomizedButtns(headerFuncPanel); // make buttons don't pass dblclick event to header panel $(".window_icon_button").dblclick(function() { return false; }); // set text & function bar width adjustHeaderTextPanelWidth(); headerFuncPanel.width( funcBarWidth ); // build iframe html var frameHeight = getFrameHeight(wh.h); if( options.url != null && $.trim(options.url) != "" ) { // iframe starting call back if( $.isFunction(options.onIframeStart) ) { log("start connecting iframe: "+options.url); options.onIframeStart(_this, options.url); } // add iframe redirect checking if( options.iframeRedirectCheckMsg ) { redirectCheck = true; window.onbeforeunload = function() { if( redirectCheck ) { var msg = options.iframeRedirectCheckMsg.replace("{url}", options.url); return msg; } } } // show loading image container.append("
Loading...
"); var loading = container.children(".frame_loading"); loading.css("marginLeft", '-' + (loading.outerWidth() / 2) - 20 + 'px'); loading.click(function() { loading.remove(); }); // append iframe html var scrollingHtml = options.scrollable? "yes":"no"; container.append(""); frame = container.children(".window_frame"); // iframe load finished call back frame.ready(function() { frame.show(); }); frame.load(function() { redirectCheck = false; loading.remove(); log("load iframe finished: "+options.url); if( $.isFunction(options.onIframeEnd) ) { options.onIframeEnd(_this, options.url); } }); } else { container.append("
"); frame = container.children(".window_frame"); if( options.content != null ) { setContent(options.content); frame.children().show(); } frame.css({ overflow: options.scrollable? "auto":"hidden" }); } // build footer html if( options.showFooter ) { cornerClass = options.showRoundCorner? "ui-corner-bottom ":""; container.append(""); footer = container.children("div.window_footer"); if( options.footerContent != null ) { setFooterContent(options.footerContent); footer.children("div").children().show(); } } else { cornerClass = options.showRoundCorner? "ui-corner-bottom ":""; frame.addClass(cornerClass); } // bind container handle mousedown event container.mousedown(function() { selectWindow(caller, _this); }); // make window draggable if( options.draggable ) { container.draggable({ cancel: ".no-draggable", start: function() { log( "drag start" ); if( minimized || maximized ) { // if window is minimized or maximized, reset the css style container.css("position", "fixed"); container.css(targetCssStyle); } showOverlay(); hideContent(); // callback if( options.onDrag ) { options.onDrag(_this); } }, stop: function() { log( "drag stop" ); if( minimized || maximized ) { // if window is minimized or maximized, reset the css style container.css("position", "fixed"); container.css(targetCssStyle); } hideOverlay(); showContent(); // callback if( options.afterDrag ) { options.afterDrag(_this); } } }); // set boundary if got opotions if( options.checkBoundary ) { container.draggable('option', 'containment', 'parent'); } } // make window resizable if( options.resizable ) { container.resizable({ cancel: ".no-resizable", alsoResize: frame, start: function() { // this will be triggered when window is going to drag in minimized or maximized mode log( "resize start" ); if( minimized || maximized ) { // if window is minimized or maximized, reset the css style return false; } showOverlay(); hideContent(); // callback if( options.onResize ) { options.onResize(_this); } }, stop: function() { log( "resize stop" ); if( minimized || maximized ) { // if window is minimized or maximized, reset the css style return false; } hideOverlay(); adjustHeaderTextPanelWidth(); showContent(); // callback if( options.afterResize ) { options.afterResize(_this); } } }); // set boundary if got opotions if( options.checkBoundary ) { // this got bug, so mark it temporarily //container.resizable('option', 'containment', "parent"); } // set resize min, max width & height if( options.maxWidth >= 0 ) { container.resizable('option', 'maxWidth', options.maxWidth); } if( options.maxHeight >= 0 ) { container.resizable('option', 'maxHeight', options.maxHeight); } if( options.minWidth >= 0 ) { container.resizable('option', 'minWidth', options.minWidth); } if( options.minHeight >= 0 ) { container.resizable('option', 'minHeight', options.minHeight); } } // onShow call back if( $.isFunction(options.onShow) ) { options.onShow(_this); } } function setTitle(title) { options.title = title; header.children(".window_title_text").text(title); if( minimized ) { _transformTitleText(); } } function getTitle() { return options.title; } function setUrl(url) { options.url = url; frame.attr("src", url); } function getUrl() { return options.url; } function setContent(content) { options.content = content; if( typeof content == 'object' ) { content = $(content).clone(true); } else if( typeof content == 'string' ) { // using original content } frame.empty(); frame.append(content); } function getContent() { return frame.html(); } function setFooterContent(content) { if( options.showFooter ) { options.footerContent = content; if( typeof content == 'object' ) { content = $(content).clone(true); } else if( typeof content == 'string' ) { // using original content } footer.children("div").empty(); footer.children("div").append(content); } } function getFooterContent() { return footer.children("div").html(); } // popup a overlay panel block whole screen while window dragging or resizing // to avoid lost event while mouse cursor over iframe region. [ISU_003] function showOverlay() { var overlay = $("#window_overlay"); if( overlay.get(0) == null ) { $("body").append("
 
"); overlay = $("#window_overlay"); overlay.css('z-index', options.z+1); } overlay.show(); } function hideOverlay() { $("#window_overlay").hide(); } function transferToFixed() { var currPos = container.offset(); var scrollPos = getBrowserScrollXY(); container.css({ position: "fixed", // this will cause IE brwoser UI error, See ISU_004 left: currPos.left - scrollPos.left, top: currPos.top - scrollPos.top }); } function transferToAbsolute() { var currPos = container.offset(); container.css({ position: "absolute", left: currPos.left, top: currPos.top }); } function addCustomizedButtns(headerFuncPanel) { if( options.custBtns != null && typeof options.custBtns == 'object' ) { for( var i=0; i" ); } else { headerFuncPanel.append( "
" ); } var btn = headerFuncPanel.children("[id="+id+"]"); btn.get(0).clickCb = callback; if( $.isFunction(callback)) { btn.click(function() { this.clickCb($(this), _this); }); } } else { // it's a html element(or wrapped with jQuery) var btn = $(btnData).clone(true); btn.addClass("window_icon_button no-draggable cust_button"); headerFuncPanel.append( btn ); btn.show(); } } funcBarWidth += ICON_OFFSET; } } } function _adjustMinimizedPos(bImmediate, callback) { animating = true; targetCssStyle = getCssStyleByDock(caller, miniStackIndex); if( bImmediate ) { container.css(targetCssStyle); animating = false; if( $.isFunction(callback) ) { callback(); } } else { container.animate(targetCssStyle, setting.animationSpeed, 'swing', function() { animating = false; if( $.isFunction(callback) ) { callback(); } }); } } function adjustHeaderTextPanelWidth() { header.children("div.window_title_text").width( header.width() - funcBarWidth - 10 ); } function adjustFrameWH() { var width = container.width(); var height = container.height(); var frameHeight = getFrameHeight(height); frame.width( width ); frame.height( frameHeight ); } function doBookmark(title, url) { if ( $.browser.mozilla && window.sidebar ) { // Mozilla Firefox Bookmark window.sidebar.addPanel(title, url, ""); } else if( $.browser.msie && window.external ) { // IE Favorite window.external.AddFavorite( url, title); } else if( ua.indexOf("chrome") >= 0 ) { // Chrome alert("Sorry! Chrome doesn't support bookmark function currently."); //alert("Press [Ctrl + D] to bookmark in Chrome"); } else if($.browser.safari || ua.indexOf("safari") >= 0 ) { // Safari alert("Sorry! Safari doesn't support bookmark function currently."); //alert("Press [Ctrl + D] to bookmark in Safari"); } else if($.browser.opera || ua.indexOf("opera") >= 0 ) { // Opera Hotlist alert("Sorry! Opera doesn't support bookmark function currently."); //alert("Press [Ctrl + D] to bookmark in Opera"); } } function hideContent() { //log("hideContent"); var bgColor = frame.css("backgroundColor"); if( bgColor != null && bgColor != "transparent" ) { container.css("backgroundColor", bgColor); } frame.hide(); if( options.showFooter ) { footer.hide(); } container.css("opacity", OPACITY_MINIMIZED); } function showContent() { //log("showContent"); frame.show(); if( options.showFooter ) { footer.show(); } container.css("opacity", 1); } function getFrameHeight(windowHeight) { var footerHeight = options.showFooter? 16:0; return windowHeight - 20 - footerHeight - 4; // minus header & footer & iframe's padding height } // modify title text as vertical presentation function _transformTitleText() { if( setting.dock == 'top' || setting.dock == 'bottom' ) { return; } var textBlock = header.children("div.window_title_text"); //var text = textBlock.text(); var text = options.title; var buf = ""; for( var i=0; i"; } } textBlock.html(buf); } function restoreTitleText() { var textBlock = header.children("div.window_title_text"); textBlock.text(options.title); } // public function getCaller() { return caller; } function getContainer() { return container; } function getHeader() { return header; } function getFrame() { return frame; } function getFooter() { return footer; } function getTargetCssStyle() { return targetCssStyle; } function alignCenter() { var pLeft = 0, pTop = 0; if( caller != null ) { var cpos = caller.offset(); pLeft = cpos.left + (caller.width() - container.width()) / 2; pTop = cpos.top + (caller.height() - container.height()) / 2; } else { var scrollPos = getBrowserScrollXY(); var screenWH = getBrowserScreenWH(); pLeft = scrollPos.left + (screenWH.width - container.width()) / 2; pTop = scrollPos.top + (screenWH.height - container.height()) / 2; }; // random new created window position if( options.createRandomOffset.x > 0 ) { pLeft += ((Math.random() - 0.5) * options.createRandomOffset.x); } if( options.createRandomOffset.y > 0 ) { pTop += ((Math.random() - 0.5) * options.createRandomOffset.y); } container.css({ left: pLeft, top: pTop }); } function alignHorizontalCenter() { var pLeft = 0; if( caller != null ) { pLeft = caller.offset().left + (caller.width() - container.width()) / 2; } else { var scrollPos = getBrowserScrollXY(); var screenWH = getBrowserScreenWH(); pLeft = scrollPos.left + (screenWH.width - container.width()) / 2; } container.css({ left: pLeft }); } function alignVerticalCenter() { var pTop = 0; if( caller != null ) { pTop = caller.offset().top + (caller.height() - container.height()) / 2; } else { var scrollPos = getBrowserScrollXY(); var screenWH = getBrowserScreenWH(); pTop = scrollPos.top + (screenWH.height - container.height()) / 2; } container.css({ top: pTop }); } function select() { selected = true; if( maximized == false ) { container.css('z-index', options.z+2); if( options.selectedHeaderClass ) { header.addClass(options.selectedHeaderClass); // add selected header class } } if( $.isFunction(options.onSelect) ) { options.onSelect(); } } function unselect() { selected = false; if( maximized == false ) { container.css('z-index', options.z); if( options.selectedHeaderClass ) { header.removeClass(options.selectedHeaderClass); } } if( $.isFunction(options.onUnselect) ) { options.onUnselect(); } } /** * @param x - the absolute x-axis value on document or shift distance, in pixels * @param y - the absolute y-axis value on document or shift distance, in pixels * @param bShift - a boolean flag to decide to shift the window position with x,y */ function move(x, y, bShift) { if( !maximized && !minimized ) { var styleObj = {}; if( typeof x == 'number' ) { if( bShift ) { var currPos = container.offset(); x += currPos.left; } styleObj.left = x; } if( typeof y == 'number' ) { styleObj.top = y; if( bShift ) { var currPos = container.offset(); y += currPos.top; } styleObj.top = y; } container.css(styleObj); } } function resize(w, h) { if( !maximized && !minimized ) { var styleObj = {}; if( w > 0 ) { styleObj.width = w; } if( h > 0 ) { styleObj.height = h; } container.css(styleObj); adjustHeaderTextPanelWidth(); } } function maximize(bImmediately, bNoSaveDisplay) { if( !$.browser.msie && caller == null ) { // in IE, must do hide scrollbar routine after animation finished hideBrowserScrollbar(); } maximized = true; container.draggable( 'disable' ); container.resizable( 'disable' ); // save current display if( bNoSaveDisplay != true ) { pos.left = container.css("left"); pos.top = container.css("top"); wh.w = container.width(); wh.h = container.height(); } // must add this, or it will get a bug when user mouse down the border of window panel if it is resized. container.addClass('no-resizable'); var scrollPos = getBrowserScrollXY(); var screenWH = getBrowserScreenWH(); if( caller != null ) { var cpos = caller.offset(); var bTop = parseInt( caller.css('borderTopWidth') ); var bLeft = parseInt( caller.css('borderLeftWidth') ); targetCssStyle = { left: cpos.left + bLeft, top: cpos.top + bTop, width: caller.width(), height: caller.height(), opacity: 1 }; } else { targetCssStyle = { left: scrollPos.left, top: scrollPos.top, width: screenWH.width, height: screenWH.height, opacity: 1 }; } if( bImmediately ) { container.css(targetCssStyle); adjustHeaderTextPanelWidth(); adjustFrameWH(); header.removeClass('window_header_normal'); header.addClass('window_header_maximize'); // switch maximize, cascade button headerFuncPanel.children(".maximizeImg").hide(); headerFuncPanel.children(".cascadeImg").show(); } else { hideContent(); container.animate(targetCssStyle, setting.animationSpeed, 'swing', function() { if( $.browser.msie && caller == null ) { // in IE, must do hide scrollbar routine after animation finished hideBrowserScrollbar(); } showContent(); adjustHeaderTextPanelWidth(); adjustFrameWH(); header.removeClass('window_header_normal'); header.addClass('window_header_maximize'); // switch maximize, cascade button headerFuncPanel.children(".maximizeImg").hide(); headerFuncPanel.children(".cascadeImg").show(); // after callback if( $.isFunction(options.afterMaximize) ) { options.afterMaximize(_this); } }); container.css('z-index', options.z+3); } // before callback if( $.isFunction(options.onMaximize) ) { options.onMaximize(_this); } } function minimize() { showBrowserScrollbar(); minimized = true; container.draggable( 'disable' ); container.resizable( 'disable' ); // save current display orgPos.left = container.css("left"); orgPos.top = container.css("top"); orgWh.w = container.width(); orgWh.h = container.height(); miniStackIndex = getMinWindowLength(caller); targetCssStyle = { opacity: OPACITY_MINIMIZED }; // must add this, or it will get a bug when user mouse down the border of window panel if it is resized. container.addClass('no-resizable'); if( caller == null ) { transferToFixed(); // transfer position to fixed first } headerFuncPanel.hide(); hideContent(); // check minimized windows' size checkMinWindowSize(caller, true); _adjustMinimizedPos(false, function() { container.css('z-index', options.z); header.children("div.window_title_text").width( "100%" ); header.attr("title", options.title); header.removeClass('window_header_normal'); header.removeClass('window_header_maximize'); header.addClass('window_header_minimize'); if( setting.dock == 'left' || setting.dock == 'right' ) { header.addClass('window_header_minimize_vertical'); } if( options.showRoundCorner ) { header.removeClass('ui-corner-top'); header.addClass('ui-corner-all'); } _transformTitleText(); // bind header click event header.click(function() { if( !animating ) { restore(); } }); // after callback if( $.isFunction(options.afterMinimize) ) { options.afterMinimize(_this); } }); container.mouseover(function() { $(this).css("opacity", 1); }); container.mouseout(function() { $(this).css("opacity", OPACITY_MINIMIZED); }); // before callback if( $.isFunction(options.onMinimize) ) { options.onMinimize(_this); } // push into minimized window storage pushMinWindow(caller, _this); } function restore() { var rpos = null; var rwh = null; var zIndex = options.z+2; if( minimized ) { // from minimized status rpos = orgPos; rwh = orgWh; transferToAbsolute(); // transfer position to fixed first header.removeClass('window_header_minimize'); if( setting.dock == 'left' || setting.dock == 'right' ) { header.removeClass('window_header_minimize_vertical'); } if( maximized ) { // minimized -> maximized header.addClass('window_header_maximize'); if( caller != null ) { var cpos = caller.offset(); var bTop = parseInt( caller.css('borderTopWidth') ); var bLeft = parseInt( caller.css('borderLeftWidth') ); rpos = { left: cpos.left + bLeft, top: cpos.top + bTop }; } else { var scrollPos = getBrowserScrollXY(); rpos = { left: scrollPos.left, top: scrollPos.top }; } zIndex = options.z+3; container.css('z-index', zIndex); // change z-index before animating } else { // minimized -> cascade header.addClass('window_header_normal'); // must add this, or it will get a bug when user mouse down the border of window panel if it is resized. container.removeClass('no-resizable'); } } else if( maximized ) { // maximized -> cascade maximized = false; rpos = pos; rwh = wh; header.removeClass('window_header_maximize'); header.addClass('window_header_normal'); // must add this, or it will get a bug when user mouse down the border of window panel if it is resized. container.removeClass('no-resizable'); } restoreTitleText(); header.removeAttr("title"); header.removeClass('window_header_minimize'); if( setting.dock == 'left' || setting.dock == 'right' ) { header.removeClass('window_header_minimize_vertical'); } if( options.showRoundCorner ) { header.removeClass('ui-corner-all'); header.addClass('ui-corner-top'); } // unbind event container.unbind("mouseover"); container.unbind("mouseout"); targetCssStyle = { left: rpos.left, top: rpos.top, width: rwh.w, height: rwh.h, opacity: 1 }; hideContent(); container.animate(targetCssStyle, setting.animationSpeed, 'swing', function() { container.css('z-index', zIndex); showContent(); header.unbind('click'); adjustHeaderTextPanelWidth(); adjustFrameWH(); // switch maximize, cacade icon if( maximized ) { if( caller == null ) { hideBrowserScrollbar(); } headerFuncPanel.children(".maximizeImg").hide(); headerFuncPanel.children(".cascadeImg").show(); } else { showBrowserScrollbar(); container.draggable( 'enable' ); container.resizable( 'enable' ); headerFuncPanel.children(".maximizeImg").show(); headerFuncPanel.children(".cascadeImg").hide(); } headerFuncPanel.show(); // pop from minimized window storage if( minimized ) { minimized = false; popMinWindow(caller, _this); checkMinWindowSize(caller, false); adjustAllMinWindows(caller); // adjust minimized window position } // after callback if( $.isFunction(options.afterCascade) ) { options.afterCascade(_this); } }); // before callback if( $.isFunction(options.onCascade) ) { options.onCascade(_this); } } function close(quiet) { // do callback if( !quiet && $.isFunction(options.onClose) ) { options.onClose(_this); } destroy(); } function destroy() { redirectCheck = false; if( maximized ) { showBrowserScrollbar(); } popWindow(_this); container.remove(); } function _decreaseMiniIndex() { miniStackIndex--; } return { // instance public methods initialize: initialize, getTargetCssStyle: getTargetCssStyle, // get the css ready to change getWindowId: function() { // get window id return windowId; }, getCaller: getCaller, // get window container's parent panel, it's a jQuery object getContainer: getContainer, // get window container panel, it's a jQuery object getHeader: getHeader, // get window header panel,it's a jQuery object getFrame: getFrame, // get window frame panel, it's a jQuery object getFooter: getFooter, // get window footer panel, it's a jQuery object alignCenter: alignCenter, // set current window as screen center alignHorizontalCenter: alignHorizontalCenter, // set current window as horizontal center alignVerticalCenter: alignVerticalCenter, // set current window as vertical center select: select, // select current window, it will increase the original z-index value with 2 unselect: unselect, // unselect current window, it will set the z-index as original options.z move: move, // move current window to target position or shift it by passed distance resize: resize, // resize current window to target width/height maximize: maximize, // maximize current window minimize: minimize, // minimize current window restore: restore, // restore current window, it could be maximized or cascade status close: close, // close current window. parameter: quiet - [boolean] to decide doing callback or not setTitle: setTitle, // change window title. parameter: title - [string] window title text setUrl: setUrl, // change iframe url. parameter: url - [string] iframe url setContent: setContent, // change frame content. parameter: content - [html string, jquery object, element] the content of frame setFooterContent: setFooterContent, // change footer content. parameter: content - [html string, jquery object, element] the content of footer getTitle: getTitle, // get window title text getUrl: getUrl, // get url string getContent: getContent, // get frame html content getFooterContent: getFooterContent, // get footer html content isMaximized: function() { // get window maximized status return maximized; }, isMinimized: function() { // get window minmized status return minimized; }, isSelected: function() { // get window selected status return selected; }, // for plugin private use _decreaseMiniIndex: _decreaseMiniIndex, _adjustMinimizedPos: _adjustMinimizedPos, _setOrgWH: function(wh) { orgWh.w = wh.width; orgWh.h = wh.height; }, _transformTitleText: _transformTitleText }; } // constructor end return { // static public methods getInstance: function(caller, options) { // create new window instance var instance = constructor(caller, options); instance.initialize(instance); selectWindow(caller, instance); // set new created window instance as selected pushWindow(instance); if( caller != null ) { if( caller.get(0)._minWinData == null ) { // create the minimized window relative data caller.get(0)._minWinData = { long: setting.minWinLong, storage: [] }; } parentCallers.push(caller); } // static initialzation if( !initialized ) { // handle window resize event $(window).resize(function() { if( resizeTimer != null ) { clearTimeout(resizeTimer); } resizeTimer = window.setTimeout(function() { var screenWH = getBrowserScreenWH(); for( var i=0, len=windowStorage.length; i