blob: 570d7a2d945b40c212182e9ebfb1d336341231fb [file] [log] [blame]
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.widget.FloatingPane");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Manager");
dojo.require("dojo.html.*");
dojo.require("dojo.html.layout");
dojo.require("dojo.html.iframe");
dojo.require("dojo.html.selection");
dojo.require("dojo.lfx.shadow");
dojo.require("dojo.widget.html.layout");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.dnd.HtmlDragMove");
dojo.require("dojo.widget.Dialog"); // for ModalFloatingPane
dojo.require("dojo.widget.ResizeHandle");
dojo.declare(
"dojo.widget.FloatingPaneBase",
null,
{
// summary
// Base class for FloatingPane, ModalFloatingPane
// title: String
// text to display in floating pane's title bar (ex: "My Window")
title: '',
// iconSrc: String
// path of icon to display in floating pane's title bar
iconSrc: '',
// hasShadow: Boolean
// if true, display a shadow behind the floating pane
hasShadow: false,
// constrainToContainer: Boolean
// if true, and the floating pane is inside another container (ContentPane, another FloatingPane, etc.),
// then don't allow the floating pane to be dragged outside of it's container
constrainToContainer: false,
// taskBarId: String
// widget id of TaskBar widget;
// if specified, then an icon for this FloatingPane will be added to the specified TaskBar
taskBarId: "",
// resizable: Boolean
// if true, allow user to resize floating pane
resizable: true,
// titleBarDisplay: Boolean
// if true, display title bar for this floating pane
titleBarDisplay: true,
// windowState: String
// controls whether window is initially not displayed ("minimized"), displayed full screen ("maximized"),
// or just displayed normally ("normal").
// Values
// "normal", "maximized", "minimized"
windowState: "normal",
// displayCloseAction: Boolean
// display button to close window
displayCloseAction: false,
// displayMinimizeAction: Boolean
// display button to minimize window (ie, window disappears so only the taskbar item remains)
displayMinimizeAction: false,
// displayMaximizeAction: Boolean
// display button to maximize window (ie, to take up the full screen)
displayMaximizeAction: false,
// Related to connecting to taskbar
// TODO: use topics rather than repeated connect attempts?
_max_taskBarConnectAttempts: 5,
_taskBarConnectAttempts: 0,
templatePath: dojo.uri.dojoUri("src/widget/templates/FloatingPane.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/FloatingPane.css"),
fillInFloatingPaneTemplate: function(args, frag){
// summary: this should be called by fillInTemplate() of the widget that I'm mixed into
// Copy style info from input node to output node
var source = this.getFragNodeRef(frag);
dojo.html.copyStyle(this.domNode, source);
// necessary for safari, khtml (for computing width/height)
dojo.body().appendChild(this.domNode);
// if display:none then state=minimized, otherwise state=normal
if(!this.isShowing()){
this.windowState="minimized";
}
// <img src=""> can hang IE! better get rid of it
if(this.iconSrc==""){
dojo.html.removeNode(this.titleBarIcon);
}else{
this.titleBarIcon.src = this.iconSrc.toString();// dojo.uri.Uri obj req. toString()
}
if(this.titleBarDisplay){
this.titleBar.style.display="";
dojo.html.disableSelection(this.titleBar);
this.titleBarIcon.style.display = (this.iconSrc=="" ? "none" : "");
this.minimizeAction.style.display = (this.displayMinimizeAction ? "" : "none");
this.maximizeAction.style.display=
(this.displayMaximizeAction && this.windowState!="maximized" ? "" : "none");
this.restoreAction.style.display=
(this.displayMaximizeAction && this.windowState=="maximized" ? "" : "none");
this.closeAction.style.display= (this.displayCloseAction ? "" : "none");
this.drag = new dojo.dnd.HtmlDragMoveSource(this.domNode);
if (this.constrainToContainer) {
this.drag.constrainTo();
}
this.drag.setDragHandle(this.titleBar);
var self = this;
dojo.event.topic.subscribe("dragMove",
function (info){
if (info.source.domNode == self.domNode){
dojo.event.topic.publish('floatingPaneMove', { source: self } );
}
}
);
}
if(this.resizable){
this.resizeBar.style.display="";
this.resizeHandle = dojo.widget.createWidget("ResizeHandle", {targetElmId: this.widgetId, id:this.widgetId+"_resize"});
this.resizeBar.appendChild(this.resizeHandle.domNode);
}
// add a drop shadow
if(this.hasShadow){
this.shadow=new dojo.lfx.shadow(this.domNode);
}
// Prevent IE bleed-through problem
this.bgIframe = new dojo.html.BackgroundIframe(this.domNode);
if( this.taskBarId ){
this._taskBarSetup();
}
// counteract body.appendChild above
dojo.body().removeChild(this.domNode);
},
postCreate: function(){
if (dojo.hostenv.post_load_) {
this._setInitialWindowState();
} else {
dojo.addOnLoad(this, "_setInitialWindowState");
}
},
maximizeWindow: function(/*Event*/ evt) {
// summary: maximize the window
var mb = dojo.html.getMarginBox(this.domNode);
this.previous={
width: mb.width || this.width,
height: mb.height || this.height,
left: this.domNode.style.left,
top: this.domNode.style.top,
bottom: this.domNode.style.bottom,
right: this.domNode.style.right
};
if(this.domNode.parentNode.style.overflow.toLowerCase() != 'hidden'){
this.parentPrevious={
overflow: this.domNode.parentNode.style.overflow
};
dojo.debug(this.domNode.parentNode.style.overflow);
this.domNode.parentNode.style.overflow = 'hidden';
}
this.domNode.style.left =
dojo.html.getPixelValue(this.domNode.parentNode, "padding-left", true) + "px";
this.domNode.style.top =
dojo.html.getPixelValue(this.domNode.parentNode, "padding-top", true) + "px";
if ((this.domNode.parentNode.nodeName.toLowerCase() == 'body')) {
var viewport = dojo.html.getViewport();
var padding = dojo.html.getPadding(dojo.body());
this.resizeTo(viewport.width-padding.width, viewport.height-padding.height);
} else {
var content = dojo.html.getContentBox(this.domNode.parentNode);
this.resizeTo(content.width, content.height);
}
this.maximizeAction.style.display="none";
this.restoreAction.style.display="";
//disable resize and drag
if(this.resizeHandle){
this.resizeHandle.domNode.style.display="none";
}
this.drag.setDragHandle(null);
this.windowState="maximized";
},
minimizeWindow: function(/*Event*/ evt) {
// summary: hide the window so that only the icon in the taskbar is shown
this.hide();
for(var attr in this.parentPrevious){
this.domNode.parentNode.style[attr] = this.parentPrevious[attr];
}
this.lastWindowState = this.windowState;
this.windowState = "minimized";
},
restoreWindow: function(/*Event*/ evt) {
// summary: set the winow to normal size (neither maximized nor minimized)
if (this.windowState=="minimized") {
this.show();
if(this.lastWindowState == "maximized"){
this.domNode.parentNode.style.overflow = 'hidden';
this.windowState="maximized";
}else{ //normal
this.windowState="normal";
}
} else if (this.windowState=="maximized"){
for(var attr in this.previous){
this.domNode.style[attr] = this.previous[attr];
}
for(var attr in this.parentPrevious){
this.domNode.parentNode.style[attr] = this.parentPrevious[attr];
}
this.resizeTo(this.previous.width, this.previous.height);
this.previous=null;
this.parentPrevious=null;
this.restoreAction.style.display="none";
this.maximizeAction.style.display=this.displayMaximizeAction ? "" : "none";
if(this.resizeHandle){
this.resizeHandle.domNode.style.display="";
}
this.drag.setDragHandle(this.titleBar);
this.windowState="normal";
} else { //normal
// do nothing
}
},
toggleDisplay: function(){
// summary: switch between hidden mode and displayed mode (either maximized or normal, depending on state before window was minimized)
if(this.windowState=="minimized"){
this.restoreWindow();
}else{
this.minimizeWindow();
}
},
closeWindow: function(/*Event*/ evt) {
// summary: destroy this window
dojo.html.removeNode(this.domNode);
this.destroy();
},
onMouseDown: function(/*Event*/ evt) {
// summary: callback when user clicks anywhere on the floating pane
this.bringToTop();
},
bringToTop: function() {
// summary
// all the floating panes are stacked in z-index order; bring this floating pane to the top of that stack,
// so that it's displayed in front of all the other floating panes
var floatingPanes= dojo.widget.manager.getWidgetsByType(this.widgetType);
var windows = [];
for (var x=0; x<floatingPanes.length; x++) {
if (this.widgetId != floatingPanes[x].widgetId) {
windows.push(floatingPanes[x]);
}
}
windows.sort(function(a,b) {
return a.domNode.style.zIndex - b.domNode.style.zIndex;
});
windows.push(this);
var floatingPaneStartingZ = 100;
for (x=0; x<windows.length;x++) {
windows[x].domNode.style.zIndex = floatingPaneStartingZ + x*2;
}
},
_setInitialWindowState: function() {
if(this.isShowing()){
this.width=-1; // force resize
var mb = dojo.html.getMarginBox(this.domNode);
this.resizeTo(mb.width, mb.height);
}
if (this.windowState == "maximized") {
this.maximizeWindow();
this.show();
return;
}
if (this.windowState=="normal") {
this.show();
return;
}
if (this.windowState=="minimized") {
this.hide();
return;
}
this.windowState="minimized";
},
_taskBarSetup: function() {
// summary: add icon to task bar, connected to me
var taskbar = dojo.widget.getWidgetById(this.taskBarId);
if (!taskbar){
if (this._taskBarConnectAttempts < this._max_taskBarConnectAttempts) {
dojo.lang.setTimeout(this, this._taskBarSetup, 50);
this._taskBarConnectAttempts++;
} else {
dojo.debug("Unable to connect to the taskBar");
}
return;
}
taskbar.addChild(this);
},
showFloatingPane: function(){
// summary:
// bring this floating pane to the top
this.bringToTop();
},
onFloatingPaneShow: function(){
// summary: callback for when someone calls FloatingPane.show
var mb = dojo.html.getMarginBox(this.domNode);
this.resizeTo(mb.width, mb.height);
},
// summary: set the floating pane to the given size
resizeTo: function(/*Integer*/ width, /*Integer*/ height){
dojo.html.setMarginBox(this.domNode, { width: width, height: height });
dojo.widget.html.layout(this.domNode,
[
{domNode: this.titleBar, layoutAlign: "top"},
{domNode: this.resizeBar, layoutAlign: "bottom"},
{domNode: this.containerNode, layoutAlign: "client"}
] );
// If any of the children have layoutAlign specified, obey it
dojo.widget.html.layout(this.containerNode, this.children, "top-bottom");
this.bgIframe.onResized();
if(this.shadow){ this.shadow.size(width, height); }
this.onResized();
},
checkSize: function() {
// summary
// checkSize() is called when the user has resized the browser window,
// but that doesn't affect this widget (or this widget's children)
// so it can be safely ignored...
// TODO: unless we are maximized. then we should resize ourself.
},
destroyFloatingPane: function() {
if(this.resizeHandle){
this.resizeHandle.destroy();
this.resizeHandle = null;
}
}
}
);
dojo.widget.defineWidget(
"dojo.widget.FloatingPane",
[dojo.widget.ContentPane, dojo.widget.FloatingPaneBase],
{
// summary
// A non-modal floating window.
// Attaches to a Taskbar which has an icon for each window.
// Must specify size (like style="width: 500px; height: 500px;"),
fillInTemplate: function(args, frag){
this.fillInFloatingPaneTemplate(args, frag);
dojo.widget.FloatingPane.superclass.fillInTemplate.call(this, args, frag);
},
postCreate: function(){
dojo.widget.FloatingPaneBase.prototype.postCreate.apply(this, arguments);
dojo.widget.FloatingPane.superclass.postCreate.apply(this, arguments);
},
show: function(){
dojo.widget.FloatingPane.superclass.show.apply(this, arguments);
this.showFloatingPane();
},
onShow: function(){
dojo.widget.FloatingPane.superclass.onShow.call(this);
this.onFloatingPaneShow();
},
destroy: function(){
this.destroyFloatingPane();
dojo.widget.FloatingPane.superclass.destroy.apply(this, arguments);
}
});
dojo.widget.defineWidget(
"dojo.widget.ModalFloatingPane",
[dojo.widget.FloatingPane, dojo.widget.ModalDialogBase],
{
// summary
// A modal floating window.
// This widget is similar to the Dialog widget, but the window, unlike the Dialog, can be moved.
// Must specify size (like style="width: 500px; height: 500px;"),
windowState: "minimized",
displayCloseAction: true,
postCreate: function(){
dojo.widget.ModalDialogBase.prototype.postCreate.call(this);
dojo.widget.ModalFloatingPane.superclass.postCreate.call(this);
},
show: function(){
this.showModalDialog();
dojo.widget.ModalFloatingPane.superclass.show.apply(this, arguments);
//place the background div under this modal pane
this.bg.style.zIndex = this.domNode.style.zIndex-1;
},
hide: function(){
this.hideModalDialog();
dojo.widget.ModalFloatingPane.superclass.hide.apply(this, arguments);
},
closeWindow: function(){
this.hide();
dojo.widget.ModalFloatingPane.superclass.closeWindow.apply(this, arguments);
}
}
);