// Data Tables - Config (function($) { 'use strict'; // we overwrite initialize of all datatables here // because we want to use select2, give search input a bootstrap look // keep in mind if you overwrite this fnInitComplete somewhere, // you should run the code inside this function to keep functionality. // // there's no better way to do this at this time :( if ( $.isFunction( $.fn[ 'dataTable' ] ) ) { $.extend(true, $.fn.dataTable.defaults, { sDom: "<'row datatables-header form-inline'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>r><'table-responsive't><'row datatables-footer'<'col-sm-12 col-md-6'i><'col-sm-12 col-md-6'p>>", oLanguage: { sLengthMenu: '_MENU_ records per page', sProcessing: '<i class="fa fa-spinner fa-spin"></i> Loading' }, fnInitComplete: function( settings, json ) { // select 2 if ( $.isFunction( $.fn[ 'select2' ] ) ) { $('.dataTables_length select', settings.nTableWrapper).select2({ minimumResultsForSearch: -1 }); } var options = $( 'table', settings.nTableWrapper ).data( 'plugin-options' ) || {}; // search var $search = $('.dataTables_filter input', settings.nTableWrapper); $search .attr({ placeholder: typeof options.searchPlaceholder !== 'undefined' ? options.searchPlaceholder : 'Search' }) .addClass('form-control'); if ( $.isFunction( $.fn.placeholder ) ) { $search.placeholder(); } } }); } }).apply( this, [ jQuery ]); /*Datatable - editable*/ (function( $ ) { 'use strict'; var EditableTable = { options: { addButton: '#addToTable', table: '#datatable-editable', dialog: { wrapper: '#dialog', cancelButton: '#dialogCancel', confirmButton: '#dialogConfirm', } }, initialize: function() { this .setVars() .build() .events(); }, setVars: function() { this.$table = $( this.options.table ); this.$addButton = $( this.options.addButton ); // dialog this.dialog = {}; this.dialog.$wrapper = $( this.options.dialog.wrapper ); this.dialog.$cancel = $( this.options.dialog.cancelButton ); this.dialog.$confirm = $( this.options.dialog.confirmButton ); return this; }, build: function() { this.datatable = this.$table.DataTable({ "serverSide" : true, aoColumns: [ null, null, null, null, null, null, null, null, null, { "bSortable": false } ], "columnDefs": [ { "targets": -1, "data": null, "defaultContent": "<button>Click!</button>" } ] }); window.dt = this.datatable; return this; }, events: function() { var _self = this; this.$table .on('click', 'a.save-row', function( e ) { //阻止它的默认行为的发生 e.preventDefault(); //closest:从元素本身开始,在DOM 树上逐级向上级元素匹配,并返回最先匹配的祖先元素。 _self.rowSave( $(this).closest( 'tr' ) ); }) .on('click', 'a.cancel-row', function( e ) { e.preventDefault(); _self.rowCancel( $(this).closest( 'tr' ) ); }) .on('click', 'a.edit-row', function( e ) { e.preventDefault(); _self.rowEdit( $(this).closest( 'tr' ) ); }) .on( 'click', 'a.remove-row', function( e ) { e.preventDefault(); //从元素本身开始,在DOM 树上逐级向上级元素匹配,并返回最先匹配的祖先元素。 var $row = $(this).closest( 'tr' ); //magnific插件,用于弹出窗口 $.magnificPopup.open({ items: { src: '#dialog', type: 'inline' }, preloader: false, modal: true, callbacks: { change: function() { _self.dialog.$confirm.on( 'click', function( e ) { e.preventDefault(); _self.rowRemove( $row ); $.magnificPopup.close(); }); }, close: function() { _self.dialog.$confirm.off( 'click' ); } } }); }); this.$addButton.on( 'click', function(e) { e.preventDefault(); _self.rowAdd(); }); this.dialog.$cancel.on( 'click', function( e ) { e.preventDefault(); $.magnificPopup.close(); }); return this; }, // ========================================================================================== // ROW FUNCTIONS // ========================================================================================== rowAdd: function() { this.$addButton.attr({ 'disabled': 'disabled' }); var actions, data, $row; actions = [ '<a href="#" class="hidden on-editing save-row"><i class="fa fa-save"></i></a>', '<a href="#" class="hidden on-editing cancel-row"><i class="fa fa-times"></i></a>', '<a href="#" class="on-default edit-row"><i class="fa fa-pencil"></i></a>', '<a href="#" class="on-default remove-row"><i class="fa fa-trash-o"></i></a>' ].join(' '); //var d = new Date(); var str = d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate(); //this.datatable是this.$table.DataTable({...})初始化后得到的DataTable对象 //.row.add是DataTable的方法,可以查看DataTable的官方文档 data = this.datatable.row.add([ '', '', '', '', '', '', '', '', '', actions ]); //猜测这段代码的意思是获取刚刚添加的这行的row对象 $row = this.datatable.row( data[0] ).nodes().to$(); $row .addClass( 'adding' ) .find( 'td:last' ) .addClass( 'actions' ); this.rowEdit( $row ); this.datatable.order([0,'asc']).draw(); // always show fields }, rowCancel: function( $row ) { var _self = this, $actions, i, data; //如果这一行是刚添加的,点击取消,则删除改行 if ( $row.hasClass('adding') ) { this.rowRemove( $row ); } else { data = this.datatable.row( $row.get(0) ).data(); this.datatable.row( $row.get(0) ).data( data ); $actions = $row.find('td.actions'); if ( $actions.get(0) ) { this.rowSetActionsDefault( $row ); } this.datatable.draw(); } }, rowEdit: function( $row ) { var _self = this, data; data = this.datatable.row( $row.get(0) ).data(); $row.children( 'td' ).each(function( i ) { var $this = $( this ); if ( $this.hasClass('actions') ) { _self.rowSetActionsEditing( $row ); } else { $this.html( '<input type="text" class="form-control input-block" value="' + data[i] + '"/>' ); } }); }, //参数$row 为祖先tr,我认为应该是一个jquery对象 rowSave: function( $row ) { var _self = this, $actions, values = []; //如果该行是新添加的,则还原添加按钮(使其变为可用),并且把该新添加行的样式"adding"去掉 if ( $row.hasClass( 'adding' ) ) { this.$addButton.removeAttr( 'disabled' ); $row.removeClass( 'adding' ); } //文本框中的内容列表 values = $row.find('td').map(function() { //此处的this指的是<td>,map函数中有说明(map的回调函数中,this指向每次迭代中的当前DOM元素。) var $this = $(this); //如果是操作那一列,则设置为 修改 和 删除 图标 if ( $this.hasClass('actions') ) { _self.rowSetActionsDefault( $row ); return _self.datatable.cell( this ).data(); } else {//如果不是操作那一列,则获取input文本框中的内容,并返回 return $.trim( $this.find('input').val() ); } }); //this.datatable是this.$table.DataTable({...})初始化后得到的DataTable对象 //row()函数的返回值是一个DataTables对象,他的参数有很多种,其中一种就是row节点的jquery对象(jQuery object of row nodes) //$row.get(0) 是jquery的方法 //.data It can be used to get existing data, or set new data to be used for the row. //but does not update the table's internal caches of data until the draw() method is called. //.data方法 是设置值,还是取值,区别于是否有参数,如果有参数,则是设置值,如果没有参数,则是取值 this.datatable.row( $row.get(0) ).data( values ); $actions = $row.find('td.actions'); if ( $actions.get(0) ) { this.rowSetActionsDefault( $row ); } this.datatable.draw(); }, rowRemove: function( $row ) { if ( $row.hasClass('adding') ) { this.$addButton.removeAttr( 'disabled' ); } this.datatable.row( $row.get(0) ).remove().draw(); }, rowSetActionsEditing: function( $row ) { $row.find( '.on-editing' ).removeClass( 'hidden' ); $row.find( '.on-default' ).addClass( 'hidden' ); }, rowSetActionsDefault: function( $row ) { $row.find( '.on-editing' ).addClass( 'hidden' ); $row.find( '.on-default' ).removeClass( 'hidden' ); } }; $(function() { EditableTable.initialize(); }); }).apply( this, [ jQuery ]);