Subversion Repositories ALCASAR

Compare Revisions

Ignore whitespace Rev 2807 → Rev 2808

/web/acc/phpsysinfo/README.ALCASAR
1,5 → 1,5
ALCASAR adaptations :
- remove folders "tools", "sample", "plugins", "js/vendor", "js/jQuery"
- in "/" remove "composer.json", "phpsysinfo.xslt", "phpsysinfo3.xsd", "xml.php", "Dockerfile"
- remove folders "tools", "sample", "plugins", "js/vendor"
- in "/" remove "composer.json", "phpsysinfo.xslt", "phpsysinfo3.xsd", "Dockerfile"
- in folder "templates" : remove all except "aqua", "aqua.css", "html" & "plugin". "Aqua.css" has benn adapted
- language/language.php : $lang is set by the web browser conf
/web/acc/phpsysinfo/js/jQuery/README
0,0 → 1,58
versions, links and simple description of used jquery files
===========================================================
 
 
jquery.js
---------
VERSION : 1.12.4-ff3fix-ff2fix
URL : http://jquery.com/
DESC : jQuery is a fast, concise, JavaScript Library that simplifies how you traverse HTML documents, handle
events, perform animations, and add Ajax interactions to your web pages.
USED : used for the entire userinterface
 
 
jquery.dataTables.js
--------------------
VERSION : 1.8.2+jquery1.9fix+parseJSONfix2+bindfix
URL : http://plugins.jquery.com/project/DataTables
DESC : dataTables is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable
table without page refreshes.
USED : provide tablesorting for the filesystem table
 
jquery.nyroModal.js
-------------------
VERSION : 1.6.2+jquery1.8fix+bindfix
URL : http://plugins.jquery.com/project/nyroModal
DESC : nyroModal is a high customizable modal window plugin.
USED : provide a modal dialog, that is shown when errors are found during execution of the php parsers, or lets say
in this way: if there are error elements in the xml file
 
jquery.timer.js
----------------
VERSION : 0.1
URL : http://plugins.jquery.com/project/Timer; https://github.com/sloat/timer
DESC : provides a cleaner way to handle intervals
USED : automatic reloading of the entire page
 
jquery.jgrowl.js
----------------
VERSION : 1.2.6+jquery1.9fix+jquery3fix+bindfix
URL : http://plugins.jquery.com/project/jGrowl
DESC : jGrowl is a jQuery plugin that raises unobtrusive messages within the browser, similar to the way that OS X's Growl Framework works
USED : show alert and error message
 
jquery.treeTable.js
-------------------
VERSION : 2009-06-22+statefix+spanfix+altfix+undefinedfix+ie6cachefix+multilinefix+divfix
URL : http://plugins.jquery.com/project/jQTreeTable; http://www.hanpau.com/index.php?page=jqtreetable
DESC : Take a plain html table, wrap the rows you want collapsing/expanding in a tbody tag with an id of treetable, map each row to it's parent row, set some options, and let jQTreeTable take it from there.
USED : Hardware, Memory, UPS blocks
 
jquery.ifixpng.js
-------------------
VERSION : 2.1 (23/04/2008)+jquery1.8fix
URL : http://jquery.khurshid.com
DESC : Designed to fix that problem by applying appropriate filters to user specified elements, while keeping all element tags intact.
USED : used for the entire userinterface
 
$Id: README 702 2012-09-21 16:52:32Z namiltd $
/web/acc/phpsysinfo/js/jQuery/README_bootstrap
0,0 → 1,17
versions, links and simple description of used jquery files
===========================================================
 
jquery.js
---------
VERSION : 1.12.4-ff3fix-ff2fix
URL : http://jquery.com/
DESC : jQuery is a fast, concise, JavaScript Library that simplifies how you traverse HTML documents, handle
events, perform animations, and add Ajax interactions to your web pages.
USED : used for the entire userinterface
 
jquery.treegrid.js
-------------------
VERSION : 0.3.0
URL : http://plugins.jquery.com/treegrid/; http://maxazan.github.io/jquery-treegrid/
DESC : TreeGrid is a lightweight and flexible jQuery plugin to create a tree grid component that renders hierarchical, nested and flat data in a table.
USED : Hardware, Memory, UPS blocks
/web/acc/phpsysinfo/js/jQuery/jquery.dataTables.js
0,0 → 1,7440
/*
* File: jquery.dataTables.js
* Version: 1.8.2+jquery1.9fix+parseJSONfix2+bindfix
* Description: Paginate, search and sort HTML tables
* Author: Allan Jardine (www.sprymedia.co.uk)
* Created: 28/3/2008
* Language: Javascript
* License: GPL v2 or BSD 3 point style
* Project: Mtaala
* Contact: allan.jardine@sprymedia.co.uk
*
* Copyright 2008-2011 Allan Jardine, all rights reserved.
*
* This source file is free software, under either the GPL v2 license or a
* BSD style license, as supplied with this software.
*
* This source file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
*
* For details please refer to: http://www.datatables.net
*/
 
/*
* When considering jsLint, we need to allow eval() as it it is used for reading cookies
*/
/*jslint evil: true, undef: true, browser: true */
/*globals $, jQuery,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn*/
 
(function($, window, document) {
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - DataTables variables
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Variable: dataTableSettings
* Purpose: Store the settings for each dataTables instance
* Scope: jQuery.fn
*/
$.fn.dataTableSettings = [];
var _aoSettings = $.fn.dataTableSettings; /* Short reference for fast internal lookup */
/*
* Variable: dataTableExt
* Purpose: Container for customisable parts of DataTables
* Scope: jQuery.fn
*/
$.fn.dataTableExt = {};
var _oExt = $.fn.dataTableExt;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - DataTables extensible objects
*
* The _oExt object is used to provide an area where user defined plugins can be
* added to DataTables. The following properties of the object are used:
* oApi - Plug-in API functions
* aTypes - Auto-detection of types
* oSort - Sorting functions used by DataTables (based on the type)
* oPagination - Pagination functions for different input styles
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Variable: sVersion
* Purpose: Version string for plug-ins to check compatibility
* Scope: jQuery.fn.dataTableExt
* Notes: Allowed format is a.b.c.d.e where:
* a:int, b:int, c:int, d:string(dev|beta), e:int. d and e are optional
*/
_oExt.sVersion = "1.8.2";
/*
* Variable: sErrMode
* Purpose: How should DataTables report an error. Can take the value 'alert' or 'throw'
* Scope: jQuery.fn.dataTableExt
*/
_oExt.sErrMode = "alert";
/*
* Variable: iApiIndex
* Purpose: Index for what 'this' index API functions should use
* Scope: jQuery.fn.dataTableExt
*/
_oExt.iApiIndex = 0;
/*
* Variable: oApi
* Purpose: Container for plugin API functions
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oApi = { };
/*
* Variable: aFiltering
* Purpose: Container for plugin filtering functions
* Scope: jQuery.fn.dataTableExt
*/
_oExt.afnFiltering = [ ];
/*
* Variable: aoFeatures
* Purpose: Container for plugin function functions
* Scope: jQuery.fn.dataTableExt
* Notes: Array of objects with the following parameters:
* fnInit: Function for initialisation of Feature. Takes oSettings and returns node
* cFeature: Character that will be matched in sDom - case sensitive
* sFeature: Feature name - just for completeness :-)
*/
_oExt.aoFeatures = [ ];
/*
* Variable: ofnSearch
* Purpose: Container for custom filtering functions
* Scope: jQuery.fn.dataTableExt
* Notes: This is an object (the name should match the type) for custom filtering function,
* which can be used for live DOM checking or formatted text filtering
*/
_oExt.ofnSearch = { };
/*
* Variable: afnSortData
* Purpose: Container for custom sorting data source functions
* Scope: jQuery.fn.dataTableExt
* Notes: Array (associative) of functions which is run prior to a column of this
* 'SortDataType' being sorted upon.
* Function input parameters:
* object:oSettings- DataTables settings object
* int:iColumn - Target column number
* Return value: Array of data which exactly matched the full data set size for the column to
* be sorted upon
*/
_oExt.afnSortData = [ ];
/*
* Variable: oStdClasses
* Purpose: Storage for the various classes that DataTables uses
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oStdClasses = {
/* Two buttons buttons */
"sPagePrevEnabled": "paginate_enabled_previous",
"sPagePrevDisabled": "paginate_disabled_previous",
"sPageNextEnabled": "paginate_enabled_next",
"sPageNextDisabled": "paginate_disabled_next",
"sPageJUINext": "",
"sPageJUIPrev": "",
/* Full numbers paging buttons */
"sPageButton": "paginate_button",
"sPageButtonActive": "paginate_active",
"sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
"sPageFirst": "first",
"sPagePrevious": "previous",
"sPageNext": "next",
"sPageLast": "last",
/* Striping classes */
"sStripeOdd": "odd",
"sStripeEven": "even",
/* Empty row */
"sRowEmpty": "dataTables_empty",
/* Features */
"sWrapper": "dataTables_wrapper",
"sFilter": "dataTables_filter",
"sInfo": "dataTables_info",
"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
"sLength": "dataTables_length",
"sProcessing": "dataTables_processing",
/* Sorting */
"sSortAsc": "sorting_asc",
"sSortDesc": "sorting_desc",
"sSortable": "sorting", /* Sortable in both directions */
"sSortableAsc": "sorting_asc_disabled",
"sSortableDesc": "sorting_desc_disabled",
"sSortableNone": "sorting_disabled",
"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
"sSortJUIAsc": "",
"sSortJUIDesc": "",
"sSortJUI": "",
"sSortJUIAscAllowed": "",
"sSortJUIDescAllowed": "",
"sSortJUIWrapper": "",
"sSortIcon": "",
/* Scrolling */
"sScrollWrapper": "dataTables_scroll",
"sScrollHead": "dataTables_scrollHead",
"sScrollHeadInner": "dataTables_scrollHeadInner",
"sScrollBody": "dataTables_scrollBody",
"sScrollFoot": "dataTables_scrollFoot",
"sScrollFootInner": "dataTables_scrollFootInner",
/* Misc */
"sFooterTH": ""
};
/*
* Variable: oJUIClasses
* Purpose: Storage for the various classes that DataTables uses - jQuery UI suitable
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oJUIClasses = {
/* Two buttons buttons */
"sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
"sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
"sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
"sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
"sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
"sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
/* Full numbers paging buttons */
"sPageButton": "fg-button ui-button ui-state-default",
"sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
"sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
"sPageFirst": "first ui-corner-tl ui-corner-bl",
"sPagePrevious": "previous",
"sPageNext": "next",
"sPageLast": "last ui-corner-tr ui-corner-br",
/* Striping classes */
"sStripeOdd": "odd",
"sStripeEven": "even",
/* Empty row */
"sRowEmpty": "dataTables_empty",
/* Features */
"sWrapper": "dataTables_wrapper",
"sFilter": "dataTables_filter",
"sInfo": "dataTables_info",
"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
"ui-buttonset-multi paging_", /* Note that the type is postfixed */
"sLength": "dataTables_length",
"sProcessing": "dataTables_processing",
/* Sorting */
"sSortAsc": "ui-state-default",
"sSortDesc": "ui-state-default",
"sSortable": "ui-state-default",
"sSortableAsc": "ui-state-default",
"sSortableDesc": "ui-state-default",
"sSortableNone": "ui-state-default",
"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
"sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
"sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
"sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
"sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
"sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
"sSortJUIWrapper": "DataTables_sort_wrapper",
"sSortIcon": "DataTables_sort_icon",
/* Scrolling */
"sScrollWrapper": "dataTables_scroll",
"sScrollHead": "dataTables_scrollHead ui-state-default",
"sScrollHeadInner": "dataTables_scrollHeadInner",
"sScrollBody": "dataTables_scrollBody",
"sScrollFoot": "dataTables_scrollFoot ui-state-default",
"sScrollFootInner": "dataTables_scrollFootInner",
/* Misc */
"sFooterTH": "ui-state-default"
};
/*
* Variable: oPagination
* Purpose: Container for the various type of pagination that dataTables supports
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oPagination = {
/*
* Variable: two_button
* Purpose: Standard two button (forward/back) pagination
* Scope: jQuery.fn.dataTableExt.oPagination
*/
"two_button": {
/*
* Function: oPagination.two_button.fnInit
* Purpose: Initialise dom elements required for pagination with forward/back buttons only
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* node:nPaging - the DIV which contains this pagination control
* function:fnCallbackDraw - draw function which must be called on update
*/
"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
{
var nPrevious, nNext, nPreviousInner, nNextInner;
/* Store the next and previous elements in the oSettings object as they can be very
* usful for automation - particularly testing
*/
if ( !oSettings.bJUI )
{
nPrevious = document.createElement( 'div' );
nNext = document.createElement( 'div' );
}
else
{
nPrevious = document.createElement( 'a' );
nNext = document.createElement( 'a' );
nNextInner = document.createElement('span');
nNextInner.className = oSettings.oClasses.sPageJUINext;
nNext.appendChild( nNextInner );
nPreviousInner = document.createElement('span');
nPreviousInner.className = oSettings.oClasses.sPageJUIPrev;
nPrevious.appendChild( nPreviousInner );
}
nPrevious.className = oSettings.oClasses.sPagePrevDisabled;
nNext.className = oSettings.oClasses.sPageNextDisabled;
nPrevious.title = oSettings.oLanguage.oPaginate.sPrevious;
nNext.title = oSettings.oLanguage.oPaginate.sNext;
nPaging.appendChild( nPrevious );
nPaging.appendChild( nNext );
$(nPrevious).on( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
{
/* Only draw when the page has actually changed */
fnCallbackDraw( oSettings );
}
} );
$(nNext).on( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
{
fnCallbackDraw( oSettings );
}
} );
/* Take the brutal approach to cancelling text selection */
$(nPrevious).on( 'selectstart.DT', function () { return false; } );
$(nNext).on( 'selectstart.DT', function () { return false; } );
/* ID the first elements only */
if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
{
nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
}
},
/*
* Function: oPagination.two_button.fnUpdate
* Purpose: Update the two button pagination at the end of the draw
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* function:fnCallbackDraw - draw function to call on page change
*/
"fnUpdate": function ( oSettings, fnCallbackDraw )
{
if ( !oSettings.aanFeatures.p )
{
return;
}
/* Loop over each instance of the pager */
var an = oSettings.aanFeatures.p;
for ( var i=0, iLen=an.length ; i<iLen ; i++ )
{
if ( an[i].childNodes.length !== 0 )
{
an[i].childNodes[0].className =
( oSettings._iDisplayStart === 0 ) ?
oSettings.oClasses.sPagePrevDisabled : oSettings.oClasses.sPagePrevEnabled;
an[i].childNodes[1].className =
( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
oSettings.oClasses.sPageNextDisabled : oSettings.oClasses.sPageNextEnabled;
}
}
}
},
/*
* Variable: iFullNumbersShowPages
* Purpose: Change the number of pages which can be seen
* Scope: jQuery.fn.dataTableExt.oPagination
*/
"iFullNumbersShowPages": 5,
/*
* Variable: full_numbers
* Purpose: Full numbers pagination
* Scope: jQuery.fn.dataTableExt.oPagination
*/
"full_numbers": {
/*
* Function: oPagination.full_numbers.fnInit
* Purpose: Initialise dom elements required for pagination with a list of the pages
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* node:nPaging - the DIV which contains this pagination control
* function:fnCallbackDraw - draw function which must be called on update
*/
"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
{
var nFirst = document.createElement( 'span' );
var nPrevious = document.createElement( 'span' );
var nList = document.createElement( 'span' );
var nNext = document.createElement( 'span' );
var nLast = document.createElement( 'span' );
nFirst.innerHTML = oSettings.oLanguage.oPaginate.sFirst;
nPrevious.innerHTML = oSettings.oLanguage.oPaginate.sPrevious;
nNext.innerHTML = oSettings.oLanguage.oPaginate.sNext;
nLast.innerHTML = oSettings.oLanguage.oPaginate.sLast;
var oClasses = oSettings.oClasses;
nFirst.className = oClasses.sPageButton+" "+oClasses.sPageFirst;
nPrevious.className = oClasses.sPageButton+" "+oClasses.sPagePrevious;
nNext.className= oClasses.sPageButton+" "+oClasses.sPageNext;
nLast.className = oClasses.sPageButton+" "+oClasses.sPageLast;
nPaging.appendChild( nFirst );
nPaging.appendChild( nPrevious );
nPaging.appendChild( nList );
nPaging.appendChild( nNext );
nPaging.appendChild( nLast );
$(nFirst).on( 'click.DT', function () {
if ( oSettings.oApi._fnPageChange( oSettings, "first" ) )
{
fnCallbackDraw( oSettings );
}
} );
$(nPrevious).on( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
{
fnCallbackDraw( oSettings );
}
} );
$(nNext).on( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
{
fnCallbackDraw( oSettings );
}
} );
$(nLast).on( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "last" ) )
{
fnCallbackDraw( oSettings );
}
} );
/* Take the brutal approach to cancelling text selection */
$('span', nPaging)
.on( 'mousedown.DT', function () { return false; } )
.on( 'selectstart.DT', function () { return false; } );
/* ID the first elements only */
if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
{
nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
nFirst.setAttribute( 'id', oSettings.sTableId+'_first' );
nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
nLast.setAttribute( 'id', oSettings.sTableId+'_last' );
}
},
/*
* Function: oPagination.full_numbers.fnUpdate
* Purpose: Update the list of page buttons shows
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* function:fnCallbackDraw - draw function to call on page change
*/
"fnUpdate": function ( oSettings, fnCallbackDraw )
{
if ( !oSettings.aanFeatures.p )
{
return;
}
var iPageCount = _oExt.oPagination.iFullNumbersShowPages;
var iPageCountHalf = Math.floor(iPageCount / 2);
var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
var sList = "";
var iStartButton, iEndButton, i, iLen;
var oClasses = oSettings.oClasses;
/* Pages calculation */
if (iPages < iPageCount)
{
iStartButton = 1;
iEndButton = iPages;
}
else
{
if (iCurrentPage <= iPageCountHalf)
{
iStartButton = 1;
iEndButton = iPageCount;
}
else
{
if (iCurrentPage >= (iPages - iPageCountHalf))
{
iStartButton = iPages - iPageCount + 1;
iEndButton = iPages;
}
else
{
iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
iEndButton = iStartButton + iPageCount - 1;
}
}
}
/* Build the dynamic list */
for ( i=iStartButton ; i<=iEndButton ; i++ )
{
if ( iCurrentPage != i )
{
sList += '<span class="'+oClasses.sPageButton+'">'+i+'</span>';
}
else
{
sList += '<span class="'+oClasses.sPageButtonActive+'">'+i+'</span>';
}
}
/* Loop over each instance of the pager */
var an = oSettings.aanFeatures.p;
var anButtons, anStatic, nPaginateList;
var fnClick = function(e) {
/* Use the information in the element to jump to the required page */
var iTarget = (this.innerHTML * 1) - 1;
oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength;
fnCallbackDraw( oSettings );
e.preventDefault();
};
var fnFalse = function () { return false; };
for ( i=0, iLen=an.length ; i<iLen ; i++ )
{
if ( an[i].childNodes.length === 0 )
{
continue;
}
/* Build up the dynamic list forst - html and listeners */
var qjPaginateList = $('span:eq(2)', an[i]);
qjPaginateList.html( sList );
$('span', qjPaginateList).on( 'click.DT', fnClick ).on( 'mousedown.DT', fnFalse )
.on( 'selectstart.DT', fnFalse );
/* Update the 'premanent botton's classes */
anButtons = an[i].getElementsByTagName('span');
anStatic = [
anButtons[0], anButtons[1],
anButtons[anButtons.length-2], anButtons[anButtons.length-1]
];
$(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
if ( iCurrentPage == 1 )
{
anStatic[0].className += " "+oClasses.sPageButtonStaticDisabled;
anStatic[1].className += " "+oClasses.sPageButtonStaticDisabled;
}
else
{
anStatic[0].className += " "+oClasses.sPageButton;
anStatic[1].className += " "+oClasses.sPageButton;
}
if ( iPages === 0 || iCurrentPage == iPages || oSettings._iDisplayLength == -1 )
{
anStatic[2].className += " "+oClasses.sPageButtonStaticDisabled;
anStatic[3].className += " "+oClasses.sPageButtonStaticDisabled;
}
else
{
anStatic[2].className += " "+oClasses.sPageButton;
anStatic[3].className += " "+oClasses.sPageButton;
}
}
}
}
};
/*
* Variable: oSort
* Purpose: Wrapper for the sorting functions that can be used in DataTables
* Scope: jQuery.fn.dataTableExt
* Notes: The functions provided in this object are basically standard javascript sort
* functions - they expect two inputs which they then compare and then return a priority
* result. For each sort method added, two functions need to be defined, an ascending sort and
* a descending sort.
*/
_oExt.oSort = {
/*
* text sorting
*/
"string-asc": function ( a, b )
{
if ( typeof a != 'string' ) { a = ''; }
if ( typeof b != 'string' ) { b = ''; }
var x = a.toLowerCase();
var y = b.toLowerCase();
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
},
"string-desc": function ( a, b )
{
if ( typeof a != 'string' ) { a = ''; }
if ( typeof b != 'string' ) { b = ''; }
var x = a.toLowerCase();
var y = b.toLowerCase();
return ((x < y) ? 1 : ((x > y) ? -1 : 0));
},
/*
* html sorting (ignore html tags)
*/
"html-asc": function ( a, b )
{
var x = a.replace( /<.*?>/g, "" ).toLowerCase();
var y = b.replace( /<.*?>/g, "" ).toLowerCase();
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
},
"html-desc": function ( a, b )
{
var x = a.replace( /<.*?>/g, "" ).toLowerCase();
var y = b.replace( /<.*?>/g, "" ).toLowerCase();
return ((x < y) ? 1 : ((x > y) ? -1 : 0));
},
/*
* date sorting
*/
"date-asc": function ( a, b )
{
var x = Date.parse( a );
var y = Date.parse( b );
if ( isNaN(x) || x==="" )
{
x = Date.parse( "01/01/1970 00:00:00" );
}
if ( isNaN(y) || y==="" )
{
y = Date.parse( "01/01/1970 00:00:00" );
}
return x - y;
},
"date-desc": function ( a, b )
{
var x = Date.parse( a );
var y = Date.parse( b );
if ( isNaN(x) || x==="" )
{
x = Date.parse( "01/01/1970 00:00:00" );
}
if ( isNaN(y) || y==="" )
{
y = Date.parse( "01/01/1970 00:00:00" );
}
return y - x;
},
/*
* numerical sorting
*/
"numeric-asc": function ( a, b )
{
var x = (a=="-" || a==="") ? 0 : a*1;
var y = (b=="-" || b==="") ? 0 : b*1;
return x - y;
},
"numeric-desc": function ( a, b )
{
var x = (a=="-" || a==="") ? 0 : a*1;
var y = (b=="-" || b==="") ? 0 : b*1;
return y - x;
}
};
/*
* Variable: aTypes
* Purpose: Container for the various type of type detection that dataTables supports
* Scope: jQuery.fn.dataTableExt
* Notes: The functions in this array are expected to parse a string to see if it is a data
* type that it recognises. If so then the function should return the name of the type (a
* corresponding sort function should be defined!), if the type is not recognised then the
* function should return null such that the parser and move on to check the next type.
* Note that ordering is important in this array - the functions are processed linearly,
* starting at index 0.
* Note that the input for these functions is always a string! It cannot be any other data
* type
*/
_oExt.aTypes = [
/*
* Function: -
* Purpose: Check to see if a string is numeric
* Returns: string:'numeric' or null
* Inputs: mixed:sText - string to check
*/
function ( sData )
{
/* Allow zero length strings as a number */
if ( typeof sData == 'number' )
{
return 'numeric';
}
else if ( typeof sData != 'string' )
{
return null;
}
var sValidFirstChars = "0123456789-";
var sValidChars = "0123456789.";
var Char;
var bDecimal = false;
/* Check for a valid first char (no period and allow negatives) */
Char = sData.charAt(0);
if (sValidFirstChars.indexOf(Char) == -1)
{
return null;
}
/* Check all the other characters are valid */
for ( var i=1 ; i<sData.length ; i++ )
{
Char = sData.charAt(i);
if (sValidChars.indexOf(Char) == -1)
{
return null;
}
/* Only allowed one decimal place... */
if ( Char == "." )
{
if ( bDecimal )
{
return null;
}
bDecimal = true;
}
}
return 'numeric';
},
/*
* Function: -
* Purpose: Check to see if a string is actually a formatted date
* Returns: string:'date' or null
* Inputs: string:sText - string to check
*/
function ( sData )
{
var iParse = Date.parse(sData);
if ( (iParse !== null && !isNaN(iParse)) || (typeof sData == 'string' && sData.length === 0) )
{
return 'date';
}
return null;
},
/*
* Function: -
* Purpose: Check to see if a string should be treated as an HTML string
* Returns: string:'html' or null
* Inputs: string:sText - string to check
*/
function ( sData )
{
if ( typeof sData == 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
{
return 'html';
}
return null;
}
];
/*
* Function: fnVersionCheck
* Purpose: Check a version string against this version of DataTables. Useful for plug-ins
* Returns: bool:true -this version of DataTables is greater or equal to the required version
* false -this version of DataTales is not suitable
* Inputs: string:sVersion - the version to check against. May be in the following formats:
* "a", "a.b" or "a.b.c"
* Notes: This function will only check the first three parts of a version string. It is
* assumed that beta and dev versions will meet the requirements. This might change in future
*/
_oExt.fnVersionCheck = function( sVersion )
{
/* This is cheap, but very effective */
var fnZPad = function (Zpad, count)
{
while(Zpad.length < count) {
Zpad += '0';
}
return Zpad;
};
var aThis = _oExt.sVersion.split('.');
var aThat = sVersion.split('.');
var sThis = '', sThat = '';
for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
{
sThis += fnZPad( aThis[i], 3 );
sThat += fnZPad( aThat[i], 3 );
}
return parseInt(sThis, 10) >= parseInt(sThat, 10);
};
/*
* Variable: _oExternConfig
* Purpose: Store information for DataTables to access globally about other instances
* Scope: jQuery.fn.dataTableExt
*/
_oExt._oExternConfig = {
/* int:iNextUnique - next unique number for an instance */
"iNextUnique": 0
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - DataTables prototype
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Function: dataTable
* Purpose: DataTables information
* Returns: -
* Inputs: object:oInit - initialisation options for the table
*/
$.fn.dataTable = function( oInit )
{
/*
* Function: classSettings
* Purpose: Settings container function for all 'class' properties which are required
* by dataTables
* Returns: -
* Inputs: -
*/
function classSettings ()
{
this.fnRecordsTotal = function ()
{
if ( this.oFeatures.bServerSide ) {
return parseInt(this._iRecordsTotal, 10);
} else {
return this.aiDisplayMaster.length;
}
};
this.fnRecordsDisplay = function ()
{
if ( this.oFeatures.bServerSide ) {
return parseInt(this._iRecordsDisplay, 10);
} else {
return this.aiDisplay.length;
}
};
this.fnDisplayEnd = function ()
{
if ( this.oFeatures.bServerSide ) {
if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
return this._iDisplayStart+this.aiDisplay.length;
} else {
return Math.min( this._iDisplayStart+this._iDisplayLength,
this._iRecordsDisplay );
}
} else {
return this._iDisplayEnd;
}
};
/*
* Variable: oInstance
* Purpose: The DataTables object for this table
* Scope: jQuery.dataTable.classSettings
*/
this.oInstance = null;
/*
* Variable: sInstance
* Purpose: Unique idendifier for each instance of the DataTables object
* Scope: jQuery.dataTable.classSettings
*/
this.sInstance = null;
/*
* Variable: oFeatures
* Purpose: Indicate the enablement of key dataTable features
* Scope: jQuery.dataTable.classSettings
*/
this.oFeatures = {
"bPaginate": true,
"bLengthChange": true,
"bFilter": true,
"bSort": true,
"bInfo": true,
"bAutoWidth": true,
"bProcessing": false,
"bSortClasses": true,
"bStateSave": false,
"bServerSide": false,
"bDeferRender": false
};
/*
* Variable: oScroll
* Purpose: Container for scrolling options
* Scope: jQuery.dataTable.classSettings
*/
this.oScroll = {
"sX": "",
"sXInner": "",
"sY": "",
"bCollapse": false,
"bInfinite": false,
"iLoadGap": 100,
"iBarWidth": 0,
"bAutoCss": true
};
/*
* Variable: aanFeatures
* Purpose: Array referencing the nodes which are used for the features
* Scope: jQuery.dataTable.classSettings
* Notes: The parameters of this object match what is allowed by sDom - i.e.
* 'l' - Length changing
* 'f' - Filtering input
* 't' - The table!
* 'i' - Information
* 'p' - Pagination
* 'r' - pRocessing
*/
this.aanFeatures = [];
/*
* Variable: oLanguage
* Purpose: Store the language strings used by dataTables
* Scope: jQuery.dataTable.classSettings
* Notes: The words in the format _VAR_ are variables which are dynamically replaced
* by javascript
*/
this.oLanguage = {
"sProcessing": "Processing...",
"sLengthMenu": "Show _MENU_ entries",
"sZeroRecords": "No matching records found",
"sEmptyTable": "No data available in table",
"sLoadingRecords": "Loading...",
"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
"sInfoEmpty": "Showing 0 to 0 of 0 entries",
"sInfoFiltered": "(filtered from _MAX_ total entries)",
"sInfoPostFix": "",
"sInfoThousands": ",",
"sSearch": "Search:",
"sUrl": "",
"oPaginate": {
"sFirst": "First",
"sPrevious": "Previous",
"sNext": "Next",
"sLast": "Last"
},
"fnInfoCallback": null
};
/*
* Variable: aoData
* Purpose: Store data information
* Scope: jQuery.dataTable.classSettings
* Notes: This is an array of objects with the following parameters:
* int: _iId - internal id for tracking
* array: _aData - internal data - used for sorting / filtering etc
* node: nTr - display node
* array node: _anHidden - hidden TD nodes
* string: _sRowStripe
*/
this.aoData = [];
/*
* Variable: aiDisplay
* Purpose: Array of indexes which are in the current display (after filtering etc)
* Scope: jQuery.dataTable.classSettings
*/
this.aiDisplay = [];
/*
* Variable: aiDisplayMaster
* Purpose: Array of indexes for display - no filtering
* Scope: jQuery.dataTable.classSettings
*/
this.aiDisplayMaster = [];
/*
* Variable: aoColumns
* Purpose: Store information about each column that is in use
* Scope: jQuery.dataTable.classSettings
*/
this.aoColumns = [];
/*
* Variable: aoHeader
* Purpose: Store information about the table's header
* Scope: jQuery.dataTable.classSettings
*/
this.aoHeader = [];
/*
* Variable: aoFooter
* Purpose: Store information about the table's footer
* Scope: jQuery.dataTable.classSettings
*/
this.aoFooter = [];
/*
* Variable: iNextId
* Purpose: Store the next unique id to be used for a new row
* Scope: jQuery.dataTable.classSettings
*/
this.iNextId = 0;
/*
* Variable: asDataSearch
* Purpose: Search data array for regular expression searching
* Scope: jQuery.dataTable.classSettings
*/
this.asDataSearch = [];
/*
* Variable: oPreviousSearch
* Purpose: Store the previous search incase we want to force a re-search
* or compare the old search to a new one
* Scope: jQuery.dataTable.classSettings
*/
this.oPreviousSearch = {
"sSearch": "",
"bRegex": false,
"bSmart": true
};
/*
* Variable: aoPreSearchCols
* Purpose: Store the previous search for each column
* Scope: jQuery.dataTable.classSettings
*/
this.aoPreSearchCols = [];
/*
* Variable: aaSorting
* Purpose: Sorting information
* Scope: jQuery.dataTable.classSettings
* Notes: Index 0 - column number
* Index 1 - current sorting direction
* Index 2 - index of asSorting for this column
*/
this.aaSorting = [ [0, 'asc', 0] ];
/*
* Variable: aaSortingFixed
* Purpose: Sorting information that is always applied
* Scope: jQuery.dataTable.classSettings
*/
this.aaSortingFixed = null;
/*
* Variable: asStripeClasses
* Purpose: Classes to use for the striping of a table
* Scope: jQuery.dataTable.classSettings
*/
this.asStripeClasses = [];
/*
* Variable: asDestroyStripes
* Purpose: If restoring a table - we should restore its striping classes as well
* Scope: jQuery.dataTable.classSettings
*/
this.asDestroyStripes = [];
/*
* Variable: sDestroyWidth
* Purpose: If restoring a table - we should restore its width
* Scope: jQuery.dataTable.classSettings
*/
this.sDestroyWidth = 0;
/*
* Variable: fnRowCallback
* Purpose: Call this function every time a row is inserted (draw)
* Scope: jQuery.dataTable.classSettings
*/
this.fnRowCallback = null;
/*
* Variable: fnHeaderCallback
* Purpose: Callback function for the header on each draw
* Scope: jQuery.dataTable.classSettings
*/
this.fnHeaderCallback = null;
/*
* Variable: fnFooterCallback
* Purpose: Callback function for the footer on each draw
* Scope: jQuery.dataTable.classSettings
*/
this.fnFooterCallback = null;
/*
* Variable: aoDrawCallback
* Purpose: Array of callback functions for draw callback functions
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call
* string:sName - name callback (feature). useful for arranging array
*/
this.aoDrawCallback = [];
/*
* Variable: fnPreDrawCallback
* Purpose: Callback function for just before the table is redrawn. A return of false
* will be used to cancel the draw.
* Scope: jQuery.dataTable.classSettings
*/
this.fnPreDrawCallback = null;
/*
* Variable: fnInitComplete
* Purpose: Callback function for when the table has been initialised
* Scope: jQuery.dataTable.classSettings
*/
this.fnInitComplete = null;
/*
* Variable: sTableId
* Purpose: Cache the table ID for quick access
* Scope: jQuery.dataTable.classSettings
*/
this.sTableId = "";
/*
* Variable: nTable
* Purpose: Cache the table node for quick access
* Scope: jQuery.dataTable.classSettings
*/
this.nTable = null;
/*
* Variable: nTHead
* Purpose: Permanent ref to the thead element
* Scope: jQuery.dataTable.classSettings
*/
this.nTHead = null;
/*
* Variable: nTFoot
* Purpose: Permanent ref to the tfoot element - if it exists
* Scope: jQuery.dataTable.classSettings
*/
this.nTFoot = null;
/*
* Variable: nTBody
* Purpose: Permanent ref to the tbody element
* Scope: jQuery.dataTable.classSettings
*/
this.nTBody = null;
/*
* Variable: nTableWrapper
* Purpose: Cache the wrapper node (contains all DataTables controlled elements)
* Scope: jQuery.dataTable.classSettings
*/
this.nTableWrapper = null;
/*
* Variable: bDeferLoading
* Purpose: Indicate if when using server-side processing the loading of data
* should be deferred until the second draw
* Scope: jQuery.dataTable.classSettings
*/
this.bDeferLoading = false;
/*
* Variable: bInitialised
* Purpose: Indicate if all required information has been read in
* Scope: jQuery.dataTable.classSettings
*/
this.bInitialised = false;
/*
* Variable: aoOpenRows
* Purpose: Information about open rows
* Scope: jQuery.dataTable.classSettings
* Notes: Has the parameters 'nTr' and 'nParent'
*/
this.aoOpenRows = [];
/*
* Variable: sDom
* Purpose: Dictate the positioning that the created elements will take
* Scope: jQuery.dataTable.classSettings
* Notes:
* The following options are allowed:
* 'l' - Length changing
* 'f' - Filtering input
* 't' - The table!
* 'i' - Information
* 'p' - Pagination
* 'r' - pRocessing
* The following constants are allowed:
* 'H' - jQueryUI theme "header" classes
* 'F' - jQueryUI theme "footer" classes
* The following syntax is expected:
* '<' and '>' - div elements
* '<"class" and '>' - div with a class
* Examples:
* '<"wrapper"flipt>', '<lf<t>ip>'
*/
this.sDom = 'lfrtip';
/*
* Variable: sPaginationType
* Purpose: Note which type of sorting should be used
* Scope: jQuery.dataTable.classSettings
*/
this.sPaginationType = "two_button";
/*
* Variable: iCookieDuration
* Purpose: The cookie duration (for bStateSave) in seconds - default 2 hours
* Scope: jQuery.dataTable.classSettings
*/
this.iCookieDuration = 60 * 60 * 2;
/*
* Variable: sCookiePrefix
* Purpose: The cookie name prefix
* Scope: jQuery.dataTable.classSettings
*/
this.sCookiePrefix = "SpryMedia_DataTables_";
/*
* Variable: fnCookieCallback
* Purpose: Callback function for cookie creation
* Scope: jQuery.dataTable.classSettings
*/
this.fnCookieCallback = null;
/*
* Variable: aoStateSave
* Purpose: Array of callback functions for state saving
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call. Takes two parameters, oSettings and the JSON string to
* save that has been thus far created. Returns a JSON string to be inserted into a
* json object (i.e. '"param": [ 0, 1, 2]')
* string:sName - name of callback
*/
this.aoStateSave = [];
/*
* Variable: aoStateLoad
* Purpose: Array of callback functions for state loading
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call. Takes two parameters, oSettings and the object stored.
* May return false to cancel state loading.
* string:sName - name of callback
*/
this.aoStateLoad = [];
/*
* Variable: oLoadedState
* Purpose: State that was loaded from the cookie. Useful for back reference
* Scope: jQuery.dataTable.classSettings
*/
this.oLoadedState = null;
/*
* Variable: sAjaxSource
* Purpose: Source url for AJAX data for the table
* Scope: jQuery.dataTable.classSettings
*/
this.sAjaxSource = null;
/*
* Variable: sAjaxDataProp
* Purpose: Property from a given object from which to read the table data from. This can
* be an empty string (when not server-side processing), in which case it is
* assumed an an array is given directly.
* Scope: jQuery.dataTable.classSettings
*/
this.sAjaxDataProp = 'aaData';
/*
* Variable: bAjaxDataGet
* Purpose: Note if draw should be blocked while getting data
* Scope: jQuery.dataTable.classSettings
*/
this.bAjaxDataGet = true;
/*
* Variable: jqXHR
* Purpose: The last jQuery XHR object that was used for server-side data gathering.
* This can be used for working with the XHR information in one of the callbacks
* Scope: jQuery.dataTable.classSettings
*/
this.jqXHR = null;
/*
* Variable: fnServerData
* Purpose: Function to get the server-side data - can be overruled by the developer
* Scope: jQuery.dataTable.classSettings
*/
this.fnServerData = function ( url, data, callback, settings ) {
settings.jqXHR = $.ajax( {
"url": url,
"data": data,
"success": function (json) {
$(settings.oInstance).trigger('xhr', settings);
callback( json );
},
"dataType": "json",
"cache": false,
"error": function (xhr, error, thrown) {
if ( error == "parsererror" ) {
alert( "DataTables warning: JSON data from server could not be parsed. "+
"This is caused by a JSON formatting error." );
}
}
} );
};
/*
* Variable: aoServerParams
* Purpose: Functions which are called prior to sending an Ajax request so extra parameters
* can easily be sent to the server
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call
* string:sName - name callback - useful for knowing where it came from (plugin etc)
*/
this.aoServerParams = [];
/*
* Variable: fnFormatNumber
* Purpose: Format numbers for display
* Scope: jQuery.dataTable.classSettings
*/
this.fnFormatNumber = function ( iIn )
{
if ( iIn < 1000 )
{
/* A small optimisation for what is likely to be the vast majority of use cases */
return iIn;
}
else
{
var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
for ( var i=0 ; i<iLen ; i++ )
{
if ( i%3 === 0 && i !== 0 )
{
out = this.oLanguage.sInfoThousands+out;
}
out = a[iLen-i-1]+out;
}
}
return out;
};
/*
* Variable: aLengthMenu
* Purpose: List of options that can be used for the user selectable length menu
* Scope: jQuery.dataTable.classSettings
* Note: This varaible can take for form of a 1D array, in which case the value and the
* displayed value in the menu are the same, or a 2D array in which case the value comes
* from the first array, and the displayed value to the end user comes from the second
* array. 2D example: [ [ 10, 25, 50, 100, -1 ], [ 10, 25, 50, 100, 'All' ] ];
*/
this.aLengthMenu = [ 10, 25, 50, 100 ];
/*
* Variable: iDraw
* Purpose: Counter for the draws that the table does. Also used as a tracker for
* server-side processing
* Scope: jQuery.dataTable.classSettings
*/
this.iDraw = 0;
/*
* Variable: bDrawing
* Purpose: Indicate if a redraw is being done - useful for Ajax
* Scope: jQuery.dataTable.classSettings
*/
this.bDrawing = 0;
/*
* Variable: iDrawError
* Purpose: Last draw error
* Scope: jQuery.dataTable.classSettings
*/
this.iDrawError = -1;
/*
* Variable: _iDisplayLength, _iDisplayStart, _iDisplayEnd
* Purpose: Display length variables
* Scope: jQuery.dataTable.classSettings
* Notes: These variable must NOT be used externally to get the data length. Rather, use
* the fnRecordsTotal() (etc) functions.
*/
this._iDisplayLength = 10;
this._iDisplayStart = 0;
this._iDisplayEnd = 10;
/*
* Variable: _iRecordsTotal, _iRecordsDisplay
* Purpose: Display length variables used for server side processing
* Scope: jQuery.dataTable.classSettings
* Notes: These variable must NOT be used externally to get the data length. Rather, use
* the fnRecordsTotal() (etc) functions.
*/
this._iRecordsTotal = 0;
this._iRecordsDisplay = 0;
/*
* Variable: bJUI
* Purpose: Should we add the markup needed for jQuery UI theming?
* Scope: jQuery.dataTable.classSettings
*/
this.bJUI = false;
/*
* Variable: oClasses
* Purpose: Should we add the markup needed for jQuery UI theming?
* Scope: jQuery.dataTable.classSettings
*/
this.oClasses = _oExt.oStdClasses;
/*
* Variable: bFiltered and bSorted
* Purpose: Flags to allow callback functions to see what actions have been performed
* Scope: jQuery.dataTable.classSettings
*/
this.bFiltered = false;
this.bSorted = false;
/*
* Variable: bSortCellsTop
* Purpose: Indicate that if multiple rows are in the header and there is more than one
* unique cell per column, if the top one (true) or bottom one (false) should
* be used for sorting / title by DataTables
* Scope: jQuery.dataTable.classSettings
*/
this.bSortCellsTop = false;
/*
* Variable: oInit
* Purpose: Initialisation object that is used for the table
* Scope: jQuery.dataTable.classSettings
*/
this.oInit = null;
/*
* Variable: aoDestroyCallback
* Purpose: Destroy callback functions
* Scope: jQuery.dataTable.classSettings
*/
this.aoDestroyCallback = [];
}
/*
* Variable: oApi
* Purpose: Container for publicly exposed 'private' functions
* Scope: jQuery.dataTable
*/
this.oApi = {};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - API functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Function: fnDraw
* Purpose: Redraw the table
* Returns: -
* Inputs: bool:bComplete - Refilter and resort (if enabled) the table before the draw.
* Optional: default - true
*/
this.fnDraw = function( bComplete )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
if ( typeof bComplete != 'undefined' && bComplete === false )
{
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
else
{
_fnReDraw( oSettings );
}
};
/*
* Function: fnFilter
* Purpose: Filter the input based on data
* Returns: -
* Inputs: string:sInput - string to filter the table on
* int:iColumn - optional - column to limit filtering to
* bool:bRegex - optional - treat as regular expression or not - default false
* bool:bSmart - optional - perform smart filtering or not - default true
* bool:bShowGlobal - optional - show the input global filter in it's input box(es)
* - default true
*/
this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
if ( !oSettings.oFeatures.bFilter )
{
return;
}
if ( typeof bRegex == 'undefined' )
{
bRegex = false;
}
if ( typeof bSmart == 'undefined' )
{
bSmart = true;
}
if ( typeof bShowGlobal == 'undefined' )
{
bShowGlobal = true;
}
if ( typeof iColumn == "undefined" || iColumn === null )
{
/* Global filter */
_fnFilterComplete( oSettings, {
"sSearch":sInput,
"bRegex": bRegex,
"bSmart": bSmart
}, 1 );
if ( bShowGlobal && typeof oSettings.aanFeatures.f != 'undefined' )
{
var n = oSettings.aanFeatures.f;
for ( var i=0, iLen=n.length ; i<iLen ; i++ )
{
$('input', n[i]).val( sInput );
}
}
}
else
{
/* Single column filter */
oSettings.aoPreSearchCols[ iColumn ].sSearch = sInput;
oSettings.aoPreSearchCols[ iColumn ].bRegex = bRegex;
oSettings.aoPreSearchCols[ iColumn ].bSmart = bSmart;
_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
}
};
/*
* Function: fnSettings
* Purpose: Get the settings for a particular table for extern. manipulation
* Returns: -
* Inputs: -
*/
this.fnSettings = function( nNode )
{
return _fnSettingsFromNode( this[_oExt.iApiIndex] );
};
/*
* Function: fnVersionCheck
* Notes: The function is the same as the 'static' function provided in the ext variable
*/
this.fnVersionCheck = _oExt.fnVersionCheck;
/*
* Function: fnSort
* Purpose: Sort the table by a particular row
* Returns: -
* Inputs: int:iCol - the data index to sort on. Note that this will
* not match the 'display index' if you have hidden data entries
*/
this.fnSort = function( aaSort )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
oSettings.aaSorting = aaSort;
_fnSort( oSettings );
};
/*
* Function: fnSortListener
* Purpose: Attach a sort listener to an element for a given column
* Returns: -
* Inputs: node:nNode - the element to attach the sort listener to
* int:iColumn - the column that a click on this node will sort on
* function:fnCallback - callback function when sort is run - optional
*/
this.fnSortListener = function( nNode, iColumn, fnCallback )
{
_fnSortAttachListener( _fnSettingsFromNode( this[_oExt.iApiIndex] ), nNode, iColumn,
fnCallback );
};
/*
* Function: fnAddData
* Purpose: Add new row(s) into the table
* Returns: array int: array of indexes (aoData) which have been added (zero length on error)
* Inputs: array:mData - the data to be added. The length must match
* the original data from the DOM
* or
* array array:mData - 2D array of data to be added
* bool:bRedraw - redraw the table or not - default true
* Notes: Warning - the refilter here will cause the table to redraw
* starting at zero
* Notes: Thanks to Yekimov Denis for contributing the basis for this function!
*/
this.fnAddData = function( mData, bRedraw )
{
if ( mData.length === 0 )
{
return [];
}
var aiReturn = [];
var iTest;
/* Find settings from table node */
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
/* Check if we want to add multiple rows or not */
if ( typeof mData[0] == "object" )
{
for ( var i=0 ; i<mData.length ; i++ )
{
iTest = _fnAddData( oSettings, mData[i] );
if ( iTest == -1 )
{
return aiReturn;
}
aiReturn.push( iTest );
}
}
else
{
iTest = _fnAddData( oSettings, mData );
if ( iTest == -1 )
{
return aiReturn;
}
aiReturn.push( iTest );
}
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
if ( typeof bRedraw == 'undefined' || bRedraw )
{
_fnReDraw( oSettings );
}
return aiReturn;
};
/*
* Function: fnDeleteRow
* Purpose: Remove a row for the table
* Returns: array:aReturn - the row that was deleted
* Inputs: mixed:mTarget -
* int: - index of aoData to be deleted, or
* node(TR): - TR element you want to delete
* function:fnCallBack - callback function - default null
* bool:bRedraw - redraw the table or not - default true
*/
this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
{
/* Find settings from table node */
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
var i, iAODataIndex;
iAODataIndex = (typeof mTarget == 'object') ?
_fnNodeToDataIndex(oSettings, mTarget) : mTarget;
/* Return the data array from this row */
var oData = oSettings.aoData.splice( iAODataIndex, 1 );
/* Remove the target row from the search array */
var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
oSettings.asDataSearch.splice( iDisplayIndex, 1 );
/* Delete from the display arrays */
_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
/* If there is a user callback function - call it */
if ( typeof fnCallBack == "function" )
{
fnCallBack.call( this, oSettings, oData );
}
/* Check for an 'overflow' they case for dislaying the table */
if ( oSettings._iDisplayStart >= oSettings.aiDisplay.length )
{
oSettings._iDisplayStart -= oSettings._iDisplayLength;
if ( oSettings._iDisplayStart < 0 )
{
oSettings._iDisplayStart = 0;
}
}
if ( typeof bRedraw == 'undefined' || bRedraw )
{
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
return oData;
};
/*
* Function: fnClearTable
* Purpose: Quickly and simply clear a table
* Returns: -
* Inputs: bool:bRedraw - redraw the table or not - default true
* Notes: Thanks to Yekimov Denis for contributing the basis for this function!
*/
this.fnClearTable = function( bRedraw )
{
/* Find settings from table node */
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
_fnClearTable( oSettings );
if ( typeof bRedraw == 'undefined' || bRedraw )
{
_fnDraw( oSettings );
}
};
/*
* Function: fnOpen
* Purpose: Open a display row (append a row after the row in question)
* Returns: node:nNewRow - the row opened
* Inputs: node:nTr - the table row to 'open'
* string|node|jQuery:mHtml - the HTML to put into the row
* string:sClass - class to give the new TD cell
*/
this.fnOpen = function( nTr, mHtml, sClass )
{
/* Find settings from table node */
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
/* the old open one if there is one */
this.fnClose( nTr );
var nNewRow = document.createElement("tr");
var nNewCell = document.createElement("td");
nNewRow.appendChild( nNewCell );
nNewCell.className = sClass;
nNewCell.colSpan = _fnVisbleColumns( oSettings );
 
if( typeof mHtml.jquery != 'undefined' || typeof mHtml == "object" )
{
nNewCell.appendChild( mHtml );
}
else
{
nNewCell.innerHTML = mHtml;
}
 
/* If the nTr isn't on the page at the moment - then we don't insert at the moment */
var nTrs = $('tr', oSettings.nTBody);
if ( $.inArray(nTr, nTrs) != -1 )
{
$(nNewRow).insertAfter(nTr);
}
oSettings.aoOpenRows.push( {
"nTr": nNewRow,
"nParent": nTr
} );
return nNewRow;
};
/*
* Function: fnClose
* Purpose: Close a display row
* Returns: int: 0 (success) or 1 (failed)
* Inputs: node:nTr - the table row to 'close'
*/
this.fnClose = function( nTr )
{
/* Find settings from table node */
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
{
if ( oSettings.aoOpenRows[i].nParent == nTr )
{
var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
if ( nTrParent )
{
/* Remove it if it is currently on display */
nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
}
oSettings.aoOpenRows.splice( i, 1 );
return 0;
}
}
return 1;
};
/*
* Function: fnGetData
* Purpose: Return an array with the data which is used to make up the table
* Returns: array array string: 2d data array ([row][column]) or array string: 1d data array
* or string if both row and column are given
* Inputs: mixed:mRow - optional - if not present, then the full 2D array for the table
* if given then:
* int: - return data object for aoData entry of this index
* node(TR): - return data object for this TR element
* int:iCol - optional - the column that you want the data of. This will take into
* account mDataProp and return the value DataTables uses for this column
*/
this.fnGetData = function( mRow, iCol )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
if ( typeof mRow != 'undefined' )
{
var iRow = (typeof mRow == 'object') ?
_fnNodeToDataIndex(oSettings, mRow) : mRow;
if ( typeof iCol != 'undefined' )
{
return _fnGetCellData( oSettings, iRow, iCol, '' );
}
return (typeof oSettings.aoData[iRow] != 'undefined') ?
oSettings.aoData[iRow]._aData : null;
}
return _fnGetDataMaster( oSettings );
};
/*
* Function: fnGetNodes
* Purpose: Return an array with the TR nodes used for drawing the table
* Returns: array node: TR elements
* or
* node (if iRow specified)
* Inputs: int:iRow - optional - if present then the array returned will be the node for
* the row with the index 'iRow'
*/
this.fnGetNodes = function( iRow )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
if ( typeof iRow != 'undefined' )
{
return (typeof oSettings.aoData[iRow] != 'undefined') ? oSettings.aoData[iRow].nTr : null;
}
return _fnGetTrNodes( oSettings );
};
/*
* Function: fnGetPosition
* Purpose: Get the array indexes of a particular cell from it's DOM element
* Returns: int: - row index, or array[ int, int, int ]: - row index, column index (visible)
* and column index including hidden columns
* Inputs: node:nNode - this can either be a TR, TD or TH in the table's body, the return is
* dependent on this input
*/
this.fnGetPosition = function( nNode )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
var sNodeName = nNode.nodeName.toUpperCase();
if ( sNodeName == "TR" )
{
return _fnNodeToDataIndex(oSettings, nNode);
}
else if ( sNodeName == "TD" || sNodeName == "TH" )
{
var iDataIndex = _fnNodeToDataIndex(oSettings, nNode.parentNode);
var anCells = _fnGetTdNodes( oSettings, iDataIndex );
 
for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
{
if ( anCells[i] == nNode )
{
return [ iDataIndex, _fnColumnIndexToVisible(oSettings, i ), i ];
}
}
}
return null;
};
/*
* Function: fnUpdate
* Purpose: Update a table cell or row - this method will accept either a single value to
* update the cell with, an array of values with one element for each column or
* an object in the same format as the original data source. The function is
* self-referencing in order to make the multi column updates easier.
* Returns: int: 0 okay, 1 error
* Inputs: object | array string | string:mData - data to update the cell/row with
* mixed:mRow -
* int: - index of aoData to be updated, or
* node(TR): - TR element you want to update
* int:iColumn - the column to update - optional (not used of mData is an array or object)
* bool:bRedraw - redraw the table or not - default true
* bool:bAction - perform predraw actions or not (you will want this as 'true' if
* you have bRedraw as true) - default true
*/
this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
var iVisibleColumn, i, iLen, sDisplay;
var iRow = (typeof mRow == 'object') ?
_fnNodeToDataIndex(oSettings, mRow) : mRow;
if ( $.isArray(mData) && typeof mData == 'object' )
{
/* Array update - update the whole row */
oSettings.aoData[iRow]._aData = mData.slice();
 
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
}
}
else if ( mData !== null && typeof mData == 'object' )
{
/* Object update - update the whole row - assume the developer gets the object right */
oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
 
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
}
}
else
{
/* Individual cell update */
sDisplay = mData;
_fnSetCellData( oSettings, iRow, iColumn, sDisplay );
if ( oSettings.aoColumns[iColumn].fnRender !== null )
{
sDisplay = oSettings.aoColumns[iColumn].fnRender( {
"iDataRow": iRow,
"iDataColumn": iColumn,
"aData": oSettings.aoData[iRow]._aData,
"oSettings": oSettings
} );
if ( oSettings.aoColumns[iColumn].bUseRendered )
{
_fnSetCellData( oSettings, iRow, iColumn, sDisplay );
}
}
if ( oSettings.aoData[iRow].nTr !== null )
{
/* Do the actual HTML update */
_fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
}
}
/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
* will rebuild the search array - however, the redraw might be disabled by the user)
*/
var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( oSettings,
_fnGetRowData( oSettings, iRow, 'filter' ) );
/* Perform pre-draw actions */
if ( typeof bAction == 'undefined' || bAction )
{
_fnAdjustColumnSizing( oSettings );
}
/* Redraw the table */
if ( typeof bRedraw == 'undefined' || bRedraw )
{
_fnReDraw( oSettings );
}
return 0;
};
/*
* Function: fnShowColoumn
* Purpose: Show a particular column
* Returns: -
* Inputs: int:iCol - the column whose display should be changed
* bool:bShow - show (true) or hide (false) the column
* bool:bRedraw - redraw the table or not - default true
*/
this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
var i, iLen;
var iColumns = oSettings.aoColumns.length;
var nTd, nCell, anTrs, jqChildren, bAppend, iBefore;
/* No point in doing anything if we are requesting what is already true */
if ( oSettings.aoColumns[iCol].bVisible == bShow )
{
return;
}
/* Show the column */
if ( bShow )
{
var iInsert = 0;
for ( i=0 ; i<iCol ; i++ )
{
if ( oSettings.aoColumns[i].bVisible )
{
iInsert++;
}
}
/* Need to decide if we should use appendChild or insertBefore */
bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
 
/* Which coloumn should we be inserting before? */
if ( !bAppend )
{
for ( i=iCol ; i<iColumns ; i++ )
{
if ( oSettings.aoColumns[i].bVisible )
{
iBefore = i;
break;
}
}
}
 
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
{
if ( oSettings.aoData[i].nTr !== null )
{
if ( bAppend )
{
oSettings.aoData[i].nTr.appendChild(
oSettings.aoData[i]._anHidden[iCol]
);
}
else
{
oSettings.aoData[i].nTr.insertBefore(
oSettings.aoData[i]._anHidden[iCol],
_fnGetTdNodes( oSettings, i )[iBefore] );
}
}
}
}
else
{
/* Remove a column from display */
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
{
if ( oSettings.aoData[i].nTr !== null )
{
nTd = _fnGetTdNodes( oSettings, i )[iCol];
oSettings.aoData[i]._anHidden[iCol] = nTd;
nTd.parentNode.removeChild( nTd );
}
}
}
 
/* Clear to set the visible flag */
oSettings.aoColumns[iCol].bVisible = bShow;
 
/* Redraw the header and footer based on the new column visibility */
_fnDrawHead( oSettings, oSettings.aoHeader );
if ( oSettings.nTFoot )
{
_fnDrawHead( oSettings, oSettings.aoFooter );
}
/* If there are any 'open' rows, then we need to alter the colspan for this col change */
for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
{
oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
}
/* Do a redraw incase anything depending on the table columns needs it
* (built-in: scrolling)
*/
if ( typeof bRedraw == 'undefined' || bRedraw )
{
_fnAdjustColumnSizing( oSettings );
_fnDraw( oSettings );
}
_fnSaveState( oSettings );
};
/*
* Function: fnPageChange
* Purpose: Change the pagination
* Returns: -
* Inputs: string:sAction - paging action to take: "first", "previous", "next" or "last"
* bool:bRedraw - redraw the table or not - optional - default true
*/
this.fnPageChange = function ( sAction, bRedraw )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
_fnPageChange( oSettings, sAction );
_fnCalculateEnd( oSettings );
if ( typeof bRedraw == 'undefined' || bRedraw )
{
_fnDraw( oSettings );
}
};
/*
* Function: fnDestroy
* Purpose: Destructor for the DataTable
* Returns: -
* Inputs: -
*/
this.fnDestroy = function ( )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
var nOrig = oSettings.nTableWrapper.parentNode;
var nBody = oSettings.nTBody;
var i, iLen;
/* Flag to note that the table is currently being destoryed - no action should be taken */
oSettings.bDestroying = true;
/* Restore hidden columns */
for ( i=0, iLen=oSettings.aoDestroyCallback.length ; i<iLen ; i++ ) {
oSettings.aoDestroyCallback[i].fn();
}
/* Restore hidden columns */
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
if ( oSettings.aoColumns[i].bVisible === false )
{
this.fnSetColumnVis( i, true );
}
}
/* Blitz all DT events */
$(oSettings.nTableWrapper).find('*').andSelf().off('.DT');
/* If there is an 'empty' indicator row, remove it */
$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
/* When scrolling we had to break the table up - restore it */
if ( oSettings.nTable != oSettings.nTHead.parentNode )
{
$(oSettings.nTable).children('thead').remove();
oSettings.nTable.appendChild( oSettings.nTHead );
}
if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
{
$(oSettings.nTable).children('tfoot').remove();
oSettings.nTable.appendChild( oSettings.nTFoot );
}
/* Remove the DataTables generated nodes, events and classes */
oSettings.nTable.parentNode.removeChild( oSettings.nTable );
$(oSettings.nTableWrapper).remove();
oSettings.aaSorting = [];
oSettings.aaSortingFixed = [];
_fnSortingClasses( oSettings );
$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
if ( !oSettings.bJUI )
{
$('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
_oExt.oStdClasses.sSortableAsc,
_oExt.oStdClasses.sSortableDesc,
_oExt.oStdClasses.sSortableNone ].join(' ')
);
}
else
{
$('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
_oExt.oJUIClasses.sSortableAsc,
_oExt.oJUIClasses.sSortableDesc,
_oExt.oJUIClasses.sSortableNone ].join(' ')
);
$('th span.'+_oExt.oJUIClasses.sSortIcon, oSettings.nTHead).remove();
 
$('th', oSettings.nTHead).each( function () {
var jqWrapper = $('div.'+_oExt.oJUIClasses.sSortJUIWrapper, this);
var kids = jqWrapper.contents();
$(this).append( kids );
jqWrapper.remove();
} );
}
/* Add the TR elements back into the table in their original order */
if ( oSettings.nTableReinsertBefore )
{
nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
}
else
{
nOrig.appendChild( oSettings.nTable );
}
 
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
{
if ( oSettings.aoData[i].nTr !== null )
{
nBody.appendChild( oSettings.aoData[i].nTr );
}
}
/* Restore the width of the original table */
if ( oSettings.oFeatures.bAutoWidth === true )
{
oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
}
/* If the were originally odd/even type classes - then we add them back here. Note
* this is not fool proof (for example if not all rows as odd/even classes - but
* it's a good effort without getting carried away
*/
$(nBody).children('tr:even').addClass( oSettings.asDestroyStripes[0] );
$(nBody).children('tr:odd').addClass( oSettings.asDestroyStripes[1] );
/* Remove the settings object from the settings array */
for ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )
{
if ( _aoSettings[i] == oSettings )
{
_aoSettings.splice( i, 1 );
}
}
/* End it all */
oSettings = null;
};
/*
* Function: fnAdjustColumnSizing
* Purpose: Update table sizing based on content. This would most likely be used for scrolling
* and will typically need a redraw after it.
* Returns: -
* Inputs: bool:bRedraw - redraw the table or not, you will typically want to - default true
*/
this.fnAdjustColumnSizing = function ( bRedraw )
{
var oSettings = _fnSettingsFromNode(this[_oExt.iApiIndex]);
_fnAdjustColumnSizing( oSettings );
if ( typeof bRedraw == 'undefined' || bRedraw )
{
this.fnDraw( false );
}
else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
{
/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
this.oApi._fnScrollDraw(oSettings);
}
};
/*
* Plugin API functions
*
* This call will add the functions which are defined in _oExt.oApi to the
* DataTables object, providing a rather nice way to allow plug-in API functions. Note that
* this is done here, so that API function can actually override the built in API functions if
* required for a particular purpose.
*/
/*
* Function: _fnExternApiFunc
* Purpose: Create a wrapper function for exporting an internal func to an external API func
* Returns: function: - wrapped function
* Inputs: string:sFunc - API function name
*/
function _fnExternApiFunc (sFunc)
{
return function() {
var aArgs = [_fnSettingsFromNode(this[_oExt.iApiIndex])].concat(
Array.prototype.slice.call(arguments) );
return _oExt.oApi[sFunc].apply( this, aArgs );
};
}
for ( var sFunc in _oExt.oApi )
{
if ( sFunc )
{
/*
* Function: anon
* Purpose: Wrap the plug-in API functions in order to provide the settings as 1st arg
* and execute in this scope
* Returns: -
* Inputs: -
*/
this[sFunc] = _fnExternApiFunc(sFunc);
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Local functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Initialisation
*/
/*
* Function: _fnInitialise
* Purpose: Draw the table for the first time, adding all required features
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnInitialise ( oSettings )
{
var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
/* Ensure that the table data is fully initialised */
if ( oSettings.bInitialised === false )
{
setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
return;
}
/* Show the display HTML options */
_fnAddOptionsHtml( oSettings );
/* Build and draw the header / footer for the table */
_fnBuildHead( oSettings );
_fnDrawHead( oSettings, oSettings.aoHeader );
if ( oSettings.nTFoot )
{
_fnDrawHead( oSettings, oSettings.aoFooter );
}
 
/* Okay to show that something is going on now */
_fnProcessingDisplay( oSettings, true );
/* Calculate sizes for columns */
if ( oSettings.oFeatures.bAutoWidth )
{
_fnCalculateColumnWidths( oSettings );
}
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
if ( oSettings.aoColumns[i].sWidth !== null )
{
oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
}
}
/* If there is default sorting required - let's do it. The sort function will do the
* drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
* the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
*/
if ( oSettings.oFeatures.bSort )
{
_fnSort( oSettings );
}
else if ( oSettings.oFeatures.bFilter )
{
_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
}
else
{
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
/* if there is an ajax source load the data */
if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
{
var aoData = [];
_fnServerParams( oSettings, aoData );
oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
var aData = json;
if ( oSettings.sAjaxDataProp !== "" )
{
var fnDataSrc = _fnGetObjectDataFn( oSettings.sAjaxDataProp );
aData = fnDataSrc( json );
}
 
/* Got the data - add it to the table */
for ( i=0 ; i<aData.length ; i++ )
{
_fnAddData( oSettings, aData[i] );
}
/* Reset the init display for cookie saving. We've already done a filter, and
* therefore cleared it before. So we need to make it appear 'fresh'
*/
oSettings.iInitDisplayStart = iAjaxStart;
if ( oSettings.oFeatures.bSort )
{
_fnSort( oSettings );
}
else
{
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
_fnProcessingDisplay( oSettings, false );
_fnInitComplete( oSettings, json );
}, oSettings );
return;
}
/* Server-side processing initialisation complete is done at the end of _fnDraw */
if ( !oSettings.oFeatures.bServerSide )
{
_fnProcessingDisplay( oSettings, false );
_fnInitComplete( oSettings );
}
}
/*
* Function: _fnInitComplete
* Purpose: Draw the table for the first time, adding all required features
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnInitComplete ( oSettings, json )
{
oSettings._bInitComplete = true;
if ( typeof oSettings.fnInitComplete == 'function' )
{
if ( typeof json != 'undefined' )
{
oSettings.fnInitComplete.call( oSettings.oInstance, oSettings, json );
}
else
{
oSettings.fnInitComplete.call( oSettings.oInstance, oSettings );
}
}
}
/*
* Function: _fnLanguageProcess
* Purpose: Copy language variables from remote object to a local one
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* object:oLanguage - Language information
* bool:bInit - init once complete
*/
function _fnLanguageProcess( oSettings, oLanguage, bInit )
{
oSettings.oLanguage = $.extend( true, oSettings.oLanguage, oLanguage );
/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
* sZeroRecords - assuming that is given.
*/
if ( typeof oLanguage.sEmptyTable == 'undefined' &&
typeof oLanguage.sZeroRecords != 'undefined' )
{
_fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
}
 
/* Likewise with loading records */
if ( typeof oLanguage.sLoadingRecords == 'undefined' &&
typeof oLanguage.sZeroRecords != 'undefined' )
{
_fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
}
if ( bInit )
{
_fnInitialise( oSettings );
}
}
/*
* Function: _fnAddColumn
* Purpose: Add a column to the list used for the table with default values
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* node:nTh - the th element for this column
*/
function _fnAddColumn( oSettings, nTh )
{
var iCol = oSettings.aoColumns.length;
var oCol = {
"sType": null,
"_bAutoType": true,
"bVisible": true,
"bSearchable": true,
"bSortable": true,
"asSorting": [ 'asc', 'desc' ],
"sSortingClass": oSettings.oClasses.sSortable,
"sSortingClassJUI": oSettings.oClasses.sSortJUI,
"sTitle": nTh ? nTh.innerHTML : '',
"sName": '',
"sWidth": null,
"sWidthOrig": null,
"sClass": null,
"fnRender": null,
"bUseRendered": true,
"iDataSort": iCol,
"mDataProp": iCol,
"fnGetData": null,
"fnSetData": null,
"sSortDataType": 'std',
"sDefaultContent": null,
"sContentPadding": "",
"nTh": nTh ? nTh : document.createElement('th'),
"nTf": null
};
oSettings.aoColumns.push( oCol );
/* Add a column specific filter */
if ( typeof oSettings.aoPreSearchCols[ iCol ] == 'undefined' ||
oSettings.aoPreSearchCols[ iCol ] === null )
{
oSettings.aoPreSearchCols[ iCol ] = {
"sSearch": "",
"bRegex": false,
"bSmart": true
};
}
else
{
/* Don't require that the user must specify bRegex and / or bSmart */
if ( typeof oSettings.aoPreSearchCols[ iCol ].bRegex == 'undefined' )
{
oSettings.aoPreSearchCols[ iCol ].bRegex = true;
}
if ( typeof oSettings.aoPreSearchCols[ iCol ].bSmart == 'undefined' )
{
oSettings.aoPreSearchCols[ iCol ].bSmart = true;
}
}
/* Use the column options function to initialise classes etc */
_fnColumnOptions( oSettings, iCol, null );
}
/*
* Function: _fnColumnOptions
* Purpose: Apply options for a column
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* int:iCol - column index to consider
* object:oOptions - object with sType, bVisible and bSearchable
*/
function _fnColumnOptions( oSettings, iCol, oOptions )
{
var oCol = oSettings.aoColumns[ iCol ];
/* User specified column options */
if ( typeof oOptions != 'undefined' && oOptions !== null )
{
if ( typeof oOptions.sType != 'undefined' )
{
oCol.sType = oOptions.sType;
oCol._bAutoType = false;
}
_fnMap( oCol, oOptions, "bVisible" );
_fnMap( oCol, oOptions, "bSearchable" );
_fnMap( oCol, oOptions, "bSortable" );
_fnMap( oCol, oOptions, "sTitle" );
_fnMap( oCol, oOptions, "sName" );
_fnMap( oCol, oOptions, "sWidth" );
_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
_fnMap( oCol, oOptions, "sClass" );
_fnMap( oCol, oOptions, "fnRender" );
_fnMap( oCol, oOptions, "bUseRendered" );
_fnMap( oCol, oOptions, "iDataSort" );
_fnMap( oCol, oOptions, "mDataProp" );
_fnMap( oCol, oOptions, "asSorting" );
_fnMap( oCol, oOptions, "sSortDataType" );
_fnMap( oCol, oOptions, "sDefaultContent" );
_fnMap( oCol, oOptions, "sContentPadding" );
}
 
/* Cache the data get and set functions for speed */
oCol.fnGetData = _fnGetObjectDataFn( oCol.mDataProp );
oCol.fnSetData = _fnSetObjectDataFn( oCol.mDataProp );
/* Feature sorting overrides column specific when off */
if ( !oSettings.oFeatures.bSort )
{
oCol.bSortable = false;
}
/* Check that the class assignment is correct for sorting */
if ( !oCol.bSortable ||
($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
{
oCol.sSortingClass = oSettings.oClasses.sSortableNone;
oCol.sSortingClassJUI = "";
}
else if ( oCol.bSortable ||
($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
{
oCol.sSortingClass = oSettings.oClasses.sSortable;
oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
}
else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
{
oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
}
else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
{
oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
}
}
/*
* Function: _fnAddData
* Purpose: Add a data array to the table, creating DOM node etc
* Returns: int: - >=0 if successful (index of new aoData entry), -1 if failed
* Inputs: object:oSettings - dataTables settings object
* array:aData - data array to be added
* Notes: There are two basic methods for DataTables to get data to display - a JS array
* (which is dealt with by this function), and the DOM, which has it's own optimised
* function (_fnGatherData). Be careful to make the same changes here as there and vice-versa
*/
function _fnAddData ( oSettings, aDataSupplied )
{
var oCol;
/* Take an independent copy of the data source so we can bash it about as we wish */
var aDataIn = ($.isArray(aDataSupplied)) ?
aDataSupplied.slice() :
$.extend( true, {}, aDataSupplied );
/* Create the object for storing information about this new row */
var iRow = oSettings.aoData.length;
var oData = {
"nTr": null,
"_iId": oSettings.iNextId++,
"_aData": aDataIn,
"_anHidden": [],
"_sRowStripe": ""
};
oSettings.aoData.push( oData );
 
/* Create the cells */
var nTd, sThisType;
for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
oCol = oSettings.aoColumns[i];
 
/* Use rendered data for filtering/sorting */
if ( typeof oCol.fnRender == 'function' && oCol.bUseRendered && oCol.mDataProp !== null )
{
_fnSetCellData( oSettings, iRow, i, oCol.fnRender( {
"iDataRow": iRow,
"iDataColumn": i,
"aData": oData._aData,
"oSettings": oSettings
} ) );
}
/* See if we should auto-detect the column type */
if ( oCol._bAutoType && oCol.sType != 'string' )
{
/* Attempt to auto detect the type - same as _fnGatherData() */
var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
if ( sVarType !== null && sVarType !== '' )
{
sThisType = _fnDetectType( sVarType );
if ( oCol.sType === null )
{
oCol.sType = sThisType;
}
else if ( oCol.sType != sThisType && oCol.sType != "html" )
{
/* String is always the 'fallback' option */
oCol.sType = 'string';
}
}
}
}
/* Add to the display array */
oSettings.aiDisplayMaster.push( iRow );
 
/* Create the DOM imformation */
if ( !oSettings.oFeatures.bDeferRender )
{
_fnCreateTr( oSettings, iRow );
}
 
return iRow;
}
/*
* Function: _fnCreateTr
* Purpose: Create a new TR element (and it's TD children) for a row
* Returns: void
* Inputs: object:oSettings - dataTables settings object
* int:iRow - Row to consider
*/
function _fnCreateTr ( oSettings, iRow )
{
var oData = oSettings.aoData[iRow];
var nTd;
 
if ( oData.nTr === null )
{
oData.nTr = document.createElement('tr');
 
/* Special parameters can be given by the data source to be used on the row */
if ( typeof oData._aData.DT_RowId != 'undefined' )
{
oData.nTr.setAttribute( 'id', oData._aData.DT_RowId );
}
 
if ( typeof oData._aData.DT_RowClass != 'undefined' )
{
$(oData.nTr).addClass( oData._aData.DT_RowClass );
}
 
/* Process each column */
for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
var oCol = oSettings.aoColumns[i];
nTd = document.createElement('td');
 
/* Render if needed - if bUseRendered is true then we already have the rendered
* value in the data source - so can just use that
*/
if ( typeof oCol.fnRender == 'function' && (!oCol.bUseRendered || oCol.mDataProp === null) )
{
nTd.innerHTML = oCol.fnRender( {
"iDataRow": iRow,
"iDataColumn": i,
"aData": oData._aData,
"oSettings": oSettings
} );
}
else
{
nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
}
/* Add user defined class */
if ( oCol.sClass !== null )
{
nTd.className = oCol.sClass;
}
if ( oCol.bVisible )
{
oData.nTr.appendChild( nTd );
oData._anHidden[i] = null;
}
else
{
oData._anHidden[i] = nTd;
}
}
}
}
/*
* Function: _fnGatherData
* Purpose: Read in the data from the target table from the DOM
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* Notes: This is a optimised version of _fnAddData (more or less) for reading information
* from the DOM. The basic actions must be identical in the two functions.
*/
function _fnGatherData( oSettings )
{
var iLoop, i, iLen, j, jLen, jInner,
nTds, nTrs, nTd, aLocalData, iThisIndex,
iRow, iRows, iColumn, iColumns, sNodeName;
/*
* Process by row first
* Add the data object for the whole table - storing the tr node. Note - no point in getting
* DOM based data if we are going to go and replace it with Ajax source data.
*/
if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
{
nTrs = oSettings.nTBody.childNodes;
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
{
if ( nTrs[i].nodeName.toUpperCase() == "TR" )
{
iThisIndex = oSettings.aoData.length;
oSettings.aoData.push( {
"nTr": nTrs[i],
"_iId": oSettings.iNextId++,
"_aData": [],
"_anHidden": [],
"_sRowStripe": ''
} );
oSettings.aiDisplayMaster.push( iThisIndex );
nTds = nTrs[i].childNodes;
jInner = 0;
for ( j=0, jLen=nTds.length ; j<jLen ; j++ )
{
sNodeName = nTds[j].nodeName.toUpperCase();
if ( sNodeName == "TD" || sNodeName == "TH" )
{
_fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTds[j].innerHTML) );
jInner++;
}
}
}
}
}
/* Gather in the TD elements of the Table - note that this is basically the same as
* fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
* setup!
*/
nTrs = _fnGetTrNodes( oSettings );
nTds = [];
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
{
for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
{
nTd = nTrs[i].childNodes[j];
sNodeName = nTd.nodeName.toUpperCase();
if ( sNodeName == "TD" || sNodeName == "TH" )
{
nTds.push( nTd );
}
}
}
/* Sanity check */
if ( nTds.length != nTrs.length * oSettings.aoColumns.length )
{
_fnLog( oSettings, 1, "Unexpected number of TD elements. Expected "+
(nTrs.length * oSettings.aoColumns.length)+" and got "+nTds.length+". DataTables does "+
"not support rowspan / colspan in the table body, and there must be one cell for each "+
"row/column combination." );
}
/* Now process by column */
for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
{
/* Get the title of the column - unless there is a user set one */
if ( oSettings.aoColumns[iColumn].sTitle === null )
{
oSettings.aoColumns[iColumn].sTitle = oSettings.aoColumns[iColumn].nTh.innerHTML;
}
var
bAutoType = oSettings.aoColumns[iColumn]._bAutoType,
bRender = typeof oSettings.aoColumns[iColumn].fnRender == 'function',
bClass = oSettings.aoColumns[iColumn].sClass !== null,
bVisible = oSettings.aoColumns[iColumn].bVisible,
nCell, sThisType, sRendered, sValType;
/* A single loop to rule them all (and be more efficient) */
if ( bAutoType || bRender || bClass || !bVisible )
{
for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
{
nCell = nTds[ (iRow*iColumns) + iColumn ];
/* Type detection */
if ( bAutoType && oSettings.aoColumns[iColumn].sType != 'string' )
{
sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
if ( sValType !== '' )
{
sThisType = _fnDetectType( sValType );
if ( oSettings.aoColumns[iColumn].sType === null )
{
oSettings.aoColumns[iColumn].sType = sThisType;
}
else if ( oSettings.aoColumns[iColumn].sType != sThisType &&
oSettings.aoColumns[iColumn].sType != "html" )
{
/* String is always the 'fallback' option */
oSettings.aoColumns[iColumn].sType = 'string';
}
}
}
/* Rendering */
if ( bRender )
{
sRendered = oSettings.aoColumns[iColumn].fnRender( {
"iDataRow": iRow,
"iDataColumn": iColumn,
"aData": oSettings.aoData[iRow]._aData,
"oSettings": oSettings
} );
nCell.innerHTML = sRendered;
if ( oSettings.aoColumns[iColumn].bUseRendered )
{
/* Use the rendered data for filtering/sorting */
_fnSetCellData( oSettings, iRow, iColumn, sRendered );
}
}
/* Classes */
if ( bClass )
{
nCell.className += ' '+oSettings.aoColumns[iColumn].sClass;
}
/* Column visability */
if ( !bVisible )
{
oSettings.aoData[iRow]._anHidden[iColumn] = nCell;
nCell.parentNode.removeChild( nCell );
}
else
{
oSettings.aoData[iRow]._anHidden[iColumn] = null;
}
}
}
}
}
/*
* Function: _fnBuildHead
* Purpose: Create the HTML header for the table
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnBuildHead( oSettings )
{
var i, nTh, iLen, j, jLen;
var anTr = oSettings.nTHead.getElementsByTagName('tr');
var iThs = oSettings.nTHead.getElementsByTagName('th').length;
var iCorrector = 0;
var jqChildren;
/* If there is a header in place - then use it - otherwise it's going to get nuked... */
if ( iThs !== 0 )
{
/* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
nTh = oSettings.aoColumns[i].nTh;
if ( oSettings.aoColumns[i].sClass !== null )
{
$(nTh).addClass( oSettings.aoColumns[i].sClass );
}
/* Set the title of the column if it is user defined (not what was auto detected) */
if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
{
nTh.innerHTML = oSettings.aoColumns[i].sTitle;
}
}
}
else
{
/* We don't have a header in the DOM - so we are going to have to create one */
var nTr = document.createElement( "tr" );
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
nTh = oSettings.aoColumns[i].nTh;
nTh.innerHTML = oSettings.aoColumns[i].sTitle;
if ( oSettings.aoColumns[i].sClass !== null )
{
$(nTh).addClass( oSettings.aoColumns[i].sClass );
}
nTr.appendChild( nTh );
}
$(oSettings.nTHead).html( '' )[0].appendChild( nTr );
_fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
}
/* Add the extra markup needed by jQuery UI's themes */
if ( oSettings.bJUI )
{
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
nTh = oSettings.aoColumns[i].nTh;
var nDiv = document.createElement('div');
nDiv.className = oSettings.oClasses.sSortJUIWrapper;
$(nTh).contents().appendTo(nDiv);
var nSpan = document.createElement('span');
nSpan.className = oSettings.oClasses.sSortIcon;
nDiv.appendChild( nSpan );
nTh.appendChild( nDiv );
}
}
/* Add sort listener */
var fnNoSelect = function (e) {
this.onselectstart = function() { return false; };
return false;
};
if ( oSettings.oFeatures.bSort )
{
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
if ( oSettings.aoColumns[i].bSortable !== false )
{
_fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
/* Take the brutal approach to cancelling text selection in header */
$(oSettings.aoColumns[i].nTh).on( 'mousedown.DT', fnNoSelect );
}
else
{
$(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
}
}
}
/* Deal with the footer - add classes if required */
if ( oSettings.oClasses.sFooterTH !== "" )
{
$(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
}
/* Cache the footer elements */
if ( oSettings.nTFoot !== null )
{
var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
if ( typeof anCells[i] != 'undefined' )
{
oSettings.aoColumns[i].nTf = anCells[i];
}
}
}
}
 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Drawing functions
*/
/*
* Function: _fnDrawHead
* Purpose: Draw the header (or footer) element based on the column visibility states. The
* methodology here is to use the layout array from _fnDetectHeader, modified for
* the instantaneous column visibility, to construct the new layout. The grid is
* traversed over cell at a time in a rows x columns grid fashion, although each
* cell insert can cover multiple elements in the grid - which is tracks using the
* aApplied array. Cell inserts in the grid will only occur where there isn't
* already a cell in that position.
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* array objects:aoSource - Layout array from _fnDetectHeader
* boolean:bIncludeHidden - If true then include the hidden columns in the calc,
* - optional: default false
*/
function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
{
var i, iLen, j, jLen, k, kLen;
var aoLocal = [];
var aApplied = [];
var iColumns = oSettings.aoColumns.length;
var iRowspan, iColspan;
 
if ( typeof bIncludeHidden == 'undefined' )
{
bIncludeHidden = false;
}
 
/* Make a copy of the master layout array, but without the visible columns in it */
for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
{
aoLocal[i] = aoSource[i].slice();
aoLocal[i].nTr = aoSource[i].nTr;
 
/* Remove any columns which are currently hidden */
for ( j=iColumns-1 ; j>=0 ; j-- )
{
if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
{
aoLocal[i].splice( j, 1 );
}
}
 
/* Prep the applied array - it needs an element for each row */
aApplied.push( [] );
}
 
for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
{
/* All cells are going to be replaced, so empty out the row */
if ( aoLocal[i].nTr )
{
for ( k=0, kLen=aoLocal[i].nTr.childNodes.length ; k<kLen ; k++ )
{
aoLocal[i].nTr.removeChild( aoLocal[i].nTr.childNodes[0] );
}
}
 
for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
{
iRowspan = 1;
iColspan = 1;
 
/* Check to see if there is already a cell (row/colspan) covering our target
* insert point. If there is, then there is nothing to do.
*/
if ( typeof aApplied[i][j] == 'undefined' )
{
aoLocal[i].nTr.appendChild( aoLocal[i][j].cell );
aApplied[i][j] = 1;
 
/* Expand the cell to cover as many rows as needed */
while ( typeof aoLocal[i+iRowspan] != 'undefined' &&
aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
{
aApplied[i+iRowspan][j] = 1;
iRowspan++;
}
 
/* Expand the cell to cover as many columns as needed */
while ( typeof aoLocal[i][j+iColspan] != 'undefined' &&
aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
{
/* Must update the applied array over the rows for the columns */
for ( k=0 ; k<iRowspan ; k++ )
{
aApplied[i+k][j+iColspan] = 1;
}
iColspan++;
}
 
/* Do the actual expansion in the DOM */
aoLocal[i][j].cell.rowSpan = iRowspan;
aoLocal[i][j].cell.colSpan = iColspan;
}
}
}
}
/*
* Function: _fnDraw
* Purpose: Insert the required TR nodes into the table for display
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnDraw( oSettings )
{
var i, iLen;
var anRows = [];
var iRowCount = 0;
var bRowError = false;
var iStripes = oSettings.asStripeClasses.length;
var iOpenRows = oSettings.aoOpenRows.length;
/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
if ( oSettings.fnPreDrawCallback !== null &&
oSettings.fnPreDrawCallback.call( oSettings.oInstance, oSettings ) === false )
{
return;
}
oSettings.bDrawing = true;
/* Check and see if we have an initial draw position from state saving */
if ( typeof oSettings.iInitDisplayStart != 'undefined' && oSettings.iInitDisplayStart != -1 )
{
if ( oSettings.oFeatures.bServerSide )
{
oSettings._iDisplayStart = oSettings.iInitDisplayStart;
}
else
{
oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
0 : oSettings.iInitDisplayStart;
}
oSettings.iInitDisplayStart = -1;
_fnCalculateEnd( oSettings );
}
/* Server-side processing draw intercept */
if ( oSettings.bDeferLoading )
{
oSettings.bDeferLoading = false;
oSettings.iDraw++;
}
else if ( !oSettings.oFeatures.bServerSide )
{
oSettings.iDraw++;
}
else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
{
return;
}
if ( oSettings.aiDisplay.length !== 0 )
{
var iStart = oSettings._iDisplayStart;
var iEnd = oSettings._iDisplayEnd;
if ( oSettings.oFeatures.bServerSide )
{
iStart = 0;
iEnd = oSettings.aoData.length;
}
for ( var j=iStart ; j<iEnd ; j++ )
{
var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
if ( aoData.nTr === null )
{
_fnCreateTr( oSettings, oSettings.aiDisplay[j] );
}
 
var nRow = aoData.nTr;
/* Remove the old striping classes and then add the new one */
if ( iStripes !== 0 )
{
var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
if ( aoData._sRowStripe != sStripe )
{
$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
aoData._sRowStripe = sStripe;
}
}
/* Custom row callback function - might want to manipule the row */
if ( typeof oSettings.fnRowCallback == "function" )
{
nRow = oSettings.fnRowCallback.call( oSettings.oInstance, nRow,
oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j );
if ( !nRow && !bRowError )
{
_fnLog( oSettings, 0, "A node was not returned by fnRowCallback" );
bRowError = true;
}
}
anRows.push( nRow );
iRowCount++;
/* If there is an open row - and it is attached to this parent - attach it on redraw */
if ( iOpenRows !== 0 )
{
for ( var k=0 ; k<iOpenRows ; k++ )
{
if ( nRow == oSettings.aoOpenRows[k].nParent )
{
anRows.push( oSettings.aoOpenRows[k].nTr );
}
}
}
}
}
else
{
/* Table is empty - create a row with an empty message in it */
anRows[ 0 ] = document.createElement( 'tr' );
if ( typeof oSettings.asStripeClasses[0] != 'undefined' )
{
anRows[ 0 ].className = oSettings.asStripeClasses[0];
}
 
var sZero = oSettings.oLanguage.sZeroRecords.replace(
'_MAX_', oSettings.fnFormatNumber(oSettings.fnRecordsTotal()) );
if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
{
sZero = oSettings.oLanguage.sLoadingRecords;
}
else if ( typeof oSettings.oLanguage.sEmptyTable != 'undefined' &&
oSettings.fnRecordsTotal() === 0 )
{
sZero = oSettings.oLanguage.sEmptyTable;
}
 
var nTd = document.createElement( 'td' );
nTd.setAttribute( 'valign', "top" );
nTd.colSpan = _fnVisbleColumns( oSettings );
nTd.className = oSettings.oClasses.sRowEmpty;
nTd.innerHTML = sZero;
anRows[ iRowCount ].appendChild( nTd );
}
/* Callback the header and footer custom funcation if there is one */
if ( typeof oSettings.fnHeaderCallback == 'function' )
{
oSettings.fnHeaderCallback.call( oSettings.oInstance, $(oSettings.nTHead).children('tr')[0],
_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
oSettings.aiDisplay );
}
if ( typeof oSettings.fnFooterCallback == 'function' )
{
oSettings.fnFooterCallback.call( oSettings.oInstance, $(oSettings.nTFoot).children('tr')[0],
_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
oSettings.aiDisplay );
}
/*
* Need to remove any old row from the display - note we can't just empty the tbody using
* $().html('') since this will unbind the jQuery event handlers (even although the node
* still exists!) - equally we can't use innerHTML, since IE throws an exception.
*/
var
nAddFrag = document.createDocumentFragment(),
nRemoveFrag = document.createDocumentFragment(),
nBodyPar, nTrs;
if ( oSettings.nTBody )
{
nBodyPar = oSettings.nTBody.parentNode;
nRemoveFrag.appendChild( oSettings.nTBody );
/* When doing infinite scrolling, only remove child rows when sorting, filtering or start
* up. When not infinite scroll, always do it.
*/
if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
oSettings.bSorted || oSettings.bFiltered )
{
nTrs = oSettings.nTBody.childNodes;
for ( i=nTrs.length-1 ; i>=0 ; i-- )
{
nTrs[i].parentNode.removeChild( nTrs[i] );
}
}
/* Put the draw table into the dom */
for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
{
nAddFrag.appendChild( anRows[i] );
}
oSettings.nTBody.appendChild( nAddFrag );
if ( nBodyPar !== null )
{
nBodyPar.appendChild( oSettings.nTBody );
}
}
/* Call all required callback functions for the end of a draw */
for ( i=oSettings.aoDrawCallback.length-1 ; i>=0 ; i-- )
{
oSettings.aoDrawCallback[i].fn.call( oSettings.oInstance, oSettings );
}
$(oSettings.oInstance).trigger('draw', oSettings);
/* Draw is complete, sorting and filtering must be as well */
oSettings.bSorted = false;
oSettings.bFiltered = false;
oSettings.bDrawing = false;
if ( oSettings.oFeatures.bServerSide )
{
_fnProcessingDisplay( oSettings, false );
if ( typeof oSettings._bInitComplete == 'undefined' )
{
_fnInitComplete( oSettings );
}
}
}
/*
* Function: _fnReDraw
* Purpose: Redraw the table - taking account of the various features which are enabled
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnReDraw( oSettings )
{
if ( oSettings.oFeatures.bSort )
{
/* Sorting will refilter and draw for us */
_fnSort( oSettings, oSettings.oPreviousSearch );
}
else if ( oSettings.oFeatures.bFilter )
{
/* Filtering will redraw for us */
_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
}
else
{
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
}
/*
* Function: _fnAjaxUpdate
* Purpose: Update the table using an Ajax call
* Returns: bool: block the table drawing or not
* Inputs: object:oSettings - dataTables settings object
*/
function _fnAjaxUpdate( oSettings )
{
if ( oSettings.bAjaxDataGet )
{
oSettings.iDraw++;
_fnProcessingDisplay( oSettings, true );
var iColumns = oSettings.aoColumns.length;
var aoData = _fnAjaxParameters( oSettings );
_fnServerParams( oSettings, aoData );
oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
function(json) {
_fnAjaxUpdateDraw( oSettings, json );
}, oSettings );
return false;
}
else
{
return true;
}
}
/*
* Function: _fnAjaxParameters
* Purpose: Build up the parameters in an object needed for a server-side processing request
* Returns: bool: block the table drawing or not
* Inputs: object:oSettings - dataTables settings object
*/
function _fnAjaxParameters( oSettings )
{
var iColumns = oSettings.aoColumns.length;
var aoData = [], mDataProp;
var i;
aoData.push( { "name": "sEcho", "value": oSettings.iDraw } );
aoData.push( { "name": "iColumns", "value": iColumns } );
aoData.push( { "name": "sColumns", "value": _fnColumnOrdering(oSettings) } );
aoData.push( { "name": "iDisplayStart", "value": oSettings._iDisplayStart } );
aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
oSettings._iDisplayLength : -1 } );
for ( i=0 ; i<iColumns ; i++ )
{
mDataProp = oSettings.aoColumns[i].mDataProp;
aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)=="function" ? 'function' : mDataProp } );
}
/* Filtering */
if ( oSettings.oFeatures.bFilter !== false )
{
aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
aoData.push( { "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex } );
for ( i=0 ; i<iColumns ; i++ )
{
aoData.push( { "name": "sSearch_"+i, "value": oSettings.aoPreSearchCols[i].sSearch } );
aoData.push( { "name": "bRegex_"+i, "value": oSettings.aoPreSearchCols[i].bRegex } );
aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
}
}
/* Sorting */
if ( oSettings.oFeatures.bSort !== false )
{
var iFixed = oSettings.aaSortingFixed !== null ? oSettings.aaSortingFixed.length : 0;
var iUser = oSettings.aaSorting.length;
aoData.push( { "name": "iSortingCols", "value": iFixed+iUser } );
for ( i=0 ; i<iFixed ; i++ )
{
aoData.push( { "name": "iSortCol_"+i, "value": oSettings.aaSortingFixed[i][0] } );
aoData.push( { "name": "sSortDir_"+i, "value": oSettings.aaSortingFixed[i][1] } );
}
for ( i=0 ; i<iUser ; i++ )
{
aoData.push( { "name": "iSortCol_"+(i+iFixed), "value": oSettings.aaSorting[i][0] } );
aoData.push( { "name": "sSortDir_"+(i+iFixed), "value": oSettings.aaSorting[i][1] } );
}
for ( i=0 ; i<iColumns ; i++ )
{
aoData.push( { "name": "bSortable_"+i, "value": oSettings.aoColumns[i].bSortable } );
}
}
return aoData;
}
/*
* Function: _fnServerParams
* Purpose: Add Ajax parameters from plugins
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* array objects:aoData - name/value pairs to send to the server
*/
function _fnServerParams( oSettings, aoData )
{
for ( var i=0, iLen=oSettings.aoServerParams.length ; i<iLen ; i++ )
{
oSettings.aoServerParams[i].fn.call( oSettings.oInstance, aoData );
}
}
/*
* Function: _fnAjaxUpdateDraw
* Purpose: Data the data from the server (nuking the old) and redraw the table
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* object:json - json data return from the server.
* The following must be defined:
* iTotalRecords, iTotalDisplayRecords, aaData
* The following may be defined:
* sColumns
*/
function _fnAjaxUpdateDraw ( oSettings, json )
{
if ( typeof json.sEcho != 'undefined' )
{
/* Protect against old returns over-writing a new one. Possible when you get
* very fast interaction, and later queires are completed much faster
*/
if ( json.sEcho*1 < oSettings.iDraw )
{
return;
}
else
{
oSettings.iDraw = json.sEcho * 1;
}
}
if ( !oSettings.oScroll.bInfinite ||
(oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
{
_fnClearTable( oSettings );
}
oSettings._iRecordsTotal = json.iTotalRecords;
oSettings._iRecordsDisplay = json.iTotalDisplayRecords;
/* Determine if reordering is required */
var sOrdering = _fnColumnOrdering(oSettings);
var bReOrder = (typeof json.sColumns != 'undefined' && sOrdering !== "" && json.sColumns != sOrdering );
if ( bReOrder )
{
var aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
}
 
var fnDataSrc = _fnGetObjectDataFn( oSettings.sAjaxDataProp );
var aData = fnDataSrc( json );
for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
{
if ( bReOrder )
{
/* If we need to re-order, then create a new array with the correct order and add it */
var aDataSorted = [];
for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
{
aDataSorted.push( aData[i][ aiIndex[j] ] );
}
_fnAddData( oSettings, aDataSorted );
}
else
{
/* No re-order required, sever got it "right" - just straight add */
_fnAddData( oSettings, aData[i] );
}
}
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
oSettings.bAjaxDataGet = false;
_fnDraw( oSettings );
oSettings.bAjaxDataGet = true;
_fnProcessingDisplay( oSettings, false );
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Options (features) HTML
*/
/*
* Function: _fnAddOptionsHtml
* Purpose: Add the options to the page HTML for the table
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnAddOptionsHtml ( oSettings )
{
/*
* Create a temporary, empty, div which we can later on replace with what we have generated
* we do it this way to rendering the 'options' html offline - speed :-)
*/
var nHolding = document.createElement( 'div' );
oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
/*
* All DataTables are wrapped in a div
*/
oSettings.nTableWrapper = document.createElement( 'div' );
oSettings.nTableWrapper.className = oSettings.oClasses.sWrapper;
if ( oSettings.sTableId !== '' )
{
oSettings.nTableWrapper.setAttribute( 'id', oSettings.sTableId+'_wrapper' );
}
 
oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
 
/* Track where we want to insert the option */
var nInsertNode = oSettings.nTableWrapper;
/* Loop over the user set positioning and place the elements as needed */
var aDom = oSettings.sDom.split('');
var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
for ( var i=0 ; i<aDom.length ; i++ )
{
iPushFeature = 0;
cOption = aDom[i];
if ( cOption == '<' )
{
/* New container div */
nNewNode = document.createElement( 'div' );
/* Check to see if we should append an id and/or a class name to the container */
cNext = aDom[i+1];
if ( cNext == "'" || cNext == '"' )
{
sAttr = "";
j = 2;
while ( aDom[i+j] != cNext )
{
sAttr += aDom[i+j];
j++;
}
/* Replace jQuery UI constants */
if ( sAttr == "H" )
{
sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix";
}
else if ( sAttr == "F" )
{
sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix";
}
/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
* breaks the string into parts and applies them as needed
*/
if ( sAttr.indexOf('.') != -1 )
{
var aSplit = sAttr.split('.');
nNewNode.setAttribute('id', aSplit[0].substr(1, aSplit[0].length-1) );
nNewNode.className = aSplit[1];
}
else if ( sAttr.charAt(0) == "#" )
{
nNewNode.setAttribute('id', sAttr.substr(1, sAttr.length-1) );
}
else
{
nNewNode.className = sAttr;
}
i += j; /* Move along the position array */
}
nInsertNode.appendChild( nNewNode );
nInsertNode = nNewNode;
}
else if ( cOption == '>' )
{
/* End container div */
nInsertNode = nInsertNode.parentNode;
}
else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
{
/* Length */
nTmp = _fnFeatureHtmlLength( oSettings );
iPushFeature = 1;
}
else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
{
/* Filter */
nTmp = _fnFeatureHtmlFilter( oSettings );
iPushFeature = 1;
}
else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
{
/* pRocessing */
nTmp = _fnFeatureHtmlProcessing( oSettings );
iPushFeature = 1;
}
else if ( cOption == 't' )
{
/* Table */
nTmp = _fnFeatureHtmlTable( oSettings );
iPushFeature = 1;
}
else if ( cOption == 'i' && oSettings.oFeatures.bInfo )
{
/* Info */
nTmp = _fnFeatureHtmlInfo( oSettings );
iPushFeature = 1;
}
else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
{
/* Pagination */
nTmp = _fnFeatureHtmlPaginate( oSettings );
iPushFeature = 1;
}
else if ( _oExt.aoFeatures.length !== 0 )
{
/* Plug-in features */
var aoFeatures = _oExt.aoFeatures;
for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
{
if ( cOption == aoFeatures[k].cFeature )
{
nTmp = aoFeatures[k].fnInit( oSettings );
if ( nTmp )
{
iPushFeature = 1;
}
break;
}
}
}
/* Add to the 2D features array */
if ( iPushFeature == 1 && nTmp !== null )
{
if ( typeof oSettings.aanFeatures[cOption] != 'object' )
{
oSettings.aanFeatures[cOption] = [];
}
oSettings.aanFeatures[cOption].push( nTmp );
nInsertNode.appendChild( nTmp );
}
}
/* Built our DOM structure - replace the holding div with what we want */
nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Feature: Filtering
*/
/*
* Function: _fnFeatureHtmlTable
* Purpose: Add any control elements for the table - specifically scrolling
* Returns: node: - Node to add to the DOM
* Inputs: object:oSettings - dataTables settings object
*/
function _fnFeatureHtmlTable ( oSettings )
{
/* Chack if scrolling is enabled or not - if not then leave the DOM unaltered */
if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
{
return oSettings.nTable;
}
/*
* The HTML structure that we want to generate in this function is:
* div - nScroller
* div - nScrollHead
* div - nScrollHeadInner
* table - nScrollHeadTable
* thead - nThead
* div - nScrollBody
* table - oSettings.nTable
* thead - nTheadSize
* tbody - nTbody
* div - nScrollFoot
* div - nScrollFootInner
* table - nScrollFootTable
* tfoot - nTfoot
*/
var
nScroller = document.createElement('div'),
nScrollHead = document.createElement('div'),
nScrollHeadInner = document.createElement('div'),
nScrollBody = document.createElement('div'),
nScrollFoot = document.createElement('div'),
nScrollFootInner = document.createElement('div'),
nScrollHeadTable = oSettings.nTable.cloneNode(false),
nScrollFootTable = oSettings.nTable.cloneNode(false),
nThead = oSettings.nTable.getElementsByTagName('thead')[0],
nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null :
oSettings.nTable.getElementsByTagName('tfoot')[0],
oClasses = (typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI) ?
_oExt.oJUIClasses : _oExt.oStdClasses;
nScrollHead.appendChild( nScrollHeadInner );
nScrollFoot.appendChild( nScrollFootInner );
nScrollBody.appendChild( oSettings.nTable );
nScroller.appendChild( nScrollHead );
nScroller.appendChild( nScrollBody );
nScrollHeadInner.appendChild( nScrollHeadTable );
nScrollHeadTable.appendChild( nThead );
if ( nTfoot !== null )
{
nScroller.appendChild( nScrollFoot );
nScrollFootInner.appendChild( nScrollFootTable );
nScrollFootTable.appendChild( nTfoot );
}
nScroller.className = oClasses.sScrollWrapper;
nScrollHead.className = oClasses.sScrollHead;
nScrollHeadInner.className = oClasses.sScrollHeadInner;
nScrollBody.className = oClasses.sScrollBody;
nScrollFoot.className = oClasses.sScrollFoot;
nScrollFootInner.className = oClasses.sScrollFootInner;
if ( oSettings.oScroll.bAutoCss )
{
nScrollHead.style.overflow = "hidden";
nScrollHead.style.position = "relative";
nScrollFoot.style.overflow = "hidden";
nScrollBody.style.overflow = "auto";
}
nScrollHead.style.border = "0";
nScrollHead.style.width = "100%";
nScrollFoot.style.border = "0";
nScrollHeadInner.style.width = "150%"; /* will be overwritten */
/* Modify attributes to respect the clones */
nScrollHeadTable.removeAttribute('id');
nScrollHeadTable.style.marginLeft = "0";
oSettings.nTable.style.marginLeft = "0";
if ( nTfoot !== null )
{
nScrollFootTable.removeAttribute('id');
nScrollFootTable.style.marginLeft = "0";
}
/* Move any caption elements from the body to the header */
var nCaptions = $(oSettings.nTable).children('caption');
for ( var i=0, iLen=nCaptions.length ; i<iLen ; i++ )
{
nScrollHeadTable.appendChild( nCaptions[i] );
}
/*
* Sizing
*/
/* When xscrolling add the width and a scroller to move the header with the body */
if ( oSettings.oScroll.sX !== "" )
{
nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
if ( nTfoot !== null )
{
nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );
}
/* When the body is scrolled, then we also want to scroll the headers */
$(nScrollBody).scroll( function (e) {
nScrollHead.scrollLeft = this.scrollLeft;
if ( nTfoot !== null )
{
nScrollFoot.scrollLeft = this.scrollLeft;
}
} );
}
/* When yscrolling, add the height */
if ( oSettings.oScroll.sY !== "" )
{
nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
}
/* Redraw - align columns across the tables */
oSettings.aoDrawCallback.push( {
"fn": _fnScrollDraw,
"sName": "scrolling"
} );
/* Infinite scrolling event handlers */
if ( oSettings.oScroll.bInfinite )
{
$(nScrollBody).scroll( function() {
/* Use a blocker to stop scrolling from loading more data while other data is still loading */
if ( !oSettings.bDrawing )
{
/* Check if we should load the next data set */
if ( $(this).scrollTop() + $(this).height() >
$(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
{
/* Only do the redraw if we have to - we might be at the end of the data */
if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
{
_fnPageChange( oSettings, 'next' );
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
}
}
} );
}
oSettings.nScrollHead = nScrollHead;
oSettings.nScrollFoot = nScrollFoot;
return nScroller;
}
/*
* Function: _fnScrollDraw
* Purpose: Update the various tables for resizing
* Returns: node: - Node to add to the DOM
* Inputs: object:o - dataTables settings object
* Notes: It's a bit of a pig this function, but basically the idea to:
* 1. Re-create the table inside the scrolling div
* 2. Take live measurements from the DOM
* 3. Apply the measurements
* 4. Clean up
*/
function _fnScrollDraw ( o )
{
var
nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
nScrollBody = o.nTable.parentNode,
i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
iWidth, aApplied=[], iSanityWidth,
nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
ie67 = (navigator.userAgent.match(/MSIE ([2-7]\.)/) !== null);
/*
* 1. Re-create the table inside the scrolling div
*/
/* Remove the old minimised thead and tfoot elements in the inner table */
var nTheadSize = o.nTable.getElementsByTagName('thead');
if ( nTheadSize.length > 0 )
{
o.nTable.removeChild( nTheadSize[0] );
}
if ( o.nTFoot !== null )
{
/* Remove the old minimised footer element in the cloned header */
var nTfootSize = o.nTable.getElementsByTagName('tfoot');
if ( nTfootSize.length > 0 )
{
o.nTable.removeChild( nTfootSize[0] );
}
}
/* Clone the current header and footer elements and then place it into the inner table */
nTheadSize = o.nTHead.cloneNode(true);
o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
if ( o.nTFoot !== null )
{
nTfootSize = o.nTFoot.cloneNode(true);
o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
}
/*
* 2. Take live measurements from the DOM - do not alter the DOM itself!
*/
/* Remove old sizing and apply the calculated column widths
* Get the unique column headers in the newly created (cloned) header. We want to apply the
* calclated sizes to this header
*/
if ( o.oScroll.sX === "" )
{
nScrollBody.style.width = '100%';
nScrollHeadInner.parentNode.style.width = '100%';
}
var nThs = _fnGetUniqueThs( o, nTheadSize );
for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
{
iVis = _fnVisibleToColumnIndex( o, i );
nThs[i].style.width = o.aoColumns[iVis].sWidth;
}
if ( o.nTFoot !== null )
{
_fnApplyToChildren( function(n) {
n.style.width = "";
}, nTfootSize.getElementsByTagName('tr') );
}
/* Size the table as a whole */
iSanityWidth = $(o.nTable).outerWidth();
if ( o.oScroll.sX === "" )
{
/* No x scrolling */
o.nTable.style.width = "100%";
/* I know this is rubbish - but IE7 will make the width of the table when 100% include
* the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
* into account.
*/
if ( ie67 && (nScrollBody.scrollHeight >
nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") )
{
o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth()-o.oScroll.iBarWidth );
}
}
else
{
if ( o.oScroll.sXInner !== "" )
{
/* x scroll inner has been given - use it */
o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
}
else if ( iSanityWidth == $(nScrollBody).width() &&
$(nScrollBody).height() < $(o.nTable).height() )
{
/* There is y-scrolling - try to take account of the y scroll bar */
o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
{
/* Not possible to take account of it */
o.nTable.style.width = _fnStringToCss( iSanityWidth );
}
}
else
{
/* All else fails */
o.nTable.style.width = _fnStringToCss( iSanityWidth );
}
}
/* Recalculate the sanity width - now that we've applied the required width, before it was
* a temporary variable. This is required because the column width calculation is done
* before this table DOM is created.
*/
iSanityWidth = $(o.nTable).outerWidth();
/* We want the hidden header to have zero height, so remove padding and borders. Then
* set the width based on the real headers
*/
anHeadToSize = o.nTHead.getElementsByTagName('tr');
anHeadSizers = nTheadSize.getElementsByTagName('tr');
_fnApplyToChildren( function(nSizer, nToSize) {
oStyle = nSizer.style;
oStyle.paddingTop = "0";
oStyle.paddingBottom = "0";
oStyle.borderTopWidth = "0";
oStyle.borderBottomWidth = "0";
oStyle.height = 0;
iWidth = $(nSizer).width();
nToSize.style.width = _fnStringToCss( iWidth );
aApplied.push( iWidth );
}, anHeadSizers, anHeadToSize );
$(anHeadSizers).height(0);
if ( o.nTFoot !== null )
{
/* Clone the current footer and then place it into the body table as a "hidden header" */
anFootSizers = nTfootSize.getElementsByTagName('tr');
anFootToSize = o.nTFoot.getElementsByTagName('tr');
_fnApplyToChildren( function(nSizer, nToSize) {
oStyle = nSizer.style;
oStyle.paddingTop = "0";
oStyle.paddingBottom = "0";
oStyle.borderTopWidth = "0";
oStyle.borderBottomWidth = "0";
oStyle.height = 0;
iWidth = $(nSizer).width();
nToSize.style.width = _fnStringToCss( iWidth );
aApplied.push( iWidth );
}, anFootSizers, anFootToSize );
$(anFootSizers).height(0);
}
/*
* 3. Apply the measurements
*/
/* "Hide" the header and footer that we used for the sizing. We want to also fix their width
* to what they currently are
*/
_fnApplyToChildren( function(nSizer) {
nSizer.innerHTML = "";
nSizer.style.width = _fnStringToCss( aApplied.shift() );
}, anHeadSizers );
if ( o.nTFoot !== null )
{
_fnApplyToChildren( function(nSizer) {
nSizer.innerHTML = "";
nSizer.style.width = _fnStringToCss( aApplied.shift() );
}, anFootSizers );
}
/* Sanity check that the table is of a sensible width. If not then we are going to get
* misalignment - try to prevent this by not allowing the table to shrink below its min width
*/
if ( $(o.nTable).outerWidth() < iSanityWidth )
{
/* The min width depends upon if we have a vertical scrollbar visible or not */
var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight ||
$(nScrollBody).css('overflow-y') == "scroll")) ?
iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
/* IE6/7 are a law unto themselves... */
if ( ie67 && (nScrollBody.scrollHeight >
nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") )
{
o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
}
/* Apply the calculated minimum width to the table wrappers */
nScrollBody.style.width = _fnStringToCss( iCorrection );
nScrollHeadInner.parentNode.style.width = _fnStringToCss( iCorrection );
if ( o.nTFoot !== null )
{
nScrollFootInner.parentNode.style.width = _fnStringToCss( iCorrection );
}
/* And give the user a warning that we've stopped the table getting too small */
if ( o.oScroll.sX === "" )
{
_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
" misalignment. The table has been drawn at its minimum possible width." );
}
else if ( o.oScroll.sXInner !== "" )
{
_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
" misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
" calculation" );
}
}
else
{
nScrollBody.style.width = _fnStringToCss( '100%' );
nScrollHeadInner.parentNode.style.width = _fnStringToCss( '100%' );
if ( o.nTFoot !== null )
{
nScrollFootInner.parentNode.style.width = _fnStringToCss( '100%' );
}
}
/*
* 4. Clean up
*/
if ( o.oScroll.sY === "" )
{
/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
* the scrollbar height from the visible display, rather than adding it on. We need to
* set the height in order to sort this. Don't want to do it in any other browsers.
*/
if ( ie67 )
{
nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
}
}
if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
{
nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
o.oScroll.iBarWidth : 0;
if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
{
nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );
}
}
/* Finally set the width's of the header and footer tables */
var iOuterWidth = $(o.nTable).outerWidth();
nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth+o.oScroll.iBarWidth );
if ( o.nTFoot !== null )
{
nScrollFootInner.style.width = _fnStringToCss( o.nTable.offsetWidth+o.oScroll.iBarWidth );
nScrollFootTable.style.width = _fnStringToCss( o.nTable.offsetWidth );
}
/* If sorting or filtering has occured, jump the scrolling back to the top */
if ( o.bSorted || o.bFiltered )
{
nScrollBody.scrollTop = 0;
}
}
/*
* Function: _fnAdjustColumnSizing
* Purpose: Adjust the table column widths for new data
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* Notes: You would probably want to do a redraw after calling this function!
*/
function _fnAdjustColumnSizing ( oSettings )
{
/* Not interested in doing column width calculation if autowidth is disabled */
if ( oSettings.oFeatures.bAutoWidth === false )
{
return false;
}
_fnCalculateColumnWidths( oSettings );
for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Feature: Filtering
*/
/*
* Function: _fnFeatureHtmlFilter
* Purpose: Generate the node required for filtering text
* Returns: node
* Inputs: object:oSettings - dataTables settings object
*/
function _fnFeatureHtmlFilter ( oSettings )
{
var sSearchStr = oSettings.oLanguage.sSearch;
sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
sSearchStr.replace('_INPUT_', '<input type="text" />') :
sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
var nFilter = document.createElement( 'div' );
nFilter.className = oSettings.oClasses.sFilter;
nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.f == "undefined" )
{
nFilter.setAttribute( 'id', oSettings.sTableId+'_filter' );
}
var jqFilter = $("input", nFilter);
jqFilter.val( oSettings.oPreviousSearch.sSearch.replace('"','&quot;') );
jqFilter.on( 'keyup.DT', function(e) {
/* Update all other filter input elements for the new display */
var n = oSettings.aanFeatures.f;
for ( var i=0, iLen=n.length ; i<iLen ; i++ )
{
if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
{
$('input', n[i]).val( this.value );
}
}
/* Now do the filter */
if ( this.value != oSettings.oPreviousSearch.sSearch )
{
_fnFilterComplete( oSettings, {
"sSearch": this.value,
"bRegex": oSettings.oPreviousSearch.bRegex,
"bSmart": oSettings.oPreviousSearch.bSmart
} );
}
} );
jqFilter.on( 'keypress.DT', function(e) {
/* Prevent default */
if ( e.keyCode == 13 )
{
return false;
}
} );
return nFilter;
}
/*
* Function: _fnFilterComplete
* Purpose: Filter the table using both the global filter and column based filtering
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* object:oSearch: search information
* int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
*/
function _fnFilterComplete ( oSettings, oInput, iForce )
{
/* Filter on everything */
_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart );
/* Now do the individual column filter */
for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
{
_fnFilterColumn( oSettings, oSettings.aoPreSearchCols[i].sSearch, i,
oSettings.aoPreSearchCols[i].bRegex, oSettings.aoPreSearchCols[i].bSmart );
}
/* Custom filtering */
if ( _oExt.afnFiltering.length !== 0 )
{
_fnFilterCustom( oSettings );
}
/* Tell the draw function we have been filtering */
oSettings.bFiltered = true;
$(oSettings.oInstance).trigger('filter', oSettings);
/* Redraw the table */
oSettings._iDisplayStart = 0;
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
/* Rebuild search array 'offline' */
_fnBuildSearchArray( oSettings, 0 );
}
/*
* Function: _fnFilterCustom
* Purpose: Apply custom filtering functions
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnFilterCustom( oSettings )
{
var afnFilters = _oExt.afnFiltering;
for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
{
var iCorrector = 0;
for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
{
var iDisIndex = oSettings.aiDisplay[j-iCorrector];
/* Check if we should use this row based on the filtering function */
if ( !afnFilters[i]( oSettings, _fnGetRowData( oSettings, iDisIndex, 'filter' ), iDisIndex ) )
{
oSettings.aiDisplay.splice( j-iCorrector, 1 );
iCorrector++;
}
}
}
}
/*
* Function: _fnFilterColumn
* Purpose: Filter the table on a per-column basis
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* string:sInput - string to filter on
* int:iColumn - column to filter
* bool:bRegex - treat search string as a regular expression or not
* bool:bSmart - use smart filtering or not
*/
function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart )
{
if ( sInput === "" )
{
return;
}
var iIndexCorrector = 0;
var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );
for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
{
var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
oSettings.aoColumns[iColumn].sType );
if ( ! rpSearch.test( sData ) )
{
oSettings.aiDisplay.splice( i, 1 );
iIndexCorrector++;
}
}
}
/*
* Function: _fnFilter
* Purpose: Filter the data table based on user input and draw the table
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* string:sInput - string to filter on
* int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
* bool:bRegex - treat as a regular expression or not
* bool:bSmart - perform smart filtering or not
*/
function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart )
{
var i;
var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );
/* Check if we are forcing or not - optional parameter */
if ( typeof iForce == 'undefined' || iForce === null )
{
iForce = 0;
}
/* Need to take account of custom filtering functions - always filter */
if ( _oExt.afnFiltering.length !== 0 )
{
iForce = 1;
}
/*
* If the input is blank - we want the full data set
*/
if ( sInput.length <= 0 )
{
oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
}
else
{
/*
* We are starting a new search or the new search string is smaller
* then the old one (i.e. delete). Search from the master array
*/
if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
oSettings.oPreviousSearch.sSearch.length > sInput.length || iForce == 1 ||
sInput.indexOf(oSettings.oPreviousSearch.sSearch) !== 0 )
{
/* Nuke the old display array - we are going to rebuild it */
oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
/* Force a rebuild of the search array */
_fnBuildSearchArray( oSettings, 1 );
/* Search through all records to populate the search array
* The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1
* mapping
*/
for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
{
if ( rpSearch.test(oSettings.asDataSearch[i]) )
{
oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
}
}
}
else
{
/* Using old search array - refine it - do it this way for speed
* Don't have to search the whole master array again
*/
var iIndexCorrector = 0;
/* Search the current results */
for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
{
if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
{
oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
iIndexCorrector++;
}
}
}
}
oSettings.oPreviousSearch.sSearch = sInput;
oSettings.oPreviousSearch.bRegex = bRegex;
oSettings.oPreviousSearch.bSmart = bSmart;
}
/*
* Function: _fnBuildSearchArray
* Purpose: Create an array which can be quickly search through
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* int:iMaster - use the master data array - optional
*/
function _fnBuildSearchArray ( oSettings, iMaster )
{
if ( !oSettings.oFeatures.bServerSide )
{
/* Clear out the old data */
oSettings.asDataSearch.splice( 0, oSettings.asDataSearch.length );
var aArray = (typeof iMaster != 'undefined' && iMaster == 1) ?
oSettings.aiDisplayMaster : oSettings.aiDisplay;
for ( var i=0, iLen=aArray.length ; i<iLen ; i++ )
{
oSettings.asDataSearch[i] = _fnBuildSearchRow( oSettings,
_fnGetRowData( oSettings, aArray[i], 'filter' ) );
}
}
}
/*
* Function: _fnBuildSearchRow
* Purpose: Create a searchable string from a single data row
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* array:aData - Row data array to use for the data to search
*/
function _fnBuildSearchRow( oSettings, aData )
{
var sSearch = '';
if ( typeof oSettings.__nTmpFilter == 'undefined' ) {
oSettings.__nTmpFilter = document.createElement('div');
}
var nTmp = oSettings.__nTmpFilter;
for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
{
if ( oSettings.aoColumns[j].bSearchable )
{
var sData = aData[j];
sSearch += _fnDataToSearch( sData, oSettings.aoColumns[j].sType )+' ';
}
}
/* If it looks like there is an HTML entity in the string, attempt to decode it */
if ( sSearch.indexOf('&') !== -1 )
{
nTmp.innerHTML = sSearch;
sSearch = nTmp.textContent ? nTmp.textContent : nTmp.innerText;
/* IE and Opera appear to put an newline where there is a <br> tag - remove it */
sSearch = sSearch.replace(/\n/g," ").replace(/\r/g,"");
}
return sSearch;
}
/*
* Function: _fnFilterCreateSearch
* Purpose: Build a regular expression object suitable for searching a table
* Returns: RegExp: - constructed object
* Inputs: string:sSearch - string to search for
* bool:bRegex - treat as a regular expression or not
* bool:bSmart - perform smart filtering or not
*/
function _fnFilterCreateSearch( sSearch, bRegex, bSmart )
{
var asSearch, sRegExpString;
if ( bSmart )
{
/* Generate the regular expression to use. Something along the lines of:
* ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
*/
asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
return new RegExp( sRegExpString, "i" );
}
else
{
sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
return new RegExp( sSearch, "i" );
}
}
/*
* Function: _fnDataToSearch
* Purpose: Convert raw data into something that the user can search on
* Returns: string: - search string
* Inputs: string:sData - data to be modified
* string:sType - data type
*/
function _fnDataToSearch ( sData, sType )
{
if ( typeof _oExt.ofnSearch[sType] == "function" )
{
return _oExt.ofnSearch[sType]( sData );
}
else if ( sType == "html" )
{
return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
}
else if ( typeof sData == "string" )
{
return sData.replace(/\n/g," ");
}
else if ( sData === null )
{
return '';
}
return sData;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Feature: Sorting
*/
/*
* Function: _fnSort
* Purpose: Change the order of the table
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* bool:bApplyClasses - optional - should we apply classes or not
* Notes: We always sort the master array and then apply a filter again
* if it is needed. This probably isn't optimal - but atm I can't think
* of any other way which is (each has disadvantages). we want to sort aiDisplayMaster -
* but according to aoData[]._aData
*/
function _fnSort ( oSettings, bApplyClasses )
{
var
iDataSort, iDataType,
i, iLen, j, jLen,
aaSort = [],
aiOrig = [],
oSort = _oExt.oSort,
aoData = oSettings.aoData,
aoColumns = oSettings.aoColumns;
/* No sorting required if server-side or no sorting array */
if ( !oSettings.oFeatures.bServerSide &&
(oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
{
if ( oSettings.aaSortingFixed !== null )
{
aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
}
else
{
aaSort = oSettings.aaSorting.slice();
}
/* If there is a sorting data type, and a fuction belonging to it, then we need to
* get the data from the developer's function and apply it for this column
*/
for ( i=0 ; i<aaSort.length ; i++ )
{
var iColumn = aaSort[i][0];
var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
var sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
if ( typeof _oExt.afnSortData[sDataType] != 'undefined' )
{
var aData = _oExt.afnSortData[sDataType]( oSettings, iColumn, iVisColumn );
for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
{
_fnSetCellData( oSettings, j, iColumn, aData[j] );
}
}
}
/* Create a value - key array of the current row positions such that we can use their
* current position during the sort, if values match, in order to perform stable sorting
*/
for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
{
aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
}
/* Do the sort - here we want multi-column sorting based on a given data source (column)
* and sorting function (from oSort) in a certain direction. It's reasonably complex to
* follow on it's own, but this is what we want (example two column sorting):
* fnLocalSorting = function(a,b){
* var iTest;
* iTest = oSort['string-asc']('data11', 'data12');
* if (iTest !== 0)
* return iTest;
* iTest = oSort['numeric-desc']('data21', 'data22');
* if (iTest !== 0)
* return iTest;
* return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
* }
* Basically we have a test for each sorting column, if the data in that column is equal,
* test the next column. If all columns match, then we use a numeric sort on the row
* positions in the original data array to provide a stable sort.
*/
var iSortLen = aaSort.length;
oSettings.aiDisplayMaster.sort( function ( a, b ) {
var iTest, iDataSort, sDataType;
for ( i=0 ; i<iSortLen ; i++ )
{
iDataSort = aoColumns[ aaSort[i][0] ].iDataSort;
sDataType = aoColumns[ iDataSort ].sType;
iTest = oSort[ (sDataType?sDataType:'string')+"-"+aaSort[i][1] ](
_fnGetCellData( oSettings, a, iDataSort, 'sort' ),
_fnGetCellData( oSettings, b, iDataSort, 'sort' )
);
if ( iTest !== 0 )
{
return iTest;
}
}
return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
} );
}
/* Alter the sorting classes to take account of the changes */
if ( (typeof bApplyClasses == 'undefined' || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
{
_fnSortingClasses( oSettings );
}
/* Tell the draw function that we have sorted the data */
oSettings.bSorted = true;
$(oSettings.oInstance).trigger('sort', oSettings);
/* Copy the master data into the draw array and re-draw */
if ( oSettings.oFeatures.bFilter )
{
/* _fnFilter() will redraw the table for us */
_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
}
else
{
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
oSettings._iDisplayStart = 0; /* reset display back to page 0 */
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
}
/*
* Function: _fnSortAttachListener
* Purpose: Attach a sort handler (click) to a node
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* node:nNode - node to attach the handler to
* int:iDataIndex - column sorting index
* function:fnCallback - callback function - optional
*/
function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
{
$(nNode).on( 'click.DT', function (e) {
/* If the column is not sortable - don't to anything */
if ( oSettings.aoColumns[iDataIndex].bSortable === false )
{
return;
}
/*
* This is a little bit odd I admit... I declare a temporary function inside the scope of
* _fnBuildHead and the click handler in order that the code presented here can be used
* twice - once for when bProcessing is enabled, and another time for when it is
* disabled, as we need to perform slightly different actions.
* Basically the issue here is that the Javascript engine in modern browsers don't
* appear to allow the rendering engine to update the display while it is still excuting
* it's thread (well - it does but only after long intervals). This means that the
* 'processing' display doesn't appear for a table sort. To break the js thread up a bit
* I force an execution break by using setTimeout - but this breaks the expected
* thread continuation for the end-developer's point of view (their code would execute
* too early), so we on;y do it when we absolutely have to.
*/
var fnInnerSorting = function () {
var iColumn, iNextSort;
/* If the shift key is pressed then we are multipe column sorting */
if ( e.shiftKey )
{
/* Are we already doing some kind of sort on this column? */
var bFound = false;
for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
{
if ( oSettings.aaSorting[i][0] == iDataIndex )
{
bFound = true;
iColumn = oSettings.aaSorting[i][0];
iNextSort = oSettings.aaSorting[i][2]+1;
if ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )
{
/* Reached the end of the sorting options, remove from multi-col sort */
oSettings.aaSorting.splice( i, 1 );
}
else
{
/* Move onto next sorting direction */
oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
oSettings.aaSorting[i][2] = iNextSort;
}
break;
}
}
/* No sort yet - add it in */
if ( bFound === false )
{
oSettings.aaSorting.push( [ iDataIndex,
oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
}
}
else
{
/* If no shift key then single column sort */
if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
{
iColumn = oSettings.aaSorting[0][0];
iNextSort = oSettings.aaSorting[0][2]+1;
if ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )
{
iNextSort = 0;
}
oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
oSettings.aaSorting[0][2] = iNextSort;
}
else
{
oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
oSettings.aaSorting.push( [ iDataIndex,
oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
}
}
/* Run the sort */
_fnSort( oSettings );
}; /* /fnInnerSorting */
if ( !oSettings.oFeatures.bProcessing )
{
fnInnerSorting();
}
else
{
_fnProcessingDisplay( oSettings, true );
setTimeout( function() {
fnInnerSorting();
if ( !oSettings.oFeatures.bServerSide )
{
_fnProcessingDisplay( oSettings, false );
}
}, 0 );
}
/* Call the user specified callback function - used for async user interaction */
if ( typeof fnCallback == 'function' )
{
fnCallback( oSettings );
}
} );
}
/*
* Function: _fnSortingClasses
* Purpose: Set the sortting classes on the header
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* Notes: It is safe to call this function when bSort and bSortClasses are false
*/
function _fnSortingClasses( oSettings )
{
var i, iLen, j, jLen, iFound;
var aaSort, sClass;
var iColumns = oSettings.aoColumns.length;
var oClasses = oSettings.oClasses;
for ( i=0 ; i<iColumns ; i++ )
{
if ( oSettings.aoColumns[i].bSortable )
{
$(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
" "+ oSettings.aoColumns[i].sSortingClass );
}
}
if ( oSettings.aaSortingFixed !== null )
{
aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
}
else
{
aaSort = oSettings.aaSorting.slice();
}
/* Apply the required classes to the header */
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
if ( oSettings.aoColumns[i].bSortable )
{
sClass = oSettings.aoColumns[i].sSortingClass;
iFound = -1;
for ( j=0 ; j<aaSort.length ; j++ )
{
if ( aaSort[j][0] == i )
{
sClass = ( aaSort[j][1] == "asc" ) ?
oClasses.sSortAsc : oClasses.sSortDesc;
iFound = j;
break;
}
}
$(oSettings.aoColumns[i].nTh).addClass( sClass );
if ( oSettings.bJUI )
{
/* jQuery UI uses extra markup */
var jqSpan = $("span", oSettings.aoColumns[i].nTh);
jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+
oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
var sSpanClass;
if ( iFound == -1 )
{
sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
}
else if ( aaSort[iFound][1] == "asc" )
{
sSpanClass = oClasses.sSortJUIAsc;
}
else
{
sSpanClass = oClasses.sSortJUIDesc;
}
jqSpan.addClass( sSpanClass );
}
}
else
{
/* No sorting on this column, so add the base class. This will have been assigned by
* _fnAddColumn
*/
$(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
}
}
/*
* Apply the required classes to the table body
* Note that this is given as a feature switch since it can significantly slow down a sort
* on large data sets (adding and removing of classes is always slow at the best of times..)
* Further to this, note that this code is admitadly fairly ugly. It could be made a lot
* simpiler using jQuery selectors and add/removeClass, but that is significantly slower
* (on the order of 5 times slower) - hence the direct DOM manipulation here.
* Note that for defered drawing we do use jQuery - the reason being that taking the first
* row found to see if the whole column needs processed can miss classes since the first
* column might be new.
*/
sClass = oClasses.sSortColumn;
if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
{
var nTds = _fnGetTdNodes( oSettings );
 
/* Remove the old classes */
if ( oSettings.oFeatures.bDeferRender )
{
$(nTds).removeClass(sClass+'1 '+sClass+'2 '+sClass+'3');
}
else if ( nTds.length >= iColumns )
{
for ( i=0 ; i<iColumns ; i++ )
{
if ( nTds[i].className.indexOf(sClass+"1") != -1 )
{
for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
{
nTds[(iColumns*j)+i].className =
$.trim( nTds[(iColumns*j)+i].className.replace( sClass+"1", "" ) );
}
}
else if ( nTds[i].className.indexOf(sClass+"2") != -1 )
{
for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
{
nTds[(iColumns*j)+i].className =
$.trim( nTds[(iColumns*j)+i].className.replace( sClass+"2", "" ) );
}
}
else if ( nTds[i].className.indexOf(sClass+"3") != -1 )
{
for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
{
nTds[(iColumns*j)+i].className =
$.trim( nTds[(iColumns*j)+i].className.replace( " "+sClass+"3", "" ) );
}
}
}
}
/* Add the new classes to the table */
var iClass = 1, iTargetCol;
for ( i=0 ; i<aaSort.length ; i++ )
{
iTargetCol = parseInt( aaSort[i][0], 10 );
for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
{
nTds[(iColumns*j)+iTargetCol].className += " "+sClass+iClass;
}
if ( iClass < 3 )
{
iClass++;
}
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Feature: Pagination. Note that most of the paging logic is done in
* _oExt.oPagination
*/
/*
* Function: _fnFeatureHtmlPaginate
* Purpose: Generate the node required for default pagination
* Returns: node
* Inputs: object:oSettings - dataTables settings object
*/
function _fnFeatureHtmlPaginate ( oSettings )
{
if ( oSettings.oScroll.bInfinite )
{
return null;
}
var nPaginate = document.createElement( 'div' );
nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
_oExt.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate,
function( oSettings ) {
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
);
/* Add a draw callback for the pagination on first instance, to update the paging display */
if ( typeof oSettings.aanFeatures.p == "undefined" )
{
oSettings.aoDrawCallback.push( {
"fn": function( oSettings ) {
_oExt.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
} );
},
"sName": "pagination"
} );
}
return nPaginate;
}
/*
* Function: _fnPageChange
* Purpose: Alter the display settings to change the page
* Returns: bool:true - page has changed, false - no change (no effect) eg 'first' on page 1
* Inputs: object:oSettings - dataTables settings object
* string:sAction - paging action to take: "first", "previous", "next" or "last"
*/
function _fnPageChange ( oSettings, sAction )
{
var iOldStart = oSettings._iDisplayStart;
if ( sAction == "first" )
{
oSettings._iDisplayStart = 0;
}
else if ( sAction == "previous" )
{
oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
oSettings._iDisplayStart - oSettings._iDisplayLength :
0;
/* Correct for underrun */
if ( oSettings._iDisplayStart < 0 )
{
oSettings._iDisplayStart = 0;
}
}
else if ( sAction == "next" )
{
if ( oSettings._iDisplayLength >= 0 )
{
/* Make sure we are not over running the display array */
if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
{
oSettings._iDisplayStart += oSettings._iDisplayLength;
}
}
else
{
oSettings._iDisplayStart = 0;
}
}
else if ( sAction == "last" )
{
if ( oSettings._iDisplayLength >= 0 )
{
var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
}
else
{
oSettings._iDisplayStart = 0;
}
}
else
{
_fnLog( oSettings, 0, "Unknown paging action: "+sAction );
}
$(oSettings.oInstance).trigger('page', oSettings);
return iOldStart != oSettings._iDisplayStart;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Feature: HTML info
*/
/*
* Function: _fnFeatureHtmlInfo
* Purpose: Generate the node required for the info display
* Returns: node
* Inputs: object:oSettings - dataTables settings object
*/
function _fnFeatureHtmlInfo ( oSettings )
{
var nInfo = document.createElement( 'div' );
nInfo.className = oSettings.oClasses.sInfo;
/* Actions that are to be taken once only for this feature */
if ( typeof oSettings.aanFeatures.i == "undefined" )
{
/* Add draw callback */
oSettings.aoDrawCallback.push( {
"fn": _fnUpdateInfo,
"sName": "information"
} );
/* Add id */
if ( oSettings.sTableId !== '' )
{
nInfo.setAttribute( 'id', oSettings.sTableId+'_info' );
}
}
return nInfo;
}
/*
* Function: _fnUpdateInfo
* Purpose: Update the information elements in the display
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnUpdateInfo ( oSettings )
{
/* Show information about the table */
if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
{
return;
}
var
iStart = oSettings._iDisplayStart+1, iEnd = oSettings.fnDisplayEnd(),
iMax = oSettings.fnRecordsTotal(), iTotal = oSettings.fnRecordsDisplay(),
sStart = oSettings.fnFormatNumber( iStart ), sEnd = oSettings.fnFormatNumber( iEnd ),
sMax = oSettings.fnFormatNumber( iMax ), sTotal = oSettings.fnFormatNumber( iTotal ),
sOut;
/* When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
* internally
*/
if ( oSettings.oScroll.bInfinite )
{
sStart = oSettings.fnFormatNumber( 1 );
}
if ( oSettings.fnRecordsDisplay() === 0 &&
oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
{
/* Empty record set */
sOut = oSettings.oLanguage.sInfoEmpty+ oSettings.oLanguage.sInfoPostFix;
}
else if ( oSettings.fnRecordsDisplay() === 0 )
{
/* Rmpty record set after filtering */
sOut = oSettings.oLanguage.sInfoEmpty +' '+
oSettings.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+
oSettings.oLanguage.sInfoPostFix;
}
else if ( oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
{
/* Normal record set */
sOut = oSettings.oLanguage.sInfo.
replace('_START_', sStart).
replace('_END_', sEnd).
replace('_TOTAL_', sTotal)+
oSettings.oLanguage.sInfoPostFix;
}
else
{
/* Record set after filtering */
sOut = oSettings.oLanguage.sInfo.
replace('_START_', sStart).
replace('_END_', sEnd).
replace('_TOTAL_', sTotal) +' '+
oSettings.oLanguage.sInfoFiltered.replace('_MAX_',
oSettings.fnFormatNumber(oSettings.fnRecordsTotal()))+
oSettings.oLanguage.sInfoPostFix;
}
if ( oSettings.oLanguage.fnInfoCallback !== null )
{
sOut = oSettings.oLanguage.fnInfoCallback( oSettings, iStart, iEnd, iMax, iTotal, sOut );
}
var n = oSettings.aanFeatures.i;
for ( var i=0, iLen=n.length ; i<iLen ; i++ )
{
$(n[i]).html( sOut );
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Feature: Length change
*/
/*
* Function: _fnFeatureHtmlLength
* Purpose: Generate the node required for user display length changing
* Returns: node
* Inputs: object:oSettings - dataTables settings object
*/
function _fnFeatureHtmlLength ( oSettings )
{
if ( oSettings.oScroll.bInfinite )
{
return null;
}
/* This can be overruled by not using the _MENU_ var/macro in the language variable */
var sName = (oSettings.sTableId === "") ? "" : 'name="'+oSettings.sTableId+'_length"';
var sStdMenu = '<select size="1" '+sName+'>';
var i, iLen;
if ( oSettings.aLengthMenu.length == 2 && typeof oSettings.aLengthMenu[0] == 'object' &&
typeof oSettings.aLengthMenu[1] == 'object' )
{
for ( i=0, iLen=oSettings.aLengthMenu[0].length ; i<iLen ; i++ )
{
sStdMenu += '<option value="'+oSettings.aLengthMenu[0][i]+'">'+
oSettings.aLengthMenu[1][i]+'</option>';
}
}
else
{
for ( i=0, iLen=oSettings.aLengthMenu.length ; i<iLen ; i++ )
{
sStdMenu += '<option value="'+oSettings.aLengthMenu[i]+'">'+
oSettings.aLengthMenu[i]+'</option>';
}
}
sStdMenu += '</select>';
var nLength = document.createElement( 'div' );
if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.l == "undefined" )
{
nLength.setAttribute( 'id', oSettings.sTableId+'_length' );
}
nLength.className = oSettings.oClasses.sLength;
nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
/*
* Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
* and Stefan Skopnik for fixing the fix!
*/
$('select option[value="'+oSettings._iDisplayLength+'"]',nLength).attr("selected",true);
$('select', nLength).on( 'change.DT', function(e) {
var iVal = $(this).val();
/* Update all other length options for the new display */
var n = oSettings.aanFeatures.l;
for ( i=0, iLen=n.length ; i<iLen ; i++ )
{
if ( n[i] != this.parentNode )
{
$('select', n[i]).val( iVal );
}
}
/* Redraw the table */
oSettings._iDisplayLength = parseInt(iVal, 10);
_fnCalculateEnd( oSettings );
/* If we have space to show extra rows (backing up from the end point - then do so */
if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
{
oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
if ( oSettings._iDisplayStart < 0 )
{
oSettings._iDisplayStart = 0;
}
}
if ( oSettings._iDisplayLength == -1 )
{
oSettings._iDisplayStart = 0;
}
_fnDraw( oSettings );
} );
return nLength;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Feature: Processing incidator
*/
/*
* Function: _fnFeatureHtmlProcessing
* Purpose: Generate the node required for the processing node
* Returns: node
* Inputs: object:oSettings - dataTables settings object
*/
function _fnFeatureHtmlProcessing ( oSettings )
{
var nProcessing = document.createElement( 'div' );
if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.r == "undefined" )
{
nProcessing.setAttribute( 'id', oSettings.sTableId+'_processing' );
}
nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
nProcessing.className = oSettings.oClasses.sProcessing;
oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
return nProcessing;
}
/*
* Function: _fnProcessingDisplay
* Purpose: Display or hide the processing indicator
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* bool:
* true - show the processing indicator
* false - don't show
*/
function _fnProcessingDisplay ( oSettings, bShow )
{
if ( oSettings.oFeatures.bProcessing )
{
var an = oSettings.aanFeatures.r;
for ( var i=0, iLen=an.length ; i<iLen ; i++ )
{
an[i].style.visibility = bShow ? "visible" : "hidden";
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Support functions
*/
/*
* Function: _fnVisibleToColumnIndex
* Purpose: Covert the index of a visible column to the index in the data array (take account
* of hidden columns)
* Returns: int:i - the data index
* Inputs: object:oSettings - dataTables settings object
*/
function _fnVisibleToColumnIndex( oSettings, iMatch )
{
var iColumn = -1;
for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
{
if ( oSettings.aoColumns[i].bVisible === true )
{
iColumn++;
}
if ( iColumn == iMatch )
{
return i;
}
}
return null;
}
/*
* Function: _fnColumnIndexToVisible
* Purpose: Covert the index of an index in the data array and convert it to the visible
* column index (take account of hidden columns)
* Returns: int:i - the data index
* Inputs: object:oSettings - dataTables settings object
*/
function _fnColumnIndexToVisible( oSettings, iMatch )
{
var iVisible = -1;
for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
{
if ( oSettings.aoColumns[i].bVisible === true )
{
iVisible++;
}
if ( i == iMatch )
{
return oSettings.aoColumns[i].bVisible === true ? iVisible : null;
}
}
return null;
}
/*
* Function: _fnNodeToDataIndex
* Purpose: Take a TR element and convert it to an index in aoData
* Returns: int:i - index if found, null if not
* Inputs: object:s - dataTables settings object
* node:n - the TR element to find
*/
function _fnNodeToDataIndex( s, n )
{
var i, iLen;
/* Optimisation - see if the nodes which are currently visible match, since that is
* the most likely node to be asked for (a selector or event for example)
*/
for ( i=s._iDisplayStart, iLen=s._iDisplayEnd ; i<iLen ; i++ )
{
if ( s.aoData[ s.aiDisplay[i] ].nTr == n )
{
return s.aiDisplay[i];
}
}
/* Otherwise we are in for a slog through the whole data cache */
for ( i=0, iLen=s.aoData.length ; i<iLen ; i++ )
{
if ( s.aoData[i].nTr == n )
{
return i;
}
}
return null;
}
/*
* Function: _fnVisbleColumns
* Purpose: Get the number of visible columns
* Returns: int:i - the number of visible columns
* Inputs: object:oS - dataTables settings object
*/
function _fnVisbleColumns( oS )
{
var iVis = 0;
for ( var i=0 ; i<oS.aoColumns.length ; i++ )
{
if ( oS.aoColumns[i].bVisible === true )
{
iVis++;
}
}
return iVis;
}
/*
* Function: _fnCalculateEnd
* Purpose: Rcalculate the end point based on the start point
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnCalculateEnd( oSettings )
{
if ( oSettings.oFeatures.bPaginate === false )
{
oSettings._iDisplayEnd = oSettings.aiDisplay.length;
}
else
{
/* Set the end point of the display - based on how many elements there are
* still to display
*/
if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
oSettings._iDisplayLength == -1 )
{
oSettings._iDisplayEnd = oSettings.aiDisplay.length;
}
else
{
oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
}
}
}
/*
* Function: _fnConvertToWidth
* Purpose: Convert a CSS unit width to pixels (e.g. 2em)
* Returns: int:iWidth - width in pixels
* Inputs: string:sWidth - width to be converted
* node:nParent - parent to get the with for (required for
* relative widths) - optional
*/
function _fnConvertToWidth ( sWidth, nParent )
{
if ( !sWidth || sWidth === null || sWidth === '' )
{
return 0;
}
if ( typeof nParent == "undefined" )
{
nParent = document.getElementsByTagName('body')[0];
}
var iWidth;
var nTmp = document.createElement( "div" );
nTmp.style.width = _fnStringToCss( sWidth );
nParent.appendChild( nTmp );
iWidth = nTmp.offsetWidth;
nParent.removeChild( nTmp );
return ( iWidth );
}
/*
* Function: _fnCalculateColumnWidths
* Purpose: Calculate the width of columns for the table
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnCalculateColumnWidths ( oSettings )
{
var iTableWidth = oSettings.nTable.offsetWidth;
var iUserInputs = 0;
var iTmpWidth;
var iVisibleColumns = 0;
var iColums = oSettings.aoColumns.length;
var i, iIndex, iCorrector, iWidth;
var oHeaders = $('th', oSettings.nTHead);
/* Convert any user input sizes into pixel sizes */
for ( i=0 ; i<iColums ; i++ )
{
if ( oSettings.aoColumns[i].bVisible )
{
iVisibleColumns++;
if ( oSettings.aoColumns[i].sWidth !== null )
{
iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig,
oSettings.nTable.parentNode );
if ( iTmpWidth !== null )
{
oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
}
iUserInputs++;
}
}
}
/* If the number of columns in the DOM equals the number that we have to process in
* DataTables, then we can use the offsets that are created by the web-browser. No custom
* sizes can be set in order for this to happen, nor scrolling used
*/
if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
{
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
iTmpWidth = $(oHeaders[i]).width();
if ( iTmpWidth !== null )
{
oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
}
}
}
else
{
/* Otherwise we are going to have to do some calculations to get the width of each column.
* Construct a 1 row table with the widest node in the data, and any user defined widths,
* then insert it into the DOM and allow the browser to do all the hard work of
* calculating table widths.
*/
var
nCalcTmp = oSettings.nTable.cloneNode( false ),
nTheadClone = oSettings.nTHead.cloneNode(true),
nBody = document.createElement( 'tbody' ),
nTr = document.createElement( 'tr' ),
nDivSizing;
nCalcTmp.removeAttribute( "id" );
nCalcTmp.appendChild( nTheadClone );
if ( oSettings.nTFoot !== null )
{
nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
_fnApplyToChildren( function(n) {
n.style.width = "";
}, nCalcTmp.getElementsByTagName('tr') );
}
nCalcTmp.appendChild( nBody );
nBody.appendChild( nTr );
/* Remove any sizing that was previously applied by the styles */
var jqColSizing = $('thead th', nCalcTmp);
if ( jqColSizing.length === 0 )
{
jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
}
 
/* Apply custom sizing to the cloned header */
var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
iCorrector = 0;
for ( i=0 ; i<iColums ; i++ )
{
var oColumn = oSettings.aoColumns[i];
if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
{
nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
}
else if ( oColumn.bVisible )
{
nThs[i-iCorrector].style.width = "";
}
else
{
iCorrector++;
}
}
 
/* Find the biggest td for each column and put it into the table */
for ( i=0 ; i<iColums ; i++ )
{
if ( oSettings.aoColumns[i].bVisible )
{
var nTd = _fnGetWidestNode( oSettings, i );
if ( nTd !== null )
{
nTd = nTd.cloneNode(true);
if ( oSettings.aoColumns[i].sContentPadding !== "" )
{
nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
}
nTr.appendChild( nTd );
}
}
}
/* Build the table and 'display' it */
var nWrapper = oSettings.nTable.parentNode;
nWrapper.appendChild( nCalcTmp );
/* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
* when not scrolling leave the table width as it is. This results in slightly different,
* but I think correct behaviour
*/
if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
{
nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
}
else if ( oSettings.oScroll.sX !== "" )
{
nCalcTmp.style.width = "";
if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
{
nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
}
}
else if ( oSettings.oScroll.sY !== "" )
{
nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
}
nCalcTmp.style.visibility = "hidden";
/* Scrolling considerations */
_fnScrollingWidthAdjust( oSettings, nCalcTmp );
/* Read the width's calculated by the browser and store them for use by the caller. We
* first of all try to use the elements in the body, but it is possible that there are
* no elements there, under which circumstances we use the header elements
*/
var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
if ( oNodes.length === 0 )
{
oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
}
 
/* Browsers need a bit of a hand when a width is assigned to any columns when
* x-scrolling as they tend to collapse the table to the min-width, even if
* we sent the column widths. So we need to keep track of what the table width
* should be by summing the user given values, and the automatic values
*/
if ( oSettings.oScroll.sX !== "" )
{
var iTotal = 0;
iCorrector = 0;
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
if ( oSettings.aoColumns[i].bVisible )
{
if ( oSettings.aoColumns[i].sWidthOrig === null )
{
iTotal += $(oNodes[iCorrector]).outerWidth();
}
else
{
iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
}
iCorrector++;
}
}
nCalcTmp.style.width = _fnStringToCss( iTotal );
oSettings.nTable.style.width = _fnStringToCss( iTotal );
}
 
iCorrector = 0;
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
if ( oSettings.aoColumns[i].bVisible )
{
iWidth = $(oNodes[iCorrector]).width();
if ( iWidth !== null && iWidth > 0 )
{
oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
}
iCorrector++;
}
}
oSettings.nTable.style.width = _fnStringToCss( $(nCalcTmp).outerWidth() );
nCalcTmp.parentNode.removeChild( nCalcTmp );
}
}
/*
* Function: _fnScrollingWidthAdjust
* Purpose: Adjust a table's width to take account of scrolling
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* node:n - table node
*/
function _fnScrollingWidthAdjust ( oSettings, n )
{
if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
{
/* When y-scrolling only, we want to remove the width of the scroll bar so the table
* + scroll bar will fit into the area avaialble.
*/
var iOrigWidth = $(n).width();
n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
}
else if ( oSettings.oScroll.sX !== "" )
{
/* When x-scrolling both ways, fix the table at it's current size, without adjusting */
n.style.width = _fnStringToCss( $(n).outerWidth() );
}
}
/*
* Function: _fnGetWidestNode
* Purpose: Get the widest node
* Returns: string: - max strlens for each column
* Inputs: object:oSettings - dataTables settings object
* int:iCol - column of interest
*/
function _fnGetWidestNode( oSettings, iCol )
{
var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
if ( iMaxIndex < 0 )
{
return null;
}
 
if ( oSettings.aoData[iMaxIndex].nTr === null )
{
var n = document.createElement('td');
n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
return n;
}
return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
}
/*
* Function: _fnGetMaxLenString
* Purpose: Get the maximum strlen for each data column
* Returns: string: - max strlens for each column
* Inputs: object:oSettings - dataTables settings object
* int:iCol - column of interest
*/
function _fnGetMaxLenString( oSettings, iCol )
{
var iMax = -1;
var iMaxIndex = -1;
for ( var i=0 ; i<oSettings.aoData.length ; i++ )
{
var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
s = s.replace( /<.*?>/g, "" );
if ( s.length > iMax )
{
iMax = s.length;
iMaxIndex = i;
}
}
return iMaxIndex;
}
/*
* Function: _fnStringToCss
* Purpose: Append a CSS unit (only if required) to a string
* Returns: 0 if match, 1 if length is different, 2 if no match
* Inputs: array:aArray1 - first array
* array:aArray2 - second array
*/
function _fnStringToCss( s )
{
if ( s === null )
{
return "0px";
}
if ( typeof s == 'number' )
{
if ( s < 0 )
{
return "0px";
}
return s+"px";
}
/* Check if the last character is not 0-9 */
var c = s.charCodeAt( s.length-1 );
if (c < 0x30 || c > 0x39)
{
return s;
}
return s+"px";
}
/*
* Function: _fnArrayCmp
* Purpose: Compare two arrays
* Returns: 0 if match, 1 if length is different, 2 if no match
* Inputs: array:aArray1 - first array
* array:aArray2 - second array
*/
function _fnArrayCmp( aArray1, aArray2 )
{
if ( aArray1.length != aArray2.length )
{
return 1;
}
for ( var i=0 ; i<aArray1.length ; i++ )
{
if ( aArray1[i] != aArray2[i] )
{
return 2;
}
}
return 0;
}
/*
* Function: _fnDetectType
* Purpose: Get the sort type based on an input string
* Returns: string: - type (defaults to 'string' if no type can be detected)
* Inputs: string:sData - data we wish to know the type of
* Notes: This function makes use of the DataTables plugin objct _oExt
* (.aTypes) such that new types can easily be added.
*/
function _fnDetectType( sData )
{
var aTypes = _oExt.aTypes;
var iLen = aTypes.length;
for ( var i=0 ; i<iLen ; i++ )
{
var sType = aTypes[i]( sData );
if ( sType !== null )
{
return sType;
}
}
return 'string';
}
/*
* Function: _fnSettingsFromNode
* Purpose: Return the settings object for a particular table
* Returns: object: Settings object - or null if not found
* Inputs: node:nTable - table we are using as a dataTable
*/
function _fnSettingsFromNode ( nTable )
{
for ( var i=0 ; i<_aoSettings.length ; i++ )
{
if ( _aoSettings[i].nTable == nTable )
{
return _aoSettings[i];
}
}
return null;
}
/*
* Function: _fnGetDataMaster
* Purpose: Return an array with the full table data
* Returns: array array:aData - Master data array
* Inputs: object:oSettings - dataTables settings object
*/
function _fnGetDataMaster ( oSettings )
{
var aData = [];
var iLen = oSettings.aoData.length;
for ( var i=0 ; i<iLen; i++ )
{
aData.push( oSettings.aoData[i]._aData );
}
return aData;
}
/*
* Function: _fnGetTrNodes
* Purpose: Return an array with the TR nodes for the table
* Returns: array: - TR array
* Inputs: object:oSettings - dataTables settings object
*/
function _fnGetTrNodes ( oSettings )
{
var aNodes = [];
for ( var i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
{
if ( oSettings.aoData[i].nTr !== null )
{
aNodes.push( oSettings.aoData[i].nTr );
}
}
return aNodes;
}
/*
* Function: _fnGetTdNodes
* Purpose: Return an flat array with all TD nodes for the table, or row
* Returns: array: - TD array
* Inputs: object:oSettings - dataTables settings object
* int:iIndividualRow - aoData index to get the nodes for - optional if not
* given then the return array will contain all nodes for the table
*/
function _fnGetTdNodes ( oSettings, iIndividualRow )
{
var anReturn = [];
var iCorrector;
var anTds;
var iRow, iRows=oSettings.aoData.length,
iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
/* Allow the collection to be limited to just one row */
if ( typeof iIndividualRow != 'undefined' )
{
iStart = iIndividualRow;
iEnd = iIndividualRow+1;
}
 
for ( iRow=iStart ; iRow<iEnd ; iRow++ )
{
oData = oSettings.aoData[iRow];
if ( oData.nTr !== null )
{
/* get the TD child nodes - taking into account text etc nodes */
anTds = [];
for ( iColumn=0, iColumns=oData.nTr.childNodes.length ; iColumn<iColumns ; iColumn++ )
{
sNodeName = oData.nTr.childNodes[iColumn].nodeName.toLowerCase();
if ( sNodeName == 'td' || sNodeName == 'th' )
{
anTds.push( oData.nTr.childNodes[iColumn] );
}
}
 
iCorrector = 0;
for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
{
if ( oSettings.aoColumns[iColumn].bVisible )
{
anReturn.push( anTds[iColumn-iCorrector] );
}
else
{
anReturn.push( oData._anHidden[iColumn] );
iCorrector++;
}
}
}
}
 
return anReturn;
}
/*
* Function: _fnEscapeRegex
* Purpose: scape a string stuch that it can be used in a regular expression
* Returns: string: - escaped string
* Inputs: string:sVal - string to escape
*/
function _fnEscapeRegex ( sVal )
{
var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^' ];
var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
return sVal.replace(reReplace, '\\$1');
}
/*
* Function: _fnDeleteIndex
* Purpose: Take an array of integers (index array) and remove a target integer (value - not
* the key!)
* Returns: -
* Inputs: a:array int - Index array to target
* int:iTarget - value to find
*/
function _fnDeleteIndex( a, iTarget )
{
var iTargetIndex = -1;
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
{
if ( a[i] == iTarget )
{
iTargetIndex = i;
}
else if ( a[i] > iTarget )
{
a[i]--;
}
}
if ( iTargetIndex != -1 )
{
a.splice( iTargetIndex, 1 );
}
}
/*
* Function: _fnReOrderIndex
* Purpose: Figure out how to reorder a display list
* Returns: array int:aiReturn - index list for reordering
* Inputs: object:oSettings - dataTables settings object
*/
function _fnReOrderIndex ( oSettings, sColumns )
{
var aColumns = sColumns.split(',');
var aiReturn = [];
for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
for ( var j=0 ; j<iLen ; j++ )
{
if ( oSettings.aoColumns[i].sName == aColumns[j] )
{
aiReturn.push( j );
break;
}
}
}
return aiReturn;
}
/*
* Function: _fnColumnOrdering
* Purpose: Get the column ordering that DataTables expects
* Returns: string: - comma separated list of names
* Inputs: object:oSettings - dataTables settings object
*/
function _fnColumnOrdering ( oSettings )
{
var sNames = '';
for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
sNames += oSettings.aoColumns[i].sName+',';
}
if ( sNames.length == iLen )
{
return "";
}
return sNames.slice(0, -1);
}
/*
* Function: _fnLog
* Purpose: Log an error message
* Returns: -
* Inputs: int:iLevel - log error messages, or display them to the user
* string:sMesg - error message
*/
function _fnLog( oSettings, iLevel, sMesg )
{
var sAlert = oSettings.sTableId === "" ?
"DataTables warning: " +sMesg :
"DataTables warning (table id = '"+oSettings.sTableId+"'): " +sMesg;
if ( iLevel === 0 )
{
if ( _oExt.sErrMode == 'alert' )
{
alert( sAlert );
}
else
{
throw sAlert;
}
return;
}
else if ( typeof console != 'undefined' && typeof console.log != 'undefined' )
{
console.log( sAlert );
}
}
/*
* Function: _fnClearTable
* Purpose: Nuke the table
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnClearTable( oSettings )
{
oSettings.aoData.splice( 0, oSettings.aoData.length );
oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
_fnCalculateEnd( oSettings );
}
/*
* Function: _fnSaveState
* Purpose: Save the state of a table in a cookie such that the page can be reloaded
* Returns: -
* Inputs: object:oSettings - dataTables settings object
*/
function _fnSaveState ( oSettings )
{
if ( !oSettings.oFeatures.bStateSave || typeof oSettings.bDestroying != 'undefined' )
{
return;
}
/* Store the interesting variables */
var i, iLen, sTmp;
var sValue = "{";
sValue += '"iCreate":'+ new Date().getTime()+',';
sValue += '"iStart":'+ (oSettings.oScroll.bInfinite ? 0 : oSettings._iDisplayStart)+',';
sValue += '"iEnd":'+ (oSettings.oScroll.bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd)+',';
sValue += '"iLength":'+ oSettings._iDisplayLength+',';
sValue += '"sFilter":"'+ encodeURIComponent(oSettings.oPreviousSearch.sSearch)+'",';
sValue += '"sFilterEsc":'+ !oSettings.oPreviousSearch.bRegex+',';
sValue += '"aaSorting":[ ';
for ( i=0 ; i<oSettings.aaSorting.length ; i++ )
{
sValue += '['+oSettings.aaSorting[i][0]+',"'+oSettings.aaSorting[i][1]+'"],';
}
sValue = sValue.substring(0, sValue.length-1);
sValue += "],";
sValue += '"aaSearchCols":[ ';
for ( i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
{
sValue += '["'+encodeURIComponent(oSettings.aoPreSearchCols[i].sSearch)+
'",'+!oSettings.aoPreSearchCols[i].bRegex+'],';
}
sValue = sValue.substring(0, sValue.length-1);
sValue += "],";
sValue += '"abVisCols":[ ';
for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
{
sValue += oSettings.aoColumns[i].bVisible+",";
}
sValue = sValue.substring(0, sValue.length-1);
sValue += "]";
/* Save state from any plug-ins */
for ( i=0, iLen=oSettings.aoStateSave.length ; i<iLen ; i++ )
{
sTmp = oSettings.aoStateSave[i].fn( oSettings, sValue );
if ( sTmp !== "" )
{
sValue = sTmp;
}
}
sValue += "}";
_fnCreateCookie( oSettings.sCookiePrefix+oSettings.sInstance, sValue,
oSettings.iCookieDuration, oSettings.sCookiePrefix, oSettings.fnCookieCallback );
}
/*
* Function: _fnLoadState
* Purpose: Attempt to load a saved table state from a cookie
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* object:oInit - DataTables init object so we can override settings
*/
function _fnLoadState ( oSettings, oInit )
{
if ( !oSettings.oFeatures.bStateSave )
{
return;
}
var oData, i, iLen;
var sData = _fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
if ( sData !== null && sData !== '' )
{
/* Try/catch the JSON eval - if it is bad then we ignore it - note that 1.7.0 and before
* incorrectly used single quotes for some strings - hence the replace below
*/
try
{
oData = (typeof JSON.parse == 'function') ?
JSON.parse( sData.replace(/'/g, '"') ) : $.parseJSON( sData.replace(/'/g, '"') );
}
catch( e )
{
return;
}
/* Allow custom and plug-in manipulation functions to alter the data set which was
* saved, and also reject any saved state by returning false
*/
for ( i=0, iLen=oSettings.aoStateLoad.length ; i<iLen ; i++ )
{
if ( !oSettings.aoStateLoad[i].fn( oSettings, oData ) )
{
return;
}
}
/* Store the saved state so it might be accessed at any time (particualrly a plug-in */
oSettings.oLoadedState = $.extend( true, {}, oData );
/* Restore key features */
oSettings._iDisplayStart = oData.iStart;
oSettings.iInitDisplayStart = oData.iStart;
oSettings._iDisplayEnd = oData.iEnd;
oSettings._iDisplayLength = oData.iLength;
oSettings.oPreviousSearch.sSearch = decodeURIComponent(oData.sFilter);
oSettings.aaSorting = oData.aaSorting.slice();
oSettings.saved_aaSorting = oData.aaSorting.slice();
/*
* Search filtering - global reference added in 1.4.1
* Note that we use a 'not' for the value of the regular expression indicator to maintain
* compatibility with pre 1.7 versions, where this was basically inverted. Added in 1.7.0
*/
if ( typeof oData.sFilterEsc != 'undefined' )
{
oSettings.oPreviousSearch.bRegex = !oData.sFilterEsc;
}
/* Column filtering - added in 1.5.0 beta 6 */
if ( typeof oData.aaSearchCols != 'undefined' )
{
for ( i=0 ; i<oData.aaSearchCols.length ; i++ )
{
oSettings.aoPreSearchCols[i] = {
"sSearch": decodeURIComponent(oData.aaSearchCols[i][0]),
"bRegex": !oData.aaSearchCols[i][1]
};
}
}
/* Column visibility state - added in 1.5.0 beta 10 */
if ( typeof oData.abVisCols != 'undefined' )
{
/* Pass back visibiliy settings to the init handler, but to do not here override
* the init object that the user might have passed in
*/
oInit.saved_aoColumns = [];
for ( i=0 ; i<oData.abVisCols.length ; i++ )
{
oInit.saved_aoColumns[i] = {};
oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
}
}
}
}
/*
* Function: _fnCreateCookie
* Purpose: Create a new cookie with a value to store the state of a table
* Returns: -
* Inputs: string:sName - name of the cookie to create
* string:sValue - the value the cookie should take
* int:iSecs - duration of the cookie
* string:sBaseName - sName is made up of the base + file name - this is the base
* function:fnCallback - User definable function to modify the cookie
*/
function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
{
var date = new Date();
date.setTime( date.getTime()+(iSecs*1000) );
/*
* Shocking but true - it would appear IE has major issues with having the path not having
* a trailing slash on it. We need the cookie to be available based on the path, so we
* have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
* patch to use at least some of the path
*/
var aParts = window.location.pathname.split('/');
var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
var sFullCookie, oData;
if ( fnCallback !== null )
{
oData = (typeof JSON.parse == 'function') ?
JSON.parse( sValue ) : $.parseJSON( sValue );
sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
aParts.join('/')+"/" );
}
else
{
sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
"; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
}
/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
* belonging to DataTables. This is FAR from bullet proof
*/
var sOldName="", iOldTime=9999999999999;
var iLength = _fnReadCookie( sNameFile )!==null ? document.cookie.length :
sFullCookie.length + document.cookie.length;
if ( iLength+10 > 4096 ) /* Magic 10 for padding */
{
var aCookies =document.cookie.split(';');
for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
{
if ( aCookies[i].indexOf( sBaseName ) != -1 )
{
/* It's a DataTables cookie, so eval it and check the time stamp */
var aSplitCookie = aCookies[i].split('=');
try { oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' ); }
catch( e ) { continue; }
if ( typeof oData.iCreate != 'undefined' && oData.iCreate < iOldTime )
{
sOldName = aSplitCookie[0];
iOldTime = oData.iCreate;
}
}
}
if ( sOldName !== "" )
{
document.cookie = sOldName+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
aParts.join('/') + "/";
}
}
document.cookie = sFullCookie;
}
/*
* Function: _fnReadCookie
* Purpose: Read an old cookie to get a cookie with an old table state
* Returns: string: - contents of the cookie - or null if no cookie with that name found
* Inputs: string:sName - name of the cookie to read
*/
function _fnReadCookie ( sName )
{
var
aParts = window.location.pathname.split('/'),
sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
sCookieContents = document.cookie.split(';');
for( var i=0 ; i<sCookieContents.length ; i++ )
{
var c = sCookieContents[i];
while (c.charAt(0)==' ')
{
c = c.substring(1,c.length);
}
if (c.indexOf(sNameEQ) === 0)
{
return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
}
}
return null;
}
/*
* Function: _fnDetectHeader
* Purpose: Use the DOM source to create up an array of header cells. The idea here is to
* create a layout grid (array) of rows x columns, which contains a reference
* to the cell that that point in the grid (regardless of col/rowspan), such that
* any column / row could be removed and the new grid constructed
* Returns: void
* Outputs: array object:aLayout - Array to store the calculated layout in
* Inputs: node:nThead - The header/footer element for the table
*/
function _fnDetectHeader ( aLayout, nThead )
{
var nTrs = $(nThead).children('tr');
var nCell;
var i, j, k, l, iLen, jLen, iColShifted;
var fnShiftCol = function ( a, i, j ) {
while ( typeof a[i][j] != 'undefined' ) {
j++;
}
return j;
};
 
aLayout.splice( 0, aLayout.length );
/* We know how many rows there are in the layout - so prep it */
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
{
aLayout.push( [] );
}
/* Calculate a layout array */
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
{
var iColumn = 0;
/* For every cell in the row... */
for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
{
nCell = nTrs[i].childNodes[j];
 
if ( nCell.nodeName.toUpperCase() == "TD" ||
nCell.nodeName.toUpperCase() == "TH" )
{
/* Get the col and rowspan attributes from the DOM and sanitise them */
var iColspan = nCell.getAttribute('colspan') * 1;
var iRowspan = nCell.getAttribute('rowspan') * 1;
iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
 
/* There might be colspan cells already in this row, so shift our target
* accordingly
*/
iColShifted = fnShiftCol( aLayout, i, iColumn );
/* If there is col / rowspan, copy the information into the layout grid */
for ( l=0 ; l<iColspan ; l++ )
{
for ( k=0 ; k<iRowspan ; k++ )
{
aLayout[i+k][iColShifted+l] = {
"cell": nCell,
"unique": iColspan == 1 ? true : false
};
aLayout[i+k].nTr = nTrs[i];
}
}
}
}
}
}
/*
* Function: _fnGetUniqueThs
* Purpose: Get an array of unique th elements, one for each column
* Returns: array node:aReturn - list of unique ths
* Inputs: object:oSettings - dataTables settings object
* node:nHeader - automatically detect the layout from this node - optional
* array object:aLayout - thead/tfoot layout from _fnDetectHeader - optional
*/
function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
{
var aReturn = [];
if ( typeof aLayout == 'undefined' )
{
aLayout = oSettings.aoHeader;
if ( typeof nHeader != 'undefined' )
{
aLayout = [];
_fnDetectHeader( aLayout, nHeader );
}
}
 
for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
{
for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
{
if ( aLayout[i][j].unique &&
(typeof aReturn[j] == 'undefined' || !oSettings.bSortCellsTop) )
{
aReturn[j] = aLayout[i][j].cell;
}
}
}
return aReturn;
}
/*
* Function: _fnScrollBarWidth
* Purpose: Get the width of a scroll bar in this browser being used
* Returns: int: - width in pixels
* Inputs: -
* Notes: All credit for this function belongs to Alexandre Gomes. Thanks for sharing!
* http://www.alexandre-gomes.com/?p=115
*/
function _fnScrollBarWidth ()
{
var inner = document.createElement('p');
var style = inner.style;
style.width = "100%";
style.height = "200px";
style.padding = "0px";
var outer = document.createElement('div');
style = outer.style;
style.position = "absolute";
style.top = "0px";
style.left = "0px";
style.visibility = "hidden";
style.width = "200px";
style.height = "150px";
style.padding = "0px";
style.overflow = "hidden";
outer.appendChild(inner);
document.body.appendChild(outer);
var w1 = inner.offsetWidth;
outer.style.overflow = 'scroll';
var w2 = inner.offsetWidth;
if ( w1 == w2 )
{
w2 = outer.clientWidth;
}
document.body.removeChild(outer);
return (w1 - w2);
}
/*
* Function: _fnApplyToChildren
* Purpose: Apply a given function to the display child nodes of an element array (typically
* TD children of TR rows
* Returns: - (done by reference)
* Inputs: function:fn - Method to apply to the objects
* array nodes:an1 - List of elements to look through for display children
* array nodes:an2 - Another list (identical structure to the first) - optional
*/
function _fnApplyToChildren( fn, an1, an2 )
{
for ( var i=0, iLen=an1.length ; i<iLen ; i++ )
{
for ( var j=0, jLen=an1[i].childNodes.length ; j<jLen ; j++ )
{
if ( an1[i].childNodes[j].nodeType == 1 )
{
if ( typeof an2 != 'undefined' )
{
fn( an1[i].childNodes[j], an2[i].childNodes[j] );
}
else
{
fn( an1[i].childNodes[j] );
}
}
}
}
}
/*
* Function: _fnMap
* Purpose: See if a property is defined on one object, if so assign it to the other object
* Returns: - (done by reference)
* Inputs: object:oRet - target object
* object:oSrc - source object
* string:sName - property
* string:sMappedName - name to map too - optional, sName used if not given
*/
function _fnMap( oRet, oSrc, sName, sMappedName )
{
if ( typeof sMappedName == 'undefined' )
{
sMappedName = sName;
}
if ( typeof oSrc[sName] != 'undefined' )
{
oRet[sMappedName] = oSrc[sName];
}
}
/*
* Function: _fnGetRowData
* Purpose: Get an array of data for a given row from the internal data cache
* Returns: array: - Data array
* Inputs: object:oSettings - dataTables settings object
* int:iRow - aoData row id
* string:sSpecific - data get type ('type' 'filter' 'sort')
*/
function _fnGetRowData( oSettings, iRow, sSpecific )
{
var out = [];
for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
{
out.push( _fnGetCellData( oSettings, iRow, i, sSpecific ) );
}
return out;
}
/*
* Function: _fnGetCellData
* Purpose: Get the data for a given cell from the internal cache, taking into account data mapping
* Returns: *: - Cell data
* Inputs: object:oSettings - dataTables settings object
* int:iRow - aoData row id
* int:iCol - Column index
* string:sSpecific - data get type ('display', 'type' 'filter' 'sort')
*/
function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
{
var sData;
var oCol = oSettings.aoColumns[iCol];
var oData = oSettings.aoData[iRow]._aData;
 
if ( (sData=oCol.fnGetData( oData )) === undefined )
{
if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
{
_fnLog( oSettings, 0, "Requested unknown parameter '"+oCol.mDataProp+
"' from the data source for row "+iRow );
oSettings.iDrawError = oSettings.iDraw;
}
return oCol.sDefaultContent;
}
 
/* When the data source is null, we can use default column data */
if ( sData === null && oCol.sDefaultContent !== null )
{
sData = oCol.sDefaultContent;
}
else if ( typeof sData == 'function' )
{
/* If the data source is a function, then we run it and use the return */
return sData();
}
 
if ( sSpecific == 'display' && sData === null )
{
return '';
}
return sData;
}
/*
* Function: _fnSetCellData
* Purpose: Set the value for a specific cell, into the internal data cache
* Returns: *: - Cell data
* Inputs: object:oSettings - dataTables settings object
* int:iRow - aoData row id
* int:iCol - Column index
* *:val - Value to set
*/
function _fnSetCellData( oSettings, iRow, iCol, val )
{
var oCol = oSettings.aoColumns[iCol];
var oData = oSettings.aoData[iRow]._aData;
 
oCol.fnSetData( oData, val );
}
/*
* Function: _fnGetObjectDataFn
* Purpose: Return a function that can be used to get data from a source object, taking
* into account the ability to use nested objects as a source
* Returns: function: - Data get function
* Inputs: string|int|function:mSource - The data source for the object
*/
function _fnGetObjectDataFn( mSource )
{
if ( mSource === null )
{
/* Give an empty string for rendering / sorting etc */
return function (data) {
return null;
};
}
else if ( typeof mSource == 'function' )
{
return function (data) {
return mSource( data );
};
}
else if ( typeof mSource == 'string' && mSource.indexOf('.') != -1 )
{
/* If there is a . in the source string then the data source is in a nested object
* we provide two 'quick' functions for the look up to speed up the most common
* operation, and a generalised one for when it is needed
*/
var a = mSource.split('.');
if ( a.length == 2 )
{
return function (data) {
return data[ a[0] ][ a[1] ];
};
}
else if ( a.length == 3 )
{
return function (data) {
return data[ a[0] ][ a[1] ][ a[2] ];
};
}
else
{
return function (data) {
for ( var i=0, iLen=a.length ; i<iLen ; i++ )
{
data = data[ a[i] ];
}
return data;
};
}
}
else
{
/* Array or flat object mapping */
return function (data) {
return data[mSource];
};
}
}
/*
* Function: _fnSetObjectDataFn
* Purpose: Return a function that can be used to set data from a source object, taking
* into account the ability to use nested objects as a source
* Returns: function: - Data set function
* Inputs: string|int|function:mSource - The data source for the object
*/
function _fnSetObjectDataFn( mSource )
{
if ( mSource === null )
{
/* Nothing to do when the data source is null */
return function (data, val) {};
}
else if ( typeof mSource == 'function' )
{
return function (data, val) {
return mSource( data, val );
};
}
else if ( typeof mSource == 'string' && mSource.indexOf('.') != -1 )
{
/* Like the get, we need to get data from a nested object. Again two fast lookup
* functions are provided, and a generalised one.
*/
var a = mSource.split('.');
if ( a.length == 2 )
{
return function (data, val) {
data[ a[0] ][ a[1] ] = val;
};
}
else if ( a.length == 3 )
{
return function (data, val) {
data[ a[0] ][ a[1] ][ a[2] ] = val;
};
}
else
{
return function (data, val) {
for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
{
data = data[ a[i] ];
}
data[ a[a.length-1] ] = val;
};
}
}
else
{
/* Array or flat object mapping */
return function (data, val) {
data[mSource] = val;
};
}
}
 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - API
* I'm not happy with this solution... - To be fixed in 2.0
*/
this.oApi._fnExternApiFunc = _fnExternApiFunc;
this.oApi._fnInitialise = _fnInitialise;
this.oApi._fnInitComplete = _fnInitComplete;
this.oApi._fnLanguageProcess = _fnLanguageProcess;
this.oApi._fnAddColumn = _fnAddColumn;
this.oApi._fnColumnOptions = _fnColumnOptions;
this.oApi._fnAddData = _fnAddData;
this.oApi._fnCreateTr = _fnCreateTr;
this.oApi._fnGatherData = _fnGatherData;
this.oApi._fnBuildHead = _fnBuildHead;
this.oApi._fnDrawHead = _fnDrawHead;
this.oApi._fnDraw = _fnDraw;
this.oApi._fnReDraw = _fnReDraw;
this.oApi._fnAjaxUpdate = _fnAjaxUpdate;
this.oApi._fnAjaxParameters = _fnAjaxParameters;
this.oApi._fnAjaxUpdateDraw = _fnAjaxUpdateDraw;
this.oApi._fnServerParams = _fnServerParams;
this.oApi._fnAddOptionsHtml = _fnAddOptionsHtml;
this.oApi._fnFeatureHtmlTable = _fnFeatureHtmlTable;
this.oApi._fnScrollDraw = _fnScrollDraw;
this.oApi._fnAdjustColumnSizing = _fnAdjustColumnSizing;
this.oApi._fnFeatureHtmlFilter = _fnFeatureHtmlFilter;
this.oApi._fnFilterComplete = _fnFilterComplete;
this.oApi._fnFilterCustom = _fnFilterCustom;
this.oApi._fnFilterColumn = _fnFilterColumn;
this.oApi._fnFilter = _fnFilter;
this.oApi._fnBuildSearchArray = _fnBuildSearchArray;
this.oApi._fnBuildSearchRow = _fnBuildSearchRow;
this.oApi._fnFilterCreateSearch = _fnFilterCreateSearch;
this.oApi._fnDataToSearch = _fnDataToSearch;
this.oApi._fnSort = _fnSort;
this.oApi._fnSortAttachListener = _fnSortAttachListener;
this.oApi._fnSortingClasses = _fnSortingClasses;
this.oApi._fnFeatureHtmlPaginate = _fnFeatureHtmlPaginate;
this.oApi._fnPageChange = _fnPageChange;
this.oApi._fnFeatureHtmlInfo = _fnFeatureHtmlInfo;
this.oApi._fnUpdateInfo = _fnUpdateInfo;
this.oApi._fnFeatureHtmlLength = _fnFeatureHtmlLength;
this.oApi._fnFeatureHtmlProcessing = _fnFeatureHtmlProcessing;
this.oApi._fnProcessingDisplay = _fnProcessingDisplay;
this.oApi._fnVisibleToColumnIndex = _fnVisibleToColumnIndex;
this.oApi._fnColumnIndexToVisible = _fnColumnIndexToVisible;
this.oApi._fnNodeToDataIndex = _fnNodeToDataIndex;
this.oApi._fnVisbleColumns = _fnVisbleColumns;
this.oApi._fnCalculateEnd = _fnCalculateEnd;
this.oApi._fnConvertToWidth = _fnConvertToWidth;
this.oApi._fnCalculateColumnWidths = _fnCalculateColumnWidths;
this.oApi._fnScrollingWidthAdjust = _fnScrollingWidthAdjust;
this.oApi._fnGetWidestNode = _fnGetWidestNode;
this.oApi._fnGetMaxLenString = _fnGetMaxLenString;
this.oApi._fnStringToCss = _fnStringToCss;
this.oApi._fnArrayCmp = _fnArrayCmp;
this.oApi._fnDetectType = _fnDetectType;
this.oApi._fnSettingsFromNode = _fnSettingsFromNode;
this.oApi._fnGetDataMaster = _fnGetDataMaster;
this.oApi._fnGetTrNodes = _fnGetTrNodes;
this.oApi._fnGetTdNodes = _fnGetTdNodes;
this.oApi._fnEscapeRegex = _fnEscapeRegex;
this.oApi._fnDeleteIndex = _fnDeleteIndex;
this.oApi._fnReOrderIndex = _fnReOrderIndex;
this.oApi._fnColumnOrdering = _fnColumnOrdering;
this.oApi._fnLog = _fnLog;
this.oApi._fnClearTable = _fnClearTable;
this.oApi._fnSaveState = _fnSaveState;
this.oApi._fnLoadState = _fnLoadState;
this.oApi._fnCreateCookie = _fnCreateCookie;
this.oApi._fnReadCookie = _fnReadCookie;
this.oApi._fnDetectHeader = _fnDetectHeader;
this.oApi._fnGetUniqueThs = _fnGetUniqueThs;
this.oApi._fnScrollBarWidth = _fnScrollBarWidth;
this.oApi._fnApplyToChildren = _fnApplyToChildren;
this.oApi._fnMap = _fnMap;
this.oApi._fnGetRowData = _fnGetRowData;
this.oApi._fnGetCellData = _fnGetCellData;
this.oApi._fnSetCellData = _fnSetCellData;
this.oApi._fnGetObjectDataFn = _fnGetObjectDataFn;
this.oApi._fnSetObjectDataFn = _fnSetObjectDataFn;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Constructor
*/
/* Want to be able to reference "this" inside the this.each function */
var _that = this;
return this.each(function()
{
var i=0, iLen, j, jLen, k, kLen;
/* Check to see if we are re-initialising a table */
for ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )
{
/* Base check on table node */
if ( _aoSettings[i].nTable == this )
{
if ( typeof oInit == 'undefined' ||
( typeof oInit.bRetrieve != 'undefined' && oInit.bRetrieve === true ) )
{
return _aoSettings[i].oInstance;
}
else if ( typeof oInit.bDestroy != 'undefined' && oInit.bDestroy === true )
{
_aoSettings[i].oInstance.fnDestroy();
break;
}
else
{
_fnLog( _aoSettings[i], 0, "Cannot reinitialise DataTable.\n\n"+
"To retrieve the DataTables object for this table, please pass either no arguments "+
"to the dataTable() function, or set bRetrieve to true. Alternatively, to destory "+
"the old table and create a new one, set bDestroy to true (note that a lot of "+
"changes to the configuration can be made through the API which is usually much "+
"faster)." );
return;
}
}
/* If the element we are initialising has the same ID as a table which was previously
* initialised, but the table nodes don't match (from before) then we destory the old
* instance by simply deleting it. This is under the assumption that the table has been
* destroyed by other methods. Anyone using non-id selectors will need to do this manually
*/
if ( _aoSettings[i].sTableId !== "" && _aoSettings[i].sTableId == this.getAttribute('id') )
{
_aoSettings.splice( i, 1 );
break;
}
}
/* Make a complete and independent copy of the settings object */
var oSettings = new classSettings();
_aoSettings.push( oSettings );
var bInitHandedOff = false;
var bUsePassedData = false;
/* Set the id */
var sId = this.getAttribute( 'id' );
if ( sId !== null )
{
oSettings.sTableId = sId;
oSettings.sInstance = sId;
}
else
{
oSettings.sInstance = _oExt._oExternConfig.iNextUnique ++;
}
/* Sanity check */
if ( this.nodeName.toLowerCase() != 'table' )
{
_fnLog( oSettings, 0, "Attempted to initialise DataTables on a node which is not a "+
"table: "+this.nodeName );
return;
}
/* Set the table node */
oSettings.nTable = this;
/* Keep a reference to the 'this' instance for the table. Note that if this table is being
* created with others, we retrieve a unique instance to ease API access.
*/
oSettings.oInstance = _that.length == 1 ? _that : $(this).dataTable();
/* Bind the API functions to the settings, so we can perform actions whenever oSettings is
* available
*/
oSettings.oApi = _that.oApi;
/* State the table's width for if a destroy is called at a later time */
oSettings.sDestroyWidth = $(this).width();
/* Store the features that we have available */
if ( typeof oInit != 'undefined' && oInit !== null )
{
oSettings.oInit = oInit;
_fnMap( oSettings.oFeatures, oInit, "bPaginate" );
_fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
_fnMap( oSettings.oFeatures, oInit, "bFilter" );
_fnMap( oSettings.oFeatures, oInit, "bSort" );
_fnMap( oSettings.oFeatures, oInit, "bInfo" );
_fnMap( oSettings.oFeatures, oInit, "bProcessing" );
_fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
_fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
_fnMap( oSettings.oFeatures, oInit, "bServerSide" );
_fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
_fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
_fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
_fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
_fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
_fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
_fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
_fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
_fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
_fnMap( oSettings, oInit, "asStripeClasses" );
_fnMap( oSettings, oInit, "fnPreDrawCallback" );
_fnMap( oSettings, oInit, "fnRowCallback" );
_fnMap( oSettings, oInit, "fnHeaderCallback" );
_fnMap( oSettings, oInit, "fnFooterCallback" );
_fnMap( oSettings, oInit, "fnCookieCallback" );
_fnMap( oSettings, oInit, "fnInitComplete" );
_fnMap( oSettings, oInit, "fnServerData" );
_fnMap( oSettings, oInit, "fnFormatNumber" );
_fnMap( oSettings, oInit, "aaSorting" );
_fnMap( oSettings, oInit, "aaSortingFixed" );
_fnMap( oSettings, oInit, "aLengthMenu" );
_fnMap( oSettings, oInit, "sPaginationType" );
_fnMap( oSettings, oInit, "sAjaxSource" );
_fnMap( oSettings, oInit, "sAjaxDataProp" );
_fnMap( oSettings, oInit, "iCookieDuration" );
_fnMap( oSettings, oInit, "sCookiePrefix" );
_fnMap( oSettings, oInit, "sDom" );
_fnMap( oSettings, oInit, "bSortCellsTop" );
_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
_fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
/* Callback functions which are array driven */
if ( typeof oInit.fnDrawCallback == 'function' )
{
oSettings.aoDrawCallback.push( {
"fn": oInit.fnDrawCallback,
"sName": "user"
} );
}
/* Ajax additional variables are array driven */
if ( typeof oInit.fnServerParams == 'function' )
{
oSettings.aoServerParams.push( {
"fn": oInit.fnServerParams,
"sName": "user"
} );
}
if ( typeof oInit.fnStateSaveCallback == 'function' )
{
oSettings.aoStateSave.push( {
"fn": oInit.fnStateSaveCallback,
"sName": "user"
} );
}
if ( typeof oInit.fnStateLoadCallback == 'function' )
{
oSettings.aoStateLoad.push( {
"fn": oInit.fnStateLoadCallback,
"sName": "user"
} );
}
if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
oSettings.oFeatures.bSortClasses )
{
/* Enable sort classes for server-side processing. Safe to do it here, since server-side
* processing must be enabled by the developer
*/
oSettings.aoDrawCallback.push( {
"fn": _fnSortingClasses,
"sName": "server_side_sort_classes"
} );
}
else if ( oSettings.oFeatures.bDeferRender )
{
oSettings.aoDrawCallback.push( {
"fn": _fnSortingClasses,
"sName": "defer_sort_classes"
} );
}
if ( typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI )
{
/* Use the JUI classes object for display. You could clone the oStdClasses object if
* you want to have multiple tables with multiple independent classes
*/
oSettings.oClasses = _oExt.oJUIClasses;
if ( typeof oInit.sDom == 'undefined' )
{
/* Set the DOM to use a layout suitable for jQuery UI's theming */
oSettings.sDom = '<"H"lfr>t<"F"ip>';
}
}
/* Calculate the scroll bar width and cache it for use later on */
if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
{
oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
}
if ( typeof oInit.iDisplayStart != 'undefined' &&
typeof oSettings.iInitDisplayStart == 'undefined' )
{
/* Display start point, taking into account the save saving */
oSettings.iInitDisplayStart = oInit.iDisplayStart;
oSettings._iDisplayStart = oInit.iDisplayStart;
}
/* Must be done after everything which can be overridden by a cookie! */
if ( typeof oInit.bStateSave != 'undefined' )
{
oSettings.oFeatures.bStateSave = oInit.bStateSave;
_fnLoadState( oSettings, oInit );
oSettings.aoDrawCallback.push( {
"fn": _fnSaveState,
"sName": "state_save"
} );
}
 
if ( typeof oInit.iDeferLoading != 'undefined' )
{
oSettings.bDeferLoading = true;
oSettings._iRecordsTotal = oInit.iDeferLoading;
oSettings._iRecordsDisplay = oInit.iDeferLoading;
}
if ( typeof oInit.aaData != 'undefined' )
{
bUsePassedData = true;
}
/* Backwards compatability */
/* aoColumns / aoData - remove at some point... */
if ( typeof oInit != 'undefined' && typeof oInit.aoData != 'undefined' )
{
oInit.aoColumns = oInit.aoData;
}
/* Language definitions */
if ( typeof oInit.oLanguage != 'undefined' )
{
if ( typeof oInit.oLanguage.sUrl != 'undefined' && oInit.oLanguage.sUrl !== "" )
{
/* Get the language definitions from a file */
oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
_fnLanguageProcess( oSettings, json, true ); } );
bInitHandedOff = true;
}
else
{
_fnLanguageProcess( oSettings, oInit.oLanguage, false );
}
}
/* Warning: The _fnLanguageProcess function is async to the remainder of this function due
* to the XHR. We use _bInitialised in _fnLanguageProcess() to check this the processing
* below is complete. The reason for spliting it like this is optimisation - we can fire
* off the XHR (if needed) and then continue processing the data.
*/
}
else
{
/* Create a dummy object for quick manipulation later on. */
oInit = {};
}
/*
* Stripes
* Add the stripe classes now that we know which classes to apply - unless overruled
*/
if ( typeof oInit.asStripClasses == 'undefined' &&
typeof oInit.asStripeClasses == 'undefined' )
{
oSettings.asStripeClasses.push( oSettings.oClasses.sStripeOdd );
oSettings.asStripeClasses.push( oSettings.oClasses.sStripeEven );
}
/* Remove row stripe classes if they are already on the table row */
var bStripeRemove = false;
var anRows = $(this).children('tbody').children('tr');
for ( i=0, iLen=oSettings.asStripeClasses.length ; i<iLen ; i++ )
{
if ( anRows.filter(":lt(2)").hasClass( oSettings.asStripeClasses[i]) )
{
bStripeRemove = true;
break;
}
}
if ( bStripeRemove )
{
/* Store the classes which we are about to remove so they can be readded on destory */
oSettings.asDestroyStripes = [ '', '' ];
if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripeOdd) )
{
oSettings.asDestroyStripes[0] += oSettings.oClasses.sStripeOdd+" ";
}
if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripeEven) )
{
oSettings.asDestroyStripes[0] += oSettings.oClasses.sStripeEven;
}
if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripeOdd) )
{
oSettings.asDestroyStripes[1] += oSettings.oClasses.sStripeOdd+" ";
}
if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripeEven) )
{
oSettings.asDestroyStripes[1] += oSettings.oClasses.sStripeEven;
}
anRows.removeClass( oSettings.asStripeClasses.join(' ') );
}
/*
* Columns
* See if we should load columns automatically or use defined ones
*/
var anThs = [];
var aoColumnsInit;
var nThead = this.getElementsByTagName('thead');
if ( nThead.length !== 0 )
{
_fnDetectHeader( oSettings.aoHeader, nThead[0] );
anThs = _fnGetUniqueThs( oSettings );
}
/* If not given a column array, generate one with nulls */
if ( typeof oInit.aoColumns == 'undefined' )
{
aoColumnsInit = [];
for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
{
aoColumnsInit.push( null );
}
}
else
{
aoColumnsInit = oInit.aoColumns;
}
/* Add the columns */
for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
{
/* Check if we have column visibilty state to restore */
if ( typeof oInit.saved_aoColumns != 'undefined' && oInit.saved_aoColumns.length == iLen )
{
if ( aoColumnsInit[i] === null )
{
aoColumnsInit[i] = {};
}
aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
}
_fnAddColumn( oSettings, anThs ? anThs[i] : null );
}
/* Add options from column definations */
if ( typeof oInit.aoColumnDefs != 'undefined' )
{
/* Loop over the column defs array - loop in reverse so first instace has priority */
for ( i=oInit.aoColumnDefs.length-1 ; i>=0 ; i-- )
{
/* Each column def can target multiple columns, as it is an array */
var aTargets = oInit.aoColumnDefs[i].aTargets;
if ( !$.isArray( aTargets ) )
{
_fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
}
for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
{
if ( typeof aTargets[j] == 'number' && aTargets[j] >= 0 )
{
/* 0+ integer, left to right column counting. We add columns which are unknown
* automatically. Is this the right behaviour for this? We should at least
* log it in future. We cannot do this for the negative or class targets, only here.
*/
while( oSettings.aoColumns.length <= aTargets[j] )
{
_fnAddColumn( oSettings );
}
_fnColumnOptions( oSettings, aTargets[j], oInit.aoColumnDefs[i] );
}
else if ( typeof aTargets[j] == 'number' && aTargets[j] < 0 )
{
/* Negative integer, right to left column counting */
_fnColumnOptions( oSettings, oSettings.aoColumns.length+aTargets[j],
oInit.aoColumnDefs[i] );
}
else if ( typeof aTargets[j] == 'string' )
{
/* Class name matching on TH element */
for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
{
if ( aTargets[j] == "_all" ||
$(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
{
_fnColumnOptions( oSettings, k, oInit.aoColumnDefs[i] );
}
}
}
}
}
}
/* Add options from column array - after the defs array so this has priority */
if ( typeof aoColumnsInit != 'undefined' )
{
for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
{
_fnColumnOptions( oSettings, i, aoColumnsInit[i] );
}
}
/*
* Sorting
* Check the aaSorting array
*/
for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
{
if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
{
oSettings.aaSorting[i][0] = 0;
}
var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
/* Add a default sorting index */
if ( typeof oSettings.aaSorting[i][2] == 'undefined' )
{
oSettings.aaSorting[i][2] = 0;
}
/* If aaSorting is not defined, then we use the first indicator in asSorting */
if ( typeof oInit.aaSorting == "undefined" &&
typeof oSettings.saved_aaSorting == "undefined" )
{
oSettings.aaSorting[i][1] = oColumn.asSorting[0];
}
/* Set the current sorting index based on aoColumns.asSorting */
for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
{
if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
{
oSettings.aaSorting[i][2] = j;
break;
}
}
}
/* Do a first pass on the sorting classes (allows any size changes to be taken into
* account, and also will apply sorting disabled classes if disabled
*/
_fnSortingClasses( oSettings );
/*
* Final init
* Cache the header, body and footer as required, creating them if needed
*/
var thead = $(this).children('thead');
if ( thead.length === 0 )
{
thead = [ document.createElement( 'thead' ) ];
this.appendChild( thead[0] );
}
oSettings.nTHead = thead[0];
var tbody = $(this).children('tbody');
if ( tbody.length === 0 )
{
tbody = [ document.createElement( 'tbody' ) ];
this.appendChild( tbody[0] );
}
oSettings.nTBody = tbody[0];
var tfoot = $(this).children('tfoot');
if ( tfoot.length > 0 )
{
oSettings.nTFoot = tfoot[0];
_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
}
/* Check if there is data passing into the constructor */
if ( bUsePassedData )
{
for ( i=0 ; i<oInit.aaData.length ; i++ )
{
_fnAddData( oSettings, oInit.aaData[ i ] );
}
}
else
{
/* Grab the data from the page */
_fnGatherData( oSettings );
}
/* Copy the data index array */
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
/* Initialisation complete - table can be drawn */
oSettings.bInitialised = true;
/* Check if we need to initialise the table (it might not have been handed off to the
* language processor)
*/
if ( bInitHandedOff === false )
{
_fnInitialise( oSettings );
}
});
};
})(jQuery, window, document);
/web/acc/phpsysinfo/js/jQuery/jquery.ifixpng.js
0,0 → 1,143
/*
* jQuery ifixpng plugin
* (previously known as pngfix)
* Version 2.1 (23/04/2008)+jquery1.9fix
* @requires jQuery v1.1.3 or above
*
* Examples at: http://jquery.khurshid.com
* Copyright (c) 2007 Kush M.
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
/**
*
* @example
*
* optional if location of pixel.gif if different to default which is images/pixel.gif
* $.ifixpng('media/pixel.gif');
*
* $('img[@src$=.png], #panel').ifixpng();
*
* @apply hack to all png images and #panel which icluded png img in its css
*
* @name ifixpng
* @type jQuery
* @cat Plugins/Image
* @return jQuery
* @author jQuery Community
*/
(function($) {
 
/**
* helper variables and function
*/
$.ifixpng = function(customPixel) {
if (customPixel !== undefined) {
$.ifixpng.pixel = customPixel;
}
};
$.ifixpng.getPixel = function() {
return $.ifixpng.pixel || 'images/pixel.gif';
};
 
var hack = {
ltie7 : (navigator.userAgent.match(/MSIE ((5\.5)|(6\.))/) !== null),
filter : function(src) {
return "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=scale,src='"+src+"')";
}
};
/**
* Applies ie png hack to selected dom elements
*
* $('img[@src$=.png]').ifixpng();
* @desc apply hack to all images with png extensions
*
* $('#panel, img[@src$=.png]').ifixpng();
* @desc apply hack to element #panel and all images with png extensions
*
* @name ifixpng
*/
$.fn.ifixpng = hack.ltie7 ? function(customPixel) {
if (customPixel !== undefined) {
$.ifixpng.pixel = customPixel;
}
return this.each(function() {
 
var filter = $(this).css('filter');
if (!filter.match(/src=["']?(.*\.png([?].*)?)["']?/i)) { // if not yet executed
// in case rewriting urls
var base = $('base').attr('href');
if (base) {
// remove anything after the last '/'
base = base.replace(/\/[^\/]+$/,'/');
}
if ($(this).is('img') || $(this).is('input')) { // hack image tags present in dom
if ($(this).attr('src')) {
if ($(this).attr('src').match(/.*\.png([?].*)?$/i)) { // make sure it is png image
// use source tag value if set
var source = (base && $(this).attr('src').search(/^(\/|http:)/i)) ? base + $(this).attr('src') : $(this).attr('src');
// apply filter
$(this).css({filter:hack.filter(source), width:$(this).width(), height:$(this).height()})
.attr({src:$.ifixpng.getPixel()})
.positionFix();
}
}
} else { // hack png css properties present inside css
var image = $(this).css('backgroundImage');
if (image.match(/^url\(["']?(.*\.png([?].*)?)["']?\)$/i)) {
image = RegExp.$1;
image = (base && image.substring(0,1)!='/') ? base + image : image;
$(this).css({backgroundImage:'none', filter:hack.filter(image)})
.children().children().positionFix();
}
}
}
});
} : function() { return this; };
/**
* Removes any png hack that may have been applied previously
*
* $('img[@src$=.png]').iunfixpng();
* @desc revert hack on all images with png extensions
*
* $('#panel, img[@src$=.png]').iunfixpng();
* @desc revert hack on element #panel and all images with png extensions
*
* @name iunfixpng
*/
$.fn.iunfixpng = hack.ltie7 ? function() {
return this.each(function() {
var src = $(this).css('filter');
if (src.match(/src=["']?(.*\.png([?].*)?)["']?/i)) { // get img source from filter
src = RegExp.$1;
if ($(this).is('img') || $(this).is('input')) {
$(this).attr({src:src}).css({filter:''});
} else {
$(this).css({filter:'', background:'url('+src+')'});
}
}
});
} : function() { return this; };
/**
* positions selected item relatively
*/
$.fn.positionFix = function() {
return this.each(function() {
var position = $(this).css('position');
if (position != 'absolute' && position != 'relative') {
$(this).css({position:'relative'});
}
});
};
 
})(jQuery);
/web/acc/phpsysinfo/js/jQuery/jquery.jgrowl.js
0,0 → 1,338
/**
* jGrowl 1.2.6+jquery1.9fix+jquery3fix+bindfix
*
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Written by Stan Lemon <stosh1985@gmail.com>
* Last updated: 2011.03.27
*
* jGrowl is a jQuery plugin implementing unobtrusive userland notifications. These
* notifications function similarly to the Growl Framework available for
* Mac OS X (http://growl.info).
*
* To Do:
* - Move library settings to containers and allow them to be changed per container
*
* Changes in 1.2.6
* - Fixed js error when a notification is opening and closing at the same time
*
* Changes in 1.2.5
* - Changed wrapper jGrowl's options usage to "o" instead of $.jGrowl.defaults
* - Added themeState option to control 'highlight' or 'error' for jQuery UI
* - Ammended some CSS to provide default positioning for nested usage.
* - Changed some CSS to be prefixed with jGrowl- to prevent namespacing issues
* - Added two new options - openDuration and closeDuration to allow
* better control of notification open and close speeds, respectively
* Patch contributed by Jesse Vincet.
* - Added afterOpen callback. Patch contributed by Russel Branca.
*
* Changes in 1.2.4
* - Fixed IE bug with the close-all button
* - Fixed IE bug with the filter CSS attribute (special thanks to gotwic)
* - Update IE opacity CSS
* - Changed font sizes to use "em", and only set the base style
*
* Changes in 1.2.3
* - The callbacks no longer use the container as context, instead they use the actual notification
* - The callbacks now receive the container as a parameter after the options parameter
* - beforeOpen and beforeClose now check the return value, if it's false - the notification does
* not continue. The open callback will also halt execution if it returns false.
* - Fixed bug where containers would get confused
* - Expanded the pause functionality to pause an entire container.
*
* Changes in 1.2.2
* - Notification can now be theme rolled for jQuery UI, special thanks to Jeff Chan!
*
* Changes in 1.2.1
* - Fixed instance where the interval would fire the close method multiple times.
* - Added CSS to hide from print media
* - Fixed issue with closer button when div { position: relative } is set
* - Fixed leaking issue with multiple containers. Special thanks to Matthew Hanlon!
*
* Changes in 1.2.0
* - Added message pooling to limit the number of messages appearing at a given time.
* - Closing a notification is now bound to the notification object and triggered by the close button.
*
* Changes in 1.1.2
* - Added iPhone styled example
* - Fixed possible IE7 bug when determining if the ie6 class shoudl be applied.
* - Added template for the close button, so that it's content could be customized.
*
* Changes in 1.1.1
* - Fixed CSS styling bug for ie6 caused by a mispelling
* - Changes height restriction on default notifications to min-height
* - Added skinned examples using a variety of images
* - Added the ability to customize the content of the [close all] box
* - Added jTweet, an example of using jGrowl + Twitter
*
* Changes in 1.1.0
* - Multiple container and instances.
* - Standard $.jGrowl() now wraps $.fn.jGrowl() by first establishing a generic jGrowl container.
* - Instance methods of a jGrowl container can be called by $.fn.jGrowl(methodName)
* - Added glue preferenced, which allows notifications to be inserted before or after nodes in the container
* - Added new log callback which is called before anything is done for the notification
* - Corner's attribute are now applied on an individual notification basis.
*
* Changes in 1.0.4
* - Various CSS fixes so that jGrowl renders correctly in IE6.
*
* Changes in 1.0.3
* - Fixed bug with options persisting across notifications
* - Fixed theme application bug
* - Simplified some selectors and manipulations.
* - Added beforeOpen and beforeClose callbacks
* - Reorganized some lines of code to be more readable
* - Removed unnecessary this.defaults context
* - If corners plugin is present, it's now customizable.
* - Customizable open animation.
* - Customizable close animation.
* - Customizable animation easing.
* - Added customizable positioning (top-left, top-right, bottom-left, bottom-right, center)
*
* Changes in 1.0.2
* - All CSS styling is now external.
* - Added a theme parameter which specifies a secondary class for styling, such
* that notifications can be customized in appearance on a per message basis.
* - Notification life span is now customizable on a per message basis.
* - Added the ability to disable the global closer, enabled by default.
* - Added callbacks for when a notification is opened or closed.
* - Added callback for the global closer.
* - Customizable animation speed.
* - jGrowl now set itself up and tears itself down.
*
* Changes in 1.0.1:
* - Removed dependency on metadata plugin in favor of .data()
* - Namespaced all events
*/
(function($) {
 
/** jGrowl Wrapper - Establish a base jGrowl Container for compatibility with older releases. **/
$.jGrowl = function( m , o ) {
// To maintain compatibility with older version that only supported one instance we'll create the base container.
if ( $('#jGrowl').length == 0 )
$('<div id="jGrowl"></div>').addClass( (o && o.position) ? o.position : $.jGrowl.defaults.position ).appendTo('body');
 
// Create a notification on the container.
$('#jGrowl').jGrowl(m,o);
};
 
 
/** Raise jGrowl Notification on a jGrowl Container **/
$.fn.jGrowl = function( m , o ) {
if ( $.isFunction(this.each) ) {
var args = arguments;
 
return this.each(function() {
var self = this;
 
/** Create a jGrowl Instance on the Container if it does not exist **/
if ( $(this).data('jGrowl.instance') == undefined ) {
$(this).data('jGrowl.instance', $.extend( new $.fn.jGrowl(), { notifications: [], element: null, interval: null } ));
$(this).data('jGrowl.instance').startup( this );
}
 
/** Optionally call jGrowl instance methods, or just raise a normal notification **/
if ( $.isFunction($(this).data('jGrowl.instance')[m]) ) {
$(this).data('jGrowl.instance')[m].apply( $(this).data('jGrowl.instance') , $.makeArray(args).slice(1) );
} else {
$(this).data('jGrowl.instance').create( m , o );
}
});
};
};
 
$.extend( $.fn.jGrowl.prototype , {
 
/** Default JGrowl Settings **/
defaults: {
pool: 0,
header: '',
group: '',
sticky: false,
position: 'top-right',
glue: 'after',
theme: 'default',
themeState: 'highlight',
corners: '10px',
check: 250,
life: 3000,
closeDuration: 'normal',
openDuration: 'normal',
easing: 'swing',
closer: true,
closeTemplate: '&times;',
closerTemplate: '<div>[ close all ]</div>',
log: function(e,m,o) {},
beforeOpen: function(e,m,o) {},
afterOpen: function(e,m,o) {},
open: function(e,m,o) {},
beforeClose: function(e,m,o) {},
close: function(e,m,o) {},
animateOpen: {
opacity: 'show'
},
animateClose: {
opacity: 'hide'
}
},
notifications: [],
/** jGrowl Container Node **/
element: null,
/** Interval Function **/
interval: null,
/** Create a Notification **/
create: function( message , o ) {
var o = $.extend({}, this.defaults, o);
 
/* To keep backward compatibility with 1.24 and earlier, honor 'speed' if the user has set it */
if (typeof o.speed !== 'undefined') {
o.openDuration = o.speed;
o.closeDuration = o.speed;
}
 
this.notifications.push({ message: message , options: o });
o.log.apply( this.element , [this.element,message,o] );
},
render: function( notification ) {
var self = this;
var message = notification.message;
var o = notification.options;
 
// Support for jQuery theme-states, if this is not used it displays a widget header
o.themeState = (o.themeState == '') ? '' : 'ui-state-' + o.themeState;
 
var notification = $(
'<div class="jGrowl-notification ' + o.themeState + ' ui-corner-all' +
((o.group != undefined && o.group != '') ? ' ' + o.group : '') + '">' +
'<div class="jGrowl-close">' + o.closeTemplate + '</div>' +
'<div class="jGrowl-header">' + o.header + '</div>' +
'<div class="jGrowl-message">' + message + '</div></div>'
).data("jGrowl", o).addClass(o.theme).children('div.jGrowl-close').on("click.jGrowl", function() {
$(this).parent().trigger('jGrowl.close');
}).parent();
 
 
/** Notification Actions **/
$(notification).on("mouseover.jGrowl", function() {
$('div.jGrowl-notification', self.element).data("jGrowl.pause", true);
}).on("mouseout.jGrowl", function() {
$('div.jGrowl-notification', self.element).data("jGrowl.pause", false);
}).on('jGrowl.beforeOpen', function() {
if ( o.beforeOpen.apply( notification , [notification,message,o,self.element] ) != false ) {
$(this).trigger('jGrowl.open');
}
}).on('jGrowl.open', function() {
if ( o.open.apply( notification , [notification,message,o,self.element] ) != false ) {
if ( o.glue == 'after' ) {
$('div.jGrowl-notification:last', self.element).after(notification);
} else {
$('div.jGrowl-notification:first', self.element).before(notification);
}
$(this).animate(o.animateOpen, o.openDuration, o.easing, function() {
// Fixes some anti-aliasing issues with IE filters.
if ((navigator.userAgent.match(/MSIE ([1-9])/) !== null) && (parseInt($(this).css('opacity'), 10) === 1 || parseInt($(this).css('opacity'), 10) === 0))
this.style.removeAttribute('filter');
 
if ( $(this).data("jGrowl") != null ) // Happens when a notification is closing before it's open.
$(this).data("jGrowl").created = new Date();
$(this).trigger('jGrowl.afterOpen');
});
}
}).on('jGrowl.afterOpen', function() {
o.afterOpen.apply( notification , [notification,message,o,self.element] );
}).on('jGrowl.beforeClose', function() {
if ( o.beforeClose.apply( notification , [notification,message,o,self.element] ) != false )
$(this).trigger('jGrowl.close');
}).on('jGrowl.close', function() {
// Pause the notification, lest during the course of animation another close event gets called.
$(this).data('jGrowl.pause', true);
$(this).animate(o.animateClose, o.closeDuration, o.easing, function() {
if ( $.isFunction(o.close) ) {
if ( o.close.apply( notification , [notification,message,o,self.element] ) !== false )
$(this).remove();
} else {
$(this).remove();
}
});
}).trigger('jGrowl.beforeOpen');
/** Optional Corners Plugin **/
if ( o.corners != '' && $.fn.corner != undefined ) $(notification).corner( o.corners );
 
/** Add a Global Closer if more than one notification exists **/
if ( $('div.jGrowl-notification:parent', self.element).length > 1 &&
$('div.jGrowl-closer', self.element).length == 0 && this.defaults.closer != false ) {
$(this.defaults.closerTemplate).addClass('jGrowl-closer ' + this.defaults.themeState + ' ui-corner-all').addClass(this.defaults.theme)
.appendTo(self.element).animate(this.defaults.animateOpen, this.defaults.speed, this.defaults.easing)
.on("click.jGrowl", function() {
$(this).siblings().trigger("jGrowl.beforeClose");
 
if ( $.isFunction( self.defaults.closer ) ) {
self.defaults.closer.apply( $(this).parent()[0] , [$(this).parent()[0]] );
}
});
};
},
 
/** Update the jGrowl Container, removing old jGrowl notifications **/
update: function() {
$(this.element).find('div.jGrowl-notification:parent').each( function() {
if ( $(this).data("jGrowl") != undefined && $(this).data("jGrowl").created != undefined &&
($(this).data("jGrowl").created.getTime() + parseInt($(this).data("jGrowl").life)) < (new Date()).getTime() &&
$(this).data("jGrowl").sticky != true &&
($(this).data("jGrowl.pause") == undefined || $(this).data("jGrowl.pause") != true) ) {
 
// Pause the notification, lest during the course of animation another close event gets called.
$(this).trigger('jGrowl.beforeClose');
}
});
 
if ( this.notifications.length > 0 &&
(this.defaults.pool == 0 || $(this.element).find('div.jGrowl-notification:parent').length < this.defaults.pool) )
this.render( this.notifications.shift() );
 
if ( $(this.element).find('div.jGrowl-notification:parent').length < 2 ) {
$(this.element).find('div.jGrowl-closer').animate(this.defaults.animateClose, this.defaults.speed, this.defaults.easing, function() {
$(this).remove();
});
}
},
 
/** Setup the jGrowl Notification Container **/
startup: function(e) {
this.element = $(e).addClass('jGrowl').append('<div class="jGrowl-notification"></div>');
this.interval = setInterval( function() {
$(e).data('jGrowl.instance').update();
}, parseInt(this.defaults.check));
if ((navigator.userAgent.match(/MSIE ([2-6]\.)/) !== null) && !window["XMLHttpRequest"]) {
$(this.element).addClass('ie6');
}
},
 
/** Shutdown jGrowl, removing it and clearing the interval **/
shutdown: function() {
$(this.element).removeClass('jGrowl').find('div.jGrowl-notification').remove();
clearInterval( this.interval );
},
close: function() {
$(this.element).find('div.jGrowl-notification').each(function(){
$(this).trigger('jGrowl.beforeClose');
});
}
});
/** Reference the Defaults Object for compatibility with older versions of jGrowl **/
$.jGrowl.defaults = $.fn.jGrowl.prototype.defaults;
 
})(jQuery);
/web/acc/phpsysinfo/js/jQuery/jquery.js
0,0 → 1,11007
/*!
* jQuery JavaScript Library v1.12.4-ff3fix-ff2fix
* http://jquery.com/
*
* Includes Sizzle.js
* http://sizzlejs.com/
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2016-05-20T17:17Z
*/
 
(function( global, factory ) {
 
if ( typeof module === "object" && typeof module.exports === "object" ) {
// For CommonJS and CommonJS-like environments where a proper `window`
// is present, execute the factory and get jQuery.
// For environments that do not have a `window` with a `document`
// (such as Node.js), expose a factory as module.exports.
// This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
// See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
 
// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
 
// Support: Firefox 18+
// Can't be in strict mode, several libs including ASP.NET trace
// the stack via arguments.caller.callee and Firefox dies if
// you try to trace through "use strict" call chains. (#13335)
//"use strict";
var deletedIds = [];
 
var document = window.document;
 
var slice = deletedIds.slice;
 
var concat = deletedIds.concat;
 
var push = deletedIds.push;
 
var indexOf = deletedIds.indexOf;
 
var class2type = {};
 
var toString = class2type.toString;
 
var hasOwn = class2type.hasOwnProperty;
 
var support = {};
 
 
 
var
version = "1.12.4",
 
// Define a local copy of jQuery
jQuery = function( selector, context ) {
 
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
 
// Support: Android<4.1, IE<9
// Make sure we trim BOM and NBSP
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
 
// Matches dashed string for camelizing
rmsPrefix = /^-ms-/,
rdashAlpha = /-([\da-z])/gi,
 
// Used by jQuery.camelCase as callback to replace()
fcamelCase = function( all, letter ) {
return letter.toUpperCase();
};
 
jQuery.fn = jQuery.prototype = {
 
// The current version of jQuery being used
jquery: version,
 
constructor: jQuery,
 
// Start with an empty selector
selector: "",
 
// The default length of a jQuery object is 0
length: 0,
 
toArray: function() {
return slice.call( this );
},
 
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
return num != null ?
 
// Return just the one element from the set
( num < 0 ? this[ num + this.length ] : this[ num ] ) :
 
// Return all the elements in a clean array
slice.call( this );
},
 
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems ) {
 
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
 
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
 
// Return the newly-formed element set
return ret;
},
 
// Execute a callback for every element in the matched set.
each: function( callback ) {
return jQuery.each( this, callback );
},
 
map: function( callback ) {
return this.pushStack( jQuery.map( this, function( elem, i ) {
return callback.call( elem, i, elem );
} ) );
},
 
slice: function() {
return this.pushStack( slice.apply( this, arguments ) );
},
 
first: function() {
return this.eq( 0 );
},
 
last: function() {
return this.eq( -1 );
},
 
eq: function( i ) {
var len = this.length,
j = +i + ( i < 0 ? len : 0 );
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
},
 
end: function() {
return this.prevObject || this.constructor();
},
 
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
sort: deletedIds.sort,
splice: deletedIds.splice
};
 
jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
 
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
 
// skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
 
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};
}
 
// extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
 
for ( ; i < length; i++ ) {
 
// Only deal with non-null/undefined values
if ( ( options = arguments[ i ] ) != null ) {
 
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
 
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
 
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = jQuery.isArray( copy ) ) ) ) {
 
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray( src ) ? src : [];
 
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
}
 
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
 
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
 
// Return the modified object
return target;
};
 
jQuery.extend( {
 
// Unique for each copy of jQuery on the page
expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
 
// Assume jQuery is ready without the ready module
isReady: true,
 
error: function( msg ) {
throw new Error( msg );
},
 
noop: function() {},
 
// See test/unit/core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
return jQuery.type( obj ) === "function";
},
 
isArray: Array.isArray || function( obj ) {
return jQuery.type( obj ) === "array";
},
 
isWindow: function( obj ) {
/* jshint eqeqeq: false */
return obj != null && obj == obj.window;
},
 
isNumeric: function( obj ) {
 
// parseFloat NaNs numeric-cast false positives (null|true|false|"")
// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
// subtraction forces infinities to NaN
// adding 1 corrects loss of precision from parseFloat (#15100)
var realStringObj = obj && obj.toString();
return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
},
 
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
return false;
}
return true;
},
 
isPlainObject: function( obj ) {
var key;
 
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
 
try {
 
// Not own constructor property must be Object
if ( obj.constructor &&
!hasOwn.call( obj, "constructor" ) &&
!hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
return false;
}
} catch ( e ) {
 
// IE8,9 Will throw exceptions on certain host objects #9897
return false;
}
 
// Support: IE<9
// Handle iteration over inherited properties before own properties.
if ( !support.ownFirst ) {
for ( key in obj ) {
return hasOwn.call( obj, key );
}
}
 
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
for ( key in obj ) {}
 
return key === undefined || hasOwn.call( obj, key );
},
 
type: function( obj ) {
if ( obj == null ) {
return obj + "";
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call( obj ) ] || "object" :
typeof obj;
},
 
// Workarounds based on findings by Jim Driscoll
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
globalEval: function( data ) {
if ( data && jQuery.trim( data ) ) {
 
// We use execScript on Internet Explorer
// We use an anonymous function so that context is window
// rather than jQuery in Firefox
( window.execScript || function( data ) {
window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation
} )( data );
}
},
 
// Convert dashed to camelCase; used by the css and data modules
// Microsoft forgot to hump their vendor prefix (#9572)
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
 
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
 
each: function( obj, callback ) {
var length, i = 0;
 
if ( isArrayLike( obj ) ) {
length = obj.length;
for ( ; i < length; i++ ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
} else {
for ( i in obj ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
}
 
return obj;
},
 
// Support: Android<4.1, IE<9
trim: function( text ) {
return text == null ?
"" :
( text + "" ).replace( rtrim, "" );
},
 
// results is for internal usage only
makeArray: function( arr, results ) {
var ret = results || [];
 
if ( arr != null ) {
if ( isArrayLike( Object( arr ) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
} else {
push.call( ret, arr );
}
}
 
return ret;
},
 
inArray: function( elem, arr, i ) {
var len;
 
if ( arr ) {
if ( indexOf ) {
return indexOf.call( arr, elem, i );
}
 
len = arr.length;
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
 
for ( ; i < len; i++ ) {
 
// Skip accessing in sparse arrays
if ( i in arr && arr[ i ] === elem ) {
return i;
}
}
}
 
return -1;
},
 
merge: function( first, second ) {
var len = +second.length,
j = 0,
i = first.length;
 
while ( j < len ) {
first[ i++ ] = second[ j++ ];
}
 
// Support: IE<9
// Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
if ( len !== len ) {
while ( second[ j ] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
 
first.length = i;
 
return first;
},
 
grep: function( elems, callback, invert ) {
var callbackInverse,
matches = [],
i = 0,
length = elems.length,
callbackExpect = !invert;
 
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
callbackInverse = !callback( elems[ i ], i );
if ( callbackInverse !== callbackExpect ) {
matches.push( elems[ i ] );
}
}
 
return matches;
},
 
// arg is for internal usage only
map: function( elems, callback, arg ) {
var length, value,
i = 0,
ret = [];
 
// Go through the array, translating each of the items to their new values
if ( isArrayLike( elems ) ) {
length = elems.length;
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
 
if ( value != null ) {
ret.push( value );
}
}
 
// Go through every key on the object,
} else {
for ( i in elems ) {
value = callback( elems[ i ], i, arg );
 
if ( value != null ) {
ret.push( value );
}
}
}
 
// Flatten any nested arrays
return concat.apply( [], ret );
},
 
// A global GUID counter for objects
guid: 1,
 
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
var args, proxy, tmp;
 
if ( typeof context === "string" ) {
tmp = fn[ context ];
context = fn;
fn = tmp;
}
 
// Quick check to determine if target is callable, in the spec
// this throws a TypeError, but we will just return undefined.
if ( !jQuery.isFunction( fn ) ) {
return undefined;
}
 
// Simulated bind
args = slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
};
 
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
 
return proxy;
},
 
now: function() {
return +( new Date() );
},
 
// jQuery.support is not used in Core but other projects attach their
// properties to it so it needs to exist.
support: support
} );
 
// JSHint would error on this code due to the Symbol not being defined in ES5.
// Defining this global in .jshintrc would create a danger of using the global
// unguarded in another place, it seems safer to just disable JSHint for these
// three lines.
/* jshint ignore: start */
if ( typeof Symbol === "function" ) {
jQuery.fn[ Symbol.iterator ] = deletedIds[ Symbol.iterator ];
}
/* jshint ignore: end */
 
// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );
 
function isArrayLike( obj ) {
 
// Support: iOS 8.2 (not reproducible in simulator)
// `in` check used to prevent JIT error (gh-2145)
// hasOwn isn't used here due to false negatives
// regarding Nodelist length in IE
var length = !!obj && "length" in obj && obj.length,
type = jQuery.type( obj );
 
if ( type === "function" || jQuery.isWindow( obj ) ) {
return false;
}
 
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
var Sizzle =
/*!
* Sizzle CSS Selector Engine v2.2.1
* http://sizzlejs.com/
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2015-10-17
*/
(function( window ) {
 
var i,
support,
Expr,
getText,
isXML,
tokenize,
compile,
select,
outermostContext,
sortInput,
hasDuplicate,
 
// Local document vars
setDocument,
document,
docElem,
documentIsHTML,
rbuggyQSA,
rbuggyMatches,
matches,
contains,
 
// Instance-specific data
expando = "sizzle" + 1 * new Date(),
preferredDoc = window.document,
dirruns = 0,
done = 0,
classCache = createCache(),
tokenCache = createCache(),
compilerCache = createCache(),
sortOrder = function( a, b ) {
if ( a === b ) {
hasDuplicate = true;
}
return 0;
},
 
// General-purpose constants
MAX_NEGATIVE = 1 << 31,
 
// Instance methods
hasOwn = ({}).hasOwnProperty,
arr = [],
pop = arr.pop,
push_native = arr.push,
push = arr.push,
slice = arr.slice,
// Use a stripped-down indexOf as it's faster than native
// http://jsperf.com/thor-indexof-vs-for/5
indexOf = function( list, elem ) {
var i = 0,
len = list.length;
for ( ; i < len; i++ ) {
if ( list[i] === elem ) {
return i;
}
}
return -1;
},
 
booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
 
// Regular expressions
 
// http://www.w3.org/TR/css3-selectors/#whitespace
whitespace = "[\\x20\\t\\r\\n\\f]",
 
// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
 
// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
// Operator (capture 2)
"*([*^$|!~]?=)" + whitespace +
// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
"*\\]",
 
pseudos = ":(" + identifier + ")(?:\\((" +
// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
// 1. quoted (capture 3; capture 4 or capture 5)
"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
// 2. simple (capture 6)
"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
// 3. anything else (capture 2)
".*" +
")\\)|)",
 
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
rwhitespace = new RegExp( whitespace + "+", "g" ),
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
 
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
 
rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
 
rpseudo = new RegExp( pseudos ),
ridentifier = new RegExp( "^" + identifier + "$" ),
 
matchExpr = {
"ID": new RegExp( "^#(" + identifier + ")" ),
"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
"TAG": new RegExp( "^(" + identifier + "|[*])" ),
"ATTR": new RegExp( "^" + attributes ),
"PSEUDO": new RegExp( "^" + pseudos ),
"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
// For use in libraries implementing .is()
// We use this for POS matching in `select`
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
},
 
rinputs = /^(?:input|select|textarea|button)$/i,
rheader = /^h\d$/i,
 
rnative = /^[^{]+\{\s*\[native \w/,
 
// Easily-parseable/retrievable ID or TAG or CLASS selectors
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
 
rsibling = /[+~]/,
rescape = /'|\\/g,
 
// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
funescape = function( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint
// Support: Firefox<24
// Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ?
escaped :
high < 0 ?
// BMP codepoint
String.fromCharCode( high + 0x10000 ) :
// Supplemental Plane codepoint (surrogate pair)
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
},
 
// Used for iframes
// See setDocument()
// Removing the function wrapper causes a "Permission Denied"
// error in IE
unloadHandler = function() {
setDocument();
};
 
// Optimize for push.apply( _, NodeList )
try {
push.apply(
(arr = slice.call( preferredDoc.childNodes )),
preferredDoc.childNodes
);
// Support: Android<4.0
// Detect silently failing push.apply
arr[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
push = { apply: arr.length ?
 
// Leverage slice if possible
function( target, els ) {
push_native.apply( target, slice.call(els) );
} :
 
// Support: IE<9
// Otherwise append directly
function( target, els ) {
var j = target.length,
i = 0;
// Can't trust NodeList.length
while ( (target[j++] = els[i++]) ) {}
target.length = j - 1;
}
};
}
 
function Sizzle( selector, context, results, seed ) {
var m, i, elem, nid, nidselect, match, groups, newSelector,
newContext = context && context.ownerDocument,
 
// nodeType defaults to 9, since context defaults to document
nodeType = context ? context.nodeType : 9;
 
results = results || [];
 
// Return early from calls with invalid selector or context
if ( typeof selector !== "string" || !selector ||
nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
 
return results;
}
 
// Try to shortcut find operations (as opposed to filters) in HTML documents
if ( !seed ) {
 
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
setDocument( context );
}
context = context || document;
 
if ( documentIsHTML ) {
 
// If the selector is sufficiently simple, try using a "get*By*" DOM method
// (excepting DocumentFragment context, where the methods don't exist)
if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
 
// ID selector
if ( (m = match[1]) ) {
 
// Document context
if ( nodeType === 9 ) {
if ( (elem = context.getElementById( m )) ) {
 
// Support: IE, Opera, Webkit
// TODO: identify versions
// getElementById can match elements by name instead of ID
if ( elem.id === m ) {
results.push( elem );
return results;
}
} else {
return results;
}
 
// Element context
} else {
 
// Support: IE, Opera, Webkit
// TODO: identify versions
// getElementById can match elements by name instead of ID
if ( newContext && (elem = newContext.getElementById( m )) &&
contains( context, elem ) &&
elem.id === m ) {
 
results.push( elem );
return results;
}
}
 
// Type selector
} else if ( match[2] ) {
push.apply( results, context.getElementsByTagName( selector ) );
return results;
 
// Class selector
} else if ( (m = match[3]) && support.getElementsByClassName &&
context.getElementsByClassName ) {
 
push.apply( results, context.getElementsByClassName( m ) );
return results;
}
}
 
// Take advantage of querySelectorAll
if ( support.qsa &&
!compilerCache[ selector + " " ] &&
(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
 
if ( nodeType !== 1 ) {
newContext = context;
newSelector = selector;
 
// qSA looks outside Element context, which is not what we want
// Thanks to Andrew Dupont for this workaround technique
// Support: IE <=8
// Exclude object elements
} else if ( context.nodeName.toLowerCase() !== "object" ) {
 
// Capture the context ID, setting it first if necessary
if ( (nid = context.getAttribute( "id" )) ) {
nid = nid.replace( rescape, "\\$&" );
} else {
context.setAttribute( "id", (nid = expando) );
}
 
// Prefix every selector in the list
groups = tokenize( selector );
i = groups.length;
nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']";
while ( i-- ) {
groups[i] = nidselect + " " + toSelector( groups[i] );
}
newSelector = groups.join( "," );
 
// Expand context for sibling selectors
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
context;
}
 
if ( newSelector ) {
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results;
} catch ( qsaError ) {
} finally {
if ( nid === expando ) {
context.removeAttribute( "id" );
}
}
}
}
}
}
 
// All others
return select( selector.replace( rtrim, "$1" ), context, results, seed );
}
 
/**
* Create key-value caches of limited size
* @returns {function(string, object)} Returns the Object data after storing it on itself with
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
* deleting the oldest entry
*/
function createCache() {
var keys = [];
 
function cache( key, value ) {
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
if ( keys.push( key + " " ) > Expr.cacheLength ) {
// Only keep the most recent entries
delete cache[ keys.shift() ];
}
return (cache[ key + " " ] = value);
}
return cache;
}
 
/**
* Mark a function for special use by Sizzle
* @param {Function} fn The function to mark
*/
function markFunction( fn ) {
fn[ expando ] = true;
return fn;
}
 
/**
* Support testing using an element
* @param {Function} fn Passed the created div and expects a boolean result
*/
function assert( fn ) {
var div = document.createElement("div");
 
try {
return !!fn( div );
} catch (e) {
return false;
} finally {
// Remove from its parent by default
if ( div.parentNode ) {
div.parentNode.removeChild( div );
}
// release memory in IE
div = null;
}
}
 
/**
* Adds the same handler for all of the specified attrs
* @param {String} attrs Pipe-separated list of attributes
* @param {Function} handler The method that will be applied
*/
function addHandle( attrs, handler ) {
var arr = attrs.split("|"),
i = arr.length;
 
while ( i-- ) {
Expr.attrHandle[ arr[i] ] = handler;
}
}
 
/**
* Checks document order of two siblings
* @param {Element} a
* @param {Element} b
* @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
*/
function siblingCheck( a, b ) {
var cur = b && a,
diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
( ~b.sourceIndex || MAX_NEGATIVE ) -
( ~a.sourceIndex || MAX_NEGATIVE );
 
// Use IE sourceIndex if available on both nodes
if ( diff ) {
return diff;
}
 
// Check if b follows a
if ( cur ) {
while ( (cur = cur.nextSibling) ) {
if ( cur === b ) {
return -1;
}
}
}
 
return a ? 1 : -1;
}
 
/**
* Returns a function to use in pseudos for input types
* @param {String} type
*/
function createInputPseudo( type ) {
return function( elem ) {
var name = elem.nodeName.toLowerCase();
return name === "input" && elem.type === type;
};
}
 
/**
* Returns a function to use in pseudos for buttons
* @param {String} type
*/
function createButtonPseudo( type ) {
return function( elem ) {
var name = elem.nodeName.toLowerCase();
return (name === "input" || name === "button") && elem.type === type;
};
}
 
/**
* Returns a function to use in pseudos for positionals
* @param {Function} fn
*/
function createPositionalPseudo( fn ) {
return markFunction(function( argument ) {
argument = +argument;
return markFunction(function( seed, matches ) {
var j,
matchIndexes = fn( [], seed.length, argument ),
i = matchIndexes.length;
 
// Match elements found at the specified indexes
while ( i-- ) {
if ( seed[ (j = matchIndexes[i]) ] ) {
seed[j] = !(matches[j] = seed[j]);
}
}
});
});
}
 
/**
* Checks a node for validity as a Sizzle context
* @param {Element|Object=} context
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
*/
function testContext( context ) {
return context && typeof context.getElementsByTagName !== "undefined" && context;
}
 
// Expose support vars for convenience
support = Sizzle.support = {};
 
/**
* Detects XML nodes
* @param {Element|Object} elem An element or a document
* @returns {Boolean} True iff elem is a non-HTML XML node
*/
isXML = Sizzle.isXML = function( elem ) {
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
 
/**
* Sets document-related variables once based on the current document
* @param {Element|Object} [doc] An element or document object to use to set the document
* @returns {Object} Returns the current document
*/
setDocument = Sizzle.setDocument = function( node ) {
var hasCompare, parent,
doc = node ? node.ownerDocument || node : preferredDoc;
 
// Return early if doc is invalid or already selected
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
return document;
}
 
// Update global variables
document = doc;
docElem = document.documentElement;
documentIsHTML = !isXML( document );
 
// Support: IE 9-11, Edge
// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
if ( (parent = document.defaultView) && parent.top !== parent ) {
// Support: IE 11
if ( parent.addEventListener ) {
parent.addEventListener( "unload", unloadHandler, false );
 
// Support: IE 9 - 10 only
} else if ( parent.attachEvent ) {
parent.attachEvent( "onunload", unloadHandler );
}
}
 
/* Attributes
---------------------------------------------------------------------- */
 
// Support: IE<8
// Verify that getAttribute really returns attributes and not properties
// (excepting IE8 booleans)
support.attributes = assert(function( div ) {
div.className = "i";
return !div.getAttribute("className");
});
 
/* getElement(s)By*
---------------------------------------------------------------------- */
 
// Check if getElementsByTagName("*") returns only elements
support.getElementsByTagName = assert(function( div ) {
div.appendChild( document.createComment("") );
return !div.getElementsByTagName("*").length;
});
 
// Support: IE<9
support.getElementsByClassName = rnative.test( document.getElementsByClassName );
 
// Support: IE<10
// Check if getElementById returns elements by name
// The broken getElementById methods don't pick up programatically-set names,
// so use a roundabout getElementsByName test
support.getById = assert(function( div ) {
docElem.appendChild( div ).id = expando;
return !document.getElementsByName || !document.getElementsByName( expando ).length;
});
 
// ID find and filter
if ( support.getById ) {
Expr.find["ID"] = function( id, context ) {
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var m = context.getElementById( id );
return m ? [ m ] : [];
}
};
Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
return elem.getAttribute("id") === attrId;
};
};
} else {
// Support: IE6/7
// getElementById is not reliable as a find shortcut
delete Expr.find["ID"];
 
Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
var node = typeof elem.getAttributeNode !== "undefined" &&
elem.getAttributeNode("id");
return node && node.value === attrId;
};
};
}
 
// Tag
Expr.find["TAG"] = support.getElementsByTagName ?
function( tag, context ) {
if ( typeof context.getElementsByTagName !== "undefined" ) {
return context.getElementsByTagName( tag );
 
// DocumentFragment nodes don't have gEBTN
} else if ( support.qsa ) {
return context.querySelectorAll( tag );
}
} :
 
function( tag, context ) {
var elem,
tmp = [],
i = 0,
// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
results = context.getElementsByTagName( tag );
 
// Filter out possible comments
if ( tag === "*" ) {
while ( (elem = results[i++]) ) {
if ( elem.nodeType === 1 ) {
tmp.push( elem );
}
}
 
return tmp;
}
return results;
};
 
// Class
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
return context.getElementsByClassName( className );
}
};
 
/* QSA/matchesSelector
---------------------------------------------------------------------- */
 
// QSA and matchesSelector support
 
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
rbuggyMatches = [];
 
// qSa(:focus) reports false when true (Chrome 21)
// We allow this because of a bug in IE8/9 that throws an error
// whenever `document.activeElement` is accessed on an iframe
// So, we allow :focus to pass through QSA all the time to avoid the IE error
// See http://bugs.jquery.com/ticket/13378
rbuggyQSA = [];
 
if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
// Build QSA regex
// Regex strategy adopted from Diego Perini
assert(function( div ) {
// Select is set to empty string on purpose
// This is to test IE's treatment of not explicitly
// setting a boolean content attribute,
// since its presence should be enough
// http://bugs.jquery.com/ticket/12359
docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
"<select id='" + expando + "-\r\\' msallowcapture=''>" +
"<option selected=''></option></select>";
 
// Support: IE8, Opera 11-12.16
// Nothing should be selected when empty strings follow ^= or $= or *=
// The test attribute must be unknown in Opera but "safe" for WinRT
// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
if ( div.querySelectorAll("[msallowcapture^='']").length ) {
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
}
 
// Support: IE8
// Boolean attributes and "value" are not treated correctly
if ( !div.querySelectorAll("[selected]").length ) {
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
}
 
// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
rbuggyQSA.push("~=");
}
 
// Webkit/Opera - :checked should return selected option elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
// IE8 throws error here and will not see later tests
if ( !div.querySelectorAll(":checked").length ) {
rbuggyQSA.push(":checked");
}
 
// Support: Safari 8+, iOS 8+
// https://bugs.webkit.org/show_bug.cgi?id=136851
// In-page `selector#id sibing-combinator selector` fails
if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
rbuggyQSA.push(".#.+[+~]");
}
});
 
assert(function( div ) {
// Support: Windows 8 Native Apps
// The type and name attributes are restricted during .innerHTML assignment
var input = document.createElement("input");
input.setAttribute( "type", "hidden" );
div.appendChild( input ).setAttribute( "name", "D" );
 
// Support: IE8
// Enforce case-sensitivity of name attribute
if ( div.querySelectorAll("[name=d]").length ) {
rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
}
 
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
// IE8 throws error here and will not see later tests
if ( !div.querySelectorAll(":enabled").length ) {
rbuggyQSA.push( ":enabled", ":disabled" );
}
 
// Opera 10-11 does not throw on post-comma invalid pseudos
div.querySelectorAll("*,:x");
rbuggyQSA.push(",.*:");
});
}
 
if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
docElem.webkitMatchesSelector ||
docElem.mozMatchesSelector ||
docElem.oMatchesSelector ||
docElem.msMatchesSelector) )) ) {
 
assert(function( div ) {
// Check to see if it's possible to do matchesSelector
// on a disconnected node (IE 9)
support.disconnectedMatch = matches.call( div, "div" );
 
// This should fail with an exception
// Gecko does not error, returns false instead
matches.call( div, "[s!='']:x" );
rbuggyMatches.push( "!=", pseudos );
});
}
 
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
 
/* Contains
---------------------------------------------------------------------- */
hasCompare = rnative.test( docElem.compareDocumentPosition );
 
// Element contains another
// Purposefully self-exclusive
// As in, an element does not contain itself
contains = hasCompare || rnative.test( docElem.contains ) ?
function( a, b ) {
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b && b.parentNode;
return a === bup || !!( bup && bup.nodeType === 1 && (
adown.contains ?
adown.contains( bup ) :
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
));
} :
function( a, b ) {
if ( b ) {
while ( (b = b.parentNode) ) {
if ( b === a ) {
return true;
}
}
}
return false;
};
 
/* Sorting
---------------------------------------------------------------------- */
 
// Document order sorting
sortOrder = hasCompare ?
function( a, b ) {
 
// Flag for duplicate removal
if ( a === b ) {
hasDuplicate = true;
return 0;
}
 
// Sort on method existence if only one input has compareDocumentPosition
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
if ( compare ) {
return compare;
}
 
// Calculate position if both inputs belong to the same document
compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
a.compareDocumentPosition( b ) :
 
// Otherwise we know they are disconnected
1;
 
// Disconnected nodes
if ( compare & 1 ||
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
 
// Choose the first element that is related to our preferred document
if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
return -1;
}
if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
return 1;
}
 
// Maintain original order
return sortInput ?
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
}
 
return compare & 4 ? -1 : 1;
} :
function( a, b ) {
// Exit early if the nodes are identical
if ( a === b ) {
hasDuplicate = true;
return 0;
}
 
var cur,
i = 0,
aup = a.parentNode,
bup = b.parentNode,
ap = [ a ],
bp = [ b ];
 
// Parentless nodes are either documents or disconnected
if ( !aup || !bup ) {
return a === document ? -1 :
b === document ? 1 :
aup ? -1 :
bup ? 1 :
sortInput ?
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
 
// If the nodes are siblings, we can do a quick check
} else if ( aup === bup ) {
return siblingCheck( a, b );
}
 
// Otherwise we need full lists of their ancestors for comparison
cur = a;
while ( (cur = cur.parentNode) ) {
ap.unshift( cur );
}
cur = b;
while ( (cur = cur.parentNode) ) {
bp.unshift( cur );
}
 
// Walk down the tree looking for a discrepancy
while ( ap[i] === bp[i] ) {
i++;
}
 
return i ?
// Do a sibling check if the nodes have a common ancestor
siblingCheck( ap[i], bp[i] ) :
 
// Otherwise nodes in our document sort first
ap[i] === preferredDoc ? -1 :
bp[i] === preferredDoc ? 1 :
0;
};
 
return document;
};
 
Sizzle.matches = function( expr, elements ) {
return Sizzle( expr, null, null, elements );
};
 
Sizzle.matchesSelector = function( elem, expr ) {
// Set document vars if needed
if ( ( elem.ownerDocument || elem ) !== document ) {
setDocument( elem );
}
 
// Make sure that attribute selectors are quoted
expr = expr.replace( rattributeQuotes, "='$1']" );
 
if ( support.matchesSelector && documentIsHTML &&
!compilerCache[ expr + " " ] &&
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
 
try {
var ret = matches.call( elem, expr );
 
// IE 9's matchesSelector returns false on disconnected nodes
if ( ret || support.disconnectedMatch ||
// As well, disconnected nodes are said to be in a document
// fragment in IE 9
elem.document && elem.document.nodeType !== 11 ) {
return ret;
}
} catch (e) {}
}
 
return Sizzle( expr, document, null, [ elem ] ).length > 0;
};
 
Sizzle.contains = function( context, elem ) {
// Set document vars if needed
if ( ( context.ownerDocument || context ) !== document ) {
setDocument( context );
}
return contains( context, elem );
};
 
Sizzle.attr = function( elem, name ) {
// Set document vars if needed
if ( ( elem.ownerDocument || elem ) !== document ) {
setDocument( elem );
}
 
var fn = Expr.attrHandle[ name.toLowerCase() ],
// Don't get fooled by Object.prototype properties (jQuery #13807)
val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
fn( elem, name, !documentIsHTML ) :
undefined;
 
return val !== undefined ?
val :
support.attributes || !documentIsHTML ?
elem.getAttribute( name ) :
(val = elem.getAttributeNode(name)) && val.specified ?
val.value :
null;
};
 
Sizzle.error = function( msg ) {
throw new Error( "Syntax error, unrecognized expression: " + msg );
};
 
/**
* Document sorting and removing duplicates
* @param {ArrayLike} results
*/
Sizzle.uniqueSort = function( results ) {
var elem,
duplicates = [],
j = 0,
i = 0;
 
// Unless we *know* we can detect duplicates, assume their presence
hasDuplicate = !support.detectDuplicates;
sortInput = !support.sortStable && results.slice( 0 );
results.sort( sortOrder );
 
if ( hasDuplicate ) {
while ( (elem = results[i++]) ) {
if ( elem === results[ i ] ) {
j = duplicates.push( i );
}
}
while ( j-- ) {
results.splice( duplicates[ j ], 1 );
}
}
 
// Clear input after sorting to release objects
// See https://github.com/jquery/sizzle/pull/225
sortInput = null;
 
return results;
};
 
/**
* Utility function for retrieving the text value of an array of DOM nodes
* @param {Array|Element} elem
*/
getText = Sizzle.getText = function( elem ) {
var node,
ret = "",
i = 0,
nodeType = elem.nodeType;
 
if ( !nodeType ) {
// If no nodeType, this is expected to be an array
while ( (node = elem[i++]) ) {
// Do not traverse comment nodes
ret += getText( node );
}
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
// Use textContent for elements
// innerText usage removed for consistency of new lines (jQuery #11153)
if ( typeof elem.textContent === "string" ) {
return elem.textContent;
} else {
// Traverse its children
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
ret += getText( elem );
}
}
} else if ( nodeType === 3 || nodeType === 4 ) {
return elem.nodeValue;
}
// Do not include comment or processing instruction nodes
 
return ret;
};
 
Expr = Sizzle.selectors = {
 
// Can be adjusted by the user
cacheLength: 50,
 
createPseudo: markFunction,
 
match: matchExpr,
 
attrHandle: {},
 
find: {},
 
relative: {
">": { dir: "parentNode", first: true },
" ": { dir: "parentNode" },
"+": { dir: "previousSibling", first: true },
"~": { dir: "previousSibling" }
},
 
preFilter: {
"ATTR": function( match ) {
match[1] = match[1].replace( runescape, funescape );
 
// Move the given value to match[3] whether quoted or unquoted
match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
 
if ( match[2] === "~=" ) {
match[3] = " " + match[3] + " ";
}
 
return match.slice( 0, 4 );
},
 
"CHILD": function( match ) {
/* matches from matchExpr["CHILD"]
1 type (only|nth|...)
2 what (child|of-type)
3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
4 xn-component of xn+y argument ([+-]?\d*n|)
5 sign of xn-component
6 x of xn-component
7 sign of y-component
8 y of y-component
*/
match[1] = match[1].toLowerCase();
 
if ( match[1].slice( 0, 3 ) === "nth" ) {
// nth-* requires argument
if ( !match[3] ) {
Sizzle.error( match[0] );
}
 
// numeric x and y parameters for Expr.filter.CHILD
// remember that false/true cast respectively to 0/1
match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
 
// other types prohibit arguments
} else if ( match[3] ) {
Sizzle.error( match[0] );
}
 
return match;
},
 
"PSEUDO": function( match ) {
var excess,
unquoted = !match[6] && match[2];
 
if ( matchExpr["CHILD"].test( match[0] ) ) {
return null;
}
 
// Accept quoted arguments as-is
if ( match[3] ) {
match[2] = match[4] || match[5] || "";
 
// Strip excess characters from unquoted arguments
} else if ( unquoted && rpseudo.test( unquoted ) &&
// Get excess from tokenize (recursively)
(excess = tokenize( unquoted, true )) &&
// advance to the next closing parenthesis
(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
 
// excess is a negative index
match[0] = match[0].slice( 0, excess );
match[2] = unquoted.slice( 0, excess );
}
 
// Return only captures needed by the pseudo filter method (type and argument)
return match.slice( 0, 3 );
}
},
 
filter: {
 
"TAG": function( nodeNameSelector ) {
var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
return nodeNameSelector === "*" ?
function() { return true; } :
function( elem ) {
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
};
},
 
"CLASS": function( className ) {
var pattern = classCache[ className + " " ];
 
return pattern ||
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
classCache( className, function( elem ) {
return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
});
},
 
"ATTR": function( name, operator, check ) {
return function( elem ) {
var result = Sizzle.attr( elem, name );
 
if ( result == null ) {
return operator === "!=";
}
if ( !operator ) {
return true;
}
 
result += "";
 
return operator === "=" ? result === check :
operator === "!=" ? result !== check :
operator === "^=" ? check && result.indexOf( check ) === 0 :
operator === "*=" ? check && result.indexOf( check ) > -1 :
operator === "$=" ? check && result.slice( -check.length ) === check :
operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
false;
};
},
 
"CHILD": function( type, what, argument, first, last ) {
var simple = type.slice( 0, 3 ) !== "nth",
forward = type.slice( -4 ) !== "last",
ofType = what === "of-type";
 
return first === 1 && last === 0 ?
 
// Shortcut for :nth-*(n)
function( elem ) {
return !!elem.parentNode;
} :
 
function( elem, context, xml ) {
var cache, uniqueCache, outerCache, node, nodeIndex, start,
dir = simple !== forward ? "nextSibling" : "previousSibling",
parent = elem.parentNode,
name = ofType && elem.nodeName.toLowerCase(),
useCache = !xml && !ofType,
diff = false;
 
if ( parent ) {
 
// :(first|last|only)-(child|of-type)
if ( simple ) {
while ( dir ) {
node = elem;
while ( (node = node[ dir ]) ) {
if ( ofType ?
node.nodeName.toLowerCase() === name :
node.nodeType === 1 ) {
 
return false;
}
}
// Reverse direction for :only-* (if we haven't yet done so)
start = dir = type === "only" && !start && "nextSibling";
}
return true;
}
 
start = [ forward ? parent.firstChild : parent.lastChild ];
 
// non-xml :nth-child(...) stores cache data on `parent`
if ( forward && useCache ) {
 
// Seek `elem` from a previously-cached index
 
// ...in a gzip-friendly way
node = parent;
outerCache = node[ expando ] || (node[ expando ] = {});
 
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
 
cache = uniqueCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex && cache[ 2 ];
node = nodeIndex && parent.childNodes[ nodeIndex ];
 
while ( (node = ++nodeIndex && node && node[ dir ] ||
 
// Fallback to seeking `elem` from the start
(diff = nodeIndex = 0) || start.pop()) ) {
 
// When found, cache indexes on `parent` and break
if ( node.nodeType === 1 && ++diff && node === elem ) {
uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
break;
}
}
 
} else {
// Use previously-cached element index if available
if ( useCache ) {
// ...in a gzip-friendly way
node = elem;
outerCache = node[ expando ] || (node[ expando ] = {});
 
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
 
cache = uniqueCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex;
}
 
// xml :nth-child(...)
// or :nth-last-child(...) or :nth(-last)?-of-type(...)
if ( diff === false ) {
// Use the same loop as above to seek `elem` from the start
while ( (node = ++nodeIndex && node && node[ dir ] ||
(diff = nodeIndex = 0) || start.pop()) ) {
 
if ( ( ofType ?
node.nodeName.toLowerCase() === name :
node.nodeType === 1 ) &&
++diff ) {
 
// Cache the index of each encountered element
if ( useCache ) {
outerCache = node[ expando ] || (node[ expando ] = {});
 
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
 
uniqueCache[ type ] = [ dirruns, diff ];
}
 
if ( node === elem ) {
break;
}
}
}
}
}
 
// Incorporate the offset, then check against cycle size
diff -= last;
return diff === first || ( diff % first === 0 && diff / first >= 0 );
}
};
},
 
"PSEUDO": function( pseudo, argument ) {
// pseudo-class names are case-insensitive
// http://www.w3.org/TR/selectors/#pseudo-classes
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
// Remember that setFilters inherits from pseudos
var args,
fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
Sizzle.error( "unsupported pseudo: " + pseudo );
 
// The user may use createPseudo to indicate that
// arguments are needed to create the filter function
// just as Sizzle does
if ( fn[ expando ] ) {
return fn( argument );
}
 
// But maintain support for old signatures
if ( fn.length > 1 ) {
args = [ pseudo, pseudo, "", argument ];
return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
markFunction(function( seed, matches ) {
var idx,
matched = fn( seed, argument ),
i = matched.length;
while ( i-- ) {
idx = indexOf( seed, matched[i] );
seed[ idx ] = !( matches[ idx ] = matched[i] );
}
}) :
function( elem ) {
return fn( elem, 0, args );
};
}
 
return fn;
}
},
 
pseudos: {
// Potentially complex pseudos
"not": markFunction(function( selector ) {
// Trim the selector passed to compile
// to avoid treating leading and trailing
// spaces as combinators
var input = [],
results = [],
matcher = compile( selector.replace( rtrim, "$1" ) );
 
return matcher[ expando ] ?
markFunction(function( seed, matches, context, xml ) {
var elem,
unmatched = matcher( seed, null, xml, [] ),
i = seed.length;
 
// Match elements unmatched by `matcher`
while ( i-- ) {
if ( (elem = unmatched[i]) ) {
seed[i] = !(matches[i] = elem);
}
}
}) :
function( elem, context, xml ) {
input[0] = elem;
matcher( input, null, xml, results );
// Don't keep the element (issue #299)
input[0] = null;
return !results.pop();
};
}),
 
"has": markFunction(function( selector ) {
return function( elem ) {
return Sizzle( selector, elem ).length > 0;
};
}),
 
"contains": markFunction(function( text ) {
text = text.replace( runescape, funescape );
return function( elem ) {
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
};
}),
 
// "Whether an element is represented by a :lang() selector
// is based solely on the element's language value
// being equal to the identifier C,
// or beginning with the identifier C immediately followed by "-".
// The matching of C against the element's language value is performed case-insensitively.
// The identifier C does not have to be a valid language name."
// http://www.w3.org/TR/selectors/#lang-pseudo
"lang": markFunction( function( lang ) {
// lang value must be a valid identifier
if ( !ridentifier.test(lang || "") ) {
Sizzle.error( "unsupported lang: " + lang );
}
lang = lang.replace( runescape, funescape ).toLowerCase();
return function( elem ) {
var elemLang;
do {
if ( (elemLang = documentIsHTML ?
elem.lang :
elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
 
elemLang = elemLang.toLowerCase();
return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
}
} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
return false;
};
}),
 
// Miscellaneous
"target": function( elem ) {
var hash = window.location && window.location.hash;
return hash && hash.slice( 1 ) === elem.id;
},
 
"root": function( elem ) {
return elem === docElem;
},
 
"focus": function( elem ) {
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
},
 
// Boolean properties
"enabled": function( elem ) {
return elem.disabled === false;
},
 
"disabled": function( elem ) {
return elem.disabled === true;
},
 
"checked": function( elem ) {
// In CSS3, :checked should return both checked and selected elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
var nodeName = elem.nodeName.toLowerCase();
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
},
 
"selected": function( elem ) {
// Accessing this property makes selected-by-default
// options in Safari work properly
if ( elem.parentNode ) {
elem.parentNode.selectedIndex;
}
 
return elem.selected === true;
},
 
// Contents
"empty": function( elem ) {
// http://www.w3.org/TR/selectors/#empty-pseudo
// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
// but not by others (comment: 8; processing instruction: 7; etc.)
// nodeType < 6 works because attributes (2) do not appear as children
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
if ( elem.nodeType < 6 ) {
return false;
}
}
return true;
},
 
"parent": function( elem ) {
return !Expr.pseudos["empty"]( elem );
},
 
// Element/input types
"header": function( elem ) {
return rheader.test( elem.nodeName );
},
 
"input": function( elem ) {
return rinputs.test( elem.nodeName );
},
 
"button": function( elem ) {
var name = elem.nodeName.toLowerCase();
return name === "input" && elem.type === "button" || name === "button";
},
 
"text": function( elem ) {
var attr;
return elem.nodeName.toLowerCase() === "input" &&
elem.type === "text" &&
 
// Support: IE<8
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
},
 
// Position-in-collection
"first": createPositionalPseudo(function() {
return [ 0 ];
}),
 
"last": createPositionalPseudo(function( matchIndexes, length ) {
return [ length - 1 ];
}),
 
"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
return [ argument < 0 ? argument + length : argument ];
}),
 
"even": createPositionalPseudo(function( matchIndexes, length ) {
var i = 0;
for ( ; i < length; i += 2 ) {
matchIndexes.push( i );
}
return matchIndexes;
}),
 
"odd": createPositionalPseudo(function( matchIndexes, length ) {
var i = 1;
for ( ; i < length; i += 2 ) {
matchIndexes.push( i );
}
return matchIndexes;
}),
 
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
var i = argument < 0 ? argument + length : argument;
for ( ; --i >= 0; ) {
matchIndexes.push( i );
}
return matchIndexes;
}),
 
"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
var i = argument < 0 ? argument + length : argument;
for ( ; ++i < length; ) {
matchIndexes.push( i );
}
return matchIndexes;
})
}
};
 
Expr.pseudos["nth"] = Expr.pseudos["eq"];
 
// Add button/input type pseudos
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
Expr.pseudos[ i ] = createInputPseudo( i );
}
for ( i in { submit: true, reset: true } ) {
Expr.pseudos[ i ] = createButtonPseudo( i );
}
 
// Easy API for creating new setFilters
function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();
 
tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
var matched, match, tokens, type,
soFar, groups, preFilters,
cached = tokenCache[ selector + " " ];
 
if ( cached ) {
return parseOnly ? 0 : cached.slice( 0 );
}
 
soFar = selector;
groups = [];
preFilters = Expr.preFilter;
 
while ( soFar ) {
 
// Comma and first run
if ( !matched || (match = rcomma.exec( soFar )) ) {
if ( match ) {
// Don't consume trailing commas as valid
soFar = soFar.slice( match[0].length ) || soFar;
}
groups.push( (tokens = []) );
}
 
matched = false;
 
// Combinators
if ( (match = rcombinators.exec( soFar )) ) {
matched = match.shift();
tokens.push({
value: matched,
// Cast descendant combinators to space
type: match[0].replace( rtrim, " " )
});
soFar = soFar.slice( matched.length );
}
 
// Filters
for ( type in Expr.filter ) {
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
(match = preFilters[ type ]( match ))) ) {
matched = match.shift();
tokens.push({
value: matched,
type: type,
matches: match
});
soFar = soFar.slice( matched.length );
}
}
 
if ( !matched ) {
break;
}
}
 
// Return the length of the invalid excess
// if we're just parsing
// Otherwise, throw an error or return tokens
return parseOnly ?
soFar.length :
soFar ?
Sizzle.error( selector ) :
// Cache the tokens
tokenCache( selector, groups ).slice( 0 );
};
 
function toSelector( tokens ) {
var i = 0,
len = tokens.length,
selector = "";
for ( ; i < len; i++ ) {
selector += tokens[i].value;
}
return selector;
}
 
function addCombinator( matcher, combinator, base ) {
var dir = combinator.dir,
checkNonElements = base && dir === "parentNode",
doneName = done++;
 
return combinator.first ?
// Check against closest ancestor/preceding element
function( elem, context, xml ) {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
return matcher( elem, context, xml );
}
}
} :
 
// Check against all ancestor/preceding elements
function( elem, context, xml ) {
var oldCache, uniqueCache, outerCache,
newCache = [ dirruns, doneName ];
 
// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
if ( xml ) {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
if ( matcher( elem, context, xml ) ) {
return true;
}
}
}
} else {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
outerCache = elem[ expando ] || (elem[ expando ] = {});
 
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
 
if ( (oldCache = uniqueCache[ dir ]) &&
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
 
// Assign to newCache so results back-propagate to previous elements
return (newCache[ 2 ] = oldCache[ 2 ]);
} else {
// Reuse newcache so results back-propagate to previous elements
uniqueCache[ dir ] = newCache;
 
// A match means we're done; a fail means we have to keep checking
if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
return true;
}
}
}
}
}
};
}
 
function elementMatcher( matchers ) {
return matchers.length > 1 ?
function( elem, context, xml ) {
var i = matchers.length;
while ( i-- ) {
if ( !matchers[i]( elem, context, xml ) ) {
return false;
}
}
return true;
} :
matchers[0];
}
 
function multipleContexts( selector, contexts, results ) {
var i = 0,
len = contexts.length;
for ( ; i < len; i++ ) {
Sizzle( selector, contexts[i], results );
}
return results;
}
 
function condense( unmatched, map, filter, context, xml ) {
var elem,
newUnmatched = [],
i = 0,
len = unmatched.length,
mapped = map != null;
 
for ( ; i < len; i++ ) {
if ( (elem = unmatched[i]) ) {
if ( !filter || filter( elem, context, xml ) ) {
newUnmatched.push( elem );
if ( mapped ) {
map.push( i );
}
}
}
}
 
return newUnmatched;
}
 
function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
if ( postFilter && !postFilter[ expando ] ) {
postFilter = setMatcher( postFilter );
}
if ( postFinder && !postFinder[ expando ] ) {
postFinder = setMatcher( postFinder, postSelector );
}
return markFunction(function( seed, results, context, xml ) {
var temp, i, elem,
preMap = [],
postMap = [],
preexisting = results.length,
 
// Get initial elements from seed or context
elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
 
// Prefilter to get matcher input, preserving a map for seed-results synchronization
matcherIn = preFilter && ( seed || !selector ) ?
condense( elems, preMap, preFilter, context, xml ) :
elems,
 
matcherOut = matcher ?
// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
 
// ...intermediate processing is necessary
[] :
 
// ...otherwise use results directly
results :
matcherIn;
 
// Find primary matches
if ( matcher ) {
matcher( matcherIn, matcherOut, context, xml );
}
 
// Apply postFilter
if ( postFilter ) {
temp = condense( matcherOut, postMap );
postFilter( temp, [], context, xml );
 
// Un-match failing elements by moving them back to matcherIn
i = temp.length;
while ( i-- ) {
if ( (elem = temp[i]) ) {
matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
}
}
}
 
if ( seed ) {
if ( postFinder || preFilter ) {
if ( postFinder ) {
// Get the final matcherOut by condensing this intermediate into postFinder contexts
temp = [];
i = matcherOut.length;
while ( i-- ) {
if ( (elem = matcherOut[i]) ) {
// Restore matcherIn since elem is not yet a final match
temp.push( (matcherIn[i] = elem) );
}
}
postFinder( null, (matcherOut = []), temp, xml );
}
 
// Move matched elements from seed to results to keep them synchronized
i = matcherOut.length;
while ( i-- ) {
if ( (elem = matcherOut[i]) &&
(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
 
seed[temp] = !(results[temp] = elem);
}
}
}
 
// Add elements to results, through postFinder if defined
} else {
matcherOut = condense(
matcherOut === results ?
matcherOut.splice( preexisting, matcherOut.length ) :
matcherOut
);
if ( postFinder ) {
postFinder( null, results, matcherOut, xml );
} else {
push.apply( results, matcherOut );
}
}
});
}
 
function matcherFromTokens( tokens ) {
var checkContext, matcher, j,
len = tokens.length,
leadingRelative = Expr.relative[ tokens[0].type ],
implicitRelative = leadingRelative || Expr.relative[" "],
i = leadingRelative ? 1 : 0,
 
// The foundational matcher ensures that elements are reachable from top-level context(s)
matchContext = addCombinator( function( elem ) {
return elem === checkContext;
}, implicitRelative, true ),
matchAnyContext = addCombinator( function( elem ) {
return indexOf( checkContext, elem ) > -1;
}, implicitRelative, true ),
matchers = [ function( elem, context, xml ) {
var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
(checkContext = context).nodeType ?
matchContext( elem, context, xml ) :
matchAnyContext( elem, context, xml ) );
// Avoid hanging onto element (issue #299)
checkContext = null;
return ret;
} ];
 
for ( ; i < len; i++ ) {
if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
} else {
matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
 
// Return special upon seeing a positional matcher
if ( matcher[ expando ] ) {
// Find the next relative operator (if any) for proper handling
j = ++i;
for ( ; j < len; j++ ) {
if ( Expr.relative[ tokens[j].type ] ) {
break;
}
}
return setMatcher(
i > 1 && elementMatcher( matchers ),
i > 1 && toSelector(
// If the preceding token was a descendant combinator, insert an implicit any-element `*`
tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
).replace( rtrim, "$1" ),
matcher,
i < j && matcherFromTokens( tokens.slice( i, j ) ),
j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
j < len && toSelector( tokens )
);
}
matchers.push( matcher );
}
}
 
return elementMatcher( matchers );
}
 
function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
var bySet = setMatchers.length > 0,
byElement = elementMatchers.length > 0,
superMatcher = function( seed, context, xml, results, outermost ) {
var elem, j, matcher,
matchedCount = 0,
i = "0",
unmatched = seed && [],
setMatched = [],
contextBackup = outermostContext,
// We must always have either seed elements or outermost context
elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
// Use integer dirruns iff this is the outermost matcher
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
len = elems.length;
 
if ( outermost ) {
outermostContext = context === document || context || outermost;
}
 
// Add elements passing elementMatchers directly to results
// Support: IE<9, Safari
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
if ( byElement && elem ) {
j = 0;
if ( !context && elem.ownerDocument !== document ) {
setDocument( elem );
xml = !documentIsHTML;
}
while ( (matcher = elementMatchers[j++]) ) {
if ( matcher( elem, context || document, xml) ) {
results.push( elem );
break;
}
}
if ( outermost ) {
dirruns = dirrunsUnique;
}
}
 
// Track unmatched elements for set filters
if ( bySet ) {
// They will have gone through all possible matchers
if ( (elem = !matcher && elem) ) {
matchedCount--;
}
 
// Lengthen the array for every element, matched or not
if ( seed ) {
unmatched.push( elem );
}
}
}
 
// `i` is now the count of elements visited above, and adding it to `matchedCount`
// makes the latter nonnegative.
matchedCount += i;
 
// Apply set filters to unmatched elements
// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
// no element matchers and no seed.
// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
// case, which will result in a "00" `matchedCount` that differs from `i` but is also
// numerically zero.
if ( bySet && i !== matchedCount ) {
j = 0;
while ( (matcher = setMatchers[j++]) ) {
matcher( unmatched, setMatched, context, xml );
}
 
if ( seed ) {
// Reintegrate element matches to eliminate the need for sorting
if ( matchedCount > 0 ) {
while ( i-- ) {
if ( !(unmatched[i] || setMatched[i]) ) {
setMatched[i] = pop.call( results );
}
}
}
 
// Discard index placeholder values to get only actual matches
setMatched = condense( setMatched );
}
 
// Add matches to results
push.apply( results, setMatched );
 
// Seedless set matches succeeding multiple successful matchers stipulate sorting
if ( outermost && !seed && setMatched.length > 0 &&
( matchedCount + setMatchers.length ) > 1 ) {
 
Sizzle.uniqueSort( results );
}
}
 
// Override manipulation of globals by nested matchers
if ( outermost ) {
dirruns = dirrunsUnique;
outermostContext = contextBackup;
}
 
return unmatched;
};
 
return bySet ?
markFunction( superMatcher ) :
superMatcher;
}
 
compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
var i,
setMatchers = [],
elementMatchers = [],
cached = compilerCache[ selector + " " ];
 
if ( !cached ) {
// Generate a function of recursive functions that can be used to check each element
if ( !match ) {
match = tokenize( selector );
}
i = match.length;
while ( i-- ) {
cached = matcherFromTokens( match[i] );
if ( cached[ expando ] ) {
setMatchers.push( cached );
} else {
elementMatchers.push( cached );
}
}
 
// Cache the compiled function
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
 
// Save selector and tokenization
cached.selector = selector;
}
return cached;
};
 
/**
* A low-level selection function that works with Sizzle's compiled
* selector functions
* @param {String|Function} selector A selector or a pre-compiled
* selector function built with Sizzle.compile
* @param {Element} context
* @param {Array} [results]
* @param {Array} [seed] A set of elements to match against
*/
select = Sizzle.select = function( selector, context, results, seed ) {
var i, tokens, token, type, find,
compiled = typeof selector === "function" && selector,
match = !seed && tokenize( (selector = compiled.selector || selector) );
 
results = results || [];
 
// Try to minimize operations if there is only one selector in the list and no seed
// (the latter of which guarantees us context)
if ( match.length === 1 ) {
 
// Reduce context if the leading compound selector is an ID
tokens = match[0] = match[0].slice( 0 );
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
support.getById && context.nodeType === 9 && documentIsHTML &&
Expr.relative[ tokens[1].type ] ) {
 
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
if ( !context ) {
return results;
 
// Precompiled matchers will still verify ancestry, so step up a level
} else if ( compiled ) {
context = context.parentNode;
}
 
selector = selector.slice( tokens.shift().value.length );
}
 
// Fetch a seed set for right-to-left matching
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
while ( i-- ) {
token = tokens[i];
 
// Abort if we hit a combinator
if ( Expr.relative[ (type = token.type) ] ) {
break;
}
if ( (find = Expr.find[ type ]) ) {
// Search, expanding context for leading sibling combinators
if ( (seed = find(
token.matches[0].replace( runescape, funescape ),
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
)) ) {
 
// If seed is empty or no tokens remain, we can return early
tokens.splice( i, 1 );
selector = seed.length && toSelector( tokens );
if ( !selector ) {
push.apply( results, seed );
return results;
}
 
break;
}
}
}
}
 
// Compile and execute a filtering function if one is not provided
// Provide `match` to avoid retokenization if we modified the selector above
( compiled || compile( selector, match ) )(
seed,
context,
!documentIsHTML,
results,
!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
);
return results;
};
 
// One-time assignments
 
// Sort stability
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
 
// Support: Chrome 14-35+
// Always assume duplicates if they aren't passed to the comparison function
support.detectDuplicates = !!hasDuplicate;
 
// Initialize against the default document
setDocument();
 
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
// Detached nodes confoundingly follow *each other*
support.sortDetached = assert(function( div1 ) {
// Should return 1, but returns 4 (following)
return div1.compareDocumentPosition( document.createElement("div") ) & 1;
});
 
// Support: IE<8
// Prevent attribute/property "interpolation"
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !assert(function( div ) {
div.innerHTML = "<a href='#'></a>";
return div.firstChild.getAttribute("href") === "#" ;
}) ) {
addHandle( "type|href|height|width", function( elem, name, isXML ) {
if ( !isXML ) {
return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
}
});
}
 
// Support: IE<9
// Use defaultValue in place of getAttribute("value")
if ( !support.attributes || !assert(function( div ) {
div.innerHTML = "<input/>";
div.firstChild.setAttribute( "value", "" );
return div.firstChild.getAttribute( "value" ) === "";
}) ) {
addHandle( "value", function( elem, name, isXML ) {
if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
return elem.defaultValue;
}
});
}
 
// Support: IE<9
// Use getAttributeNode to fetch booleans when getAttribute lies
if ( !assert(function( div ) {
return div.getAttribute("disabled") == null;
}) ) {
addHandle( booleans, function( elem, name, isXML ) {
var val;
if ( !isXML ) {
return elem[ name ] === true ? name.toLowerCase() :
(val = elem.getAttributeNode( name )) && val.specified ?
val.value :
null;
}
});
}
 
return Sizzle;
 
})( window );
 
 
 
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;
 
 
 
var dir = function( elem, dir, until ) {
var matched = [],
truncate = until !== undefined;
 
while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
if ( elem.nodeType === 1 ) {
if ( truncate && jQuery( elem ).is( until ) ) {
break;
}
matched.push( elem );
}
}
return matched;
};
 
 
var siblings = function( n, elem ) {
var matched = [];
 
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType === 1 && n !== elem ) {
matched.push( n );
}
}
 
return matched;
};
 
 
var rneedsContext = jQuery.expr.match.needsContext;
 
var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );
 
 
 
var risSimple = /^.[^:#\[\.,]*$/;
 
// Implement the identical functionality for filter and not
function winnow( elements, qualifier, not ) {
if ( jQuery.isFunction( qualifier ) ) {
return jQuery.grep( elements, function( elem, i ) {
/* jshint -W018 */
return !!qualifier.call( elem, i, elem ) !== not;
} );
 
}
 
if ( qualifier.nodeType ) {
return jQuery.grep( elements, function( elem ) {
return ( elem === qualifier ) !== not;
} );
 
}
 
if ( typeof qualifier === "string" ) {
if ( risSimple.test( qualifier ) ) {
return jQuery.filter( qualifier, elements, not );
}
 
qualifier = jQuery.filter( qualifier, elements );
}
 
return jQuery.grep( elements, function( elem ) {
return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not;
} );
}
 
jQuery.filter = function( expr, elems, not ) {
var elem = elems[ 0 ];
 
if ( not ) {
expr = ":not(" + expr + ")";
}
 
return elems.length === 1 && elem.nodeType === 1 ?
jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
return elem.nodeType === 1;
} ) );
};
 
jQuery.fn.extend( {
find: function( selector ) {
var i,
ret = [],
self = this,
len = self.length;
 
if ( typeof selector !== "string" ) {
return this.pushStack( jQuery( selector ).filter( function() {
for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( self[ i ], this ) ) {
return true;
}
}
} ) );
}
 
for ( i = 0; i < len; i++ ) {
jQuery.find( selector, self[ i ], ret );
}
 
// Needed because $( selector, context ) becomes $( context ).find( selector )
ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
ret.selector = this.selector ? this.selector + " " + selector : selector;
return ret;
},
filter: function( selector ) {
return this.pushStack( winnow( this, selector || [], false ) );
},
not: function( selector ) {
return this.pushStack( winnow( this, selector || [], true ) );
},
is: function( selector ) {
return !!winnow(
this,
 
// If this is a positional/relative selector, check membership in the returned set
// so $("p:first").is("p:last") won't return true for a doc with two "p".
typeof selector === "string" && rneedsContext.test( selector ) ?
jQuery( selector ) :
selector || [],
false
).length;
}
} );
 
 
// Initialize a jQuery object
 
 
// A central reference to the root jQuery(document)
var rootjQuery,
 
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
 
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
 
// HANDLE: $(""), $(null), $(undefined), $(false)
if ( !selector ) {
return this;
}
 
// init accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery;
 
// Handle HTML strings
if ( typeof selector === "string" ) {
if ( selector.charAt( 0 ) === "<" &&
selector.charAt( selector.length - 1 ) === ">" &&
selector.length >= 3 ) {
 
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
 
} else {
match = rquickExpr.exec( selector );
}
 
// Match html or make sure no context is specified for #id
if ( match && ( match[ 1 ] || !context ) ) {
 
// HANDLE: $(html) -> $(array)
if ( match[ 1 ] ) {
context = context instanceof jQuery ? context[ 0 ] : context;
 
// scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge( this, jQuery.parseHTML(
match[ 1 ],
context && context.nodeType ? context.ownerDocument || context : document,
true
) );
 
// HANDLE: $(html, props)
if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
for ( match in context ) {
 
// Properties of context are called as methods if possible
if ( jQuery.isFunction( this[ match ] ) ) {
this[ match ]( context[ match ] );
 
// ...and otherwise set as attributes
} else {
this.attr( match, context[ match ] );
}
}
}
 
return this;
 
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[ 2 ] );
 
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
 
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[ 2 ] ) {
return rootjQuery.find( selector );
}
 
// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[ 0 ] = elem;
}
 
this.context = document;
this.selector = selector;
return this;
}
 
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || root ).find( selector );
 
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}
 
// HANDLE: $(DOMElement)
} else if ( selector.nodeType ) {
this.context = this[ 0 ] = selector;
this.length = 1;
return this;
 
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return typeof root.ready !== "undefined" ?
root.ready( selector ) :
 
// Execute immediately if ready is not present
selector( jQuery );
}
 
if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
 
return jQuery.makeArray( selector, this );
};
 
// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;
 
// Initialize central reference
rootjQuery = jQuery( document );
 
 
var rparentsprev = /^(?:parents|prev(?:Until|All))/,
 
// methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
children: true,
contents: true,
next: true,
prev: true
};
 
jQuery.fn.extend( {
has: function( target ) {
var i,
targets = jQuery( target, this ),
len = targets.length;
 
return this.filter( function() {
for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( this, targets[ i ] ) ) {
return true;
}
}
} );
},
 
closest: function( selectors, context ) {
var cur,
i = 0,
l = this.length,
matched = [],
pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
jQuery( selectors, context || this.context ) :
0;
 
for ( ; i < l; i++ ) {
for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
 
// Always skip document fragments
if ( cur.nodeType < 11 && ( pos ?
pos.index( cur ) > -1 :
 
// Don't pass non-elements to Sizzle
cur.nodeType === 1 &&
jQuery.find.matchesSelector( cur, selectors ) ) ) {
 
matched.push( cur );
break;
}
}
}
 
return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
},
 
// Determine the position of an element within
// the matched set of elements
index: function( elem ) {
 
// No argument, return index in parent
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
 
// index in selector
if ( typeof elem === "string" ) {
return jQuery.inArray( this[ 0 ], jQuery( elem ) );
}
 
// Locate the position of the desired element
return jQuery.inArray(
 
// If it receives a jQuery object, the first element is used
elem.jquery ? elem[ 0 ] : elem, this );
},
 
add: function( selector, context ) {
return this.pushStack(
jQuery.uniqueSort(
jQuery.merge( this.get(), jQuery( selector, context ) )
)
);
},
 
addBack: function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter( selector )
);
}
} );
 
function sibling( cur, dir ) {
do {
cur = cur[ dir ];
} while ( cur && cur.nodeType !== 1 );
 
return cur;
}
 
jQuery.each( {
parent: function( elem ) {
var parent = elem.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
},
parents: function( elem ) {
return dir( elem, "parentNode" );
},
parentsUntil: function( elem, i, until ) {
return dir( elem, "parentNode", until );
},
next: function( elem ) {
return sibling( elem, "nextSibling" );
},
prev: function( elem ) {
return sibling( elem, "previousSibling" );
},
nextAll: function( elem ) {
return dir( elem, "nextSibling" );
},
prevAll: function( elem ) {
return dir( elem, "previousSibling" );
},
nextUntil: function( elem, i, until ) {
return dir( elem, "nextSibling", until );
},
prevUntil: function( elem, i, until ) {
return dir( elem, "previousSibling", until );
},
siblings: function( elem ) {
return siblings( ( elem.parentNode || {} ).firstChild, elem );
},
children: function( elem ) {
return siblings( elem.firstChild );
},
contents: function( elem ) {
return jQuery.nodeName( elem, "iframe" ) ?
elem.contentDocument || elem.contentWindow.document :
jQuery.merge( [], elem.childNodes );
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
var ret = jQuery.map( this, fn, until );
 
if ( name.slice( -5 ) !== "Until" ) {
selector = until;
}
 
if ( selector && typeof selector === "string" ) {
ret = jQuery.filter( selector, ret );
}
 
if ( this.length > 1 ) {
 
// Remove duplicates
if ( !guaranteedUnique[ name ] ) {
ret = jQuery.uniqueSort( ret );
}
 
// Reverse order for parents* and prev-derivatives
if ( rparentsprev.test( name ) ) {
ret = ret.reverse();
}
}
 
return this.pushStack( ret );
};
} );
var rnotwhite = ( /\S+/g );
 
 
 
// Convert String-formatted options into Object-formatted ones
function createOptions( options ) {
var object = {};
jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
object[ flag ] = true;
} );
return object;
}
 
/*
* Create a callback list using the following parameters:
*
* options: an optional list of space-separated options that will change how
* the callback list behaves or a more traditional option object
*
* By default a callback list will act like an event callback list and can be
* "fired" multiple times.
*
* Possible options:
*
* once: will ensure the callback list can only be fired once (like a Deferred)
*
* memory: will keep track of previous values and will call any callback added
* after the list has been fired right away with the latest "memorized"
* values (like a Deferred)
*
* unique: will ensure a callback can only be added once (no duplicate in the list)
*
* stopOnFalse: interrupt callings when a callback returns false
*
*/
jQuery.Callbacks = function( options ) {
 
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
createOptions( options ) :
jQuery.extend( {}, options );
 
var // Flag to know if list is currently firing
firing,
 
// Last fire value for non-forgettable lists
memory,
 
// Flag to know if list was already fired
fired,
 
// Flag to prevent firing
locked,
 
// Actual callback list
list = [],
 
// Queue of execution data for repeatable lists
queue = [],
 
// Index of currently firing callback (modified by add/remove as needed)
firingIndex = -1,
 
// Fire callbacks
fire = function() {
 
// Enforce single-firing
locked = options.once;
 
// Execute callbacks for all pending executions,
// respecting firingIndex overrides and runtime changes
fired = firing = true;
for ( ; queue.length; firingIndex = -1 ) {
memory = queue.shift();
while ( ++firingIndex < list.length ) {
 
// Run callback and check for early termination
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
options.stopOnFalse ) {
 
// Jump to end and forget the data so .add doesn't re-fire
firingIndex = list.length;
memory = false;
}
}
}
 
// Forget the data if we're done with it
if ( !options.memory ) {
memory = false;
}
 
firing = false;
 
// Clean up if we're done firing for good
if ( locked ) {
 
// Keep an empty list if we have data for future add calls
if ( memory ) {
list = [];
 
// Otherwise, this object is spent
} else {
list = "";
}
}
},
 
// Actual Callbacks object
self = {
 
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
 
// If we have memory from a past run, we should fire after adding
if ( memory && !firing ) {
firingIndex = list.length - 1;
queue.push( memory );
}
 
( function add( args ) {
jQuery.each( args, function( _, arg ) {
if ( jQuery.isFunction( arg ) ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
 
// Inspect recursively
add( arg );
}
} );
} )( arguments );
 
if ( memory && !firing ) {
fire();
}
}
return this;
},
 
// Remove a callback from the list
remove: function() {
jQuery.each( arguments, function( _, arg ) {
var index;
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
 
// Handle firing indexes
if ( index <= firingIndex ) {
firingIndex--;
}
}
} );
return this;
},
 
// Check if a given callback is in the list.
// If no argument is given, return whether or not list has callbacks attached.
has: function( fn ) {
return fn ?
jQuery.inArray( fn, list ) > -1 :
list.length > 0;
},
 
// Remove all callbacks from the list
empty: function() {
if ( list ) {
list = [];
}
return this;
},
 
// Disable .fire and .add
// Abort any current/pending executions
// Clear all callbacks and values
disable: function() {
locked = queue = [];
list = memory = "";
return this;
},
disabled: function() {
return !list;
},
 
// Disable .fire
// Also disable .add unless we have memory (since it would have no effect)
// Abort any pending executions
lock: function() {
locked = true;
if ( !memory ) {
self.disable();
}
return this;
},
locked: function() {
return !!locked;
},
 
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
if ( !locked ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
queue.push( args );
if ( !firing ) {
fire();
}
}
return this;
},
 
// Call all the callbacks with the given arguments
fire: function() {
self.fireWith( this, arguments );
return this;
},
 
// To know if the callbacks have already been called at least once
fired: function() {
return !!fired;
}
};
 
return self;
};
 
 
jQuery.extend( {
 
Deferred: function( func ) {
var tuples = [
 
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ],
[ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ],
[ "notify", "progress", jQuery.Callbacks( "memory" ) ]
],
state = "pending",
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred( function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
 
// deferred[ done | fail | progress ] for forwarding actions to newDefer
deferred[ tuple[ 1 ] ]( function() {
var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.progress( newDefer.notify )
.done( newDefer.resolve )
.fail( newDefer.reject );
} else {
newDefer[ tuple[ 0 ] + "With" ](
this === promise ? newDefer.promise() : this,
fn ? [ returned ] : arguments
);
}
} );
} );
fns = null;
} ).promise();
},
 
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
 
// Keep pipe for back-compat
promise.pipe = promise.then;
 
// Add list-specific methods
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],
stateString = tuple[ 3 ];
 
// promise[ done | fail | progress ] = list.add
promise[ tuple[ 1 ] ] = list.add;
 
// Handle state
if ( stateString ) {
list.add( function() {
 
// state = [ resolved | rejected ]
state = stateString;
 
// [ reject_list | resolve_list ].disable; progress_list.lock
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}
 
// deferred[ resolve | reject | notify ]
deferred[ tuple[ 0 ] ] = function() {
deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments );
return this;
};
deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
} );
 
// Make the deferred a promise
promise.promise( deferred );
 
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
 
// All done!
return deferred;
},
 
// Deferred helper
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = slice.call( arguments ),
length = resolveValues.length,
 
// the count of uncompleted subordinates
remaining = length !== 1 ||
( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
 
// the master Deferred.
// If resolveValues consist of only a single Deferred, just use that.
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
 
// Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
return function( value ) {
contexts[ i ] = this;
values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
if ( values === progressValues ) {
deferred.notifyWith( contexts, values );
 
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
},
 
progressValues, progressContexts, resolveContexts;
 
// add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
resolveValues[ i ].promise()
.progress( updateFunc( i, progressContexts, progressValues ) )
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject );
} else {
--remaining;
}
}
}
 
// if we're not waiting on anything, resolve the master
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
 
return deferred.promise();
}
} );
 
 
// The deferred used on DOM ready
var readyList;
 
jQuery.fn.ready = function( fn ) {
 
// Add the callback
jQuery.ready.promise().done( fn );
 
return this;
};
 
jQuery.extend( {
 
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
 
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
 
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
jQuery.readyWait++;
} else {
jQuery.ready( true );
}
},
 
// Handle when the DOM is ready
ready: function( wait ) {
 
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
 
// Remember that the DOM is ready
jQuery.isReady = true;
 
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
 
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
 
// Trigger any bound ready events
if ( jQuery.fn.triggerHandler ) {
jQuery( document ).triggerHandler( "ready" );
jQuery( document ).off( "ready" );
}
}
} );
 
/**
* Clean-up method for dom ready events
*/
function detach() {
if ( document.addEventListener ) {
document.removeEventListener( "DOMContentLoaded", completed, false );
window.removeEventListener( "load", completed, false );
 
} else {
document.detachEvent( "onreadystatechange", completed );
window.detachEvent( "onload", completed );
}
}
 
/**
* The ready event handler and self cleanup method
*/
function completed() {
 
// readyState === "complete" is good enough for us to call the dom ready in oldIE
if ( document.addEventListener ||
window.event.type === "load" ||
document.readyState === "complete" ) {
 
detach();
jQuery.ready();
}
}
 
jQuery.ready.promise = function( obj ) {
if ( !readyList ) {
readyList = jQuery.Deferred();
 
// Catch cases where $(document).ready() is called
// after the browser event has already occurred.
// Support: IE6-10
// Older IE sometimes signals "interactive" too soon
if ( document.readyState === "complete" ||
( document.readyState !== "loading" && !document.documentElement.doScroll && (/a/[-1]!=='a') ) ) {
 
// Handle it asynchronously to allow scripts the opportunity to delay ready
window.setTimeout( jQuery.ready );
 
// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
 
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", completed, false );
 
// A fallback to window.onload, that will always work
window.addEventListener( "load", completed, false );
 
// If IE event model is used
} else {
 
// Ensure firing before onload, maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", completed );
 
// A fallback to window.onload, that will always work
window.attachEvent( "onload", completed );
 
// If IE and not a frame
// continually check to see if the document is ready
var top = false;
 
try {
top = window.frameElement == null && document.documentElement;
} catch ( e ) {}
 
if ( top && top.doScroll ) {
( function doScrollCheck() {
if ( !jQuery.isReady ) {
 
try {
 
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll( "left" );
} catch ( e ) {
return window.setTimeout( doScrollCheck, 50 );
}
 
// detach all dom ready events
detach();
 
// and execute any waiting functions
jQuery.ready();
}
} )();
}
}
}
return readyList.promise( obj );
};
 
// Kick off the DOM ready check even if the user does not
jQuery.ready.promise();
 
 
 
 
// Support: IE<9
// Iteration over object's inherited properties before its own
var i;
for ( i in jQuery( support ) ) {
break;
}
support.ownFirst = i === "0";
 
// Note: most support tests are defined in their respective modules.
// false until the test is run
support.inlineBlockNeedsLayout = false;
 
// Execute ASAP in case we need to set body.style.zoom
jQuery( function() {
 
// Minified: var a,b,c,d
var val, div, body, container;
 
body = document.getElementsByTagName( "body" )[ 0 ];
if ( !body || !body.style ) {
 
// Return for frameset docs that don't have a body
return;
}
 
// Setup
div = document.createElement( "div" );
container = document.createElement( "div" );
container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
body.appendChild( container ).appendChild( div );
 
if ( typeof div.style.zoom !== "undefined" ) {
 
// Support: IE<8
// Check if natively block-level elements act like inline-block
// elements when setting their display to 'inline' and giving
// them layout
div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
 
support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
if ( val ) {
 
// Prevent IE 6 from affecting layout for positioned elements #11048
// Prevent IE from shrinking the body in IE 7 mode #12869
// Support: IE<8
body.style.zoom = 1;
}
}
 
body.removeChild( container );
} );
 
 
( function() {
var div = document.createElement( "div" );
 
// Support: IE<9
support.deleteExpando = true;
try {
delete div.test;
} catch ( e ) {
support.deleteExpando = false;
}
 
// Null elements to avoid leaks in IE.
div = null;
} )();
var acceptData = function( elem ) {
var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ],
nodeType = +elem.nodeType || 1;
 
// Do not set data on non-element DOM nodes because it will not be cleared (#8335).
return nodeType !== 1 && nodeType !== 9 ?
false :
 
// Nodes accept data unless otherwise specified; rejection can be conditional
!noData || noData !== true && elem.getAttribute( "classid" ) === noData;
};
 
 
 
 
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
rmultiDash = /([A-Z])/g;
 
function dataAttr( elem, key, data ) {
 
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && elem.nodeType === 1 ) {
 
var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
 
data = elem.getAttribute( name );
 
if ( typeof data === "string" ) {
try {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
 
// Only convert to a number if it doesn't change the string
+data + "" === data ? +data :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
data;
} catch ( e ) {}
 
// Make sure we set the data so it isn't changed later
jQuery.data( elem, key, data );
 
} else {
data = undefined;
}
}
 
return data;
}
 
// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
var name;
for ( name in obj ) {
 
// if the public data object is empty, the private is still empty
if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) {
continue;
}
if ( name !== "toJSON" ) {
return false;
}
}
 
return true;
}
 
function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
if ( !acceptData( elem ) ) {
return;
}
 
var ret, thisCache,
internalKey = jQuery.expando,
 
// We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
isNode = elem.nodeType,
 
// Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
cache = isNode ? jQuery.cache : elem,
 
// Only defining an ID for JS objects if its cache already exists allows
// the code to shortcut on the same path as a DOM node with no cache
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
 
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) &&
data === undefined && typeof name === "string" ) {
return;
}
 
if ( !id ) {
 
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
} else {
id = internalKey;
}
}
 
if ( !cache[ id ] ) {
 
// Avoid exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
}
 
// An object can be passed to jQuery.data instead of a key/value pair; this gets
// shallow copied over onto the existing cache
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
 
thisCache = cache[ id ];
 
// jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
// data.
if ( !pvt ) {
if ( !thisCache.data ) {
thisCache.data = {};
}
 
thisCache = thisCache.data;
}
 
if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}
 
// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
if ( typeof name === "string" ) {
 
// First Try to find as-is property data
ret = thisCache[ name ];
 
// Test for null|undefined property data
if ( ret == null ) {
 
// Try to find the camelCased property
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else {
ret = thisCache;
}
 
return ret;
}
 
function internalRemoveData( elem, name, pvt ) {
if ( !acceptData( elem ) ) {
return;
}
 
var thisCache, i,
isNode = elem.nodeType,
 
// See jQuery.data for more information
cache = isNode ? jQuery.cache : elem,
id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
 
// If there is already no cache entry for this object, there is no
// purpose in continuing
if ( !cache[ id ] ) {
return;
}
 
if ( name ) {
 
thisCache = pvt ? cache[ id ] : cache[ id ].data;
 
if ( thisCache ) {
 
// Support array or space separated string names for data keys
if ( !jQuery.isArray( name ) ) {
 
// try the string as a key before any manipulation
if ( name in thisCache ) {
name = [ name ];
} else {
 
// split the camel cased version by spaces unless a key with the spaces exists
name = jQuery.camelCase( name );
if ( name in thisCache ) {
name = [ name ];
} else {
name = name.split( " " );
}
}
} else {
 
// If "name" is an array of keys...
// When data is initially created, via ("key", "val") signature,
// keys will be converted to camelCase.
// Since there is no way to tell _how_ a key was added, remove
// both plain key and camelCase key. #12786
// This will only penalize the array argument path.
name = name.concat( jQuery.map( name, jQuery.camelCase ) );
}
 
i = name.length;
while ( i-- ) {
delete thisCache[ name[ i ] ];
}
 
// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) {
return;
}
}
}
 
// See jQuery.data for more information
if ( !pvt ) {
delete cache[ id ].data;
 
// Don't destroy the parent cache unless the internal data object
// had been the only thing left in it
if ( !isEmptyDataObject( cache[ id ] ) ) {
return;
}
}
 
// Destroy the cache
if ( isNode ) {
jQuery.cleanData( [ elem ], true );
 
// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
/* jshint eqeqeq: false */
} else if ( support.deleteExpando || cache != cache.window ) {
/* jshint eqeqeq: true */
delete cache[ id ];
 
// When all else fails, undefined
} else {
cache[ id ] = undefined;
}
}
 
jQuery.extend( {
cache: {},
 
// The following elements (space-suffixed to avoid Object.prototype collisions)
// throw uncatchable exceptions if you attempt to set expando properties
noData: {
"applet ": true,
"embed ": true,
 
// ...but Flash objects (which have this classid) *can* handle expandos
"object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
},
 
hasData: function( elem ) {
elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ];
return !!elem && !isEmptyDataObject( elem );
},
 
data: function( elem, name, data ) {
return internalData( elem, name, data );
},
 
removeData: function( elem, name ) {
return internalRemoveData( elem, name );
},
 
// For internal use only.
_data: function( elem, name, data ) {
return internalData( elem, name, data, true );
},
 
_removeData: function( elem, name ) {
return internalRemoveData( elem, name, true );
}
} );
 
jQuery.fn.extend( {
data: function( key, value ) {
var i, name, data,
elem = this[ 0 ],
attrs = elem && elem.attributes;
 
// Special expections of .data basically thwart jQuery.access,
// so implement the relevant behavior ourselves
 
// Gets all values
if ( key === undefined ) {
if ( this.length ) {
data = jQuery.data( elem );
 
if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
i = attrs.length;
while ( i-- ) {
 
// Support: IE11+
// The attrs elements can be null (#14894)
if ( attrs[ i ] ) {
name = attrs[ i ].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = jQuery.camelCase( name.slice( 5 ) );
dataAttr( elem, name, data[ name ] );
}
}
}
jQuery._data( elem, "parsedAttrs", true );
}
}
 
return data;
}
 
// Sets multiple values
if ( typeof key === "object" ) {
return this.each( function() {
jQuery.data( this, key );
} );
}
 
return arguments.length > 1 ?
 
// Sets one value
this.each( function() {
jQuery.data( this, key, value );
} ) :
 
// Gets one value
// Try to fetch any internally stored data first
elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
},
 
removeData: function( key ) {
return this.each( function() {
jQuery.removeData( this, key );
} );
}
} );
 
 
jQuery.extend( {
queue: function( elem, type, data ) {
var queue;
 
if ( elem ) {
type = ( type || "fx" ) + "queue";
queue = jQuery._data( elem, type );
 
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !queue || jQuery.isArray( data ) ) {
queue = jQuery._data( elem, type, jQuery.makeArray( data ) );
} else {
queue.push( data );
}
}
return queue || [];
}
},
 
dequeue: function( elem, type ) {
type = type || "fx";
 
var queue = jQuery.queue( elem, type ),
startLength = queue.length,
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
next = function() {
jQuery.dequeue( elem, type );
};
 
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
startLength--;
}
 
if ( fn ) {
 
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
queue.unshift( "inprogress" );
}
 
// clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next, hooks );
}
 
if ( !startLength && hooks ) {
hooks.empty.fire();
}
},
 
// not intended for public consumption - generates a queueHooks object,
// or returns the current one
_queueHooks: function( elem, type ) {
var key = type + "queueHooks";
return jQuery._data( elem, key ) || jQuery._data( elem, key, {
empty: jQuery.Callbacks( "once memory" ).add( function() {
jQuery._removeData( elem, type + "queue" );
jQuery._removeData( elem, key );
} )
} );
}
} );
 
jQuery.fn.extend( {
queue: function( type, data ) {
var setter = 2;
 
if ( typeof type !== "string" ) {
data = type;
type = "fx";
setter--;
}
 
if ( arguments.length < setter ) {
return jQuery.queue( this[ 0 ], type );
}
 
return data === undefined ?
this :
this.each( function() {
var queue = jQuery.queue( this, type, data );
 
// ensure a hooks for this queue
jQuery._queueHooks( this, type );
 
if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
} );
},
dequeue: function( type ) {
return this.each( function() {
jQuery.dequeue( this, type );
} );
},
clearQueue: function( type ) {
return this.queue( type || "fx", [] );
},
 
// Get a promise resolved when queues of a certain type
// are emptied (fx is the type by default)
promise: function( type, obj ) {
var tmp,
count = 1,
defer = jQuery.Deferred(),
elements = this,
i = this.length,
resolve = function() {
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
};
 
if ( typeof type !== "string" ) {
obj = type;
type = undefined;
}
type = type || "fx";
 
while ( i-- ) {
tmp = jQuery._data( elements[ i ], type + "queueHooks" );
if ( tmp && tmp.empty ) {
count++;
tmp.empty.add( resolve );
}
}
resolve();
return defer.promise( obj );
}
} );
 
 
( function() {
var shrinkWrapBlocksVal;
 
support.shrinkWrapBlocks = function() {
if ( shrinkWrapBlocksVal != null ) {
return shrinkWrapBlocksVal;
}
 
// Will be changed later if needed.
shrinkWrapBlocksVal = false;
 
// Minified: var b,c,d
var div, body, container;
 
body = document.getElementsByTagName( "body" )[ 0 ];
if ( !body || !body.style ) {
 
// Test fired too early or in an unsupported environment, exit.
return;
}
 
// Setup
div = document.createElement( "div" );
container = document.createElement( "div" );
container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
body.appendChild( container ).appendChild( div );
 
// Support: IE6
// Check if elements with layout shrink-wrap their children
if ( typeof div.style.zoom !== "undefined" ) {
 
// Reset CSS: box-sizing; display; margin; border
div.style.cssText =
 
// Support: Firefox<29, Android 2.3
// Vendor-prefix box-sizing
"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
"box-sizing:content-box;display:block;margin:0;border:0;" +
"padding:1px;width:1px;zoom:1";
div.appendChild( document.createElement( "div" ) ).style.width = "5px";
shrinkWrapBlocksVal = div.offsetWidth !== 3;
}
 
body.removeChild( container );
 
return shrinkWrapBlocksVal;
};
 
} )();
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
 
var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
 
 
var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
 
var isHidden = function( elem, el ) {
 
// isHidden might be called from jQuery#filter function;
// in that case, element will be second argument
elem = el || elem;
return jQuery.css( elem, "display" ) === "none" ||
!jQuery.contains( elem.ownerDocument, elem );
};
 
 
 
function adjustCSS( elem, prop, valueParts, tween ) {
var adjusted,
scale = 1,
maxIterations = 20,
currentValue = tween ?
function() { return tween.cur(); } :
function() { return jQuery.css( elem, prop, "" ); },
initial = currentValue(),
unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
 
// Starting value computation is required for potential unit mismatches
initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
rcssNum.exec( jQuery.css( elem, prop ) );
 
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
 
// Trust units reported by jQuery.css
unit = unit || initialInUnit[ 3 ];
 
// Make sure we update the tween properties later on
valueParts = valueParts || [];
 
// Iteratively approximate from a nonzero starting point
initialInUnit = +initial || 1;
 
do {
 
// If previous iteration zeroed out, double until we get *something*.
// Use string for doubling so we don't accidentally see scale as unchanged below
scale = scale || ".5";
 
// Adjust and apply
initialInUnit = initialInUnit / scale;
jQuery.style( elem, prop, initialInUnit + unit );
 
// Update scale, tolerating zero or NaN from tween.cur()
// Break the loop if scale is unchanged or perfect, or if we've just had enough.
} while (
scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
);
}
 
if ( valueParts ) {
initialInUnit = +initialInUnit || +initial || 0;
 
// Apply relative offset (+=/-=) if specified
adjusted = valueParts[ 1 ] ?
initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+valueParts[ 2 ];
if ( tween ) {
tween.unit = unit;
tween.start = initialInUnit;
tween.end = adjusted;
}
}
return adjusted;
}
 
 
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
length = elems.length,
bulk = key == null;
 
// Sets many values
if ( jQuery.type( key ) === "object" ) {
chainable = true;
for ( i in key ) {
access( elems, fn, i, key[ i ], true, emptyGet, raw );
}
 
// Sets one value
} else if ( value !== undefined ) {
chainable = true;
 
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
 
if ( bulk ) {
 
// Bulk operations run against the entire set
if ( raw ) {
fn.call( elems, value );
fn = null;
 
// ...except when executing function values
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
 
if ( fn ) {
for ( ; i < length; i++ ) {
fn(
elems[ i ],
key,
raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) )
);
}
}
}
 
return chainable ?
elems :
 
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[ 0 ], key ) : emptyGet;
};
var rcheckableType = ( /^(?:checkbox|radio)$/i );
 
var rtagName = ( /<([\w:-]+)/ );
 
var rscriptType = ( /^$|\/(?:java|ecma)script/i );
 
var rleadingWhitespace = ( /^\s+/ );
 
var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" +
"details|dialog|figcaption|figure|footer|header|hgroup|main|" +
"mark|meter|nav|output|picture|progress|section|summary|template|time|video";
 
 
 
function createSafeFragment( document ) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment();
 
if ( safeFrag.createElement ) {
while ( list.length ) {
safeFrag.createElement(
list.pop()
);
}
}
return safeFrag;
}
 
 
( function() {
var div = document.createElement( "div" ),
fragment = document.createDocumentFragment(),
input = document.createElement( "input" );
 
// Setup
div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
 
// IE strips leading whitespace when .innerHTML is used
support.leadingWhitespace = div.firstChild.nodeType === 3;
 
// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
support.tbody = !div.getElementsByTagName( "tbody" ).length;
 
// Make sure that link elements get serialized correctly by innerHTML
// This requires a wrapper element in IE
support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
 
// Makes sure cloning an html5 element does not cause problems
// Where outerHTML is undefined, this still works
support.html5Clone =
document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
 
// Check if a disconnected checkbox will retain its checked
// value of true after appended to the DOM (IE6/7)
input.type = "checkbox";
input.checked = true;
fragment.appendChild( input );
support.appendChecked = input.checked;
 
// Make sure textarea (and checkbox) defaultValue is properly cloned
// Support: IE6-IE11+
div.innerHTML = "<textarea>x</textarea>";
support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
 
// #11217 - WebKit loses check when the name is after the checked attribute
fragment.appendChild( div );
 
// Support: Windows Web Apps (WWA)
// `name` and `type` must use .setAttribute for WWA (#14901)
input = document.createElement( "input" );
input.setAttribute( "type", "radio" );
input.setAttribute( "checked", "checked" );
input.setAttribute( "name", "t" );
 
div.appendChild( input );
 
// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
// old WebKit doesn't clone checked state correctly in fragments
support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
 
// Support: IE<9
// Cloned elements keep attachEvent handlers, we use addEventListener on IE9+
support.noCloneEvent = !!div.addEventListener;
 
// Support: IE<9
// Since attributes and properties are the same in IE,
// cleanData must set properties to undefined rather than use removeAttribute
div[ jQuery.expando ] = 1;
support.attributes = !div.getAttribute( jQuery.expando );
} )();
 
 
// We have to close these tags to support XHTML (#13200)
var wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
area: [ 1, "<map>", "</map>" ],
 
// Support: IE8
param: [ 1, "<object>", "</object>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
 
// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
// unless wrapped in a div with non-breaking characters in front of it.
_default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
};
 
// Support: IE8-IE9
wrapMap.optgroup = wrapMap.option;
 
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
 
 
function getAll( context, tag ) {
var elems, elem,
i = 0,
found = typeof context.getElementsByTagName !== "undefined" ?
context.getElementsByTagName( tag || "*" ) :
typeof context.querySelectorAll !== "undefined" ?
context.querySelectorAll( tag || "*" ) :
undefined;
 
if ( !found ) {
for ( found = [], elems = context.childNodes || context;
( elem = elems[ i ] ) != null;
i++
) {
if ( !tag || jQuery.nodeName( elem, tag ) ) {
found.push( elem );
} else {
jQuery.merge( found, getAll( elem, tag ) );
}
}
}
 
return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
jQuery.merge( [ context ], found ) :
found;
}
 
 
// Mark scripts as having already been evaluated
function setGlobalEval( elems, refElements ) {
var elem,
i = 0;
for ( ; ( elem = elems[ i ] ) != null; i++ ) {
jQuery._data(
elem,
"globalEval",
!refElements || jQuery._data( refElements[ i ], "globalEval" )
);
}
}
 
 
var rhtml = /<|&#?\w+;/,
rtbody = /<tbody/i;
 
function fixDefaultChecked( elem ) {
if ( rcheckableType.test( elem.type ) ) {
elem.defaultChecked = elem.checked;
}
}
 
function buildFragment( elems, context, scripts, selection, ignored ) {
var j, elem, contains,
tmp, tag, tbody, wrap,
l = elems.length,
 
// Ensure a safe fragment
safe = createSafeFragment( context ),
 
nodes = [],
i = 0;
 
for ( ; i < l; i++ ) {
elem = elems[ i ];
 
if ( elem || elem === 0 ) {
 
// Add nodes directly
if ( jQuery.type( elem ) === "object" ) {
jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
 
// Convert non-html into a text node
} else if ( !rhtml.test( elem ) ) {
nodes.push( context.createTextNode( elem ) );
 
// Convert html into DOM nodes
} else {
tmp = tmp || safe.appendChild( context.createElement( "div" ) );
 
// Deserialize a standard representation
tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
wrap = wrapMap[ tag ] || wrapMap._default;
 
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
 
// Descend through wrappers to the right content
j = wrap[ 0 ];
while ( j-- ) {
tmp = tmp.lastChild;
}
 
// Manually add leading whitespace removed by IE
if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[ 0 ] ) );
}
 
// Remove IE's autoinserted <tbody> from table fragments
if ( !support.tbody ) {
 
// String was a <table>, *may* have spurious <tbody>
elem = tag === "table" && !rtbody.test( elem ) ?
tmp.firstChild :
 
// String was a bare <thead> or <tfoot>
wrap[ 1 ] === "<table>" && !rtbody.test( elem ) ?
tmp :
0;
 
j = elem && elem.childNodes.length;
while ( j-- ) {
if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) &&
!tbody.childNodes.length ) {
 
elem.removeChild( tbody );
}
}
}
 
jQuery.merge( nodes, tmp.childNodes );
 
// Fix #12392 for WebKit and IE > 9
tmp.textContent = "";
 
// Fix #12392 for oldIE
while ( tmp.firstChild ) {
tmp.removeChild( tmp.firstChild );
}
 
// Remember the top-level container for proper cleanup
tmp = safe.lastChild;
}
}
}
 
// Fix #11356: Clear elements from fragment
if ( tmp ) {
safe.removeChild( tmp );
}
 
// Reset defaultChecked for any radios and checkboxes
// about to be appended to the DOM in IE 6/7 (#8060)
if ( !support.appendChecked ) {
jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
}
 
i = 0;
while ( ( elem = nodes[ i++ ] ) ) {
 
// Skip elements already in the context collection (trac-4087)
if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
if ( ignored ) {
ignored.push( elem );
}
 
continue;
}
 
contains = jQuery.contains( elem.ownerDocument, elem );
 
// Append to fragment
tmp = getAll( safe.appendChild( elem ), "script" );
 
// Preserve script evaluation history
if ( contains ) {
setGlobalEval( tmp );
}
 
// Capture executables
if ( scripts ) {
j = 0;
while ( ( elem = tmp[ j++ ] ) ) {
if ( rscriptType.test( elem.type || "" ) ) {
scripts.push( elem );
}
}
}
}
 
tmp = null;
 
return safe;
}
 
 
( function() {
var i, eventName,
div = document.createElement( "div" );
 
// Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events)
for ( i in { submit: true, change: true, focusin: true } ) {
eventName = "on" + i;
 
if ( !( support[ i ] = eventName in window ) ) {
 
// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
div.setAttribute( eventName, "t" );
support[ i ] = div.attributes[ eventName ].expando === false;
}
}
 
// Null elements to avoid leaks in IE.
div = null;
} )();
 
 
var rformElems = /^(?:input|select|textarea)$/i,
rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
 
function returnTrue() {
return true;
}
 
function returnFalse() {
return false;
}
 
// Support: IE9
// See #13393 for more info
function safeActiveElement() {
try {
return document.activeElement;
} catch ( err ) { }
}
 
function on( elem, types, selector, data, fn, one ) {
var origFn, type;
 
// Types can be a map of types/handlers
if ( typeof types === "object" ) {
 
// ( types-Object, selector, data )
if ( typeof selector !== "string" ) {
 
// ( types-Object, data )
data = data || selector;
selector = undefined;
}
for ( type in types ) {
on( elem, type, selector, data, types[ type ], one );
}
return elem;
}
 
if ( data == null && fn == null ) {
 
// ( types, fn )
fn = selector;
data = selector = undefined;
} else if ( fn == null ) {
if ( typeof selector === "string" ) {
 
// ( types, selector, fn )
fn = data;
data = undefined;
} else {
 
// ( types, data, fn )
fn = data;
data = selector;
selector = undefined;
}
}
if ( fn === false ) {
fn = returnFalse;
} else if ( !fn ) {
return elem;
}
 
if ( one === 1 ) {
origFn = fn;
fn = function( event ) {
 
// Can use an empty set, since event contains the info
jQuery().off( event );
return origFn.apply( this, arguments );
};
 
// Use same guid so caller can remove using origFn
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
}
return elem.each( function() {
jQuery.event.add( this, types, fn, data, selector );
} );
}
 
/*
* Helper functions for managing events -- not part of the public interface.
* Props to Dean Edwards' addEvent library for many of the ideas.
*/
jQuery.event = {
 
global: {},
 
add: function( elem, types, handler, data, selector ) {
var tmp, events, t, handleObjIn,
special, eventHandle, handleObj,
handlers, type, namespaces, origType,
elemData = jQuery._data( elem );
 
// Don't attach events to noData or text/comment nodes (but allow plain objects)
if ( !elemData ) {
return;
}
 
// Caller can pass in an object of custom data in lieu of the handler
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
selector = handleObjIn.selector;
}
 
// Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
 
// Init the element's event structure and main handler, if this is the first
if ( !( events = elemData.events ) ) {
events = elemData.events = {};
}
if ( !( eventHandle = elemData.handle ) ) {
eventHandle = elemData.handle = function( e ) {
 
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== "undefined" &&
( !e || jQuery.event.triggered !== e.type ) ?
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
 
// Add elem as a property of the handle fn to prevent a memory leak
// with IE non-native events
eventHandle.elem = elem;
}
 
// Handle multiple events separated by a space
types = ( types || "" ).match( rnotwhite ) || [ "" ];
t = types.length;
while ( t-- ) {
tmp = rtypenamespace.exec( types[ t ] ) || [];
type = origType = tmp[ 1 ];
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
 
// There *must* be a type, no attaching namespace-only handlers
if ( !type ) {
continue;
}
 
// If event changes its type, use the special event handlers for the changed type
special = jQuery.event.special[ type ] || {};
 
// If selector defined, determine special event api type, otherwise given type
type = ( selector ? special.delegateType : special.bindType ) || type;
 
// Update special based on newly reset type
special = jQuery.event.special[ type ] || {};
 
// handleObj is passed to all event handlers
handleObj = jQuery.extend( {
type: type,
origType: origType,
data: data,
handler: handler,
guid: handler.guid,
selector: selector,
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
namespace: namespaces.join( "." )
}, handleObjIn );
 
// Init the event handler queue if we're the first
if ( !( handlers = events[ type ] ) ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0;
 
// Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup ||
special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
 
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
 
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
}
 
if ( special.add ) {
special.add.call( elem, handleObj );
 
if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
}
 
// Add to the element's handler list, delegates in front
if ( selector ) {
handlers.splice( handlers.delegateCount++, 0, handleObj );
} else {
handlers.push( handleObj );
}
 
// Keep track of which events have ever been used, for event optimization
jQuery.event.global[ type ] = true;
}
 
// Nullify elem to prevent memory leaks in IE
elem = null;
},
 
// Detach an event or set of events from an element
remove: function( elem, types, handler, selector, mappedTypes ) {
var j, handleObj, tmp,
origCount, t, events,
special, handlers, type,
namespaces, origType,
elemData = jQuery.hasData( elem ) && jQuery._data( elem );
 
if ( !elemData || !( events = elemData.events ) ) {
return;
}
 
// Once for each type.namespace in types; type may be omitted
types = ( types || "" ).match( rnotwhite ) || [ "" ];
t = types.length;
while ( t-- ) {
tmp = rtypenamespace.exec( types[ t ] ) || [];
type = origType = tmp[ 1 ];
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
 
// Unbind all events (on this namespace, if provided) for the element
if ( !type ) {
for ( type in events ) {
jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
}
continue;
}
 
special = jQuery.event.special[ type ] || {};
type = ( selector ? special.delegateType : special.bindType ) || type;
handlers = events[ type ] || [];
tmp = tmp[ 2 ] &&
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
 
// Remove matching events
origCount = j = handlers.length;
while ( j-- ) {
handleObj = handlers[ j ];
 
if ( ( mappedTypes || origType === handleObj.origType ) &&
( !handler || handler.guid === handleObj.guid ) &&
( !tmp || tmp.test( handleObj.namespace ) ) &&
( !selector || selector === handleObj.selector ||
selector === "**" && handleObj.selector ) ) {
handlers.splice( j, 1 );
 
if ( handleObj.selector ) {
handlers.delegateCount--;
}
if ( special.remove ) {
special.remove.call( elem, handleObj );
}
}
}
 
// Remove generic event handler if we removed something and no more handlers exist
// (avoids potential for endless recursion during removal of special event handlers)
if ( origCount && !handlers.length ) {
if ( !special.teardown ||
special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
 
jQuery.removeEvent( elem, type, elemData.handle );
}
 
delete events[ type ];
}
}
 
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
delete elemData.handle;
 
// removeData also checks for emptiness and clears the expando if empty
// so use it instead of delete
jQuery._removeData( elem, "events" );
}
},
 
trigger: function( event, data, elem, onlyHandlers ) {
var handle, ontype, cur,
bubbleType, special, tmp, i,
eventPath = [ elem || document ],
type = hasOwn.call( event, "type" ) ? event.type : event,
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
 
cur = tmp = elem = elem || document;
 
// Don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
 
// focus/blur morphs to focusin/out; ensure we're not firing them right now
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
return;
}
 
if ( type.indexOf( "." ) > -1 ) {
 
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split( "." );
type = namespaces.shift();
namespaces.sort();
}
ontype = type.indexOf( ":" ) < 0 && "on" + type;
 
// Caller can pass in a jQuery.Event object, Object, or just an event type string
event = event[ jQuery.expando ] ?
event :
new jQuery.Event( type, typeof event === "object" && event );
 
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
event.isTrigger = onlyHandlers ? 2 : 3;
event.namespace = namespaces.join( "." );
event.rnamespace = event.namespace ?
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
null;
 
// Clean up the event in case it is being reused
event.result = undefined;
if ( !event.target ) {
event.target = elem;
}
 
// Clone any incoming data and prepend the event, creating the handler arg list
data = data == null ?
[ event ] :
jQuery.makeArray( data, [ event ] );
 
// Allow special events to draw outside the lines
special = jQuery.event.special[ type ] || {};
if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
return;
}
 
// Determine event propagation path in advance, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
 
bubbleType = special.delegateType || type;
if ( !rfocusMorph.test( bubbleType + type ) ) {
cur = cur.parentNode;
}
for ( ; cur; cur = cur.parentNode ) {
eventPath.push( cur );
tmp = cur;
}
 
// Only add window if we got to document (e.g., not plain obj or detached DOM)
if ( tmp === ( elem.ownerDocument || document ) ) {
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
}
}
 
// Fire handlers on the event path
i = 0;
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
 
event.type = i > 1 ?
bubbleType :
special.bindType || type;
 
// jQuery handler
handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] &&
jQuery._data( cur, "handle" );
 
if ( handle ) {
handle.apply( cur, data );
}
 
// Native handler
handle = ontype && cur[ ontype ];
if ( handle && handle.apply && acceptData( cur ) ) {
event.result = handle.apply( cur, data );
if ( event.result === false ) {
event.preventDefault();
}
}
}
event.type = type;
 
// If nobody prevented the default action, do it now
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
 
if (
( !special._default ||
special._default.apply( eventPath.pop(), data ) === false
) && acceptData( elem )
) {
 
// Call a native DOM method on the target with the same name name as the event.
// Can't use an .isFunction() check here because IE6/7 fails that test.
// Don't do default actions on window, that's where global variables be (#6170)
if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
 
// Don't re-trigger an onFOO event when we call its FOO() method
tmp = elem[ ontype ];
 
if ( tmp ) {
elem[ ontype ] = null;
}
 
// Prevent re-triggering of the same event, since we already bubbled it above
jQuery.event.triggered = type;
try {
elem[ type ]();
} catch ( e ) {
 
// IE<9 dies on focus/blur to hidden element (#1486,#12518)
// only reproducible on winXP IE8 native, not IE9 in IE8 mode
}
jQuery.event.triggered = undefined;
 
if ( tmp ) {
elem[ ontype ] = tmp;
}
}
}
}
 
return event.result;
},
 
dispatch: function( event ) {
 
// Make a writable jQuery.Event from the native event object
event = jQuery.event.fix( event );
 
var i, j, ret, matched, handleObj,
handlerQueue = [],
args = slice.call( arguments ),
handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
special = jQuery.event.special[ event.type ] || {};
 
// Use the fix-ed jQuery.Event rather than the (read-only) native event
args[ 0 ] = event;
event.delegateTarget = this;
 
// Call the preDispatch hook for the mapped type, and let it bail if desired
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
return;
}
 
// Determine handlers
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
 
// Run delegates first; they may want to stop propagation beneath us
i = 0;
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
event.currentTarget = matched.elem;
 
j = 0;
while ( ( handleObj = matched.handlers[ j++ ] ) &&
!event.isImmediatePropagationStopped() ) {
 
// Triggered event must either 1) have no namespace, or 2) have namespace(s)
// a subset or equal to those in the bound event (both can have no namespace).
if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
 
event.handleObj = handleObj;
event.data = handleObj.data;
 
ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
handleObj.handler ).apply( matched.elem, args );
 
if ( ret !== undefined ) {
if ( ( event.result = ret ) === false ) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
}
 
// Call the postDispatch hook for the mapped type
if ( special.postDispatch ) {
special.postDispatch.call( this, event );
}
 
return event.result;
},
 
handlers: function( event, handlers ) {
var i, matches, sel, handleObj,
handlerQueue = [],
delegateCount = handlers.delegateCount,
cur = event.target;
 
// Support (at least): Chrome, IE9
// Find delegate handlers
// Black-hole SVG <use> instance trees (#13180)
//
// Support: Firefox<=42+
// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
if ( delegateCount && cur.nodeType &&
( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
 
/* jshint eqeqeq: false */
for ( ; cur != this; cur = cur.parentNode || this ) {
/* jshint eqeqeq: true */
 
// Don't check non-elements (#13208)
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
matches = [];
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
 
// Don't conflict with Object.prototype properties (#13203)
sel = handleObj.selector + " ";
 
if ( matches[ sel ] === undefined ) {
matches[ sel ] = handleObj.needsContext ?
jQuery( sel, this ).index( cur ) > -1 :
jQuery.find( sel, this, null, [ cur ] ).length;
}
if ( matches[ sel ] ) {
matches.push( handleObj );
}
}
if ( matches.length ) {
handlerQueue.push( { elem: cur, handlers: matches } );
}
}
}
}
 
// Add the remaining (directly-bound) handlers
if ( delegateCount < handlers.length ) {
handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );
}
 
return handlerQueue;
},
 
fix: function( event ) {
if ( event[ jQuery.expando ] ) {
return event;
}
 
// Create a writable copy of the event object and normalize some properties
var i, prop, copy,
type = event.type,
originalEvent = event,
fixHook = this.fixHooks[ type ];
 
if ( !fixHook ) {
this.fixHooks[ type ] = fixHook =
rmouseEvent.test( type ) ? this.mouseHooks :
rkeyEvent.test( type ) ? this.keyHooks :
{};
}
copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
 
event = new jQuery.Event( originalEvent );
 
i = copy.length;
while ( i-- ) {
prop = copy[ i ];
event[ prop ] = originalEvent[ prop ];
}
 
// Support: IE<9
// Fix target property (#1925)
if ( !event.target ) {
event.target = originalEvent.srcElement || document;
}
 
// Support: Safari 6-8+
// Target should not be a text node (#504, #13143)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
 
// Support: IE<9
// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
event.metaKey = !!event.metaKey;
 
return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
},
 
// Includes some event props shared by KeyEvent and MouseEvent
props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " +
"metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ),
 
fixHooks: {},
 
keyHooks: {
props: "char charCode key keyCode".split( " " ),
filter: function( event, original ) {
 
// Add which for key events
if ( event.which == null ) {
event.which = original.charCode != null ? original.charCode : original.keyCode;
}
 
return event;
}
},
 
mouseHooks: {
props: ( "button buttons clientX clientY fromElement offsetX offsetY " +
"pageX pageY screenX screenY toElement" ).split( " " ),
filter: function( event, original ) {
var body, eventDoc, doc,
button = original.button,
fromElement = original.fromElement;
 
// Calculate pageX/Y if missing and clientX/Y available
if ( event.pageX == null && original.clientX != null ) {
eventDoc = event.target.ownerDocument || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
 
event.pageX = original.clientX +
( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
( doc && doc.clientLeft || body && body.clientLeft || 0 );
event.pageY = original.clientY +
( doc && doc.scrollTop || body && body.scrollTop || 0 ) -
( doc && doc.clientTop || body && body.clientTop || 0 );
}
 
// Add relatedTarget, if necessary
if ( !event.relatedTarget && fromElement ) {
event.relatedTarget = fromElement === event.target ?
original.toElement :
fromElement;
}
 
// Add which for click: 1 === left; 2 === middle; 3 === right
// Note: button is not normalized, so don't use it
if ( !event.which && button !== undefined ) {
event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
}
 
return event;
}
},
 
special: {
load: {
 
// Prevent triggered image.load events from bubbling to window.load
noBubble: true
},
focus: {
 
// Fire native event if possible so blur/focus sequence is correct
trigger: function() {
if ( this !== safeActiveElement() && this.focus ) {
try {
this.focus();
return false;
} catch ( e ) {
 
// Support: IE<9
// If we error on focus to hidden element (#1486, #12518),
// let .trigger() run the handlers
}
}
},
delegateType: "focusin"
},
blur: {
trigger: function() {
if ( this === safeActiveElement() && this.blur ) {
this.blur();
return false;
}
},
delegateType: "focusout"
},
click: {
 
// For checkbox, fire native event so checked state will be right
trigger: function() {
if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
this.click();
return false;
}
},
 
// For cross-browser consistency, don't fire native .click() on links
_default: function( event ) {
return jQuery.nodeName( event.target, "a" );
}
},
 
beforeunload: {
postDispatch: function( event ) {
 
// Support: Firefox 20+
// Firefox doesn't alert if the returnValue field is not set.
if ( event.result !== undefined && event.originalEvent ) {
event.originalEvent.returnValue = event.result;
}
}
}
},
 
// Piggyback on a donor event to simulate a different one
simulate: function( type, elem, event ) {
var e = jQuery.extend(
new jQuery.Event(),
event,
{
type: type,
isSimulated: true
 
// Previously, `originalEvent: {}` was set here, so stopPropagation call
// would not be triggered on donor event, since in our own
// jQuery.event.stopPropagation function we had a check for existence of
// originalEvent.stopPropagation method, so, consequently it would be a noop.
//
// Guard for simulated events was moved to jQuery.event.stopPropagation function
// since `originalEvent` should point to the original event for the
// constancy with other events and for more focused logic
}
);
 
jQuery.event.trigger( e, null, elem );
 
if ( e.isDefaultPrevented() ) {
event.preventDefault();
}
}
};
 
jQuery.removeEvent = document.removeEventListener ?
function( elem, type, handle ) {
 
// This "if" is needed for plain objects
if ( elem.removeEventListener ) {
elem.removeEventListener( type, handle, false );
}
} :
function( elem, type, handle ) {
var name = "on" + type;
 
if ( elem.detachEvent ) {
 
// #8545, #7054, preventing memory leaks for custom events in IE6-8
// detachEvent needed property on element, by name of that event,
// to properly expose it to GC
if ( typeof elem[ name ] === "undefined" ) {
elem[ name ] = null;
}
 
elem.detachEvent( name, handle );
}
};
 
jQuery.Event = function( src, props ) {
 
// Allow instantiation without the 'new' keyword
if ( !( this instanceof jQuery.Event ) ) {
return new jQuery.Event( src, props );
}
 
// Event object
if ( src && src.type ) {
this.originalEvent = src;
this.type = src.type;
 
// Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value.
this.isDefaultPrevented = src.defaultPrevented ||
src.defaultPrevented === undefined &&
 
// Support: IE < 9, Android < 4.0
src.returnValue === false ?
returnTrue :
returnFalse;
 
// Event type
} else {
this.type = src;
}
 
// Put explicitly provided properties onto the event object
if ( props ) {
jQuery.extend( this, props );
}
 
// Create a timestamp if incoming event doesn't have one
this.timeStamp = src && src.timeStamp || jQuery.now();
 
// Mark it as fixed
this[ jQuery.expando ] = true;
};
 
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
constructor: jQuery.Event,
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse,
 
preventDefault: function() {
var e = this.originalEvent;
 
this.isDefaultPrevented = returnTrue;
if ( !e ) {
return;
}
 
// If preventDefault exists, run it on the original event
if ( e.preventDefault ) {
e.preventDefault();
 
// Support: IE
// Otherwise set the returnValue property of the original event to false
} else {
e.returnValue = false;
}
},
stopPropagation: function() {
var e = this.originalEvent;
 
this.isPropagationStopped = returnTrue;
 
if ( !e || this.isSimulated ) {
return;
}
 
// If stopPropagation exists, run it on the original event
if ( e.stopPropagation ) {
e.stopPropagation();
}
 
// Support: IE
// Set the cancelBubble property of the original event to true
e.cancelBubble = true;
},
stopImmediatePropagation: function() {
var e = this.originalEvent;
 
this.isImmediatePropagationStopped = returnTrue;
 
if ( e && e.stopImmediatePropagation ) {
e.stopImmediatePropagation();
}
 
this.stopPropagation();
}
};
 
// Create mouseenter/leave events using mouseover/out and event-time checks
// so that event delegation works in jQuery.
// Do the same for pointerenter/pointerleave and pointerover/pointerout
//
// Support: Safari 7 only
// Safari sends mouseenter too often; see:
// https://code.google.com/p/chromium/issues/detail?id=470258
// for the description of the bug (it existed in older Chrome versions as well).
jQuery.each( {
mouseenter: "mouseover",
mouseleave: "mouseout",
pointerenter: "pointerover",
pointerleave: "pointerout"
}, function( orig, fix ) {
jQuery.event.special[ orig ] = {
delegateType: fix,
bindType: fix,
 
handle: function( event ) {
var ret,
target = this,
related = event.relatedTarget,
handleObj = event.handleObj;
 
// For mouseenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
event.type = handleObj.origType;
ret = handleObj.handler.apply( this, arguments );
event.type = fix;
}
return ret;
}
};
} );
 
// IE submit delegation
if ( !support.submit ) {
 
jQuery.event.special.submit = {
setup: function() {
 
// Only need this for delegated form submit events
if ( jQuery.nodeName( this, "form" ) ) {
return false;
}
 
// Lazy-add a submit handler when a descendant form may potentially be submitted
jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
 
// Node name check avoids a VML-related crash in IE (#9807)
var elem = e.target,
form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ?
 
// Support: IE <=8
// We use jQuery.prop instead of elem.form
// to allow fixing the IE8 delegated submit issue (gh-2332)
// by 3rd party polyfills/workarounds.
jQuery.prop( elem, "form" ) :
undefined;
 
if ( form && !jQuery._data( form, "submit" ) ) {
jQuery.event.add( form, "submit._submit", function( event ) {
event._submitBubble = true;
} );
jQuery._data( form, "submit", true );
}
} );
 
// return undefined since we don't need an event listener
},
 
postDispatch: function( event ) {
 
// If form was submitted by the user, bubble the event up the tree
if ( event._submitBubble ) {
delete event._submitBubble;
if ( this.parentNode && !event.isTrigger ) {
jQuery.event.simulate( "submit", this.parentNode, event );
}
}
},
 
teardown: function() {
 
// Only need this for delegated form submit events
if ( jQuery.nodeName( this, "form" ) ) {
return false;
}
 
// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
jQuery.event.remove( this, "._submit" );
}
};
}
 
// IE change delegation and checkbox/radio fix
if ( !support.change ) {
 
jQuery.event.special.change = {
 
setup: function() {
 
if ( rformElems.test( this.nodeName ) ) {
 
// IE doesn't fire change on a check/radio until blur; trigger it on click
// after a propertychange. Eat the blur-change in special.change.handle.
// This still fires onchange a second time for check/radio after blur.
if ( this.type === "checkbox" || this.type === "radio" ) {
jQuery.event.add( this, "propertychange._change", function( event ) {
if ( event.originalEvent.propertyName === "checked" ) {
this._justChanged = true;
}
} );
jQuery.event.add( this, "click._change", function( event ) {
if ( this._justChanged && !event.isTrigger ) {
this._justChanged = false;
}
 
// Allow triggered, simulated change events (#11500)
jQuery.event.simulate( "change", this, event );
} );
}
return false;
}
 
// Delegated event; lazy-add a change handler on descendant inputs
jQuery.event.add( this, "beforeactivate._change", function( e ) {
var elem = e.target;
 
if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "change" ) ) {
jQuery.event.add( elem, "change._change", function( event ) {
if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
jQuery.event.simulate( "change", this.parentNode, event );
}
} );
jQuery._data( elem, "change", true );
}
} );
},
 
handle: function( event ) {
var elem = event.target;
 
// Swallow native change events from checkbox/radio, we already triggered them above
if ( this !== elem || event.isSimulated || event.isTrigger ||
( elem.type !== "radio" && elem.type !== "checkbox" ) ) {
 
return event.handleObj.handler.apply( this, arguments );
}
},
 
teardown: function() {
jQuery.event.remove( this, "._change" );
 
return !rformElems.test( this.nodeName );
}
};
}
 
// Support: Firefox
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
//
// Support: Chrome, Safari
// focus(in | out) events fire after focus & blur events,
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
if ( !support.focusin ) {
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
 
// Attach a single capturing handler on the document while someone wants focusin/focusout
var handler = function( event ) {
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
};
 
jQuery.event.special[ fix ] = {
setup: function() {
var doc = this.ownerDocument || this,
attaches = jQuery._data( doc, fix );
 
if ( !attaches ) {
doc.addEventListener( orig, handler, true );
}
jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
},
teardown: function() {
var doc = this.ownerDocument || this,
attaches = jQuery._data( doc, fix ) - 1;
 
if ( !attaches ) {
doc.removeEventListener( orig, handler, true );
jQuery._removeData( doc, fix );
} else {
jQuery._data( doc, fix, attaches );
}
}
};
} );
}
 
jQuery.fn.extend( {
 
on: function( types, selector, data, fn ) {
return on( this, types, selector, data, fn );
},
one: function( types, selector, data, fn ) {
return on( this, types, selector, data, fn, 1 );
},
off: function( types, selector, fn ) {
var handleObj, type;
if ( types && types.preventDefault && types.handleObj ) {
 
// ( event ) dispatched jQuery.Event
handleObj = types.handleObj;
jQuery( types.delegateTarget ).off(
handleObj.namespace ?
handleObj.origType + "." + handleObj.namespace :
handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if ( typeof types === "object" ) {
 
// ( types-object [, selector] )
for ( type in types ) {
this.off( type, selector, types[ type ] );
}
return this;
}
if ( selector === false || typeof selector === "function" ) {
 
// ( types [, fn] )
fn = selector;
selector = undefined;
}
if ( fn === false ) {
fn = returnFalse;
}
return this.each( function() {
jQuery.event.remove( this, types, fn, selector );
} );
},
 
trigger: function( type, data ) {
return this.each( function() {
jQuery.event.trigger( type, data, this );
} );
},
triggerHandler: function( type, data ) {
var elem = this[ 0 ];
if ( elem ) {
return jQuery.event.trigger( type, data, elem, true );
}
}
} );
 
 
var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
rnoshimcache = new RegExp( "<(?:" + nodeNames + ")[\\s/>]", "i" ),
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,
 
// Support: IE 10-11, Edge 10240+
// In IE/Edge using regex groups here causes severe slowdowns.
// See https://connect.microsoft.com/IE/feedback/details/1736512/
rnoInnerhtml = /<script|<style|<link/i,
 
// checked="checked" or checked
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
rscriptTypeMasked = /^true\/(.*)/,
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
safeFragment = createSafeFragment( document ),
fragmentDiv = safeFragment.appendChild( document.createElement( "div" ) );
 
// Support: IE<8
// Manipulating tables requires a tbody
function manipulationTarget( elem, content ) {
return jQuery.nodeName( elem, "table" ) &&
jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
 
elem.getElementsByTagName( "tbody" )[ 0 ] ||
elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) :
elem;
}
 
// Replace/restore the type attribute of script elements for safe DOM manipulation
function disableScript( elem ) {
elem.type = ( jQuery.find.attr( elem, "type" ) !== null ) + "/" + elem.type;
return elem;
}
function restoreScript( elem ) {
var match = rscriptTypeMasked.exec( elem.type );
if ( match ) {
elem.type = match[ 1 ];
} else {
elem.removeAttribute( "type" );
}
return elem;
}
 
function cloneCopyEvent( src, dest ) {
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
return;
}
 
var type, i, l,
oldData = jQuery._data( src ),
curData = jQuery._data( dest, oldData ),
events = oldData.events;
 
if ( events ) {
delete curData.handle;
curData.events = {};
 
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
jQuery.event.add( dest, type, events[ type ][ i ] );
}
}
}
 
// make the cloned public data object a copy from the original
if ( curData.data ) {
curData.data = jQuery.extend( {}, curData.data );
}
}
 
function fixCloneNodeIssues( src, dest ) {
var nodeName, e, data;
 
// We do not need to do anything for non-Elements
if ( dest.nodeType !== 1 ) {
return;
}
 
nodeName = dest.nodeName.toLowerCase();
 
// IE6-8 copies events bound via attachEvent when using cloneNode.
if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
data = jQuery._data( dest );
 
for ( e in data.events ) {
jQuery.removeEvent( dest, e, data.handle );
}
 
// Event data gets referenced instead of copied if the expando gets copied too
dest.removeAttribute( jQuery.expando );
}
 
// IE blanks contents when cloning scripts, and tries to evaluate newly-set text
if ( nodeName === "script" && dest.text !== src.text ) {
disableScript( dest ).text = src.text;
restoreScript( dest );
 
// IE6-10 improperly clones children of object elements using classid.
// IE10 throws NoModificationAllowedError if parent is null, #12132.
} else if ( nodeName === "object" ) {
if ( dest.parentNode ) {
dest.outerHTML = src.outerHTML;
}
 
// This path appears unavoidable for IE9. When cloning an object
// element in IE9, the outerHTML strategy above is not sufficient.
// If the src has innerHTML and the destination does not,
// copy the src.innerHTML into the dest.innerHTML. #10324
if ( support.html5Clone && ( src.innerHTML && !jQuery.trim( dest.innerHTML ) ) ) {
dest.innerHTML = src.innerHTML;
}
 
} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
 
// IE6-8 fails to persist the checked state of a cloned checkbox
// or radio button. Worse, IE6-7 fail to give the cloned element
// a checked appearance if the defaultChecked value isn't also set
 
dest.defaultChecked = dest.checked = src.checked;
 
// IE6-7 get confused and end up setting the value of a cloned
// checkbox/radio button to an empty string instead of "on"
if ( dest.value !== src.value ) {
dest.value = src.value;
}
 
// IE6-8 fails to return the selected option to the default selected
// state when cloning options
} else if ( nodeName === "option" ) {
dest.defaultSelected = dest.selected = src.defaultSelected;
 
// IE6-8 fails to set the defaultValue to the correct value when
// cloning other types of input fields
} else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue;
}
}
 
function domManip( collection, args, callback, ignored ) {
 
// Flatten any nested arrays
args = concat.apply( [], args );
 
var first, node, hasScripts,
scripts, doc, fragment,
i = 0,
l = collection.length,
iNoClone = l - 1,
value = args[ 0 ],
isFunction = jQuery.isFunction( value );
 
// We can't cloneNode fragments that contain checked, in WebKit
if ( isFunction ||
( l > 1 && typeof value === "string" &&
!support.checkClone && rchecked.test( value ) ) ) {
return collection.each( function( index ) {
var self = collection.eq( index );
if ( isFunction ) {
args[ 0 ] = value.call( this, index, self.html() );
}
domManip( self, args, callback, ignored );
} );
}
 
if ( l ) {
fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
first = fragment.firstChild;
 
if ( fragment.childNodes.length === 1 ) {
fragment = first;
}
 
// Require either new content or an interest in ignored elements to invoke the callback
if ( first || ignored ) {
scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
hasScripts = scripts.length;
 
// Use the original fragment for the last item
// instead of the first because it can end up
// being emptied incorrectly in certain situations (#8070).
for ( ; i < l; i++ ) {
node = fragment;
 
if ( i !== iNoClone ) {
node = jQuery.clone( node, true, true );
 
// Keep references to cloned scripts for later restoration
if ( hasScripts ) {
 
// Support: Android<4.1, PhantomJS<2
// push.apply(_, arraylike) throws on ancient WebKit
jQuery.merge( scripts, getAll( node, "script" ) );
}
}
 
callback.call( collection[ i ], node, i );
}
 
if ( hasScripts ) {
doc = scripts[ scripts.length - 1 ].ownerDocument;
 
// Reenable scripts
jQuery.map( scripts, restoreScript );
 
// Evaluate executable scripts on first document insertion
for ( i = 0; i < hasScripts; i++ ) {
node = scripts[ i ];
if ( rscriptType.test( node.type || "" ) &&
!jQuery._data( node, "globalEval" ) &&
jQuery.contains( doc, node ) ) {
 
if ( node.src ) {
 
// Optional AJAX dependency, but won't run scripts if not present
if ( jQuery._evalUrl ) {
jQuery._evalUrl( node.src );
}
} else {
jQuery.globalEval(
( node.text || node.textContent || node.innerHTML || "" )
.replace( rcleanScript, "" )
);
}
}
}
}
 
// Fix #11809: Avoid leaking memory
fragment = first = null;
}
}
 
return collection;
}
 
function remove( elem, selector, keepData ) {
var node,
elems = selector ? jQuery.filter( selector, elem ) : elem,
i = 0;
 
for ( ; ( node = elems[ i ] ) != null; i++ ) {
 
if ( !keepData && node.nodeType === 1 ) {
jQuery.cleanData( getAll( node ) );
}
 
if ( node.parentNode ) {
if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
setGlobalEval( getAll( node, "script" ) );
}
node.parentNode.removeChild( node );
}
}
 
return elem;
}
 
jQuery.extend( {
htmlPrefilter: function( html ) {
return html.replace( rxhtmlTag, "<$1></$2>" );
},
 
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var destElements, node, clone, i, srcElements,
inPage = jQuery.contains( elem.ownerDocument, elem );
 
if ( support.html5Clone || jQuery.isXMLDoc( elem ) ||
!rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
 
clone = elem.cloneNode( true );
 
// IE<=8 does not properly clone detached, unknown element nodes
} else {
fragmentDiv.innerHTML = elem.outerHTML;
fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
}
 
if ( ( !support.noCloneEvent || !support.noCloneChecked ) &&
( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {
 
// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
destElements = getAll( clone );
srcElements = getAll( elem );
 
// Fix all IE cloning issues
for ( i = 0; ( node = srcElements[ i ] ) != null; ++i ) {
 
// Ensure that the destination node is not null; Fixes #9587
if ( destElements[ i ] ) {
fixCloneNodeIssues( node, destElements[ i ] );
}
}
}
 
// Copy the events from the original to the clone
if ( dataAndEvents ) {
if ( deepDataAndEvents ) {
srcElements = srcElements || getAll( elem );
destElements = destElements || getAll( clone );
 
for ( i = 0; ( node = srcElements[ i ] ) != null; i++ ) {
cloneCopyEvent( node, destElements[ i ] );
}
} else {
cloneCopyEvent( elem, clone );
}
}
 
// Preserve script evaluation history
destElements = getAll( clone, "script" );
if ( destElements.length > 0 ) {
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
}
 
destElements = srcElements = node = null;
 
// Return the cloned set
return clone;
},
 
cleanData: function( elems, /* internal */ forceAcceptData ) {
var elem, type, id, data,
i = 0,
internalKey = jQuery.expando,
cache = jQuery.cache,
attributes = support.attributes,
special = jQuery.event.special;
 
for ( ; ( elem = elems[ i ] ) != null; i++ ) {
if ( forceAcceptData || acceptData( elem ) ) {
 
id = elem[ internalKey ];
data = id && cache[ id ];
 
if ( data ) {
if ( data.events ) {
for ( type in data.events ) {
if ( special[ type ] ) {
jQuery.event.remove( elem, type );
 
// This is a shortcut to avoid jQuery.event.remove's overhead
} else {
jQuery.removeEvent( elem, type, data.handle );
}
}
}
 
// Remove cache only if it was not already removed by jQuery.event.remove
if ( cache[ id ] ) {
 
delete cache[ id ];
 
// Support: IE<9
// IE does not allow us to delete expando properties from nodes
// IE creates expando attributes along with the property
// IE does not have a removeAttribute function on Document nodes
if ( !attributes && typeof elem.removeAttribute !== "undefined" ) {
elem.removeAttribute( internalKey );
 
// Webkit & Blink performance suffers when deleting properties
// from DOM nodes, so set to undefined instead
// https://code.google.com/p/chromium/issues/detail?id=378607
} else {
elem[ internalKey ] = undefined;
}
 
deletedIds.push( id );
}
}
}
}
}
} );
 
jQuery.fn.extend( {
 
// Keep domManip exposed until 3.0 (gh-2225)
domManip: domManip,
 
detach: function( selector ) {
return remove( this, selector, true );
},
 
remove: function( selector ) {
return remove( this, selector );
},
 
text: function( value ) {
return access( this, function( value ) {
return value === undefined ?
jQuery.text( this ) :
this.empty().append(
( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value )
);
}, null, value, arguments.length );
},
 
append: function() {
return domManip( this, arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.appendChild( elem );
}
} );
},
 
prepend: function() {
return domManip( this, arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.insertBefore( elem, target.firstChild );
}
} );
},
 
before: function() {
return domManip( this, arguments, function( elem ) {
if ( this.parentNode ) {
this.parentNode.insertBefore( elem, this );
}
} );
},
 
after: function() {
return domManip( this, arguments, function( elem ) {
if ( this.parentNode ) {
this.parentNode.insertBefore( elem, this.nextSibling );
}
} );
},
 
empty: function() {
var elem,
i = 0;
 
for ( ; ( elem = this[ i ] ) != null; i++ ) {
 
// Remove element nodes and prevent memory leaks
if ( elem.nodeType === 1 ) {
jQuery.cleanData( getAll( elem, false ) );
}
 
// Remove any remaining nodes
while ( elem.firstChild ) {
elem.removeChild( elem.firstChild );
}
 
// If this is a select, ensure that it displays empty (#12336)
// Support: IE<9
if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
elem.options.length = 0;
}
}
 
return this;
},
 
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
 
return this.map( function() {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
} );
},
 
html: function( value ) {
return access( this, function( value ) {
var elem = this[ 0 ] || {},
i = 0,
l = this.length;
 
if ( value === undefined ) {
return elem.nodeType === 1 ?
elem.innerHTML.replace( rinlinejQuery, "" ) :
undefined;
}
 
// See if we can take a shortcut and just use innerHTML
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
( support.htmlSerialize || !rnoshimcache.test( value ) ) &&
( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
 
value = jQuery.htmlPrefilter( value );
 
try {
for ( ; i < l; i++ ) {
 
// Remove element nodes and prevent memory leaks
elem = this[ i ] || {};
if ( elem.nodeType === 1 ) {
jQuery.cleanData( getAll( elem, false ) );
elem.innerHTML = value;
}
}
 
elem = 0;
 
// If using innerHTML throws an exception, use the fallback method
} catch ( e ) {}
}
 
if ( elem ) {
this.empty().append( value );
}
}, null, value, arguments.length );
},
 
replaceWith: function() {
var ignored = [];
 
// Make the changes, replacing each non-ignored context element with the new content
return domManip( this, arguments, function( elem ) {
var parent = this.parentNode;
 
if ( jQuery.inArray( this, ignored ) < 0 ) {
jQuery.cleanData( getAll( this ) );
if ( parent ) {
parent.replaceChild( elem, this );
}
}
 
// Force callback invocation
}, ignored );
}
} );
 
jQuery.each( {
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
insertAfter: "after",
replaceAll: "replaceWith"
}, function( name, original ) {
jQuery.fn[ name ] = function( selector ) {
var elems,
i = 0,
ret = [],
insert = jQuery( selector ),
last = insert.length - 1;
 
for ( ; i <= last; i++ ) {
elems = i === last ? this : this.clone( true );
jQuery( insert[ i ] )[ original ]( elems );
 
// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
push.apply( ret, elems.get() );
}
 
return this.pushStack( ret );
};
} );
 
 
var iframe,
elemdisplay = {
 
// Support: Firefox
// We have to pre-define these values for FF (#10227)
HTML: "block",
BODY: "block"
};
 
/**
* Retrieve the actual display of a element
* @param {String} name nodeName of the element
* @param {Object} doc Document object
*/
 
// Called only from within defaultDisplay
function actualDisplay( name, doc ) {
var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
 
display = jQuery.css( elem[ 0 ], "display" );
 
// We don't have any data stored on the element,
// so use "detach" method as fast way to get rid of the element
elem.detach();
 
return display;
}
 
/**
* Try to determine the default display value of an element
* @param {String} nodeName
*/
function defaultDisplay( nodeName ) {
var doc = document,
display = elemdisplay[ nodeName ];
 
if ( !display ) {
display = actualDisplay( nodeName, doc );
 
// If the simple way fails, read from inside an iframe
if ( display === "none" || !display ) {
 
// Use the already-created iframe if possible
iframe = ( iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" ) )
.appendTo( doc.documentElement );
 
// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
 
// Support: IE
doc.write();
doc.close();
 
display = actualDisplay( nodeName, doc );
iframe.detach();
}
 
// Store the correct default display
elemdisplay[ nodeName ] = display;
}
 
return display;
}
var rmargin = ( /^margin/ );
 
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
 
var swap = function( elem, options, callback, args ) {
var ret, name,
old = {};
 
// Remember the old values, and insert the new ones
for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
 
ret = callback.apply( elem, args || [] );
 
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
 
return ret;
};
 
 
var documentElement = document.documentElement;
 
 
 
( function() {
var pixelPositionVal, pixelMarginRightVal, boxSizingReliableVal,
reliableHiddenOffsetsVal, reliableMarginRightVal, reliableMarginLeftVal,
container = document.createElement( "div" ),
div = document.createElement( "div" );
 
// Finish early in limited (non-browser) environments
if ( !div.style ) {
return;
}
 
div.style.cssText = "float:left;opacity:.5";
 
// Support: IE<9
// Make sure that element opacity exists (as opposed to filter)
support.opacity = div.style.opacity === "0.5";
 
// Verify style float existence
// (IE uses styleFloat instead of cssFloat)
support.cssFloat = !!div.style.cssFloat;
 
div.style.backgroundClip = "content-box";
div.cloneNode( true ).style.backgroundClip = "";
support.clearCloneStyle = div.style.backgroundClip === "content-box";
 
container = document.createElement( "div" );
container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
"padding:0;margin-top:1px;position:absolute";
div.innerHTML = "";
container.appendChild( div );
 
// Support: Firefox<29, Android 2.3
// Vendor-prefix box-sizing
support.boxSizing = div.style.boxSizing === "" || div.style.MozBoxSizing === "" ||
div.style.WebkitBoxSizing === "";
 
jQuery.extend( support, {
reliableHiddenOffsets: function() {
if ( pixelPositionVal == null ) {
computeStyleTests();
}
return reliableHiddenOffsetsVal;
},
 
boxSizingReliable: function() {
 
// We're checking for pixelPositionVal here instead of boxSizingReliableVal
// since that compresses better and they're computed together anyway.
if ( pixelPositionVal == null ) {
computeStyleTests();
}
return boxSizingReliableVal;
},
 
pixelMarginRight: function() {
 
// Support: Android 4.0-4.3
if ( pixelPositionVal == null ) {
computeStyleTests();
}
return pixelMarginRightVal;
},
 
pixelPosition: function() {
if ( pixelPositionVal == null ) {
computeStyleTests();
}
return pixelPositionVal;
},
 
reliableMarginRight: function() {
 
// Support: Android 2.3
if ( pixelPositionVal == null ) {
computeStyleTests();
}
return reliableMarginRightVal;
},
 
reliableMarginLeft: function() {
 
// Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37
if ( pixelPositionVal == null ) {
computeStyleTests();
}
return reliableMarginLeftVal;
}
} );
 
function computeStyleTests() {
var contents, divStyle,
documentElement = document.documentElement;
 
// Setup
documentElement.appendChild( container );
 
div.style.cssText =
 
// Support: Android 2.3
// Vendor-prefix box-sizing
"-webkit-box-sizing:border-box;box-sizing:border-box;" +
"position:relative;display:block;" +
"margin:auto;border:1px;padding:1px;" +
"top:1%;width:50%";
 
// Support: IE<9
// Assume reasonable values in the absence of getComputedStyle
pixelPositionVal = boxSizingReliableVal = reliableMarginLeftVal = false;
pixelMarginRightVal = reliableMarginRightVal = true;
 
// Check for getComputedStyle so that this code is not run in IE<9.
if ( window.getComputedStyle ) {
divStyle = window.getComputedStyle( div, null );
pixelPositionVal = ( divStyle || {} ).top !== "1%";
reliableMarginLeftVal = ( divStyle || {} ).marginLeft === "2px";
boxSizingReliableVal = ( divStyle || { width: "4px" } ).width === "4px";
 
// Support: Android 4.0 - 4.3 only
// Some styles come back with percentage values, even though they shouldn't
div.style.marginRight = "50%";
pixelMarginRightVal = ( divStyle || { marginRight: "4px" } ).marginRight === "4px";
 
// Support: Android 2.3 only
// Div with explicit width and no margin-right incorrectly
// gets computed margin-right based on width of container (#3333)
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
contents = div.appendChild( document.createElement( "div" ) );
 
// Reset CSS: box-sizing; display; margin; border; padding
contents.style.cssText = div.style.cssText =
 
// Support: Android 2.3
// Vendor-prefix box-sizing
"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
contents.style.marginRight = contents.style.width = "0";
div.style.width = "1px";
 
reliableMarginRightVal =
!parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
 
div.removeChild( contents );
}
 
// Support: IE6-8
// First check that getClientRects works as expected
// Check if table cells still have offsetWidth/Height when they are set
// to display:none and there are still other visible table cells in a
// table row; if so, offsetWidth/Height are not reliable for use when
// determining if an element has been hidden directly using
// display:none (it is still safe to use offsets if a parent element is
// hidden; don safety goggles and see bug #4512 for more information).
div.style.display = "none";
reliableHiddenOffsetsVal = !div.getClientRects || (div.getClientRects().length === 0);
if ( reliableHiddenOffsetsVal ) {
div.style.display = "";
div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
div.childNodes[ 0 ].style.borderCollapse = "separate";
contents = div.getElementsByTagName( "td" );
contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
if ( reliableHiddenOffsetsVal ) {
contents[ 0 ].style.display = "";
contents[ 1 ].style.display = "none";
reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
}
}
 
// Teardown
documentElement.removeChild( container );
}
 
} )();
 
 
var getStyles, curCSS,
rposition = /^(top|right|bottom|left)$/;
 
if ( window.getComputedStyle ) {
getStyles = function( elem ) {
 
// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
// IE throws on elements created in popups
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
var view = elem.ownerDocument.defaultView;
 
if ( !view || !view.opener ) {
view = window;
}
 
return view.getComputedStyle( elem, null );
};
 
curCSS = function( elem, name, computed ) {
var width, minWidth, maxWidth, ret,
style = elem.style;
 
computed = computed || getStyles( elem );
 
// getPropertyValue is only needed for .css('filter') in IE9, see #12537
ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
 
// Support: Opera 12.1x only
// Fall back to style even without computed
// computed is undefined for elems on document fragments
if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) {
ret = jQuery.style( elem, name );
}
 
if ( computed ) {
 
// A tribute to the "awesome hack by Dean Edwards"
// Chrome < 17 and Safari 5.0 uses "computed value"
// instead of "used value" for margin-right
// Safari 5.1.7 (at least) returns percentage for a larger set of values,
// but width seems to be reliably pixels
// this is against the CSSOM draft spec:
// http://dev.w3.org/csswg/cssom/#resolved-values
if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {
 
// Remember the original values
width = style.width;
minWidth = style.minWidth;
maxWidth = style.maxWidth;
 
// Put in the new values to get a computed value out
style.minWidth = style.maxWidth = style.width = ret;
ret = computed.width;
 
// Revert the changed values
style.width = width;
style.minWidth = minWidth;
style.maxWidth = maxWidth;
}
}
 
// Support: IE
// IE returns zIndex value as an integer.
return ret === undefined ?
ret :
ret + "";
};
} else if ( documentElement.currentStyle ) {
getStyles = function( elem ) {
return elem.currentStyle;
};
 
curCSS = function( elem, name, computed ) {
var left, rs, rsLeft, ret,
style = elem.style;
 
computed = computed || getStyles( elem );
ret = computed ? computed[ name ] : undefined;
 
// Avoid setting ret to empty string here
// so we don't default to auto
if ( ret == null && style && style[ name ] ) {
ret = style[ name ];
}
 
// From the awesome hack by Dean Edwards
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
 
// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to pixels
// but not position css attributes, as those are
// proportional to the parent element instead
// and we can't measure the parent instead because it
// might trigger a "stacking dolls" problem
if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
 
// Remember the original values
left = style.left;
rs = elem.runtimeStyle;
rsLeft = rs && rs.left;
 
// Put in the new values to get a computed value out
if ( rsLeft ) {
rs.left = elem.currentStyle.left;
}
style.left = name === "fontSize" ? "1em" : ret;
ret = style.pixelLeft + "px";
 
// Revert the changed values
style.left = left;
if ( rsLeft ) {
rs.left = rsLeft;
}
}
 
// Support: IE
// IE returns zIndex value as an integer.
return ret === undefined ?
ret :
ret + "" || "auto";
};
}
 
 
 
 
function addGetHookIf( conditionFn, hookFn ) {
 
// Define the hook, we'll check on the first run if it's really needed.
return {
get: function() {
if ( conditionFn() ) {
 
// Hook not needed (or it's not possible to use it due
// to missing dependency), remove it.
delete this.get;
return;
}
 
// Hook needed; redefine it so that the support test is not executed again.
return ( this.get = hookFn ).apply( this, arguments );
}
};
}
 
 
var
 
ralpha = /alpha\([^)]*\)/i,
ropacity = /opacity\s*=\s*([^)]*)/i,
 
// swappable if display is none or starts with table except
// "table", "table-cell", or "table-caption"
// see here for display values:
// https://developer.mozilla.org/en-US/docs/CSS/display
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
 
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
letterSpacing: "0",
fontWeight: "400"
},
 
cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
emptyStyle = document.createElement( "div" ).style;
 
 
// return a css property mapped to a potentially vendor prefixed property
function vendorPropName( name ) {
 
// shortcut for names that are not vendor prefixed
if ( name in emptyStyle ) {
return name;
}
 
// check for vendor prefixed names
var capName = name.charAt( 0 ).toUpperCase() + name.slice( 1 ),
i = cssPrefixes.length;
 
while ( i-- ) {
name = cssPrefixes[ i ] + capName;
if ( name in emptyStyle ) {
return name;
}
}
}
 
function showHide( elements, show ) {
var display, elem, hidden,
values = [],
index = 0,
length = elements.length;
 
for ( ; index < length; index++ ) {
elem = elements[ index ];
if ( !elem.style ) {
continue;
}
 
values[ index ] = jQuery._data( elem, "olddisplay" );
display = elem.style.display;
if ( show ) {
 
// Reset the inline display of this element to learn if it is
// being hidden by cascaded rules or not
if ( !values[ index ] && display === "none" ) {
elem.style.display = "";
}
 
// Set elements which have been overridden with display: none
// in a stylesheet to whatever the default browser style is
// for such an element
if ( elem.style.display === "" && isHidden( elem ) ) {
values[ index ] =
jQuery._data( elem, "olddisplay", defaultDisplay( elem.nodeName ) );
}
} else {
hidden = isHidden( elem );
 
if ( display && display !== "none" || !hidden ) {
jQuery._data(
elem,
"olddisplay",
hidden ? display : jQuery.css( elem, "display" )
);
}
}
}
 
// Set the display of most of the elements in a second loop
// to avoid the constant reflow
for ( index = 0; index < length; index++ ) {
elem = elements[ index ];
if ( !elem.style ) {
continue;
}
if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
elem.style.display = show ? values[ index ] || "" : "none";
}
}
 
return elements;
}
 
function setPositiveNumber( elem, value, subtract ) {
var matches = rnumsplit.exec( value );
return matches ?
 
// Guard against undefined "subtract", e.g., when used as in cssHooks
Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
value;
}
 
function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
var i = extra === ( isBorderBox ? "border" : "content" ) ?
 
// If we already have the right measurement, avoid augmentation
4 :
 
// Otherwise initialize for horizontal or vertical properties
name === "width" ? 1 : 0,
 
val = 0;
 
for ( ; i < 4; i += 2 ) {
 
// both box models exclude margin, so add it if we want it
if ( extra === "margin" ) {
val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
}
 
if ( isBorderBox ) {
 
// border-box includes padding, so remove it if we want content
if ( extra === "content" ) {
val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
}
 
// at this point, extra isn't border nor margin, so remove border
if ( extra !== "margin" ) {
val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
} else {
 
// at this point, extra isn't content, so add padding
val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
 
// at this point, extra isn't content nor padding, so add border
if ( extra !== "padding" ) {
val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
}
}
 
return val;
}
 
function getWidthOrHeight( elem, name, extra ) {
 
// Start with offset property, which is equivalent to the border-box value
var valueIsBorderBox = true,
val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
styles = getStyles( elem ),
isBorderBox = support.boxSizing &&
jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
 
// some non-html elements return undefined for offsetWidth, so check for null/undefined
// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
if ( val <= 0 || val == null ) {
 
// Fall back to computed then uncomputed css if necessary
val = curCSS( elem, name, styles );
if ( val < 0 || val == null ) {
val = elem.style[ name ];
}
 
// Computed unit is not pixels. Stop here and return.
if ( rnumnonpx.test( val ) ) {
return val;
}
 
// we need the check for style in case a browser which returns unreliable values
// for getComputedStyle silently falls back to the reliable elem.style
valueIsBorderBox = isBorderBox &&
( support.boxSizingReliable() || val === elem.style[ name ] );
 
// Normalize "", auto, and prepare for extra
val = parseFloat( val ) || 0;
}
 
// use the active box-sizing model to add/subtract irrelevant styles
return ( val +
augmentWidthOrHeight(
elem,
name,
extra || ( isBorderBox ? "border" : "content" ),
valueIsBorderBox,
styles
)
) + "px";
}
 
jQuery.extend( {
 
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
cssHooks: {
opacity: {
get: function( elem, computed ) {
if ( computed ) {
 
// We should always get a number back from opacity
var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
}
}
}
},
 
// Don't automatically add "px" to these possibly-unitless properties
cssNumber: {
"animationIterationCount": true,
"columnCount": true,
"fillOpacity": true,
"flexGrow": true,
"flexShrink": true,
"fontWeight": true,
"lineHeight": true,
"opacity": true,
"order": true,
"orphans": true,
"widows": true,
"zIndex": true,
"zoom": true
},
 
// Add in properties whose names you wish to fix before
// setting or getting the value
cssProps: {
 
// normalize float css property
"float": support.cssFloat ? "cssFloat" : "styleFloat"
},
 
// Get and set the style property on a DOM Node
style: function( elem, name, value, extra ) {
 
// Don't set styles on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
return;
}
 
// Make sure that we're working with the right name
var ret, type, hooks,
origName = jQuery.camelCase( name ),
style = elem.style;
 
name = jQuery.cssProps[ origName ] ||
( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
 
// gets hook for the prefixed version
// followed by the unprefixed version
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
 
// Check if we're setting a value
if ( value !== undefined ) {
type = typeof value;
 
// Convert "+=" or "-=" to relative numbers (#7345)
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
value = adjustCSS( elem, name, ret );
 
// Fixes bug #9237
type = "number";
}
 
// Make sure that null and NaN values aren't set. See: #7116
if ( value == null || value !== value ) {
return;
}
 
// If a number was passed in, add the unit (except for certain CSS properties)
if ( type === "number" ) {
value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
}
 
// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
// but it would mean to define eight
// (for every problematic property) identical functions
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
style[ name ] = "inherit";
}
 
// If a hook was provided, use that value, otherwise just set the specified value
if ( !hooks || !( "set" in hooks ) ||
( value = hooks.set( elem, value, extra ) ) !== undefined ) {
 
// Support: IE
// Swallow errors from 'invalid' CSS values (#5509)
try {
style[ name ] = value;
} catch ( e ) {}
}
 
} else {
 
// If a hook was provided get the non-computed value from there
if ( hooks && "get" in hooks &&
( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
 
return ret;
}
 
// Otherwise just get the value from the style object
return style[ name ];
}
},
 
css: function( elem, name, extra, styles ) {
var num, val, hooks,
origName = jQuery.camelCase( name );
 
// Make sure that we're working with the right name
name = jQuery.cssProps[ origName ] ||
( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
 
// gets hook for the prefixed version
// followed by the unprefixed version
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
 
// If a hook was provided get the computed value from there
if ( hooks && "get" in hooks ) {
val = hooks.get( elem, true, extra );
}
 
// Otherwise, if a way to get the computed value exists, use that
if ( val === undefined ) {
val = curCSS( elem, name, styles );
}
 
//convert "normal" to computed value
if ( val === "normal" && name in cssNormalTransform ) {
val = cssNormalTransform[ name ];
}
 
// Return, converting to number if forced or a qualifier was provided and val looks numeric
if ( extra === "" || extra ) {
num = parseFloat( val );
return extra === true || isFinite( num ) ? num || 0 : val;
}
return val;
}
} );
 
jQuery.each( [ "height", "width" ], function( i, name ) {
jQuery.cssHooks[ name ] = {
get: function( elem, computed, extra ) {
if ( computed ) {
 
// certain elements can have dimension info if we invisibly show them
// however, it must have a current display style that would benefit from this
return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
elem.offsetWidth === 0 ?
swap( elem, cssShow, function() {
return getWidthOrHeight( elem, name, extra );
} ) :
getWidthOrHeight( elem, name, extra );
}
},
 
set: function( elem, value, extra ) {
var styles = extra && getStyles( elem );
return setPositiveNumber( elem, value, extra ?
augmentWidthOrHeight(
elem,
name,
extra,
support.boxSizing &&
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
styles
) : 0
);
}
};
} );
 
if ( !support.opacity ) {
jQuery.cssHooks.opacity = {
get: function( elem, computed ) {
 
// IE uses filters for opacity
return ropacity.test( ( computed && elem.currentStyle ?
elem.currentStyle.filter :
elem.style.filter ) || "" ) ?
( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
computed ? "1" : "";
},
 
set: function( elem, value ) {
var style = elem.style,
currentStyle = elem.currentStyle,
opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
filter = currentStyle && currentStyle.filter || style.filter || "";
 
// IE has trouble with opacity if it does not have layout
// Force it by setting the zoom level
style.zoom = 1;
 
// if setting opacity to 1, and no other filters exist -
// attempt to remove filter attribute #6652
// if value === "", then remove inline opacity #12685
if ( ( value >= 1 || value === "" ) &&
jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
style.removeAttribute ) {
 
// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
// if "filter:" is present at all, clearType is disabled, we want to avoid this
// style.removeAttribute is IE Only, but so apparently is this code path...
style.removeAttribute( "filter" );
 
// if there is no filter style applied in a css rule
// or unset inline opacity, we are done
if ( value === "" || currentStyle && !currentStyle.filter ) {
return;
}
}
 
// otherwise, set new filter values
style.filter = ralpha.test( filter ) ?
filter.replace( ralpha, opacity ) :
filter + " " + opacity;
}
};
}
 
jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
function( elem, computed ) {
if ( computed ) {
return swap( elem, { "display": "inline-block" },
curCSS, [ elem, "marginRight" ] );
}
}
);
 
jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
function( elem, computed ) {
if ( computed ) {
return (
parseFloat( curCSS( elem, "marginLeft" ) ) ||
 
// Support: IE<=11+
// Running getBoundingClientRect on a disconnected node in IE throws an error
// Support: IE8 only
// getClientRects() errors on disconnected elems
( jQuery.contains( elem.ownerDocument, elem ) ?
(!elem.getBoundingClientRect?0:(elem.getBoundingClientRect().left -
swap( elem, { marginLeft: 0 }, function() {
return elem.getBoundingClientRect().left;
} ) ) ):
0
)
) + "px";
}
}
);
 
// These hooks are used by animate to expand properties
jQuery.each( {
margin: "",
padding: "",
border: "Width"
}, function( prefix, suffix ) {
jQuery.cssHooks[ prefix + suffix ] = {
expand: function( value ) {
var i = 0,
expanded = {},
 
// assumes a single number if not a string
parts = typeof value === "string" ? value.split( " " ) : [ value ];
 
for ( ; i < 4; i++ ) {
expanded[ prefix + cssExpand[ i ] + suffix ] =
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
}
 
return expanded;
}
};
 
if ( !rmargin.test( prefix ) ) {
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
}
} );
 
jQuery.fn.extend( {
css: function( name, value ) {
return access( this, function( elem, name, value ) {
var styles, len,
map = {},
i = 0;
 
if ( jQuery.isArray( name ) ) {
styles = getStyles( elem );
len = name.length;
 
for ( ; i < len; i++ ) {
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
}
 
return map;
}
 
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
},
show: function() {
return showHide( this, true );
},
hide: function() {
return showHide( this );
},
toggle: function( state ) {
if ( typeof state === "boolean" ) {
return state ? this.show() : this.hide();
}
 
return this.each( function() {
if ( isHidden( this ) ) {
jQuery( this ).show();
} else {
jQuery( this ).hide();
}
} );
}
} );
 
 
function Tween( elem, options, prop, end, easing ) {
return new Tween.prototype.init( elem, options, prop, end, easing );
}
jQuery.Tween = Tween;
 
Tween.prototype = {
constructor: Tween,
init: function( elem, options, prop, end, easing, unit ) {
this.elem = elem;
this.prop = prop;
this.easing = easing || jQuery.easing._default;
this.options = options;
this.start = this.now = this.cur();
this.end = end;
this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
},
cur: function() {
var hooks = Tween.propHooks[ this.prop ];
 
return hooks && hooks.get ?
hooks.get( this ) :
Tween.propHooks._default.get( this );
},
run: function( percent ) {
var eased,
hooks = Tween.propHooks[ this.prop ];
 
if ( this.options.duration ) {
this.pos = eased = jQuery.easing[ this.easing ](
percent, this.options.duration * percent, 0, 1, this.options.duration
);
} else {
this.pos = eased = percent;
}
this.now = ( this.end - this.start ) * eased + this.start;
 
if ( this.options.step ) {
this.options.step.call( this.elem, this.now, this );
}
 
if ( hooks && hooks.set ) {
hooks.set( this );
} else {
Tween.propHooks._default.set( this );
}
return this;
}
};
 
Tween.prototype.init.prototype = Tween.prototype;
 
Tween.propHooks = {
_default: {
get: function( tween ) {
var result;
 
// Use a property on the element directly when it is not a DOM element,
// or when there is no matching style property that exists.
if ( tween.elem.nodeType !== 1 ||
tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
return tween.elem[ tween.prop ];
}
 
// passing an empty string as a 3rd parameter to .css will automatically
// attempt a parseFloat and fallback to a string if the parse fails
// so, simple values such as "10px" are parsed to Float.
// complex values such as "rotate(1rad)" are returned as is.
result = jQuery.css( tween.elem, tween.prop, "" );
 
// Empty strings, null, undefined and "auto" are converted to 0.
return !result || result === "auto" ? 0 : result;
},
set: function( tween ) {
 
// use step hook for back compat - use cssHook if its there - use .style if its
// available and use plain properties where available
if ( jQuery.fx.step[ tween.prop ] ) {
jQuery.fx.step[ tween.prop ]( tween );
} else if ( tween.elem.nodeType === 1 &&
( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
jQuery.cssHooks[ tween.prop ] ) ) {
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
} else {
tween.elem[ tween.prop ] = tween.now;
}
}
}
};
 
// Support: IE <=9
// Panic based approach to setting things on disconnected nodes
 
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
set: function( tween ) {
if ( tween.elem.nodeType && tween.elem.parentNode ) {
tween.elem[ tween.prop ] = tween.now;
}
}
};
 
jQuery.easing = {
linear: function( p ) {
return p;
},
swing: function( p ) {
return 0.5 - Math.cos( p * Math.PI ) / 2;
},
_default: "swing"
};
 
jQuery.fx = Tween.prototype.init;
 
// Back Compat <1.8 extension point
jQuery.fx.step = {};
 
 
 
 
var
fxNow, timerId,
rfxtypes = /^(?:toggle|show|hide)$/,
rrun = /queueHooks$/;
 
// Animations created synchronously will run synchronously
function createFxNow() {
window.setTimeout( function() {
fxNow = undefined;
} );
return ( fxNow = jQuery.now() );
}
 
// Generate parameters to create a standard animation
function genFx( type, includeWidth ) {
var which,
attrs = { height: type },
i = 0;
 
// if we include width, step value is 1 to do all cssExpand values,
// if we don't include width, step value is 2 to skip over Left and Right
includeWidth = includeWidth ? 1 : 0;
for ( ; i < 4 ; i += 2 - includeWidth ) {
which = cssExpand[ i ];
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
}
 
if ( includeWidth ) {
attrs.opacity = attrs.width = type;
}
 
return attrs;
}
 
function createTween( value, prop, animation ) {
var tween,
collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
index = 0,
length = collection.length;
for ( ; index < length; index++ ) {
if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
 
// we're done with this property
return tween;
}
}
}
 
function defaultPrefilter( elem, props, opts ) {
/* jshint validthis: true */
var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
anim = this,
orig = {},
style = elem.style,
hidden = elem.nodeType && isHidden( elem ),
dataShow = jQuery._data( elem, "fxshow" );
 
// handle queue: false promises
if ( !opts.queue ) {
hooks = jQuery._queueHooks( elem, "fx" );
if ( hooks.unqueued == null ) {
hooks.unqueued = 0;
oldfire = hooks.empty.fire;
hooks.empty.fire = function() {
if ( !hooks.unqueued ) {
oldfire();
}
};
}
hooks.unqueued++;
 
anim.always( function() {
 
// doing this makes sure that the complete handler will be called
// before this completes
anim.always( function() {
hooks.unqueued--;
if ( !jQuery.queue( elem, "fx" ).length ) {
hooks.empty.fire();
}
} );
} );
}
 
// height/width overflow pass
if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
 
// Make sure that nothing sneaks out
// Record all 3 overflow attributes because IE does not
// change the overflow attribute when overflowX and
// overflowY are set to the same value
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
 
// Set display property to inline-block for height/width
// animations on inline elements that are having width/height animated
display = jQuery.css( elem, "display" );
 
// Test default display if display is currently "none"
checkDisplay = display === "none" ?
jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
 
if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
 
// inline-level elements accept inline-block;
// block-level elements need to be inline with layout
if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
style.display = "inline-block";
} else {
style.zoom = 1;
}
}
}
 
if ( opts.overflow ) {
style.overflow = "hidden";
if ( !support.shrinkWrapBlocks() ) {
anim.always( function() {
style.overflow = opts.overflow[ 0 ];
style.overflowX = opts.overflow[ 1 ];
style.overflowY = opts.overflow[ 2 ];
} );
}
}
 
// show/hide pass
for ( prop in props ) {
value = props[ prop ];
if ( rfxtypes.exec( value ) ) {
delete props[ prop ];
toggle = toggle || value === "toggle";
if ( value === ( hidden ? "hide" : "show" ) ) {
 
// If there is dataShow left over from a stopped hide or show
// and we are going to proceed with show, we should pretend to be hidden
if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
hidden = true;
} else {
continue;
}
}
orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
 
// Any non-fx value stops us from restoring the original display value
} else {
display = undefined;
}
}
 
if ( !jQuery.isEmptyObject( orig ) ) {
if ( dataShow ) {
if ( "hidden" in dataShow ) {
hidden = dataShow.hidden;
}
} else {
dataShow = jQuery._data( elem, "fxshow", {} );
}
 
// store state if its toggle - enables .stop().toggle() to "reverse"
if ( toggle ) {
dataShow.hidden = !hidden;
}
if ( hidden ) {
jQuery( elem ).show();
} else {
anim.done( function() {
jQuery( elem ).hide();
} );
}
anim.done( function() {
var prop;
jQuery._removeData( elem, "fxshow" );
for ( prop in orig ) {
jQuery.style( elem, prop, orig[ prop ] );
}
} );
for ( prop in orig ) {
tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
 
if ( !( prop in dataShow ) ) {
dataShow[ prop ] = tween.start;
if ( hidden ) {
tween.end = tween.start;
tween.start = prop === "width" || prop === "height" ? 1 : 0;
}
}
}
 
// If this is a noop like .hide().hide(), restore an overwritten display value
} else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : display ) === "inline" ) {
style.display = display;
}
}
 
function propFilter( props, specialEasing ) {
var index, name, easing, value, hooks;
 
// camelCase, specialEasing and expand cssHook pass
for ( index in props ) {
name = jQuery.camelCase( index );
easing = specialEasing[ name ];
value = props[ index ];
if ( jQuery.isArray( value ) ) {
easing = value[ 1 ];
value = props[ index ] = value[ 0 ];
}
 
if ( index !== name ) {
props[ name ] = value;
delete props[ index ];
}
 
hooks = jQuery.cssHooks[ name ];
if ( hooks && "expand" in hooks ) {
value = hooks.expand( value );
delete props[ name ];
 
// not quite $.extend, this wont overwrite keys already present.
// also - reusing 'index' from above because we have the correct "name"
for ( index in value ) {
if ( !( index in props ) ) {
props[ index ] = value[ index ];
specialEasing[ index ] = easing;
}
}
} else {
specialEasing[ name ] = easing;
}
}
}
 
function Animation( elem, properties, options ) {
var result,
stopped,
index = 0,
length = Animation.prefilters.length,
deferred = jQuery.Deferred().always( function() {
 
// don't match elem in the :animated selector
delete tick.elem;
} ),
tick = function() {
if ( stopped ) {
return false;
}
var currentTime = fxNow || createFxNow(),
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
 
// Support: Android 2.3
// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
temp = remaining / animation.duration || 0,
percent = 1 - temp,
index = 0,
length = animation.tweens.length;
 
for ( ; index < length ; index++ ) {
animation.tweens[ index ].run( percent );
}
 
deferred.notifyWith( elem, [ animation, percent, remaining ] );
 
if ( percent < 1 && length ) {
return remaining;
} else {
deferred.resolveWith( elem, [ animation ] );
return false;
}
},
animation = deferred.promise( {
elem: elem,
props: jQuery.extend( {}, properties ),
opts: jQuery.extend( true, {
specialEasing: {},
easing: jQuery.easing._default
}, options ),
originalProperties: properties,
originalOptions: options,
startTime: fxNow || createFxNow(),
duration: options.duration,
tweens: [],
createTween: function( prop, end ) {
var tween = jQuery.Tween( elem, animation.opts, prop, end,
animation.opts.specialEasing[ prop ] || animation.opts.easing );
animation.tweens.push( tween );
return tween;
},
stop: function( gotoEnd ) {
var index = 0,
 
// if we are going to the end, we want to run all the tweens
// otherwise we skip this part
length = gotoEnd ? animation.tweens.length : 0;
if ( stopped ) {
return this;
}
stopped = true;
for ( ; index < length ; index++ ) {
animation.tweens[ index ].run( 1 );
}
 
// resolve when we played the last frame
// otherwise, reject
if ( gotoEnd ) {
deferred.notifyWith( elem, [ animation, 1, 0 ] );
deferred.resolveWith( elem, [ animation, gotoEnd ] );
} else {
deferred.rejectWith( elem, [ animation, gotoEnd ] );
}
return this;
}
} ),
props = animation.props;
 
propFilter( props, animation.opts.specialEasing );
 
for ( ; index < length ; index++ ) {
result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
if ( result ) {
if ( jQuery.isFunction( result.stop ) ) {
jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
jQuery.proxy( result.stop, result );
}
return result;
}
}
 
jQuery.map( props, createTween, animation );
 
if ( jQuery.isFunction( animation.opts.start ) ) {
animation.opts.start.call( elem, animation );
}
 
jQuery.fx.timer(
jQuery.extend( tick, {
elem: elem,
anim: animation,
queue: animation.opts.queue
} )
);
 
// attach callbacks from options
return animation.progress( animation.opts.progress )
.done( animation.opts.done, animation.opts.complete )
.fail( animation.opts.fail )
.always( animation.opts.always );
}
 
jQuery.Animation = jQuery.extend( Animation, {
 
tweeners: {
"*": [ function( prop, value ) {
var tween = this.createTween( prop, value );
adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
return tween;
} ]
},
 
tweener: function( props, callback ) {
if ( jQuery.isFunction( props ) ) {
callback = props;
props = [ "*" ];
} else {
props = props.match( rnotwhite );
}
 
var prop,
index = 0,
length = props.length;
 
for ( ; index < length ; index++ ) {
prop = props[ index ];
Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
Animation.tweeners[ prop ].unshift( callback );
}
},
 
prefilters: [ defaultPrefilter ],
 
prefilter: function( callback, prepend ) {
if ( prepend ) {
Animation.prefilters.unshift( callback );
} else {
Animation.prefilters.push( callback );
}
}
} );
 
jQuery.speed = function( speed, easing, fn ) {
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
};
 
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
opt.duration in jQuery.fx.speeds ?
jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
 
// normalize opt.queue - true/undefined/null -> "fx"
if ( opt.queue == null || opt.queue === true ) {
opt.queue = "fx";
}
 
// Queueing
opt.old = opt.complete;
 
opt.complete = function() {
if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this );
}
 
if ( opt.queue ) {
jQuery.dequeue( this, opt.queue );
}
};
 
return opt;
};
 
jQuery.fn.extend( {
fadeTo: function( speed, to, easing, callback ) {
 
// show any hidden elements after setting opacity to 0
return this.filter( isHidden ).css( "opacity", 0 ).show()
 
// animate to the value specified
.end().animate( { opacity: to }, speed, easing, callback );
},
animate: function( prop, speed, easing, callback ) {
var empty = jQuery.isEmptyObject( prop ),
optall = jQuery.speed( speed, easing, callback ),
doAnimation = function() {
 
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
 
// Empty animations, or finishing resolves immediately
if ( empty || jQuery._data( this, "finish" ) ) {
anim.stop( true );
}
};
doAnimation.finish = doAnimation;
 
return empty || optall.queue === false ?
this.each( doAnimation ) :
this.queue( optall.queue, doAnimation );
},
stop: function( type, clearQueue, gotoEnd ) {
var stopQueue = function( hooks ) {
var stop = hooks.stop;
delete hooks.stop;
stop( gotoEnd );
};
 
if ( typeof type !== "string" ) {
gotoEnd = clearQueue;
clearQueue = type;
type = undefined;
}
if ( clearQueue && type !== false ) {
this.queue( type || "fx", [] );
}
 
return this.each( function() {
var dequeue = true,
index = type != null && type + "queueHooks",
timers = jQuery.timers,
data = jQuery._data( this );
 
if ( index ) {
if ( data[ index ] && data[ index ].stop ) {
stopQueue( data[ index ] );
}
} else {
for ( index in data ) {
if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
stopQueue( data[ index ] );
}
}
}
 
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this &&
( type == null || timers[ index ].queue === type ) ) {
 
timers[ index ].anim.stop( gotoEnd );
dequeue = false;
timers.splice( index, 1 );
}
}
 
// start the next in the queue if the last step wasn't forced
// timers currently will call their complete callbacks, which will dequeue
// but only if they were gotoEnd
if ( dequeue || !gotoEnd ) {
jQuery.dequeue( this, type );
}
} );
},
finish: function( type ) {
if ( type !== false ) {
type = type || "fx";
}
return this.each( function() {
var index,
data = jQuery._data( this ),
queue = data[ type + "queue" ],
hooks = data[ type + "queueHooks" ],
timers = jQuery.timers,
length = queue ? queue.length : 0;
 
// enable finishing flag on private data
data.finish = true;
 
// empty the queue first
jQuery.queue( this, type, [] );
 
if ( hooks && hooks.stop ) {
hooks.stop.call( this, true );
}
 
// look for any active animations, and finish them
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
timers[ index ].anim.stop( true );
timers.splice( index, 1 );
}
}
 
// look for any animations in the old queue and finish them
for ( index = 0; index < length; index++ ) {
if ( queue[ index ] && queue[ index ].finish ) {
queue[ index ].finish.call( this );
}
}
 
// turn off finishing flag
delete data.finish;
} );
}
} );
 
jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = jQuery.fn[ name ];
jQuery.fn[ name ] = function( speed, easing, callback ) {
return speed == null || typeof speed === "boolean" ?
cssFn.apply( this, arguments ) :
this.animate( genFx( name, true ), speed, easing, callback );
};
} );
 
// Generate shortcuts for custom animations
jQuery.each( {
slideDown: genFx( "show" ),
slideUp: genFx( "hide" ),
slideToggle: genFx( "toggle" ),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
jQuery.fn[ name ] = function( speed, easing, callback ) {
return this.animate( props, speed, easing, callback );
};
} );
 
jQuery.timers = [];
jQuery.fx.tick = function() {
var timer,
timers = jQuery.timers,
i = 0;
 
fxNow = jQuery.now();
 
for ( ; i < timers.length; i++ ) {
timer = timers[ i ];
 
// Checks the timer has not already been removed
if ( !timer() && timers[ i ] === timer ) {
timers.splice( i--, 1 );
}
}
 
if ( !timers.length ) {
jQuery.fx.stop();
}
fxNow = undefined;
};
 
jQuery.fx.timer = function( timer ) {
jQuery.timers.push( timer );
if ( timer() ) {
jQuery.fx.start();
} else {
jQuery.timers.pop();
}
};
 
jQuery.fx.interval = 13;
 
jQuery.fx.start = function() {
if ( !timerId ) {
timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
}
};
 
jQuery.fx.stop = function() {
window.clearInterval( timerId );
timerId = null;
};
 
jQuery.fx.speeds = {
slow: 600,
fast: 200,
 
// Default speed
_default: 400
};
 
 
// Based off of the plugin by Clint Helfers, with permission.
// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
jQuery.fn.delay = function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
 
return this.queue( type, function( next, hooks ) {
var timeout = window.setTimeout( next, time );
hooks.stop = function() {
window.clearTimeout( timeout );
};
} );
};
 
 
( function() {
var a,
input = document.createElement( "input" ),
div = document.createElement( "div" ),
select = document.createElement( "select" ),
opt = select.appendChild( document.createElement( "option" ) );
 
// Setup
div = document.createElement( "div" );
div.setAttribute( "className", "t" );
div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
a = div.getElementsByTagName( "a" )[ 0 ];
 
// Support: Windows Web Apps (WWA)
// `type` must use .setAttribute for WWA (#14901)
input.setAttribute( "type", "checkbox" );
div.appendChild( input );
 
a = div.getElementsByTagName( "a" )[ 0 ];
 
// First batch of tests.
a.style.cssText = "top:1px";
 
// Test setAttribute on camelCase class.
// If it works, we need attrFixes when doing get/setAttribute (ie6/7)
support.getSetAttribute = div.className !== "t";
 
// Get the style information from getAttribute
// (IE uses .cssText instead)
support.style = /top/.test( a.getAttribute( "style" ) );
 
// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
support.hrefNormalized = a.getAttribute( "href" ) === "/a";
 
// Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
support.checkOn = !!input.value;
 
// Make sure that a selected-by-default option has a working selected property.
// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
support.optSelected = opt.selected;
 
// Tests for enctype support on a form (#6743)
support.enctype = !!document.createElement( "form" ).enctype;
 
// Make sure that the options inside disabled selects aren't marked as disabled
// (WebKit marks them as disabled)
select.disabled = true;
support.optDisabled = !opt.disabled;
 
// Support: IE8 only
// Check if we can trust getAttribute("value")
input = document.createElement( "input" );
input.setAttribute( "value", "" );
support.input = input.getAttribute( "value" ) === "";
 
// Check if an input maintains its value after becoming a radio
input.value = "t";
input.setAttribute( "type", "radio" );
support.radioValue = input.value === "t";
} )();
 
 
var rreturn = /\r/g,
rspaces = /[\x20\t\r\n\f]+/g;
 
jQuery.fn.extend( {
val: function( value ) {
var hooks, ret, isFunction,
elem = this[ 0 ];
 
if ( !arguments.length ) {
if ( elem ) {
hooks = jQuery.valHooks[ elem.type ] ||
jQuery.valHooks[ elem.nodeName.toLowerCase() ];
 
if (
hooks &&
"get" in hooks &&
( ret = hooks.get( elem, "value" ) ) !== undefined
) {
return ret;
}
 
ret = elem.value;
 
return typeof ret === "string" ?
 
// handle most common string cases
ret.replace( rreturn, "" ) :
 
// handle cases where value is null/undef or number
ret == null ? "" : ret;
}
 
return;
}
 
isFunction = jQuery.isFunction( value );
 
return this.each( function( i ) {
var val;
 
if ( this.nodeType !== 1 ) {
return;
}
 
if ( isFunction ) {
val = value.call( this, i, jQuery( this ).val() );
} else {
val = value;
}
 
// Treat null/undefined as ""; convert numbers to string
if ( val == null ) {
val = "";
} else if ( typeof val === "number" ) {
val += "";
} else if ( jQuery.isArray( val ) ) {
val = jQuery.map( val, function( value ) {
return value == null ? "" : value + "";
} );
}
 
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
 
// If set returns undefined, fall back to normal setting
if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
} );
}
} );
 
jQuery.extend( {
valHooks: {
option: {
get: function( elem ) {
var val = jQuery.find.attr( elem, "value" );
return val != null ?
val :
 
// Support: IE10-11+
// option.text throws exceptions (#14686, #14858)
// Strip and collapse whitespace
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " );
}
},
select: {
get: function( elem ) {
var value, option,
options = elem.options,
index = elem.selectedIndex,
one = elem.type === "select-one" || index < 0,
values = one ? null : [],
max = one ? index + 1 : options.length,
i = index < 0 ?
max :
one ? index : 0;
 
// Loop through all the selected options
for ( ; i < max; i++ ) {
option = options[ i ];
 
// oldIE doesn't update selected after form reset (#2551)
if ( ( option.selected || i === index ) &&
 
// Don't return options that are disabled or in a disabled optgroup
( support.optDisabled ?
!option.disabled :
option.getAttribute( "disabled" ) === null ) &&
( !option.parentNode.disabled ||
!jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
 
// Get the specific value for the option
value = jQuery( option ).val();
 
// We don't need an array for one selects
if ( one ) {
return value;
}
 
// Multi-Selects return an array
values.push( value );
}
}
 
return values;
},
 
set: function( elem, value ) {
var optionSet, option,
options = elem.options,
values = jQuery.makeArray( value ),
i = options.length;
 
while ( i-- ) {
option = options[ i ];
 
if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 ) {
 
// Support: IE6
// When new option element is added to select box we need to
// force reflow of newly added node in order to workaround delay
// of initialization properties
try {
option.selected = optionSet = true;
 
} catch ( _ ) {
 
// Will be executed only in IE6
option.scrollHeight;
}
 
} else {
option.selected = false;
}
}
 
// Force browsers to behave consistently when non-matching value is set
if ( !optionSet ) {
elem.selectedIndex = -1;
}
 
return options;
}
}
}
} );
 
// Radios and checkboxes getter/setter
jQuery.each( [ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = {
set: function( elem, value ) {
if ( jQuery.isArray( value ) ) {
return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
}
}
};
if ( !support.checkOn ) {
jQuery.valHooks[ this ].get = function( elem ) {
return elem.getAttribute( "value" ) === null ? "on" : elem.value;
};
}
} );
 
 
 
 
var nodeHook, boolHook,
attrHandle = jQuery.expr.attrHandle,
ruseDefault = /^(?:checked|selected)$/i,
getSetAttribute = support.getSetAttribute,
getSetInput = support.input;
 
jQuery.fn.extend( {
attr: function( name, value ) {
return access( this, jQuery.attr, name, value, arguments.length > 1 );
},
 
removeAttr: function( name ) {
return this.each( function() {
jQuery.removeAttr( this, name );
} );
}
} );
 
jQuery.extend( {
attr: function( elem, name, value ) {
var ret, hooks,
nType = elem.nodeType;
 
// Don't get/set attributes on text, comment and attribute nodes
if ( nType === 3 || nType === 8 || nType === 2 ) {
return;
}
 
// Fallback to prop when attributes are not supported
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
 
// All attributes are lowercase
// Grab necessary hook if one is defined
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
name = name.toLowerCase();
hooks = jQuery.attrHooks[ name ] ||
( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
}
 
if ( value !== undefined ) {
if ( value === null ) {
jQuery.removeAttr( elem, name );
return;
}
 
if ( hooks && "set" in hooks &&
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
return ret;
}
 
elem.setAttribute( name, value + "" );
return value;
}
 
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
return ret;
}
 
ret = jQuery.find.attr( elem, name );
 
// Non-existent attributes return null, we normalize to undefined
return ret == null ? undefined : ret;
},
 
attrHooks: {
type: {
set: function( elem, value ) {
if ( !support.radioValue && value === "radio" &&
jQuery.nodeName( elem, "input" ) ) {
 
// Setting the type on a radio button after the value resets the value in IE8-9
// Reset value to default in case type is set after value during creation
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
elem.value = val;
}
return value;
}
}
}
},
 
removeAttr: function( elem, value ) {
var name, propName,
i = 0,
attrNames = value && value.match( rnotwhite );
 
if ( attrNames && elem.nodeType === 1 ) {
while ( ( name = attrNames[ i++ ] ) ) {
propName = jQuery.propFix[ name ] || name;
 
// Boolean attributes get special treatment (#10870)
if ( jQuery.expr.match.bool.test( name ) ) {
 
// Set corresponding property to false
if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
elem[ propName ] = false;
 
// Support: IE<9
// Also clear defaultChecked/defaultSelected (if appropriate)
} else {
elem[ jQuery.camelCase( "default-" + name ) ] =
elem[ propName ] = false;
}
 
// See #9699 for explanation of this approach (setting first, then removal)
} else {
jQuery.attr( elem, name, "" );
}
 
elem.removeAttribute( getSetAttribute ? name : propName );
}
}
}
} );
 
// Hooks for boolean attributes
boolHook = {
set: function( elem, value, name ) {
if ( value === false ) {
 
// Remove boolean attributes when set to false
jQuery.removeAttr( elem, name );
} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
 
// IE<8 needs the *property* name
elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
 
} else {
 
// Support: IE<9
// Use defaultChecked and defaultSelected for oldIE
elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
}
return name;
}
};
 
jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
var getter = attrHandle[ name ] || jQuery.find.attr;
 
if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
attrHandle[ name ] = function( elem, name, isXML ) {
var ret, handle;
if ( !isXML ) {
 
// Avoid an infinite loop by temporarily removing this function from the getter
handle = attrHandle[ name ];
attrHandle[ name ] = ret;
ret = getter( elem, name, isXML ) != null ?
name.toLowerCase() :
null;
attrHandle[ name ] = handle;
}
return ret;
};
} else {
attrHandle[ name ] = function( elem, name, isXML ) {
if ( !isXML ) {
return elem[ jQuery.camelCase( "default-" + name ) ] ?
name.toLowerCase() :
null;
}
};
}
} );
 
// fix oldIE attroperties
if ( !getSetInput || !getSetAttribute ) {
jQuery.attrHooks.value = {
set: function( elem, value, name ) {
if ( jQuery.nodeName( elem, "input" ) ) {
 
// Does not return so that setAttribute is also used
elem.defaultValue = value;
} else {
 
// Use nodeHook if defined (#1954); otherwise setAttribute is fine
return nodeHook && nodeHook.set( elem, value, name );
}
}
};
}
 
// IE6/7 do not support getting/setting some attributes with get/setAttribute
if ( !getSetAttribute ) {
 
// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = {
set: function( elem, value, name ) {
 
// Set the existing or create a new attribute node
var ret = elem.getAttributeNode( name );
if ( !ret ) {
elem.setAttributeNode(
( ret = elem.ownerDocument.createAttribute( name ) )
);
}
 
ret.value = value += "";
 
// Break association with cloned elements by also using setAttribute (#9646)
if ( name === "value" || value === elem.getAttribute( name ) ) {
return value;
}
}
};
 
// Some attributes are constructed with empty-string values when not defined
attrHandle.id = attrHandle.name = attrHandle.coords =
function( elem, name, isXML ) {
var ret;
if ( !isXML ) {
return ( ret = elem.getAttributeNode( name ) ) && ret.value !== "" ?
ret.value :
null;
}
};
 
// Fixing value retrieval on a button requires this module
jQuery.valHooks.button = {
get: function( elem, name ) {
var ret = elem.getAttributeNode( name );
if ( ret && ret.specified ) {
return ret.value;
}
},
set: nodeHook.set
};
 
// Set contenteditable to false on removals(#10429)
// Setting to empty string throws an error as an invalid value
jQuery.attrHooks.contenteditable = {
set: function( elem, value, name ) {
nodeHook.set( elem, value === "" ? false : value, name );
}
};
 
// Set width and height to auto instead of 0 on empty string( Bug #8150 )
// This is for removals
jQuery.each( [ "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = {
set: function( elem, value ) {
if ( value === "" ) {
elem.setAttribute( name, "auto" );
return value;
}
}
};
} );
}
 
if ( !support.style ) {
jQuery.attrHooks.style = {
get: function( elem ) {
 
// Return undefined in the case of empty string
// Note: IE uppercases css property names, but if we were to .toLowerCase()
// .cssText, that would destroy case sensitivity in URL's, like in "background"
return elem.style.cssText || undefined;
},
set: function( elem, value ) {
return ( elem.style.cssText = value + "" );
}
};
}
 
 
 
 
var rfocusable = /^(?:input|select|textarea|button|object)$/i,
rclickable = /^(?:a|area)$/i;
 
jQuery.fn.extend( {
prop: function( name, value ) {
return access( this, jQuery.prop, name, value, arguments.length > 1 );
},
 
removeProp: function( name ) {
name = jQuery.propFix[ name ] || name;
return this.each( function() {
 
// try/catch handles cases where IE balks (such as removing a property on window)
try {
this[ name ] = undefined;
delete this[ name ];
} catch ( e ) {}
} );
}
} );
 
jQuery.extend( {
prop: function( elem, name, value ) {
var ret, hooks,
nType = elem.nodeType;
 
// Don't get/set properties on text, comment and attribute nodes
if ( nType === 3 || nType === 8 || nType === 2 ) {
return;
}
 
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
 
// Fix name and attach hooks
name = jQuery.propFix[ name ] || name;
hooks = jQuery.propHooks[ name ];
}
 
if ( value !== undefined ) {
if ( hooks && "set" in hooks &&
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
return ret;
}
 
return ( elem[ name ] = value );
}
 
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
return ret;
}
 
return elem[ name ];
},
 
propHooks: {
tabIndex: {
get: function( elem ) {
 
// elem.tabIndex doesn't always return the
// correct value when it hasn't been explicitly set
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
// Use proper attribute retrieval(#12072)
var tabindex = jQuery.find.attr( elem, "tabindex" );
 
return tabindex ?
parseInt( tabindex, 10 ) :
rfocusable.test( elem.nodeName ) ||
rclickable.test( elem.nodeName ) && elem.href ?
0 :
-1;
}
}
},
 
propFix: {
"for": "htmlFor",
"class": "className"
}
} );
 
// Some attributes require a special call on IE
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !support.hrefNormalized ) {
 
// href/src property should get the full normalized URL (#10299/#12915)
jQuery.each( [ "href", "src" ], function( i, name ) {
jQuery.propHooks[ name ] = {
get: function( elem ) {
return elem.getAttribute( name, 4 );
}
};
} );
}
 
// Support: Safari, IE9+
// Accessing the selectedIndex property
// forces the browser to respect setting selected
// on the option
// The getter ensures a default option is selected
// when in an optgroup
if ( !support.optSelected ) {
jQuery.propHooks.selected = {
get: function( elem ) {
var parent = elem.parentNode;
 
if ( parent ) {
parent.selectedIndex;
 
// Make sure that it also works with optgroups, see #5701
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
return null;
},
set: function( elem ) {
var parent = elem.parentNode;
if ( parent ) {
parent.selectedIndex;
 
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
}
};
}
 
jQuery.each( [
"tabIndex",
"readOnly",
"maxLength",
"cellSpacing",
"cellPadding",
"rowSpan",
"colSpan",
"useMap",
"frameBorder",
"contentEditable"
], function() {
jQuery.propFix[ this.toLowerCase() ] = this;
} );
 
// IE6/7 call enctype encoding
if ( !support.enctype ) {
jQuery.propFix.enctype = "encoding";
}
 
 
 
 
var rclass = /[\t\r\n\f]/g;
 
function getClass( elem ) {
return jQuery.attr( elem, "class" ) || "";
}
 
jQuery.fn.extend( {
addClass: function( value ) {
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
 
if ( jQuery.isFunction( value ) ) {
return this.each( function( j ) {
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
} );
}
 
if ( typeof value === "string" && value ) {
classes = value.match( rnotwhite ) || [];
 
while ( ( elem = this[ i++ ] ) ) {
curValue = getClass( elem );
cur = elem.nodeType === 1 &&
( " " + curValue + " " ).replace( rclass, " " );
 
if ( cur ) {
j = 0;
while ( ( clazz = classes[ j++ ] ) ) {
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
cur += clazz + " ";
}
}
 
// only assign if different to avoid unneeded rendering.
finalValue = jQuery.trim( cur );
if ( curValue !== finalValue ) {
jQuery.attr( elem, "class", finalValue );
}
}
}
}
 
return this;
},
 
removeClass: function( value ) {
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
 
if ( jQuery.isFunction( value ) ) {
return this.each( function( j ) {
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
} );
}
 
if ( !arguments.length ) {
return this.attr( "class", "" );
}
 
if ( typeof value === "string" && value ) {
classes = value.match( rnotwhite ) || [];
 
while ( ( elem = this[ i++ ] ) ) {
curValue = getClass( elem );
 
// This expression is here for better compressibility (see addClass)
cur = elem.nodeType === 1 &&
( " " + curValue + " " ).replace( rclass, " " );
 
if ( cur ) {
j = 0;
while ( ( clazz = classes[ j++ ] ) ) {
 
// Remove *all* instances
while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
cur = cur.replace( " " + clazz + " ", " " );
}
}
 
// Only assign if different to avoid unneeded rendering.
finalValue = jQuery.trim( cur );
if ( curValue !== finalValue ) {
jQuery.attr( elem, "class", finalValue );
}
}
}
}
 
return this;
},
 
toggleClass: function( value, stateVal ) {
var type = typeof value;
 
if ( typeof stateVal === "boolean" && type === "string" ) {
return stateVal ? this.addClass( value ) : this.removeClass( value );
}
 
if ( jQuery.isFunction( value ) ) {
return this.each( function( i ) {
jQuery( this ).toggleClass(
value.call( this, i, getClass( this ), stateVal ),
stateVal
);
} );
}
 
return this.each( function() {
var className, i, self, classNames;
 
if ( type === "string" ) {
 
// Toggle individual class names
i = 0;
self = jQuery( this );
classNames = value.match( rnotwhite ) || [];
 
while ( ( className = classNames[ i++ ] ) ) {
 
// Check each className given, space separated list
if ( self.hasClass( className ) ) {
self.removeClass( className );
} else {
self.addClass( className );
}
}
 
// Toggle whole class name
} else if ( value === undefined || type === "boolean" ) {
className = getClass( this );
if ( className ) {
 
// store className if set
jQuery._data( this, "__className__", className );
}
 
// If the element has a class name or if we're passed "false",
// then remove the whole classname (if there was one, the above saved it).
// Otherwise bring back whatever was previously saved (if anything),
// falling back to the empty string if nothing was stored.
jQuery.attr( this, "class",
className || value === false ?
"" :
jQuery._data( this, "__className__" ) || ""
);
}
} );
},
 
hasClass: function( selector ) {
var className, elem,
i = 0;
 
className = " " + selector + " ";
while ( ( elem = this[ i++ ] ) ) {
if ( elem.nodeType === 1 &&
( " " + getClass( elem ) + " " ).replace( rclass, " " )
.indexOf( className ) > -1
) {
return true;
}
}
 
return false;
}
} );
 
 
 
 
// Return jQuery for attributes-only inclusion
 
 
jQuery.each( ( "blur focus focusin focusout load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error contextmenu" ).split( " " ),
function( i, name ) {
 
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
return arguments.length > 0 ?
this.on( name, null, data, fn ) :
this.trigger( name );
};
} );
 
jQuery.fn.extend( {
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
}
} );
 
 
var location = window.location;
 
var nonce = jQuery.now();
 
var rquery = ( /\?/ );
 
 
 
var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
 
jQuery.parseJSON = function( data ) {
 
// Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
 
// Support: Android 2.3
// Workaround failure to string-cast null input
return window.JSON.parse( data + "" );
}
 
var requireNonComma,
depth = null,
str = jQuery.trim( data + "" );
 
// Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
// after removing valid tokens
return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
 
// Force termination if we see a misplaced comma
if ( requireNonComma && comma ) {
depth = 0;
}
 
// Perform no more replacements after returning to outermost depth
if ( depth === 0 ) {
return token;
}
 
// Commas must not follow "[", "{", or ","
requireNonComma = open || comma;
 
// Determine new depth
// array/object open ("[" or "{"): depth += true - false (increment)
// array/object close ("]" or "}"): depth += false - true (decrement)
// other cases ("," or primitive): depth += true - true (numeric cast)
depth += !close - !open;
 
// Remove this token
return "";
} ) ) ?
( Function( "return " + str ) )() :
jQuery.error( "Invalid JSON: " + data );
};
 
 
// Cross-browser xml parsing
jQuery.parseXML = function( data ) {
var xml, tmp;
if ( !data || typeof data !== "string" ) {
return null;
}
try {
if ( window.DOMParser ) { // Standard
tmp = new window.DOMParser();
xml = tmp.parseFromString( data, "text/xml" );
} else { // IE
xml = new window.ActiveXObject( "Microsoft.XMLDOM" );
xml.async = "false";
xml.loadXML( data );
}
} catch ( e ) {
xml = undefined;
}
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
};
 
 
var
rhash = /#.*$/,
rts = /([?&])_=[^&]*/,
 
// IE leaves an \r character at EOL
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg,
 
// #7653, #8125, #8152: local protocol detection
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
rnoContent = /^(?:GET|HEAD)$/,
rprotocol = /^\/\//,
rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
 
/* Prefilters
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
* 2) These are called:
* - BEFORE asking for a transport
* - AFTER param serialization (s.data is a string if s.processData is true)
* 3) key is the dataType
* 4) the catchall symbol "*" can be used
* 5) execution will start with transport dataType and THEN continue down to "*" if needed
*/
prefilters = {},
 
/* Transports bindings
* 1) key is the dataType
* 2) the catchall symbol "*" can be used
* 3) selection will start with transport dataType and THEN go to "*" if needed
*/
transports = {},
 
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
allTypes = "*/".concat( "*" ),
 
// Document location
ajaxLocation = location.href,
 
// Segment location into parts
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
 
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {
 
// dataTypeExpression is optional and defaults to "*"
return function( dataTypeExpression, func ) {
 
if ( typeof dataTypeExpression !== "string" ) {
func = dataTypeExpression;
dataTypeExpression = "*";
}
 
var dataType,
i = 0,
dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
 
if ( jQuery.isFunction( func ) ) {
 
// For each dataType in the dataTypeExpression
while ( ( dataType = dataTypes[ i++ ] ) ) {
 
// Prepend if requested
if ( dataType.charAt( 0 ) === "+" ) {
dataType = dataType.slice( 1 ) || "*";
( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
 
// Otherwise append
} else {
( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
}
}
}
};
}
 
// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
 
var inspected = {},
seekingTransport = ( structure === transports );
 
function inspect( dataType ) {
var selected;
inspected[ dataType ] = true;
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
if ( typeof dataTypeOrTransport === "string" &&
!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
 
options.dataTypes.unshift( dataTypeOrTransport );
inspect( dataTypeOrTransport );
return false;
} else if ( seekingTransport ) {
return !( selected = dataTypeOrTransport );
}
} );
return selected;
}
 
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}
 
// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend( target, src ) {
var deep, key,
flatOptions = jQuery.ajaxSettings.flatOptions || {};
 
for ( key in src ) {
if ( src[ key ] !== undefined ) {
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
}
}
if ( deep ) {
jQuery.extend( true, target, deep );
}
 
return target;
}
 
/* Handles responses to an ajax request:
* - finds the right dataType (mediates between content-type and expected dataType)
* - returns the corresponding response
*/
function ajaxHandleResponses( s, jqXHR, responses ) {
var firstDataType, ct, finalDataType, type,
contents = s.contents,
dataTypes = s.dataTypes;
 
// Remove auto dataType and get content-type in the process
while ( dataTypes[ 0 ] === "*" ) {
dataTypes.shift();
if ( ct === undefined ) {
ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
}
}
 
// Check if we're dealing with a known content-type
if ( ct ) {
for ( type in contents ) {
if ( contents[ type ] && contents[ type ].test( ct ) ) {
dataTypes.unshift( type );
break;
}
}
}
 
// Check to see if we have a response for the expected dataType
if ( dataTypes[ 0 ] in responses ) {
finalDataType = dataTypes[ 0 ];
} else {
 
// Try convertible dataTypes
for ( type in responses ) {
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
finalDataType = type;
break;
}
if ( !firstDataType ) {
firstDataType = type;
}
}
 
// Or just use first one
finalDataType = finalDataType || firstDataType;
}
 
// If we found a dataType
// We add the dataType to the list if needed
// and return the corresponding response
if ( finalDataType ) {
if ( finalDataType !== dataTypes[ 0 ] ) {
dataTypes.unshift( finalDataType );
}
return responses[ finalDataType ];
}
}
 
/* Chain conversions given the request and the original response
* Also sets the responseXXX fields on the jqXHR instance
*/
function ajaxConvert( s, response, jqXHR, isSuccess ) {
var conv2, current, conv, tmp, prev,
converters = {},
 
// Work with a copy of dataTypes in case we need to modify it for conversion
dataTypes = s.dataTypes.slice();
 
// Create converters map with lowercased keys
if ( dataTypes[ 1 ] ) {
for ( conv in s.converters ) {
converters[ conv.toLowerCase() ] = s.converters[ conv ];
}
}
 
current = dataTypes.shift();
 
// Convert to each sequential dataType
while ( current ) {
 
if ( s.responseFields[ current ] ) {
jqXHR[ s.responseFields[ current ] ] = response;
}
 
// Apply the dataFilter if provided
if ( !prev && isSuccess && s.dataFilter ) {
response = s.dataFilter( response, s.dataType );
}
 
prev = current;
current = dataTypes.shift();
 
if ( current ) {
 
// There's only work to do if current dataType is non-auto
if ( current === "*" ) {
 
current = prev;
 
// Convert response if prev dataType is non-auto and differs from current
} else if ( prev !== "*" && prev !== current ) {
 
// Seek a direct converter
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
 
// If none found, seek a pair
if ( !conv ) {
for ( conv2 in converters ) {
 
// If conv2 outputs current
tmp = conv2.split( " " );
if ( tmp[ 1 ] === current ) {
 
// If prev can be converted to accepted input
conv = converters[ prev + " " + tmp[ 0 ] ] ||
converters[ "* " + tmp[ 0 ] ];
if ( conv ) {
 
// Condense equivalence converters
if ( conv === true ) {
conv = converters[ conv2 ];
 
// Otherwise, insert the intermediate dataType
} else if ( converters[ conv2 ] !== true ) {
current = tmp[ 0 ];
dataTypes.unshift( tmp[ 1 ] );
}
break;
}
}
}
}
 
// Apply converter (if not an equivalence)
if ( conv !== true ) {
 
// Unless errors are allowed to bubble, catch and return them
if ( conv && s[ "throws" ] ) { // jscs:ignore requireDotNotation
response = conv( response );
} else {
try {
response = conv( response );
} catch ( e ) {
return {
state: "parsererror",
error: conv ? e : "No conversion from " + prev + " to " + current
};
}
}
}
}
}
}
 
return { state: "success", data: response };
}
 
jQuery.extend( {
 
// Counter for holding the number of active queries
active: 0,
 
// Last-Modified header cache for next request
lastModified: {},
etag: {},
 
ajaxSettings: {
url: ajaxLocation,
type: "GET",
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
global: true,
processData: true,
async: true,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
/*
timeout: 0,
data: null,
dataType: null,
username: null,
password: null,
cache: null,
throws: false,
traditional: false,
headers: {},
*/
 
accepts: {
"*": allTypes,
text: "text/plain",
html: "text/html",
xml: "application/xml, text/xml",
json: "application/json, text/javascript"
},
 
contents: {
xml: /\bxml\b/,
html: /\bhtml/,
json: /\bjson\b/
},
 
responseFields: {
xml: "responseXML",
text: "responseText",
json: "responseJSON"
},
 
// Data converters
// Keys separate source (or catchall "*") and destination types with a single space
converters: {
 
// Convert anything to text
"* text": String,
 
// Text to html (true = no transformation)
"text html": true,
 
// Evaluate text as a json expression
"text json": jQuery.parseJSON,
 
// Parse text as xml
"text xml": jQuery.parseXML
},
 
// For options that shouldn't be deep extended:
// you can add your own custom options here if
// and when you create one that shouldn't be
// deep extended (see ajaxExtend)
flatOptions: {
url: true,
context: true
}
},
 
// Creates a full fledged settings object into target
// with both ajaxSettings and settings fields.
// If target is omitted, writes into ajaxSettings.
ajaxSetup: function( target, settings ) {
return settings ?
 
// Building a settings object
ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
 
// Extending ajaxSettings
ajaxExtend( jQuery.ajaxSettings, target );
},
 
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
ajaxTransport: addToPrefiltersOrTransports( transports ),
 
// Main method
ajax: function( url, options ) {
 
// If url is an object, simulate pre-1.5 signature
if ( typeof url === "object" ) {
options = url;
url = undefined;
}
 
// Force options to be an object
options = options || {};
 
var
 
// Cross-domain detection vars
parts,
 
// Loop variable
i,
 
// URL without anti-cache param
cacheURL,
 
// Response headers as string
responseHeadersString,
 
// timeout handle
timeoutTimer,
 
// To know if global events are to be dispatched
fireGlobals,
 
transport,
 
// Response headers
responseHeaders,
 
// Create the final options object
s = jQuery.ajaxSetup( {}, options ),
 
// Callbacks context
callbackContext = s.context || s,
 
// Context for global events is callbackContext if it is a DOM node or jQuery collection
globalEventContext = s.context &&
( callbackContext.nodeType || callbackContext.jquery ) ?
jQuery( callbackContext ) :
jQuery.event,
 
// Deferreds
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks( "once memory" ),
 
// Status-dependent callbacks
statusCode = s.statusCode || {},
 
// Headers (they are sent all at once)
requestHeaders = {},
requestHeadersNames = {},
 
// The jqXHR state
state = 0,
 
// Default abort message
strAbort = "canceled",
 
// Fake xhr
jqXHR = {
readyState: 0,
 
// Builds headers hashtable if needed
getResponseHeader: function( key ) {
var match;
if ( state === 2 ) {
if ( !responseHeaders ) {
responseHeaders = {};
while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
}
}
match = responseHeaders[ key.toLowerCase() ];
}
return match == null ? null : match;
},
 
// Raw string
getAllResponseHeaders: function() {
return state === 2 ? responseHeadersString : null;
},
 
// Caches the header
setRequestHeader: function( name, value ) {
var lname = name.toLowerCase();
if ( !state ) {
name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
requestHeaders[ name ] = value;
}
return this;
},
 
// Overrides response content-type header
overrideMimeType: function( type ) {
if ( !state ) {
s.mimeType = type;
}
return this;
},
 
// Status-dependent callbacks
statusCode: function( map ) {
var code;
if ( map ) {
if ( state < 2 ) {
for ( code in map ) {
 
// Lazy-add the new callback in a way that preserves old ones
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
}
} else {
 
// Execute the appropriate callbacks
jqXHR.always( map[ jqXHR.status ] );
}
}
return this;
},
 
// Cancel the request
abort: function( statusText ) {
var finalText = statusText || strAbort;
if ( transport ) {
transport.abort( finalText );
}
done( 0, finalText );
return this;
}
};
 
// Attach deferreds
deferred.promise( jqXHR ).complete = completeDeferred.add;
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
 
// Remove hash character (#7531: and string promotion)
// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
// Handle falsy url in the settings object (#10093: consistency with old signature)
// We also use the url parameter if available
s.url = ( ( url || s.url || ajaxLocation ) + "" )
.replace( rhash, "" )
.replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
 
// Alias method option to type as per ticket #12004
s.type = options.method || options.type || s.method || s.type;
 
// Extract dataTypes list
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
 
// A cross-domain request is in order when we have a protocol:host:port mismatch
if ( s.crossDomain == null ) {
parts = rurl.exec( s.url.toLowerCase() );
s.crossDomain = !!( parts &&
( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
);
}
 
// Convert data if not already a string
if ( s.data && s.processData && typeof s.data !== "string" ) {
s.data = jQuery.param( s.data, s.traditional );
}
 
// Apply prefilters
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
 
// If request was aborted inside a prefilter, stop there
if ( state === 2 ) {
return jqXHR;
}
 
// We can fire global events as of now if asked to
// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
fireGlobals = jQuery.event && s.global;
 
// Watch for a new set of requests
if ( fireGlobals && jQuery.active++ === 0 ) {
jQuery.event.trigger( "ajaxStart" );
}
 
// Uppercase the type
s.type = s.type.toUpperCase();
 
// Determine if request has content
s.hasContent = !rnoContent.test( s.type );
 
// Save the URL in case we're toying with the If-Modified-Since
// and/or If-None-Match header later on
cacheURL = s.url;
 
// More options handling for requests with no content
if ( !s.hasContent ) {
 
// If data is available, append data to url
if ( s.data ) {
cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
 
// #9682: remove data so that it's not used in an eventual retry
delete s.data;
}
 
// Add anti-cache in url if needed
if ( s.cache === false ) {
s.url = rts.test( cacheURL ) ?
 
// If there is already a '_' parameter, set its value
cacheURL.replace( rts, "$1_=" + nonce++ ) :
 
// Otherwise add one to the end
cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
}
}
 
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
if ( jQuery.lastModified[ cacheURL ] ) {
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
}
if ( jQuery.etag[ cacheURL ] ) {
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
}
}
 
// Set the correct header, if data is being sent
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
jqXHR.setRequestHeader( "Content-Type", s.contentType );
}
 
// Set the Accepts header for the server, depending on the dataType
jqXHR.setRequestHeader(
"Accept",
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
s.accepts[ s.dataTypes[ 0 ] ] +
( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
s.accepts[ "*" ]
);
 
// Check for headers option
for ( i in s.headers ) {
jqXHR.setRequestHeader( i, s.headers[ i ] );
}
 
// Allow custom headers/mimetypes and early abort
if ( s.beforeSend &&
( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
 
// Abort if not done already and return
return jqXHR.abort();
}
 
// aborting is no longer a cancellation
strAbort = "abort";
 
// Install callbacks on deferreds
for ( i in { success: 1, error: 1, complete: 1 } ) {
jqXHR[ i ]( s[ i ] );
}
 
// Get transport
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
 
// If no transport, we auto-abort
if ( !transport ) {
done( -1, "No Transport" );
} else {
jqXHR.readyState = 1;
 
// Send global event
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
}
 
// If request was aborted inside ajaxSend, stop there
if ( state === 2 ) {
return jqXHR;
}
 
// Timeout
if ( s.async && s.timeout > 0 ) {
timeoutTimer = window.setTimeout( function() {
jqXHR.abort( "timeout" );
}, s.timeout );
}
 
try {
state = 1;
transport.send( requestHeaders, done );
} catch ( e ) {
 
// Propagate exception as error if not done
if ( state < 2 ) {
done( -1, e );
 
// Simply rethrow otherwise
} else {
throw e;
}
}
}
 
// Callback for when everything is done
function done( status, nativeStatusText, responses, headers ) {
var isSuccess, success, error, response, modified,
statusText = nativeStatusText;
 
// Called once
if ( state === 2 ) {
return;
}
 
// State is "done" now
state = 2;
 
// Clear timeout if it exists
if ( timeoutTimer ) {
window.clearTimeout( timeoutTimer );
}
 
// Dereference transport for early garbage collection
// (no matter how long the jqXHR object will be used)
transport = undefined;
 
// Cache response headers
responseHeadersString = headers || "";
 
// Set readyState
jqXHR.readyState = status > 0 ? 4 : 0;
 
// Determine if successful
isSuccess = status >= 200 && status < 300 || status === 304;
 
// Get response data
if ( responses ) {
response = ajaxHandleResponses( s, jqXHR, responses );
}
 
// Convert no matter what (that way responseXXX fields are always set)
response = ajaxConvert( s, response, jqXHR, isSuccess );
 
// If successful, handle type chaining
if ( isSuccess ) {
 
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
modified = jqXHR.getResponseHeader( "Last-Modified" );
if ( modified ) {
jQuery.lastModified[ cacheURL ] = modified;
}
modified = jqXHR.getResponseHeader( "etag" );
if ( modified ) {
jQuery.etag[ cacheURL ] = modified;
}
}
 
// if no content
if ( status === 204 || s.type === "HEAD" ) {
statusText = "nocontent";
 
// if not modified
} else if ( status === 304 ) {
statusText = "notmodified";
 
// If we have data, let's convert it
} else {
statusText = response.state;
success = response.data;
error = response.error;
isSuccess = !error;
}
} else {
 
// We extract error from statusText
// then normalize statusText and status for non-aborts
error = statusText;
if ( status || !statusText ) {
statusText = "error";
if ( status < 0 ) {
status = 0;
}
}
}
 
// Set data for the fake xhr object
jqXHR.status = status;
jqXHR.statusText = ( nativeStatusText || statusText ) + "";
 
// Success/Error
if ( isSuccess ) {
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
} else {
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
}
 
// Status-dependent callbacks
jqXHR.statusCode( statusCode );
statusCode = undefined;
 
if ( fireGlobals ) {
globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
[ jqXHR, s, isSuccess ? success : error ] );
}
 
// Complete
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
 
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
 
// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
jQuery.event.trigger( "ajaxStop" );
}
}
}
 
return jqXHR;
},
 
getJSON: function( url, data, callback ) {
return jQuery.get( url, data, callback, "json" );
},
 
getScript: function( url, callback ) {
return jQuery.get( url, undefined, callback, "script" );
}
} );
 
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
 
// shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}
 
// The url can be an options object (which then must have .url)
return jQuery.ajax( jQuery.extend( {
url: url,
type: method,
dataType: type,
data: data,
success: callback
}, jQuery.isPlainObject( url ) && url ) );
};
} );
 
 
jQuery._evalUrl = function( url ) {
return jQuery.ajax( {
url: url,
 
// Make this explicit, since user can override this through ajaxSetup (#11264)
type: "GET",
dataType: "script",
cache: true,
async: false,
global: false,
"throws": true
} );
};
 
 
jQuery.fn.extend( {
wrapAll: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each( function( i ) {
jQuery( this ).wrapAll( html.call( this, i ) );
} );
}
 
if ( this[ 0 ] ) {
 
// The elements to wrap the target around
var wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
 
if ( this[ 0 ].parentNode ) {
wrap.insertBefore( this[ 0 ] );
}
 
wrap.map( function() {
var elem = this;
 
while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
elem = elem.firstChild;
}
 
return elem;
} ).append( this );
}
 
return this;
},
 
wrapInner: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each( function( i ) {
jQuery( this ).wrapInner( html.call( this, i ) );
} );
}
 
return this.each( function() {
var self = jQuery( this ),
contents = self.contents();
 
if ( contents.length ) {
contents.wrapAll( html );
 
} else {
self.append( html );
}
} );
},
 
wrap: function( html ) {
var isFunction = jQuery.isFunction( html );
 
return this.each( function( i ) {
jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
} );
},
 
unwrap: function() {
return this.parent().each( function() {
if ( !jQuery.nodeName( this, "body" ) ) {
jQuery( this ).replaceWith( this.childNodes );
}
} ).end();
}
} );
 
 
function getDisplay( elem ) {
return elem.style && elem.style.display || jQuery.css( elem, "display" );
}
 
function filterHidden( elem ) {
 
// Disconnected elements are considered hidden
if ( !jQuery.contains( elem.ownerDocument || document, elem ) ) {
return true;
}
while ( elem && elem.nodeType === 1 ) {
if ( getDisplay( elem ) === "none" || elem.type === "hidden" ) {
return true;
}
elem = elem.parentNode;
}
return false;
}
 
jQuery.expr.filters.hidden = function( elem ) {
 
// Support: Opera <= 12.12
// Opera reports offsetWidths and offsetHeights less than zero on some elements
return support.reliableHiddenOffsets() ?
( elem.offsetWidth <= 0 && elem.offsetHeight <= 0 &&
(!elem.getClientRects || !elem.getClientRects().length) ) :
filterHidden( elem );
};
 
jQuery.expr.filters.visible = function( elem ) {
return !jQuery.expr.filters.hidden( elem );
};
 
 
 
 
var r20 = /%20/g,
rbracket = /\[\]$/,
rCRLF = /\r?\n/g,
rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
rsubmittable = /^(?:input|select|textarea|keygen)/i;
 
function buildParams( prefix, obj, traditional, add ) {
var name;
 
if ( jQuery.isArray( obj ) ) {
 
// Serialize array item.
jQuery.each( obj, function( i, v ) {
if ( traditional || rbracket.test( prefix ) ) {
 
// Treat each array item as a scalar.
add( prefix, v );
 
} else {
 
// Item is non-scalar (array or object), encode its numeric index.
buildParams(
prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
v,
traditional,
add
);
}
} );
 
} else if ( !traditional && jQuery.type( obj ) === "object" ) {
 
// Serialize object item.
for ( name in obj ) {
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
}
 
} else {
 
// Serialize scalar item.
add( prefix, obj );
}
}
 
// Serialize an array of form elements or a set of
// key/values into a query string
jQuery.param = function( a, traditional ) {
var prefix,
s = [],
add = function( key, value ) {
 
// If value is a function, invoke it and return its value
value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
};
 
// Set traditional to true for jQuery <= 1.3.2 behavior.
if ( traditional === undefined ) {
traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
}
 
// If an array was passed in, assume that it is an array of form elements.
if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
 
// Serialize the form elements
jQuery.each( a, function() {
add( this.name, this.value );
} );
 
} else {
 
// If traditional, encode the "old" way (the way 1.3.2 or older
// did it), otherwise encode params recursively.
for ( prefix in a ) {
buildParams( prefix, a[ prefix ], traditional, add );
}
}
 
// Return the resulting serialization
return s.join( "&" ).replace( r20, "+" );
};
 
jQuery.fn.extend( {
serialize: function() {
return jQuery.param( this.serializeArray() );
},
serializeArray: function() {
return this.map( function() {
 
// Can add propHook for "elements" to filter or add form elements
var elements = jQuery.prop( this, "elements" );
return elements ? jQuery.makeArray( elements ) : this;
} )
.filter( function() {
var type = this.type;
 
// Use .is(":disabled") so that fieldset[disabled] works
return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !rcheckableType.test( type ) );
} )
.map( function( i, elem ) {
var val = jQuery( this ).val();
 
return val == null ?
null :
jQuery.isArray( val ) ?
jQuery.map( val, function( val ) {
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
} ) :
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
} ).get();
}
} );
 
 
// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
 
// Support: IE6-IE8
function() {
 
// XHR cannot access local files, always use ActiveX for that case
if ( this.isLocal ) {
return createActiveXHR();
}
 
// Support: IE 9-11
// IE seems to error on cross-domain PATCH requests when ActiveX XHR
// is used. In IE 9+ always use the native XHR.
// Note: this condition won't catch Edge as it doesn't define
// document.documentMode but it also doesn't support ActiveX so it won't
// reach this code.
if ( document.documentMode > 8 ) {
return createStandardXHR();
}
 
// Support: IE<9
// oldIE XHR does not support non-RFC2616 methods (#13240)
// See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
// and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
// Although this check for six methods instead of eight
// since IE also does not support "trace" and "connect"
return /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
createStandardXHR() || createActiveXHR();
} :
 
// For all other browsers, use the standard XMLHttpRequest object
createStandardXHR;
 
var xhrId = 0,
xhrCallbacks = {},
xhrSupported = jQuery.ajaxSettings.xhr();
 
// Support: IE<10
// Open requests must be manually aborted on unload (#5280)
// See https://support.microsoft.com/kb/2856746 for more info
if ( window.attachEvent ) {
window.attachEvent( "onunload", function() {
for ( var key in xhrCallbacks ) {
xhrCallbacks[ key ]( undefined, true );
}
} );
}
 
// Determine support properties
support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
xhrSupported = support.ajax = !!xhrSupported;
 
// Create transport if the browser can provide an xhr
if ( xhrSupported ) {
 
jQuery.ajaxTransport( function( options ) {
 
// Cross domain only allowed if supported through XMLHttpRequest
if ( !options.crossDomain || support.cors ) {
 
var callback;
 
return {
send: function( headers, complete ) {
var i,
xhr = options.xhr(),
id = ++xhrId;
 
// Open the socket
xhr.open(
options.type,
options.url,
options.async,
options.username,
options.password
);
 
// Apply custom fields if provided
if ( options.xhrFields ) {
for ( i in options.xhrFields ) {
xhr[ i ] = options.xhrFields[ i ];
}
}
 
// Override mime type if needed
if ( options.mimeType && xhr.overrideMimeType ) {
xhr.overrideMimeType( options.mimeType );
}
 
// X-Requested-With header
// For cross-domain requests, seeing as conditions for a preflight are
// akin to a jigsaw puzzle, we simply never set it to be sure.
// (it can always be set on a per-request basis or even using ajaxSetup)
// For same-domain requests, won't change header if already provided.
if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
headers[ "X-Requested-With" ] = "XMLHttpRequest";
}
 
// Set headers
for ( i in headers ) {
 
// Support: IE<9
// IE's ActiveXObject throws a 'Type Mismatch' exception when setting
// request header to a null-value.
//
// To keep consistent with other XHR implementations, cast the value
// to string and ignore `undefined`.
if ( headers[ i ] !== undefined ) {
xhr.setRequestHeader( i, headers[ i ] + "" );
}
}
 
// Do send the request
// This may raise an exception which is actually
// handled in jQuery.ajax (so no try/catch here)
xhr.send( ( options.hasContent && options.data ) || null );
 
// Listener
callback = function( _, isAbort ) {
var status, statusText, responses;
 
// Was never called and is aborted or complete
if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
 
// Clean up
delete xhrCallbacks[ id ];
callback = undefined;
xhr.onreadystatechange = jQuery.noop;
 
// Abort manually if needed
if ( isAbort ) {
if ( xhr.readyState !== 4 ) {
xhr.abort();
}
} else {
responses = {};
status = xhr.status;
 
// Support: IE<10
// Accessing binary-data responseText throws an exception
// (#11426)
if ( typeof xhr.responseText === "string" ) {
responses.text = xhr.responseText;
}
 
// Firefox throws an exception when accessing
// statusText for faulty cross-domain requests
try {
statusText = xhr.statusText;
} catch ( e ) {
 
// We normalize with Webkit giving an empty statusText
statusText = "";
}
 
// Filter status for non standard behaviors
 
// If the request is local and we have data: assume a success
// (success with no data won't get notified, that's the best we
// can do given current implementations)
if ( !status && options.isLocal && !options.crossDomain ) {
status = responses.text ? 200 : 404;
 
// IE - #1450: sometimes returns 1223 when it should be 204
} else if ( status === 1223 ) {
status = 204;
}
}
}
 
// Call complete if needed
if ( responses ) {
complete( status, statusText, responses, xhr.getAllResponseHeaders() );
}
};
 
// Do send the request
// `xhr.send` may raise an exception, but it will be
// handled in jQuery.ajax (so no try/catch here)
if ( !options.async ) {
 
// If we're in sync mode we fire the callback
callback();
} else if ( xhr.readyState === 4 ) {
 
// (IE6 & IE7) if it's in cache and has been
// retrieved directly we need to fire the callback
window.setTimeout( callback );
} else {
 
// Register the callback, but delay it in case `xhr.send` throws
// Add to the list of active xhr callbacks
xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
}
},
 
abort: function() {
if ( callback ) {
callback( undefined, true );
}
}
};
}
} );
}
 
// Functions to create xhrs
function createStandardXHR() {
try {
return new window.XMLHttpRequest();
} catch ( e ) {}
}
 
function createActiveXHR() {
try {
return new window.ActiveXObject( "Microsoft.XMLHTTP" );
} catch ( e ) {}
}
 
 
 
 
// Install script dataType
jQuery.ajaxSetup( {
accepts: {
script: "text/javascript, application/javascript, " +
"application/ecmascript, application/x-ecmascript"
},
contents: {
script: /\b(?:java|ecma)script\b/
},
converters: {
"text script": function( text ) {
jQuery.globalEval( text );
return text;
}
}
} );
 
// Handle cache's special case and global
jQuery.ajaxPrefilter( "script", function( s ) {
if ( s.cache === undefined ) {
s.cache = false;
}
if ( s.crossDomain ) {
s.type = "GET";
s.global = false;
}
} );
 
// Bind script tag hack transport
jQuery.ajaxTransport( "script", function( s ) {
 
// This transport only deals with cross domain requests
if ( s.crossDomain ) {
 
var script,
head = document.head || jQuery( "head" )[ 0 ] || document.documentElement;
 
return {
 
send: function( _, callback ) {
 
script = document.createElement( "script" );
 
script.async = true;
 
if ( s.scriptCharset ) {
script.charset = s.scriptCharset;
}
 
script.src = s.url;
 
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function( _, isAbort ) {
 
if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
 
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
 
// Remove the script
if ( script.parentNode ) {
script.parentNode.removeChild( script );
}
 
// Dereference the script
script = null;
 
// Callback if not abort
if ( !isAbort ) {
callback( 200, "success" );
}
}
};
 
// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
// Use native DOM manipulation to avoid our domManip AJAX trickery
head.insertBefore( script, head.firstChild );
},
 
abort: function() {
if ( script ) {
script.onload( undefined, true );
}
}
};
}
} );
 
 
 
 
var oldCallbacks = [],
rjsonp = /(=)\?(?=&|$)|\?\?/;
 
// Default jsonp settings
jQuery.ajaxSetup( {
jsonp: "callback",
jsonpCallback: function() {
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
this[ callback ] = true;
return callback;
}
} );
 
// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
 
var callbackName, overwritten, responseContainer,
jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
"url" :
typeof s.data === "string" &&
( s.contentType || "" )
.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
rjsonp.test( s.data ) && "data"
);
 
// Handle iff the expected data type is "jsonp" or we have a parameter to set
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
 
// Get callback name, remembering preexisting value associated with it
callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
s.jsonpCallback() :
s.jsonpCallback;
 
// Insert callback into url or form data
if ( jsonProp ) {
s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
} else if ( s.jsonp !== false ) {
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
}
 
// Use data converter to retrieve json after script execution
s.converters[ "script json" ] = function() {
if ( !responseContainer ) {
jQuery.error( callbackName + " was not called" );
}
return responseContainer[ 0 ];
};
 
// force json dataType
s.dataTypes[ 0 ] = "json";
 
// Install callback
overwritten = window[ callbackName ];
window[ callbackName ] = function() {
responseContainer = arguments;
};
 
// Clean-up function (fires after converters)
jqXHR.always( function() {
 
// If previous value didn't exist - remove it
if ( overwritten === undefined ) {
jQuery( window ).removeProp( callbackName );
 
// Otherwise restore preexisting value
} else {
window[ callbackName ] = overwritten;
}
 
// Save back as free
if ( s[ callbackName ] ) {
 
// make sure that re-using the options doesn't screw things around
s.jsonpCallback = originalSettings.jsonpCallback;
 
// save the callback name for future use
oldCallbacks.push( callbackName );
}
 
// Call if it was a function and we have a response
if ( responseContainer && jQuery.isFunction( overwritten ) ) {
overwritten( responseContainer[ 0 ] );
}
 
responseContainer = overwritten = undefined;
} );
 
// Delegate to script
return "script";
}
} );
 
 
 
 
// data: string of html
// context (optional): If specified, the fragment will be created in this context,
// defaults to document
// keepScripts (optional): If true, will include scripts passed in the html string
jQuery.parseHTML = function( data, context, keepScripts ) {
if ( !data || typeof data !== "string" ) {
return null;
}
if ( typeof context === "boolean" ) {
keepScripts = context;
context = false;
}
context = context || document;
 
var parsed = rsingleTag.exec( data ),
scripts = !keepScripts && [];
 
// Single tag
if ( parsed ) {
return [ context.createElement( parsed[ 1 ] ) ];
}
 
parsed = buildFragment( [ data ], context, scripts );
 
if ( scripts && scripts.length ) {
jQuery( scripts ).remove();
}
 
return jQuery.merge( [], parsed.childNodes );
};
 
 
// Keep a copy of the old load method
var _load = jQuery.fn.load;
 
/**
* Load a url into a page
*/
jQuery.fn.load = function( url, params, callback ) {
if ( typeof url !== "string" && _load ) {
return _load.apply( this, arguments );
}
 
var selector, type, response,
self = this,
off = url.indexOf( " " );
 
if ( off > -1 ) {
selector = jQuery.trim( url.slice( off, url.length ) );
url = url.slice( 0, off );
}
 
// If it's a function
if ( jQuery.isFunction( params ) ) {
 
// We assume that it's the callback
callback = params;
params = undefined;
 
// Otherwise, build a param string
} else if ( params && typeof params === "object" ) {
type = "POST";
}
 
// If we have elements to modify, make the request
if ( self.length > 0 ) {
jQuery.ajax( {
url: url,
 
// If "type" variable is undefined, then "GET" method will be used.
// Make value of this field explicit since
// user can override it through ajaxSetup method
type: type || "GET",
dataType: "html",
data: params
} ).done( function( responseText ) {
 
// Save response for use in complete callback
response = arguments;
 
self.html( selector ?
 
// If a selector was specified, locate the right elements in a dummy div
// Exclude scripts to avoid IE 'Permission Denied' errors
jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
 
// Otherwise use the full result
responseText );
 
// If the request succeeds, this function gets "data", "status", "jqXHR"
// but they are ignored because response was set above.
// If it fails, this function gets "jqXHR", "status", "error"
} ).always( callback && function( jqXHR, status ) {
self.each( function() {
callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
} );
} );
}
 
return this;
};
 
 
 
 
// Attach a bunch of functions for handling common AJAX events
jQuery.each( [
"ajaxStart",
"ajaxStop",
"ajaxComplete",
"ajaxError",
"ajaxSuccess",
"ajaxSend"
], function( i, type ) {
jQuery.fn[ type ] = function( fn ) {
return this.on( type, fn );
};
} );
 
 
 
 
jQuery.expr.filters.animated = function( elem ) {
return jQuery.grep( jQuery.timers, function( fn ) {
return elem === fn.elem;
} ).length;
};
 
 
 
 
 
/**
* Gets a window from an element
*/
function getWindow( elem ) {
return jQuery.isWindow( elem ) ?
elem :
elem.nodeType === 9 ?
elem.defaultView || elem.parentWindow :
false;
}
 
jQuery.offset = {
setOffset: function( elem, options, i ) {
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
position = jQuery.css( elem, "position" ),
curElem = jQuery( elem ),
props = {};
 
// set position first, in-case top/left are set even on static elem
if ( position === "static" ) {
elem.style.position = "relative";
}
 
curOffset = curElem.offset();
curCSSTop = jQuery.css( elem, "top" );
curCSSLeft = jQuery.css( elem, "left" );
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
jQuery.inArray( "auto", [ curCSSTop, curCSSLeft ] ) > -1;
 
// need to be able to calculate position if either top or left
// is auto and position is either absolute or fixed
if ( calculatePosition ) {
curPosition = curElem.position();
curTop = curPosition.top;
curLeft = curPosition.left;
} else {
curTop = parseFloat( curCSSTop ) || 0;
curLeft = parseFloat( curCSSLeft ) || 0;
}
 
if ( jQuery.isFunction( options ) ) {
 
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
}
 
if ( options.top != null ) {
props.top = ( options.top - curOffset.top ) + curTop;
}
if ( options.left != null ) {
props.left = ( options.left - curOffset.left ) + curLeft;
}
 
if ( "using" in options ) {
options.using.call( elem, props );
} else {
curElem.css( props );
}
}
};
 
jQuery.fn.extend( {
offset: function( options ) {
if ( arguments.length ) {
return options === undefined ?
this :
this.each( function( i ) {
jQuery.offset.setOffset( this, options, i );
} );
}
 
var docElem, win,
box = { top: 0, left: 0 },
elem = this[ 0 ],
doc = elem && elem.ownerDocument;
 
if ( !doc ) {
return;
}
 
docElem = doc.documentElement;
 
// Make sure it's not a disconnected DOM node
if ( !jQuery.contains( docElem, elem ) ) {
return box;
}
 
// If we don't have gBCR, just use 0,0 rather than error
// BlackBerry 5, iOS 3 (original iPhone)
if ( typeof elem.getBoundingClientRect !== "undefined" ) {
box = elem.getBoundingClientRect();
}
win = getWindow( doc );
return {
top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
};
},
 
position: function() {
if ( !this[ 0 ] ) {
return;
}
 
var offsetParent, offset,
parentOffset = { top: 0, left: 0 },
elem = this[ 0 ];
 
// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
// because it is its only offset parent
if ( jQuery.css( elem, "position" ) === "fixed" ) {
 
// we assume that getBoundingClientRect is available when computed position is fixed
offset = elem.getBoundingClientRect();
} else {
 
// Get *real* offsetParent
offsetParent = this.offsetParent();
 
// Get correct offsets
offset = this.offset();
if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
parentOffset = offsetParent.offset();
}
 
// Add offsetParent borders
parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
}
 
// Subtract parent offsets and element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
return {
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
};
},
 
offsetParent: function() {
return this.map( function() {
var offsetParent = this.offsetParent;
 
while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) &&
jQuery.css( offsetParent, "position" ) === "static" ) ) {
offsetParent = offsetParent.offsetParent;
}
return offsetParent || documentElement;
} );
}
} );
 
// Create scrollLeft and scrollTop methods
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
var top = /Y/.test( prop );
 
jQuery.fn[ method ] = function( val ) {
return access( this, function( elem, method, val ) {
var win = getWindow( elem );
 
if ( val === undefined ) {
return win ? ( prop in win ) ? win[ prop ] :
win.document.documentElement[ method ] :
elem[ method ];
}
 
if ( win ) {
win.scrollTo(
!top ? val : jQuery( win ).scrollLeft(),
top ? val : jQuery( win ).scrollTop()
);
 
} else {
elem[ method ] = val;
}
}, method, val, arguments.length, null );
};
} );
 
// Support: Safari<7-8+, Chrome<37-44+
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// getComputedStyle returns percent when specified for top/left/bottom/right
// rather than make the css module depend on the offset module, we just check for it here
jQuery.each( [ "top", "left" ], function( i, prop ) {
jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
function( elem, computed ) {
if ( computed ) {
computed = curCSS( elem, prop );
 
// if curCSS returns percentage, fallback to offset
return rnumnonpx.test( computed ) ?
jQuery( elem ).position()[ prop ] + "px" :
computed;
}
}
);
} );
 
 
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
function( defaultExtra, funcName ) {
 
// margin is only for outerHeight, outerWidth
jQuery.fn[ funcName ] = function( margin, value ) {
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
 
return access( this, function( elem, type, value ) {
var doc;
 
if ( jQuery.isWindow( elem ) ) {
 
// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
// isn't a whole lot we can do. See pull request at this URL for discussion:
// https://github.com/jquery/jquery/pull/764
return elem.document.documentElement[ "client" + name ];
}
 
// Get document width or height
if ( elem.nodeType === 9 ) {
doc = elem.documentElement;
 
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
// whichever is greatest
// unfortunately, this causes bug #3838 in IE6/8 only,
// but there is currently no good, small way to fix it.
return Math.max(
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
elem.body[ "offset" + name ], doc[ "offset" + name ],
doc[ "client" + name ]
);
}
 
return value === undefined ?
 
// Get width or height on the element, requesting but not forcing parseFloat
jQuery.css( elem, type, extra ) :
 
// Set width or height on the element
jQuery.style( elem, type, value, extra );
}, type, chainable ? margin : undefined, chainable, null );
};
} );
} );
 
 
jQuery.fn.extend( {
 
bind: function( types, data, fn ) {
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
return this.off( types, null, fn );
},
 
delegate: function( selector, types, data, fn ) {
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
 
// ( namespace ) or ( selector, types [, fn] )
return arguments.length === 1 ?
this.off( selector, "**" ) :
this.off( types, selector || "**", fn );
}
} );
 
// The number of elements contained in the matched element set
jQuery.fn.size = function() {
return this.length;
};
 
jQuery.fn.andSelf = jQuery.fn.addBack;
 
 
 
 
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
 
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
 
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
} );
}
 
 
 
var
 
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
 
// Map over the $ in case of overwrite
_$ = window.$;
 
jQuery.noConflict = function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
 
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
 
return jQuery;
};
 
// Expose jQuery and $ identifiers, even in
// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
if ( !noGlobal ) {
window.jQuery = window.$ = jQuery;
}
 
return jQuery;
}));
/web/acc/phpsysinfo/js/jQuery/jquery.nyroModal.js
0,0 → 1,1709
/*
* nyroModal - jQuery Plugin
* http://nyromodal.nyrodev.com
*
* Copyright (c) 2010 Cedric Nirousset (nyrodev.com)
* Licensed under the MIT license
*
* $Date: 2010-02-23 (Tue, 23 Feb 2010) $
* $version: 1.6.2+jquery1.8fix+bindfix+ff2fix
*/
jQuery(function($) {
 
// -------------------------------------------------------
// Private Variables
// -------------------------------------------------------
 
var userAgent = navigator.userAgent.toLowerCase();
var browserVersion = (userAgent.match(/.+(?:rv|webkit|khtml|opera|msie)[\/: ]([\d.]+)/ ) || [0,'0'])[1];
 
var isIE6 = (/msie/.test(userAgent) && !/opera/.test(userAgent) && parseInt(browserVersion) < 7 && (!window.XMLHttpRequest || typeof(XMLHttpRequest) === 'function'));
var body = $('body');
 
var currentSettings;
var callingSettings;
 
var shouldResize = false;
 
var gallery = {};
 
// To know if the fix for the Issue 10 should be applied (or has been applied)
var fixFF = false;
 
// Used for retrieve the content from an hidden div
var contentElt;
var contentEltLast;
 
// Contains info about nyroModal state and all div references
var modal = {
started: false,
ready: false,
dataReady: false,
anim: false,
animContent: false,
loadingShown: false,
transition: false,
resizing: false,
closing: false,
error: false,
blocker: null,
blockerVars: null,
full: null,
bg: null,
loading: null,
tmp: null,
content: null,
wrapper: null,
contentWrapper: null,
scripts: new Array(),
scriptsShown: new Array()
};
 
// Indicate of the height or the width was resized, to reinit the currentsettings related to null
var resized = {
width: false,
height: false,
windowResizing: false
};
 
var initSettingsSize = {
width: null,
height: null,
windowResizing: true
};
 
var windowResizeTimeout;
 
 
// -------------------------------------------------------
// Public function
// -------------------------------------------------------
 
// jQuery extension function. A paramater object could be used to overwrite the default settings
$.fn.nyroModal = function(settings) {
if (!this)
return false;
return this.each(function() {
var me = $(this);
if (this.nodeName.toLowerCase() == 'form') {
me
.off('submit.nyroModal')
.on('submit.nyroModal', function(e) {
if(e.isDefaultPrevented())
return false;
if (me.data('nyroModalprocessing'))
return true;
if (this.enctype == 'multipart/form-data') {
processModal($.extend(settings, {
from: this
}));
return true;
}
e.preventDefault();
processModal($.extend(settings, {
from: this
}));
return false;
});
} else {
me
.off('click.nyroModal')
.on('click.nyroModal', function(e) {
if(e.isDefaultPrevented())
return false;
e.preventDefault();
processModal($.extend(settings, {
from: this
}));
return false;
});
}
});
};
 
// jQuery extension function to call manually the modal. A paramater object could be used to overwrite the default settings
$.fn.nyroModalManual = function(settings) {
if (!this.length)
processModal(settings);
return this.each(function(){
processModal($.extend(settings, {
from: this
}));
});
};
 
$.nyroModalManual = function(settings) {
processModal(settings);
};
 
// Update the current settings
// object settings
// string deep1 first key where overwrite the settings
// string deep2 second key where overwrite the settings
$.nyroModalSettings = function(settings, deep1, deep2) {
setCurrentSettings(settings, deep1, deep2);
if (!deep1 && modal.started) {
if (modal.bg && settings.bgColor)
currentSettings.updateBgColor(modal, currentSettings, function(){});
 
if (modal.contentWrapper && settings.title)
setTitle();
 
if (!modal.error && (settings.windowResizing || (!modal.resizing && (('width' in settings && settings.width == currentSettings.width) || ('height' in settings && settings.height == currentSettings.height))))) {
modal.resizing = true;
if (modal.contentWrapper)
calculateSize(true);
if (modal.contentWrapper && modal.contentWrapper.is(':visible') && !modal.animContent) {
if (fixFF)
modal.content.css({position: ''});
currentSettings.resize(modal, currentSettings, function() {
currentSettings.windowResizing = false;
modal.resizing = false;
if (fixFF)
modal.content.css({position: 'fixed'});
if ($.isFunction(currentSettings.endResize))
currentSettings.endResize(modal, currentSettings);
});
}
}
}
};
 
// Remove the modal function
$.nyroModalRemove = function() {
removeModal();
};
 
// Go to the next image for a gallery
// return false if nothing was done
$.nyroModalNext = function() {
var link = getGalleryLink(1);
if (link)
return link.nyroModalManual(getCurrentSettingsNew());
return false;
};
 
// Go to the previous image for a gallery
// return false if nothing was done
$.nyroModalPrev = function() {
var link = getGalleryLink(-1);
if (link)
return link.nyroModalManual(getCurrentSettingsNew());
return false;
};
 
 
// -------------------------------------------------------
// Default Settings
// -------------------------------------------------------
 
$.fn.nyroModal.settings = {
debug: false, // Show the debug in the background
 
blocker: false, // Element which will be blocked by the modal
windowResize: true, // indicates if the modal should resize when the window is resized
 
modal: false, // Esc key or click backgrdound enabling or not
 
type: '', // nyroModal type (form, formData, iframe, image, etc...)
forceType: null, // Used to force the type
from: '', // Dom object where the call come from
hash: '', // Eventual hash in the url
 
processHandler: null, // Handler just before the real process
 
selIndicator: 'nyroModalSel', // Value added when a form or Ajax is sent with a filter content
 
formIndicator: 'nyroModal', // Value added when a form is sent
 
content: null, // Raw content if type content is used
 
bgColor: '#000000', // Background color
 
ajax: {}, // Ajax option (url, data, type, success will be overwritten for a form, url and success only for an ajax call)
 
swf: { // Swf player options if swf type is used.
wmode: 'transparent'
},
 
width: null, // default Width If null, will be calculate automatically
height: null, // default Height If null, will be calculate automatically
 
minWidth: 400, // Minimum width
minHeight: 300, // Minimum height
 
resizable: true, // Indicate if the content is resizable. Will be set to false for swf
autoSizable: true, // Indicate if the content is auto sizable. If not, the min size will be used
 
padding: 25, // padding for the max modal size
 
regexImg: '[^\.]\.(jpg|jpeg|png|tiff|gif|bmp)\s*$', // Regex to find images
addImageDivTitle: false, // Indicate if the div title should be inserted
defaultImgAlt: 'Image', // Default alt attribute for the images
setWidthImgTitle: true, // Set the width to the image title
ltr: true, // Left to Right by default. Put to false for Hebrew or Right to Left language
 
gallery: null, // Gallery name if provided
galleryLinks: '<a href="#" class="nyroModalPrev">Prev</a><a href="#" class="nyroModalNext">Next</a>', // Use .nyroModalPrev and .nyroModalNext to set the navigation link
galleryCounts: galleryCounts, // Callback to show the gallery count
galleryLoop: false, // Indicate if the gallery should loop
 
zIndexStart: 100,
 
cssOpt: { // Default CSS option for the nyroModal Div. Some will be overwritten or updated when using IE6
bg: {
position: 'absolute',
overflow: 'hidden',
top: 0,
left: 0,
height: '100%',
width: '100%'
},
wrapper: {
position: 'absolute',
top: '50%',
left: '50%'
},
wrapper2: {
},
content: {
},
loading: {
position: 'absolute',
top: '50%',
left: '50%',
marginTop: '-50px',
marginLeft: '-50px'
}
},
 
wrap: { // Wrapper div used to style the modal regarding the content type
div: '<div class="wrapper"></div>',
ajax: '<div class="wrapper"></div>',
form: '<div class="wrapper"></div>',
formData: '<div class="wrapper"></div>',
image: '<div class="wrapperImg"></div>',
swf: '<div class="wrapperSwf"></div>',
iframe: '<div class="wrapperIframe"></div>',
iframeForm: '<div class="wrapperIframe"></div>',
manual: '<div class="wrapper"></div>'
},
 
closeButton: '<a href="#" class="nyroModalClose" id="closeBut" title="close"></a>', // Adding automaticly as the first child of #nyroModalWrapper
 
title: null, // Modal title
titleFromIframe: true, // When using iframe in the same domain, try to get the title from it
 
openSelector: '.nyroModal', // selector for open a new modal. will be used to parse automaticly at page loading
closeSelector: '.nyroModalClose', // selector to close the modal
 
contentLoading: '<a href="#" class="nyroModalClose">Cancel</a>', // Loading div content
 
errorClass: 'error', // CSS Error class added to the loading div in case of error
contentError: 'The requested content cannot be loaded.<br />Please try again later.<br /><a href="#" class="nyroModalClose">Close</a>', // Content placed in the loading div in case of error
 
handleError: null, // Callback in case of error
 
showBackground: showBackground, // Show background animation function
hideBackground: hideBackground, // Hide background animation function
 
endFillContent: null, // Will be called after filling and wraping the content, before parsing closeSelector and openSelector and showing the content
showContent: showContent, // Show content animation function
endShowContent: null, // Will be called once the content is shown
beforeHideContent: null, // Will be called just before the modal closing
hideContent: hideContent, // Hide content animation function
 
showTransition: showTransition, // Show the transition animation (a modal is already shown and a new one is requested)
hideTransition: hideTransition, // Hide the transition animation to show the content
 
showLoading: showLoading, // show loading animation function
hideLoading: hideLoading, // hide loading animation function
 
resize: resize, // Resize animation function
endResize: null, // Will be called one the content is resized
 
updateBgColor: updateBgColor, // Change background color animation function
 
endRemove: null // Will be called once the modal is totally gone
};
 
// -------------------------------------------------------
// Private function
// -------------------------------------------------------
 
// Main function
function processModal(settings) {
if (modal.loadingShown || modal.transition || modal.anim)
return;
debug('processModal');
modal.started = true;
callingSettings = $.extend(true, settings);
setDefaultCurrentSettings(settings);
if (!modal.full)
modal.blockerVars = modal.blocker = null;
modal.error = false;
modal.closing = false;
modal.dataReady = false;
modal.scripts = new Array();
modal.scriptsShown = new Array();
 
currentSettings.type = fileType();
if (currentSettings.forceType) {
if (!currentSettings.content)
currentSettings.from = true;
currentSettings.type = currentSettings.forceType;
currentSettings.forceType = null;
}
 
if ($.isFunction(currentSettings.processHandler))
currentSettings.processHandler(currentSettings);
 
var from = currentSettings.from;
var url = currentSettings.url;
 
initSettingsSize.width = currentSettings.width;
initSettingsSize.height = currentSettings.height;
 
if (currentSettings.type == 'swf') {
// Swf is transforming as a raw content
setCurrentSettings({overflow: 'visible'}, 'cssOpt', 'content');
currentSettings.content = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+currentSettings.width+'" height="'+currentSettings.height+'"><param name="movie" value="'+url+'"></param>';
var tmp = '';
$.each(currentSettings.swf, function(name, val) {
currentSettings.content+= '<param name="'+name+'" value="'+val+'"></param>';
tmp+= ' '+name+'="'+val+'"';
});
currentSettings.content+= '<embed src="'+url+'" type="application/x-shockwave-flash" width="'+currentSettings.width+'" height="'+currentSettings.height+'"'+tmp+'></embed></object>';
}
 
if (from) {
var jFrom = $(from).blur();
if (currentSettings.type == 'form') {
var data = $(from).serializeArray();
data.push({name: currentSettings.formIndicator, value: 1});
if (currentSettings.selector)
data.push({name: currentSettings.selIndicator, value: currentSettings.selector.substring(1)});
showModal();
$.ajax($.extend({}, currentSettings.ajax, {
url: url,
data: data,
type: jFrom.attr('method') ? jFrom.attr('method') : 'get',
success: ajaxLoaded,
error: loadingError
}));
debug('Form Ajax Load: '+jFrom.attr('action'));
} else if (currentSettings.type == 'formData') {
// Form with data. We're using a hidden iframe
initModal();
jFrom.attr('target', 'nyroModalIframe');
jFrom.attr('action', url);
jFrom.prepend('<input type="hidden" name="'+currentSettings.formIndicator+'" value="1" />');
if (currentSettings.selector)
jFrom.prepend('<input type="hidden" name="'+currentSettings.selIndicator+'" value="'+currentSettings.selector.substring(1)+'" />');
modal.tmp.html('<iframe frameborder="0" hspace="0" name="nyroModalIframe" src="javascript:\'\';"></iframe>');
$('iframe', modal.tmp)
.css({
width: currentSettings.width,
height: currentSettings.height
})
.error(loadingError)
.load(formDataLoaded);
debug('Form Data Load: '+jFrom.attr('action'));
showModal();
showContentOrLoading();
} else if (currentSettings.type == 'image') {
debug('Image Load: '+url);
var title = jFrom.attr('title') || currentSettings.defaultImgAlt;
initModal();
modal.tmp.html('<img id="nyroModalImg" />').find('img').attr('alt', title);
modal.tmp.css({lineHeight: 0});
$('img', modal.tmp)
.error(loadingError)
.load(function() {
debug('Image Loaded: '+this.src);
$(this).off('load');
var w = modal.tmp.width();
var h = modal.tmp.height();
modal.tmp.css({lineHeight: ''});
resized.width = w;
resized.height = h;
setCurrentSettings({
width: w,
height: h,
imgWidth: w,
imgHeight: h
});
initSettingsSize.width = w;
initSettingsSize.height = h;
setCurrentSettings({overflow: 'visible'}, 'cssOpt', 'content');
modal.dataReady = true;
if (modal.loadingShown || modal.transition)
showContentOrLoading();
})
.attr('src', url);
showModal();
} else if (currentSettings.type == 'iframeForm') {
initModal();
modal.tmp.html('<iframe frameborder="0" hspace="0" src="javascript:\'\';" name="nyroModalIframe" id="nyroModalIframe"></iframe>');
debug('Iframe Form Load: '+url);
$('iframe', modal.tmp).eq(0)
.css({
width: '100%',
height: $.support.boxModel? '99%' : '100%'
})
.load(iframeLoaded);
modal.dataReady = true;
showModal();
} else if (currentSettings.type == 'iframe') {
initModal();
modal.tmp.html('<iframe frameborder="0" hspace="0" src="javascript:\'\';" name="nyroModalIframe" id="nyroModalIframe"></iframe>');
debug('Iframe Load: '+url);
$('iframe', modal.tmp).eq(0)
.css({
width: '100%',
height: $.support.boxModel? '99%' : '100%'
})
.load(iframeLoaded);
modal.dataReady = true;
showModal();
} else if (currentSettings.type) {
// Could be every other kind of type or a dom selector
debug('Content: '+currentSettings.type);
initModal();
modal.tmp.html(currentSettings.content);
var w = modal.tmp.width();
var h = modal.tmp.height();
var div = $(currentSettings.type);
if (div.length) {
setCurrentSettings({type: 'div'});
w = div.width();
h = div.height();
if (contentElt)
contentEltLast = contentElt;
contentElt = div;
modal.tmp.append(div.contents());
}
initSettingsSize.width = w;
initSettingsSize.height = h;
setCurrentSettings({
width: w,
height: h
});
if (modal.tmp.html())
modal.dataReady = true;
else
loadingError();
if (!modal.ready)
showModal();
else
endHideContent();
} else {
debug('Ajax Load: '+url);
setCurrentSettings({type: 'ajax'});
var data = currentSettings.ajax.data || {};
if (currentSettings.selector) {
if (typeof data == "string") {
data+= '&'+currentSettings.selIndicator+'='+currentSettings.selector.substring(1);
} else {
data[currentSettings.selIndicator] = currentSettings.selector.substring(1);
}
}
showModal();
$.ajax($.extend(true, currentSettings.ajax, {
url: url,
success: ajaxLoaded,
error: loadingError,
data: data
}));
}
} else if (currentSettings.content) {
// Raw content not from a DOM element
debug('Content: '+currentSettings.type);
setCurrentSettings({type: 'manual'});
initModal();
modal.tmp.html($('<div/>').html(currentSettings.content).contents());
if (modal.tmp.html())
modal.dataReady = true;
else
loadingError();
showModal();
} else {
// What should we show here? nothing happen
}
}
 
// Update the current settings
// object settings
// string deep1 first key where overwrite the settings
// string deep2 second key where overwrite the settings
function setDefaultCurrentSettings(settings) {
debug('setDefaultCurrentSettings');
currentSettings = $.extend(true, {}, $.fn.nyroModal.settings, settings);
setMargin();
}
 
function setCurrentSettings(settings, deep1, deep2) {
if (modal.started) {
if (deep1 && deep2) {
$.extend(true, currentSettings[deep1][deep2], settings);
} else if (deep1) {
$.extend(true, currentSettings[deep1], settings);
} else {
if (modal.animContent) {
if ('width' in settings) {
if (!modal.resizing) {
settings.setWidth = settings.width;
shouldResize = true;
}
delete settings['width'];
}
if ('height' in settings) {
if (!modal.resizing) {
settings.setHeight = settings.height;
shouldResize = true;
}
delete settings['height'];
}
}
$.extend(true, currentSettings, settings);
}
} else {
if (deep1 && deep2) {
$.extend(true, $.fn.nyroModal.settings[deep1][deep2], settings);
} else if (deep1) {
$.extend(true, $.fn.nyroModal.settings[deep1], settings);
} else {
$.extend(true, $.fn.nyroModal.settings, settings);
}
}
}
 
// Set the margin for postionning the element. Useful for IE6
function setMarginScroll() {
if (isIE6 && !modal.blocker) {
if (document.documentElement) {
currentSettings.marginScrollLeft = document.documentElement.scrollLeft;
currentSettings.marginScrollTop = document.documentElement.scrollTop;
} else {
currentSettings.marginScrollLeft = document.body.scrollLeft;
currentSettings.marginScrollTop = document.body.scrollTop;
}
} else {
currentSettings.marginScrollLeft = 0;
currentSettings.marginScrollTop = 0;
}
}
 
// Set the margin for the content
function setMargin() {
setMarginScroll();
currentSettings.marginLeft = -(currentSettings.width+currentSettings.borderW)/2;
currentSettings.marginTop = -(currentSettings.height+currentSettings.borderH)/2;
if (!modal.blocker) {
currentSettings.marginLeft+= currentSettings.marginScrollLeft;
currentSettings.marginTop+= currentSettings.marginScrollTop;
}
}
 
// Set the margin for the current loading
function setMarginLoading() {
setMarginScroll();
var outer = getOuter(modal.loading);
currentSettings.marginTopLoading = -(modal.loading.height() + outer.h.border + outer.h.padding)/2;
currentSettings.marginLeftLoading = -(modal.loading.width() + outer.w.border + outer.w.padding)/2;
if (!modal.blocker) {
currentSettings.marginLeftLoading+= currentSettings.marginScrollLeft;
currentSettings.marginTopLoading+= currentSettings.marginScrollTop;
}
}
 
// Set the modal Title
function setTitle() {
var title = $('h1#nyroModalTitle', modal.contentWrapper);
if (title.length)
title.text(currentSettings.title);
else
modal.contentWrapper.prepend('<h1 id="nyroModalTitle">'+currentSettings.title+'</h1>');
}
 
// Init the nyroModal div by settings the CSS elements and hide needed elements
function initModal() {
debug('initModal');
if (!modal.full) {
if (currentSettings.debug)
setCurrentSettings({color: 'white'}, 'cssOpt', 'bg');
 
var full = {
zIndex: currentSettings.zIndexStart,
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100%'
};
 
var contain = body;
var iframeHideIE = '';
if (currentSettings.blocker) {
modal.blocker = contain = $(currentSettings.blocker);
var pos = modal.blocker.offset();
var w = modal.blocker.outerWidth();
var h = modal.blocker.outerHeight();
if (isIE6) {
setCurrentSettings({
height: '100%',
width: '100%',
top: 0,
left: 0
}, 'cssOpt', 'bg');
}
modal.blockerVars = {
top: pos.top,
left: pos.left,
width: w,
height: h
};
var plusTop = (/msie/.test(userAgent) ?0:getCurCSS(body.get(0), 'borderTopWidth'));
var plusLeft = (/msie/.test(userAgent) ?0:getCurCSS(body.get(0), 'borderLeftWidth'));
full = {
position: 'absolute',
top: pos.top + plusTop,
left: pos.left + plusLeft,
width: w,
height: h
};
} else if (isIE6) {
body.css({
marginLeft: 0,
marginRight: 0
});
var w = body.width();
var h = $(window).height()+'px';
if ($(window).height() >= body.outerHeight()) {
h = body.outerHeight()+'px';
} else
w+= 20;
w += 'px';
body.css({
width: w,
height: h,
position: 'static',
overflow: 'hidden'
});
$('html').css({overflow: 'hidden'});
setCurrentSettings({
cssOpt: {
bg: {
position: 'absolute',
zIndex: currentSettings.zIndexStart+1,
height: '110%',
width: '110%',
top: currentSettings.marginScrollTop+'px',
left: currentSettings.marginScrollLeft+'px'
},
wrapper: { zIndex: currentSettings.zIndexStart+2 },
loading: { zIndex: currentSettings.zIndexStart+3 }
}
});
 
iframeHideIE = $('<iframe id="nyroModalIframeHideIe" src="javascript:\'\';"></iframe>')
.css($.extend({},
currentSettings.cssOpt.bg, {
opacity: 0,
zIndex: 50,
border: 'none'
}));
}
 
contain.append($('<div id="nyroModalFull"><div id="nyroModalBg"></div><div id="nyroModalWrapper"><div id="nyroModalContent"></div></div><div id="nyrModalTmp"></div><div id="nyroModalLoading"></div></div>').hide());
 
modal.full = $('#nyroModalFull')
.css(full)
.show();
modal.bg = $('#nyroModalBg')
.css($.extend({
backgroundColor: currentSettings.bgColor
}, currentSettings.cssOpt.bg))
.before(iframeHideIE);
modal.bg.on('click.nyroModal', clickBg);
modal.loading = $('#nyroModalLoading')
.css(currentSettings.cssOpt.loading)
.hide();
modal.contentWrapper = $('#nyroModalWrapper')
.css(currentSettings.cssOpt.wrapper)
.hide();
modal.content = $('#nyroModalContent');
modal.tmp = $('#nyrModalTmp').hide();
 
// To stop the mousewheel if the the plugin is available
if ($.isFunction($.fn.mousewheel)) {
modal.content.mousewheel(function(e, d) {
var elt = modal.content.get(0);
if ((d > 0 && elt.scrollTop == 0) ||
(d < 0 && elt.scrollHeight - elt.scrollTop == elt.clientHeight)) {
e.preventDefault();
e.stopPropagation();
}
});
}
 
$(document).on('keydown.nyroModal', keyHandler);
modal.content.css({width: 'auto', height: 'auto'});
modal.contentWrapper.css({width: 'auto', height: 'auto'});
 
if (!currentSettings.blocker && currentSettings.windowResize) {
$(window).on('resize.nyroModal', function() {
window.clearTimeout(windowResizeTimeout);
windowResizeTimeout = window.setTimeout(windowResizeHandler, 200);
});
}
}
}
 
function windowResizeHandler() {
$.nyroModalSettings(initSettingsSize);
}
 
// Show the modal (ie: the background and then the loading if needed or the content directly)
function showModal() {
debug('showModal');
if (!modal.ready) {
initModal();
modal.anim = true;
currentSettings.showBackground(modal, currentSettings, endBackground);
} else {
modal.anim = true;
modal.transition = true;
currentSettings.showTransition(modal, currentSettings, function(){endHideContent();modal.anim=false;showContentOrLoading();});
}
}
 
// Called when user click on background
function clickBg(e) {
if (!currentSettings.modal)
removeModal();
}
// Used for the escape key or the arrow in the gallery type
function keyHandler(e) {
if (e.keyCode == 27) {
if (!currentSettings.modal)
removeModal();
} else if (currentSettings.gallery && modal.ready && modal.dataReady && !modal.anim && !modal.transition) {
if (e.keyCode == 39 || e.keyCode == 40) {
e.preventDefault();
$.nyroModalNext();
return false;
} else if (e.keyCode == 37 || e.keyCode == 38) {
e.preventDefault();
$.nyroModalPrev();
return false;
}
}
}
 
// Determine the filetype regarding the link DOM element
function fileType() {
var from = currentSettings.from;
 
var url;
 
if (from && from.nodeName) {
var jFrom = $(from);
 
url = jFrom.attr(from.nodeName.toLowerCase() == 'form' ? 'action' : 'href');
if (!url)
url = location.href.substring(window.location.host.length+7);
currentSettings.url = url;
 
if (jFrom.attr('rev') == 'modal')
currentSettings.modal = true;
 
currentSettings.title = jFrom.attr('title');
 
if (from && from.rel && from.rel.toLowerCase() != 'nofollow') {
var indexSpace = from.rel.indexOf(' ');
currentSettings.gallery = indexSpace > 0 ? from.rel.substr(0, indexSpace) : from.rel;
}
 
var imgType = imageType(url, from);
if (imgType)
return imgType;
 
if (isSwf(url))
return 'swf';
 
var iframe = false;
if (from.target && from.target.toLowerCase() == '_blank' || (from.hostname && from.hostname.replace(/:\d*$/,'') != window.location.hostname.replace(/:\d*$/,''))) {
iframe = true;
}
if (from.nodeName.toLowerCase() == 'form') {
if (iframe)
return 'iframeForm';
setCurrentSettings(extractUrlSel(url));
if (jFrom.attr('enctype') == 'multipart/form-data')
return 'formData';
return 'form';
}
if (iframe)
return 'iframe';
} else {
url = currentSettings.url;
if (!currentSettings.content)
currentSettings.from = true;
 
if (!url)
return null;
 
if (isSwf(url))
return 'swf';
 
var reg1 = new RegExp("^http://|https://", "g");
if (url.match(reg1))
return 'iframe';
}
 
var imgType = imageType(url, from);
if (imgType)
return imgType;
 
var tmp = extractUrlSel(url);
setCurrentSettings(tmp);
 
if (!tmp.url)
return tmp.selector;
}
 
function imageType(url, from) {
var image = new RegExp(currentSettings.regexImg, 'i');
if (image.test(url)) {
return 'image';
}
}
 
function isSwf(url) {
var swf = new RegExp('[^\.]\.(swf)\s*$', 'i');
return swf.test(url);
}
 
function extractUrlSel(url) {
var ret = {
url: null,
selector: null
};
 
if (url) {
var hash = getHash(url);
var hashLoc = getHash(window.location.href);
var curLoc = window.location.href.substring(0, window.location.href.length - hashLoc.length);
var req = url.substring(0, url.length - hash.length);
 
if (req == curLoc || req == $('base').attr('href')) {
ret.selector = hash;
} else {
ret.url = req;
ret.selector = hash;
}
}
return ret;
}
 
// Called when the content cannot be loaded or tiemout reached
function loadingError() {
debug('loadingError');
 
modal.error = true;
 
if (!modal.ready)
return;
 
if ($.isFunction(currentSettings.handleError))
currentSettings.handleError(modal, currentSettings);
 
modal.loading
.addClass(currentSettings.errorClass)
.html(currentSettings.contentError);
$(currentSettings.closeSelector, modal.loading)
.off('click.nyroModal')
.on('click.nyroModal', removeModal);
setMarginLoading();
modal.loading
.css({
marginTop: currentSettings.marginTopLoading+'px',
marginLeft: currentSettings.marginLeftLoading+'px'
});
}
 
// Put the content from modal.tmp to modal.content
function fillContent() {
debug('fillContent');
if (!modal.tmp.html())
return;
 
modal.content.html(modal.tmp.contents());
modal.tmp.empty();
wrapContent();
 
if (currentSettings.type == 'iframeForm') {
$(currentSettings.from)
.attr('target', 'nyroModalIframe')
.data('nyroModalprocessing', 1)
.submit()
.attr('target', '_blank')
.removeData('nyroModalprocessing');
}
 
if (!currentSettings.modal)
modal.wrapper.prepend(currentSettings.closeButton);
 
if ($.isFunction(currentSettings.endFillContent))
currentSettings.endFillContent(modal, currentSettings);
 
modal.content.append(modal.scripts);
 
$(currentSettings.closeSelector, modal.contentWrapper)
.off('click.nyroModal')
.on('click.nyroModal', removeModal);
$(currentSettings.openSelector, modal.contentWrapper).nyroModal(getCurrentSettingsNew());
}
 
// Get the current settings to be used in new links
function getCurrentSettingsNew() {
return callingSettings;
/*
var currentSettingsNew = $.extend(true, {}, currentSettings);
if (resized.width)
currentSettingsNew.width = null;
else
currentSettingsNew.width = initSettingsSize.width;
if (resized.height)
currentSettingsNew.height = null;
else
currentSettingsNew.height = initSettingsSize.height;
currentSettingsNew.cssOpt.content.overflow = 'auto';
return currentSettingsNew;
*/
}
 
// Wrap the content and update the modal size if needed
function wrapContent() {
debug('wrapContent');
 
var wrap = $(currentSettings.wrap[currentSettings.type]);
modal.content.append(wrap.children().remove());
modal.contentWrapper.wrapInner(wrap);
 
if (currentSettings.gallery) {
// Set the action for the next and prev button (or remove them)
modal.content.append(currentSettings.galleryLinks);
 
gallery.links = $('[rel="'+currentSettings.gallery+'"], [rel^="'+currentSettings.gallery+' "]');
gallery.index = gallery.links.index(currentSettings.from);
 
if (currentSettings.galleryCounts && $.isFunction(currentSettings.galleryCounts))
currentSettings.galleryCounts(gallery.index + 1, gallery.links.length, modal, currentSettings);
 
var currentSettingsNew = getCurrentSettingsNew();
 
var linkPrev = getGalleryLink(-1);
if (linkPrev) {
var prev = $('.nyroModalPrev', modal.contentWrapper)
.attr('href', linkPrev.attr('href'))
.click(function(e) {
e.preventDefault();
$.nyroModalPrev();
return false;
});
if (isIE6 && currentSettings.type == 'swf') {
prev.before($('<iframe id="nyroModalIframeHideIeGalleryPrev" src="javascript:\'\';"></iframe>').css({
position: prev.css('position'),
top: prev.css('top'),
left: prev.css('left'),
width: prev.width(),
height: prev.height(),
opacity: 0,
border: 'none'
}));
}
} else {
$('.nyroModalPrev', modal.contentWrapper).remove();
}
var linkNext = getGalleryLink(1);
if (linkNext) {
var next = $('.nyroModalNext', modal.contentWrapper)
.attr('href', linkNext.attr('href'))
.click(function(e) {
e.preventDefault();
$.nyroModalNext();
return false;
});
if (isIE6 && currentSettings.type == 'swf') {
next.before($('<iframe id="nyroModalIframeHideIeGalleryNext" src="javascript:\'\';"></iframe>')
.css($.extend({}, {
position: next.css('position'),
top: next.css('top'),
left: next.css('left'),
width: next.width(),
height: next.height(),
opacity: 0,
border: 'none'
})));
}
} else {
$('.nyroModalNext', modal.contentWrapper).remove();
}
}
 
calculateSize();
}
 
function getGalleryLink(dir) {
if (currentSettings.gallery) {
if (!currentSettings.ltr)
dir *= -1;
var index = gallery.index + dir;
if (index >= 0 && index < gallery.links.length)
return gallery.links.eq(index);
else if (currentSettings.galleryLoop) {
if (index < 0)
return gallery.links.eq(gallery.links.length-1);
else
return gallery.links.eq(0);
}
}
return false;
}
 
// Calculate the size for the contentWrapper
function calculateSize(resizing) {
debug('calculateSize');
 
modal.wrapper = modal.contentWrapper.children('div:first');
 
resized.width = false;
resized.height = false;
if (false && !currentSettings.windowResizing) {
initSettingsSize.width = currentSettings.width;
initSettingsSize.height = currentSettings.height;
}
 
if (currentSettings.autoSizable && (!currentSettings.width || !currentSettings.height)) {
modal.contentWrapper
.css({
opacity: 0,
width: 'auto',
height: 'auto'
})
.show();
var tmp = {
width: 'auto',
height: 'auto'
};
if (currentSettings.width) {
tmp.width = currentSettings.width;
} else if (currentSettings.type == 'iframe') {
tmp.width = currentSettings.minWidth;
}
 
if (currentSettings.height) {
tmp.height = currentSettings.height;
} else if (currentSettings.type == 'iframe') {
tmp.height = currentSettings.minHeight;
}
 
modal.content.css(tmp);
if (!currentSettings.width) {
currentSettings.width = modal.content.outerWidth(true);
resized.width = true;
}
if (!currentSettings.height) {
currentSettings.height = modal.content.outerHeight(true);
resized.height = true;
}
modal.contentWrapper.css({opacity: 1});
if (!resizing)
modal.contentWrapper.hide();
}
 
if (currentSettings.type != 'image' && currentSettings.type != 'swf') {
currentSettings.width = Math.max(currentSettings.width, currentSettings.minWidth);
currentSettings.height = Math.max(currentSettings.height, currentSettings.minHeight);
}
 
var outerWrapper = getOuter(modal.contentWrapper);
var outerWrapper2 = getOuter(modal.wrapper);
var outerContent = getOuter(modal.content);
 
var tmp = {
content: {
width: currentSettings.width,
height: currentSettings.height
},
wrapper2: {
width: currentSettings.width + outerContent.w.total,
height: currentSettings.height + outerContent.h.total
},
wrapper: {
width: currentSettings.width + outerContent.w.total + outerWrapper2.w.total,
height: currentSettings.height + outerContent.h.total + outerWrapper2.h.total
}
};
 
if (currentSettings.resizable) {
var maxHeight = modal.blockerVars? modal.blockerVars.height : $(window).height()
- outerWrapper.h.border
- (tmp.wrapper.height - currentSettings.height);
var maxWidth = modal.blockerVars? modal.blockerVars.width : $(window).width()
- outerWrapper.w.border
- (tmp.wrapper.width - currentSettings.width);
maxHeight-= currentSettings.padding*2;
maxWidth-= currentSettings.padding*2;
 
if (tmp.content.height > maxHeight || tmp.content.width > maxWidth) {
// We're gonna resize the modal as it will goes outside the view port
if (currentSettings.type == 'image' || currentSettings.type == 'swf') {
// An image is resized proportionnaly
var useW = currentSettings.imgWidth?currentSettings.imgWidth : currentSettings.width;
var useH = currentSettings.imgHeight?currentSettings.imgHeight : currentSettings.height;
var diffW = tmp.content.width - useW;
var diffH = tmp.content.height - useH;
if (diffH < 0) diffH = 0;
if (diffW < 0) diffW = 0;
var calcH = maxHeight - diffH;
var calcW = maxWidth - diffW;
var ratio = Math.min(calcH/useH, calcW/useW);
calcW = Math.floor(useW*ratio);
calcH = Math.floor(useH*ratio);
tmp.content.height = calcH + diffH;
tmp.content.width = calcW + diffW;
} else {
// For an HTML content, we simply decrease the size
tmp.content.height = Math.min(tmp.content.height, maxHeight);
tmp.content.width = Math.min(tmp.content.width, maxWidth);
}
tmp.wrapper2 = {
width: tmp.content.width + outerContent.w.total,
height: tmp.content.height + outerContent.h.total
};
tmp.wrapper = {
width: tmp.content.width + outerContent.w.total + outerWrapper2.w.total,
height: tmp.content.height + outerContent.h.total + outerWrapper2.h.total
};
}
}
 
if (currentSettings.type == 'swf') {
$('object, embed', modal.content)
.attr('width', tmp.content.width)
.attr('height', tmp.content.height);
} else if (currentSettings.type == 'image') {
$('img', modal.content).css({
width: tmp.content.width,
height: tmp.content.height
});
}
 
modal.content.css($.extend({}, tmp.content, currentSettings.cssOpt.content));
modal.wrapper.css($.extend({}, tmp.wrapper2, currentSettings.cssOpt.wrapper2));
 
if (!resizing)
modal.contentWrapper.css($.extend({}, tmp.wrapper, currentSettings.cssOpt.wrapper));
 
if (currentSettings.type == 'image' && currentSettings.addImageDivTitle) {
// Adding the title for the image
$('img', modal.content).removeAttr('alt');
var divTitle = $('div', modal.content);
if (currentSettings.title != currentSettings.defaultImgAlt && currentSettings.title) {
if (divTitle.length == 0) {
divTitle = $('<div>'+currentSettings.title+'</div>');
modal.content.append(divTitle);
}
if (currentSettings.setWidthImgTitle) {
var outerDivTitle = getOuter(divTitle);
divTitle.css({width: (tmp.content.width + outerContent.w.padding - outerDivTitle.w.total)+'px'});
}
} else if (divTitle.length = 0) {
divTitle.remove();
}
}
 
if (currentSettings.title)
setTitle();
 
tmp.wrapper.borderW = outerWrapper.w.border;
tmp.wrapper.borderH = outerWrapper.h.border;
 
setCurrentSettings(tmp.wrapper);
setMargin();
}
 
function removeModal(e) {
debug('removeModal');
if (e)
e.preventDefault();
if (modal.full && modal.ready) {
$(document).off('keydown.nyroModal');
if (!currentSettings.blocker)
$(window).off('resize.nyroModal');
modal.ready = false;
modal.anim = true;
modal.closing = true;
if (modal.loadingShown || modal.transition) {
currentSettings.hideLoading(modal, currentSettings, function() {
modal.loading.hide();
modal.loadingShown = false;
modal.transition = false;
currentSettings.hideBackground(modal, currentSettings, endRemove);
});
} else {
if (fixFF)
modal.content.css({position: ''}); // Fix Issue #10, remove the attribute
modal.wrapper.css({overflow: 'hidden'}); // Used to fix a visual issue when hiding
modal.content.css({overflow: 'hidden'}); // Used to fix a visual issue when hiding
$('iframe', modal.content).hide(); // Fix issue 359
if ($.isFunction(currentSettings.beforeHideContent)) {
currentSettings.beforeHideContent(modal, currentSettings, function() {
currentSettings.hideContent(modal, currentSettings, function() {
endHideContent();
currentSettings.hideBackground(modal, currentSettings, endRemove);
});
});
} else {
currentSettings.hideContent(modal, currentSettings, function() {
endHideContent();
currentSettings.hideBackground(modal, currentSettings, endRemove);
});
}
}
}
if (e)
return false;
}
 
function showContentOrLoading() {
debug('showContentOrLoading');
if (modal.ready && !modal.anim) {
if (modal.dataReady) {
if (modal.tmp.html()) {
modal.anim = true;
if (modal.transition) {
fillContent();
modal.animContent = true;
currentSettings.hideTransition(modal, currentSettings, function() {
modal.loading.hide();
modal.transition = false;
modal.loadingShown = false;
endShowContent();
});
} else {
currentSettings.hideLoading(modal, currentSettings, function() {
modal.loading.hide();
modal.loadingShown = false;
fillContent();
setMarginLoading();
setMargin();
modal.animContent = true;
currentSettings.showContent(modal, currentSettings, endShowContent);
});
}
}
} else if (!modal.loadingShown && !modal.transition) {
modal.anim = true;
modal.loadingShown = true;
if (modal.error)
loadingError();
else
modal.loading.html(currentSettings.contentLoading);
$(currentSettings.closeSelector, modal.loading)
.off('click.nyroModal')
.on('click.nyroModal', removeModal);
setMarginLoading();
currentSettings.showLoading(modal, currentSettings, function(){modal.anim=false;showContentOrLoading();});
}
}
}
// -------------------------------------------------------
// Private Data Loaded callback
// -------------------------------------------------------
 
function ajaxLoaded(data) {
debug('AjaxLoaded: '+this.url);
if (currentSettings.selector) {
var tmp = {};
var i = 0;
// Looking for script to store them
data = data
.replace(/\r\n/gi,'nyroModalLN')
.replace(/<script(.|\s)*?\/script>/gi, function(x) {
tmp[i] = x;
return '<pre style="display: none" class=nyroModalScript rel="'+(i++)+'"></pre>';
});
data = $('<div>'+data+'</div>').find(currentSettings.selector).html()
.replace(/<pre style="display: none;?" class="?nyroModalScript"? rel="(.?)"><\/pre>/gi, function(x, y, z) {
return tmp[y];
})
.replace(/nyroModalLN/gi,"\r\n");
}
modal.tmp.html(filterScripts(data));
if (modal.tmp.html()) {
modal.dataReady = true;
showContentOrLoading();
} else
loadingError();
}
 
function formDataLoaded() {
debug('formDataLoaded');
var jFrom = $(currentSettings.from);
jFrom.attr('action', jFrom.attr('action')+currentSettings.selector);
jFrom.attr('target', '');
$('input[name='+currentSettings.formIndicator+']', currentSettings.from).remove();
var iframe = modal.tmp.children('iframe');
var iframeContent = iframe.off('load').contents().find(currentSettings.selector || 'body').not('script[src]');
iframe.attr('src', 'about:blank'); // Used to stop the loading in FF
modal.tmp.html(iframeContent.html());
if (modal.tmp.html()) {
modal.dataReady = true;
showContentOrLoading();
} else
loadingError();
}
function iframeLoaded() {
if ((window.location.hostname && currentSettings.url.indexOf(window.location.hostname) > -1)
|| currentSettings.url.indexOf('http://')) {
var iframe = $('iframe', modal.full).contents();
var tmp = {};
if (currentSettings.titleFromIframe) {
tmp.title = iframe.find('title').text();
if (!tmp.title) {
// for IE
try {
tmp.title = iframe.find('title').html();
} catch(err) {}
}
}
var body = iframe.find('body');
if (!currentSettings.height && body.height())
tmp.height = body.height();
if (!currentSettings.width && body.width())
tmp.width = body.width();
$.extend(initSettingsSize, tmp);
$.nyroModalSettings(tmp);
}
}
 
function galleryCounts(nb, total, elts, settings) {
if (total > 1)
settings.title+= (settings.title?' - ':'') +nb+'/'+total;
}
 
 
// -------------------------------------------------------
// Private Animation callback
// -------------------------------------------------------
 
function endHideContent() {
debug('endHideContent');
modal.anim = false;
if (contentEltLast) {
contentEltLast.append(modal.content.contents());
contentEltLast = null;
} else if (contentElt) {
contentElt.append(modal.content.contents());
contentElt= null;
}
modal.content.empty();
 
gallery = {};
 
modal.contentWrapper.hide().children().remove().empty().attr('style', '').hide();
 
if (modal.closing || modal.transition)
modal.contentWrapper.hide();
 
modal.contentWrapper
.css(currentSettings.cssOpt.wrapper)
.append(modal.content);
showContentOrLoading();
}
 
function endRemove() {
debug('endRemove');
$(document).off('keydown', keyHandler);
modal.anim = false;
modal.full.remove();
modal.full = null;
if (isIE6) {
body.css({height: '', width: '', position: '', overflow: '', marginLeft: '', marginRight: ''});
$('html').css({overflow: ''});
}
if ($.isFunction(currentSettings.endRemove))
currentSettings.endRemove(modal, currentSettings);
}
 
function endBackground() {
debug('endBackground');
modal.ready = true;
modal.anim = false;
showContentOrLoading();
}
 
function endShowContent() {
debug('endShowContent');
modal.anim = false;
modal.animContent = false;
modal.contentWrapper.css({opacity: ''}); // for the close button in IE
fixFF = /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent) && parseFloat(browserVersion) < 1.9 && currentSettings.type != 'image';
 
if (fixFF)
modal.content.css({position: 'fixed'}); // Fix Issue #10
modal.content.append(modal.scriptsShown);
 
if(currentSettings.type == 'iframe')
modal.content.find('iframe').attr('src', currentSettings.url);
 
if ($.isFunction(currentSettings.endShowContent))
currentSettings.endShowContent(modal, currentSettings);
 
if (shouldResize) {
shouldResize = false;
$.nyroModalSettings({width: currentSettings.setWidth, height: currentSettings.setHeight});
delete currentSettings['setWidth'];
delete currentSettings['setHeight'];
}
if (resized.width)
setCurrentSettings({width: null});
if (resized.height)
setCurrentSettings({height: null});
}
 
 
// -------------------------------------------------------
// Utilities
// -------------------------------------------------------
 
// Get the selector from an url (as string)
function getHash(url) {
if (typeof url == 'string') {
var hashPos = url.indexOf('#');
if (hashPos > -1)
return url.substring(hashPos);
}
return '';
}
 
// Filter an html content to remove the script[src]
function filterScripts(data) {
// Removing the body, head and html tag
if (typeof data == 'string')
data = data.replace(/<\/?(html|head|body)([^>]*)>/gi, '');
var tmp = new Array();
$.each($.clean({0:data}, this.ownerDocument), function() {
if ($.nodeName(this, "script")) {
if (!this.src || $(this).attr('rel') == 'forceLoad') {
if ($(this).attr('rev') == 'shown')
modal.scriptsShown.push(this);
else
modal.scripts.push(this);
}
} else
tmp.push(this);
});
return tmp;
}
 
// Get the vertical and horizontal margin, padding and border dimension
function getOuter(elm) {
elm = elm.get(0);
var ret = {
h: {
margin: getCurCSS(elm, 'marginTop') + getCurCSS(elm, 'marginBottom'),
border: getCurCSS(elm, 'borderTopWidth') + getCurCSS(elm, 'borderBottomWidth'),
padding: getCurCSS(elm, 'paddingTop') + getCurCSS(elm, 'paddingBottom')
},
w: {
margin: getCurCSS(elm, 'marginLeft') + getCurCSS(elm, 'marginRight'),
border: getCurCSS(elm, 'borderLeftWidth') + getCurCSS(elm, 'borderRightWidth'),
padding: getCurCSS(elm, 'paddingLeft') + getCurCSS(elm, 'paddingRight')
}
};
 
ret.h.outer = ret.h.margin + ret.h.border;
ret.w.outer = ret.w.margin + ret.w.border;
 
ret.h.inner = ret.h.padding + ret.h.border;
ret.w.inner = ret.w.padding + ret.w.border;
 
ret.h.total = ret.h.outer + ret.h.padding;
ret.w.total = ret.w.outer + ret.w.padding;
 
return ret;
}
 
function getCurCSS(elm, name) {
var ret = parseInt($.css(elm, name, true));
if (isNaN(ret))
ret = 0;
return ret;
}
 
// Proxy Debug function
function debug(msg) {
if ($.fn.nyroModal.settings.debug || currentSettings && currentSettings.debug)
nyroModalDebug(msg, modal, currentSettings || {});
}
 
// -------------------------------------------------------
// Default animation function
// -------------------------------------------------------
 
function showBackground(elts, settings, callback) {
elts.bg.css({opacity:0}).fadeTo(500, 0.75, callback);
}
 
function hideBackground(elts, settings, callback) {
elts.bg.fadeOut(300, callback);
}
 
function showLoading(elts, settings, callback) {
elts.loading
.css({
marginTop: settings.marginTopLoading+'px',
marginLeft: settings.marginLeftLoading+'px',
opacity: 0
})
.show()
.animate({
opacity: 1
}, {complete: callback, duration: 400});
}
 
function hideLoading(elts, settings, callback) {
callback();
}
 
function showContent(elts, settings, callback) {
elts.loading
.css({
marginTop: settings.marginTopLoading+'px',
marginLeft: settings.marginLeftLoading+'px'
})
.show()
.animate({
width: settings.width+'px',
height: settings.height+'px',
marginTop: settings.marginTop+'px',
marginLeft: settings.marginLeft+'px'
}, {duration: 350, complete: function() {
elts.contentWrapper
.css({
width: settings.width+'px',
height: settings.height+'px',
marginTop: settings.marginTop+'px',
marginLeft: settings.marginLeft+'px'
})
.show();
elts.loading.fadeOut(200, callback);
}
});
}
 
function hideContent(elts, settings, callback) {
elts.contentWrapper
.animate({
height: '50px',
width: '50px',
marginTop: (-(25+settings.borderH)/2 + settings.marginScrollTop)+'px',
marginLeft: (-(25+settings.borderW)/2 + settings.marginScrollLeft)+'px'
}, {duration: 350, complete: function() {
elts.contentWrapper.hide();
callback();
}});
}
 
function showTransition(elts, settings, callback) {
// Put the loading with the same dimensions of the current content
elts.loading
.css({
marginTop: elts.contentWrapper.css('marginTop'),
marginLeft: elts.contentWrapper.css('marginLeft'),
height: elts.contentWrapper.css('height'),
width: elts.contentWrapper.css('width'),
opacity: 0
})
.show()
.fadeTo(400, 1, function() {
elts.contentWrapper.hide();
callback();
});
}
 
function hideTransition(elts, settings, callback) {
// Place the content wrapper underneath the the loading with the right dimensions
elts.contentWrapper
.hide()
.css({
width: settings.width+'px',
height: settings.height+'px',
marginLeft: settings.marginLeft+'px',
marginTop: settings.marginTop+'px',
opacity: 1
});
elts.loading
.animate({
width: settings.width+'px',
height: settings.height+'px',
marginLeft: settings.marginLeft+'px',
marginTop: settings.marginTop+'px'
}, {complete: function() {
elts.contentWrapper.show();
elts.loading.fadeOut(400, function() {
elts.loading.hide();
callback();
});
}, duration: 350});
}
 
function resize(elts, settings, callback) {
elts.contentWrapper
.animate({
width: settings.width+'px',
height: settings.height+'px',
marginLeft: settings.marginLeft+'px',
marginTop: settings.marginTop+'px'
}, {complete: callback, duration: 400});
}
 
function updateBgColor(elts, settings, callback) {
if (!$.fx.step.backgroundColor) {
elts.bg.css({backgroundColor: settings.bgColor});
callback();
} else
elts.bg
.animate({
backgroundColor: settings.bgColor
}, {complete: callback, duration: 400});
}
 
// -------------------------------------------------------
// Default initialization
// -------------------------------------------------------
 
$($.fn.nyroModal.settings.openSelector).nyroModal();
 
});
 
// Default debug function, to be overwritten if needed
// Be aware that the settings parameter could be empty
var tmpDebug = '';
function nyroModalDebug(msg, elts, settings) {
if (elts.full && elts.bg) {
elts.bg.prepend(msg+'<br />'+tmpDebug);
tmpDebug = '';
} else
tmpDebug+= msg+'<br />';
}
/web/acc/phpsysinfo/js/jQuery/jquery.timer.js
0,0 → 1,74
/*
*
* jQuery Timer plugin v0.1
* Matt Schmidt [http://www.mattptr.net]
*
* Licensed under the MIT License
*
*/
jQuery.timer = function (interval, callback)
{
/**
*
* timer() provides a cleaner way to handle intervals
*
* @usage
* $.timer(interval, callback);
*
*
* @example
* $.timer(1000, function (timer) {
* alert("hello");
* timer.stop();
* });
* @desc Show an alert box after 1 second and stop
*
* @example
* var second = false;
* $.timer(1000, function (timer) {
* if (!second) {
* alert('First time!');
* second = true;
* timer.reset(3000);
* }
* else {
* alert('Second time');
* timer.stop();
* }
* });
* @desc Show an alert box after 1 second and show another after 3 seconds
*
*
*/
 
var interval = interval || 100;
 
if (!callback)
return false;
_timer = function (interval, callback) {
this.stop = function () {
clearInterval(self.id);
};
this.internalCallback = function () {
callback(self);
};
this.reset = function (val) {
if (self.id)
clearInterval(self.id);
var val = val || 100;
this.id = setInterval(this.internalCallback, val);
};
this.interval = interval;
this.id = setInterval(this.internalCallback, this.interval);
var self = this;
};
return new _timer(interval, callback);
};
/web/acc/phpsysinfo/js/jQuery/jquery.treeTable.js
0,0 → 1,130
/*
Copyright: Paul Hanlon
version 2009-06-22+statefix+spanfix+altfix+undefinedfix+ie6cachefix+multilinefix+divfix
Released under the MIT/BSD licence which means you can do anything you want
with it, as long as you keep this copyright notice on the page
*/
(function(jq){
jq.fn.jqTreeTable=function(map, options){
var opts = jq.extend({openImg:"",shutImg:"",leafImg:"",lastOpenImg:"",lastShutImg:"",lastLeafImg:"",vertLineImg:"",blankImg:"",collapse:false,column:0,striped:false,highlight:false,state:true},options),
mapa=[],mapb=[],tid=this.attr("id"),collarr=[],
stripe=function(){
if(opts.striped){
$("#"+tid+" tr:not(.collapsed)").filter(":even").addClass("even").removeClass("odd").end().filter(":odd").removeClass("even").addClass("odd");
}
},
buildText = function(parno, preStr){//Recursively build up the text for the images that make it work
var mp=mapa[parno], ro=0, pre="", pref, img;
if (mp!==undefined) for (var y=0,yl=mp.length;y<yl;y++){
ro = mp[y];
if (mapa[ro]){//It's a parent as well. Build it's string and move on to it's children
pre=(y==yl-1)? opts.blankImg: opts.vertLineImg;
img=(y==yl-1)? opts.lastOpenImg: opts.openImg;
mapb[ro-1] = preStr + '<span class="treeimg" style="background-image: url(\''+pre+'\')"><div style="background-image: url(\''+img+'\')" class="parimg" id="'+tid+ro+'"'+(img=(y==yl-1)? ' last=1': '')+'></div></span>';
pref = preStr + '<span class="treeimg preimg" style="background-image: url(\''+pre+'\')"></span>';
arguments.callee(ro, pref);
}else{//it's a child
pre=(y==yl-1)? opts.blankImg: opts.vertLineImg;
img = (y==yl-1)? opts.lastLeafImg: opts.leafImg;//It's the last child, It's child will have a blank field behind it
mapb[ro-1] = preStr + '<span class="treeimg" style="background-image: url(\''+pre+'\')"><div style="background-image: url(\''+img+'\')" class="ttimage" id="'+tid+ro+'"></div></span>';
}
}
},
expandKids = function(num, last){//Expands immediate children, and their uncollapsed children
jq("#"+tid+num).css('background-image', "url('"+((last)? opts.lastOpenImg: opts.openImg)+"')");
for (var x=0, xl=mapa[num].length;x<xl;x++){
var mnx = mapa[num][x];
jq("#"+tid+mnx).parents("tr").removeClass("collapsed");
if (mapa[mnx] && opts.state && jq.inArray(mnx, collarr)<0){////If it is a parent and its number is not in the collapsed array
arguments.callee(mnx,(x==xl-1));//Expand it. More intuitive way of displaying the tree
}
}
},
collapseKids = function(num, last){//Recursively collapses all children and their children and change icon
if (mapa[num]){
jq("#"+tid+num).css('background-image', "url('"+((last)? opts.lastShutImg: opts.shutImg)+"')");
for (var x=0, xl=mapa[num].length;x<xl;x++){
var mnx = mapa[num][x];
jq("#"+tid+mnx).parents("tr").addClass("collapsed");
if (mapa[mnx]){//If it is a parent
arguments.callee(mnx,(x==xl-1));
}
}
}
},
creset = function(num, exp){//Resets the collapse array
var o = (exp)? collarr.splice(jq.inArray(num, collarr), 1): collarr.push(num);
cset(tid,collarr);
},
cget = function(n){
var v='',c=' '+document.cookie+';',s=c.indexOf(' '+n+'=');
if (s>=0) {
s+=n.length+2;
v=(c.substring(s,c.indexOf(';',s))).split("|");
}
return v||[];
},
cset = function (n,v) {
v = arrUniq(v);
document.cookie = n+"="+v.join("|")+";";
},
arrUniq = function(a) {/* http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/ */
var o = {}, i, l = a.length, r = [];
for(i=0; i<l;i++) o[a[i]] = a[i];
for(i in o) r.push(o[i]);
return r;
};
 
try { //ie6 flickering fix
document.execCommand("BackgroundImageCache", false, true);
} catch(err) {}
 
for (var x=0,xl=map.length; x<xl;x++){//From map of parents, get map of kids
num = map[x];
if (!mapa[num]){
mapa[num]=[];
}
mapa[num].push(x+1);
}
buildText(0,"");
jq("tbody tr", this).each(function(i){//Inject the images into the column to make it work
jq(this).children("td").eq(opts.column).children("div").prepend(mapb[i]);
});
if(opts.state) collarr = cget(tid);
if (!collarr.length){
if(opts.collapse.constructor == Array) {
collarr=collarr.concat(opts.collapse);
if ((collarr.length) && (opts.state)){
cset(tid,collarr);
}
}
}
if (collarr.length){
for (var y=0,yl=collarr.length;y<yl;y++){
collapseKids(collarr[y], $("#"+tid+collarr[y]+ ".parimg").attr("last")==1);
}
}
stripe();
jq(".parimg", this).each(function(i){
var jqt = jq(this),last;
jqt.click(function(){
var num = parseInt(jqt.attr("id").substr(tid.length));//Number of the row
if (jqt.parents("tr").next().is(".collapsed")){//If the table row directly below is collapsed
expandKids(num, jqt.attr("last")==1);//Then expand all children not in collarr
if(opts.state){creset(num,true);}//If state is set, store in cookie
}else{//Collapse all and set image to opts.shutImg or opts.lastShutImg on parents
collapseKids(num, jqt.attr("last")==1);
if(opts.state){creset(num,false);}//If state is set, store in cookie
}
stripe();//Restripe the rows
});
});
if (opts.highlight){//This is where it highlights the rows
jq("tr", this).hover(
function(){jq(this).addClass("over");},
function(){jq(this).removeClass("over");}
);
};
};
return this;
})(jQuery);
/web/acc/phpsysinfo/js/jQuery/jquery.treegrid.js
0,0 → 1,626
/*
* jQuery treegrid Plugin 0.3.0
* https://github.com/maxazan/jquery-treegrid
*
* Copyright 2013, Pomazan Max
* Licensed under the MIT licenses.
*/
(function($) {
 
var methods = {
/**
* Initialize tree
*
* @param {Object} options
* @returns {Object[]}
*/
initTree: function(options) {
var settings = $.extend({}, this.treegrid.defaults, options);
return this.each(function() {
var $this = $(this);
$this.treegrid('setTreeContainer', $(this));
$this.treegrid('setSettings', settings);
settings.getRootNodes.apply(this, [$(this)]).treegrid('initNode', settings);
$this.treegrid('getRootNodes').treegrid('render');
});
},
/**
* Initialize node
*
* @param {Object} settings
* @returns {Object[]}
*/
initNode: function(settings) {
return this.each(function() {
var $this = $(this);
$this.treegrid('setTreeContainer', settings.getTreeGridContainer.apply(this));
$this.treegrid('getChildNodes').treegrid('initNode', settings);
$this.treegrid('initExpander').treegrid('initIndent').treegrid('initEvents').treegrid('initState').treegrid('initChangeEvent').treegrid("initSettingsEvents");
});
},
initChangeEvent: function() {
var $this = $(this);
//Save state on change
$this.on("change", function() {
var $this = $(this);
$this.treegrid('render');
if ($this.treegrid('getSetting', 'saveState')) {
$this.treegrid('saveState');
}
});
return $this;
},
/**
* Initialize node events
*
* @returns {Node}
*/
initEvents: function() {
var $this = $(this);
//Default behavior on collapse
$this.on("collapse", function() {
var $this = $(this);
$this.removeClass('treegrid-expanded');
$this.addClass('treegrid-collapsed');
});
//Default behavior on expand
$this.on("expand", function() {
var $this = $(this);
$this.removeClass('treegrid-collapsed');
$this.addClass('treegrid-expanded');
});
 
return $this;
},
/**
* Initialize events from settings
*
* @returns {Node}
*/
initSettingsEvents: function() {
var $this = $(this);
//Save state on change
$this.on("change", function() {
var $this = $(this);
if (typeof($this.treegrid('getSetting', 'onChange')) === "function") {
$this.treegrid('getSetting', 'onChange').apply($this);
}
});
//Default behavior on collapse
$this.on("collapse", function() {
var $this = $(this);
if (typeof($this.treegrid('getSetting', 'onCollapse')) === "function") {
$this.treegrid('getSetting', 'onCollapse').apply($this);
}
});
//Default behavior on expand
$this.on("expand", function() {
var $this = $(this);
if (typeof($this.treegrid('getSetting', 'onExpand')) === "function") {
$this.treegrid('getSetting', 'onExpand').apply($this);
}
 
});
 
return $this;
},
/**
* Initialize expander for node
*
* @returns {Node}
*/
initExpander: function() {
var $this = $(this);
var cell = $this.find('td').get($this.treegrid('getSetting', 'treeColumn'));
var tpl = $this.treegrid('getSetting', 'expanderTemplate');
var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
if (expander) {
expander.remove();
}
$(tpl).prependTo(cell).click(function() {
$($(this).closest('tr')).treegrid('toggle');
});
return $this;
},
/**
* Initialize indent for node
*
* @returns {Node}
*/
initIndent: function() {
var $this = $(this);
$this.find('.treegrid-indent').remove();
var tpl = $this.treegrid('getSetting', 'indentTemplate');
var expander = $this.find('.treegrid-expander');
var depth = $this.treegrid('getDepth');
for (var i = 0; i < depth; i++) {
$(tpl).insertBefore(expander);
}
return $this;
},
/**
* Initialise state of node
*
* @returns {Node}
*/
initState: function() {
var $this = $(this);
if ($this.treegrid('getSetting', 'saveState') && !$this.treegrid('isFirstInit')) {
$this.treegrid('restoreState');
} else {
if ($this.treegrid('getSetting', 'initialState') === "expanded") {
$this.treegrid('expand');
} else {
$this.treegrid('collapse');
}
}
return $this;
},
/**
* Return true if this tree was never been initialised
*
* @returns {Boolean}
*/
isFirstInit: function() {
var tree = $(this).treegrid('getTreeContainer');
if (tree.data('first_init') === undefined) {
tree.data('first_init', $.cookie(tree.treegrid('getSetting', 'saveStateName')) === undefined);
}
return tree.data('first_init');
},
/**
* Save state of current node
*
* @returns {Node}
*/
saveState: function() {
var $this = $(this);
if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') {
 
var stateArrayString = $.cookie($this.treegrid('getSetting', 'saveStateName')) || '';
var stateArray = (stateArrayString === '' ? [] : stateArrayString.split(','));
var nodeId = $this.treegrid('getNodeId');
 
if ($this.treegrid('isExpanded')) {
if ($.inArray(nodeId, stateArray) === -1) {
stateArray.push(nodeId);
}
} else if ($this.treegrid('isCollapsed')) {
if ($.inArray(nodeId, stateArray) !== -1) {
stateArray.splice($.inArray(nodeId, stateArray), 1);
}
}
$.cookie($this.treegrid('getSetting', 'saveStateName'), stateArray.join(','));
}
return $this;
},
/**
* Restore state of current node.
*
* @returns {Node}
*/
restoreState: function() {
var $this = $(this);
if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') {
var stateArray = $.cookie($this.treegrid('getSetting', 'saveStateName')).split(',');
if ($.inArray($this.treegrid('getNodeId'), stateArray) !== -1) {
$this.treegrid('expand');
} else {
$this.treegrid('collapse');
}
 
}
return $this;
},
/**
* Method return setting by name
*
* @param {type} name
* @returns {unresolved}
*/
getSetting: function(name) {
if (!$(this).treegrid('getTreeContainer')) {
return null;
}
return $(this).treegrid('getTreeContainer').data('settings')[name];
},
/**
* Add new settings
*
* @param {Object} settings
*/
setSettings: function(settings) {
$(this).treegrid('getTreeContainer').data('settings', settings);
},
/**
* Return tree container
*
* @returns {HtmlElement}
*/
getTreeContainer: function() {
return $(this).data('treegrid');
},
/**
* Set tree container
*
* @param {HtmlE;ement} container
*/
setTreeContainer: function(container) {
return $(this).data('treegrid', container);
},
/**
* Method return all root nodes of tree.
*
* Start init all child nodes from it.
*
* @returns {Array}
*/
getRootNodes: function() {
return $(this).treegrid('getSetting', 'getRootNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
},
/**
* Method return all nodes of tree.
*
* @returns {Array}
*/
getAllNodes: function() {
return $(this).treegrid('getSetting', 'getAllNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
},
/**
* Mthod return true if element is Node
*
* @returns {String}
*/
isNode: function() {
return $(this).treegrid('getNodeId') !== null;
},
/**
* Mthod return id of node
*
* @returns {String}
*/
getNodeId: function() {
if ($(this).treegrid('getSetting', 'getNodeId') === null) {
return null;
} else {
return $(this).treegrid('getSetting', 'getNodeId').apply(this);
}
},
/**
* Method return parent id of node or null if root node
*
* @returns {String}
*/
getParentNodeId: function() {
return $(this).treegrid('getSetting', 'getParentNodeId').apply(this);
},
/**
* Method return parent node or null if root node
*
* @returns {Object[]}
*/
getParentNode: function() {
if ($(this).treegrid('getParentNodeId') === null) {
return null;
} else {
return $(this).treegrid('getSetting', 'getNodeById').apply(this, [$(this).treegrid('getParentNodeId'), $(this).treegrid('getTreeContainer')]);
}
},
/**
* Method return array of child nodes or null if node is leaf
*
* @returns {Object[]}
*/
getChildNodes: function() {
return $(this).treegrid('getSetting', 'getChildNodes').apply(this, [$(this).treegrid('getNodeId'), $(this).treegrid('getTreeContainer')]);
},
/**
* Method return depth of tree.
*
* This method is needs for calculate indent
*
* @returns {Number}
*/
getDepth: function() {
if ($(this).treegrid('getParentNode') === null) {
return 0;
}
return $(this).treegrid('getParentNode').treegrid('getDepth') + 1;
},
/**
* Method return true if node is root
*
* @returns {Boolean}
*/
isRoot: function() {
return $(this).treegrid('getDepth') === 0;
},
/**
* Method return true if node has no child nodes
*
* @returns {Boolean}
*/
isLeaf: function() {
return $(this).treegrid('getChildNodes').length === 0;
},
/**
* Method return true if node last in branch
*
* @returns {Boolean}
*/
isLast: function() {
if ($(this).treegrid('isNode')) {
var parentNode = $(this).treegrid('getParentNode');
if (parentNode === null) {
if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').last().treegrid('getNodeId')) {
return true;
}
} else {
if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').last().treegrid('getNodeId')) {
return true;
}
}
}
return false;
},
/**
* Method return true if node first in branch
*
* @returns {Boolean}
*/
isFirst: function() {
if ($(this).treegrid('isNode')) {
var parentNode = $(this).treegrid('getParentNode');
if (parentNode === null) {
if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').first().treegrid('getNodeId')) {
return true;
}
} else {
if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').first().treegrid('getNodeId')) {
return true;
}
}
}
return false;
},
/**
* Return true if node expanded
*
* @returns {Boolean}
*/
isExpanded: function() {
return $(this).hasClass('treegrid-expanded');
},
/**
* Return true if node collapsed
*
* @returns {Boolean}
*/
isCollapsed: function() {
return $(this).hasClass('treegrid-collapsed');
},
/**
* Return true if at least one of parent node is collapsed
*
* @returns {Boolean}
*/
isOneOfParentsCollapsed: function() {
var $this = $(this);
if ($this.treegrid('isRoot')) {
return false;
} else {
if ($this.treegrid('getParentNode').treegrid('isCollapsed')) {
return true;
} else {
return $this.treegrid('getParentNode').treegrid('isOneOfParentsCollapsed');
}
}
},
/**
* Expand node
*
* @returns {Node}
*/
expand: function() {
if (!this.treegrid('isLeaf') && !this.treegrid("isExpanded")) {
this.trigger("expand");
this.trigger("change");
return this;
}
return this;
},
/**
* Expand all nodes
*
* @returns {Node}
*/
expandAll: function() {
var $this = $(this);
$this.treegrid('getRootNodes').treegrid('expandRecursive');
return $this;
},
/**
* Expand current node and all child nodes begin from current
*
* @returns {Node}
*/
expandRecursive: function() {
return $(this).each(function() {
var $this = $(this);
$this.treegrid('expand');
if (!$this.treegrid('isLeaf')) {
$this.treegrid('getChildNodes').treegrid('expandRecursive');
}
});
},
/**
* Collapse node
*
* @returns {Node}
*/
collapse: function() {
return $(this).each(function() {
var $this = $(this);
if (!$this.treegrid('isLeaf') && !$this.treegrid("isCollapsed")) {
$this.trigger("collapse");
$this.trigger("change");
}
});
},
/**
* Collapse all nodes
*
* @returns {Node}
*/
collapseAll: function() {
var $this = $(this);
$this.treegrid('getRootNodes').treegrid('collapseRecursive');
return $this;
},
/**
* Collapse current node and all child nodes begin from current
*
* @returns {Node}
*/
collapseRecursive: function() {
return $(this).each(function() {
var $this = $(this);
$this.treegrid('collapse');
if (!$this.treegrid('isLeaf')) {
$this.treegrid('getChildNodes').treegrid('collapseRecursive');
}
});
},
/**
* Expand if collapsed, Collapse if expanded
*
* @returns {Node}
*/
toggle: function() {
var $this = $(this);
if ($this.treegrid('isExpanded')) {
$this.treegrid('collapse');
} else {
$this.treegrid('expand');
}
return $this;
},
/**
* Rendering node
*
* @returns {Node}
*/
render: function() {
return $(this).each(function() {
var $this = $(this);
//if parent colapsed we hidden
if ($this.treegrid('isOneOfParentsCollapsed')) {
$this.hide();
} else {
$this.show();
}
if (!$this.treegrid('isLeaf')) {
$this.treegrid('renderExpander');
$this.treegrid('getChildNodes').treegrid('render');
}
});
},
/**
* Rendering expander depends on node state
*
* @returns {Node}
*/
renderExpander: function() {
return $(this).each(function() {
var $this = $(this);
var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
if (expander) {
 
if (!$this.treegrid('isCollapsed')) {
expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass'));
} else {
expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass'));
expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
}
} else {
$this.treegrid('initExpander');
$this.treegrid('renderExpander');
}
});
}
};
$.fn.treegrid = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.initTree.apply(this, arguments);
} else {
$.error('Method with name ' + method + ' does not exists for jQuery.treegrid');
}
};
/**
* Plugin's default options
*/
$.fn.treegrid.defaults = {
initialState: 'expanded',
saveState: false,
saveStateMethod: 'cookie',
saveStateName: 'tree-grid-state',
expanderTemplate: '<span class="treegrid-expander"></span>',
indentTemplate: '<span class="treegrid-indent"></span>',
expanderExpandedClass: 'treegrid-expander-expanded',
expanderCollapsedClass: 'treegrid-expander-collapsed',
treeColumn: 0,
getExpander: function() {
return $(this).find('.treegrid-expander');
},
getNodeId: function() {
var template = /treegrid-([A-Za-z0-9_-]+)/;
if (template.test($(this).attr('class'))) {
return template.exec($(this).attr('class'))[1];
}
return null;
},
getParentNodeId: function() {
var template = /treegrid-parent-([A-Za-z0-9_-]+)/;
if (template.test($(this).attr('class'))) {
return template.exec($(this).attr('class'))[1];
}
return null;
},
getNodeById: function(id, treegridContainer) {
var templateClass = "treegrid-" + id;
return treegridContainer.find('tr.' + templateClass);
},
getChildNodes: function(id, treegridContainer) {
var templateClass = "treegrid-parent-" + id;
return treegridContainer.find('tr.' + templateClass);
},
getTreeGridContainer: function() {
return $(this).closest('table');
},
getRootNodes: function(treegridContainer) {
var result = $.grep(treegridContainer.find('tr'), function(element) {
var classNames = $(element).attr('class');
var templateClass = /treegrid-([A-Za-z0-9_-]+)/;
var templateParentClass = /treegrid-parent-([A-Za-z0-9_-]+)/;
return templateClass.test(classNames) && !templateParentClass.test(classNames);
});
return $(result);
},
getAllNodes: function(treegridContainer) {
var result = $.grep(treegridContainer.find('tr'), function(element) {
var classNames = $(element).attr('class');
var templateClass = /treegrid-([A-Za-z0-9_-]+)/;
return templateClass.test(classNames);
});
return $(result);
},
//Events
onCollapse: null,
onExpand: null,
onChange: null
 
};
})(jQuery);
/web/acc/phpsysinfo/xml.php
0,0 → 1,55
<?php
header('Access-Control-Allow-Origin: *');
/**
* generate the xml
*
* PHP version 5
*
* @category PHP
* @package PSI_XML
* @author Michael Cramer <BigMichi1@users.sourceforge.net>
* @copyright 2009 phpSysInfo
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License version 2, or (at your option) any later version
* @version SVN: $Id: xml.php 614 2012-07-28 09:02:59Z jacky672 $
* @link http://phpsysinfo.sourceforge.net
*/
 
/**
* application root path
*
* @var string
*/
define('PSI_APP_ROOT', dirname(__FILE__));
 
require_once PSI_APP_ROOT.'/includes/autoloader.inc.php';
 
if ((isset($_GET['json']) || isset($_GET['jsonp'])) && !extension_loaded("json")) {
echo '<Error Message="The json extension to php required!" Function="ERROR"/>';
} else {
// check what xml part should be generated
if (isset($_GET['plugin'])) {
if (($_GET['plugin'] !== "") && !preg_match('/[^A-Za-z]/', $_GET['plugin'])) {
$output = new WebpageXML($_GET['plugin']);
} else {
unset($output);
}
} else {
$output = new WebpageXML();
}
// if $output is correct generate output in proper type
if (isset($output) && is_object($output)) {
if (isset($_GET['json']) || isset($_GET['jsonp'])) {
header("Cache-Control: no-cache, must-revalidate\n");
$json = $output->getJsonString();
if (isset($_GET['jsonp'])) {
header("Content-Type: application/javascript\n\n");
echo (!preg_match('/[^\w\?]/', $_GET['callback'])?$_GET['callback']:'') . '('.$json.')';
} else {
header("Content-Type: application/json\n\n");
echo $json;
}
} else {
$output->run();
}
}
}