-
Notifications
You must be signed in to change notification settings - Fork 153
Expand file tree
/
Copy pathdatatableBinding.js
More file actions
206 lines (174 loc) · 6.63 KB
/
Copy pathdatatableBinding.js
File metadata and controls
206 lines (174 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
define([
'jquery',
'knockout',
'datatables.net',
'appConfig',
'xss',
'moment',
'services/MomentAPI',
'utils/DatatablePaginationUtils',
'datatables.net-buttons',
'colvis',
'datatables.net-buttons-html5',
], function (
$,
ko,
dataTables,
config,
filterXSS,
moment,
momentApi,
paginationUtils
) {
function renderSelected(s, p, d) {
return '<span class="fa fa-check-circle"></span>';
}
function _getSelectedData(element)
{
var selectedRows = $(element).DataTable().rows('tr:has(td.select:has(span.selected))', {
'search': 'applied'
}).data();
var selectedData = [];
$.each(selectedRows, function(index, value) {
selectedData.push(value);
});
return selectedData;
}
function isUrlAbsolute(url) {
return (url.indexOf('://') > 0 || url.indexOf('//') === 0);
}
function filterAbsoluteUrls(html) {
return html.replace(/href="([^"]*)"|href='([^']*)'/g, function(match, p1, p2)
{
const link = p1 || p2;
if (isUrlAbsolute(link)) {
return match.replace(link, '#' + link);
}
return match;
}
);
}
function sortAbs(x, y) {
const abxX = Math.abs(x);
const absY = Math.abs(y);
return abxX < absY ? -1 : abxX>absY ? 1 : 0;
}
function redrawTable(table, mode) {
// drawing may access observables, which updating we do not want to trigger a redraw to the table
// see: https://knockoutjs.com/documentation/computed-dependency-tracking.html#IgnoringDependencies
const func = mode ? table.draw.bind(null, mode) : table.draw;
ko.ignoreDependencies(func);
}
ko.bindingHandlers.dataTable = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
jQuery.fn.dataTableExt.oSort["numberAbs-desc"] = function(x, y) {
return -1 * sortAbs(x, y);
};
jQuery.fn.dataTableExt.oSort["numberAbs-asc"] = function(x, y) {
return sortAbs(x, y);
}
var binding = ko.utils.unwrapObservable(valueAccessor());
// If the binding is an object with an options field,
// initialise the dataTable with those options.
if (binding.options) {
// Set default placeholder for datatables search input
const defaultPlaceholder = { searchPlaceholder: 'Search...' };
const language = binding.options.language
? { ...defaultPlaceholder, ...binding.options.language }
: defaultPlaceholder;
binding.options.language = language;
// allow row level binding context
const createdRow = binding.options.createdRow;
binding.options.createdRow = (row, data, index) => {
if (createdRow) {
createdRow(row, data, index);
}
ko.cleanNode(row);
ko.applyBindings(bindingContext.createChildContext(data), row);
};
// test for 'select' column (must be first column in column definition
const columns = binding.options.columns;
if (columns && columns[0] == 'select') {
columns[0] = { width:'20px', orderable: false, class: 'select', render: renderSelected };
$(element).on("click","td > span.fa.fa-check-circle", function () {
$(this).toggleClass('selected');
});
}
const xssOptions = config.xssOptions;
binding.options.columns = columns.map((column) => {
const originalRender = column.render;
const originalDataAccessor = column.data;
const hasOriginalRender = typeof originalRender === 'function';
const hasDataAccessor = typeof originalDataAccessor === 'function';
// do not apply xss filtering if the table is marked safe, and the column is not marked not safe
if (binding.options.xssSafe && column.xssSafe != false) return column; // disable XSS filtering if column is marked 'safe'
return Object.assign({}, column, {
data: hasDataAccessor
? d => filterAbsoluteUrls(filterXSS(originalDataAccessor(d), xssOptions))
: filterAbsoluteUrls(filterXSS(originalDataAccessor, xssOptions)),
render: hasOriginalRender
? (s, p, d) => filterAbsoluteUrls(filterXSS(originalRender(s, p, d), xssOptions))
// https://datatables.net/reference/option/columns.render
// "render" property having "string" or "object" data type is not obvious for filtering, so do not pass such things to UI for now
: $.fn.dataTable.render.text()
});
});
// For case of complex header which uses data-bindings (https://datatables.net/examples/advanced_init/complex_header.html)
if ($(element).find('thead')[0]) {
ko.applyBindings(bindingContext, $(element).find('thead')[0]);
}
const datatable = $(element).DataTable(binding.options);
paginationUtils.applyPaginationListeners(element, datatable, binding);
if (binding.api != null)
{
// expose datatable API to context's api binding.
binding.api({
getSelectedData: function() { return _getSelectedData(element);}
});
}
// Workaround for bug when datatable header column width is not adjusted to column values when using scrollY datatable option
// https://stackoverflow.com/questions/32679625/jquery-datatables-header-is-not-adjusting-to-column-values-initially-but-adjust
if (!!binding.options.scrollY) {
setTimeout(() => $(element).DataTable().columns.adjust().draw('page'), 0);
}
// setup dispose callback:
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
// This will be called when the element is removed by Knockout or
// if some other part of your code calls ko.removeNode(element)
$(element).DataTable().destroy(true);
$(element).empty();
});
}
return {
controlsDescendantBindings: true
};
},
update: function (element, valueAccessor) {
var binding = ko.utils.unwrapObservable(valueAccessor());
var table = $(element).DataTable();
// assign data to either the binding's data or the actual binding.
var data = ko.utils.unwrapObservable(binding.data || binding);
// clear events that .on() attached to previously. Prior to this update, the binding may have specified an 'onRowClick' option, but no longer does.
$(element).off("click","tr");
if (binding.onRowClick != null) // attach a onRowclick handler if the options binding specifies it.
{
$(element).on("click","tr", function(evt)
{
if (this._DT_RowIndex != null)
{
binding.onRowClick(data[this._DT_RowIndex], evt, this, this._DT_RowIndex);
}
});
}
// Clear table
table.clear();
// Rebuild table from data source specified in binding
if (data.length > 0)
table.rows.add(data);
paginationUtils.applyDtSearch(table);
paginationUtils.applyDtSorting(table);
redrawTable(table);
paginationUtils.applyDtPage(table, redrawTable);
}
};
});