1 | /** |
||
2 | * Symfony DataTables Bundle |
||
3 | * (c) Omines Internetbureau B.V. - https://omines.nl/ |
||
4 | * |
||
5 | * For the full copyright and license information, please view the LICENSE |
||
6 | * file that was distributed with this source code. |
||
7 | * |
||
8 | * @author Niels Keurentjes <[email protected]> |
||
9 | */ |
||
10 | |||
11 | (function($) { |
||
12 | /** |
||
13 | * Initializes the datatable dynamically. |
||
14 | */ |
||
15 | $.fn.initDataTables = function(config, options) { |
||
16 | |||
17 | //Update default used url, so it reflects the current location (useful on single side apps) |
||
18 | //CHANGED jbtronics: Preserve the get parameters (needed so we can pass additional params to query) |
||
19 | $.fn.initDataTables.defaults.url = window.location.origin + window.location.pathname + window.location.search; |
||
20 | |||
21 | var root = this, |
||
22 | config = $.extend({}, $.fn.initDataTables.defaults, config), |
||
23 | state = '' |
||
24 | ; |
||
25 | |||
26 | // Load page state if needed |
||
27 | switch (config.state) { |
||
28 | case 'fragment': |
||
29 | state = window.location.hash; |
||
30 | break; |
||
31 | case 'query': |
||
32 | state = window.location.search; |
||
33 | break; |
||
34 | } |
||
35 | state = (state.length > 1 ? deparam(state.substr(1)) : {}); |
||
36 | var persistOptions = config.state === 'none' ? {} : { |
||
37 | stateSave: true, |
||
38 | stateLoadCallback: function(s, cb) { |
||
0 ignored issues
–
show
|
|||
39 | // Only need stateSave to expose state() function as loading lazily is not possible otherwise |
||
40 | return null; |
||
41 | } |
||
42 | }; |
||
43 | |||
44 | return new Promise((fulfill, reject) => { |
||
45 | // Perform initial load |
||
46 | $.ajax(typeof config.url === 'function' ? config.url(null) : config.url, { |
||
47 | method: config.method, |
||
48 | data: { |
||
49 | _dt: config.name, |
||
50 | _init: true |
||
51 | } |
||
52 | }).done(function(data) { |
||
53 | var baseState; |
||
54 | |||
55 | // Merge all options from different sources together and add the Ajax loader |
||
56 | var dtOpts = $.extend({}, data.options, typeof config.options === 'function' ? {} : config.options, options, persistOptions, { |
||
57 | ajax: function (request, drawCallback, settings) { |
||
58 | if (data) { |
||
59 | data.draw = request.draw; |
||
60 | drawCallback(data); |
||
61 | data = null; |
||
62 | if (Object.keys(state).length) { |
||
63 | var api = new $.fn.dataTable.Api( settings ); |
||
64 | var merged = $.extend(true, {}, api.state(), state); |
||
65 | |||
66 | api |
||
67 | .order(merged.order) |
||
68 | .search(merged.search.search) |
||
69 | .page.len(merged.length) |
||
70 | .page(merged.start / merged.length) |
||
71 | .draw(false); |
||
72 | } |
||
73 | } else { |
||
74 | request._dt = config.name; |
||
75 | $.ajax(typeof config.url === 'function' ? config.url(dt) : config.url, { |
||
0 ignored issues
–
show
The variable
dt seems to be never declared. If this is a global, consider adding a /** global: dt */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
76 | method: config.method, |
||
77 | data: request |
||
78 | }).done(function(data) { |
||
79 | drawCallback(data); |
||
80 | }) |
||
81 | } |
||
82 | } |
||
83 | }); |
||
84 | |||
85 | if (typeof config.options === 'function') { |
||
86 | dtOpts = config.options(dtOpts); |
||
87 | } |
||
88 | |||
89 | root.html(data.template); |
||
90 | dt = $('table', root).DataTable(dtOpts); |
||
0 ignored issues
–
show
|
|||
91 | if (config.state !== 'none') { |
||
92 | dt.on('draw.dt', function(e) { |
||
0 ignored issues
–
show
|
|||
93 | var data = $.param(dt.state()).split('&'); |
||
94 | |||
95 | // First draw establishes state, subsequent draws run diff on the first |
||
96 | if (!baseState) { |
||
97 | baseState = data; |
||
98 | } else { |
||
99 | var diff = data.filter(el => { return baseState.indexOf(el) === -1 && el.indexOf('time=') !== 0; }); |
||
100 | switch (config.state) { |
||
101 | case 'fragment': |
||
102 | history.replaceState(null, null, window.location.origin + window.location.pathname + window.location.search |
||
103 | + '#' + decodeURIComponent(diff.join('&'))); |
||
104 | break; |
||
105 | case 'query': |
||
106 | history.replaceState(null, null, window.location.origin + window.location.pathname |
||
107 | + '?' + decodeURIComponent(diff.join('&') + window.location.hash)); |
||
108 | break; |
||
109 | } |
||
110 | } |
||
111 | }) |
||
112 | } |
||
113 | |||
114 | fulfill(dt); |
||
115 | }).fail(function(xhr, cause, msg) { |
||
116 | console.error('DataTables request failed: ' + msg); |
||
117 | reject(cause); |
||
118 | }); |
||
119 | }); |
||
120 | }; |
||
121 | |||
122 | /** |
||
123 | * Provide global component defaults. |
||
124 | */ |
||
125 | $.fn.initDataTables.defaults = { |
||
126 | method: 'POST', |
||
127 | state: 'fragment', |
||
128 | url: window.location.origin + window.location.pathname |
||
129 | }; |
||
130 | |||
131 | /** |
||
132 | * Server-side export. |
||
133 | */ |
||
134 | $.fn.initDataTables.exportBtnAction = function(exporterName, settings) { |
||
135 | settings = $.extend({}, $.fn.initDataTables.defaults, settings); |
||
136 | |||
137 | return function(e, dt) { |
||
138 | const params = $.param($.extend({}, dt.ajax.params(), {'_dt': settings.name, '_exporter': exporterName})); |
||
139 | |||
140 | // Credit: https://stackoverflow.com/a/23797348 |
||
141 | const xhr = new XMLHttpRequest(); |
||
142 | xhr.open(settings.method, settings.method === 'GET' ? (settings.url + '?' + params) : settings.url, true); |
||
143 | xhr.responseType = 'arraybuffer'; |
||
144 | xhr.onload = function () { |
||
145 | if (this.status === 200) { |
||
146 | let filename = ""; |
||
147 | const disposition = xhr.getResponseHeader('Content-Disposition'); |
||
148 | if (disposition && disposition.indexOf('attachment') !== -1) { |
||
149 | const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; |
||
150 | const matches = filenameRegex.exec(disposition); |
||
151 | if (matches != null && matches[1]) { |
||
0 ignored issues
–
show
|
|||
152 | filename = matches[1].replace(/['"]/g, ''); |
||
153 | } |
||
154 | } |
||
155 | |||
156 | const type = xhr.getResponseHeader('Content-Type'); |
||
157 | |||
158 | let blob; |
||
159 | if (typeof File === 'function') { |
||
0 ignored issues
–
show
The variable
File seems to be never declared. If this is a global, consider adding a /** global: File */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
160 | try { |
||
161 | blob = new File([this.response], filename, { type: type }); |
||
162 | } catch (e) { /* Edge */ } |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
Best Practice
introduced
by
|
|||
163 | } |
||
164 | |||
165 | if (typeof blob === 'undefined') { |
||
0 ignored issues
–
show
|
|||
166 | blob = new Blob([this.response], { type: type }); |
||
0 ignored issues
–
show
The variable
Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
167 | } |
||
168 | |||
169 | if (typeof window.navigator.msSaveBlob !== 'undefined') { |
||
170 | // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed." |
||
171 | window.navigator.msSaveBlob(blob, filename); |
||
172 | } |
||
173 | else { |
||
174 | const URL = window.URL || window.webkitURL; |
||
175 | const downloadUrl = URL.createObjectURL(blob); |
||
176 | |||
177 | if (filename) { |
||
178 | // use HTML5 a[download] attribute to specify filename |
||
179 | const a = document.createElement("a"); |
||
180 | // safari doesn't support this yet |
||
181 | if (typeof a.download === 'undefined') { |
||
182 | window.location = downloadUrl; |
||
183 | } |
||
184 | else { |
||
185 | a.href = downloadUrl; |
||
186 | a.download = filename; |
||
187 | document.body.appendChild(a); |
||
188 | a.click(); |
||
189 | } |
||
190 | } |
||
191 | else { |
||
192 | window.location = downloadUrl; |
||
193 | } |
||
194 | |||
195 | setTimeout(function() { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup |
||
196 | } |
||
197 | } |
||
198 | }; |
||
199 | |||
200 | xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); |
||
201 | xhr.send(settings.method === 'POST' ? params : null); |
||
202 | } |
||
203 | }; |
||
204 | |||
205 | /** |
||
206 | * Convert a querystring to a proper array - reverses $.param |
||
207 | */ |
||
208 | function deparam(params, coerce) { |
||
209 | var obj = {}, |
||
210 | coerce_types = {'true': !0, 'false': !1, 'null': null}; |
||
211 | $.each(params.replace(/\+/g, ' ').split('&'), function (j, v) { |
||
212 | var param = v.split('='), |
||
213 | key = decodeURIComponent(param[0]), |
||
214 | val, |
||
215 | cur = obj, |
||
216 | i = 0, |
||
217 | keys = key.split(']['), |
||
218 | keys_last = keys.length - 1; |
||
219 | |||
220 | if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) { |
||
221 | keys[keys_last] = keys[keys_last].replace(/\]$/, ''); |
||
222 | keys = keys.shift().split('[').concat(keys); |
||
223 | keys_last = keys.length - 1; |
||
224 | } else { |
||
225 | keys_last = 0; |
||
226 | } |
||
227 | |||
228 | if (param.length === 2) { |
||
229 | val = decodeURIComponent(param[1]); |
||
230 | |||
231 | if (coerce) { |
||
232 | val = val && !isNaN(val) ? +val // number |
||
233 | : val === 'undefined' ? undefined // undefined |
||
234 | : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null |
||
235 | : val; // string |
||
236 | } |
||
237 | |||
238 | if (keys_last) { |
||
239 | for (; i <= keys_last; i++) { |
||
240 | key = keys[i] === '' ? cur.length : keys[i]; |
||
241 | cur = cur[key] = i < keys_last |
||
242 | ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : []) |
||
243 | : val; |
||
244 | } |
||
245 | |||
246 | } else { |
||
247 | if ($.isArray(obj[key])) { |
||
248 | obj[key].push(val); |
||
249 | } else if (obj[key] !== undefined) { |
||
250 | obj[key] = [obj[key], val]; |
||
251 | } else { |
||
252 | obj[key] = val; |
||
253 | } |
||
254 | } |
||
255 | |||
256 | } else if (key) { |
||
257 | obj[key] = coerce |
||
258 | ? undefined |
||
259 | : ''; |
||
260 | } |
||
261 | }); |
||
262 | |||
263 | return obj; |
||
264 | } |
||
265 | }(jQuery)); |
||
266 |
This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.