/trunk/api/js/dojo1.0/dijit/layout/StackContainer.js |
---|
New file |
0,0 → 1,451 |
if(!dojo._hasResource["dijit.layout.StackContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout.StackContainer"] = true; |
dojo.provide("dijit.layout.StackContainer"); |
dojo.require("dijit._Templated"); |
dojo.require("dijit.layout._LayoutWidget"); |
dojo.require("dijit.form.Button"); |
dojo.declare( |
"dijit.layout.StackContainer", |
dijit.layout._LayoutWidget, |
// summary |
// A container that has multiple children, but shows only |
// one child at a time (like looking at the pages in a book one by one). |
// |
// Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild |
// |
// Can be base class for container, Wizard, Show, etc. |
{ |
// doLayout: Boolean |
// if true, change the size of my currently displayed child to match my size |
doLayout: true, |
_started: false, |
// selectedChildWidget: Widget |
// References the currently selected child widget, if any |
postCreate: function(){ |
dijit.setWaiRole((this.containerNode || this.domNode), "tabpanel"); |
this.connect(this.domNode, "onkeypress", this._onKeyPress); |
}, |
startup: function(){ |
if(this._started){ return; } |
var children = this.getChildren(); |
// Setup each page panel |
dojo.forEach(children, this._setupChild, this); |
// Figure out which child to initially display |
dojo.some(children, function(child){ |
if(child.selected){ |
this.selectedChildWidget = child; |
} |
return child.selected; |
}, this); |
var selected = this.selectedChildWidget; |
// Default to the first child |
if(!selected && children[0]){ |
selected = this.selectedChildWidget = children[0]; |
selected.selected = true; |
} |
if(selected){ |
this._showChild(selected); |
} |
// Now publish information about myself so any StackControllers can initialize.. |
dojo.publish(this.id+"-startup", [{children: children, selected: selected}]); |
this.inherited("startup",arguments); |
this._started = true; |
}, |
_setupChild: function(/*Widget*/ page){ |
// Summary: prepare the given child |
page.domNode.style.display = "none"; |
// since we are setting the width/height of the child elements, they need |
// to be position:relative, or IE has problems (See bug #2033) |
page.domNode.style.position = "relative"; |
return page; // dijit._Widget |
}, |
addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){ |
// summary: Adds a widget to the stack |
dijit._Container.prototype.addChild.apply(this, arguments); |
child = this._setupChild(child); |
if(this._started){ |
// in case the tab titles have overflowed from one line to two lines |
this.layout(); |
dojo.publish(this.id+"-addChild", [child, insertIndex]); |
// if this is the first child, then select it |
if(!this.selectedChildWidget){ |
this.selectChild(child); |
} |
} |
}, |
removeChild: function(/*Widget*/ page){ |
// summary: Removes the pane from the stack |
dijit._Container.prototype.removeChild.apply(this, arguments); |
// If we are being destroyed than don't run the code below (to select another page), because we are deleting |
// every page one by one |
if(this._beingDestroyed){ return; } |
if(this._started){ |
// this will notify any tablists to remove a button; do this first because it may affect sizing |
dojo.publish(this.id+"-removeChild", [page]); |
// in case the tab titles now take up one line instead of two lines |
this.layout(); |
} |
if(this.selectedChildWidget === page){ |
this.selectedChildWidget = undefined; |
if(this._started){ |
var children = this.getChildren(); |
if(children.length){ |
this.selectChild(children[0]); |
} |
} |
} |
}, |
selectChild: function(/*Widget*/ page){ |
// summary: |
// Show the given widget (which must be one of my children) |
page = dijit.byId(page); |
if(this.selectedChildWidget != page){ |
// Deselect old page and select new one |
this._transition(page, this.selectedChildWidget); |
this.selectedChildWidget = page; |
dojo.publish(this.id+"-selectChild", [page]); |
} |
}, |
_transition: function(/*Widget*/newWidget, /*Widget*/oldWidget){ |
if(oldWidget){ |
this._hideChild(oldWidget); |
} |
this._showChild(newWidget); |
// Size the new widget, in case this is the first time it's being shown, |
// or I have been resized since the last time it was shown. |
// page must be visible for resizing to work |
if(this.doLayout && newWidget.resize){ |
newWidget.resize(this._containerContentBox || this._contentBox); |
} |
}, |
_adjacent: function(/*Boolean*/ forward){ |
// summary: Gets the next/previous child widget in this container from the current selection |
var children = this.getChildren(); |
var index = dojo.indexOf(children, this.selectedChildWidget); |
index += forward ? 1 : children.length - 1; |
return children[ index % children.length ]; // dijit._Widget |
}, |
forward: function(){ |
// Summary: advance to next page |
this.selectChild(this._adjacent(true)); |
}, |
back: function(){ |
// Summary: go back to previous page |
this.selectChild(this._adjacent(false)); |
}, |
_onKeyPress: function(e){ |
dojo.publish(this.id+"-containerKeyPress", [{ e: e, page: this}]); |
}, |
layout: function(){ |
if(this.doLayout && this.selectedChildWidget && this.selectedChildWidget.resize){ |
this.selectedChildWidget.resize(this._contentBox); |
} |
}, |
_showChild: function(/*Widget*/ page){ |
var children = this.getChildren(); |
page.isFirstChild = (page == children[0]); |
page.isLastChild = (page == children[children.length-1]); |
page.selected = true; |
page.domNode.style.display=""; |
if(page._loadCheck){ |
page._loadCheck(); // trigger load in ContentPane |
} |
if(page.onShow){ |
page.onShow(); |
} |
}, |
_hideChild: function(/*Widget*/ page){ |
page.selected=false; |
page.domNode.style.display="none"; |
if(page.onHide){ |
page.onHide(); |
} |
}, |
closeChild: function(/*Widget*/ page){ |
// summary |
// callback when user clicks the [X] to remove a page |
// if onClose() returns true then remove and destroy the childd |
var remove = page.onClose(this, page); |
if(remove){ |
this.removeChild(page); |
// makes sure we can clean up executeScripts in ContentPane onUnLoad |
page.destroy(); |
} |
}, |
destroy: function(){ |
this._beingDestroyed = true; |
this.inherited("destroy",arguments); |
} |
}); |
dojo.declare( |
"dijit.layout.StackController", |
[dijit._Widget, dijit._Templated, dijit._Container], |
{ |
// summary: |
// Set of buttons to select a page in a page list. |
// Monitors the specified StackContainer, and whenever a page is |
// added, deleted, or selected, updates itself accordingly. |
templateString: "<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>", |
// containerId: String |
// the id of the page container that I point to |
containerId: "", |
// buttonWidget: String |
// the name of the button widget to create to correspond to each page |
buttonWidget: "dijit.layout._StackButton", |
postCreate: function(){ |
dijit.setWaiRole(this.domNode, "tablist"); |
this.pane2button = {}; // mapping from panes to buttons |
this._subscriptions=[ |
dojo.subscribe(this.containerId+"-startup", this, "onStartup"), |
dojo.subscribe(this.containerId+"-addChild", this, "onAddChild"), |
dojo.subscribe(this.containerId+"-removeChild", this, "onRemoveChild"), |
dojo.subscribe(this.containerId+"-selectChild", this, "onSelectChild"), |
dojo.subscribe(this.containerId+"-containerKeyPress", this, "onContainerKeyPress") |
]; |
}, |
onStartup: function(/*Object*/ info){ |
// summary: called after StackContainer has finished initializing |
dojo.forEach(info.children, this.onAddChild, this); |
this.onSelectChild(info.selected); |
}, |
destroy: function(){ |
dojo.forEach(this._subscriptions, dojo.unsubscribe); |
this.inherited("destroy",arguments); |
}, |
onAddChild: function(/*Widget*/ page, /*Integer?*/ insertIndex){ |
// summary: |
// Called whenever a page is added to the container. |
// Create button corresponding to the page. |
// add a node that will be promoted to the button widget |
var refNode = document.createElement("span"); |
this.domNode.appendChild(refNode); |
// create an instance of the button widget |
var cls = dojo.getObject(this.buttonWidget); |
var button = new cls({label: page.title, closeButton: page.closable}, refNode); |
this.addChild(button, insertIndex); |
this.pane2button[page] = button; |
page.controlButton = button; // this value might be overwritten if two tabs point to same container |
dojo.connect(button, "onClick", dojo.hitch(this,"onButtonClick",page)); |
dojo.connect(button, "onClickCloseButton", dojo.hitch(this,"onCloseButtonClick",page)); |
if(!this._currentChild){ // put the first child into the tab order |
button.focusNode.setAttribute("tabIndex","0"); |
this._currentChild = page; |
} |
}, |
onRemoveChild: function(/*Widget*/ page){ |
// summary: |
// Called whenever a page is removed from the container. |
// Remove the button corresponding to the page. |
if(this._currentChild === page){ this._currentChild = null; } |
var button = this.pane2button[page]; |
if(button){ |
// TODO? if current child { reassign } |
button.destroy(); |
} |
this.pane2button[page] = null; |
}, |
onSelectChild: function(/*Widget*/ page){ |
// summary: |
// Called when a page has been selected in the StackContainer, either by me or by another StackController |
if(!page){ return; } |
if(this._currentChild){ |
var oldButton=this.pane2button[this._currentChild]; |
oldButton.setChecked(false); |
oldButton.focusNode.setAttribute("tabIndex", "-1"); |
} |
var newButton=this.pane2button[page]; |
newButton.setChecked(true); |
this._currentChild = page; |
newButton.focusNode.setAttribute("tabIndex", "0"); |
}, |
onButtonClick: function(/*Widget*/ page){ |
// summary: |
// Called whenever one of my child buttons is pressed in an attempt to select a page |
var container = dijit.byId(this.containerId); // TODO: do this via topics? |
container.selectChild(page); |
}, |
onCloseButtonClick: function(/*Widget*/ page){ |
// summary: |
// Called whenever one of my child buttons [X] is pressed in an attempt to close a page |
var container = dijit.byId(this.containerId); |
container.closeChild(page); |
var b = this.pane2button[this._currentChild]; |
if(b){ |
dijit.focus(b.focusNode || b.domNode); |
} |
}, |
// TODO: this is a bit redundant with forward, back api in StackContainer |
adjacent: function(/*Boolean*/ forward){ |
// find currently focused button in children array |
var children = this.getChildren(); |
var current = dojo.indexOf(children, this.pane2button[this._currentChild]); |
// pick next button to focus on |
var offset = forward ? 1 : children.length - 1; |
return children[ (current + offset) % children.length ]; // dijit._Widget |
}, |
onkeypress: function(/*Event*/ e){ |
// summary: |
// Handle keystrokes on the page list, for advancing to next/previous button |
// and closing the current page if the page is closable. |
if(this.disabled || e.altKey ){ return; } |
var forward = true; |
if(e.ctrlKey || !e._djpage){ |
var k = dojo.keys; |
switch(e.keyCode){ |
case k.LEFT_ARROW: |
case k.UP_ARROW: |
case k.PAGE_UP: |
forward = false; |
// fall through |
case k.RIGHT_ARROW: |
case k.DOWN_ARROW: |
case k.PAGE_DOWN: |
this.adjacent(forward).onClick(); |
dojo.stopEvent(e); |
break; |
case k.DELETE: |
if(this._currentChild.closable){ |
this.onCloseButtonClick(this._currentChild); |
} |
dojo.stopEvent(e); |
break; |
default: |
if(e.ctrlKey){ |
if(e.keyCode == k.TAB){ |
this.adjacent(!e.shiftKey).onClick(); |
dojo.stopEvent(e); |
}else if(e.keyChar == "w"){ |
if(this._currentChild.closable){ |
this.onCloseButtonClick(this._currentChild); |
} |
dojo.stopEvent(e); // avoid browser tab closing. |
} |
} |
} |
} |
}, |
onContainerKeyPress: function(/*Object*/ info){ |
info.e._djpage = info.page; |
this.onkeypress(info.e); |
} |
}); |
dojo.declare("dijit.layout._StackButton", |
dijit.form.ToggleButton, |
{ |
// summary |
// Internal widget used by StackContainer. |
// The button-like or tab-like object you click to select or delete a page |
tabIndex: "-1", // StackContainer buttons are not in the tab order by default |
postCreate: function(/*Event*/ evt){ |
dijit.setWaiRole((this.focusNode || this.domNode), "tab"); |
this.inherited("postCreate", arguments); |
}, |
onClick: function(/*Event*/ evt){ |
// summary: This is for TabContainer where the tabs are <span> rather than button, |
// so need to set focus explicitly (on some browsers) |
dijit.focus(this.focusNode); |
// ... now let StackController catch the event and tell me what to do |
}, |
onClickCloseButton: function(/*Event*/ evt){ |
// summary |
// StackContainer connects to this function; if your widget contains a close button |
// then clicking it should call this function. |
evt.stopPropagation(); |
} |
}); |
// These arguments can be specified for the children of a StackContainer. |
// Since any widget can be specified as a StackContainer child, mix them |
// into the base widget class. (This is a hack, but it's effective.) |
dojo.extend(dijit._Widget, { |
// title: String |
// Title of this widget. Used by TabContainer to the name the tab, etc. |
title: "", |
// selected: Boolean |
// Is this child currently selected? |
selected: false, |
// closable: Boolean |
// True if user can close (destroy) this child, such as (for example) clicking the X on the tab. |
closable: false, // true if user can close this tab pane |
onClose: function(){ |
// summary: Callback if someone tries to close the child, child will be closed if func returns true |
return true; |
} |
}); |
} |
/trunk/api/js/dojo1.0/dijit/layout/TabContainer.js |
---|
New file |
0,0 → 1,146 |
if(!dojo._hasResource["dijit.layout.TabContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout.TabContainer"] = true; |
dojo.provide("dijit.layout.TabContainer"); |
dojo.require("dijit.layout.StackContainer"); |
dojo.require("dijit._Templated"); |
dojo.declare("dijit.layout.TabContainer", |
[dijit.layout.StackContainer, dijit._Templated], |
{ |
// summary: |
// A Container with Title Tabs, each one pointing at a pane in the container. |
// description: |
// A TabContainer is a container that has multiple panes, but shows only |
// one pane at a time. There are a set of tabs corresponding to each pane, |
// where each tab has the title (aka title) of the pane, and optionally a close button. |
// |
// Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild |
// (where <widgetId> is the id of the TabContainer itself. |
// |
// tabPosition: String |
// Defines where tabs go relative to tab content. |
// "top", "bottom", "left-h", "right-h" |
tabPosition: "top", |
templateString: null, // override setting in StackContainer |
templateString:"<div class=\"dijitTabContainer\">\n\t<div dojoAttachPoint=\"tablistNode\"></div>\n\t<div class=\"dijitTabPaneWrapper\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n", |
postCreate: function(){ |
dijit.layout.TabContainer.superclass.postCreate.apply(this, arguments); |
// create the tab list that will have a tab (a.k.a. tab button) for each tab panel |
this.tablist = new dijit.layout.TabController( |
{ |
id: this.id + "_tablist", |
tabPosition: this.tabPosition, |
doLayout: this.doLayout, |
containerId: this.id |
}, this.tablistNode); |
}, |
_setupChild: function(/* Widget */tab){ |
dojo.addClass(tab.domNode, "dijitTabPane"); |
this.inherited("_setupChild",arguments); |
return tab; // Widget |
}, |
startup: function(){ |
if(this._started){ return; } |
// wire up the tablist and its tabs |
this.tablist.startup(); |
this.inherited("startup",arguments); |
if(dojo.isSafari){ |
// sometimes safari 3.0.3 miscalculates the height of the tab labels, see #4058 |
setTimeout(dojo.hitch(this, "layout"), 0); |
} |
}, |
layout: function(){ |
// Summary: Configure the content pane to take up all the space except for where the tabs are |
if(!this.doLayout){ return; } |
// position and size the titles and the container node |
var titleAlign=this.tabPosition.replace(/-h/,""); |
var children = [ |
{domNode: this.tablist.domNode, layoutAlign: titleAlign}, |
{domNode: this.containerNode, layoutAlign: "client"} |
]; |
dijit.layout.layoutChildren(this.domNode, this._contentBox, children); |
// Compute size to make each of my children. |
// children[1] is the margin-box size of this.containerNode, set by layoutChildren() call above |
this._containerContentBox = dijit.layout.marginBox2contentBox(this.containerNode, children[1]); |
if(this.selectedChildWidget){ |
this._showChild(this.selectedChildWidget); |
if(this.doLayout && this.selectedChildWidget.resize){ |
this.selectedChildWidget.resize(this._containerContentBox); |
} |
} |
}, |
destroy: function(){ |
this.tablist.destroy(); |
this.inherited("destroy",arguments); |
} |
}); |
//TODO: make private? |
dojo.declare("dijit.layout.TabController", |
dijit.layout.StackController, |
{ |
// summary: |
// Set of tabs (the things with titles and a close button, that you click to show a tab panel). |
// description: |
// Lets the user select the currently shown pane in a TabContainer or StackContainer. |
// TabController also monitors the TabContainer, and whenever a pane is |
// added or deleted updates itself accordingly. |
templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>", |
// tabPosition: String |
// Defines where tabs go relative to the content. |
// "top", "bottom", "left-h", "right-h" |
tabPosition: "top", |
// doLayout: Boolean |
// TODOC: deprecate doLayout? not sure. |
doLayout: true, |
// buttonWidget: String |
// the name of the tab widget to create to correspond to each page |
buttonWidget: "dijit.layout._TabButton", |
postMixInProperties: function(){ |
this["class"] = "dijitTabLabels-" + this.tabPosition + (this.doLayout ? "" : " dijitTabNoLayout"); |
this.inherited("postMixInProperties",arguments); |
} |
}); |
dojo.declare("dijit.layout._TabButton", |
dijit.layout._StackButton, |
{ |
// summary: |
// A tab (the thing you click to select a pane). |
// description: |
// Contains the title of the pane, and optionally a close-button to destroy the pane. |
// This is an internal widget and should not be instantiated directly. |
baseClass: "dijitTab", |
templateString:"<div dojoAttachEvent='onclick:onClick,onmouseenter:_onMouse,onmouseleave:_onMouse'>\n <div class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n <span dojoAttachPoint='containerNode,focusNode'>${!label}</span>\n <span dojoAttachPoint='closeButtonNode' class='closeImage' dojoAttachEvent='onmouseenter:_onMouse, onmouseleave:_onMouse, onclick:onClickCloseButton' stateModifier='CloseButton'>\n <span dojoAttachPoint='closeText' class='closeText'>x</span>\n </span>\n </div>\n</div>\n", |
postCreate: function(){ |
if(this.closeButton){ |
dojo.addClass(this.innerDiv, "dijitClosable"); |
} else { |
this.closeButtonNode.style.display="none"; |
} |
this.inherited("postCreate",arguments); |
dojo.setSelectable(this.containerNode, false); |
} |
}); |
} |
/trunk/api/js/dojo1.0/dijit/layout/ContentPane.js |
---|
New file |
0,0 → 1,409 |
if(!dojo._hasResource["dijit.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout.ContentPane"] = true; |
dojo.provide("dijit.layout.ContentPane"); |
dojo.require("dijit._Widget"); |
dojo.require("dijit.layout._LayoutWidget"); |
dojo.require("dojo.parser"); |
dojo.require("dojo.string"); |
dojo.requireLocalization("dijit", "loading", null, "ko,zh,ja,zh-tw,ru,it,ROOT,hu,fr,pt,pl,es,de,cs"); |
dojo.declare( |
"dijit.layout.ContentPane", |
dijit._Widget, |
{ |
// summary: |
// A widget that acts as a Container for other widgets, and includes a ajax interface |
// description: |
// A widget that can be used as a standalone widget |
// or as a baseclass for other widgets |
// Handles replacement of document fragment using either external uri or javascript |
// generated markup or DOM content, instantiating widgets within that content. |
// Don't confuse it with an iframe, it only needs/wants document fragments. |
// It's useful as a child of LayoutContainer, SplitContainer, or TabContainer. |
// But note that those classes can contain any widget as a child. |
// example: |
// Some quick samples: |
// To change the innerHTML use .setContent('<b>new content</b>') |
// |
// Or you can send it a NodeList, .setContent(dojo.query('div [class=selected]', userSelection)) |
// please note that the nodes in NodeList will copied, not moved |
// |
// To do a ajax update use .setHref('url') |
// |
// href: String |
// The href of the content that displays now. |
// Set this at construction if you want to load data externally when the |
// pane is shown. (Set preload=true to load it immediately.) |
// Changing href after creation doesn't have any effect; see setHref(); |
href: "", |
// extractContent: Boolean |
// Extract visible content from inside of <body> .... </body> |
extractContent: false, |
// parseOnLoad: Boolean |
// parse content and create the widgets, if any |
parseOnLoad: true, |
// preventCache: Boolean |
// Cache content retreived externally |
preventCache: false, |
// preload: Boolean |
// Force load of data even if pane is hidden. |
preload: false, |
// refreshOnShow: Boolean |
// Refresh (re-download) content when pane goes from hidden to shown |
refreshOnShow: false, |
// loadingMessage: String |
// Message that shows while downloading |
loadingMessage: "<span class='dijitContentPaneLoading'>${loadingState}</span>", |
// errorMessage: String |
// Message that shows if an error occurs |
errorMessage: "<span class='dijitContentPaneError'>${errorState}</span>", |
// isLoaded: Boolean |
// Tells loading status see onLoad|onUnload for event hooks |
isLoaded: false, |
// class: String |
// Class name to apply to ContentPane dom nodes |
"class": "dijitContentPane", |
postCreate: function(){ |
// remove the title attribute so it doesn't show up when i hover |
// over a node |
this.domNode.title = ""; |
if(this.preload){ |
this._loadCheck(); |
} |
var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang); |
this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages); |
this.errorMessage = dojo.string.substitute(this.errorMessage, messages); |
// for programatically created ContentPane (with <span> tag), need to muck w/CSS |
// or it's as though overflow:visible is set |
dojo.addClass(this.domNode, this["class"]); |
}, |
startup: function(){ |
if(this._started){ return; } |
this._checkIfSingleChild(); |
if(this._singleChild){ |
this._singleChild.startup(); |
} |
this._loadCheck(); |
this._started = true; |
}, |
_checkIfSingleChild: function(){ |
// summary: |
// Test if we have exactly one widget as a child, and if so assume that we are a container for that widget, |
// and should propogate startup() and resize() calls to it. |
var childNodes = dojo.query(">", this.containerNode || this.domNode), |
childWidgets = childNodes.filter("[widgetId]"); |
if(childNodes.length == 1 && childWidgets.length == 1){ |
this.isContainer = true; |
this._singleChild = dijit.byNode(childWidgets[0]); |
}else{ |
delete this.isContainer; |
delete this._singleChild; |
} |
}, |
refresh: function(){ |
// summary: |
// Force a refresh (re-download) of content, be sure to turn off cache |
// we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane |
return this._prepareLoad(true); |
}, |
setHref: function(/*String|Uri*/ href){ |
// summary: |
// Reset the (external defined) content of this pane and replace with new url |
// Note: It delays the download until widget is shown if preload is false |
// href: |
// url to the page you want to get, must be within the same domain as your mainpage |
this.href = href; |
// we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane |
return this._prepareLoad(); |
}, |
setContent: function(/*String|DomNode|Nodelist*/data){ |
// summary: |
// Replaces old content with data content, include style classes from old content |
// data: |
// the new Content may be String, DomNode or NodeList |
// |
// if data is a NodeList (or an array of nodes) nodes are copied |
// so you can import nodes from another document implicitly |
// clear href so we cant run refresh and clear content |
// refresh should only work if we downloaded the content |
if(!this._isDownloaded){ |
this.href = ""; |
this._onUnloadHandler(); |
} |
this._setContent(data || ""); |
this._isDownloaded = false; // must be set after _setContent(..), pathadjust in dojox.layout.ContentPane |
if(this.parseOnLoad){ |
this._createSubWidgets(); |
} |
this._checkIfSingleChild(); |
if(this._singleChild && this._singleChild.resize){ |
this._singleChild.resize(this._contentBox); |
} |
this._onLoadHandler(); |
}, |
cancel: function(){ |
// summary: |
// Cancels a inflight download of content |
if(this._xhrDfd && (this._xhrDfd.fired == -1)){ |
this._xhrDfd.cancel(); |
} |
delete this._xhrDfd; // garbage collect |
}, |
destroy: function(){ |
// if we have multiple controllers destroying us, bail after the first |
if(this._beingDestroyed){ |
return; |
} |
// make sure we call onUnload |
this._onUnloadHandler(); |
this._beingDestroyed = true; |
this.inherited("destroy",arguments); |
}, |
resize: function(size){ |
dojo.marginBox(this.domNode, size); |
// Compute content box size in case we [later] need to size child |
// If either height or width wasn't specified by the user, then query node for it. |
// But note that setting the margin box and then immediately querying dimensions may return |
// inaccurate results, so try not to depend on it. |
var node = this.containerNode || this.domNode, |
mb = dojo.mixin(dojo.marginBox(node), size||{}); |
this._contentBox = dijit.layout.marginBox2contentBox(node, mb); |
// If we have a single widget child then size it to fit snugly within my borders |
if(this._singleChild && this._singleChild.resize){ |
this._singleChild.resize(this._contentBox); |
} |
}, |
_prepareLoad: function(forceLoad){ |
// sets up for a xhrLoad, load is deferred until widget onShow |
// cancels a inflight download |
this.cancel(); |
this.isLoaded = false; |
this._loadCheck(forceLoad); |
}, |
_loadCheck: function(forceLoad){ |
// call this when you change onShow (onSelected) status when selected in parent container |
// it's used as a trigger for href download when this.domNode.display != 'none' |
// sequence: |
// if no href -> bail |
// forceLoad -> always load |
// this.preload -> load when download not in progress, domNode display doesn't matter |
// this.refreshOnShow -> load when download in progress bails, domNode display !='none' AND |
// this.open !== false (undefined is ok), isLoaded doesn't matter |
// else -> load when download not in progress, if this.open !== false (undefined is ok) AND |
// domNode display != 'none', isLoaded must be false |
var displayState = ((this.open !== false) && (this.domNode.style.display != 'none')); |
if(this.href && |
(forceLoad || |
(this.preload && !this._xhrDfd) || |
(this.refreshOnShow && displayState && !this._xhrDfd) || |
(!this.isLoaded && displayState && !this._xhrDfd) |
) |
){ |
this._downloadExternalContent(); |
} |
}, |
_downloadExternalContent: function(){ |
this._onUnloadHandler(); |
// display loading message |
this._setContent( |
this.onDownloadStart.call(this) |
); |
var self = this; |
var getArgs = { |
preventCache: (this.preventCache || this.refreshOnShow), |
url: this.href, |
handleAs: "text" |
}; |
if(dojo.isObject(this.ioArgs)){ |
dojo.mixin(getArgs, this.ioArgs); |
} |
var hand = this._xhrDfd = (this.ioMethod || dojo.xhrGet)(getArgs); |
hand.addCallback(function(html){ |
try{ |
self.onDownloadEnd.call(self); |
self._isDownloaded = true; |
self.setContent.call(self, html); // onload event is called from here |
}catch(err){ |
self._onError.call(self, 'Content', err); // onContentError |
} |
delete self._xhrDfd; |
return html; |
}); |
hand.addErrback(function(err){ |
if(!hand.cancelled){ |
// show error message in the pane |
self._onError.call(self, 'Download', err); // onDownloadError |
} |
delete self._xhrDfd; |
return err; |
}); |
}, |
_onLoadHandler: function(){ |
this.isLoaded = true; |
try{ |
this.onLoad.call(this); |
}catch(e){ |
console.error('Error '+this.widgetId+' running custom onLoad code'); |
} |
}, |
_onUnloadHandler: function(){ |
this.isLoaded = false; |
this.cancel(); |
try{ |
this.onUnload.call(this); |
}catch(e){ |
console.error('Error '+this.widgetId+' running custom onUnload code'); |
} |
}, |
_setContent: function(cont){ |
this.destroyDescendants(); |
try{ |
var node = this.containerNode || this.domNode; |
while(node.firstChild){ |
dojo._destroyElement(node.firstChild); |
} |
if(typeof cont == "string"){ |
// dijit.ContentPane does only minimal fixes, |
// No pathAdjustments, script retrieval, style clean etc |
// some of these should be available in the dojox.layout.ContentPane |
if(this.extractContent){ |
match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im); |
if(match){ cont = match[1]; } |
} |
node.innerHTML = cont; |
}else{ |
// domNode or NodeList |
if(cont.nodeType){ // domNode (htmlNode 1 or textNode 3) |
node.appendChild(cont); |
}else{// nodelist or array such as dojo.Nodelist |
dojo.forEach(cont, function(n){ |
node.appendChild(n.cloneNode(true)); |
}); |
} |
} |
}catch(e){ |
// check if a domfault occurs when we are appending this.errorMessage |
// like for instance if domNode is a UL and we try append a DIV |
var errMess = this.onContentError(e); |
try{ |
node.innerHTML = errMess; |
}catch(e){ |
console.error('Fatal '+this.id+' could not change content due to '+e.message, e); |
} |
} |
}, |
_onError: function(type, err, consoleText){ |
// shows user the string that is returned by on[type]Error |
// overide on[type]Error and return your own string to customize |
var errText = this['on' + type + 'Error'].call(this, err); |
if(consoleText){ |
console.error(consoleText, err); |
}else if(errText){// a empty string won't change current content |
this._setContent.call(this, errText); |
} |
}, |
_createSubWidgets: function(){ |
// summary: scan my contents and create subwidgets |
var rootNode = this.containerNode || this.domNode; |
try{ |
dojo.parser.parse(rootNode, true); |
}catch(e){ |
this._onError('Content', e, "Couldn't create widgets in "+this.id |
+(this.href ? " from "+this.href : "")); |
} |
}, |
// EVENT's, should be overide-able |
onLoad: function(e){ |
// summary: |
// Event hook, is called after everything is loaded and widgetified |
}, |
onUnload: function(e){ |
// summary: |
// Event hook, is called before old content is cleared |
}, |
onDownloadStart: function(){ |
// summary: |
// called before download starts |
// the string returned by this function will be the html |
// that tells the user we are loading something |
// override with your own function if you want to change text |
return this.loadingMessage; |
}, |
onContentError: function(/*Error*/ error){ |
// summary: |
// called on DOM faults, require fault etc in content |
// default is to display errormessage inside pane |
}, |
onDownloadError: function(/*Error*/ error){ |
// summary: |
// Called when download error occurs, default is to display |
// errormessage inside pane. Overide function to change that. |
// The string returned by this function will be the html |
// that tells the user a error happend |
return this.errorMessage; |
}, |
onDownloadEnd: function(){ |
// summary: |
// called when download is finished |
} |
}); |
} |
/trunk/api/js/dojo1.0/dijit/layout/SplitContainer.js |
---|
New file |
0,0 → 1,537 |
if(!dojo._hasResource["dijit.layout.SplitContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout.SplitContainer"] = true; |
dojo.provide("dijit.layout.SplitContainer"); |
// |
// FIXME: make it prettier |
// FIXME: active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case) |
// |
dojo.require("dojo.cookie"); |
dojo.require("dijit.layout._LayoutWidget"); |
dojo.declare("dijit.layout.SplitContainer", |
dijit.layout._LayoutWidget, |
{ |
// summary: |
// A Container widget with sizing handles in-between each child |
// description: |
// Contains multiple children widgets, all of which are displayed side by side |
// (either horizontally or vertically); there's a bar between each of the children, |
// and you can adjust the relative size of each child by dragging the bars. |
// |
// You must specify a size (width and height) for the SplitContainer. |
// |
// activeSizing: Boolean |
// If true, the children's size changes as you drag the bar; |
// otherwise, the sizes don't change until you drop the bar (by mouse-up) |
activeSizing: false, |
// sizerWidth: Integer |
// Size in pixels of the bar between each child |
sizerWidth: 7, // FIXME: this should be a CSS attribute (at 7 because css wants it to be 7 until we fix to css) |
// orientation: String |
// either 'horizontal' or vertical; indicates whether the children are |
// arranged side-by-side or up/down. |
orientation: 'horizontal', |
// persist: Boolean |
// Save splitter positions in a cookie |
persist: true, |
postMixInProperties: function(){ |
this.inherited("postMixInProperties",arguments); |
this.isHorizontal = (this.orientation == 'horizontal'); |
}, |
postCreate: function(){ |
this.inherited("postCreate",arguments); |
this.sizers = []; |
dojo.addClass(this.domNode, "dijitSplitContainer"); |
// overflow has to be explicitly hidden for splitContainers using gekko (trac #1435) |
// to keep other combined css classes from inadvertantly making the overflow visible |
if(dojo.isMozilla){ |
this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work |
} |
// create the fake dragger |
if(typeof this.sizerWidth == "object"){ |
try{ //FIXME: do this without a try/catch |
this.sizerWidth = parseInt(this.sizerWidth.toString()); |
}catch(e){ this.sizerWidth = 7; } |
} |
var sizer = this.virtualSizer = document.createElement('div'); |
sizer.style.position = 'relative'; |
// #1681: work around the dreaded 'quirky percentages in IE' layout bug |
// If the splitcontainer's dimensions are specified in percentages, it |
// will be resized when the virtualsizer is displayed in _showSizingLine |
// (typically expanding its bounds unnecessarily). This happens because |
// we use position: relative for .dijitSplitContainer. |
// The workaround: instead of changing the display style attribute, |
// switch to changing the zIndex (bring to front/move to back) |
sizer.style.zIndex = 10; |
sizer.className = this.isHorizontal ? 'dijitSplitContainerVirtualSizerH' : 'dijitSplitContainerVirtualSizerV'; |
this.domNode.appendChild(sizer); |
dojo.setSelectable(sizer, false); |
}, |
startup: function(){ |
if(this._started){ return; } |
dojo.forEach(this.getChildren(), function(child, i, children){ |
// attach the children and create the draggers |
this._injectChild(child); |
if(i < children.length-1){ |
this._addSizer(); |
} |
}, this); |
if(this.persist){ |
this._restoreState(); |
} |
this.inherited("startup",arguments); |
this._started = true; |
}, |
_injectChild: function(child){ |
child.domNode.style.position = "absolute"; |
dojo.addClass(child.domNode, "dijitSplitPane"); |
}, |
_addSizer: function(){ |
var i = this.sizers.length; |
// TODO: use a template for this!!! |
var sizer = this.sizers[i] = document.createElement('div'); |
sizer.className = this.isHorizontal ? 'dijitSplitContainerSizerH' : 'dijitSplitContainerSizerV'; |
// add the thumb div |
var thumb = document.createElement('div'); |
thumb.className = 'thumb'; |
sizer.appendChild(thumb); |
// FIXME: are you serious? why aren't we using mover start/stop combo? |
var self = this; |
var handler = (function(){ var sizer_i = i; return function(e){ self.beginSizing(e, sizer_i); } })(); |
dojo.connect(sizer, "onmousedown", handler); |
this.domNode.appendChild(sizer); |
dojo.setSelectable(sizer, false); |
}, |
removeChild: function(widget){ |
// summary: Remove sizer, but only if widget is really our child and |
// we have at least one sizer to throw away |
if(this.sizers.length && dojo.indexOf(this.getChildren(), widget) != -1){ |
var i = this.sizers.length - 1; |
dojo._destroyElement(this.sizers[i]); |
this.sizers.length--; |
} |
// Remove widget and repaint |
this.inherited("removeChild",arguments); |
if(this._started){ |
this.layout(); |
} |
}, |
addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){ |
// summary: Add a child widget to the container |
// child: a widget to add |
// insertIndex: postion in the "stack" to add the child widget |
this.inherited("addChild",arguments); |
if(this._started){ |
// Do the stuff that startup() does for each widget |
this._injectChild(child); |
var children = this.getChildren(); |
if(children.length > 1){ |
this._addSizer(); |
} |
// and then reposition (ie, shrink) every pane to make room for the new guy |
this.layout(); |
} |
}, |
layout: function(){ |
// summary: |
// Do layout of panels |
// base class defines this._contentBox on initial creation and also |
// on resize |
this.paneWidth = this._contentBox.w; |
this.paneHeight = this._contentBox.h; |
var children = this.getChildren(); |
if(!children.length){ return; } |
// |
// calculate space |
// |
var space = this.isHorizontal ? this.paneWidth : this.paneHeight; |
if(children.length > 1){ |
space -= this.sizerWidth * (children.length - 1); |
} |
// |
// calculate total of SizeShare values |
// |
var outOf = 0; |
dojo.forEach(children, function(child){ |
outOf += child.sizeShare; |
}); |
// |
// work out actual pixels per sizeshare unit |
// |
var pixPerUnit = space / outOf; |
// |
// set the SizeActual member of each pane |
// |
var totalSize = 0; |
dojo.forEach(children.slice(0, children.length - 1), function(child){ |
var size = Math.round(pixPerUnit * child.sizeShare); |
child.sizeActual = size; |
totalSize += size; |
}); |
children[children.length-1].sizeActual = space - totalSize; |
// |
// make sure the sizes are ok |
// |
this._checkSizes(); |
// |
// now loop, positioning each pane and letting children resize themselves |
// |
var pos = 0; |
var size = children[0].sizeActual; |
this._movePanel(children[0], pos, size); |
children[0].position = pos; |
pos += size; |
// if we don't have any sizers, our layout method hasn't been called yet |
// so bail until we are called..TODO: REVISIT: need to change the startup |
// algorithm to guaranteed the ordering of calls to layout method |
if(!this.sizers){ |
return; |
} |
dojo.some(children.slice(1), function(child, i){ |
// error-checking |
if(!this.sizers[i]){ |
return true; |
} |
// first we position the sizing handle before this pane |
this._moveSlider(this.sizers[i], pos, this.sizerWidth); |
this.sizers[i].position = pos; |
pos += this.sizerWidth; |
size = child.sizeActual; |
this._movePanel(child, pos, size); |
child.position = pos; |
pos += size; |
}, this); |
}, |
_movePanel: function(panel, pos, size){ |
if(this.isHorizontal){ |
panel.domNode.style.left = pos + 'px'; // TODO: resize() takes l and t parameters too, don't need to set manually |
panel.domNode.style.top = 0; |
var box = {w: size, h: this.paneHeight}; |
if(panel.resize){ |
panel.resize(box); |
}else{ |
dojo.marginBox(panel.domNode, box); |
} |
}else{ |
panel.domNode.style.left = 0; // TODO: resize() takes l and t parameters too, don't need to set manually |
panel.domNode.style.top = pos + 'px'; |
var box = {w: this.paneWidth, h: size}; |
if(panel.resize){ |
panel.resize(box); |
}else{ |
dojo.marginBox(panel.domNode, box); |
} |
} |
}, |
_moveSlider: function(slider, pos, size){ |
if(this.isHorizontal){ |
slider.style.left = pos + 'px'; |
slider.style.top = 0; |
dojo.marginBox(slider, { w: size, h: this.paneHeight }); |
}else{ |
slider.style.left = 0; |
slider.style.top = pos + 'px'; |
dojo.marginBox(slider, { w: this.paneWidth, h: size }); |
} |
}, |
_growPane: function(growth, pane){ |
if(growth > 0){ |
if(pane.sizeActual > pane.sizeMin){ |
if((pane.sizeActual - pane.sizeMin) > growth){ |
// stick all the growth in this pane |
pane.sizeActual = pane.sizeActual - growth; |
growth = 0; |
}else{ |
// put as much growth in here as we can |
growth -= pane.sizeActual - pane.sizeMin; |
pane.sizeActual = pane.sizeMin; |
} |
} |
} |
return growth; |
}, |
_checkSizes: function(){ |
var totalMinSize = 0; |
var totalSize = 0; |
var children = this.getChildren(); |
dojo.forEach(children, function(child){ |
totalSize += child.sizeActual; |
totalMinSize += child.sizeMin; |
}); |
// only make adjustments if we have enough space for all the minimums |
if(totalMinSize <= totalSize){ |
var growth = 0; |
dojo.forEach(children, function(child){ |
if(child.sizeActual < child.sizeMin){ |
growth += child.sizeMin - child.sizeActual; |
child.sizeActual = child.sizeMin; |
} |
}); |
if(growth > 0){ |
var list = this.isDraggingLeft ? children.reverse() : children; |
dojo.forEach(list, function(child){ |
growth = this._growPane(growth, child); |
}, this); |
} |
}else{ |
dojo.forEach(children, function(child){ |
child.sizeActual = Math.round(totalSize * (child.sizeMin / totalMinSize)); |
}); |
} |
}, |
beginSizing: function(e, i){ |
var children = this.getChildren(); |
this.paneBefore = children[i]; |
this.paneAfter = children[i+1]; |
this.isSizing = true; |
this.sizingSplitter = this.sizers[i]; |
if(!this.cover){ |
this.cover = dojo.doc.createElement('div'); |
this.domNode.appendChild(this.cover); |
var s = this.cover.style; |
s.position = 'absolute'; |
s.zIndex = 1; |
s.top = 0; |
s.left = 0; |
s.width = "100%"; |
s.height = "100%"; |
}else{ |
this.cover.style.zIndex = 1; |
} |
this.sizingSplitter.style.zIndex = 2; |
// TODO: REVISIT - we want MARGIN_BOX and core hasn't exposed that yet (but can't we use it anyway if we pay attention? we do elsewhere.) |
this.originPos = dojo.coords(children[0].domNode, true); |
if(this.isHorizontal){ |
var client = (e.layerX ? e.layerX : e.offsetX); |
var screen = e.pageX; |
this.originPos = this.originPos.x; |
}else{ |
var client = (e.layerY ? e.layerY : e.offsetY); |
var screen = e.pageY; |
this.originPos = this.originPos.y; |
} |
this.startPoint = this.lastPoint = screen; |
this.screenToClientOffset = screen - client; |
this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position; |
if(!this.activeSizing){ |
this._showSizingLine(); |
} |
// |
// attach mouse events |
// |
this._connects = []; |
this._connects.push(dojo.connect(document.documentElement, "onmousemove", this, "changeSizing")); |
this._connects.push(dojo.connect(document.documentElement, "onmouseup", this, "endSizing")); |
dojo.stopEvent(e); |
}, |
changeSizing: function(e){ |
if(!this.isSizing){ return; } |
this.lastPoint = this.isHorizontal ? e.pageX : e.pageY; |
this.movePoint(); |
if(this.activeSizing){ |
this._updateSize(); |
}else{ |
this._moveSizingLine(); |
} |
dojo.stopEvent(e); |
}, |
endSizing: function(e){ |
if(!this.isSizing){ return; } |
if(this.cover){ |
this.cover.style.zIndex = -1; |
} |
if(!this.activeSizing){ |
this._hideSizingLine(); |
} |
this._updateSize(); |
this.isSizing = false; |
if(this.persist){ |
this._saveState(this); |
} |
dojo.forEach(this._connects,dojo.disconnect); |
}, |
movePoint: function(){ |
// make sure lastPoint is a legal point to drag to |
var p = this.lastPoint - this.screenToClientOffset; |
var a = p - this.dragOffset; |
a = this.legaliseSplitPoint(a); |
p = a + this.dragOffset; |
this.lastPoint = p + this.screenToClientOffset; |
}, |
legaliseSplitPoint: function(a){ |
a += this.sizingSplitter.position; |
this.isDraggingLeft = !!(a > 0); |
if(!this.activeSizing){ |
var min = this.paneBefore.position + this.paneBefore.sizeMin; |
if(a < min){ |
a = min; |
} |
var max = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin)); |
if(a > max){ |
a = max; |
} |
} |
a -= this.sizingSplitter.position; |
this._checkSizes(); |
return a; |
}, |
_updateSize: function(){ |
//FIXME: sometimes this.lastPoint is NaN |
var pos = this.lastPoint - this.dragOffset - this.originPos; |
var start_region = this.paneBefore.position; |
var end_region = this.paneAfter.position + this.paneAfter.sizeActual; |
this.paneBefore.sizeActual = pos - start_region; |
this.paneAfter.position = pos + this.sizerWidth; |
this.paneAfter.sizeActual = end_region - this.paneAfter.position; |
dojo.forEach(this.getChildren(), function(child){ |
child.sizeShare = child.sizeActual; |
}); |
if(this._started){ |
this.layout(); |
} |
}, |
_showSizingLine: function(){ |
this._moveSizingLine(); |
dojo.marginBox(this.virtualSizer, |
this.isHorizontal ? { w: this.sizerWidth, h: this.paneHeight } : { w: this.paneWidth, h: this.sizerWidth }); |
this.virtualSizer.style.display = 'block'; |
}, |
_hideSizingLine: function(){ |
this.virtualSizer.style.display = 'none'; |
}, |
_moveSizingLine: function(){ |
var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position; |
dojo.style(this.virtualSizer,(this.isHorizontal ? "left" : "top"),pos+"px"); |
// this.virtualSizer.style[ this.isHorizontal ? "left" : "top" ] = pos + 'px'; // FIXME: remove this line if the previous is better |
}, |
_getCookieName: function(i){ |
return this.id + "_" + i; |
}, |
_restoreState: function(){ |
dojo.forEach(this.getChildren(), function(child, i){ |
var cookieName = this._getCookieName(i); |
var cookieValue = dojo.cookie(cookieName); |
if(cookieValue){ |
var pos = parseInt(cookieValue); |
if(typeof pos == "number"){ |
child.sizeShare = pos; |
} |
} |
}, this); |
}, |
_saveState: function(){ |
dojo.forEach(this.getChildren(), function(child, i){ |
dojo.cookie(this._getCookieName(i), child.sizeShare); |
}, this); |
} |
}); |
// These arguments can be specified for the children of a SplitContainer. |
// Since any widget can be specified as a SplitContainer child, mix them |
// into the base widget class. (This is a hack, but it's effective.) |
dojo.extend(dijit._Widget, { |
// sizeMin: Integer |
// Minimum size (width or height) of a child of a SplitContainer. |
// The value is relative to other children's sizeShare properties. |
sizeMin: 10, |
// sizeShare: Integer |
// Size (width or height) of a child of a SplitContainer. |
// The value is relative to other children's sizeShare properties. |
// For example, if there are two children and each has sizeShare=10, then |
// each takes up 50% of the available space. |
sizeShare: 10 |
}); |
} |
/trunk/api/js/dojo1.0/dijit/layout/LayoutContainer.js |
---|
New file |
0,0 → 1,71 |
if(!dojo._hasResource["dijit.layout.LayoutContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout.LayoutContainer"] = true; |
dojo.provide("dijit.layout.LayoutContainer"); |
dojo.require("dijit.layout._LayoutWidget"); |
dojo.declare( |
"dijit.layout.LayoutContainer", |
dijit.layout._LayoutWidget, |
{ |
// summary |
// Provides Delphi-style panel layout semantics. |
// |
// details |
// A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"), |
// that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client". |
// It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box, |
// and then it takes the child marked "client" and puts it into the remaining space in the middle. |
// |
// Left/right positioning is similar to CSS's "float: left" and "float: right", |
// and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such |
// CSS. |
// |
// Note that there can only be one client element, but there can be multiple left, right, top, |
// or bottom elements. |
// |
// usage |
// <style> |
// html, body{ height: 100%; width: 100%; } |
// </style> |
// <div dojoType="dijit.layout.LayoutContainer" style="width: 100%; height: 100%"> |
// <div dojoType="dijit.layout.ContentPane" layoutAlign="top">header text</div> |
// <div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="width: 200px;">table of contents</div> |
// <div dojoType="dijit.layout.ContentPane" layoutAlign="client">client area</div> |
// </div> |
// |
// Lays out each child in the natural order the children occur in. |
// Basically each child is laid out into the "remaining space", where "remaining space" is initially |
// the content area of this widget, but is reduced to a smaller rectangle each time a child is added. |
// |
layout: function(){ |
dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren()); |
}, |
addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){ |
dijit._Container.prototype.addChild.apply(this, arguments); |
if(this._started){ |
dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren()); |
} |
}, |
removeChild: function(/*Widget*/ widget){ |
dijit._Container.prototype.removeChild.apply(this, arguments); |
if(this._started){ |
dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren()); |
} |
} |
}); |
// This argument can be specified for the children of a LayoutContainer. |
// Since any widget can be specified as a LayoutContainer child, mix it |
// into the base widget class. (This is a hack, but it's effective.) |
dojo.extend(dijit._Widget, { |
// layoutAlign: String |
// "none", "left", "right", "bottom", "top", and "client". |
// See the LayoutContainer description for details on this parameter. |
layoutAlign: 'none' |
}); |
} |
/trunk/api/js/dojo1.0/dijit/layout/_LayoutWidget.js |
---|
New file |
0,0 → 1,187 |
if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout._LayoutWidget"] = true; |
dojo.provide("dijit.layout._LayoutWidget"); |
dojo.require("dijit._Widget"); |
dojo.require("dijit._Container"); |
dojo.declare("dijit.layout._LayoutWidget", |
[dijit._Widget, dijit._Container, dijit._Contained], |
{ |
// summary |
// Mixin for widgets that contain a list of children like SplitContainer. |
// Widgets which mixin this code must define layout() to lay out the children |
isLayoutContainer: true, |
postCreate: function(){ |
dojo.addClass(this.domNode, "dijitContainer"); |
}, |
startup: function(){ |
// summary: |
// Called after all the widgets have been instantiated and their |
// dom nodes have been inserted somewhere under document.body. |
// |
// Widgets should override this method to do any initialization |
// dependent on other widgets existing, and then call |
// this superclass method to finish things off. |
// |
// startup() in subclasses shouldn't do anything |
// size related because the size of the widget hasn't been set yet. |
if(this._started){ return; } |
this._started=true; |
if(this.getChildren){ |
dojo.forEach(this.getChildren(), function(child){ child.startup(); }); |
} |
// If I am a top level widget |
if(!this.getParent || !this.getParent()){ |
// Do recursive sizing and layout of all my descendants |
// (passing in no argument to resize means that it has to glean the size itself) |
this.resize(); |
// since my parent isn't a layout container, and my style is width=height=100% (or something similar), |
// then I need to watch when the window resizes, and size myself accordingly |
// (passing in no argument to resize means that it has to glean the size itself) |
this.connect(window, 'onresize', function(){this.resize();}); |
} |
}, |
resize: function(args){ |
// summary: |
// Explicitly set this widget's size (in pixels), |
// and then call layout() to resize contents (and maybe adjust child widgets) |
// |
// args: Object? |
// {w: int, h: int, l: int, t: int} |
var node = this.domNode; |
// set margin box size, unless it wasn't specified, in which case use current size |
if(args){ |
dojo.marginBox(node, args); |
// set offset of the node |
if(args.t){ node.style.top = args.t + "px"; } |
if(args.l){ node.style.left = args.l + "px"; } |
} |
// If either height or width wasn't specified by the user, then query node for it. |
// But note that setting the margin box and then immediately querying dimensions may return |
// inaccurate results, so try not to depend on it. |
var mb = dojo.mixin(dojo.marginBox(node), args||{}); |
// Save the size of my content box. |
this._contentBox = dijit.layout.marginBox2contentBox(node, mb); |
// Callback for widget to adjust size of it's children |
this.layout(); |
}, |
layout: function(){ |
// summary |
// Widgets override this method to size & position their contents/children. |
// When this is called this._contentBox is guaranteed to be set (see resize()). |
// |
// This is called after startup(), and also when the widget's size has been |
// changed. |
} |
} |
); |
dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){ |
// summary: |
// Given the margin-box size of a node, return it's content box size. |
// Functions like dojo.contentBox() but is more reliable since it doesn't have |
// to wait for the browser to compute sizes. |
var cs = dojo.getComputedStyle(node); |
var me=dojo._getMarginExtents(node, cs); |
var pb=dojo._getPadBorderExtents(node, cs); |
return { |
l: dojo._toPixelValue(node, cs.paddingLeft), |
t: dojo._toPixelValue(node, cs.paddingTop), |
w: mb.w - (me.w + pb.w), |
h: mb.h - (me.h + pb.h) |
}; |
}; |
(function(){ |
var capitalize = function(word){ |
return word.substring(0,1).toUpperCase() + word.substring(1); |
}; |
var size = function(widget, dim){ |
// size the child |
widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim); |
// record child's size, but favor our own numbers when we have them. |
// the browser lies sometimes |
dojo.mixin(widget, dojo.marginBox(widget.domNode)); |
dojo.mixin(widget, dim); |
}; |
dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){ |
/** |
* summary |
* Layout a bunch of child dom nodes within a parent dom node |
* container: |
* parent node |
* dim: |
* {l, t, w, h} object specifying dimensions of container into which to place children |
* children: |
* an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ] |
*/ |
// copy dim because we are going to modify it |
dim = dojo.mixin({}, dim); |
dojo.addClass(container, "dijitLayoutContainer"); |
// Move "client" elements to the end of the array for layout. a11y dictates that the author |
// needs to be able to put them in the document in tab-order, but this algorithm requires that |
// client be last. |
children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; }) |
.concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; })); |
// set positions/sizes |
dojo.forEach(children, function(child){ |
var elm = child.domNode, |
pos = child.layoutAlign; |
// set elem to upper left corner of unused space; may move it later |
var elmStyle = elm.style; |
elmStyle.left = dim.l+"px"; |
elmStyle.top = dim.t+"px"; |
elmStyle.bottom = elmStyle.right = "auto"; |
dojo.addClass(elm, "dijitAlign" + capitalize(pos)); |
// set size && adjust record of remaining space. |
// note that setting the width of a <div> may affect it's height. |
if(pos=="top" || pos=="bottom"){ |
size(child, { w: dim.w }); |
dim.h -= child.h; |
if(pos=="top"){ |
dim.t += child.h; |
}else{ |
elmStyle.top = dim.t + dim.h + "px"; |
} |
}else if(pos=="left" || pos=="right"){ |
size(child, { h: dim.h }); |
dim.w -= child.w; |
if(pos=="left"){ |
dim.l += child.w; |
}else{ |
elmStyle.left = dim.l + dim.w + "px"; |
} |
}else if(pos=="client"){ |
size(child, dim); |
} |
}); |
}; |
})(); |
} |
/trunk/api/js/dojo1.0/dijit/layout/LinkPane.js |
---|
New file |
0,0 → 1,36 |
if(!dojo._hasResource["dijit.layout.LinkPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout.LinkPane"] = true; |
dojo.provide("dijit.layout.LinkPane"); |
dojo.require("dijit.layout.ContentPane"); |
dojo.require("dijit._Templated"); |
dojo.declare("dijit.layout.LinkPane", |
[dijit.layout.ContentPane, dijit._Templated], |
{ |
// summary: |
// A ContentPane that loads data remotely |
// description: |
// LinkPane is just a ContentPane that loads data remotely (via the href attribute), |
// and has markup similar to an anchor. The anchor's body (the words between <a> and </a>) |
// become the title of the widget (used for TabContainer, AccordionContainer, etc.) |
// example: |
// <a href="foo.html">my title</a> |
// I'm using a template because the user may specify the input as |
// <a href="foo.html">title</a>, in which case we need to get rid of the |
// <a> because we don't want a link. |
templateString: '<div class="dijitLinkPane"></div>', |
postCreate: function(){ |
// If user has specified node contents, they become the title |
// (the link must be plain text) |
if(this.srcNodeRef){ |
this.title += this.srcNodeRef.innerHTML; |
} |
this.inherited("postCreate",arguments); |
} |
}); |
} |
/trunk/api/js/dojo1.0/dijit/layout/templates/TabContainer.html |
---|
New file |
0,0 → 1,4 |
<div class="dijitTabContainer"> |
<div dojoAttachPoint="tablistNode"></div> |
<div class="dijitTabPaneWrapper" dojoAttachPoint="containerNode"></div> |
</div> |
/trunk/api/js/dojo1.0/dijit/layout/templates/TooltipDialog.html |
---|
New file |
0,0 → 1,7 |
<div class="dijitTooltipDialog" > |
<div class="dijitTooltipContainer"> |
<div class ="dijitTooltipContents dijitTooltipFocusNode" dojoAttachPoint="containerNode" tabindex="0" waiRole="dialog"></div> |
</div> |
<span dojoAttachPoint="tabEnd" tabindex="0" dojoAttachEvent="focus:_cycleFocus"></span> |
<div class="dijitTooltipConnector" ></div> |
</div> |
/trunk/api/js/dojo1.0/dijit/layout/templates/_TabButton.html |
---|
New file |
0,0 → 1,8 |
<div dojoAttachEvent='onclick:onClick,onmouseenter:_onMouse,onmouseleave:_onMouse'> |
<div class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'> |
<span dojoAttachPoint='containerNode,focusNode'>${!label}</span> |
<span dojoAttachPoint='closeButtonNode' class='closeImage' dojoAttachEvent='onmouseenter:_onMouse, onmouseleave:_onMouse, onclick:onClickCloseButton' stateModifier='CloseButton'> |
<span dojoAttachPoint='closeText' class='closeText'>x</span> |
</span> |
</div> |
</div> |
/trunk/api/js/dojo1.0/dijit/layout/templates/AccordionPane.html |
---|
New file |
0,0 → 1,11 |
<div class='dijitAccordionPane' |
><div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onTitleKeyPress,onfocus:_handleFocus,onblur:_handleFocus' |
class='dijitAccordionTitle' wairole="tab" |
><div class='dijitAccordionArrow'></div |
><div class='arrowTextUp' waiRole="presentation">▲</div |
><div class='arrowTextDown' waiRole="presentation">▼</div |
><div dojoAttachPoint='titleTextNode' class='dijitAccordionText'>${title}</div></div |
><div><div dojoAttachPoint='containerNode' style='overflow: hidden; height: 1px; display: none' |
class='dijitAccordionBody' wairole="tabpanel" |
></div></div> |
</div> |
/trunk/api/js/dojo1.0/dijit/layout/AccordionContainer.js |
---|
New file |
0,0 → 1,209 |
if(!dojo._hasResource["dijit.layout.AccordionContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit.layout.AccordionContainer"] = true; |
dojo.provide("dijit.layout.AccordionContainer"); |
dojo.require("dojo.fx"); |
dojo.require("dijit._Container"); |
dojo.require("dijit._Templated"); |
dojo.require("dijit.layout.StackContainer"); |
dojo.require("dijit.layout.ContentPane"); |
dojo.declare( |
"dijit.layout.AccordionContainer", |
dijit.layout.StackContainer, |
{ |
// summary: |
// Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time, |
// and switching between panes is visualized by sliding the other panes up/down. |
// usage: |
// <div dojoType="dijit.layout.AccordionContainer"> |
// <div dojoType="dijit.layout.AccordionPane" title="pane 1"> |
// <div dojoType="dijit.layout.ContentPane">...</div> |
// </div> |
// <div dojoType="dijit.layout.AccordionPane" title="pane 2"> |
// <p>This is some text</p> |
// ... |
// </div> |
// duration: Integer |
// Amount of time (in ms) it takes to slide panes |
duration: 250, |
_verticalSpace: 0, |
postCreate: function(){ |
this.domNode.style.overflow="hidden"; |
this.inherited("postCreate",arguments); |
dijit.setWaiRole(this.domNode, "tablist"); |
dojo.addClass(this.domNode,"dijitAccordionContainer"); |
}, |
startup: function(){ |
if(this._started){ return; } |
this.inherited("startup",arguments); |
if(this.selectedChildWidget){ |
var style = this.selectedChildWidget.containerNode.style; |
style.display = ""; |
style.overflow = "auto"; |
this.selectedChildWidget._setSelectedState(true); |
} |
}, |
layout: function(){ |
// summary |
// Set the height of the open pane based on what room remains |
// get cumulative height of all the title bars, and figure out which pane is open |
var totalCollapsedHeight = 0; |
var openPane = this.selectedChildWidget; |
dojo.forEach(this.getChildren(), function(child){ |
totalCollapsedHeight += child.getTitleHeight(); |
}); |
var mySize = this._contentBox; |
this._verticalSpace = (mySize.h - totalCollapsedHeight); |
if(openPane){ |
openPane.containerNode.style.height = this._verticalSpace + "px"; |
/*** |
TODO: this is wrong. probably you wanted to call resize on the SplitContainer |
inside the AccordionPane?? |
if(openPane.resize){ |
openPane.resize({h: this._verticalSpace}); |
} |
***/ |
} |
}, |
_setupChild: function(/*Widget*/ page){ |
// Summary: prepare the given child |
return page; |
}, |
_transition: function(/*Widget?*/newWidget, /*Widget?*/oldWidget){ |
//TODO: should be able to replace this with calls to slideIn/slideOut |
if(this._inTransition){ return; } |
this._inTransition = true; |
var animations = []; |
var paneHeight = this._verticalSpace; |
if(newWidget){ |
newWidget.setSelected(true); |
var newContents = newWidget.containerNode; |
newContents.style.display = ""; |
animations.push(dojo.animateProperty({ |
node: newContents, |
duration: this.duration, |
properties: { |
height: { start: "1", end: paneHeight } |
}, |
onEnd: function(){ |
newContents.style.overflow = "auto"; |
} |
})); |
} |
if(oldWidget){ |
oldWidget.setSelected(false); |
var oldContents = oldWidget.containerNode; |
oldContents.style.overflow = "hidden"; |
animations.push(dojo.animateProperty({ |
node: oldContents, |
duration: this.duration, |
properties: { |
height: { start: paneHeight, end: "1" } |
}, |
onEnd: function(){ |
oldContents.style.display = "none"; |
} |
})); |
} |
this._inTransition = false; |
dojo.fx.combine(animations).play(); |
}, |
// note: we are treating the container as controller here |
_onKeyPress: function(/*Event*/ e){ |
if(this.disabled || e.altKey ){ return; } |
var k = dojo.keys; |
switch(e.keyCode){ |
case k.LEFT_ARROW: |
case k.UP_ARROW: |
case k.PAGE_UP: |
this._adjacent(false)._onTitleClick(); |
dojo.stopEvent(e); |
break; |
case k.RIGHT_ARROW: |
case k.DOWN_ARROW: |
case k.PAGE_DOWN: |
this._adjacent(true)._onTitleClick(); |
dojo.stopEvent(e); |
break; |
default: |
if(e.ctrlKey && e.keyCode == k.TAB){ |
this._adjacent(e._dijitWidget, !e.shiftKey)._onTitleClick(); |
dojo.stopEvent(e); |
} |
} |
} |
} |
); |
dojo.declare( |
"dijit.layout.AccordionPane", |
[dijit.layout.ContentPane, dijit._Templated, dijit._Contained], |
{ |
// summary |
// AccordionPane is a ContentPane with a title that may contain another widget. |
// Nested layout widgets, such as SplitContainer, are not supported at this time. |
templateString:"<div class='dijitAccordionPane'\n\t><div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onTitleKeyPress,onfocus:_handleFocus,onblur:_handleFocus'\n\t\tclass='dijitAccordionTitle' wairole=\"tab\"\n\t\t><div class='dijitAccordionArrow'></div\n\t\t><div class='arrowTextUp' waiRole=\"presentation\">▲</div\n\t\t><div class='arrowTextDown' waiRole=\"presentation\">▼</div\n\t\t><div dojoAttachPoint='titleTextNode' class='dijitAccordionText'>${title}</div></div\n\t><div><div dojoAttachPoint='containerNode' style='overflow: hidden; height: 1px; display: none'\n\t\tclass='dijitAccordionBody' wairole=\"tabpanel\"\n\t></div></div>\n</div>\n", |
postCreate: function(){ |
this.inherited("postCreate",arguments) |
dojo.setSelectable(this.titleNode, false); |
this.setSelected(this.selected); |
}, |
getTitleHeight: function(){ |
// summary: returns the height of the title dom node |
return dojo.marginBox(this.titleNode).h; // Integer |
}, |
_onTitleClick: function(){ |
// summary: callback when someone clicks my title |
var parent = this.getParent(); |
if(!parent._inTransition){ |
parent.selectChild(this); |
dijit.focus(this.focusNode); |
} |
}, |
_onTitleKeyPress: function(/*Event*/ evt){ |
evt._dijitWidget = this; |
return this.getParent()._onKeyPress(evt); |
}, |
_setSelectedState: function(/*Boolean*/ isSelected){ |
this.selected = isSelected; |
dojo[(isSelected ? "addClass" : "removeClass")](this.domNode,"dijitAccordionPane-selected"); |
this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1"); |
}, |
_handleFocus: function(/*Event*/e){ |
// summary: handle the blur and focus state of this widget |
dojo[(e.type=="focus" ? "addClass" : "removeClass")](this.focusNode,"dijitAccordionPaneFocused"); |
}, |
setSelected: function(/*Boolean*/ isSelected){ |
// summary: change the selected state on this pane |
this._setSelectedState(isSelected); |
if(isSelected){ this.onSelected(); } |
}, |
onSelected: function(){ |
// summary: called when this pane is selected |
} |
}); |
} |