jquery-tablesorter 1.17.4 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@
4
4
  ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██
5
5
  █████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀
6
6
  */
7
- /*! tablesorter (FORK) - updated 07-28-2015 (v2.22.5)*/
7
+ /*! tablesorter (FORK) - updated 08-17-2015 (v2.23.0)*/
8
8
  /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
9
9
  (function(factory) {
10
10
  if (typeof define === 'function' && define.amd) {
@@ -372,7 +372,7 @@
372
372
 
373
373
  })(jQuery);
374
374
 
375
- /*! Widget: filter - updated 7/28/2015 (v2.22.4) *//*
375
+ /*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
376
376
  * Requires tablesorter v2.8+ and jQuery 1.7+
377
377
  * by Rob Garrison
378
378
  */
@@ -1361,7 +1361,8 @@
1361
1361
  } else {
1362
1362
  if ( wo.filter_startsWith ) {
1363
1363
  showRow = false;
1364
- columnIndex = c.columns;
1364
+ // data.rowArray may not contain all columns
1365
+ columnIndex = Math.min( c.columns, data.rowArray.length );
1365
1366
  while ( !showRow && columnIndex > 0 ) {
1366
1367
  columnIndex--;
1367
1368
  showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
@@ -1,4 +1,4 @@
1
- /*! Parser: input & select - updated 7/28/2015 (v2.22.4) *//*
1
+ /*! Parser: input & select - updated 8/17/2015 (v2.23.0) *//*
2
2
  * for jQuery 1.7+ & tablesorter 2.7.11+
3
3
  * Demo: http://mottie.github.com/tablesorter/docs/example-widget-grouping.html
4
4
  */
@@ -66,7 +66,7 @@
66
66
  $row.toggleClass( checkedClass + '-' + cellIndex, isChecked );
67
67
  if ( isChecked ) {
68
68
  $row.addClass( checkedClass );
69
- } else if ( !( $row[0].className || '' ).match( checkedClass + '-' ) ) {
69
+ } else if ( $row.length && !( $row[0].className || '' ).match( checkedClass + '-' ) ) {
70
70
  // don't remove checked class if other columns have a check
71
71
  $row.removeClass( checkedClass );
72
72
  }
@@ -1,4 +1,4 @@
1
- /* Widget: columnSelector (responsive table widget) - updated 3/5/2015 (v2.21.0) *//*
1
+ /* Widget: columnSelector (responsive table widget) - updated 8/17/2015 (v2.23.0) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Justin Hallett & Rob Garrison
4
4
  */
@@ -35,7 +35,7 @@
35
35
  colSel.$breakpoints = $('<style></style>').prop('disabled', true).appendTo('head');
36
36
 
37
37
  colSel.isInitializing = true;
38
- tsColSel.setupSelector(table, c, wo);
38
+ tsColSel.setupSelector(c, wo);
39
39
 
40
40
  if (wo.columnSelector_mediaquery) {
41
41
  tsColSel.setupBreakpoints(c, wo);
@@ -50,43 +50,69 @@
50
50
 
51
51
  c.$table
52
52
  .off('refreshColumnSelector' + namespace)
53
- .on('refreshColumnSelector' + namespace, function(e, opt){
53
+ /* $('table').trigger('refreshColumnSelector', arguments ); showing arguments below
54
+ undefined = refresh current settings (update css hiding columns)
55
+ 'selectors' = update container contents (replace inputs/labels)
56
+ [ [2,3,4] ] = set visible columns; turn off "auto" mode.
57
+ [ 'columns', [2,3,4] ] = set visible columns; turn off "auto" mode.
58
+ [ 'auto', [2,3,4] ] = set visible columns; turn on "auto" mode.
59
+ true = turn on "auto" mode.
60
+ */
61
+ .on('refreshColumnSelector' + namespace, function( e, optName, optState ){
54
62
  // make sure we're using current config settings
55
- var i,
56
- isArry = $.isArray(opt),
57
- c = this.config,
58
- wo = c.widgetOptions;
59
- // see #798
60
- if (opt && c.selector.$container.length) {
61
- if (isArry) {
62
- // make sure array contains numbers
63
- $.each(opt, function(i, v){
64
- opt[i] = parseInt(v, 10);
65
- });
66
- for (i = 0; i < c.columns; i++) {
67
- c.selector.$container
68
- .find('input[data-column=' + i + ']')
69
- .prop('checked', $.inArray( i, opt ) >= 0 );
70
- }
71
- }
72
- // if passing an array, set auto to false to allow manual column selection & update columns
73
- tsColSel.updateAuto( c, wo, colSel.$container.find('input[data-column="auto"]').prop('checked', !isArry) );
74
- } else {
75
- tsColSel.updateBreakpoints(c, wo);
76
- tsColSel.updateCols(c, wo);
77
- }
63
+ tsColSel.refreshColumns( this.config, optName, optState );
78
64
  });
79
65
 
80
66
  },
81
67
 
82
- setupSelector: function(table, c, wo) {
68
+ refreshColumns: function( c, optName, optState ) {
69
+ var i, arry,
70
+ isArry = $.isArray(optState || optName),
71
+ wo = c.widgetOptions;
72
+ // see #798
73
+ if (typeof optName !== 'undefined' && c.selector.$container.length) {
74
+ // pass "selectors" to update the all of the container contents
75
+ if ( optName === 'selectors' ) {
76
+ c.selector.$container.empty();
77
+ tsColSel.setupSelector(c, wo);
78
+ tsColSel.setupBreakpoints(c, wo);
79
+ // if optState is undefined, maintain the current "auto" state
80
+ if ( typeof optState === 'undefined' ) {
81
+ optState = c.selector.auto;
82
+ }
83
+ }
84
+ // pass an array of column zero-based indexes to turn off auto mode & toggle selected columns
85
+ if (isArry) {
86
+ arry = optState || optName;
87
+ // make sure array contains numbers
88
+ $.each(arry, function(i, v){
89
+ arry[i] = parseInt(v, 10);
90
+ });
91
+ for (i = 0; i < c.columns; i++) {
92
+ c.selector.$container
93
+ .find('input[data-column=' + i + ']')
94
+ .prop('checked', $.inArray( i, arry ) >= 0 );
95
+ }
96
+ }
97
+ // if passing an array, set auto to false to allow manual column selection & update columns
98
+ // refreshColumns( c, 'auto', true ) === refreshColumns( c, true );
99
+ tsColSel
100
+ .updateAuto( c, wo, c.selector.$container.find('input[data-column="auto"]')
101
+ .prop('checked', optState === true || optName === true || optName === 'auto' && optState !== false) );
102
+ } else {
103
+ tsColSel.updateBreakpoints(c, wo);
104
+ tsColSel.updateCols(c, wo);
105
+ }
106
+ },
107
+
108
+ setupSelector: function(c, wo) {
83
109
  var name,
84
110
  colSel = c.selector,
85
111
  $container = colSel.$container,
86
112
  useStorage = wo.columnSelector_saveColumns && ts.storage,
87
113
  // get stored column states
88
- saved = useStorage ? ts.storage( table, 'tablesorter-columnSelector' ) : [],
89
- state = useStorage ? ts.storage( table, 'tablesorter-columnSelector-auto') : {};
114
+ saved = useStorage ? ts.storage( c.table, 'tablesorter-columnSelector' ) : [],
115
+ state = useStorage ? ts.storage( c.table, 'tablesorter-columnSelector-auto') : {};
90
116
 
91
117
  // initial states
92
118
  colSel.auto = $.isEmptyObject(state) || $.type(state.auto) !== 'boolean' ? wo.columnSelector_mediaqueryState : state.auto;
@@ -95,7 +121,7 @@
95
121
  colSel.$wrapper = [];
96
122
  colSel.$checkbox = [];
97
123
  // populate the selector container
98
- c.$table.children('thead').find('tr:first th', table).each(function() {
124
+ c.$table.children('thead').find('tr:first th', c.table).each(function() {
99
125
  var $this = $(this),
100
126
  // if no data-priority is assigned, default to 1, but don't remove it from the selector list
101
127
  priority = $this.attr(wo.columnSelector_priority) || 1,
@@ -117,7 +143,6 @@
117
143
 
118
144
  // set default col title
119
145
  name = $this.attr(wo.columnSelector_name) || $this.text();
120
-
121
146
  if ($container.length) {
122
147
  colSel.$wrapper[colId] = $(wo.columnSelector_layout.replace(/\{name\}/g, name)).appendTo($container);
123
148
  colSel.$checkbox[colId] = colSel.$wrapper[colId]
@@ -1,4 +1,4 @@
1
- /*! Widget: editable - updated 5/17/2015 (v2.22.0) *//*
1
+ /*! Widget: editable - updated 8/17/2015 (v2.23.0) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Rob Garrison
4
4
  */
@@ -45,38 +45,43 @@
45
45
  },
46
46
 
47
47
  getColumns : function( c, wo ) {
48
- var indx, tmp,
49
- colIndex = [],
48
+ var list, indx, range, len, tmp,
49
+ editableColumns = wo.editable_columns,
50
50
  cols = [];
51
- if ( !wo.editable_columnsArray && $.type( wo.editable_columns ) === 'string' && wo.editable_columns.indexOf( '-' ) >= 0 ) {
52
- // editable_columns can contain a range string ( i.e. '2-4' )
53
- tmp = wo.editable_columns.split( /\s*-\s*/ );
54
- indx = parseInt( tmp[ 0 ], 10 ) || 0;
55
- tmp = parseInt( tmp[ 1 ], 10 ) || ( c.columns - 1 );
56
- if ( tmp > c.columns ) {
57
- tmp = c.columns - 1;
58
- }
59
- for ( ; indx <= tmp; indx++ ) {
60
- colIndex.push( indx );
61
- cols.push( 'td:nth-child(' + ( indx + 1 ) + ')' );
51
+ if ( typeof editableColumns === 'string' ) {
52
+ // editable_columns can contain a range string, or comma separated values (e.g. '1,2-4,7')
53
+ list = editableColumns.replace( /\s+/, '' ).split( /,/ );
54
+ len = list.length - 1;
55
+ while ( len >= 0 ) {
56
+ if ( list[ len ].indexOf( '-' ) >= 0 ) {
57
+ range = list[ len ].split( '-' );
58
+ indx = parseInt( range[ 0 ], 10 ) || 0;
59
+ range = parseInt( range[ 1 ], 10) || c.columns - 1;
60
+ if ( indx > range ) {
61
+ // in case someone does '5-3'
62
+ tmp = indx; indx = range; range = tmp;
63
+ }
64
+ for ( ; indx <= range; indx++ ) {
65
+ cols.push( 'td:nth-child(' + ( indx + 1 ) + ')' );
66
+ }
67
+ } else {
68
+ cols.push( 'td:nth-child(' + ( ( parseInt( list[ len ], 10 ) || 0 ) + 1 ) + ')' );
69
+ }
70
+ len--;
62
71
  }
63
- } else if ( $.isArray( wo.editable_columns ) ) {
64
- $.each( wo.editable_columnsArray || wo.editable_columns, function( i, col ) {
65
- if ( col < c.columns ) {
66
- colIndex.push( col );
67
- cols.push( 'td:nth-child(' + ( col + 1 ) + ')' );
72
+ } else if ( $.isArray( editableColumns ) ) {
73
+ len = editableColumns.length;
74
+ for ( indx = 0; indx < len; indx++ ) {
75
+ if ( editableColumns[ indx ] < c.columns ) {
76
+ cols.push( 'td:nth-child(' + ( editableColumns[ indx ] + 1 ) + ')' );
68
77
  }
69
- });
70
- }
71
- if ( !wo.editable_columnsArray ) {
72
- wo.editable_columnsArray = colIndex;
73
- wo.editable_columnsArray.sort(function(a, b){ return a - b; });
78
+ }
74
79
  }
75
80
  return cols;
76
81
  },
77
82
 
78
83
  update: function( c, wo ) {
79
- var $t,
84
+ var $t, $cells, cellIndex, cellLen, $editable, editableIndex, editableLen,
80
85
  tmp = $( '<div>' ).wrapInner( wo.editable_wrapContent ).children().length || $.isFunction( wo.editable_wrapContent ),
81
86
  cols = tse.getColumns( c, wo ).join( ',' );
82
87
 
@@ -86,24 +91,28 @@
86
91
 
87
92
  // IE does not allow making TR/TH/TD cells directly editable ( issue #404 )
88
93
  // so add a div or span inside ( it's faster than using wrapInner() )
89
- c.$tbodies.find( cols ).not( '.' + wo.editable_noEdit ).each( function() {
94
+ $cells = c.$tbodies.find( cols ).not( '.' + wo.editable_noEdit );
95
+ cellLen = $cells.length;
96
+ for ( cellIndex = 0; cellIndex < cellLen; cellIndex++ ) {
97
+ /*jshint loopfunc:true */
90
98
  // test for children, if they exist, then make the children editable
91
- $t = $( this );
92
-
99
+ $t = $cells.eq( cellIndex );
93
100
  if ( tmp && $t.children( 'div, span' ).length === 0 ) {
94
101
  $t.wrapInner( wo.editable_wrapContent );
95
102
  }
96
- if ( $t.children( 'div, span' ).length ) {
103
+ $editable = $t.children( 'div, span' ).not( '.' + wo.editable_noEdit );
104
+ editableLen = $editable.length;
105
+ if ( editableLen ) {
97
106
  // make div/span children content editable
98
- $t.children( 'div, span' ).not( '.' + wo.editable_noEdit ).each( function() {
99
- var $this = $( this );
107
+ for ( editableIndex = 0; editableIndex < editableLen; editableIndex++ ) {
108
+ var $this = $editable.eq( editableIndex );
100
109
  if ( wo.editable_trimContent ) {
101
110
  $this.html( function( i, txt ) {
102
111
  return $.trim( txt );
103
112
  });
104
113
  }
105
114
  $this.prop( 'contenteditable', true );
106
- });
115
+ }
107
116
  } else {
108
117
  if ( wo.editable_trimContent ) {
109
118
  $t.html( function( i, txt ) {
@@ -112,7 +121,7 @@
112
121
  }
113
122
  $t.prop( 'contenteditable', true );
114
123
  }
115
- });
124
+ }
116
125
  },
117
126
 
118
127
  bindEvents: function( c, wo ) {
@@ -1,4 +1,4 @@
1
- /*! Widget: filter - updated 7/28/2015 (v2.22.4) *//*
1
+ /*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Rob Garrison
4
4
  */
@@ -987,7 +987,8 @@
987
987
  } else {
988
988
  if ( wo.filter_startsWith ) {
989
989
  showRow = false;
990
- columnIndex = c.columns;
990
+ // data.rowArray may not contain all columns
991
+ columnIndex = Math.min( c.columns, data.rowArray.length );
991
992
  while ( !showRow && columnIndex > 0 ) {
992
993
  columnIndex--;
993
994
  showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
@@ -1,4 +1,4 @@
1
- /*! Widget: Pager - updated 7/28/2015 (v2.22.4) */
1
+ /*! Widget: Pager - updated 8/17/2015 (v2.23.0) */
2
2
  /* Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Rob Garrison
4
4
  */
@@ -62,6 +62,11 @@
62
62
  // modify the url after all processing has been applied
63
63
  pager_customAjaxUrl: function(table, url) { return url; },
64
64
 
65
+ // ajax error callback from $.tablesorter.showError function
66
+ // pager_ajaxError: function( config, xhr, exception ){ return exception; };
67
+ // returning false will abort the error message
68
+ pager_ajaxError: null,
69
+
65
70
  // modify the $.ajax object to allow complete control over your ajax requests
66
71
  pager_ajaxObject: {
67
72
  dataType: 'json'
@@ -144,9 +149,7 @@
144
149
  last: {},
145
150
  // save original pager size
146
151
  setSize: wo.pager_size,
147
- setPage: wo.pager_startPage,
148
- events: 'filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete ' +
149
- 'pageSize pageSet pageAndSize pagerUpdate refreshComplete '
152
+ setPage: wo.pager_startPage
150
153
  }, c.pager);
151
154
 
152
155
  // pager initializes multiple times before table has completed initialization
@@ -236,7 +239,7 @@
236
239
  s = wo.pager_selectors;
237
240
 
238
241
  c.$table
239
- .off( $.trim(p.events.split(' ').join(namespace + ' ')) )
242
+ .off( namespace )
240
243
  .on('filterInit filterStart '.split(' ').join(namespace + ' '), function(e, filters) {
241
244
  p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch');
242
245
  // don't change page if filters are the same (pager updating, etc)
@@ -257,15 +260,15 @@
257
260
  c.$table.trigger('applyWidgets');
258
261
  }
259
262
  })
260
- .on('disable' + namespace, function(e){
263
+ .on('disablePager' + namespace, function(e){
261
264
  e.stopPropagation();
262
265
  tsp.showAllRows(table, c);
263
266
  })
264
- .on('enable' + namespace, function(e){
267
+ .on('enablePager' + namespace, function(e){
265
268
  e.stopPropagation();
266
269
  tsp.enablePager(table, c, true);
267
270
  })
268
- .on('destroy' + namespace, function(e, refreshing){
271
+ .on('destroyPager' + namespace, function(e, refreshing){
269
272
  e.stopPropagation();
270
273
  tsp.destroyPager(table, c, refreshing);
271
274
  })
@@ -655,13 +658,13 @@
655
658
  hl = $table.find('thead th').length;
656
659
 
657
660
  // Clean up any previous error.
658
- ts.showError(table);
661
+ ts.showError( table );
659
662
 
660
663
  if ( exception ) {
661
664
  if (c.debug) {
662
665
  console.error('Pager: >> Ajax Error', xhr, exception);
663
666
  }
664
- ts.showError(table, exception.message + ' (' + xhr.status + ')');
667
+ ts.showError( table, xhr, exception );
665
668
  c.$tbodies.eq(0).children('tr').detach();
666
669
  p.totalRows = 0;
667
670
  } else {
@@ -1073,17 +1076,25 @@
1073
1076
 
1074
1077
  destroyPager: function(table, c, refreshing){
1075
1078
  var p = c.pager,
1079
+ s = c.widgetOptions.pager_selectors,
1080
+ ctrls = [ s.first, s.prev, s.next, s.last, s.gotoPage, s.pageSize ].join( ',' ),
1076
1081
  namespace = c.namespace + 'pager';
1077
1082
  p.initialized = false;
1078
- c.$table.off( $.trim(p.events.split(' ').join(namespace + ' ')) );
1079
- if (refreshing) { return; }
1083
+ c.$table.off( namespace );
1084
+ p.$container
1085
+ // hide pager
1086
+ .hide()
1087
+ // unbind pager controls
1088
+ .find( ctrls )
1089
+ .off( namespace );
1090
+ if ( refreshing ) { return; }
1080
1091
  tsp.showAllRows(table, c);
1081
- p.$container.hide(); // hide pager
1082
1092
  c.appender = null; // remove pager appender function
1083
- delete table.config.rowsCopy;
1084
1093
  if (ts.storage) {
1085
1094
  ts.storage(table, c.widgetOptions.pager_storageKey, '');
1086
1095
  }
1096
+ delete table.config.pager;
1097
+ delete table.config.rowsCopy;
1087
1098
  },
1088
1099
 
1089
1100
  enablePager: function(table, c, triggered){
@@ -1131,32 +1142,73 @@
1131
1142
  };
1132
1143
 
1133
1144
  // see #486
1134
- ts.showError = function( table, message ) {
1135
- var index, $row, c, wo, errorRow,
1145
+ ts.showError = function( table, xhr, exception ) {
1146
+ var $row,
1136
1147
  $table = $( table ),
1137
- len = $table.length;
1138
- for ( index = 0; index < len; index++ ) {
1139
- c = $table[ index ].config;
1140
- if ( c ) {
1141
- wo = c.widgetOptions;
1142
- errorRow = c.pager && c.pager.cssErrorRow || wo.pager_css && wo.pager_css.errorRow || 'tablesorter-errorRow';
1143
- if ( typeof message === 'undefined' ) {
1144
- c.$table.find('thead').find(c.selectorRemove).remove();
1148
+ c = $table[0].config,
1149
+ wo = c && c.widgetOptions,
1150
+ errorRow = c.pager && c.pager.cssErrorRow || wo.pager_css && wo.pager_css.errorRow || 'tablesorter-errorRow',
1151
+ typ = typeof xhr,
1152
+ valid = true,
1153
+ message = '',
1154
+ removeRow = function(){
1155
+ c.$table.find( 'thead' ).find( '.' + errorRow ).remove();
1156
+ };
1157
+
1158
+ if ( !$table.length ) {
1159
+ console.error('tablesorter showError: no table parameter passed');
1160
+ return;
1161
+ }
1162
+
1163
+ if ( typ !== 'string' ) {
1164
+ // ajaxError callback for plugin or widget - see #992
1165
+ if ( typeof c.pager.ajaxError === 'function' ) {
1166
+ valid = c.pager.ajaxError( c, xhr, exception );
1167
+ if ( valid === false ) {
1168
+ return removeRow();
1145
1169
  } else {
1146
- $row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
1147
- .click(function(){
1148
- $(this).remove();
1149
- })
1150
- // add error row to thead instead of tbody, or clicking on the header will result in a parser error
1151
- .appendTo( c.$table.find('thead:first') )
1152
- .addClass( errorRow + ' ' + c.selectorRemove.slice(1) )
1153
- .attr({
1154
- role : 'alert',
1155
- 'aria-live' : 'assertive'
1156
- });
1170
+ message = valid;
1157
1171
  }
1172
+ } else if ( typeof wo.pager_ajaxError === 'function' ) {
1173
+ valid = wo.pager_ajaxError( c, xhr, exception );
1174
+ if ( valid === false ) {
1175
+ return removeRow();
1176
+ } else {
1177
+ message = valid;
1178
+ }
1179
+ } else {
1180
+ message =
1181
+ xhr.status === 0 ? 'Not connected, verify Network' :
1182
+ xhr.status === 404 ? 'Requested page not found [404]' :
1183
+ xhr.status === 500 ? 'Internal Server Error [500]' :
1184
+ exception === 'parsererror' ? 'Requested JSON parse failed' :
1185
+ exception === 'timeout' ? 'Time out error' :
1186
+ exception === 'abort' ? 'Ajax Request aborted' :
1187
+ 'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']';
1158
1188
  }
1189
+ } else if ( typ !== 'undefined' ) {
1190
+ // keep backward compatibility (external usage just passes a message string)
1191
+ message = xhr;
1192
+ }
1193
+
1194
+ if ( message === '' ) {
1195
+ // remove all error rows
1196
+ return removeRow();
1159
1197
  }
1198
+
1199
+ // allow message to include HTML (must include entire row!)
1200
+ $row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
1201
+ .click( function() {
1202
+ $( this ).remove();
1203
+ })
1204
+ // add error row to thead instead of tbody, or clicking on the header will result in a parser error
1205
+ .appendTo( c.$table.find( 'thead:first' ) )
1206
+ .addClass( errorRow + ' ' + c.selectorRemove.slice(1) )
1207
+ .attr({
1208
+ role : 'alert',
1209
+ 'aria-live' : 'assertive'
1210
+ });
1211
+
1160
1212
  };
1161
1213
 
1162
1214
  })(jQuery);