PHP Classes

File: assets/plugins/datatables/extensions/AutoFill/js/dataTables.autoFill.js

Recommend this page to a friend!
  Classes of Kishor Mali   PHP User Feedback System   assets/plugins/datatables/extensions/AutoFill/js/dataTables.autoFill.js   Download  
File: assets/plugins/datatables/extensions/AutoFill/js/dataTables.autoFill.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: PHP User Feedback System
Application to record feedback from customers
Author: By
Last change:
Date: 3 years ago
Size: 22,645 bytes
 

Contents

Class file image Download
/*! AutoFill 1.2.1 * ©2008-2014 SpryMedia Ltd - datatables.net/license */ /** * @summary AutoFill * @description Add Excel like click and drag auto-fill options to DataTables * @version 1.2.1 * @file dataTables.autoFill.js * @author SpryMedia Ltd (www.sprymedia.co.uk) * @contact www.sprymedia.co.uk/contact * @copyright Copyright 2010-2014 SpryMedia Ltd. * * This source file is free software, available under the following license: * MIT license - http://datatables.net/license/mit * * 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 */ (function( window, document, undefined ) { var factory = function( $, DataTable ) { "use strict"; /** * AutoFill provides Excel like auto-fill features for a DataTable * * @class AutoFill * @constructor * @param {object} oTD DataTables settings object * @param {object} oConfig Configuration object for AutoFill */ var AutoFill = function( oDT, oConfig ) { /* Sanity check that we are a new instance */ if ( ! (this instanceof AutoFill) ) { throw( "Warning: AutoFill must be initialised with the keyword 'new'" ); } if ( ! $.fn.dataTableExt.fnVersionCheck('1.7.0') ) { throw( "Warning: AutoFill requires DataTables 1.7 or greater"); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Public class variables * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ this.c = {}; /** * @namespace Settings object which contains customisable information for AutoFill instance */ this.s = { /** * @namespace Cached information about the little dragging icon (the filler) */ "filler": { "height": 0, "width": 0 }, /** * @namespace Cached information about the border display */ "border": { "width": 2 }, /** * @namespace Store for live information for the current drag */ "drag": { "startX": -1, "startY": -1, "startTd": null, "endTd": null, "dragging": false }, /** * @namespace Data cache for information that we need for scrolling the screen when we near * the edges */ "screen": { "interval": null, "y": 0, "height": 0, "scrollTop": 0 }, /** * @namespace Data cache for the position of the DataTables scrolling element (when scrolling * is enabled) */ "scroller": { "top": 0, "bottom": 0 }, /** * @namespace Information stored for each column. An array of objects */ "columns": [] }; /** * @namespace Common and useful DOM elements for the class instance */ this.dom = { "table": null, "filler": null, "borderTop": null, "borderRight": null, "borderBottom": null, "borderLeft": null, "currentTarget": null }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Public class methods * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * Retreieve the settings object from an instance * @method fnSettings * @returns {object} AutoFill settings object */ this.fnSettings = function () { return this.s; }; /* Constructor logic */ this._fnInit( oDT, oConfig ); return this; }; AutoFill.prototype = { /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Private methods (they are of course public in JS, but recommended as private) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * Initialisation * @method _fnInit * @param {object} dt DataTables settings object * @param {object} config Configuration object for AutoFill * @returns void */ "_fnInit": function ( dt, config ) { var that = this, i, iLen; // Use DataTables API to get the settings allowing selectors, instances // etc to be used, or for backwards compatibility get from the old // fnSettings method this.s.dt = DataTable.Api ? new DataTable.Api( dt ).settings()[0] : dt.fnSettings(); this.s.init = config || {}; this.dom.table = this.s.dt.nTable; $.extend( true, this.c, AutoFill.defaults, config ); /* Add and configure the columns */ this._initColumns(); /* Auto Fill click and drag icon */ var filler = $('<div/>', { 'class': 'AutoFill_filler' } ) .appendTo( 'body' ); this.dom.filler = filler[0]; // Get the height / width of the click element this.s.filler.height = filler.height(); this.s.filler.width = filler.width(); filler[0].style.display = "none"; /* Border display - one div for each side. We can't just use a single * one with a border, as we want the events to effectively pass through * the transparent bit of the box */ var border; var appender = document.body; if ( that.s.dt.oScroll.sY !== "" ) { that.s.dt.nTable.parentNode.style.position = "relative"; appender = that.s.dt.nTable.parentNode; } border = $('<div/>', { "class": "AutoFill_border" } ); this.dom.borderTop = border.clone().appendTo( appender )[0]; this.dom.borderRight = border.clone().appendTo( appender )[0]; this.dom.borderBottom = border.clone().appendTo( appender )[0]; this.dom.borderLeft = border.clone().appendTo( appender )[0]; /* Events */ filler.on( 'mousedown.DTAF', function (e) { this.onselectstart = function() { return false; }; that._fnFillerDragStart.call( that, e ); return false; } ); $('tbody', this.dom.table).on( 'mouseover.DTAF mouseout.DTAF', '>tr>td, >tr>th', function (e) { that._fnFillerDisplay.call( that, e ); } ); $(this.dom.table).on( 'destroy.dt.DTAF', function () { filler.off( 'mousedown.DTAF' ).remove(); $('tbody', this.dom.table).off( 'mouseover.DTAF mouseout.DTAF' ); } ); }, _initColumns: function ( ) { var that = this; var i, ien; var dt = this.s.dt; var config = this.s.init; for ( i=0, ien=dt.aoColumns.length ; i<ien ; i++ ) { this.s.columns[i] = $.extend( true, {}, AutoFill.defaults.column ); } dt.oApi._fnApplyColumnDefs( dt, config.aoColumnDefs || config.columnDefs, config.aoColumns || config.columns, function (colIdx, def) { that._fnColumnOptions( colIdx, def ); } ); // For columns which don't have read, write, step functions defined, // use the default ones for ( i=0, ien=dt.aoColumns.length ; i<ien ; i++ ) { var column = this.s.columns[i]; if ( ! column.read ) { column.read = this._fnReadCell; } if ( ! column.write ) { column.read = this._fnWriteCell; } if ( ! column.step ) { column.read = this._fnStep; } } }, "_fnColumnOptions": function ( i, opts ) { var column = this.s.columns[ i ]; var set = function ( outProp, inProp ) { if ( opts[ inProp[0] ] !== undefined ) { column[ outProp ] = opts[ inProp[0] ]; } if ( opts[ inProp[1] ] !== undefined ) { column[ outProp ] = opts[ inProp[1] ]; } }; // Compatibility with the old Hungarian style of notation set( 'enable', ['bEnable', 'enable'] ); set( 'read', ['fnRead', 'read'] ); set( 'write', ['fnWrite', 'write'] ); set( 'step', ['fnStep', 'step'] ); set( 'increment', ['bIncrement', 'increment'] ); }, /** * Find out the coordinates of a given TD cell in a table * @method _fnTargetCoords * @param {Node} nTd * @returns {Object} x and y properties, for the position of the cell in the tables DOM */ "_fnTargetCoords": function ( nTd ) { var nTr = $(nTd).parents('tr')[0]; var position = this.s.dt.oInstance.fnGetPosition( nTd ); return { "x": $('td', nTr).index(nTd), "y": $('tr', nTr.parentNode).index(nTr), "row": position[0], "column": position[2] }; }, /** * Display the border around one or more cells (from start to end) * @method _fnUpdateBorder * @param {Node} nStart Starting cell * @param {Node} nEnd Ending cell * @returns void */ "_fnUpdateBorder": function ( nStart, nEnd ) { var border = this.s.border.width, offsetStart = $(nStart).offset(), offsetEnd = $(nEnd).offset(), x1 = offsetStart.left - border, x2 = offsetEnd.left + $(nEnd).outerWidth(), y1 = offsetStart.top - border, y2 = offsetEnd.top + $(nEnd).outerHeight(), width = offsetEnd.left + $(nEnd).outerWidth() - offsetStart.left + (2*border), height = offsetEnd.top + $(nEnd).outerHeight() - offsetStart.top + (2*border), oStyle; // Recalculate start and end (when dragging "backwards") if( offsetStart.left > offsetEnd.left) { x1 = offsetEnd.left - border; x2 = offsetStart.left + $(nStart).outerWidth(); width = offsetStart.left + $(nStart).outerWidth() - offsetEnd.left + (2*border); } if ( this.s.dt.oScroll.sY !== "" ) { /* The border elements are inside the DT scroller - so position relative to that */ var offsetScroll = $(this.s.dt.nTable.parentNode).offset(), scrollTop = $(this.s.dt.nTable.parentNode).scrollTop(), scrollLeft = $(this.s.dt.nTable.parentNode).scrollLeft(); x1 -= offsetScroll.left - scrollLeft; x2 -= offsetScroll.left - scrollLeft; y1 -= offsetScroll.top - scrollTop; y2 -= offsetScroll.top - scrollTop; } /* Top */ oStyle = this.dom.borderTop.style; oStyle.top = y1+"px"; oStyle.left = x1+"px"; oStyle.height = this.s.border.width+"px"; oStyle.width = width+"px"; /* Bottom */ oStyle = this.dom.borderBottom.style; oStyle.top = y2+"px"; oStyle.left = x1+"px"; oStyle.height = this.s.border.width+"px"; oStyle.width = width+"px"; /* Left */ oStyle = this.dom.borderLeft.style; oStyle.top = y1+"px"; oStyle.left = x1+"px"; oStyle.height = height+"px"; oStyle.width = this.s.border.width+"px"; /* Right */ oStyle = this.dom.borderRight.style; oStyle.top = y1+"px"; oStyle.left = x2+"px"; oStyle.height = height+"px"; oStyle.width = this.s.border.width+"px"; }, /** * Mouse down event handler for starting a drag * @method _fnFillerDragStart * @param {Object} e Event object * @returns void */ "_fnFillerDragStart": function (e) { var that = this; var startingTd = this.dom.currentTarget; this.s.drag.dragging = true; that.dom.borderTop.style.display = "block"; that.dom.borderRight.style.display = "block"; that.dom.borderBottom.style.display = "block"; that.dom.borderLeft.style.display = "block"; var coords = this._fnTargetCoords( startingTd ); this.s.drag.startX = coords.x; this.s.drag.startY = coords.y; this.s.drag.startTd = startingTd; this.s.drag.endTd = startingTd; this._fnUpdateBorder( startingTd, startingTd ); $(document).bind('mousemove.AutoFill', function (e) { that._fnFillerDragMove.call( that, e ); } ); $(document).bind('mouseup.AutoFill', function (e) { that._fnFillerFinish.call( that, e ); } ); /* Scrolling information cache */ this.s.screen.y = e.pageY; this.s.screen.height = $(window).height(); this.s.screen.scrollTop = $(document).scrollTop(); if ( this.s.dt.oScroll.sY !== "" ) { this.s.scroller.top = $(this.s.dt.nTable.parentNode).offset().top; this.s.scroller.bottom = this.s.scroller.top + $(this.s.dt.nTable.parentNode).height(); } /* Scrolling handler - we set an interval (which is cancelled on mouse up) which will fire * regularly and see if we need to do any scrolling */ this.s.screen.interval = setInterval( function () { var iScrollTop = $(document).scrollTop(); var iScrollDelta = iScrollTop - that.s.screen.scrollTop; that.s.screen.y += iScrollDelta; if ( that.s.screen.height - that.s.screen.y + iScrollTop < 50 ) { $('html, body').animate( { "scrollTop": iScrollTop + 50 }, 240, 'linear' ); } else if ( that.s.screen.y - iScrollTop < 50 ) { $('html, body').animate( { "scrollTop": iScrollTop - 50 }, 240, 'linear' ); } if ( that.s.dt.oScroll.sY !== "" ) { if ( that.s.screen.y > that.s.scroller.bottom - 50 ) { $(that.s.dt.nTable.parentNode).animate( { "scrollTop": $(that.s.dt.nTable.parentNode).scrollTop() + 50 }, 240, 'linear' ); } else if ( that.s.screen.y < that.s.scroller.top + 50 ) { $(that.s.dt.nTable.parentNode).animate( { "scrollTop": $(that.s.dt.nTable.parentNode).scrollTop() - 50 }, 240, 'linear' ); } } }, 250 ); }, /** * Mouse move event handler for during a move. See if we want to update the display based on the * new cursor position * @method _fnFillerDragMove * @param {Object} e Event object * @returns void */ "_fnFillerDragMove": function (e) { if ( e.target && e.target.nodeName.toUpperCase() == "TD" && e.target != this.s.drag.endTd ) { var coords = this._fnTargetCoords( e.target ); if ( this.c.mode == "y" && coords.x != this.s.drag.startX ) { e.target = $('tbody>tr:eq('+coords.y+')>td:eq('+this.s.drag.startX+')', this.dom.table)[0]; } if ( this.c.mode == "x" && coords.y != this.s.drag.startY ) { e.target = $('tbody>tr:eq('+this.s.drag.startY+')>td:eq('+coords.x+')', this.dom.table)[0]; } if ( this.c.mode == "either") { if(coords.x != this.s.drag.startX ) { e.target = $('tbody>tr:eq('+this.s.drag.startY+')>td:eq('+coords.x+')', this.dom.table)[0]; } else if ( coords.y != this.s.drag.startY ) { e.target = $('tbody>tr:eq('+coords.y+')>td:eq('+this.s.drag.startX+')', this.dom.table)[0]; } } // update coords if ( this.c.mode !== "both" ) { coords = this._fnTargetCoords( e.target ); } var drag = this.s.drag; drag.endTd = e.target; if ( coords.y >= this.s.drag.startY ) { this._fnUpdateBorder( drag.startTd, drag.endTd ); } else { this._fnUpdateBorder( drag.endTd, drag.startTd ); } this._fnFillerPosition( e.target ); } /* Update the screen information so we can perform scrolling */ this.s.screen.y = e.pageY; this.s.screen.scrollTop = $(document).scrollTop(); if ( this.s.dt.oScroll.sY !== "" ) { this.s.scroller.scrollTop = $(this.s.dt.nTable.parentNode).scrollTop(); this.s.scroller.top = $(this.s.dt.nTable.parentNode).offset().top; this.s.scroller.bottom = this.s.scroller.top + $(this.s.dt.nTable.parentNode).height(); } }, /** * Mouse release handler - end the drag and take action to update the cells with the needed values * @method _fnFillerFinish * @param {Object} e Event object * @returns void */ "_fnFillerFinish": function (e) { var that = this, i, iLen, j; $(document).unbind('mousemove.AutoFill mouseup.AutoFill'); this.dom.borderTop.style.display = "none"; this.dom.borderRight.style.display = "none"; this.dom.borderBottom.style.display = "none"; this.dom.borderLeft.style.display = "none"; this.s.drag.dragging = false; clearInterval( this.s.screen.interval ); var cells = []; var table = this.dom.table; var coordsStart = this._fnTargetCoords( this.s.drag.startTd ); var coordsEnd = this._fnTargetCoords( this.s.drag.endTd ); var columnIndex = function ( visIdx ) { return that.s.dt.oApi._fnVisibleToColumnIndex( that.s.dt, visIdx ); }; // xxx - urgh - there must be a way of reducing this... if ( coordsStart.y <= coordsEnd.y ) { for ( i=coordsStart.y ; i<=coordsEnd.y ; i++ ) { if ( coordsStart.x <= coordsEnd.x ) { for ( j=coordsStart.x ; j<=coordsEnd.x ; j++ ) { cells.push( { node: $('tbody>tr:eq('+i+')>td:eq('+j+')', table)[0], x: j - coordsStart.x, y: i - coordsStart.y, colIdx: columnIndex( j ) } ); } } else { for ( j=coordsStart.x ; j>=coordsEnd.x ; j-- ) { cells.push( { node: $('tbody>tr:eq('+i+')>td:eq('+j+')', table)[0], x: j - coordsStart.x, y: i - coordsStart.y, colIdx: columnIndex( j ) } ); } } } } else { for ( i=coordsStart.y ; i>=coordsEnd.y ; i-- ) { if ( coordsStart.x <= coordsEnd.x ) { for ( j=coordsStart.x ; j<=coordsEnd.x ; j++ ) { cells.push( { node: $('tbody>tr:eq('+i+')>td:eq('+j+')', table)[0], x: j - coordsStart.x, y: i - coordsStart.y, colIdx: columnIndex( j ) } ); } } else { for ( j=coordsStart.x ; j>=coordsEnd.x ; j-- ) { cells.push( { node: $('tbody>tr:eq('+i+')>td:eq('+j+')', table)[0], x: coordsStart.x - j, y: coordsStart.y - i, colIdx: columnIndex( j ) } ); } } } } // An auto-fill requires 2 or more cells if ( cells.length <= 1 ) { return; } var edited = []; var previous; for ( i=0, iLen=cells.length ; i<iLen ; i++ ) { var cell = cells[i]; var column = this.s.columns[ cell.colIdx ]; var read = column.read.call( column, cell.node ); var stepValue = column.step.call( column, cell.node, read, previous, i, cell.x, cell.y ); column.write.call( column, cell.node, stepValue ); previous = stepValue; edited.push( { cell: cell, colIdx: cell.colIdx, newValue: stepValue, oldValue: read } ); } if ( this.c.complete !== null ) { this.c.complete.call( this, edited ); } // In 1.10 we can do a static draw if ( DataTable.Api ) { new DataTable.Api( this.s.dt ).draw( false ); } else { this.s.dt.oInstance.fnDraw(); } }, /** * Display the drag handle on mouse over cell * @method _fnFillerDisplay * @param {Object} e Event object * @returns void */ "_fnFillerDisplay": function (e) { var filler = this.dom.filler; /* Don't display automatically when dragging */ if ( this.s.drag.dragging) { return; } /* Check that we are allowed to AutoFill this column or not */ var nTd = (e.target.nodeName.toLowerCase() == 'td') ? e.target : $(e.target).parents('td')[0]; var iX = this._fnTargetCoords(nTd).column; if ( !this.s.columns[iX].enable ) { filler.style.display = "none"; return; } if (e.type == 'mouseover') { this.dom.currentTarget = nTd; this._fnFillerPosition( nTd ); filler.style.display = "block"; } else if ( !e.relatedTarget || !e.relatedTarget.className.match(/AutoFill/) ) { filler.style.display = "none"; } }, /** * Position the filler icon over a cell * @method _fnFillerPosition * @param {Node} nTd Cell to position filler icon over * @returns void */ "_fnFillerPosition": function ( nTd ) { var offset = $(nTd).offset(); var filler = this.dom.filler; filler.style.top = (offset.top - (this.s.filler.height / 2)-1 + $(nTd).outerHeight())+"px"; filler.style.left = (offset.left - (this.s.filler.width / 2)-1 + $(nTd).outerWidth())+"px"; } }; // Alias for access DataTable.AutoFill = AutoFill; DataTable.AutoFill = AutoFill; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constants * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * AutoFill version * @constant version * @type String * @default See code */ AutoFill.version = "1.2.1"; /** * AutoFill defaults * @namespace */ AutoFill.defaults = { /** * Mode for dragging (restrict to y-axis only, x-axis only, either one or none): * * * `y` - y-axis only (default) * * `x` - x-axis only * * `either` - either one, but not both axis at the same time * * `both` - multiple cells allowed * * @type {string} * @default `y` */ mode: 'y', complete: null, /** * Column definition defaults * @namespace */ column: { /** * If AutoFill should be enabled on this column * * @type {boolean} * @default true */ enable: true, /** * Allow automatic increment / decrement on this column if a number * is found. * * @type {boolean} * @default true */ increment: true, /** * Cell read function * * Default function will simply read the value from the HTML of the * cell. * * @type {function} * @param {node} cell `th` / `td` element to read the value from * @return {string} Data that has been read */ read: function ( cell ) { return $(cell).html(); }, /** * Cell write function * * Default function will simply write to the HTML and tell the DataTable * to update. * * @type {function} * @param {node} cell `th` / `td` element to write the value to * @return {string} Data two write */ write: function ( cell, val ) { var table = $(cell).parents('table'); if ( DataTable.Api ) { // 1.10 table.DataTable().cell( cell ).data( val ); } else { // 1.9 var dt = table.dataTable(); var pos = dt.fnGetPosition( cell ); dt.fnUpdate( val, pos[0], pos[2], false ); } }, /** * Step function. This provides the ability to customise how the values * are incremented. * * @param {node} cell `th` / `td` element that is being operated upon * @param {string} read Cell value from `read` function * @param {string} last Value of the previous cell * @param {integer} i Loop counter * @param {integer} x Cell x-position in the current auto-fill. The * starting cell is coordinate 0 regardless of its physical position * in the DataTable. * @param {integer} y Cell y-position in the current auto-fill. The * starting cell is coordinate 0 regardless of its physical position * in the DataTable. * @return {string} Value to write */ step: function ( cell, read, last, i, x, y ) { // Increment a number if it is found var re = /(\-?\d+)/; var match = this.increment && last ? last.match(re) : null; if ( match ) { return last.replace( re, parseInt(match[1],10) + (x<0 || y<0 ? -1 : 1) ); } return last === undefined ? read : last; } } }; return AutoFill; }; // Define as an AMD module if possible if ( typeof define === 'function' && define.amd ) { define( ['jquery', 'datatables'], factory ); } else if ( typeof exports === 'object' ) { // Node/CommonJS factory( require('jquery'), require('datatables') ); } else if ( jQuery && !jQuery.fn.dataTable.AutoFill ) { // Otherwise simply initialise as normal, stopping multiple evaluation factory( jQuery, jQuery.fn.dataTable ); } }(window, document));