📄 accordionbehavior.js
字号:
/// even number of child divs (such that ith pane has a header at div 2i and
/// has content at div 2i+1).
/// </param>
AjaxControlToolkit.AccordionBehavior.initializeBase(this, [element]);
// The _selectedIndex variable is used to track the currently visible content
// pane. It is persisted via ClientState so that it can be restored on PostBack.
// If 0 <= _selectedIndex < _panes.Length is not true, then no pane is selected
// (and they all appear collapsed). While any index outside the bounds of the
// _panes array indicates that no pane is selected, we don't automatically set
// the value to a sentinel like -1 (especially on the server) because it's
// possible for additional panes to be added at any time. We abstract this
// problem using the get_Pane() function which returns the selected pane when
// it's called with no arguments (and returns null when the current selected
// index is invalid).
this._selectedIndex = 0;
// The _panes array represents the collection of Accordion panes. Each element of
// the array is an object of the form {header, content, animation} corresponding
// to that pane's header section, content section, and the animation used to open
// and close its content section. The content element is a new div that has been
// created to wrap the original div (so we can completely collapse it - even if it
// has padding, margins, etc.) which is pointed to by a dynamic _original property.
// The header element has a dynamic _index property indicating its position in the
// Accordion's pane collection (used primarily by the headers' shared click handler).
// Furthermore, the animation will either be an instance of LengthAnimation or
// ParallelAnimation (in the latter case, it will have two children which are a
// LengthAnimation and a FadeAnimation). There will be two dynamic properties
// _length and _fade pointing to each of these children (to easily set the length
// and fadeEffect properties). There is also a dynamic _ended property which is
// an event handler to be fired when the animation is complete, a dynamic _opening
// property to indicate whether the animation was opening or closing the pane, and
// a dynamic _pane property to provide a reference to the pane that was being
// animated.
this._panes = [];
// The this._fadeTransitions flag determines whether or not we enable a simple fade
// animation effect on top of the opening and closing effect
this._fadeTransitions = false;
// The this._duration represents the transition duration of the animations in seconds
this._duration = 0.25;
// framesPerSecond is used to tune the animation to perform well depending on
// the the type of effect being used an the number of accordion panes, etc.
this._framesPerSecond = 30;
// Determine how growth of the Accordion will be controlled. If it is set to
// None, then the Accordion can grow as large or as small as necessary. If it is
// set to Limit, then the Accordion will always be less than or equal to its
// available space. If it is set to Fill, then it will always be equal to its
// available space.
this._autoSize = AjaxControlToolkit.AutoSize.None;
// Whether or not clicking the header will close the currently opened pane (which
// leaves all the Accordion's panes closed)
this._requireOpenedPane = true;
// Whether or not we suppress the client-side click handlers of any elements
// (including server controls like Button or HTML elements like anchor) in the header
// sections of the Accordion
this._suppressHeaderPostbacks = false;
// Size of all the headers
this._headersSize = 0;
// The _headerClickHandler is a reference to the event handler that all the header
// elements of our panes will be wired up to
this._headerClickHandler = null;
// The _headerSelectedCssClass is the css class applied to the selected header.
this._headerCssClass = '';
// The _headerSelectedCssClass is the css class applied to the selected header.
this._headerSelectedCssClass = '';
// The _headerSelectedCssClass is the css class applied to the selected header.
this._contentCssClass = '';
// The _resizeHandler is a reference to the global event handler used to patch
// up the accordion when the window is resized
this._resizeHandler = null;
}
AjaxControlToolkit.AccordionBehavior.prototype = {
initialize : function() {
/// <summary>
/// The initialize function is responsible for getting the selected index from
/// the ClientState mechanism and walking the children of the behavior's target
/// to find all of the accordion's child panes. It builds up a collection of the
/// panes from the headers and content sections. Then we hide all the content
/// sections that aren't selected and initialize the layout.
/// </summary>
/// <returns />
AjaxControlToolkit.AccordionBehavior.callBaseMethod(this, 'initialize');
// Create the onclick handler used by the accordion's headers
this._headerClickHandler = Function.createDelegate(this, this._onHeaderClick);
// Get the selected index from ClientState
var state = this.get_ClientState();
if (state !== null && state !== '') {
this._changeSelectedIndex(parseInt(state), false, true);
}
// Walk the children of the target control to obtain the accordion's child panes.
// We are expecting a hierarchy of divs that looks like:
// <div id="accordion"> this.element
// ...
// <div id="header_i"></div> this.element.childNodes[2i]
// <div id="content_i"></div> this.element.childNodes[2i+1]
// ...
// </div>
// We'll turn this hierarchy of divs into objects filling the _panes collection.
// See the comment above the _panes array for more details on the structure of
// these objects. It's also worth pointing out that we effectively "box" the
// index so it can be passed by reference to the _getNextDiv function
var nodes = this.get_element().childNodes;
var index = { };
for (index.value = 0; index.value < nodes.length; index.value++) {
var header = this._getNextDiv(nodes, index);
if (!header) {
break;
}
var content = this._getNextDiv(nodes, index);
if (content) {
// Add the pane once we've found both a header and a content section
// (but bump the loop index back so we don't skip an element when the
// loop increments)
this.addPane(header, content);
index.value--;
}
}
// Ensure we have an opened pane if we're required to (and use the first
// pane if we don't have a valid selected index)
if (this._requireOpenedPane && !this.get_Pane() && this._panes.length > 0) {
this._changeSelectedIndex(0, false, true);
}
// Setup the layout for the given AutoSize mode
this._initializeLayout();
},
_getNextDiv : function(nodes, index) {
/// <summary>
/// Get the next div in a sequence of child nodes starting at the
/// given index
/// </summary>
/// <param name="nodes" type="Array" mayBeNull="false" elementMayBeNull="true"
/// elementType="Sys.UI.DomElement" elementDomElement="true">
/// Array of child nodes (i.e. element.childNodes)
/// </param>
/// <param name="index" type="Object" mayBeNull="false">
/// The index is an object of the form { value } where index.value represents
/// the current index in the collection of nodes. We wrap the index in an object
/// to perform the .NET equivalent of boxing so it can be passed by reference.
/// </param>
/// <returns type="Sys.UI.DomElement" DomElement="true" mayBeNull="true">
/// The next DOM element representing a div tag, starting at the provided index.
/// </returns>
var div = null;
while (index.value < nodes.length && (div = nodes[index.value++])) {
if (div.tagName && (div.tagName.toLowerCase() === 'div')) {
break;
}
}
return div;
},
addPane : function(header, content) {
/// <summary>
/// Create a new Accordion pane given references to its header and content divs
/// and add it to the _panes collection. We also wrap the content div in a new
/// container div, add a click handler to the header div, etc.
/// </summary>
/// <param name="header" type="Sys.UI.DomElement" domElement="true" mayBeNull="false">
/// Header element of the new Accordion pane
/// </param>
/// <param name="content" type="Sys.UI.DomElement" domElement="true" mayBeNull="false">
/// Content element of the new Accordion pane
/// </param>
/// <returns type="Object" mayBeNull="false">
/// New pane object added to the end of the Accordion's pane collection. The pane
/// is an object of the form {header, content, animation} corresponding to that
/// pane's header section, content section, and the animation used to open and
/// close its content section. The content element is a new div that has been
/// created to wrap the original div (so we can completely collapse it - even if it
/// has padding, margins, etc.) which is pointed to by a dynamic _original property.
/// The header element has a dynamic _index property indicating its position in the
/// Accordion's pane collection (used primarily by the headers' shared click handler).
/// Furthermore, the animation will either be an instance of LengthAnimation or
/// ParallelAnimation (in the latter case, it will have two children which are a
/// LengthAnimation and a FadeAnimation). There will be two dynamic properties
/// _length and _fade pointing to each of these children (to easily set the length
/// and fadeEffect properties). There is also a dynamic _ended property which is
/// an event handler to be fired when the animation is complete, a dynamic _opening
/// property to indicate whether the animation was opening or closing the pane, and
/// a dynamic _pane property to provide a reference to the pane that was being
/// animated.
/// </returns>
// Create the new pane object
var pane = { };
pane.animation = null;
// Initialize the header
pane.header = header;
header._index = this._panes.length;
$addHandler(header, "click", this._headerClickHandler);
// Wrap the content in a new element
var accordion = this.get_element();
var wrapper = document.createElement('div');
accordion.insertBefore(wrapper, content);
wrapper.appendChild(content);
wrapper._original = content;
pane.content = wrapper;
// Remove any style facets (possibly) automatically applied by
// CSS selectors so they don't interfere with UI/layout
wrapper.style.border = '';
wrapper.style.margin = '';
wrapper.style.padding = '';
// Add the new pane at the bottom of the accordion
Array.add(this._panes, pane);
// Setup the layout attributes for the pane so that it will be in a proper opened or
// closed state (we don't bother setting the opacity of the wrapper with
// $common.setElementOpacity(wrapper, selected ? 1 : 0); because it will
// be taken care of by the animation)
this._initializePane(header._index);
// Since the content section of the accordion panes will be sent down from the server
// with display: none (so the content sections aren't shown before they're wrapped in
// new divs) we'll turn them back on once they've been wrapped in hidden divs
content.style.display = 'block';
return pane;
},
_getAnimation : function(pane) {
/// <summary>
/// Get the animation for the specified accordion section or demand create
/// the animation if it doesn't already exist.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -