/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('"','"') ); |
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: '×', |
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/js/phpSysInfo/phpsysinfo.js |
---|
0,0 → 1,1993 |
/*************************************************************************** |
* Copyright (C) 2008 by phpSysInfo - A PHP System Information Script * |
* http://phpsysinfo.sourceforge.net/ * |
* * |
* This program is free software; you can redistribute it and/or modify * |
* it under the terms of the GNU General Public License as published by * |
* the Free Software Foundation; either version 2 of the License, or * |
* (at your option) any later version. * |
* * |
* This program 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 * |
* GNU General Public License for more details. * |
* * |
* You should have received a copy of the GNU General Public License * |
* along with this program; if not, write to the * |
* Free Software Foundation, Inc., * |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
***************************************************************************/ |
// |
// $Id: phpsysinfo.js 699 2012-09-15 11:57:13Z namiltd $ |
// |
/*global $, jQuery */ |
"use strict"; |
var langxml = [], filesystemTable, current_language = "", plugin_liste = [], blocks = [], langarr = [], |
showCPUListExpanded, showCPUInfoExpanded, showNetworkInfosExpanded, showMemoryInfosExpanded, showNetworkActiveSpeed, showCPULoadCompact, oldnetwork = []; |
/** |
* Fix PNG loading on IE6 or below |
*/ |
function PNGload(png) { |
if (typeof(png.ifixpng)==='function') { //IE6 PNG fix |
png.ifixpng('./gfx/blank.gif'); |
} |
} |
/** |
* generate a cookie, if not exist, and add an entry to it<br><br> |
* inspired by <a href="http://www.quirksmode.org/js/cookies.html">http://www.quirksmode.org/js/cookies.html</a> |
* @param {String} name name that holds the value |
* @param {String} value value that needs to be stored |
* @param {Number} days how many days the entry should be valid in the cookie |
*/ |
function createCookie(name, value, days) { |
var date = new Date(), expires = ""; |
if (days) { |
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); |
if (typeof(date.toUTCString)==="function") { |
expires = "; expires=" + date.toUTCString(); |
} else { |
//deprecated |
expires = "; expires=" + date.toGMTString(); |
} |
} else { |
expires = ""; |
} |
document.cookie = name + "=" + value + expires + "; path=/"; |
} |
/** |
* read a value out of a cookie and return the value<br><br> |
* inspired by <a href="http://www.quirksmode.org/js/cookies.html">http://www.quirksmode.org/js/cookies.html</a> |
* @param {String} name name of the value that should be retrieved |
* @return {String} |
*/ |
function readCookie(name) { |
var nameEQ = "", ca = [], c = '', i = 0; |
nameEQ = name + "="; |
ca = document.cookie.split(';'); |
for (i = 0; i < ca.length; i++) { |
c = ca[i]; |
while (c.charAt(0) === ' ') { |
c = c.substring(1, c.length); |
} |
if (!c.indexOf(nameEQ)) { |
return c.substring(nameEQ.length, c.length); |
} |
} |
return null; |
} |
/** |
* round a given value to the specified precision, difference to Math.round() is that there |
* will be appended Zeros to the end if the precision is not reached (0.1 gets rounded to 0.100 when precision is set to 3) |
* @param {Number} x value to round |
* @param {Number} n precision |
* @return {String} |
*/ |
function round(x, n) { |
var e = 0, k = ""; |
if (n < 0 || n > 14) { |
return 0; |
} |
if (n === 0) { |
return Math.round(x); |
} else { |
e = Math.pow(10, n); |
k = (Math.round(x * e) / e).toString(); |
if (k.indexOf('.') === -1) { |
k += '.'; |
} |
k += e.toString().substring(1); |
return k.substring(0, k.indexOf('.') + n + 1); |
} |
} |
/** |
* activates a given style and disables the old one in the document |
* @param {String} template template that should be activated |
*/ |
function switchStyle(template) { |
$('link[rel*=style][title]').each(function getTitle(i) { |
if (this.getAttribute('title') === 'PSI_Template') { |
this.setAttribute('href', './templates/' + template + ".css"); |
} |
}); |
} |
/** |
* load the given translation an translate the entire page<br><br>retrieving the translation is done through a |
* ajax call |
* @private |
* @param {String} plugin if plugin is given, the plugin translation file will be read instead of the main translation file |
* @param {String} langarrId internal plugin name |
* @return {jQuery} translation jQuery-Object |
*/ |
function getLanguage(plugin, langarrId) { |
var getLangUrl = ""; |
if (current_language) { |
getLangUrl = 'language/language.php?lang=' + current_language; |
if (plugin) { |
getLangUrl += "&plugin=" + plugin; |
} |
} else { |
getLangUrl = 'language/language.php'; |
if (plugin) { |
getLangUrl += "?plugin=" + plugin; |
} |
} |
$.ajax({ |
url: getLangUrl, |
type: 'GET', |
dataType: 'xml', |
timeout: 100000, |
error: function error() { |
$.jGrowl("Error loading language - " + getLangUrl); |
}, |
success: function buildblocks(xml) { |
var idexp; |
langxml[langarrId] = xml; |
if (langarr[langarrId] === undefined) { |
langarr.push(langarrId); |
langarr[langarrId] = []; |
} |
$("expression", langxml[langarrId]).each(function langstore(id) { |
idexp = $("expression", xml).get(id); |
langarr[langarrId][this.getAttribute('id')] = $("exp", idexp).text().toString().replace(/\//g, "/<wbr>"); |
}); |
changeSpanLanguage(plugin); |
} |
}); |
} |
/** |
* generate a span tag |
* @param {Number} id translation id in the xml file |
* @param {String} [plugin] name of the plugin for which the tag should be generated |
* @return {String} string which contains generated span tag for translation string |
*/ |
function genlang(id, plugin) { |
var html = "", idString = "", plugname = "", |
langarrId = current_language + "_"; |
if (plugin === undefined) { |
plugname = ""; |
langarrId += "phpSysInfo"; |
} else { |
plugname = plugin.toLowerCase(); |
langarrId += plugname; |
} |
if (id < 100) { |
if (id < 10) { |
idString = "00" + id.toString(); |
} else { |
idString = "0" + id.toString(); |
} |
} else { |
idString = id.toString(); |
} |
if (plugin) { |
idString = "plugin_" + plugname + "_" + idString; |
} |
html += "<span class=\"lang_" + idString + "\">"; |
if ((langxml[langarrId] !== undefined) && (langarr[langarrId] !== undefined)) { |
html += langarr[langarrId][idString]; |
} |
html += "</span>"; |
return html; |
} |
/** |
* translates all expressions based on the translation xml file<br> |
* translation expressions must be in the format <span class="lang_???"></span>, where ??? is |
* the number of the translated expression in the xml file<br><br>if a translated expression is not found in the xml |
* file nothing would be translated, so the initial value which is inside the span tag is displayed |
* @param {String} [plugin] name of the plugin |
*/ |
function changeLanguage(plugin) { |
var langarrId = current_language + "_"; |
if (plugin === undefined) { |
langarrId += "phpSysInfo"; |
} else { |
langarrId += plugin; |
} |
if (langxml[langarrId] !== undefined) { |
changeSpanLanguage(plugin); |
} else { |
langxml.push(langarrId); |
getLanguage(plugin, langarrId); |
} |
} |
function changeSpanLanguage(plugin) { |
var langId = "", langStr = "", langarrId = current_language + "_"; |
if (plugin === undefined) { |
langarrId += "phpSysInfo"; |
$('span[class*=lang_]').each(function translate(i) { |
langId = this.className.substring(5); |
if (langId.indexOf('plugin_') !== 0) { //does not begin with plugin_ |
langStr = langarr[langarrId][langId]; |
if (langStr !== undefined) { |
if (langStr.length > 0) { |
this.innerHTML = langStr; |
} |
} |
} |
}); |
$("#loader").hide(); |
$("#output").fadeIn("slow"); //show if any language loaded |
} else { |
langarrId += plugin; |
$('span[class*=lang_plugin_'+plugin.toLowerCase()+'_]').each(function translate(i) { |
langId = this.className.substring(5); |
langStr = langarr[langarrId][langId]; |
if (langStr !== undefined) { |
if (langStr.length > 0) { |
this.innerHTML = langStr; |
} |
} |
}); |
$('#panel_'+plugin).show(); //show plugin if any language loaded |
} |
} |
/** |
* generate the filesystemTable and activate the dataTables plugin on it |
*/ |
function filesystemtable() { |
var html = ""; |
html += "<h2>" + genlang(30) + "</h2>\n"; |
html += " <div style=\"overflow-x:auto;\">\n"; |
html += " <table id=\"filesystemTable\" style=\"border-collapse:collapse;\">\n"; |
html += " <thead>\n"; |
html += " <tr>\n"; |
html += " <th>" + genlang(31) + "</th>\n"; |
html += " <th>" + genlang(34) + "</th>\n"; |
html += " <th>" + genlang(32) + "</th>\n"; |
html += " <th>" + genlang(33) + "</th>\n"; |
html += " <th class=\"right\">" + genlang(35) + "</th>\n"; |
html += " <th class=\"right\">" + genlang(36) + "</th>\n"; |
html += " <th class=\"right\">" + genlang(37) + "</th>\n"; |
html += " </tr>\n"; |
html += " </thead>\n"; |
html += " <tfoot>\n"; |
html += " <tr style=\"font-weight : bold\">\n"; |
html += " <td> </td>\n"; |
html += " <td> </td>\n"; |
html += " <td>" + genlang(38) + "</td>\n"; |
html += " <td id=\"s_fs_total\"></td>\n"; |
html += " <td class=\"right\"><span id=\"s_fs_tfree\"></span></td>\n"; |
html += " <td class=\"right\"><span id=\"s_fs_tused\"></span></td>\n"; |
html += " <td class=\"right\"><span id=\"s_fs_tsize\"></span></td>\n"; |
html += " </tr>\n"; |
html += " </tfoot>\n"; |
html += " <tbody>\n"; |
html += " </tbody>\n"; |
html += " </table>\n"; |
html += " </div>\n"; |
$("#filesystem").append(html); |
filesystemTable = $("#filesystemTable").dataTable({ |
"bPaginate": false, |
"bLengthChange": false, |
"bFilter": false, |
"bSort": true, |
"bInfo": false, |
"bProcessing": true, |
"bAutoWidth": false, |
"bStateSave": true, |
"aoColumns": [{ |
"sType": 'span-string', |
"sWidth": "100px" |
}, { |
"sType": 'span-string', |
"sWidth": "50px" |
}, { |
"sType": 'span-string', |
"sWidth": "200px" |
}, { |
"sType": 'span-number' |
}, { |
"sType": 'span-number', |
"sWidth": "80px", |
"sClass": "right" |
}, { |
"sType": 'span-number', |
"sWidth": "80px", |
"sClass": "right" |
}, { |
"sType": 'span-number', |
"sWidth": "80px", |
"sClass": "right" |
}] |
}); |
} |
/** |
* fill all errors from the xml in the error div element in the document and show the error icon |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function populateErrors(xml) { |
var values = false; |
$("Errors Error", xml).each(function getError(id) { |
// $("#errorlist").append("<b>" + $(this).attr("Function") + "</b><br><br><pre>" + $(this).text() + "</pre><hr>"); |
$("#errorlist").append("<b>" + $(this).attr("Function") + "</b><br><br><pre>" + $(this).attr("Message") + "</pre><hr>"); |
values = true; |
}); |
if (values) { |
$("#warn").css("display", "inline"); |
$("#loadwarn").css("display", "inline"); |
} |
} |
/** |
* show the page |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function displayPage(xml) { |
var versioni = ""; |
// $("#loader").hide(); |
// $("#output").fadeIn("slow"); |
versioni = $("Generation", xml).attr("version").toString(); |
$("#version").html(versioni); |
} |
/** |
* format seconds to a better readable statement with days, hours and minutes |
* @param {Number} sec seconds that should be formatted |
* @return {String} html string with no breaking spaces and translation statements |
*/ |
function formatUptime(sec) { |
var txt = "", intMin = 0, intHours = 0, intDays = 0; |
intMin = sec / 60; |
intHours = intMin / 60; |
intDays = Math.floor(intHours / 24); |
intHours = Math.floor(intHours - (intDays * 24)); |
intMin = Math.floor(intMin - (intDays * 60 * 24) - (intHours * 60)); |
if (intDays) { |
txt += intDays.toString() + " " + genlang(48) + " "; |
} |
if (intHours) { |
txt += intHours.toString() + " " + genlang(49) + " "; |
} |
return txt + intMin.toString() + " " + genlang(50); |
} |
/** |
* format a given MHz value to a better readable statement with the right suffix |
* @param {Number} mhertz mhertz value that should be formatted |
* @return {String} html string with no breaking spaces and translation statements |
*/ |
function formatHertz(mhertz) { |
if ((mhertz >= 0) && (mhertz < 1000)) { |
return mhertz.toString() + " " + genlang(92); |
} else { |
if (mhertz >= 1000) { |
return round(mhertz / 1000, 2) + " " + genlang(93); |
} else { |
return ""; |
} |
} |
} |
/** |
* format the byte values into a user friendly value with the corespondenting unit expression<br>support is included |
* for binary and decimal output<br>user can specify a constant format for all byte outputs or the output is formated |
* automatically so that every value can be read in a user friendly way |
* @param {Number} bytes value that should be converted in the corespondenting format, which is specified in the phpsysinfo.ini |
* @param {jQuery} xml phpSysInfo-XML |
* @return {String} string of the converted bytes with the translated unit expression |
*/ |
function formatBytes(bytes, xml) { |
var byteFormat = "", show = ""; |
$("Options", xml).each(function getByteFormat(id) { |
byteFormat = $(this).attr("byteFormat"); |
}); |
switch (byteFormat.toLowerCase()) { |
case "pib": |
show += round(bytes / Math.pow(1024, 5), 2); |
show += " " + genlang(90); |
break; |
case "tib": |
show += round(bytes / Math.pow(1024, 4), 2); |
show += " " + genlang(86); |
break; |
case "gib": |
show += round(bytes / Math.pow(1024, 3), 2); |
show += " " + genlang(87); |
break; |
case "mib": |
show += round(bytes / Math.pow(1024, 2), 2); |
show += " " + genlang(88); |
break; |
case "kib": |
show += round(bytes / Math.pow(1024, 1), 2); |
show += " " + genlang(89); |
break; |
case "pb": |
show += round(bytes / Math.pow(1000, 5), 2); |
show += " " + genlang(91); |
break; |
case "tb": |
show += round(bytes / Math.pow(1000, 4), 2); |
show += " " + genlang(85); |
break; |
case "gb": |
show += round(bytes / Math.pow(1000, 3), 2); |
show += " " + genlang(41); |
break; |
case "mb": |
show += round(bytes / Math.pow(1000, 2), 2); |
show += " " + genlang(40); |
break; |
case "kb": |
show += round(bytes / Math.pow(1000, 1), 2); |
show += " " + genlang(39); |
break; |
case "b": |
show += bytes; |
show += " " + genlang(96); |
break; |
case "auto_decimal": |
if (bytes > Math.pow(1000, 5)) { |
show += round(bytes / Math.pow(1000, 5), 2); |
show += " " + genlang(91); |
} else { |
if (bytes > Math.pow(1000, 4)) { |
show += round(bytes / Math.pow(1000, 4), 2); |
show += " " + genlang(85); |
} else { |
if (bytes > Math.pow(1000, 3)) { |
show += round(bytes / Math.pow(1000, 3), 2); |
show += " " + genlang(41); |
} else { |
if (bytes > Math.pow(1000, 2)) { |
show += round(bytes / Math.pow(1000, 2), 2); |
show += " " + genlang(40); |
} else { |
if (bytes > Math.pow(1000, 1)) { |
show += round(bytes / Math.pow(1000, 1), 2); |
show += " " + genlang(39); |
} else { |
show += bytes; |
show += " " + genlang(96); |
} |
} |
} |
} |
} |
break; |
default: |
if (bytes > Math.pow(1024, 5)) { |
show += round(bytes / Math.pow(1024, 5), 2); |
show += " " + genlang(90); |
} else { |
if (bytes > Math.pow(1024, 4)) { |
show += round(bytes / Math.pow(1024, 4), 2); |
show += " " + genlang(86); |
} else { |
if (bytes > Math.pow(1024, 3)) { |
show += round(bytes / Math.pow(1024, 3), 2); |
show += " " + genlang(87); |
} else { |
if (bytes > Math.pow(1024, 2)) { |
show += round(bytes / Math.pow(1024, 2), 2); |
show += " " + genlang(88); |
} else { |
if (bytes > Math.pow(1024, 1)) { |
show += round(bytes / Math.pow(1024, 1), 2); |
show += " " + genlang(89); |
} else { |
show += bytes; |
show += " " + genlang(96); |
} |
} |
} |
} |
} |
} |
return show; |
} |
function formatBPS(bps) { |
var show = ""; |
if (bps > Math.pow(1000, 5)) { |
show += round(bps / Math.pow(1000, 5), 2); |
show += String.fromCharCode(160) + 'Pb/s'; |
} else { |
if (bps > Math.pow(1000, 4)) { |
show += round(bps / Math.pow(1000, 4), 2); |
show += String.fromCharCode(160) + 'Tb/s'; |
} else { |
if (bps > Math.pow(1000, 3)) { |
show += round(bps / Math.pow(1000, 3), 2); |
show += String.fromCharCode(160) + 'Gb/s'; |
} else { |
if (bps > Math.pow(1000, 2)) { |
show += round(bps / Math.pow(1000, 2), 2); |
show += String.fromCharCode(160) + 'Mb/s'; |
} else { |
if (bps > Math.pow(1000, 1)) { |
show += round(bps / Math.pow(1000, 1), 2); |
show += String.fromCharCode(160) + 'Kb/s'; |
} else { |
show += bps; |
show += String.fromCharCode(160) + 'b/s'; |
} |
} |
} |
} |
} |
return show; |
} |
/** |
* format a celcius temperature to fahrenheit and also append the right suffix |
* @param {String} degreeC temperature in celvius |
* @param {jQuery} xml phpSysInfo-XML |
* @return {String} html string with no breaking spaces and translation statements |
*/ |
function formatTemp(degreeC, xml) { |
var tempFormat = "", degree = 0; |
$("Options", xml).each(function getOptions(id) { |
tempFormat = $(this).attr("tempFormat").toString().toLowerCase(); |
}); |
degree = parseFloat(degreeC); |
if (isNaN(degreeC)) { |
return "---"; |
} else { |
switch (tempFormat) { |
case "f": |
return round((((9 * degree) / 5) + 32), 1) + " " + genlang(61); |
case "c": |
return round(degree, 1) + " " + genlang(60); |
case "c-f": |
return round(degree, 1) + " " + genlang(60) + "<br><i>(" + round((((9 * degree) / 5) + 32), 1) + " " + genlang(61) + ")</i>"; |
case "f-c": |
return round((((9 * degree) / 5) + 32), 1) + " " + genlang(61) + "<br><i>(" + round(degree, 1) + " " + genlang(60) + ")</i>"; |
} |
} |
} |
/** |
* create a visual HTML bar from a given size, the layout of that bar can be costumized through the bar css-class |
* @param {Number} size barclass |
* @return {String} HTML string which contains the full layout of the bar |
*/ |
function createBar(size, barclass) { |
if (barclass === undefined) { |
barclass = "bar"; |
} |
return "<div class=\"" + barclass + "\" style=\"float:left; width: " + Math.max(Math.min(Math.round(size), 100), 0) + "px;\"> </div> " + size + "%"; |
} |
/** |
* (re)fill the vitals block with the values from the given xml |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshVitals(xml) { |
var hostname = "", ip = ""; |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('vitals', blocks) < 0))) { |
$("#vitals").remove(); |
$("Vitals", xml).each(function getVitals(id) { |
hostname = $(this).attr("Hostname"); |
ip = $(this).attr("IPAddr"); |
document.title = "System information: " + hostname + " (" + ip + ")"; |
$("#s_hostname_title").html(hostname); |
$("#s_ip_title").html(ip); |
}); |
return; |
} |
var kernel = "", distro = "", icon = "", uptime = "", users = 0, loadavg = "", os = ""; |
var processes = 0, prunning = 0, psleeping = 0, pstopped = 0, pzombie = 0, pwaiting = 0, pother = 0; |
var syslang = "", codepage = ""; |
var lastboot = 0; |
var timestamp = parseInt($("Generation", xml).attr("timestamp"), 10)*1000; //server time |
var not_first = false; |
var datetimeFormat = ""; |
if (isNaN(timestamp)) timestamp = Number(new Date()); //client time |
$("Options", xml).each(function getDatetimeFormat(id) { |
datetimeFormat = $(this).attr("datetimeFormat"); |
}); |
$("Vitals", xml).each(function getVitals(id) { |
hostname = $(this).attr("Hostname"); |
ip = $(this).attr("IPAddr"); |
kernel = $(this).attr("Kernel"); |
distro = $(this).attr("Distro"); |
icon = $(this).attr("Distroicon"); |
os = $(this).attr("OS"); |
uptime = formatUptime(parseInt($(this).attr("Uptime"), 10)); |
lastboot = new Date(timestamp - (parseInt($(this).attr("Uptime"), 10)*1000)); |
users = parseInt($(this).attr("Users"), 10); |
loadavg = $(this).attr("LoadAvg"); |
if ($(this).attr("CPULoad") !== undefined) { |
loadavg = loadavg + "<br>" + createBar(parseInt($(this).attr("CPULoad"), 10)); |
} |
if ($(this).attr("SysLang") !== undefined) { |
syslang = $(this).attr("SysLang"); |
document.getElementById("s_syslang_tr").style.display=''; |
} |
if ($(this).attr("CodePage") !== undefined) { |
codepage = $(this).attr("CodePage"); |
if ($(this).attr("SysLang") !== undefined) { |
document.getElementById("s_codepage_tr1").style.display=''; |
} else { |
document.getElementById("s_codepage_tr2").style.display=''; |
} |
} |
//processes |
if ($(this).attr("Processes") !== undefined) { |
processes = parseInt($(this).attr("Processes"), 10); |
if ((($(this).attr("CodePage") !== undefined) && ($(this).attr("SysLang") === undefined)) || |
(($(this).attr("CodePage") === undefined) && ($(this).attr("SysLang") !== undefined))) { |
document.getElementById("s_processes_tr1").style.display=''; |
} else { |
document.getElementById("s_processes_tr2").style.display=''; |
} |
} |
if ($(this).attr("ProcessesRunning") !== undefined) { |
prunning = parseInt($(this).attr("ProcessesRunning"), 10); |
} |
if ($(this).attr("ProcessesSleeping") !== undefined) { |
psleeping = parseInt($(this).attr("ProcessesSleeping"), 10); |
} |
if ($(this).attr("ProcessesStopped") !== undefined) { |
pstopped = parseInt($(this).attr("ProcessesStopped"), 10); |
} |
if ($(this).attr("ProcessesZombie") !== undefined) { |
pzombie = parseInt($(this).attr("ProcessesZombie"), 10); |
} |
if ($(this).attr("ProcessesWaiting") !== undefined) { |
pwaiting = parseInt($(this).attr("ProcessesWaiting"), 10); |
} |
if ($(this).attr("ProcessesOther") !== undefined) { |
pother = parseInt($(this).attr("ProcessesOther"), 10); |
} |
document.title = "System information: " + hostname + " (" + ip + ")"; |
$("#s_hostname_title").html(hostname); |
$("#s_ip_title").html(ip); |
$("#s_hostname").html(hostname); |
$("#s_ip").html(ip); |
$("#s_kernel").html(kernel); |
$("#s_distro").html("<img src='./gfx/images/" + icon + "' alt='Icon' title='' style='width:16px;height:16px;vertical-align:middle;' onload='PNGload($(this));' /> " + distro); //onload IE6 PNG fix |
$("#s_os").html("<img src='./gfx/images/" + os + ".png' alt='OSIcon' title='' style='width:16px;height:16px;vertical-align:middle;' onload='PNGload($(this));' /> " + os); //onload IE6 PNG fix |
$("#s_uptime").html(uptime); |
if ((datetimeFormat !== undefined) && (datetimeFormat.toLowerCase() === "locale")) { |
$("#s_lastboot").html(lastboot.toLocaleString()); |
} else { |
if (typeof(lastboot.toUTCString)==="function") { |
$("#s_lastboot").html(lastboot.toUTCString()); |
} else { |
//deprecated |
$("#s_lastboot").html(lastboot.toGMTString()); |
} |
} |
$("#s_users").html(users); |
$("#s_loadavg").html(loadavg); |
$("#s_syslang").html(syslang); |
$("#s_codepage_1").html(codepage); |
$("#s_codepage_2").html(codepage); |
$("#s_processes_1").html(processes); |
$("#s_processes_2").html(processes); |
if (prunning || psleeping || pstopped || pzombie || pwaiting || pother) { |
$("#s_processes_1").append(" ("); |
$("#s_processes_2").append(" ("); |
var typelist = {running:111,sleeping:112,stopped:113,zombie:114,waiting:115,other:116}; |
for (var proc_type in typelist) { |
if (eval("p" + proc_type)) { |
if (not_first) { |
$("#s_processes_1").append(", "); |
$("#s_processes_2").append(", "); |
} |
$("#s_processes_1").append(eval("p" + proc_type) + " " + genlang(typelist[proc_type])); |
$("#s_processes_2").append(eval("p" + proc_type) + " " + genlang(typelist[proc_type])); |
not_first = true; |
} |
} |
$("#s_processes_1").append(") "); |
$("#s_processes_2").append(") "); |
} |
}); |
} |
/** |
* build the cpu information as table rows |
* @param {jQuery} xml phpSysInfo-XML |
* @param {Array} tree array that holds the positions for treetable plugin |
* @param {Number} rootposition position of the parent element |
* @param {Array} collapsed array that holds all collapsed elements hwne opening page |
*/ |
function fillCpu(xml, tree, rootposition, collapsed) { |
var cpucount = 0, html = ""; |
$("Hardware CPU CpuCore", xml).each(function getCpuCore(cpuCoreId) { |
var model = "", speed = 0, bus = 0, cache = 0, bogo = 0, temp = 0, load = 0, speedmax = 0, speedmin = 0, cpucoreposition = 0, virt = "", manufacturer = ""; |
cpucount++; |
model = $(this).attr("Model"); |
speed = parseInt($(this).attr("CpuSpeed"), 10); |
speedmax = parseInt($(this).attr("CpuSpeedMax"), 10); |
speedmin = parseInt($(this).attr("CpuSpeedMin"), 10); |
cache = parseInt($(this).attr("Cache"), 10); |
virt = $(this).attr("Virt"); |
bus = parseInt($(this).attr("BusSpeed"), 10); |
temp = parseInt($(this).attr("Cputemp"), 10); |
bogo = parseInt($(this).attr("Bogomips"), 10); |
manufacturer = $(this).attr("Manufacturer"); |
load = parseInt($(this).attr("Load"), 10); |
if (!showCPUListExpanded) { |
collapsed.push(rootposition); |
} |
if (!isNaN(load) && showCPULoadCompact) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + model + "</span></div></td><td>" + createBar(load) + "</td></tr>\n"; |
} else { |
html += "<tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespan\">" + model + "</span></div></td></tr>\n"; |
} |
cpucoreposition = tree.push(rootposition); |
if (!showCPUInfoExpanded) { |
collapsed.push(cpucoreposition); |
} |
if (!isNaN(speed)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(13) + ":</span></div></td><td>" + formatHertz(speed) + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
if (!isNaN(speedmax)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(100) + ":</span></div></td><td>" + formatHertz(speedmax) + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
if (!isNaN(speedmin)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(101) + ":</span></div></td><td>" + formatHertz(speedmin) + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
if (!isNaN(cache)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(15) + ":</span></div></td><td>" + formatBytes(cache, xml) + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
if (virt !== undefined) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(94) + ":</span></div></td><td>" + virt + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
if (!isNaN(bus)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(14) + ":</span></div></td><td>" + formatHertz(bus) + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
if (!isNaN(bogo)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(16) + ":</span></div></td><td>" + bogo.toString() + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
/* |
if (!isNaN(temp)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(51) + ":</span></div></td><td>" + formatTemp(temp, xml) + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
*/ |
if (manufacturer !== undefined) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(122) + ":</span></div></td><td>" + manufacturer + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
if (!isNaN(load) && !showCPULoadCompact) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(9) + ":</span></div></td><td>" + createBar(load) + "</td></tr>\n"; |
tree.push(cpucoreposition); |
} |
}); |
if (cpucount === 0) { |
html += "<tr><td colspan=\"2\">" + genlang(42) + "</td></tr>\n"; |
tree.push(rootposition); |
} |
return html; |
} |
function countCpu(xml) { |
var cpucount = 0; |
$("Hardware CPU CpuCore", xml).each(function getCpuCore(cpuCoreId) { |
cpucount++; |
}); |
return cpucount; |
} |
/** |
* build rows for a treetable out of the hardwaredevices |
* @param {jQuery} xml phpSysInfo-XML |
* @param {String} type type of the hardware device |
* @param {Array} tree array that holds the positions for treetable plugin |
* @param {Number} rootposition position of the parent element |
*/ |
function fillHWDevice(xml, type, tree, rootposition) { |
var devicecount = 0, html = ""; |
$("Hardware " + type + " Device", xml).each(function getHWDevice(deviceId) { |
var name = "", count = 0, capacity = 0, manufacturer = "", product = "", serial = "", devcoreposition = 0; |
devicecount++; |
name = $(this).attr("Name"); |
capacity = parseInt($(this).attr("Capacity"), 10); |
manufacturer = $(this).attr("Manufacturer"); |
product = $(this).attr("Product"); |
serial = $(this).attr("Serial"); |
count = parseInt($(this).attr("Count"), 10); |
if (!isNaN(count) && count > 1) { |
name = "(" + count + "x) " + name; |
} |
html += "<tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespan\">" + name + "</span></div></td></tr>\n"; |
devcoreposition = tree.push(rootposition); |
if (!isNaN(capacity)) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(43) + ":</span></div></td><td>" + formatBytes(capacity, xml) + "</td></tr>\n"; |
tree.push(devcoreposition); |
} |
if (manufacturer!== undefined) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(122) + ":</span></div></td><td>" + manufacturer + "</td></tr>\n"; |
tree.push(devcoreposition); |
} |
if (product !== undefined) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(123) + ":</span></div></td><td>" + product + "</td></tr>\n"; |
tree.push(devcoreposition); |
} |
if (serial !== undefined) { |
html += "<tr><td style=\"width:68%\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(124) + ":</span></div></td><td>" + serial + "</td></tr>\n"; |
tree.push(devcoreposition); |
} |
}); |
if (devicecount === 0) { |
html += "<tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(42) + "</span></div></td></tr>\n"; |
tree.push(rootposition); |
} |
return html; |
} |
function countHWDevice(xml, type) { |
var devicecount = 0; |
$("Hardware " + type + " Device", xml).each(function getHWDevice(deviceId) { |
devicecount++; |
}); |
return devicecount; |
} |
/** |
* (re)fill the hardware block with the values from the given xml |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshHardware(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('hardware', blocks) < 0))) { |
$("#hardware").remove(); |
return; |
} |
var html = "", tree = [], closed = [], index = 0, machine = ""; |
$("#hardware").empty(); |
html += "<h2>" + genlang(10) + "</h2>\n"; |
html += " <div style=\"overflow-x:auto;\">\n"; |
html += " <table id=\"HardwareTree\" class=\"tablemain\">\n"; |
html += " <tbody class=\"tree\">\n"; |
$("Hardware", xml).each(function getMachine(id) { |
machine = $(this).attr("Name"); |
}); |
if ((machine !== undefined) && (machine !== "")) { |
html += " <tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespanbold\">" + genlang(107) + "</span></div></td></tr>\n"; |
html += "<tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespan\">" + machine + "</span></div></td></tr>\n"; |
tree.push(tree.push(0)); |
} |
if (countCpu(xml)) { |
html += " <tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespanbold\">" + genlang(11) + "</span></div></td></tr>\n"; |
html += fillCpu(xml, tree, tree.push(0), closed); |
} |
var typelist = {PCI:17,IDE:18,SCSI:19,NVMe:126,USB:20,TB:117,I2C:118}; |
for (var dev_type in typelist) { |
if (countHWDevice(xml, dev_type)) { |
html += " <tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespanbold\">" + genlang(typelist[dev_type]) + "</span></div></td></tr>\n"; |
index = tree.push(0); |
closed.push(index); |
html += fillHWDevice(xml, dev_type, tree, index); |
} |
} |
html += " </tbody>\n"; |
html += " </table>\n"; |
html += " </div>\n"; |
$("#hardware").append(html); |
$("#HardwareTree").jqTreeTable(tree, { |
openImg: "./gfx/treeTable/tv-collapsable.gif", |
shutImg: "./gfx/treeTable/tv-expandable.gif", |
leafImg: "./gfx/treeTable/tv-item.gif", |
lastOpenImg: "./gfx/treeTable/tv-collapsable-last.gif", |
lastShutImg: "./gfx/treeTable/tv-expandable-last.gif", |
lastLeafImg: "./gfx/treeTable/tv-item-last.gif", |
vertLineImg: "./gfx/treeTable/vertline.gif", |
blankImg: "./gfx/treeTable/blank.gif", |
collapse: closed, |
column: 0, |
striped: true, |
highlight: false, |
state: false |
}); |
} |
/** |
*(re)fill the network block with the values from the given xml |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshNetwork(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('network', blocks) < 0))) { |
$("#network").remove(); |
return; |
} |
var tree = [], closed = [], html0= "", html1= "" ,html = "", isinfo = false, preoldnetwork = [], timestamp; |
$("#network").empty(); |
html0 += "<h2>" + genlang(21) + "</h2>\n"; |
html1 += " <thead>\n"; |
html1 += " <tr>\n"; |
html1 += " <th>" + genlang(22) + "</th>\n"; |
html1 += " <th class=\"right\" style=\"width:50px;\">" + genlang(23) + "</th>\n"; |
html1 += " <th class=\"right\" style=\"width:50px;\">" + genlang(24) + "</th>\n"; |
html1 += " <th class=\"right\" style=\"width:50px;\">" + genlang(25) + "</th>\n"; |
html1 += " </tr>\n"; |
html1 += " </thead>\n"; |
if (showNetworkActiveSpeed) { |
$("Generation", xml).each(function getTimestamp(id) { |
timestamp = $(this).attr("timestamp"); |
}); |
} |
$("Network NetDevice", xml).each(function getDevice(id) { |
var name = "", rx = 0, tx = 0, er = 0, dr = 0, info = "", networkindex = 0, htmlrx = '', htmltx = ''; |
name = $(this).attr("Name"); |
rx = parseInt($(this).attr("RxBytes"), 10); |
tx = parseInt($(this).attr("TxBytes"), 10); |
er = parseInt($(this).attr("Err"), 10); |
dr = parseInt($(this).attr("Drops"), 10); |
if (showNetworkActiveSpeed && ($.inArray(name, oldnetwork) >= 0)) { |
var diff, difftime; |
if (((diff = rx - oldnetwork[name].rx) > 0) && ((difftime = timestamp - oldnetwork[name].timestamp) > 0)) { |
if (showNetworkActiveSpeed == 2) { |
htmlrx ="<br><i>("+formatBPS(round(8*diff/difftime, 2))+")</i>"; |
} else { |
htmlrx ="<br><i>("+formatBytes(round(diff/difftime, 2), xml)+"/s)</i>"; |
} |
} |
if (((diff = tx - oldnetwork[name].tx) > 0) && (difftime > 0)) { |
if (showNetworkActiveSpeed == 2) { |
htmltx ="<br><i>("+formatBPS(round(8*diff/difftime, 2))+")</i>"; |
} else { |
htmltx ="<br><i>("+formatBytes(round(diff/difftime, 2), xml)+"/s)</i>"; |
} |
} |
} |
html +="<tr><td><div class=\"treediv\"><span class=\"treespan\">" + name + "</span></div></td><td class=\"right\">" + formatBytes(rx, xml) + htmlrx + "</td><td class=\"right\">" + formatBytes(tx, xml) + htmltx +"</td><td class=\"right\">" + er.toString() + "/<wbr>" + dr.toString() + "</td></tr>"; |
networkindex = tree.push(0); |
if (showNetworkActiveSpeed) { |
preoldnetwork.pushIfNotExist(name); |
preoldnetwork[name] = {timestamp:timestamp, rx:rx, tx:tx}; |
} |
info = $(this).attr("Info"); |
if ( (info !== undefined) && (info !== "") ) { |
var i = 0, infos = info.replace(/:/g, "<wbr>:").split(";"); /* split long addresses */ |
isinfo = true; |
for(i = 0; i < infos.length; i++){ |
html +="<tr><td colspan=\"4\"><div class=\"treediv\"><span class=\"treespan\">" + infos[i] + "</span></div></td></tr>"; |
tree.push(networkindex); |
} |
if (!showNetworkInfosExpanded) { |
closed.push(networkindex); |
} |
} |
}); |
html += " </tbody>\n"; |
html += " </table>\n"; |
html += "</div>\n"; |
html0 += "<div style=\"overflow-x:auto;\">\n"; |
if (isinfo) { |
html0 += " <table id=\"NetworkTree\" class=\"tablemain\">\n"; |
html1 += " <tbody class=\"tree\">\n"; |
} else { |
html0 += " <table id=\"NetworkTree\" class=\"stripeMe\" style=\"border-collapse:collapse;\">\n"; |
html1 += " <tbody class=\"tbody_network\">\n"; |
} |
$("#network").append(html0+html1+html); |
if (isinfo) $("#NetworkTree").jqTreeTable(tree, { |
openImg: "./gfx/treeTable/tv-collapsable.gif", |
shutImg: "./gfx/treeTable/tv-expandable.gif", |
leafImg: "./gfx/treeTable/tv-item.gif", |
lastOpenImg: "./gfx/treeTable/tv-collapsable-last.gif", |
lastShutImg: "./gfx/treeTable/tv-expandable-last.gif", |
lastLeafImg: "./gfx/treeTable/tv-item-last.gif", |
vertLineImg: "./gfx/treeTable/vertline.gif", |
blankImg: "./gfx/treeTable/blank.gif", |
collapse: closed, |
column: 0, |
striped: true, |
highlight: false, |
state: false |
}); |
if (showNetworkActiveSpeed) { |
while (oldnetwork.length > 0) { |
delete oldnetwork[oldnetwork.length-1]; //remove last object |
oldnetwork.pop(); //remove last object reference from array |
} |
oldnetwork = preoldnetwork; |
} |
} |
/** |
* (re)fill the memory block with the values from the given xml |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshMemory(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('memory', blocks) < 0))) { |
$("#memory").remove(); |
return; |
} |
var html = "", tree = [], closed = []; |
$("#memory").empty(); |
html += "<h2>" + genlang(27) + "</h2>\n"; |
html += "<div style=\"overflow-x:auto;\">\n"; |
html += " <table id=\"MemoryTree\" class=\"tablemain\">\n"; |
html += " <thead>\n"; |
html += " <tr>\n"; |
html += " <th style=\"width:200px;\">" + genlang(34) + "</th>\n"; |
html += " <th style=\"width:285px;\">" + genlang(33) + "</th>\n"; |
html += " <th class=\"right\" style=\"width:100px;\">" + genlang(125) + "</th>\n"; |
html += " <th class=\"right\" style=\"width:100px;\">" + genlang(36) + "</th>\n"; |
html += " <th class=\"right\" style=\"width:100px;\">" + genlang(37) + "</th>\n"; |
html += " </tr>\n"; |
html += " </thead>\n"; |
html += " <tbody class=\"tree\">\n"; |
$("Memory", xml).each(function getMemory(id) { |
var free = 0, total = 0, used = 0, percent = 0, memoryindex = 0; |
free = parseInt($(this).attr("Free"), 10); |
used = parseInt($(this).attr("Used"), 10); |
total = parseInt($(this).attr("Total"), 10); |
percent = parseInt($(this).attr("Percent"), 10); |
html += "<tr><td style=\"width:200px;\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(28) + "</span></div></td><td style=\"width:285px;\">" + createBar(percent) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(free, xml) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(used, xml) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(total, xml) + "</td></tr>"; |
memoryindex = tree.push(0); |
$("Memory Details", xml).each(function getMemorydetails(id) { |
var app = 0, appp = 0, buff = 0, buffp = 0, cached = 0, cachedp = 0; |
app = parseInt($(this).attr("App"), 10); |
appp = parseInt($(this).attr("AppPercent"), 10); |
buff = parseInt($(this).attr("Buffers"), 10); |
buffp = parseInt($(this).attr("BuffersPercent"), 10); |
cached = parseInt($(this).attr("Cached"), 10); |
cachedp = parseInt($(this).attr("CachedPercent"), 10); |
if (!isNaN(app)) { |
html += "<tr><td style=\"width:184px;\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(64) + "</span></div></td><td style=\"width:285px;\">" + createBar(appp) + "</td><td class=\"right\" style=\"width:100px;\"> </td><td class=\"right\" style=\"width:100px\">" + formatBytes(app, xml) + "</td><td class=\"right\" style=\"width:100px;\"> </td></tr>"; |
tree.push(memoryindex); |
} |
if (!isNaN(cached)) { |
html += "<tr><td style=\"width:184px;\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(66) + "</span></div></td><td style=\"width:285px;\">" + createBar(cachedp) + "</td><td class=\"right\" style=\"width:100px;\"> </td><td class=\"right\" style=\"width:100px;\">" + formatBytes(cached, xml) + "</td><td class=\"right\" style=\"width:100px;\"> </td></tr>"; |
tree.push(memoryindex); |
} |
if (!isNaN(buff)) { |
html += "<tr><td style=\"width:184px;\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(65) + "</span></div></td><td style=\"width:285px\">" + createBar(buffp) + "</td><td class=\"rigth\" style=\"width:100px;\"> </td><td class=\"right\" style=\"width:100px;\">" + formatBytes(buff, xml) + "</td><td class=\"right\" style=\"width:100px;\"> </td></tr>"; |
tree.push(memoryindex); |
} |
if (!isNaN(app) || !isNaN(buff) || !isNaN(cached)) { |
if (!showMemoryInfosExpanded) { |
closed.push(memoryindex); |
} |
} |
}); |
}); |
$("Memory Swap", xml).each(function getSwap(id) { |
var free = 0, total = 0, used = 0, percent = 0, swapindex = 0; |
free = parseInt($(this).attr("Free"), 10); |
used = parseInt($(this).attr("Used"), 10); |
total = parseInt($(this).attr("Total"), 10); |
percent = parseInt($(this).attr("Percent"), 10); |
html += "<tr><td style=\"width:200px;\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(29) + "</span></div></td><td style=\"width:285px;\">" + createBar(percent) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(free, xml) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(used, xml) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(total, xml) + "</td></tr>"; |
swapindex = tree.push(0); |
$("Memory Swap Mount", xml).each(function getDevices(id) { |
var free = 0, total = 0, used = 0, percent = 0, mpoint = "", mpid = 0; |
if (!showMemoryInfosExpanded) { |
closed.push(swapindex); |
} |
free = parseInt($(this).attr("Free"), 10); |
used = parseInt($(this).attr("Used"), 10); |
total = parseInt($(this).attr("Total"), 10); |
percent = parseInt($(this).attr("Percent"), 10); |
mpid = parseInt($(this).attr("MountPointID"), 10); |
mpoint = $(this).attr("MountPoint"); |
if (mpoint === undefined) { |
mpoint = mpid; |
} |
html += "<tr><td style=\"width:184px;\"><div class=\"treediv\"><span class=\"treespan\">" + mpoint + "</span></div></td><td style=\"width:285px;\">" + createBar(percent) + "</td><td class=\"right\" style=\"width:100px\">" + formatBytes(free, xml) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(used, xml) + "</td><td class=\"right\" style=\"width:100px;\">" + formatBytes(total, xml) + "</td></tr>"; |
tree.push(swapindex); |
}); |
}); |
html += " </tbody>\n"; |
html += " </table>\n"; |
html += "</div>\n"; |
$("#memory").append(html); |
$("#MemoryTree").jqTreeTable(tree, { |
openImg: "./gfx/treeTable/tv-collapsable.gif", |
shutImg: "./gfx/treeTable/tv-expandable.gif", |
leafImg: "./gfx/treeTable/tv-item.gif", |
lastOpenImg: "./gfx/treeTable/tv-collapsable-last.gif", |
lastShutImg: "./gfx/treeTable/tv-expandable-last.gif", |
lastLeafImg: "./gfx/treeTable/tv-item-last.gif", |
vertLineImg: "./gfx/treeTable/vertline.gif", |
blankImg: "./gfx/treeTable/blank.gif", |
collapse: closed, |
column: 0, |
striped: true, |
highlight: false, |
state: false |
}); |
} |
/** |
* (re)fill the filesystems block with the values from the given xml<br><br> |
* appends the filesystems (each in a row) to the filesystem table in the tbody<br>before the rows are inserted the entire |
* tbody is cleared |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshFilesystems(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('filesystem', blocks) < 0))) { |
$("#filesystem").remove(); |
return; |
} |
var total_usage = 0, total_used = 0, total_free = 0, total_size = 0, threshold = 0; |
filesystemTable.fnClearTable(); |
$("Options", xml).each(function getThreshold(id) { |
threshold = parseInt($(this).attr("threshold"), 10); |
}); |
$("FileSystem Mount", xml).each(function getMount(mid) { |
var mpoint = "", mpid = 0, type = "", name = "", free = 0, used = 0, size = 0, percent = 0, options = "", inodes = 0, inodes_text = "", options_text = "", ignore = 0; |
mpid = parseInt($(this).attr("MountPointID"), 10); |
type = $(this).attr("FSType"); |
name = $(this).attr("Name").replace(/;/g, ";<wbr>"); /* split long name */ |
free = parseInt($(this).attr("Free"), 10); |
used = parseInt($(this).attr("Used"), 10); |
size = parseInt($(this).attr("Total"), 10); |
percent = parseInt($(this).attr("Percent"), 10); |
options = $(this).attr("MountOptions"); |
inodes = parseInt($(this).attr("Inodes"), 10); |
mpoint = $(this).attr("MountPoint"); |
ignore = parseInt($(this).attr("Ignore"), 10); |
if (mpoint === undefined) { |
mpoint = mpid; |
} |
if (options !== undefined) { |
options_text = "<br><i>(" + options + ")</i>"; |
} |
if (!isNaN(inodes)) { |
inodes_text = "<span style=\"font-style:italic\"> (" + inodes.toString() + "%)</span>"; |
} |
if (!isNaN(ignore) && (ignore > 0)) { |
if (ignore >= 2) { |
if ((ignore == 2) && !isNaN(threshold) && (percent >= threshold)) { |
filesystemTable.fnAddData(["<span style=\"display:none;\">" + mpoint + "</span>" + mpoint, "<span style=\"display:none;\">" + type + "</span>" + type, "<span style=\"display:none;\">" + name + "</span>" + name + options_text, "<span style=\"display:none;\">" + percent.toString() + "</span>" + createBar(percent, "barwarn") + inodes_text, "<span style=\"display:none;\">" + free.toString() + "</span><i>(" + formatBytes(free, xml) + ")</i>", "<span style=\"display:none;\">" + used.toString() + "</span><i>(" + formatBytes(used, xml) + ")</i>", "<span style=\"display:none;\">" + size.toString() + "</span><i>(" + formatBytes(size, xml) + ")</i>"]); |
} else { |
filesystemTable.fnAddData(["<span style=\"display:none;\">" + mpoint + "</span>" + mpoint, "<span style=\"display:none;\">" + type + "</span>" + type, "<span style=\"display:none;\">" + name + "</span>" + name + options_text, "<span style=\"display:none;\">" + percent.toString() + "</span>" + createBar(percent) + inodes_text, "<span style=\"display:none;\">" + free.toString() + "</span><i>(" + formatBytes(free, xml) + ")</i>", "<span style=\"display:none;\">" + used.toString() + "</span><i>(" + formatBytes(used, xml) + ")</i>", "<span style=\"display:none;\">" + size.toString() + "</span><i>(" + formatBytes(size, xml) + ")</i>"]); |
} |
} else { |
if (!isNaN(threshold) && (percent >= threshold)) { |
filesystemTable.fnAddData(["<span style=\"display:none;\">" + mpoint + "</span>" + mpoint, "<span style=\"display:none;\">" + type + "</span>" + type, "<span style=\"display:none;\">" + name + "</span>" + name + options_text, "<span style=\"display:none;\">" + percent.toString() + "</span>" + createBar(percent, "barwarn") + inodes_text, "<span style=\"display:none;\">" + free.toString() + "</span><i>(" + formatBytes(free, xml) + ")</i>", "<span style=\"display:none;\">" + used.toString() + "</span>" + formatBytes(used, xml), "<span style=\"display:none;\">" + size.toString() + "</span><i>(" + formatBytes(size, xml) + ")</i>"]); |
} else { |
filesystemTable.fnAddData(["<span style=\"display:none;\">" + mpoint + "</span>" + mpoint, "<span style=\"display:none;\">" + type + "</span>" + type, "<span style=\"display:none;\">" + name + "</span>" + name + options_text, "<span style=\"display:none;\">" + percent.toString() + "</span>" + createBar(percent) + inodes_text, "<span style=\"display:none;\">" + free.toString() + "</span><i>(" + formatBytes(free, xml) + ")</i>", "<span style=\"display:none;\">" + used.toString() + "</span>" + formatBytes(used, xml), "<span style=\"display:none;\">" + size.toString() + "</span><i>(" + formatBytes(size, xml) + ")</i>"]); |
} |
} |
} else { |
if (!isNaN(threshold) && (percent >= threshold)) { |
filesystemTable.fnAddData(["<span style=\"display:none;\">" + mpoint + "</span>" + mpoint, "<span style=\"display:none;\">" + type + "</span>" + type, "<span style=\"display:none;\">" + name + "</span>" + name + options_text, "<span style=\"display:none;\">" + percent.toString() + "</span>" + createBar(percent, "barwarn") + inodes_text, "<span style=\"display:none;\">" + free.toString() + "</span>" + formatBytes(free, xml), "<span style=\"display:none;\">" + used.toString() + "</span>" + formatBytes(used, xml), "<span style=\"display:none;\">" + size.toString() + "</span>" + formatBytes(size, xml)]); |
} else { |
filesystemTable.fnAddData(["<span style=\"display:none;\">" + mpoint + "</span>" + mpoint, "<span style=\"display:none;\">" + type + "</span>" + type, "<span style=\"display:none;\">" + name + "</span>" + name + options_text, "<span style=\"display:none;\">" + percent.toString() + "</span>" + createBar(percent) + inodes_text, "<span style=\"display:none;\">" + free.toString() + "</span>" + formatBytes(free, xml), "<span style=\"display:none;\">" + used.toString() + "</span>" + formatBytes(used, xml), "<span style=\"display:none;\">" + size.toString() + "</span>" + formatBytes(size, xml)]); |
} |
} |
if (!isNaN(ignore) && (ignore > 0)) { |
if (ignore == 1) { |
total_used += used; |
total_size += used; |
} |
} else { |
total_used += used; |
total_free += free; |
total_size += size; |
} |
total_usage = round((total_used / total_size) * 100, 2); |
}); |
if (!isNaN(threshold) && (total_usage >= threshold)) { |
$("#s_fs_total").html(createBar(total_usage, "barwarn")); |
} else { |
$("#s_fs_total").html(createBar(total_usage)); |
} |
$("#s_fs_tfree").html(formatBytes(total_free, xml)); |
$("#s_fs_tused").html(formatBytes(total_used, xml)); |
$("#s_fs_tsize").html(formatBytes(total_size, xml)); |
} |
/** |
* (re)fill the temperature block with the values from the given xml<br><br> |
* build the block content for the temperature block, this includes normal temperature information in the XML |
* and also the HDDTemp information, if there are no information the entire table will be removed |
* to avoid HTML warnings |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshTemp(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('temperature', blocks) < 0))) { |
$("#temperature").remove(); |
return; |
} |
var values = false; |
$("#temperatureTable tbody").empty(); |
$("MBInfo Temperature Item", xml).each(function getTemperatures(id) { |
var label = "", value = "", limit = 0, _limit = "", event = ""; |
label = $(this).attr("Label"); |
value = $(this).attr("Value"); |
limit = parseFloat($(this).attr("Max")); |
if (isFinite(limit)) |
_limit = formatTemp(limit, xml); |
event = $(this).attr("Event"); |
if (event !== undefined) |
label += " <img style=\"vertical-align: middle; width:16px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\""+event+"\"/>"; |
$("#temperatureTable tbody").append("<tr><td>" + label + "</td><td class=\"right\">" + formatTemp(value, xml) + "</td><td class=\"right\">" + _limit + "</td></tr>"); |
values = true; |
}); |
if (values) { |
$("#temperature").show(); |
} else { |
$("#temperature").hide(); |
} |
} |
/** |
* (re)fill the voltage block with the values from the given xml<br><br> |
* build the voltage information into a separate block, if there is no voltage information available the |
* entire table will be removed to avoid HTML warnings |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshVoltage(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('voltage', blocks) < 0))) { |
$("#voltage").remove(); |
return; |
} |
var values = false; |
$("#voltageTable tbody").empty(); |
$("MBInfo Voltage Item", xml).each(function getVoltages(id) { |
var label = "", value = 0, max = 0, min = 0, _min = "", _max = "", event = ""; |
label = $(this).attr("Label"); |
value = parseFloat($(this).attr("Value")); |
max = parseFloat($(this).attr("Max")); |
if (isFinite(max)) |
_max = round(max, 2) + " " + genlang(62); |
min = parseFloat($(this).attr("Min")); |
if (isFinite(min)) |
_min = round(min, 2) + " " + genlang(62); |
event = $(this).attr("Event"); |
if (event !== undefined) |
label += " <img style=\"vertical-align: middle; width:16px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\""+event+"\"/>"; |
$("#voltageTable tbody").append("<tr><td>" + label + "</td><td class=\"right\">" + round(value, 2) + " " + genlang(62) + "</td><td class=\"right\">" + _min + "</td><td class=\"right\">" + _max + "</td></tr>"); |
values = true; |
}); |
if (values) { |
$("#voltage").show(); |
} else { |
$("#voltage").hide(); |
} |
} |
/** |
* (re)fill the fan block with the values from the given xml<br><br> |
* build the fan information into a separate block, if there is no fan information available the |
* entire table will be removed to avoid HTML warnings |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshFans(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('fans', blocks) < 0))) { |
$("#fans").remove(); |
return; |
} |
var values = false; |
$("#fansTable tbody").empty(); |
$("MBInfo Fans Item", xml).each(function getFans(id) { |
var label = "", value = 0, min = 0, _min = "", event = ""; |
label = $(this).attr("Label"); |
value = parseFloat($(this).attr("Value")); |
min = parseFloat($(this).attr("Min")); |
if (isFinite(min)) |
_min = round(min,0) + " " + genlang(63); |
event = $(this).attr("Event"); |
if (event !== undefined) |
label += " <img style=\"vertical-align: middle; width:16px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\""+event+"\"/>"; |
$("#fansTable tbody").append("<tr><td>" + label + "</td><td class=\"right\">" + round(value,0) + " " + genlang(63) + "</td><td class=\"right\">" + _min + "</td></tr>"); |
values = true; |
}); |
if (values) { |
$("#fans").show(); |
} else { |
$("#fans").hide(); |
} |
} |
/** |
* (re)fill the power block with the values from the given xml<br><br> |
* build the power information into a separate block, if there is no power information available the |
* entire table will be removed to avoid HTML warnings |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshPower(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('power', blocks) < 0))) { |
$("#power").remove(); |
return; |
} |
var values = false; |
$("#powerTable tbody").empty(); |
$("MBInfo Power Item", xml).each(function getPowers(id) { |
var label = "", value = "", limit = 0, _limit = "", event = ""; |
label = $(this).attr("Label"); |
value = $(this).attr("Value"); |
limit = parseFloat($(this).attr("Max")); |
if (isFinite(limit)) |
_limit = round(limit, 2) + " " + genlang(103); |
event = $(this).attr("Event"); |
if (event !== undefined) |
label += " <img style=\"vertical-align: middle; width:16px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\""+event+"\"/>"; |
$("#powerTable tbody").append("<tr><td>" + label + "</td><td class=\"right\">" + round(value, 2) + " " + genlang(103) + "</td><td class=\"right\">" + _limit + "</td></tr>"); |
values = true; |
}); |
if (values) { |
$("#power").show(); |
} else { |
$("#power").hide(); |
} |
} |
/** |
* (re)fill the current block with the values from the given xml<br><br> |
* build the current information into a separate block, if there is no current information available the |
* entire table will be removed to avoid HTML warnings |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshCurrent(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('current', blocks) < 0))) { |
$("#current").remove(); |
return; |
} |
var values = false; |
$("#currentTable tbody").empty(); |
$("MBInfo Current Item", xml).each(function getCurrents(id) { |
var label = "", value = "", min = 0, max = 0, _min = "", _max = "", event = ""; |
label = $(this).attr("Label"); |
value = $(this).attr("Value"); |
max = parseFloat($(this).attr("Max")); |
if (isFinite(max)) |
_max = round(max, 2) + " " + genlang(106); |
min = parseFloat($(this).attr("Min")); |
if (isFinite(min)) |
_min = round(min, 2) + " " + genlang(106); |
event = $(this).attr("Event"); |
if (event !== undefined) |
label += " <img style=\"vertical-align: middle; width:16px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\""+event+"\"/>"; |
$("#currentTable tbody").append("<tr><td>" + label + "</td><td class=\"right\">" + round(value, 2) + " " + genlang(106) + "</td><td class=\"right\">" + _min + "</td><td class=\"right\">" + _max + "</td></tr>"); |
values = true; |
}); |
if (values) { |
$("#current").show(); |
} else { |
$("#current").hide(); |
} |
} |
/** |
* (re)fill the other block with the values from the given xml<br><br> |
* build the other information into a separate block, if there is no other information available the |
* entire table will be removed to avoid HTML warnings |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshOther(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('other', blocks) < 0))) { |
$("#other").remove(); |
return; |
} |
var values = false; |
$("#otherTable tbody").empty(); |
$("MBInfo Other Item", xml).each(function getOthers(id) { |
var label = "", value = "", event = ""; |
label = $(this).attr("Label"); |
value = $(this).attr("Value"); |
event = $(this).attr("Event"); |
if (event !== undefined) |
label += " <img style=\"vertical-align: middle; width:16px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\""+event+"\"/>"; |
$("#otherTable tbody").append("<tr><td>" + label + "</td><td class=\"right\">" + value + "</td></tr>"); |
values = true; |
}); |
if (values) { |
$("#other").show(); |
} else { |
$("#other").hide(); |
} |
} |
/** |
* (re)fill the ups block with the values from the given xml<br><br> |
* build the ups information into a separate block, if there is no ups information available the |
* entire table will be removed to avoid HTML warnings |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function refreshUps(xml) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('ups', blocks) < 0))) { |
$("#ups").remove(); |
return; |
} |
var add_apcupsd_cgi_links = ($("[ApcupsdCgiLinks='1']", xml).length > 0); |
var html = "", tree = [], closed = [], index = 0, values = false; |
html += "<h2>" + genlang(68) + "</h2>\n"; |
html += " <div style=\"overflow-x:auto;\">\n"; |
html += " <table class=\"tablemain\" id=\"UPSTree\">\n"; |
html += " <tbody class=\"tree\">\n"; |
$("#ups").empty(); |
$("UPSInfo UPS", xml).each(function getUps(id) { |
var name = "", model = "", mode = "", start_time = "", upsstatus = "", temperature = "", outages_count = "", last_outage = "", last_outage_finish = "", line_voltage = "", line_frequency = "", load_percent = "", battery_date = "", battery_voltage = "", battery_charge_percent = "", time_left_minutes = ""; |
name = $(this).attr("Name"); |
model = $(this).attr("Model"); |
mode = $(this).attr("Mode"); |
start_time = $(this).attr("StartTime"); |
upsstatus = $(this).attr("Status"); |
temperature = $(this).attr("Temperature"); |
outages_count = $(this).attr("OutagesCount"); |
last_outage = $(this).attr("LastOutage"); |
last_outage_finish = $(this).attr("LastOutageFinish"); |
line_voltage = $(this).attr("LineVoltage"); |
line_frequency = $(this).attr("LineFrequency"); |
load_percent = parseInt($(this).attr("LoadPercent"), 10); |
battery_date = $(this).attr("BatteryDate"); |
battery_voltage = $(this).attr("BatteryVoltage"); |
battery_charge_percent = parseInt($(this).attr("BatteryChargePercent"), 10); |
time_left_minutes = $(this).attr("TimeLeftMinutes"); |
if (mode !== undefined) { |
html += "<tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespanbold\">" + name + " (" + mode + ")</span></div></td></tr>\n"; |
} else { |
html += "<tr><td colspan=\"2\"><div class=\"treediv\"><span class=\"treespanbold\">" + name + "</span></div></td></tr>\n"; |
} |
index = tree.push(0); |
if (model !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(70) + "</span></div></td><td>" + model + "</td></tr>\n"; |
tree.push(index); |
} |
if (start_time !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(72) + "</span></div></td><td>" + start_time + "</td></tr>\n"; |
tree.push(index); |
} |
if (upsstatus !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(73) + "</span></div></td><td>" + upsstatus + "</td></tr>\n"; |
tree.push(index); |
} |
if (temperature !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(84) + "</span></div></td><td>" + temperature + "</td></tr>\n"; |
tree.push(index); |
} |
if (outages_count !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(74) + "</span></div></td><td>" + outages_count + "</td></tr>\n"; |
tree.push(index); |
} |
if (last_outage !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(75) + "</span></div></td><td>" + last_outage + "</td></tr>\n"; |
tree.push(index); |
} |
if (last_outage_finish !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(76) + "</span></div></td><td>" + last_outage_finish + "</td></tr>\n"; |
tree.push(index); |
} |
if (line_voltage !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(77) + "</span></div></td><td>" + line_voltage + " " + genlang(82) + "</td></tr>\n"; |
tree.push(index); |
} |
if (line_frequency !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(108) + "</span></div></td><td>" + line_frequency + " " + genlang(109) + "</td></tr>\n"; |
tree.push(index); |
} |
if (!isNaN(load_percent)) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(78) + "</span></div></td><td>" + createBar(load_percent) + "</td></tr>\n"; |
tree.push(index); |
} |
if (battery_date !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(104) + "</span></div></td><td>" + battery_date + "</td></tr>\n"; |
tree.push(index); |
} |
if (battery_voltage !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(79) + "</span></div></td><td>" + battery_voltage + " " + genlang(82) + "</td></tr>\n"; |
tree.push(index); |
} |
if (!isNaN(battery_charge_percent)) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(80) + "</span></div></td><td>" + createBar(battery_charge_percent) + "</td></tr>\n"; |
tree.push(index); |
} |
if (time_left_minutes !== undefined) { |
html += "<tr><td style=\"width:160px\"><div class=\"treediv\"><span class=\"treespan\">" + genlang(81) + "</span></div></td><td>" + time_left_minutes + " " + genlang(83) + "</td></tr>\n"; |
tree.push(index); |
} |
values=true; |
}); |
html += " </tbody>\n"; |
html += " </table>\n"; |
html += " </div>\n"; |
if (add_apcupsd_cgi_links){ |
html += " (<a title='details' href='/cgi-bin/apcupsd/multimon.cgi' target='apcupsdcgi'>" + genlang(99) + "</a>)\n"; |
} |
$("#ups").append(html); |
if (values) { |
$("#UPSTree").jqTreeTable(tree, { |
openImg: "./gfx/treeTable/tv-collapsable.gif", |
shutImg: "./gfx/treeTable/tv-expandable.gif", |
leafImg: "./gfx/treeTable/tv-item.gif", |
lastOpenImg: "./gfx/treeTable/tv-collapsable-last.gif", |
lastShutImg: "./gfx/treeTable/tv-expandable-last.gif", |
lastLeafImg: "./gfx/treeTable/tv-item-last.gif", |
vertLineImg: "./gfx/treeTable/vertline.gif", |
blankImg: "./gfx/treeTable/blank.gif", |
collapse: closed, |
column: 0, |
striped: true, |
highlight: false, |
state: false |
}); |
$("#ups").show(); |
} else { |
$("#ups").hide(); |
} |
} |
/** |
* reload the page, this means all values are refreshed |
*/ |
function reload(initiate) { |
$.ajax({ |
url: 'xml.php', |
dataType: 'xml', |
error: function error() { |
if ((typeof(initiate) === 'boolean') && (initiate === true)) { |
$.jGrowl("Error loading XML document!", { |
sticky: true |
}); |
} else { |
$.jGrowl("Error loading XML document!"); |
} |
}, |
success: function buildblocks(xml) { |
if ((typeof(initiate) === 'boolean') && (initiate === true)) { |
populateErrors(xml); |
} |
refreshVitals(xml); |
refreshHardware(xml); |
refreshMemory(xml); |
refreshFilesystems(xml); |
refreshNetwork(xml); |
refreshVoltage(xml); |
refreshCurrent(xml); |
refreshTemp(xml); |
refreshFans(xml); |
refreshPower(xml); |
refreshOther(xml); |
refreshUps(xml); |
changeLanguage(); |
if ((typeof(initiate) === 'boolean') && (initiate === true)) { |
displayPage(xml); |
settimer(xml); |
} else { |
for (var i = 0; i < plugin_liste.length; i++) { |
try { |
//dynamic call |
window[plugin_liste[i].toLowerCase() + '_request'](); |
} |
catch (err) { |
} |
} |
} |
$('.stripeMe tr:nth-child(even)').addClass('even'); |
} |
}); |
} |
/** |
* set a reload timer for the page |
* @param {jQuery} xml phpSysInfo-XML |
*/ |
function settimer(xml) { |
$("Options", xml).each(function getRefreshTime(id) { |
var options, refresh = ""; |
options = $("Options", xml).get(id); |
refresh = $(this).attr("refresh"); |
if (refresh !== '0') { |
$.timer(refresh, reload); |
} |
}); |
} |
$(document).ready(function buildpage() { |
var i = 0, old_template = null, cookie_template = null, cookie_language = null, blocktmp = ""; |
showCPUListExpanded = $("#showCPUListExpanded").val().toString()==="true"; |
showCPUInfoExpanded = $("#showCPUInfoExpanded").val().toString()==="true"; |
showNetworkInfosExpanded = $("#showNetworkInfosExpanded").val().toString()==="true"; |
showMemoryInfosExpanded = $("#showMemoryInfosExpanded").val().toString()==="true"; |
showCPULoadCompact = $("#showCPULoadCompact").val().toString()==="true"; |
switch ($("#showNetworkActiveSpeed").val().toString()) { |
case "bps": showNetworkActiveSpeed = 2; |
break; |
case "true": showNetworkActiveSpeed = 1; |
break; |
default: showNetworkActiveSpeed = 0; |
} |
blocktmp = $("#blocks").val().toString(); |
if (blocktmp.length >0 ){ |
if (blocktmp === "true") { |
blocks[0] = "true"; |
} else { |
blocks = blocktmp.split(','); |
var j = 2; |
for (i = 0; i < blocks.length; i++) { |
if ($("#"+blocks[i]).length > 0) { |
$("#output").children().eq(j).before($("#"+blocks[i])); |
j++; |
} |
} |
} |
} |
if ($("#language option").length < 2) { |
current_language = $("#language").val().toString(); |
/* |
changeLanguage(); |
for (i = 0; i < plugin_liste.length; i++) { |
changeLanguage(plugin_liste[i]); |
} |
*/ |
} else { |
cookie_language = readCookie("psi_language"); |
if (cookie_language !== null) { |
current_language = cookie_language; |
$("#language").val(current_language); |
} else { |
current_language = $("#language").val().toString(); |
} |
/* |
changeLanguage(); |
for (i = 0; i < plugin_liste.length; i++) { |
changeLanguage(plugin_liste[i]); |
} |
*/ |
$('#language').show(); |
$('span[class=lang_045]').show(); |
$("#language").change(function changeLang() { |
var i = 0; |
current_language = $("#language").val().toString(); |
createCookie('psi_language', current_language, 365); |
changeLanguage(); |
for (i = 0; i < plugin_liste.length; i++) { |
changeLanguage(plugin_liste[i]); |
} |
return false; |
}); |
} |
if ($("#template option").length < 2) { |
switchStyle($("#template").val().toString()); |
} else { |
cookie_template = readCookie("psi_template"); |
if (cookie_template !== null) { |
old_template = $("#template").val(); |
$("#template").val(cookie_template); |
if ($("#template").val() === null) { |
$("#template").val(old_template); |
} |
} |
switchStyle($("#template").val().toString()); |
$('#template').show(); |
$('span[class=lang_044]').show(); |
$("#template").change(function changeTemplate() { |
switchStyle($("#template").val().toString()); |
createCookie('psi_template', $("#template").val().toString(), 365); |
return false; |
}); |
} |
filesystemtable(); |
reload(true); |
$("#errors").nyroModal(); |
}); |
jQuery.fn.dataTableExt.oSort['span-string-asc'] = function sortStringAsc(a, b) { |
var x = "", y = ""; |
x = a.substring(a.indexOf(">") + 1, a.indexOf("</")); |
y = b.substring(b.indexOf(">") + 1, b.indexOf("</")); |
return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
}; |
jQuery.fn.dataTableExt.oSort['span-string-desc'] = function sortStringDesc(a, b) { |
var x = "", y = ""; |
x = a.substring(a.indexOf(">") + 1, a.indexOf("</")); |
y = b.substring(b.indexOf(">") + 1, b.indexOf("</")); |
return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
}; |
jQuery.fn.dataTableExt.oSort['span-number-asc'] = function sortNumberAsc(a, b) { |
var x = 0, y = 0; |
x = parseInt(a.substring(a.indexOf(">") + 1, a.indexOf("</")), 10); |
y = parseInt(b.substring(b.indexOf(">") + 1, b.indexOf("</")), 10); |
return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
}; |
jQuery.fn.dataTableExt.oSort['span-number-desc'] = function sortNumberDesc(a, b) { |
var x = 0, y = 0; |
x = parseInt(a.substring(a.indexOf(">") + 1, a.indexOf("</")), 10); |
y = parseInt(b.substring(b.indexOf(">") + 1, b.indexOf("</")), 10); |
return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
}; |
jQuery.fn.dataTableExt.oSort['span-ip-asc'] = function sortIpAsc(a, b) { |
var x = 0, y = 0, aa = "", bb = ""; |
aa = a.substring(a.indexOf(">") + 1, a.indexOf("</")); |
bb = b.substring(b.indexOf(">") + 1, b.indexOf("</")); |
x = full_addr(aa); |
y = full_addr(bb); |
if ((x === '') || (y === '')) { |
x = aa; |
y = bb; |
} |
return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
}; |
jQuery.fn.dataTableExt.oSort['span-ip-desc'] = function sortIpDesc(a, b) { |
var x = 0, y = 0, aa = "", bb = ""; |
aa = a.substring(a.indexOf(">") + 1, a.indexOf("</")); |
bb = b.substring(b.indexOf(">") + 1, b.indexOf("</")); |
x = full_addr(aa); |
y = full_addr(bb); |
if ((x === '') || (y === '')) { |
x = aa; |
y = bb; |
} |
return ((x < y) ? 1 : ((x > y) ? -1 : 0)); |
}; |
function full_addr(ip_string) { |
var wrongvalue = false; |
ip_string = $.trim(ip_string).toLowerCase(); |
// ipv4 notation |
if (ip_string.match(/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$)/)) { |
ip_string ='::ffff:' + ip_string; |
} |
// replace ipv4 address if any |
var ipv4 = ip_string.match(/(.*:)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$)/); |
if (ipv4) { |
ip_string = ipv4[1]; |
ipv4 = ipv4[2].match(/[0-9]+/g); |
for (var i = 0;i < 4;i ++) { |
var byte = parseInt(ipv4[i],10); |
if (byte<256) { |
ipv4[i] = ("0" + byte.toString(16)).substr(-2); |
} else { |
wrongvalue = true; |
break; |
} |
} |
if (wrongvalue) { |
ip_string = ''; |
} else { |
ip_string += ipv4[0] + ipv4[1] + ':' + ipv4[2] + ipv4[3]; |
} |
} |
if (ip_string === '') { |
return ''; |
} |
// take care of leading and trailing :: |
ip_string = ip_string.replace(/^:|:$/g, ''); |
var ipv6 = ip_string.split(':'); |
for (var li = 0; li < ipv6.length; li ++) { |
var hex = ipv6[li]; |
if (hex !== "") { |
if (!hex.match(/^[0-9a-f]{1,4}$/)) { |
wrongvalue = true; |
break; |
} |
// normalize leading zeros |
ipv6[li] = ("0000" + hex).substr(-4); |
} |
else { |
// normalize grouped zeros :: |
hex = []; |
for (var j = ipv6.length; j <= 8; j ++) { |
hex.push('0000'); |
} |
ipv6[li] = hex.join(':'); |
} |
} |
if (!wrongvalue) { |
var out = ipv6.join(':'); |
if (out.length == 39) { |
return out; |
} else { |
return ''; |
} |
} else { |
return ''; |
} |
} |
/** |
* generate the block element for a specific plugin that is available |
* @param {String} plugin name of the plugin |
* @param {Number} translationid id of the translated headline in the plugin translation file |
* @param {Boolean} reload controls if a reload button should be appended to the headline |
* @return {String} HTML string which contains the full layout of the block |
*/ |
function buildBlock(plugin, translationid, reload) { |
var block = "", reloadpic = ""; |
if (reload) { |
reloadpic = "<img id=\"Reload_" + plugin + "Table\" src=\"./gfx/reload.gif\" alt=\"reload\" title=\"reload\" style=\"vertical-align:middle;float:right;cursor:pointer;border:0px;width:16px\" /> "; |
} |
block += "<div id=\"panel_" + plugin + "\" style=\"display:none;\">\n"; |
block += "<div id=\"Plugin_" + plugin + "\" class=\"plugin\" style=\"display:none;\">\n"; |
block += "<h2>" + reloadpic + genlang(translationid, plugin) + "</h2>\n"; |
block += "</div>\n"; |
block += "</div>\n"; |
return block; |
} |
/** |
* translate a plugin and add this plugin to the internal plugin-list, this is only needed once and shouldn't be called more than once |
* @param {String} plugin name of the plugin that should be translated |
*/ |
function plugin_translate(plugin) { |
plugin_liste.pushIfNotExist(plugin); |
changeLanguage(plugin); |
} |
/** |
* generate a formatted datetime string of the current datetime |
* @return {String} formatted datetime string |
*/ |
function datetime() { |
var date, day = 0, month = 0, year = 0, hour = 0, minute = 0, days = "", months = "", years = "", hours = "", minutes = ""; |
date = new Date(); |
day = date.getDate(); |
month = date.getMonth() + 1; |
year = date.getFullYear(); |
hour = date.getHours(); |
minute = date.getMinutes(); |
// format values smaller that 10 with a leading 0 |
days = (day < 10) ? "0" + day.toString() : day.toString(); |
months = (month < 10) ? "0" + month.toString() : month.toString(); |
years = (year < 1000) ? year.toString() : year.toString(); |
minutes = (minute < 10) ? "0" + minute.toString() : minute.toString(); |
hours = (hour < 10) ? "0" + hour.toString() : hour.toString(); |
return days + "." + months + "." + years + " - " + hours + ":" + minutes; |
} |
Array.prototype.pushIfNotExist = function(val) { |
if (typeof(val) == 'undefined' || val === '') { |
return; |
} |
val = $.trim(val); |
if ($.inArray(val, this) == -1) { |
this.push(val); |
} |
}; |
/** |
* insert dynamically a js script file into the website |
* @param {String} name name of the script that should be included |
*/ |
/* |
function appendjs(name) { |
var scrptE, hdEl; |
scrptE = document.createElement("script"); |
hdEl = document.getElementsByTagName("head")[0]; |
scrptE.setAttribute("src", name); |
scrptE.setAttribute("type", "text/javascript"); |
hdEl.appendChild(scrptE); |
} |
*/ |
/** |
* insert dynamically a css file into the website |
* @param {String} name name of the css file that should be included |
*/ |
/* |
function appendcss(name) { |
var scrptE, hdEl; |
scrptE = document.createElement("link"); |
hdEl = document.getElementsByTagName("head")[0]; |
scrptE.setAttribute("type", "text/css"); |
scrptE.setAttribute("rel", "stylesheet"); |
scrptE.setAttribute("href", name); |
hdEl.appendChild(scrptE); |
} |
*/ |
/web/acc/phpsysinfo/js/phpSysInfo/phpsysinfo_bootstrap.js |
---|
0,0 → 1,1859 |
var langxml = [], langarr = [], current_language = "", plugins = [], blocks = [], plugin_liste = [], |
showCPUListExpanded, showCPUInfoExpanded, showNetworkInfosExpanded, showNetworkActiveSpeed, showCPULoadCompact, oldnetwork = [], refrTimer; |
/** |
* generate a cookie, if not exist, and add an entry to it<br><br> |
* inspired by <a href="http://www.quirksmode.org/js/cookies.html">http://www.quirksmode.org/js/cookies.html</a> |
* @param {String} name name that holds the value |
* @param {String} value value that needs to be stored |
* @param {Number} days how many days the entry should be valid in the cookie |
*/ |
function createCookie(name, value, days) { |
var date = new Date(), expires = ""; |
if (days) { |
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); |
if (typeof(date.toUTCString)==="function") { |
expires = "; expires=" + date.toUTCString(); |
} else { |
//deprecated |
expires = "; expires=" + date.toGMTString(); |
} |
} else { |
expires = ""; |
} |
document.cookie = name + "=" + value + expires + "; path=/"; |
} |
/** |
* read a value out of a cookie and return the value<br><br> |
* inspired by <a href="http://www.quirksmode.org/js/cookies.html">http://www.quirksmode.org/js/cookies.html</a> |
* @param {String} name name of the value that should be retrieved |
* @return {String} |
*/ |
function readCookie(name) { |
var nameEQ = "", ca = [], c = ''; |
nameEQ = name + "="; |
ca = document.cookie.split(';'); |
for (var i = 0; i < ca.length; i++) { |
c = ca[i]; |
while (c.charAt(0) === ' ') { |
c = c.substring(1, c.length); |
} |
if (!c.indexOf(nameEQ)) { |
return c.substring(nameEQ.length, c.length); |
} |
} |
return null; |
} |
/** |
* activates a given style and disables the old one in the document |
* @param {String} template template that should be activated |
*/ |
function switchStyle(template) { |
$("#PSI_Template")[0].setAttribute('href', 'templates/' + template + "_bootstrap.css"); |
} |
/** |
* load the given translation an translate the entire page<br><br>retrieving the translation is done through a |
* ajax call |
* @private |
* @param {String} plugin if plugin is given, the plugin translation file will be read instead of the main translation file |
* @param {String} langarrId internal plugin name |
* @return {jQuery} translation jQuery-Object |
*/ |
function getLanguage(plugin, langarrId) { |
var getLangUrl = ""; |
if (current_language) { |
getLangUrl = 'language/language.php?lang=' + current_language; |
if (plugin) { |
getLangUrl += "&plugin=" + plugin; |
} |
} else { |
getLangUrl = 'language/language.php'; |
if (plugin) { |
getLangUrl += "?plugin=" + plugin; |
} |
} |
$.ajax({ |
url: getLangUrl, |
type: 'GET', |
dataType: 'xml', |
timeout: 100000, |
error: function error() { |
$("#errors").append("<li><b>Error loading language</b> - " + getLangUrl + "</li><br>"); |
$("#errorbutton").attr('data-toggle', 'modal'); |
$("#errorbutton").css('cursor', 'pointer'); |
$("#errorbutton").css("visibility", "visible"); |
}, |
success: function buildblocks(xml) { |
var idexp; |
langxml[langarrId] = xml; |
if (langarr[langarrId] === undefined) { |
langarr.push(langarrId); |
langarr[langarrId] = []; |
} |
$("expression", langxml[langarrId]).each(function langstore(id) { |
idexp = $("expression", xml).get(id); |
langarr[langarrId][this.getAttribute('id')] = $("exp", idexp).text().toString().replace(/\//g, "/<wbr>"); |
}); |
changeSpanLanguage(plugin); |
} |
}); |
} |
/** |
* generate a span tag |
* @param {Number} id translation id in the xml file |
* @param {String} [plugin] name of the plugin for which the tag should be generated |
* @return {String} string which contains generated span tag for translation string |
*/ |
function genlang(id, plugin) { |
var html = "", idString = "", plugname = "", |
langarrId = current_language + "_"; |
if (plugin === undefined) { |
plugname = ""; |
langarrId += "phpSysInfo"; |
} else { |
plugname = plugin.toLowerCase(); |
langarrId += plugname; |
} |
if (id < 100) { |
if (id < 10) { |
idString = "00" + id.toString(); |
} else { |
idString = "0" + id.toString(); |
} |
} else { |
idString = id.toString(); |
} |
if (plugin) { |
idString = "plugin_" + plugname + "_" + idString; |
} |
html += "<span class=\"lang_" + idString + "\">"; |
if ((langxml[langarrId] !== undefined) && (langarr[langarrId] !== undefined)) { |
html += langarr[langarrId][idString]; |
} |
html += "</span>"; |
return html; |
} |
/** |
* translates all expressions based on the translation xml file<br> |
* translation expressions must be in the format <span class="lang_???"></span>, where ??? is |
* the number of the translated expression in the xml file<br><br>if a translated expression is not found in the xml |
* file nothing would be translated, so the initial value which is inside the span tag is displayed |
* @param {String} [plugin] name of the plugin |
*/ |
function changeLanguage(plugin) { |
var langarrId = current_language + "_"; |
if (plugin === undefined) { |
langarrId += "phpSysInfo"; |
} else { |
langarrId += plugin; |
} |
if (langxml[langarrId] !== undefined) { |
changeSpanLanguage(plugin); |
} else { |
langxml.push(langarrId); |
getLanguage(plugin, langarrId); |
} |
} |
function changeSpanLanguage(plugin) { |
var langId = "", langStr = "", langarrId = current_language + "_"; |
if (plugin === undefined) { |
langarrId += "phpSysInfo"; |
$('span[class*=lang_]').each(function translate(i) { |
langId = this.className.substring(5); |
if (langId.indexOf('plugin_') !== 0) { //does not begin with plugin_ |
langStr = langarr[langarrId][langId]; |
if (langStr !== undefined) { |
if (langStr.length > 0) { |
this.innerHTML = langStr; |
} |
} |
} |
}); |
$("#select").css( "display", "table-cell" ); //show if any language loaded |
$("#output").show(); |
} else { |
langarrId += plugin; |
$('span[class*=lang_plugin_'+plugin.toLowerCase()+'_]').each(function translate(i) { |
langId = this.className.substring(5); |
langStr = langarr[langarrId][langId]; |
if (langStr !== undefined) { |
if (langStr.length > 0) { |
this.innerHTML = langStr; |
} |
} |
}); |
$('#panel_'+plugin.toLowerCase()).show(); //show plugin if any language loaded |
} |
} |
function reload(initiate) { |
$("#errorbutton").css("visibility", "hidden"); |
$("#errorbutton").css('cursor', 'default'); |
$("#errorbutton").attr('data-toggle', ''); |
$("#errors").empty(); |
$.ajax({ |
dataType: "json", |
url: "xml.php?json", |
error: function(jqXHR, status, thrownError) { |
if ((status === "parsererror") && (typeof(xmlDoc = $.parseXML(jqXHR.responseText)) === "object")) { |
var errs = 0; |
try { |
$(xmlDoc).find("Error").each(function() { |
$("#errors").append("<li><b>"+$(this)[0].attributes.Function.nodeValue+"</b> - "+$(this)[0].attributes.Message.nodeValue.replace(/\n/g, "<br>")+"</li><br>"); |
errs++; |
}); |
} |
catch (err) { |
} |
if (errs > 0) { |
$("#errorbutton").attr('data-toggle', 'modal'); |
$("#errorbutton").css('cursor', 'pointer'); |
$("#errorbutton").css("visibility", "visible"); |
} |
} |
}, |
success: function (data) { |
// console.log(data); |
// data_dbg = data; |
if ((typeof(initiate) === 'boolean') && (data.Options !== undefined) && (data.Options["@attributes"] !== undefined) && ((refrtime = data.Options["@attributes"].refresh) !== undefined) && (refrtime !== "0")) { |
if ((initiate === false) && (typeof(refrTimer) === 'number')) { |
clearInterval(refrTimer); |
} |
refrTimer = setInterval(reload, refrtime); |
} |
renderErrors(data); |
renderVitals(data); |
renderHardware(data); |
renderMemory(data); |
renderFilesystem(data); |
renderNetwork(data); |
renderVoltage(data); |
renderTemperature(data); |
renderFans(data); |
renderPower(data); |
renderCurrent(data); |
renderOther(data); |
renderUPS(data); |
changeLanguage(); |
} |
}); |
for (var i = 0; i < plugins.length; i++) { |
plugin_request(plugins[i]); |
if ($("#reload_"+plugins[i]).length > 0) { |
$("#reload_"+plugins[i]).attr("title", "reload"); |
} |
} |
if ((typeof(initiate) === 'boolean') && (initiate === true)) { |
for (var j = 0; j < plugins.length; j++) { |
if ($("#reload_"+plugins[j]).length > 0) { |
$("#reload_"+plugins[j]).click(clickfunction()); |
} |
} |
} |
} |
function clickfunction(){ |
return function(){ |
plugin_request(this.id.substring(7)); //cut "reload_" from name |
$(this).attr("title", datetime()); |
}; |
} |
/** |
* load the plugin json via ajax |
*/ |
function plugin_request(pluginname) { |
$.ajax({ |
dataType: "json", |
url: "xml.php?plugin=" + pluginname + "&json", |
pluginname: pluginname, |
success: function (data) { |
try { |
// dynamic call |
window['renderPlugin_' + this.pluginname](data); |
changeLanguage(this.pluginname); |
plugin_liste.pushIfNotExist(this.pluginname); |
} |
catch (err) { |
} |
renderErrors(data); |
} |
}); |
} |
$(document).ready(function () { |
var old_template = null, cookie_template = null, cookie_language = null, plugtmp = "", blocktmp = "", ua = null, useragent = navigator.userAgent; |
if ($("#hideBootstrapLoader").val().toString()!=="true") { |
$(document).ajaxStart(function () { |
$("#loader").css("visibility", "visible"); |
}); |
$(document).ajaxStop(function () { |
$("#loader").css("visibility", "hidden"); |
}); |
} |
if (((ua=useragent.match(/Safari\/(\d+)\.[\d\.]+$/)) !== null) && (ua[1]<=534)) { |
$("#PSI_CSS_Fix")[0].setAttribute('href', 'templates/vendor/bootstrap-safari5.css'); |
} else if ((ua=useragent.match(/Firefox\/(\d+)\.[\d\.]+$/)) !== null) { |
if (ua[1]<=15) { |
$("#PSI_CSS_Fix")[0].setAttribute('href', 'templates/vendor/bootstrap-firefox15.css'); |
} else if (ua[1]<=20) { |
$("#PSI_CSS_Fix")[0].setAttribute('href', 'templates/vendor/bootstrap-firefox20.css'); |
} else if (ua[1]<=27) { |
$("#PSI_CSS_Fix")[0].setAttribute('href', 'templates/vendor/bootstrap-firefox27.css'); |
} else if (ua[1]==28) { |
$("#PSI_CSS_Fix")[0].setAttribute('href', 'templates/vendor/bootstrap-firefox28.css'); |
} |
} |
$(window).resize(); |
sorttable.init(); |
showCPUListExpanded = $("#showCPUListExpanded").val().toString()==="true"; |
showCPUInfoExpanded = $("#showCPUInfoExpanded").val().toString()==="true"; |
showNetworkInfosExpanded = $("#showNetworkInfosExpanded").val().toString()==="true"; |
showCPULoadCompact = $("#showCPULoadCompact").val().toString()==="true"; |
switch ($("#showNetworkActiveSpeed").val().toString()) { |
case "bps": showNetworkActiveSpeed = 2; |
break; |
case "true": showNetworkActiveSpeed = 1; |
break; |
default: showNetworkActiveSpeed = 0; |
} |
blocktmp = $("#blocks").val().toString(); |
if (blocktmp.length >0 ){ |
if (blocktmp === "true") { |
blocks[0] = "true"; |
} else { |
blocks = blocktmp.split(','); |
var j = 0; |
for (var i = 0; i < blocks.length; i++) { |
if ($("#block_"+blocks[i]).length > 0) { |
$("#output").children().eq(j).before($("#block_"+blocks[i])); |
j++; |
} |
} |
} |
} |
plugtmp = $("#plugins").val().toString(); |
if (plugtmp.length >0 ){ |
plugins = plugtmp.split(','); |
} |
if ($("#language option").length < 2) { |
current_language = $("#language").val().toString(); |
/* not visible any objects |
changeLanguage(); |
*/ |
/* plugin_liste not initialized yet |
for (var i = 0; i < plugin_liste.length; i++) { |
changeLanguage(plugin_liste[i]); |
} |
*/ |
} else { |
cookie_language = readCookie("psi_language"); |
if (cookie_language !== null) { |
current_language = cookie_language; |
$("#language").val(current_language); |
} else { |
current_language = $("#language").val().toString(); |
} |
/* not visible any objects |
changeLanguage(); |
*/ |
/* plugin_liste not initialized yet |
for (var i = 0; i < plugin_liste.length; i++) { |
changeLanguage(plugin_liste[i]); |
} |
*/ |
$("#langblock").css( "display", "inline-block" ); |
$("#language").change(function changeLang() { |
current_language = $("#language").val().toString(); |
createCookie('psi_language', current_language, 365); |
changeLanguage(); |
for (var i = 0; i < plugin_liste.length; i++) { |
changeLanguage(plugin_liste[i]); |
} |
return false; |
}); |
} |
if ($("#template option").length < 2) { |
switchStyle($("#template").val().toString()); |
} else { |
cookie_template = readCookie("psi_bootstrap_template"); |
if (cookie_template !== null) { |
old_template = $("#template").val(); |
$("#template").val(cookie_template); |
if ($("#template").val() === null) { |
$("#template").val(old_template); |
} |
} |
switchStyle($("#template").val().toString()); |
$("#tempblock").css( "display", "inline-block" ); |
$("#template").change(function changeTemplate() { |
switchStyle($("#template").val().toString()); |
createCookie('psi_bootstrap_template', $("#template").val().toString(), 365); |
return false; |
}); |
} |
reload(true); |
$(".logo").click(function () { |
reload(false); |
}); |
}); |
Array.prototype.push_attrs=function(element) { |
for (var i = 0; i < element.length ; i++) { |
this.push(element[i]["@attributes"]); |
} |
return i; |
}; |
function full_addr(ip_string) { |
var wrongvalue = false; |
ip_string = $.trim(ip_string).toLowerCase(); |
// ipv4 notation |
if (ip_string.match(/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$)/)) { |
ip_string ='::ffff:' + ip_string; |
} |
// replace ipv4 address if any |
var ipv4 = ip_string.match(/(.*:)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$)/); |
if (ipv4) { |
ip_string = ipv4[1]; |
ipv4 = ipv4[2].match(/[0-9]+/g); |
for (var i = 0;i < 4;i ++) { |
var byte = parseInt(ipv4[i],10); |
if (byte<256) { |
ipv4[i] = ("0" + byte.toString(16)).substr(-2); |
} else { |
wrongvalue = true; |
break; |
} |
} |
if (wrongvalue) { |
ip_string = ''; |
} else { |
ip_string += ipv4[0] + ipv4[1] + ':' + ipv4[2] + ipv4[3]; |
} |
} |
if (ip_string === '') { |
return ''; |
} |
// take care of leading and trailing :: |
ip_string = ip_string.replace(/^:|:$/g, ''); |
var ipv6 = ip_string.split(':'); |
for (var li = 0; li < ipv6.length; li ++) { |
var hex = ipv6[li]; |
if (hex !== "") { |
if (!hex.match(/^[0-9a-f]{1,4}$/)) { |
wrongvalue = true; |
break; |
} |
// normalize leading zeros |
ipv6[li] = ("0000" + hex).substr(-4); |
} |
else { |
// normalize grouped zeros :: |
hex = []; |
for (var j = ipv6.length; j <= 8; j ++) { |
hex.push('0000'); |
} |
ipv6[li] = hex.join(':'); |
} |
} |
if (!wrongvalue) { |
var out = ipv6.join(':'); |
if (out.length == 39) { |
return out; |
} else { |
return ''; |
} |
} else { |
return ''; |
} |
} |
sorttable.sort_ip=function(a,b) { |
var x = full_addr(a[0]); |
var y = full_addr(b[0]); |
if ((x === '') || (y === '')) { |
x = a[0]; |
y = b[0]; |
} |
return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
}; |
function items(data) { |
if (data !== undefined) { |
if ((data.length > 0) && (data[0] !== undefined) && (data[0]["@attributes"] !== undefined)) { |
return data; |
} else if (data["@attributes"] !== undefined ) { |
return [data]; |
} else { |
return []; |
} |
} else { |
return []; |
} |
} |
function renderVitals(data) { |
var hostname = "", ip = ""; |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('vitals', blocks) < 0))) { |
$("#block_vitals").remove(); |
if ((data.Vitals !== undefined) && (data.Vitals["@attributes"] !== undefined) && ((hostname = data.Vitals["@attributes"].Hostname) !== undefined) && ((ip = data.Vitals["@attributes"].IPAddr) !== undefined)) { |
document.title = "System information: " + hostname + " (" + ip + ")"; |
} |
return; |
} |
var directives = { |
Uptime: { |
html: function () { |
return formatUptime(this.Uptime); |
} |
}, |
LastBoot: { |
text: function () { |
var lastboot; |
var timestamp = 0; |
var datetimeFormat; |
if ((data.Generation !== undefined) && (data.Generation["@attributes"] !== undefined) && (data.Generation["@attributes"].timestamp !== undefined) ) { |
timestamp = parseInt(data.Generation["@attributes"].timestamp)*1000; //server time |
if (isNaN(timestamp)) timestamp = Number(new Date()); //client time |
} else { |
timestamp = Number(new Date()); //client time |
} |
lastboot = new Date(timestamp - (parseInt(this.Uptime)*1000)); |
if (((datetimeFormat = data.Options["@attributes"].datetimeFormat) !== undefined) && (datetimeFormat.toLowerCase() === "locale")) { |
return lastboot.toLocaleString(); |
} else { |
if (typeof(lastboot.toUTCString) === "function") { |
return lastboot.toUTCString(); |
} else { |
//deprecated |
return lastboot.toGMTString(); |
} |
} |
} |
}, |
Distro: { |
html: function () { |
return '<table class="borderless table-hover table-nopadding" style="width:100%;"><tr><td style="padding-right:4px!important;width:32px;"><img src="gfx/images/' + this.Distroicon + '" alt="" style="width:32px;height:32px;" /></td><td style="vertical-align:middle;">' + this.Distro + '</td></tr></table>'; |
} |
}, |
OS: { |
html: function () { |
return '<table class="borderless table-hover table-nopadding" style="width:100%;"><tr><td style="padding-right:4px!important;width:32px;"><img src="gfx/images/' + this.OS + '.png" alt="" style="width:32px;height:32px;" /></td><td style="vertical-align:middle;">' + this.OS + '</td></tr></table>'; |
} |
}, |
LoadAvg: { |
html: function () { |
if (this.CPULoad !== undefined) { |
return '<table class="borderless table-hover table-nopadding" style="width:100%;"><tr><td style="padding-right:4px!important;width:50%;">'+this.LoadAvg + '</td><td><div class="progress">' + |
'<div class="progress-bar progress-bar-info" style="width:' + round(this.CPULoad,0) + '%;"></div>' + |
'</div><div class="percent">' + round(this.CPULoad,0) + '%</div></td></tr></table>'; |
} else { |
return this.LoadAvg; |
} |
} |
}, |
Processes: { |
html: function () { |
var processes = "", p111 = 0, p112 = 0, p113 = 0, p114 = 0, p115 = 0, p116 = 0; |
var not_first = false; |
processes = parseInt(this.Processes); |
if (this.ProcessesRunning !== undefined) { |
p111 = parseInt(this.ProcessesRunning); |
} |
if (this.ProcessesSleeping !== undefined) { |
p112 = parseInt(this.ProcessesSleeping); |
} |
if (this.ProcessesStopped !== undefined) { |
p113 = parseInt(this.ProcessesStopped); |
} |
if (this.ProcessesZombie !== undefined) { |
p114 = parseInt(this.ProcessesZombie); |
} |
if (this.ProcessesWaiting !== undefined) { |
p115 = parseInt(this.ProcessesWaiting); |
} |
if (this.ProcessesOther !== undefined) { |
p116 = parseInt(this.ProcessesOther); |
} |
if (p111 || p112 || p113 || p114 || p115 || p116) { |
processes += " ("; |
for (var proc_type in {111:0,112:1,113:2,114:3,115:4,116:5}) { |
if (eval("p" + proc_type)) { |
if (not_first) { |
processes += ", "; |
} |
processes += eval("p" + proc_type) + String.fromCharCode(160) + genlang(proc_type); |
not_first = true; |
} |
} |
processes += ")"; |
} |
return processes; |
} |
} |
}; |
if (data.Vitals["@attributes"].SysLang === undefined) { |
$("#tr_SysLang").hide(); |
} |
if (data.Vitals["@attributes"].CodePage === undefined) { |
$("#tr_CodePage").hide(); |
} |
if (data.Vitals["@attributes"].Processes === undefined) { |
$("#tr_Processes").hide(); |
} |
$('#vitals').render(data.Vitals["@attributes"], directives); |
if ((data.Vitals !== undefined) && (data.Vitals["@attributes"] !== undefined) && ((hostname = data.Vitals["@attributes"].Hostname) !== undefined) && ((ip = data.Vitals["@attributes"].IPAddr) !== undefined)) { |
document.title = "System information: " + hostname + " (" + ip + ")"; |
} |
$("#block_vitals").show(); |
} |
function renderHardware(data) { |
var hw_type, datas, proc_param, i; |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('hardware', blocks) < 0))) { |
$("#block_hardware").remove(); |
return; |
} |
var directives = { |
Model: { |
text: function () { |
return this.Model; |
} |
}, |
CpuSpeed: { |
html: function () { |
return formatHertz(this.CpuSpeed); |
} |
}, |
CpuSpeedMax: { |
html: function () { |
return formatHertz(this.CpuSpeedMax); |
} |
}, |
CpuSpeedMin: { |
html: function () { |
return formatHertz(this.CpuSpeedMin); |
} |
}, |
Cache: { |
html: function () { |
return formatBytes(this.Cache, data.Options["@attributes"].byteFormat); |
} |
}, |
BusSpeed: { |
html: function () { |
return formatHertz(this.BusSpeed); |
} |
}, |
Cputemp: { |
html: function () { |
return formatTemp(this.Cputemp, data.Options["@attributes"].tempFormat); |
} |
}, |
Bogomips: { |
text: function () { |
return parseInt(this.Bogomips); |
} |
}, |
Load: { |
html: function () { |
return '<div class="progress">' + |
'<div class="progress-bar progress-bar-info" style="width:' + round(this.Load,0) + '%;"></div>' + |
'</div><div class="percent">' + round(this.Load,0) + '%</div>'; |
} |
} |
}; |
var hw_directives = { |
hwName: { |
html: function() { |
return this.Name; |
} |
}, |
hwCount: { |
text: function() { |
if ((this.Count !== undefined) && !isNaN(this.Count) && (parseInt(this.Count)>1)) { |
return parseInt(this.Count); |
} else { |
return ""; |
} |
} |
} |
}; |
var dev_directives = { |
Capacity: { |
html: function () { |
return formatBytes(this.Capacity, data.Options["@attributes"].byteFormat); |
} |
} |
}; |
var html=""; |
if ((data.Hardware["@attributes"] !== undefined) && (data.Hardware["@attributes"].Name !== undefined)) { |
html+="<tr id=\"hardware-Machine\">"; |
html+="<th style=\"width:8%;\">"+genlang(107)+"</th>"; //Machine |
html+="<td colspan=\"2\"><span data-bind=\"Name\"></span></td>"; |
html+="</tr>"; |
} |
var paramlist = {CpuSpeed:13,CpuSpeedMax:100,CpuSpeedMin:101,Cache:15,Virt:94,BusSpeed:14,Bogomips:16,Cputemp:51,Manufacturer:122,Load:9}; |
try { |
datas = items(data.Hardware.CPU.CpuCore); |
for (i = 0; i < datas.length; i++) { |
if (i === 0) { |
html+="<tr id=\"hardware-CPU\" class=\"treegrid-CPU\">"; |
html+="<th>CPU</th>"; |
html+="<td><span class=\"treegrid-span\">" + genlang(119) + ":</span></td>"; //Number of processors |
html+="<td class=\"rightCell\"><span id=\"CPUCount\"></span></td>"; |
html+="</tr>"; |
} |
html+="<tr id=\"hardware-CPU-" + i +"\" class=\"treegrid-CPU-" + i +" treegrid-parent-CPU\">"; |
html+="<th></th>"; |
if (showCPULoadCompact && (datas[i]["@attributes"].Load !== undefined)) { |
html+="<td><span class=\"treegrid-span\" data-bind=\"Model\"></span></td>"; |
html+="<td style=\"width:15%;\" class=\"rightCell\"><span data-bind=\"Load\"></span></td>"; |
} else { |
html+="<td colspan=\"2\"><span class=\"treegrid-span\" data-bind=\"Model\"></span></td>"; |
} |
html+="</tr>"; |
for (proc_param in paramlist) { |
if (((proc_param !== 'Load') || !showCPULoadCompact) && (datas[i]["@attributes"][proc_param] !== undefined)) { |
html+="<tr id=\"hardware-CPU-" + i + "-" + proc_param + "\" class=\"treegrid-parent-CPU-" + i +"\">"; |
html+="<th></th>"; |
html+="<td><span class=\"treegrid-span\">" + genlang(paramlist[proc_param]) + "<span></td>"; |
html+="<td class=\"rightCell\"><span data-bind=\"" + proc_param + "\"></span></td>"; |
html+="</tr>"; |
} |
} |
} |
} |
catch (err) { |
$("#hardware-CPU").hide(); |
} |
var devparamlist = {Capacity:43,Manufacturer:122,Product:123,Serial:124}; |
for (hw_type in {PCI:0,IDE:1,SCSI:2,NVMe:3,USB:4,TB:5,I2C:6}) { |
try { |
datas = items(data.Hardware[hw_type].Device); |
for (i = 0; i < datas.length; i++) { |
if (i === 0) { |
html+="<tr id=\"hardware-" + hw_type + "\" class=\"treegrid-" + hw_type + "\">"; |
html+="<th>" + hw_type + "</th>"; |
html+="<td><span class=\"treegrid-span\">" + genlang('120') + ":</span></td>"; //Number of devices |
html+="<td class=\"rightCell\"><span id=\"" + hw_type + "Count\"></span></td>"; |
html+="</tr>"; |
} |
html+="<tr id=\"hardware-" + hw_type + "-" + i +"\" class=\"treegrid-" + hw_type + "-" + i +" treegrid-parent-" + hw_type + "\">"; |
html+="<th></th>"; |
html+="<td><span class=\"treegrid-span\" data-bind=\"hwName\"></span></td>"; |
html+="<td class=\"rightCell\"><span data-bind=\"hwCount\"></span></td>"; |
html+="</tr>"; |
for (proc_param in devparamlist) { |
if (datas[i]["@attributes"][proc_param] !== undefined) { |
html+="<tr id=\"hardware-" + hw_type +"-" + i + "-" + proc_param + "\" class=\"treegrid-parent-" + hw_type +"-" + i +"\">"; |
html+="<th></th>"; |
html+="<td><span class=\"treegrid-span\">" + genlang(devparamlist[proc_param]) + "<span></td>"; |
html+="<td class=\"rightCell\"><span data-bind=\"" + proc_param + "\"></span></td>"; |
html+="</tr>"; |
} |
} |
} |
} |
catch (err) { |
$("#hardware-data"+hw_type).hide(); |
} |
} |
$("#hardware-data").empty().append(html); |
if ((data.Hardware["@attributes"] !== undefined) && (data.Hardware["@attributes"].Name !== undefined)) { |
$('#hardware-Machine').render(data.Hardware["@attributes"]); |
} |
try { |
datas = items(data.Hardware.CPU.CpuCore); |
for (i = 0; i < datas.length; i++) { |
$('#hardware-CPU-'+ i).render(datas[i]["@attributes"], directives); |
for (proc_param in paramlist) { |
if (((proc_param !== 'Load') || !showCPULoadCompact) && (datas[i]["@attributes"][proc_param] !== undefined)) { |
$('#hardware-CPU-'+ i +'-'+proc_param).render(datas[i]["@attributes"], directives); |
} |
} |
} |
if (i > 0) { |
$("#CPUCount").html(i); |
} |
} |
catch (err) { |
$("#hardware-CPU").hide(); |
} |
var licz; |
for (hw_type in {PCI:0,IDE:1,SCSI:2,NVMe:3,USB:4,TB:5,I2C:6}) { |
try { |
licz = 0; |
datas = items(data.Hardware[hw_type].Device); |
for (i = 0; i < datas.length; i++) { |
$('#hardware-'+hw_type+'-'+ i).render(datas[i]["@attributes"], hw_directives); |
if ((datas[i]["@attributes"].Count !== undefined) && !isNaN(datas[i]["@attributes"].Count) && (parseInt(datas[i]["@attributes"].Count)>1)) { |
licz += parseInt(datas[i]["@attributes"].Count); |
} else { |
licz++; |
} |
for (proc_param in devparamlist) { |
if ((datas[i]["@attributes"][proc_param] !== undefined)) { |
$('#hardware-'+hw_type+'-'+ i +'-'+proc_param).render(datas[i]["@attributes"], dev_directives); |
} |
} |
} |
if (i > 0) { |
$("#" + hw_type + "Count").html(licz); |
} |
} |
catch (err) { |
$("#hardware-"+hw_type).hide(); |
} |
} |
$('#hardware').treegrid({ |
initialState: 'collapsed', |
expanderExpandedClass: 'normalicon normalicon-down', |
expanderCollapsedClass: 'normalicon normalicon-right' |
}); |
if (showCPUListExpanded) { |
try { |
$('#hardware-CPU').treegrid('expand'); |
} |
catch (err) { |
} |
} |
if (showCPUInfoExpanded && showCPUListExpanded) { |
try { |
datas = items(data.Hardware.CPU.CpuCore); |
for (i = 0; i < datas.length; i++) { |
$('#hardware-CPU-'+i).treegrid('expand'); |
} |
} |
catch (err) { |
} |
} |
$("#block_hardware").show(); |
} |
function renderMemory(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('memory', blocks) < 0))) { |
$("#block_memory").remove(); |
return; |
} |
var directives = { |
Total: { |
html: function () { |
return formatBytes(this["@attributes"].Total, data.Options["@attributes"].byteFormat); |
} |
}, |
Free: { |
html: function () { |
return formatBytes(this["@attributes"].Free, data.Options["@attributes"].byteFormat); |
} |
}, |
Used: { |
html: function () { |
return formatBytes(this["@attributes"].Used, data.Options["@attributes"].byteFormat); |
} |
}, |
Usage: { |
html: function () { |
if ((this.Details === undefined) || (this.Details["@attributes"] === undefined)) { |
return '<div class="progress">' + |
'<div class="progress-bar progress-bar-info" style="width:' + this["@attributes"].Percent + '%;"></div>' + |
'</div><div class="percent">' + this["@attributes"].Percent + '%</div>'; |
} else { |
var rest = parseInt(this["@attributes"].Percent); |
var html = '<div class="progress">'; |
if ((this.Details["@attributes"].AppPercent !== undefined) && (this.Details["@attributes"].AppPercent > 0)) { |
html += '<div class="progress-bar progress-bar-info" style="width:' + this.Details["@attributes"].AppPercent + '%;"></div>'; |
rest -= parseInt(this.Details["@attributes"].AppPercent); |
} |
if ((this.Details["@attributes"].CachedPercent !== undefined) && (this.Details["@attributes"].CachedPercent > 0)) { |
html += '<div class="progress-bar progress-bar-warning" style="width:' + this.Details["@attributes"].CachedPercent + '%;"></div>'; |
rest -= parseInt(this.Details["@attributes"].CachedPercent); |
} |
if ((this.Details["@attributes"].BuffersPercent !== undefined) && (this.Details["@attributes"].BuffersPercent > 0)) { |
html += '<div class="progress-bar progress-bar-danger" style="width:' + this.Details["@attributes"].BuffersPercent + '%;"></div>'; |
rest -= parseInt(this.Details["@attributes"].BuffersPercent); |
} |
if (rest > 0) { |
html += '<div class="progress-bar progress-bar-success" style="width:' + rest + '%;"></div>'; |
} |
html += '</div>'; |
html += '<div class="percent">' + 'Total: ' + this["@attributes"].Percent + '% ' + '<i>('; |
var not_first = false; |
if (this.Details["@attributes"].AppPercent !== undefined) { |
html += genlang(64) + ': '+ this.Details["@attributes"].AppPercent + '%'; //Kernel + apps |
not_first = true; |
} |
if (this.Details["@attributes"].CachedPercent !== undefined) { |
if (not_first) html += ' - '; |
html += genlang(66) + ': ' + this.Details["@attributes"].CachedPercent + '%'; //Cache |
not_first = true; |
} |
if (this.Details["@attributes"].BuffersPercent !== undefined) { |
if (not_first) html += ' - '; |
html += genlang(65) + ': ' + this.Details["@attributes"].BuffersPercent + '%'; //Buffers |
} |
html += ')</i></div>'; |
return html; |
} |
} |
}, |
Type: { |
html: function () { |
return genlang(28); //Physical Memory |
} |
} |
}; |
var directive_swap = { |
Total: { |
html: function () { |
return formatBytes(this.Total, data.Options["@attributes"].byteFormat); |
} |
}, |
Free: { |
html: function () { |
return formatBytes(this.Free, data.Options["@attributes"].byteFormat); |
} |
}, |
Used: { |
html: function () { |
return formatBytes(this.Used, data.Options["@attributes"].byteFormat); |
} |
}, |
Usage: { |
html: function () { |
return '<div class="progress">' + |
'<div class="progress-bar progress-bar-info" style="width:' + this.Percent + '%;"></div>' + |
'</div><div class="percent">' + this.Percent + '%</div>'; |
} |
}, |
Name: { |
html: function () { |
return this.Name + '<br>' + ((this.MountPoint !== undefined) ? this.MountPoint : this.MountPointID); |
} |
} |
}; |
var data_memory = []; |
if (data.Memory.Swap !== undefined) { |
var datas = items(data.Memory.Swap.Mount); |
data_memory.push_attrs(datas); |
$('#swap-data').render(data_memory, directive_swap); |
$('#swap-data').show(); |
} else { |
$('#swap-data').hide(); |
} |
$('#memory-data').render(data.Memory, directives); |
$("#block_memory").show(); |
} |
function renderFilesystem(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('filesystem', blocks) < 0))) { |
$("#block_filesystem").remove(); |
return; |
} |
var directives = { |
Total: { |
html: function () { |
if ((this.Ignore !== undefined) && (this.Ignore > 0)) { |
return formatBytes(this.Total, data.Options["@attributes"].byteFormat, true); |
} else { |
return formatBytes(this.Total, data.Options["@attributes"].byteFormat); |
} |
} |
}, |
Free: { |
html: function () { |
if ((this.Ignore !== undefined) && (this.Ignore > 0)) { |
return formatBytes(this.Free, data.Options["@attributes"].byteFormat, true); |
} else { |
return formatBytes(this.Free, data.Options["@attributes"].byteFormat); |
} |
} |
}, |
Used: { |
html: function () { |
if ((this.Ignore !== undefined) && (this.Ignore >= 2)) { |
return formatBytes(this.Used, data.Options["@attributes"].byteFormat, true); |
} else { |
return formatBytes(this.Used, data.Options["@attributes"].byteFormat); |
} |
} |
}, |
MountPoint: { |
text: function () { |
return ((this.MountPoint !== undefined) ? this.MountPoint : this.MountPointID); |
} |
}, |
Name: { |
html: function () { |
return this.Name.replace(/;/g, ";<wbr>") + ((this.MountOptions !== undefined) ? '<br><i>(' + this.MountOptions + ')</i>' : ''); |
} |
}, |
Percent: { |
html: function () { |
return '<div class="progress">' + '<div class="' + |
( ( ((this.Ignore == undefined) || (this.Ignore < 3)) && ((data.Options["@attributes"].threshold !== undefined) && |
(parseInt(this.Percent) >= parseInt(data.Options["@attributes"].threshold))) ) ? 'progress-bar progress-bar-danger' : 'progress-bar progress-bar-info' ) + |
'" style="width:' + this.Percent + '% ;"></div>' + |
'</div>' + '<div class="percent">' + this.Percent + '% ' + ((this.Inodes !== undefined) ? '<i>(' + this.Inodes + '%)</i>' : '') + '</div>'; |
} |
} |
}; |
try { |
var fs_data = []; |
var datas = items(data.FileSystem.Mount); |
var total = {Total:0,Free:0,Used:0}; |
for (var i = 0; i < datas.length; i++) { |
fs_data.push(datas[i]["@attributes"]); |
if ((datas[i]["@attributes"].Ignore !== undefined) && (datas[i]["@attributes"].Ignore > 0)) { |
if (datas[i]["@attributes"].Ignore == 1) { |
total.Total += parseInt(datas[i]["@attributes"].Used); |
total.Used += parseInt(datas[i]["@attributes"].Used); |
} |
} else { |
total.Total += parseInt(datas[i]["@attributes"].Total); |
total.Free += parseInt(datas[i]["@attributes"].Free); |
total.Used += parseInt(datas[i]["@attributes"].Used); |
} |
total.Percent = (total.Total !== 0) ? round((total.Used / total.Total) * 100, 2) : 0; |
} |
if (i > 0) { |
$('#filesystem-data').render(fs_data, directives); |
$('#filesystem-foot').render(total, directives); |
$('#filesystem_MountPoint').removeClass("sorttable_sorted"); //reset sort order |
// sorttable.innerSortFunction.apply(document.getElementById('filesystem_MountPoint'), []); |
sorttable.innerSortFunction.apply($('#filesystem_MountPoint')[0], []); |
$("#block_filesystem").show(); |
} else { |
$("#block_filesystem").hide(); |
} |
} |
catch (err) { |
$("#block_filesystem").hide(); |
} |
} |
function renderNetwork(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('network', blocks) < 0))) { |
$("#block_network").remove(); |
return; |
} |
var directives = { |
RxBytes: { |
html: function () { |
var htmladd = ''; |
if (showNetworkActiveSpeed && ($.inArray(this.Name, oldnetwork) >= 0)) { |
var diff, difftime; |
if (((diff = this.RxBytes - oldnetwork[this.Name].RxBytes) > 0) && ((difftime = data.Generation["@attributes"].timestamp - oldnetwork[this.Name].timestamp) > 0)) { |
if (showNetworkActiveSpeed == 2) { |
htmladd ="<br><i>("+formatBPS(round(8*diff/difftime, 2))+")</i>"; |
} else { |
htmladd ="<br><i>("+formatBytes(round(diff/difftime, 2), data.Options["@attributes"].byteFormat)+"/s)</i>"; |
} |
} |
} |
return formatBytes(this.RxBytes, data.Options["@attributes"].byteFormat) + htmladd; |
} |
}, |
TxBytes: { |
html: function () { |
var htmladd = ''; |
if (showNetworkActiveSpeed && ($.inArray(this.Name, oldnetwork) >= 0)) { |
var diff, difftime; |
if (((diff = this.TxBytes - oldnetwork[this.Name].TxBytes) > 0) && ((difftime = data.Generation["@attributes"].timestamp - oldnetwork[this.Name].timestamp) > 0)) { |
if (showNetworkActiveSpeed == 2) { |
htmladd ="<br><i>("+formatBPS(round(8*diff/difftime, 2))+")</i>"; |
} else { |
htmladd ="<br><i>("+formatBytes(round(diff/difftime, 2), data.Options["@attributes"].byteFormat)+"/s)</i>"; |
} |
} |
} |
return formatBytes(this.TxBytes, data.Options["@attributes"].byteFormat) + htmladd; |
} |
}, |
Drops: { |
html: function () { |
return this.Err + "/<wbr>" + this.Drops; |
} |
} |
}; |
var html = ""; |
var preoldnetwork = []; |
try { |
var datas = items(data.Network.NetDevice); |
for (var i = 0; i < datas.length; i++) { |
html+="<tr id=\"network-" + i +"\" class=\"treegrid-network-" + i + "\">"; |
html+="<td><span class=\"treegrid-spanbold\" data-bind=\"Name\"></span></td>"; |
html+="<td class=\"rightCell\"><span data-bind=\"RxBytes\"></span></td>"; |
html+="<td class=\"rightCell\"><span data-bind=\"TxBytes\"></span></td>"; |
html+="<td class=\"rightCell\"><span data-bind=\"Drops\"></span></td>"; |
html+="</tr>"; |
var info = datas[i]["@attributes"].Info; |
if ( (info !== undefined) && (info !== "") ) { |
var infos = info.replace(/:/g, "<wbr>:").split(";"); /* split long addresses */ |
for (var j = 0; j < infos.length; j++){ |
html +="<tr class=\"treegrid-parent-network-" + i + "\"><td colspan=\"4\"><span class=\"treegrid-span\">" + infos[j] + "</span></td></tr>"; |
} |
} |
} |
$("#network-data").empty().append(html); |
if (i > 0) { |
for (var k = 0; k < datas.length; k++) { |
$('#network-' + k).render(datas[k]["@attributes"], directives); |
if (showNetworkActiveSpeed) { |
preoldnetwork.pushIfNotExist(datas[k]["@attributes"].Name); |
preoldnetwork[datas[k]["@attributes"].Name] = {timestamp:data.Generation["@attributes"].timestamp, RxBytes:datas[k]["@attributes"].RxBytes, TxBytes:datas[k]["@attributes"].TxBytes}; |
} |
} |
$('#network').treegrid({ |
initialState: showNetworkInfosExpanded?'expanded':'collapsed', |
expanderExpandedClass: 'normalicon normalicon-down', |
expanderCollapsedClass: 'normalicon normalicon-right' |
}); |
$("#block_network").show(); |
} else { |
$("#block_network").hide(); |
} |
} |
catch (err) { |
$("#block_network").hide(); |
} |
if (showNetworkActiveSpeed) { |
while (oldnetwork.length > 0) { |
delete oldnetwork[oldnetwork.length-1]; //remove last object |
oldnetwork.pop(); //remove last object reference from array |
} |
oldnetwork = preoldnetwork; |
} |
} |
function renderVoltage(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('voltage', blocks) < 0))) { |
$("#block_voltage").remove(); |
return; |
} |
var directives = { |
Value: { |
text: function () { |
return round(this.Value,2) + String.fromCharCode(160) + "V"; |
} |
}, |
Min: { |
text: function () { |
if (this.Min !== undefined) |
return round(this.Min,2) + String.fromCharCode(160) + "V"; |
} |
}, |
Max: { |
text: function () { |
if (this.Max !== undefined) |
return round(this.Max,2) + String.fromCharCode(160) + "V"; |
} |
}, |
Label: { |
html: function () { |
if (this.Event === undefined) |
return this.Label; |
else |
return this.Label + " <img style=\"vertical-align:middle;width:20px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\"" + this.Event + "\"/>"; |
} |
} |
}; |
try { |
var voltage_data = []; |
var datas = items(data.MBInfo.Voltage.Item); |
if (voltage_data.push_attrs(datas) > 0) { |
$('#voltage-data').render(voltage_data, directives); |
$("#block_voltage").show(); |
} else { |
$("#block_voltage").hide(); |
} |
} |
catch (err) { |
$("#block_voltage").hide(); |
} |
} |
function renderTemperature(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('temperature', blocks) < 0))) { |
$("#block_temperature").remove(); |
return; |
} |
var directives = { |
Value: { |
html: function () { |
return formatTemp(this.Value, data.Options["@attributes"].tempFormat); |
} |
}, |
Max: { |
html: function () { |
if (this.Max !== undefined) |
return formatTemp(this.Max, data.Options["@attributes"].tempFormat); |
} |
}, |
Label: { |
html: function () { |
if (this.Event === undefined) |
return this.Label; |
else |
return this.Label + " <img style=\"vertical-align:middle;width:20px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\"" + this.Event + "\"/>"; |
} |
} |
}; |
try { |
var temperature_data = []; |
var datas = items(data.MBInfo.Temperature.Item); |
if (temperature_data.push_attrs(datas) > 0) { |
$('#temperature-data').render(temperature_data, directives); |
$("#block_temperature").show(); |
} else { |
$("#block_temperature").hide(); |
} |
} |
catch (err) { |
$("#block_temperature").hide(); |
} |
} |
function renderFans(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('fans', blocks) < 0))) { |
$("#block_fans").remove(); |
return; |
} |
var directives = { |
Value: { |
html: function () { |
return round(this.Value,0) + String.fromCharCode(160) + genlang(63); //RPM |
} |
}, |
Min: { |
html: function () { |
if (this.Min !== undefined) |
return round(this.Min,0) + String.fromCharCode(160) + genlang(63); //RPM |
} |
}, |
Label: { |
html: function () { |
if (this.Event === undefined) |
return this.Label; |
else |
return this.Label + " <img style=\"vertical-align:middle;width:20px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\"" + this.Event + "\"/>"; |
} |
} |
}; |
try { |
var fans_data = []; |
var datas = items(data.MBInfo.Fans.Item); |
if (fans_data.push_attrs(datas) > 0) { |
$('#fans-data').render(fans_data, directives); |
$("#block_fans").show(); |
} else { |
$("#block_fans").hide(); |
} |
} |
catch (err) { |
$("#block_fans").hide(); |
} |
} |
function renderPower(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('power', blocks) < 0))) { |
$("#block_power").remove(); |
return; |
} |
var directives = { |
Value: { |
text: function () { |
return round(this.Value,2) + String.fromCharCode(160) + "W"; |
} |
}, |
Max: { |
text: function () { |
if (this.Max !== undefined) |
return round(this.Max,2) + String.fromCharCode(160) + "W"; |
} |
}, |
Label: { |
html: function () { |
if (this.Event === undefined) |
return this.Label; |
else |
return this.Label + " <img style=\"vertical-align:middle;width:20px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\"" + this.Event + "\"/>"; |
} |
} |
}; |
try { |
var power_data = []; |
var datas = items(data.MBInfo.Power.Item); |
if (power_data.push_attrs(datas) > 0) { |
$('#power-data').render(power_data, directives); |
$("#block_power").show(); |
} else { |
$("#block_power").hide(); |
} |
} |
catch (err) { |
$("#block_power").hide(); |
} |
} |
function renderCurrent(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('current', blocks) < 0))) { |
$("#block_current").remove(); |
return; |
} |
var directives = { |
Value: { |
text: function () { |
return round(this.Value,2) + String.fromCharCode(160) + "A"; |
} |
}, |
Min: { |
text: function () { |
if (this.Min !== undefined) |
return round(this.Min,2) + String.fromCharCode(160) + "A"; |
} |
}, |
Max: { |
text: function () { |
if (this.Max !== undefined) |
return round(this.Max,2) + String.fromCharCode(160) + "A"; |
} |
}, |
Label: { |
html: function () { |
if (this.Event === undefined) |
return this.Label; |
else |
return this.Label + " <img style=\"vertical-align:middle;width:20px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\"" + this.Event + "\"/>"; |
} |
} |
}; |
try { |
var current_data = []; |
var datas = items(data.MBInfo.Current.Item); |
if (current_data.push_attrs(datas) > 0) { |
$('#current-data').render(current_data, directives); |
$("#block_current").show(); |
} else { |
$("#block_current").hide(); |
} |
} |
catch (err) { |
$("#block_current").hide(); |
} |
} |
function renderOther(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('other', blocks) < 0))) { |
$("#block_other").remove(); |
return; |
} |
var directives = { |
Label: { |
html: function () { |
if (this.Event === undefined) |
return this.Label; |
else |
return this.Label + " <img style=\"vertical-align:middle;width:20px;\" src=\"./gfx/attention.gif\" alt=\"!\" title=\"" + this.Event + "\"/>"; |
} |
} |
}; |
try { |
var other_data = []; |
var datas = items(data.MBInfo.Other.Item); |
if (other_data.push_attrs(datas) > 0) { |
$('#other-data').render(other_data, directives); |
$("#block_other").show(); |
} else { |
$("#block_other").hide(); |
} |
} |
catch (err) { |
$("#block_other").hide(); |
} |
} |
function renderUPS(data) { |
if ((blocks.length <= 0) || ((blocks[0] !== "true") && ($.inArray('ups', blocks) < 0))) { |
$("#block_ups").remove(); |
return; |
} |
var i, datas, proc_param; |
var directives = { |
Name: { |
text: function () { |
return this.Name + ((this.Mode !== undefined) ? " (" + this.Mode + ")" : ""); |
} |
}, |
LineVoltage: { |
html: function () { |
return this.LineVoltage + String.fromCharCode(160) + genlang(82); //V |
} |
}, |
LineFrequency: { |
html: function () { |
return this.LineFrequency + String.fromCharCode(160) + genlang(109); //Hz |
} |
}, |
BatteryVoltage: { |
html: function () { |
return this.BatteryVoltage + String.fromCharCode(160) + genlang(82); //V |
} |
}, |
TimeLeftMinutes: { |
html: function () { |
return this.TimeLeftMinutes + String.fromCharCode(160) + genlang(83); //minutes |
} |
}, |
LoadPercent: { |
html: function () { |
return '<div class="progress">' + |
'<div class="progress-bar progress-bar-info" style="width:' + round(this.LoadPercent,0) + '%;"></div>' + |
'</div><div class="percent">' + round(this.LoadPercent,0) + '%</div>'; |
} |
}, |
BatteryChargePercent: { |
html: function () { |
return '<div class="progress">' + |
'<div class="progress-bar progress-bar-info" style="width:' + round(this.BatteryChargePercent,0) + '%;"></div>' + |
'</div><div class="percent">' + round(this.BatteryChargePercent,0) + '%</div>'; |
} |
} |
}; |
if ((data.UPSInfo !== undefined) && (items(data.UPSInfo.UPS).length > 0)) { |
var html=""; |
var paramlist = {Model:70,StartTime:72,Status:73,Temperature:84,OutagesCount:74,LastOutage:75,LastOutageFinish:76,LineVoltage:77,LineFrequency:108,LoadPercent:78,BatteryDate:104,BatteryVoltage:79,BatteryChargePercent:80,TimeLeftMinutes:81}; |
try { |
datas = items(data.UPSInfo.UPS); |
for (i = 0; i < datas.length; i++) { |
html+="<tr id=\"ups-" + i +"\" class=\"treegrid-UPS-" + i+ "\">"; |
html+="<td colspan=\"2\"><span class=\"treegrid-spanbold\" data-bind=\"Name\"></span></td>"; |
html+="</tr>"; |
for (proc_param in paramlist) { |
if (datas[i]["@attributes"][proc_param] !== undefined) { |
html+="<tr id=\"ups-" + i + "-" + proc_param + "\" class=\"treegrid-parent-UPS-" + i +"\">"; |
html+="<td style=\"width:60%;\"><span class=\"treegrid-spanbold\">" + genlang(paramlist[proc_param]) + "</span></td>"; |
html+="<td class=\"rightCell\"><span data-bind=\"" + proc_param + "\"></span></td>"; |
html+="</tr>"; |
} |
} |
} |
} |
catch (err) { |
} |
if ((data.UPSInfo["@attributes"] !== undefined) && (data.UPSInfo["@attributes"].ApcupsdCgiLinks === "1")) { |
html+="<tr>"; |
html+="<td colspan=\"2\">(<a title='details' href='/cgi-bin/apcupsd/multimon.cgi' target='apcupsdcgi'>"+genlang(99)+"</a>)</td>"; |
html+="</tr>"; |
} |
$("#ups-data").empty().append(html); |
try { |
datas = items(data.UPSInfo.UPS); |
for (i = 0; i < datas.length; i++) { |
$('#ups-'+ i).render(datas[i]["@attributes"], directives); |
for (proc_param in paramlist) { |
if (datas[i]["@attributes"][proc_param] !== undefined) { |
$('#ups-'+ i +'-'+proc_param).render(datas[i]["@attributes"], directives); |
} |
} |
} |
} |
catch (err) { |
} |
$('#ups').treegrid({ |
initialState: 'expanded', |
expanderExpandedClass: 'normalicon normalicon-down', |
expanderCollapsedClass: 'normalicon normalicon-right' |
}); |
$("#block_ups").show(); |
} else { |
$("#block_ups").hide(); |
} |
} |
function renderErrors(data) { |
try { |
var datas = items(data.Errors.Error); |
for (var i = 0; i < datas.length; i++) { |
$("#errors").append("<li><b>"+datas[i]["@attributes"].Function+"</b> - "+datas[i]["@attributes"].Message.replace(/\n/g, "<br>")+"</li><br>"); |
} |
if (i > 0) { |
$("#errorbutton").attr('data-toggle', 'modal'); |
$("#errorbutton").css('cursor', 'pointer'); |
$("#errorbutton").css("visibility", "visible"); |
} |
} |
catch (err) { |
$("#errorbutton").css("visibility", "hidden"); |
$("#errorbutton").css('cursor', 'default'); |
$("#errorbutton").attr('data-toggle', ''); |
} |
} |
/** |
* format seconds to a better readable statement with days, hours and minutes |
* @param {Number} sec seconds that should be formatted |
* @return {String} html string with no breaking spaces and translation statemen |
*/ |
function formatUptime(sec) { |
var txt = "", intMin = 0, intHours = 0, intDays = 0; |
intMin = sec / 60; |
intHours = intMin / 60; |
intDays = Math.floor(intHours / 24); |
intHours = Math.floor(intHours - (intDays * 24)); |
intMin = Math.floor(intMin - (intDays * 60 * 24) - (intHours * 60)); |
if (intDays) { |
txt += intDays.toString() + String.fromCharCode(160) + genlang(48) + String.fromCharCode(160); //days |
} |
if (intHours) { |
txt += intHours.toString() + String.fromCharCode(160) + genlang(49) + String.fromCharCode(160); //hours |
} |
return txt + intMin.toString() + String.fromCharCode(160) + genlang(50); //Minutes |
} |
/** |
* format a celcius temperature to fahrenheit and also append the right suffix |
* @param {String} degreeC temperature in celvius |
* @param {jQuery} xml phpSysInfo-XML |
* @return {String} html string with no breaking spaces and translation statements |
*/ |
function formatTemp(degreeC, tempFormat) { |
var degree = 0; |
if (tempFormat === undefined) { |
tempFormat = "c"; |
} |
degree = parseFloat(degreeC); |
if (isNaN(degreeC)) { |
return "---"; |
} else { |
switch (tempFormat.toLowerCase()) { |
case "f": |
return round((((9 * degree) / 5) + 32), 1) + String.fromCharCode(160) + genlang(61); |
case "c": |
return round(degree, 1) + String.fromCharCode(160) + genlang(60); |
case "c-f": |
return round(degree, 1) + String.fromCharCode(160) + genlang(60) + "<br><i>(" + round((((9 * degree) / 5) + 32), 1) + String.fromCharCode(160) + genlang(61) + ")</i>"; |
case "f-c": |
return round((((9 * degree) / 5) + 32), 1) + String.fromCharCode(160) + genlang(61) + "<br><i>(" + round(degree, 1) + String.fromCharCode(160) + genlang(60) + ")</i>"; |
} |
} |
} |
/** |
* format a given MHz value to a better readable statement with the right suffix |
* @param {Number} mhertz mhertz value that should be formatted |
* @return {String} html string with no breaking spaces and translation statements |
*/ |
function formatHertz(mhertz) { |
if ((mhertz >= 0) && (mhertz < 1000)) { |
return mhertz.toString() + String.fromCharCode(160) + genlang(92); |
} else { |
if (mhertz >= 1000) { |
return round(mhertz / 1000, 2) + String.fromCharCode(160) + genlang(93); |
} else { |
return ""; |
} |
} |
} |
/** |
* format the byte values into a user friendly value with the corespondenting unit expression<br>support is included |
* for binary and decimal output<br>user can specify a constant format for all byte outputs or the output is formated |
* automatically so that every value can be read in a user friendly way |
* @param {Number} bytes value that should be converted in the corespondenting format, which is specified in the phpsysinfo.ini |
* @param {jQuery} xml phpSysInfo-XML |
* @param {parenths} if true then add parentheses |
* @return {String} string of the converted bytes with the translated unit expression |
*/ |
function formatBytes(bytes, byteFormat, parenths) { |
var show = ""; |
if (byteFormat === undefined) { |
byteFormat = "auto_binary"; |
} |
switch (byteFormat.toLowerCase()) { |
case "pib": |
show += round(bytes / Math.pow(1024, 5), 2); |
show += String.fromCharCode(160) + genlang(90); |
break; |
case "tib": |
show += round(bytes / Math.pow(1024, 4), 2); |
show += String.fromCharCode(160) + genlang(86); |
break; |
case "gib": |
show += round(bytes / Math.pow(1024, 3), 2); |
show += String.fromCharCode(160) + genlang(87); |
break; |
case "mib": |
show += round(bytes / Math.pow(1024, 2), 2); |
show += String.fromCharCode(160) + genlang(88); |
break; |
case "kib": |
show += round(bytes / Math.pow(1024, 1), 2); |
show += String.fromCharCode(160) + genlang(89); |
break; |
case "pb": |
show += round(bytes / Math.pow(1000, 5), 2); |
show += String.fromCharCode(160) + genlang(91); |
break; |
case "tb": |
show += round(bytes / Math.pow(1000, 4), 2); |
show += String.fromCharCode(160) + genlang(85); |
break; |
case "gb": |
show += round(bytes / Math.pow(1000, 3), 2); |
show += String.fromCharCode(160) + genlang(41); |
break; |
case "mb": |
show += round(bytes / Math.pow(1000, 2), 2); |
show += String.fromCharCode(160) + genlang(40); |
break; |
case "kb": |
show += round(bytes / Math.pow(1000, 1), 2); |
show += String.fromCharCode(160) + genlang(39); |
break; |
case "b": |
show += bytes; |
show += String.fromCharCode(160) + genlang(96); |
break; |
case "auto_decimal": |
if (bytes > Math.pow(1000, 5)) { |
show += round(bytes / Math.pow(1000, 5), 2); |
show += String.fromCharCode(160) + genlang(91); |
} else { |
if (bytes > Math.pow(1000, 4)) { |
show += round(bytes / Math.pow(1000, 4), 2); |
show += String.fromCharCode(160) + genlang(85); |
} else { |
if (bytes > Math.pow(1000, 3)) { |
show += round(bytes / Math.pow(1000, 3), 2); |
show += String.fromCharCode(160) + genlang(41); |
} else { |
if (bytes > Math.pow(1000, 2)) { |
show += round(bytes / Math.pow(1000, 2), 2); |
show += String.fromCharCode(160) + genlang(40); |
} else { |
if (bytes > Math.pow(1000, 1)) { |
show += round(bytes / Math.pow(1000, 1), 2); |
show += String.fromCharCode(160) + genlang(39); |
} else { |
show += bytes; |
show += String.fromCharCode(160) + genlang(96); |
} |
} |
} |
} |
} |
break; |
default: |
if (bytes > Math.pow(1024, 5)) { |
show += round(bytes / Math.pow(1024, 5), 2); |
show += String.fromCharCode(160) + genlang(90); |
} else { |
if (bytes > Math.pow(1024, 4)) { |
show += round(bytes / Math.pow(1024, 4), 2); |
show += String.fromCharCode(160) + genlang(86); |
} else { |
if (bytes > Math.pow(1024, 3)) { |
show += round(bytes / Math.pow(1024, 3), 2); |
show += String.fromCharCode(160) + genlang(87); |
} else { |
if (bytes > Math.pow(1024, 2)) { |
show += round(bytes / Math.pow(1024, 2), 2); |
show += String.fromCharCode(160) + genlang(88); |
} else { |
if (bytes > Math.pow(1024, 1)) { |
show += round(bytes / Math.pow(1024, 1), 2); |
show += String.fromCharCode(160) + genlang(89); |
} else { |
show += bytes; |
show += String.fromCharCode(160) + genlang(96); |
} |
} |
} |
} |
} |
} |
if (parenths === true) { |
show = "<i>(" + show + ")</i>"; |
} |
return "<span style='display:none'>" + round(bytes,0) + ".</span>" + show; //span for sorting |
} |
function formatBPS(bps) { |
var show = ""; |
if (bps > Math.pow(1000, 5)) { |
show += round(bps / Math.pow(1000, 5), 2); |
show += String.fromCharCode(160) + 'Pb/s'; |
} else { |
if (bps > Math.pow(1000, 4)) { |
show += round(bps / Math.pow(1000, 4), 2); |
show += String.fromCharCode(160) + 'Tb/s'; |
} else { |
if (bps > Math.pow(1000, 3)) { |
show += round(bps / Math.pow(1000, 3), 2); |
show += String.fromCharCode(160) + 'Gb/s'; |
} else { |
if (bps > Math.pow(1000, 2)) { |
show += round(bps / Math.pow(1000, 2), 2); |
show += String.fromCharCode(160) + 'Mb/s'; |
} else { |
if (bps > Math.pow(1000, 1)) { |
show += round(bps / Math.pow(1000, 1), 2); |
show += String.fromCharCode(160) + 'Kb/s'; |
} else { |
show += bps; |
show += String.fromCharCode(160) + 'b/s'; |
} |
} |
} |
} |
} |
return show; |
} |
Array.prototype.pushIfNotExist = function(val) { |
if (typeof(val) == 'undefined' || val === '') { |
return; |
} |
val = $.trim(val); |
if ($.inArray(val, this) == -1) { |
this.push(val); |
} |
}; |
/** |
* generate a formatted datetime string of the current datetime |
* @return {String} formatted datetime string |
*/ |
function datetime() { |
var date, day = 0, month = 0, year = 0, hour = 0, minute = 0, days = "", months = "", years = "", hours = "", minutes = ""; |
date = new Date(); |
day = date.getDate(); |
month = date.getMonth() + 1; |
year = date.getFullYear(); |
hour = date.getHours(); |
minute = date.getMinutes(); |
// format values smaller that 10 with a leading 0 |
days = (day < 10) ? "0" + day.toString() : day.toString(); |
months = (month < 10) ? "0" + month.toString() : month.toString(); |
years = (year < 1000) ? year.toString() : year.toString(); |
minutes = (minute < 10) ? "0" + minute.toString() : minute.toString(); |
hours = (hour < 10) ? "0" + hour.toString() : hour.toString(); |
return days + "." + months + "." + years + " - " + hours + ":" + minutes; |
} |
/** |
* round a given value to the specified precision, difference to Math.round() is that there |
* will be appended Zeros to the end if the precision is not reached (0.1 gets rounded to 0.100 when precision is set to 3) |
* @param {Number} x value to round |
* @param {Number} n precision |
* @return {String} |
*/ |
function round(x, n) { |
var e = 0, k = ""; |
if (n < 0 || n > 14) { |
return 0; |
} |
if (n === 0) { |
return Math.round(x); |
} else { |
e = Math.pow(10, n); |
k = (Math.round(x * e) / e).toString(); |
if (k.indexOf('.') === -1) { |
k += '.'; |
} |
k += e.toString().substring(1); |
return k.substring(0, k.indexOf('.') + n + 1); |
} |
} |