Skip to content

Commit f126696

Browse files
committed
table reflowing and column hiding in mobile sizes
1 parent 189c984 commit f126696

8 files changed

Lines changed: 236 additions & 37 deletions

File tree

app/sprinkles/admin/bundle.config.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
"scripts": [
55
"vendor/moment/moment.js",
66
"local/core/js/handlebars-helpers.js",
7-
"vendor/tablesorter/dist/js/jquery.tablesorter.js",
8-
"vendor/tablesorter/dist/js/jquery.tablesorter.widgets.js",
9-
"vendor/tablesorter/dist/js/widgets/widget-sort2Hash.min.js",
10-
"vendor/tablesorter/dist/js/extras/jquery.tablesorter.pager.min.js",
11-
"local/core/js/query-string.js",
12-
"local/core/js/uf-table.js"
7+
"vendor/tablesorter/dist/js/jquery.tablesorter.js",
8+
"vendor/tablesorter/dist/js/jquery.tablesorter.widgets.js",
9+
"vendor/tablesorter/dist/js/widgets/widget-sort2Hash.min.js",
10+
"vendor/tablesorter/dist/js/widgets/widget-columnSelector.min.js",
11+
"vendor/tablesorter/dist/js/widgets/widget-reflow.min.js",
12+
"vendor/tablesorter/dist/js/extras/jquery.tablesorter.pager.min.js",
13+
"local/core/js/query-string.js",
14+
"local/core/js/uf-table.js"
1315
],
1416
"options": {
1517
"result": {
@@ -152,6 +154,7 @@
152154
"local/font-starcraft/css/font-starcraft.css",
153155
"vendor/tablesorter/dist/css/theme.bootstrap.min.css",
154156
"vendor/tablesorter/dist/css/jquery.tablesorter.pager.min.css",
157+
"local/core/css/tablesorter-reflow.css",
155158
"local/pages/css/tablesorter-custom.css"
156159
],
157160
"options": {

app/sprinkles/admin/templates/components/tables/table-paginated.html.twig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
# Requires tablesorter-custom.css for proper styling of pager elements.
33
#}
44

5+
<div class="table-search form-group has-feedback">
6+
<input type="search" class="form-control" data-column="all">
7+
<i class="fa fa-search form-control-icon" aria-hidden="true"></i>
8+
</div>
59
<div class="table-responsive">
610
{% block table %}
711
{# Define your table skeleton in this block in your child template #}

app/sprinkles/admin/templates/components/tables/users.html.twig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
<table id="{{table.id}}" class="tablesorter table table-bordered table-hover table-striped" data-sortlist="[[0, 0]]">
1212
<thead>
1313
<tr>
14-
<th class="sorter-metatext" data-column-name="name" data-column-template="#user-table-column-info">{{translate('USER')}} <i class="fa fa-sort"></i></th>
14+
<th class="sorter-metatext" data-column-name="name" data-column-template="#user-table-column-info" data-priority="1">{{translate('USER')}} <i class="fa fa-sort"></i></th>
1515
{% if 'last_activity' in table.columns %}
16-
<th class="sorter-metanum" data-column-name="last_activity" data-column-template="#user-table-column-last-activity">{{translate("ACTIVITY.LAST")}} <i class="fa fa-sort"></i></th>
16+
<th class="sorter-metanum" data-column-name="last_activity" data-column-template="#user-table-column-last-activity" data-priority="2">{{translate("ACTIVITY.LAST")}} <i class="fa fa-sort"></i></th>
1717
{% endif %}
18-
<th class="filter-select filter-metaselect" data-column-name="flag_enabled" data-column-template="#user-table-column-actions">{{translate("STATUS")}}/{{translate("ACTIONS")}} <i class="fa fa-sort"></i></th>
18+
<th class="filter-select filter-metaselect" data-column-name="flag_enabled" data-column-template="#user-table-column-actions" data-priority="1">{{translate("STATUS")}}/{{translate("ACTIONS")}} <i class="fa fa-sort"></i></th>
1919
</tr>
2020
</thead>
2121
<tbody>

app/sprinkles/admin/templates/pages/users.html.twig

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,27 @@
1717
<div class="box-header">
1818
<h3 class="box-title pull-left"><i class="fa fa-fw fa-user"></i> {{translate('USER', 2)}}</h3>
1919
<div class="box-tools pull-right">
20-
<button class="btn btn-sm btn-default js-download-table"><i class="fa fa-table"></i> {{ translate("DOWNLOAD.CSV") }}</button>
20+
<div class="btn-group">
21+
<button type="button" class="btn btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
22+
<i class="fa fa-gear"></i> <span class="caret"></span>
23+
</button>
24+
<ul class="dropdown-menu box-tool-menu">
25+
<li>
26+
<a href="#" class="js-download-table">
27+
<i class="fa fa-table fa-fw"></i> {{ translate("DOWNLOAD.CSV") }}
28+
</a>
29+
</li>
30+
<li role="separator" class="divider"></li>
31+
<li>
32+
<div class="menu-table-column-selector-title">
33+
Toggle Columns:
34+
</div>
35+
<div class="menu-table-column-selector-options">
36+
37+
</div>
38+
</li>
39+
</ul>
40+
</div>
2141
</div>
2242
</div>
2343
<div class="box-body">
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* REQUIRED CSS: change your reflow breakpoint here (35em below) */
2+
@media ( max-width: 35em ) {
3+
4+
/* uncomment out the line below if you don't want the sortable headers to show */
5+
table.ui-table-reflow thead { display: none; }
6+
7+
.table-search {
8+
display: inherit;
9+
}
10+
11+
/* css for reflow & reflow2 widgets */
12+
.ui-table-reflow td,
13+
.ui-table-reflow th {
14+
-webkit-box-sizing: border-box;
15+
-moz-box-sizing: border-box;
16+
box-sizing: border-box;
17+
float: right;
18+
/* if not using the stickyHeaders widget (not the css3 version)
19+
* the "!important" flag, and "height: auto" can be removed */
20+
width: 100% !important;
21+
height: auto !important;
22+
}
23+
24+
.tablesorter-bootstrap > thead > tr > th,
25+
.tablesorter-bootstrap > thead > tr > td,
26+
.tablesorter-bootstrap > tfoot > tr > th,
27+
.tablesorter-bootstrap > tfoot > tr > td {
28+
padding: 4px;
29+
margin: 0;
30+
}
31+
32+
/* reflow widget only */
33+
.ui-table-reflow tbody td[data-title]:not(:first-child):before {
34+
color: #469;
35+
font-size: 1.5em;
36+
content: attr(data-title);
37+
width: 100%;
38+
white-space: pre;
39+
display: block;
40+
}
41+
42+
/* reflow2 widget only */
43+
table.ui-table-reflow .ui-table-cell-label {
44+
display: none;
45+
}
46+
47+
table.ui-table-reflow .ui-table-cell-label.ui-table-cell-label-top {
48+
display: block;
49+
padding: .4em 0;
50+
margin: .4em 0;
51+
text-transform: uppercase;
52+
font-size: 1.5em;
53+
font-weight: 400;
54+
}
55+
56+
} /* end media query */
57+
58+
/* reflow2 widget */
59+
.ui-table-reflow .ui-table-cell-label {
60+
display: none;
61+
}

app/sprinkles/core/assets/local/core/css/userfrosting.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,32 @@ form textarea {
3838
float: right !important;
3939
}
4040

41+
/* Styles for table column selectors */
42+
43+
.menu-table-column-selector-title {
44+
padding: 0px 20px;
45+
font-weight: bold;
46+
}
47+
48+
.menu-table-column-selector-options {
49+
padding: 3px 20px;
50+
}
51+
52+
.menu-table-column-selector-options label {
53+
width: 100%;
54+
font-weight: normal;
55+
word-wrap: break-word;
56+
word-break: break-all;
57+
}
58+
59+
.menu-table-column-selector-options label span {
60+
padding-left: 10px;
61+
}
62+
63+
.table-search {
64+
display: none;
65+
}
66+
4167
/* Special wrapper for alerts on public form pages (sign-in, register, etc) */
4268
.form-alerts {
4369
margin-bottom: 10px !important;

app/sprinkles/core/assets/local/core/js/uf-table.js

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,20 +108,24 @@
108108
this.options= $.extend(
109109
true, // deep extend
110110
{
111-
DEBUG : false,
112-
dataUrl : "",
113-
msgTarget : $('#alerts-page'),
114-
addParams : {},
111+
DEBUG : false,
112+
dataUrl : "",
113+
msgTarget : $('#alerts-page'),
114+
addParams : {},
115+
filterAllField: '_all',
115116
tablesorter : {
116117
debug: false,
117118
theme : 'bootstrap',
118119
widthFixed: true,
119120
// Set up pagination of data via an AJAX source
120121
// See http://jsfiddle.net/Mottie/uwZc2/
121122
// Also see https://mottie.github.io/tablesorter/docs/example-pager-ajax.html
122-
widgets: ['saveSort','sort2Hash','filter'],
123+
widgets: ['saveSort','sort2Hash','filter', 'columnSelector', 'reflow2'],
123124
widgetOptions : {
125+
columnSelector_container : this.$T.find('.menu-table-column-selector-options'),
126+
columnSelector_layout : '<label><input type="checkbox"> <span>{name}</span></label>',
124127
filter_cssFilter: 'form-control',
128+
filter_external : this.$T.find('.table-search input'),
125129
filter_saveFilters : true,
126130
filter_serversideFiltering : true,
127131
filter_selectSource: {
@@ -135,9 +139,6 @@
135139
sort2Hash_tableId : null,
136140
// if true, show header cell text instead of a zero-based column index
137141
sort2Hash_headerTextAttr : 'data-column-name',
138-
sort2Hash_encodeHash : base._encodeHash,
139-
sort2Hash_decodeHash : base._decodeHash,
140-
sort2Hash_cleanHash : base._cleanHash,
141142
// direction text shown in the URL e.g. [ 'asc', 'desc' ]
142143
sort2Hash_directionText : [ 'asc', 'desc' ], // default values
143144
// if true, override saveSort widget sort, if used & stored sort is available
@@ -237,7 +238,12 @@
237238
var filters = {};
238239
for (i = 0; i < filterList.length; i++) {
239240
if (filterList[i]) {
240-
var columnName = $(table.config.headerList[i]).data('column-name');
241+
if (table.config.headerList[i]) {
242+
var columnName = $(table.config.headerList[i]).data('column-name');
243+
} else {
244+
var columnName = base.options.filterAllField;
245+
}
246+
241247
filters[columnName] = filterList[i];
242248
}
243249
}
@@ -271,10 +277,22 @@
271277
};
272278

273279
// Callback to display errors
274-
base.options.pager.ajaxError = function ( config, xhr, settings, exception ) {
280+
base.options.pager.ajaxError = function ( config, xhr, settings, exception ) {
275281
return base._ajaxError(base, config, xhr, settings, exception);
276282
};
277283

284+
base.options.tablesorter.widgetOptions.sort2Hash_encodeHash = function (config, tableId, component, value, rawValue) {
285+
return base._encodeHash(base, config, tableId, component, value, rawValue);
286+
};
287+
288+
base.options.tablesorter.widgetOptions.sort2Hash_decodeHash = function (config, tableId, component) {
289+
return base._decodeHash(base, config, tableId, component);
290+
};
291+
292+
base.options.tablesorter.widgetOptions.sort2Hash_cleanHash = function (config, tableId, component, hash ) {
293+
return base._cleanHash(base, config, tableId, component, hash);
294+
};
295+
278296
// Set up tablesorter and pager
279297
base.ts = $el.find('.tablesorter').tablesorter(base.options.tablesorter);
280298
base.ts.tablesorterPager(base.options.pager);
@@ -293,6 +311,11 @@
293311
window.location = base.options.dataUrl + '?' + $.param( tableState );
294312
});
295313

314+
// Allow clicking on the labels in the table menu without closing the menu
315+
$(base.options.tablesorter.widgetOptions.columnSelector_container).find('label').on('click', function(e) {
316+
e.stopPropagation();
317+
});
318+
296319
base.ts.on('pagerComplete', function () {
297320
$el.find('.tablesorter').trigger('update');
298321
$el.trigger('pagerComplete.ufTable');
@@ -395,15 +418,19 @@
395418
/**
396419
* Private method used to encode the current table state variables into a URL hash.
397420
*/
398-
Plugin.prototype._encodeHash = function ( config, tableId, component, value, rawValue ) {
421+
Plugin.prototype._encodeHash = function (base, config, tableId, component, value, rawValue) {
399422
var wo = config.widgetOptions;
400423
if ( component === 'filter' ) {
401424
// rawValue is an array of filter values, numerically indexed
402425
var encodedFilters = "";
403426
var len = rawValue.length;
404427
for ( index = 0; index < len; index++ ) {
405428
if (rawValue[index]) {
406-
var columnName = $(config.$headerIndexed[ index ][0]).attr(wo.sort2Hash_headerTextAttr);
429+
if (config.$headerIndexed[index]) {
430+
var columnName = $(config.$headerIndexed[index][0]).attr(wo.sort2Hash_headerTextAttr);
431+
} else {
432+
var columnName = base.options.filterAllField;
433+
}
407434
encodedFilters += '&filter[' + tableId + '][' + columnName + ']=' + encodeURIComponent(rawValue[index]);
408435
}
409436
}
@@ -426,7 +453,8 @@
426453
/**
427454
* Private method used to decode the current table state variables from the URL hash.
428455
*/
429-
Plugin.prototype._decodeHash = function ( config, tableId, component ) {
456+
Plugin.prototype._decodeHash = function (base, config, tableId, component ) {
457+
base = this;
430458
var wo = config.widgetOptions;
431459
var result;
432460
// Convert hash into JSON object
@@ -441,9 +469,9 @@
441469
// Build a numerically indexed array of filter values
442470
var len = config.$headerIndexed.length;
443471
for ( index = 0; index < len; index++ ) {
444-
var column_name = $(config.$headerIndexed[ index ][0]).attr(wo.sort2Hash_headerTextAttr);
445-
if (filters[column_name]) {
446-
decodedFilters.push(filters[column_name]);
472+
var columnName = $(config.$headerIndexed[index][0]).attr(wo.sort2Hash_headerTextAttr);
473+
if (filters[columnName] && filters[columnName] != base.options.filterAllField) {
474+
decodedFilters.push(filters[columnName]);
447475
} else {
448476
decodedFilters.push('');
449477
}
@@ -462,7 +490,7 @@
462490
/**
463491
* Private method used to clean up URL hash.
464492
*/
465-
Plugin.prototype._cleanHash = function ( config, tableId, component, hash ) {
493+
Plugin.prototype._cleanHash = function (base, config, tableId, component, hash ) {
466494
var wo = config.widgetOptions;
467495
// Convert hash to JSON object
468496
var urlObject = $.String.deparam(hash);

0 commit comments

Comments
 (0)