Commit | Line | Data |
---|---|---|
158bd3ca TD |
1 | /** |
2 | * Class and function collection for WCF ACP | |
3 | * | |
13d8b49b | 4 | * @author Alexander Ebert, Matthias Schmidt |
7b7b9764 | 5 | * @copyright 2001-2019 WoltLab GmbH |
158bd3ca TD |
6 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
7 | */ | |
8 | ||
9 | /** | |
10 | * Initialize WCF.ACP namespace | |
11 | */ | |
cb6e5946 | 12 | WCF.ACP = { }; |
158bd3ca | 13 | |
1a8d655f AE |
14 | /** |
15 | * Namespace for ACP application management. | |
16 | */ | |
17 | WCF.ACP.Application = { }; | |
18 | ||
29873759 MS |
19 | /** |
20 | * Namespace for ACP cronjob management. | |
21 | */ | |
22 | WCF.ACP.Cronjob = { }; | |
23 | ||
02b148ad MS |
24 | /** |
25 | * Handles the manual execution of cronjobs. | |
26 | */ | |
27 | WCF.ACP.Cronjob.ExecutionHandler = Class.extend({ | |
28 | /** | |
29 | * notification object | |
30 | * @var WCF.System.Notification | |
31 | */ | |
32 | _notification: null, | |
33 | ||
34 | /** | |
35 | * action proxy | |
36 | * @var WCF.Action.Proxy | |
37 | */ | |
38 | _proxy: null, | |
39 | ||
40 | /** | |
41 | * Initializes WCF.ACP.Cronjob.ExecutionHandler object. | |
42 | */ | |
43 | init: function() { | |
44 | this._proxy = new WCF.Action.Proxy({ | |
45 | success: $.proxy(this._success, this) | |
46 | }); | |
47 | ||
48 | $('.jsCronjobRow .jsExecuteButton').click($.proxy(this._click, this)); | |
49 | ||
50 | this._notification = new WCF.System.Notification(WCF.Language.get('wcf.global.success'), 'success'); | |
51 | }, | |
52 | ||
53 | /** | |
54 | * Handles a click on an execute button. | |
55 | * | |
56 | * @param object event | |
57 | */ | |
58 | _click: function(event) { | |
59 | this._proxy.setOption('data', { | |
60 | actionName: 'execute', | |
61 | className: 'wcf\\data\\cronjob\\CronjobAction', | |
62 | objectIDs: [ $(event.target).data('objectID') ] | |
63 | }); | |
64 | ||
65 | this._proxy.sendRequest(); | |
66 | }, | |
67 | ||
68 | /** | |
69 | * Handles successful cronjob execution. | |
70 | * | |
71 | * @param object data | |
72 | * @param string textStatus | |
73 | * @param jQuery jqXHR | |
74 | */ | |
75 | _success: function(data, textStatus, jqXHR) { | |
76 | $('.jsCronjobRow').each($.proxy(function(index, row) { | |
77 | var $button = $(row).find('.jsExecuteButton'); | |
78 | var $objectID = ($button).data('objectID'); | |
79 | ||
80 | if (WCF.inArray($objectID, data.objectIDs)) { | |
81 | if (data.returnValues[$objectID]) { | |
82 | // insert feedback here | |
83 | $(row).find('td.columnNextExec').html(data.returnValues[$objectID].formatted); | |
84 | $(row).wcfHighlight(); | |
85 | } | |
86 | ||
87 | this._notification.show(); | |
88 | ||
89 | return false; | |
90 | } | |
91 | }, this)); | |
92 | } | |
93 | }); | |
94 | ||
29873759 MS |
95 | /** |
96 | * Handles the cronjob log list. | |
97 | */ | |
98 | WCF.ACP.Cronjob.LogList = Class.extend({ | |
99 | /** | |
100 | * error message dialog | |
101 | * @var jQuery | |
102 | */ | |
103 | _dialog: null, | |
104 | ||
105 | /** | |
106 | * Initializes WCF.ACP.Cronjob.LogList object. | |
107 | */ | |
108 | init: function() { | |
109 | // bind event listener to delete cronjob log button | |
110 | $('.jsCronjobLogDelete').click(function() { | |
111 | WCF.System.Confirmation.show(WCF.Language.get('wcf.acp.cronjob.log.clear.confirm'), function(action) { | |
112 | if (action == 'confirm') { | |
113 | new WCF.Action.Proxy({ | |
114 | autoSend: true, | |
115 | data: { | |
116 | actionName: 'clearAll', | |
117 | className: 'wcf\\data\\cronjob\\log\\CronjobLogAction' | |
118 | }, | |
119 | success: function() { | |
120 | window.location.reload(); | |
121 | } | |
122 | }); | |
123 | } | |
124 | }); | |
125 | }); | |
126 | ||
127 | // bind event listeners to error badges | |
128 | $('.jsCronjobError').click($.proxy(this._showError, this)); | |
129 | }, | |
130 | ||
131 | /** | |
132 | * Shows certain error message | |
133 | * | |
134 | * @param object event | |
135 | */ | |
136 | _showError: function(event) { | |
137 | var $errorBadge = $(event.currentTarget); | |
138 | ||
139 | if (this._dialog === null) { | |
cafc0b69 | 140 | this._dialog = $('<div style="overflow: auto"><pre>' + $errorBadge.next().html() + '</pre></div>').hide().appendTo(document.body); |
29873759 MS |
141 | this._dialog.wcfDialog({ |
142 | title: WCF.Language.get('wcf.acp.cronjob.log.error.details') | |
143 | }); | |
144 | } | |
145 | else { | |
cafc0b69 | 146 | this._dialog.html('<pre>' + $errorBadge.next().html() + '</pre>'); |
29873759 MS |
147 | this._dialog.wcfDialog('open'); |
148 | } | |
149 | } | |
150 | }); | |
151 | ||
e5b88a7f AE |
152 | /** |
153 | * Namespace for ACP package management. | |
154 | */ | |
3536d2fe | 155 | WCF.ACP.Package = { }; |
d71e5a29 | 156 | |
158bd3ca | 157 | /** |
cb9e9c12 | 158 | * Provides the package installation. |
158bd3ca | 159 | * |
158bd3ca | 160 | * @param integer queueID |
2ef79140 | 161 | * @param string actionName |
158bd3ca | 162 | */ |
cb9e9c12 | 163 | WCF.ACP.Package.Installation = Class.extend({ |
158bd3ca TD |
164 | /** |
165 | * package installation type | |
158bd3ca TD |
166 | * @var string |
167 | */ | |
cb9e9c12 | 168 | _actionName: 'InstallPackage', |
9f959ced | 169 | |
89aa80c1 MS |
170 | /** |
171 | * additional parameters send in all requests | |
172 | * @var object | |
173 | */ | |
174 | _additionalRequestParameters: {}, | |
175 | ||
0acbb6be AE |
176 | /** |
177 | * true, if rollbacks are supported | |
178 | * @var boolean | |
179 | */ | |
180 | _allowRollback: false, | |
181 | ||
e5b88a7f | 182 | /** |
cb9e9c12 AE |
183 | * dialog object |
184 | * @var jQuery | |
158bd3ca TD |
185 | */ |
186 | _dialog: null, | |
187 | ||
6207cc21 MS |
188 | /** |
189 | * name of the language item with the title of the dialog | |
190 | * @var string | |
191 | */ | |
192 | _dialogTitle: '', | |
193 | ||
e5b88a7f AE |
194 | /** |
195 | * action proxy | |
196 | * @var WCF.Action.Proxy | |
197 | */ | |
198 | _proxy: null, | |
9f959ced | 199 | |
158bd3ca | 200 | /** |
cb9e9c12 | 201 | * package installation queue id |
158bd3ca TD |
202 | * @var integer |
203 | */ | |
204 | _queueID: 0, | |
9f959ced | 205 | |
ba133309 AE |
206 | /** |
207 | * true, if dialog should be rendered again | |
208 | * @var boolean | |
209 | */ | |
210 | _shouldRender: false, | |
211 | ||
0a3949d4 | 212 | /** |
cb9e9c12 | 213 | * Initializes the WCF.ACP.Package.Installation class. |
158bd3ca | 214 | * |
158bd3ca | 215 | * @param integer queueID |
2ef79140 | 216 | * @param string actionName |
0acbb6be | 217 | * @param boolean allowRollback |
adf9791d | 218 | * @param boolean isUpdate |
89aa80c1 | 219 | * @param object additionalRequestParameters |
158bd3ca | 220 | */ |
89aa80c1 | 221 | init: function(queueID, actionName, allowRollback, isUpdate, additionalRequestParameters) { |
2ef79140 | 222 | this._actionName = (actionName) ? actionName : 'InstallPackage'; |
9d9aede4 | 223 | this._allowRollback = (allowRollback === true); |
158bd3ca | 224 | this._queueID = queueID; |
89aa80c1 | 225 | this._additionalRequestParameters = additionalRequestParameters || {}; |
cb9e9c12 | 226 | |
89aa80c1 MS |
227 | this._dialogTitle = 'wcf.acp.package.' + (isUpdate ? 'update' : 'install') + '.title'; |
228 | if (this._actionName === 'UninstallPackage') { | |
229 | this._dialogTitle = 'wcf.acp.package.uninstallation.title'; | |
6207cc21 MS |
230 | } |
231 | ||
0acbb6be AE |
232 | this._initProxy(); |
233 | this._init(); | |
234 | }, | |
235 | ||
236 | /** | |
237 | * Initializes the WCF.Action.Proxy object. | |
238 | */ | |
239 | _initProxy: function() { | |
e31cf611 AE |
240 | var $actionName = ''; |
241 | var $parts = this._actionName.split(/([A-Z][a-z0-9]+)/); | |
242 | for (var $i = 0, $length = $parts.length; $i < $length; $i++) { | |
243 | var $part = $parts[$i]; | |
244 | if ($part.length) { | |
245 | if ($actionName.length) $actionName += '-'; | |
246 | $actionName += $part.toLowerCase(); | |
247 | } | |
248 | } | |
249 | ||
e5b88a7f | 250 | this._proxy = new WCF.Action.Proxy({ |
cb9e9c12 | 251 | failure: $.proxy(this._failure, this), |
324e8301 | 252 | showLoadingOverlay: false, |
cb9e9c12 | 253 | success: $.proxy(this._success, this), |
772f616f | 254 | url: 'index.php?' + $actionName + '/&t=' + SECURITY_TOKEN |
e5b88a7f | 255 | }); |
cb9e9c12 AE |
256 | }, |
257 | ||
258 | /** | |
259 | * Initializes the package installation. | |
260 | */ | |
261 | _init: function() { | |
5bae7259 | 262 | const button = document.getElementById('submitButton'); |
99930e4a | 263 | button?.addEventListener( |
5bae7259 TD |
264 | 'click', |
265 | () => { | |
266 | button.disabled = true; | |
267 | this.prepareInstallation(); | |
268 | } | |
269 | ); | |
cb9e9c12 AE |
270 | }, |
271 | ||
272 | /** | |
273 | * Handles erroneous AJAX requests. | |
cb9e9c12 | 274 | */ |
014819c4 | 275 | _failure: function() { |
e0a0fe54 | 276 | if (this._dialog !== null) { |
5df9b2ef | 277 | $('#packageInstallationProgress').removeAttr('value'); |
0caf2e88 | 278 | this._setIcon('xmark'); |
e0a0fe54 | 279 | } |
e098d212 | 280 | |
0acbb6be AE |
281 | if (!this._allowRollback) { |
282 | return; | |
283 | } | |
284 | ||
7289c8d3 MS |
285 | if (this._dialog !== null) { |
286 | this._purgeTemplateContent($.proxy(function() { | |
287 | var $form = $('<div class="formSubmit" />').appendTo($('#packageInstallationInnerContent')); | |
58d5a1b5 | 288 | $('<button type="button" class="button buttonPrimary">' + WCF.Language.get('wcf.acp.package.installation.rollback') + '</button>').appendTo($form).click($.proxy(this._rollback, this)); |
7289c8d3 MS |
289 | |
290 | $('#packageInstallationInnerContentContainer').show(); | |
291 | ||
292 | this._dialog.wcfDialog('render'); | |
293 | }, this)); | |
294 | } | |
0acbb6be AE |
295 | }, |
296 | ||
297 | /** | |
298 | * Performs a rollback. | |
7fcd3ad5 AE |
299 | * |
300 | * @param object event | |
0acbb6be | 301 | */ |
7fcd3ad5 | 302 | _rollback: function(event) { |
e098d212 AE |
303 | this._setIcon('spinner'); |
304 | ||
7fcd3ad5 AE |
305 | if (event) { |
306 | $(event.currentTarget).disable(); | |
307 | } | |
308 | ||
0acbb6be | 309 | this._executeStep('rollback'); |
158bd3ca TD |
310 | }, |
311 | ||
312 | /** | |
313 | * Prepares installation dialog. | |
314 | */ | |
b32a906e | 315 | prepareInstallation: function() { |
639e46d6 AE |
316 | if (document.activeElement) { |
317 | document.activeElement.blur(); | |
318 | } | |
319 | ||
872db512 | 320 | require(['WoltLabSuite/Core/Ajax/Status'], ({show}) => show()); |
4da866ad AE |
321 | this._proxy.setOption('data', this._getParameters()); |
322 | this._proxy.sendRequest(); | |
158bd3ca TD |
323 | }, |
324 | ||
325 | /** | |
cb9e9c12 AE |
326 | * Returns parameters to prepare installation. |
327 | * | |
328 | * @return object | |
329 | */ | |
330 | _getParameters: function() { | |
89aa80c1 | 331 | return $.extend({}, this._additionalRequestParameters, { |
cb9e9c12 AE |
332 | queueID: this._queueID, |
333 | step: 'prepare' | |
89aa80c1 | 334 | }); |
cb9e9c12 AE |
335 | }, |
336 | ||
337 | /** | |
338 | * Handles successful AJAX requests. | |
e5b88a7f AE |
339 | * |
340 | * @param object data | |
341 | * @param string textStatus | |
342 | * @param jQuery jqXHR | |
158bd3ca | 343 | */ |
cb9e9c12 | 344 | _success: function(data, textStatus, jqXHR) { |
ba133309 | 345 | this._shouldRender = false; |
cb9e9c12 | 346 | |
a7f9deff TD |
347 | if (typeof window._trackPackageStep === 'function') window._trackPackageStep(this._actionName, data); |
348 | ||
4da866ad | 349 | if (this._dialog === null) { |
ac86f5f7 | 350 | this._dialog = $('<div id="package' + (this._actionName === 'UninstallPackage' ? 'Uni' : 'I') + 'nstallationDialog" />').hide().appendTo(document.body); |
4da866ad AE |
351 | this._dialog.wcfDialog({ |
352 | closable: false, | |
6207cc21 | 353 | title: WCF.Language.get(this._dialogTitle) |
4da866ad | 354 | }); |
872db512 | 355 | require(['WoltLabSuite/Core/Ajax/Status'], ({hide}) => hide()); |
4da866ad AE |
356 | } |
357 | ||
e098d212 AE |
358 | this._setIcon('spinner'); |
359 | ||
0acbb6be AE |
360 | if (data.step == 'rollback') { |
361 | this._dialog.wcfDialog('close'); | |
e9add3b2 | 362 | this._dialog.remove(); |
0acbb6be | 363 | |
81fe3118 | 364 | setTimeout(function () { |
0acbb6be AE |
365 | var $uninstallation = new WCF.ACP.Package.Uninstallation(); |
366 | $uninstallation.start(data.packageID); | |
367 | }, 200); | |
368 | ||
369 | return; | |
370 | } | |
371 | ||
158bd3ca | 372 | // receive new queue id |
e5b88a7f AE |
373 | if (data.queueID) { |
374 | this._queueID = data.queueID; | |
158bd3ca TD |
375 | } |
376 | ||
47d85da7 AE |
377 | // update template |
378 | if (data.template && !data.ignoreTemplate) { | |
379 | this._dialog.html(data.template); | |
380 | this._shouldRender = true; | |
381 | } | |
382 | ||
158bd3ca | 383 | // update progress |
e5b88a7f AE |
384 | if (data.progress) { |
385 | $('#packageInstallationProgress').attr('value', data.progress).text(data.progress + '%'); | |
386 | $('#packageInstallationProgressLabel').text(data.progress + '%'); | |
e70175d6 | 387 | } |
9f959ced | 388 | |
e70175d6 | 389 | // update action |
e5b88a7f AE |
390 | if (data.currentAction) { |
391 | $('#packageInstallationAction').html(data.currentAction); | |
158bd3ca TD |
392 | } |
393 | ||
394 | // handle success | |
cb9e9c12 | 395 | if (data.step === 'success') { |
962f1164 | 396 | this._setIcon('check'); |
e098d212 | 397 | |
0a3949d4 | 398 | this._purgeTemplateContent($.proxy(function() { |
cb9e9c12 | 399 | var $form = $('<div class="formSubmit" />').appendTo($('#packageInstallationInnerContent')); |
58d5a1b5 | 400 | var $button = $('<button type="button" class="button buttonPrimary">' + WCF.Language.get('wcf.global.button.next') + '</button>').appendTo($form).click(function() { |
7fcd3ad5 AE |
401 | $(this).disable(); |
402 | window.location = data.redirectLocation; | |
403 | }); | |
3c87a1b1 | 404 | |
0a3949d4 | 405 | $('#packageInstallationInnerContentContainer').show(); |
cb9e9c12 | 406 | |
45f1e6f9 AE |
407 | $(document).keydown(function(event) { |
408 | if (event.which === $.ui.keyCode.ENTER) { | |
409 | $button.trigger('click'); | |
410 | } | |
411 | }); | |
412 | ||
cb9e9c12 | 413 | this._dialog.wcfDialog('render'); |
0a3949d4 | 414 | }, this)); |
158bd3ca TD |
415 | |
416 | return; | |
417 | } | |
418 | ||
158bd3ca | 419 | // handle inner template |
e5b88a7f | 420 | if (data.innerTemplate) { |
599a39ba | 421 | var self = this; |
599a39ba | 422 | $('#packageInstallationInnerContent').html(data.innerTemplate).find('input').keyup(function(event) { |
45f1e6f9 | 423 | if (event.keyCode === $.ui.keyCode.ENTER) { |
b32a906e | 424 | self._submit(data); |
599a39ba AE |
425 | } |
426 | }); | |
158bd3ca TD |
427 | |
428 | // create button to handle next step | |
e5b88a7f | 429 | if (data.step && data.node) { |
5df9b2ef | 430 | $('#packageInstallationProgress').removeAttr('value'); |
e098d212 AE |
431 | this._setIcon('question'); |
432 | ||
cb9e9c12 | 433 | var $form = $('<div class="formSubmit" />').appendTo($('#packageInstallationInnerContent')); |
58d5a1b5 | 434 | $('<button type="button" class="button buttonPrimary">' + WCF.Language.get('wcf.global.button.next') + '</button>').appendTo($form).click($.proxy(function(event) { |
7fcd3ad5 AE |
435 | $(event.currentTarget).disable(); |
436 | ||
437 | this._submit(data); | |
9db0c330 | 438 | }, this)); |
158bd3ca TD |
439 | } |
440 | ||
0a3949d4 | 441 | $('#packageInstallationInnerContentContainer').show(); |
158bd3ca | 442 | |
cb9e9c12 | 443 | this._dialog.wcfDialog('render'); |
158bd3ca TD |
444 | return; |
445 | } | |
446 | ||
447 | // purge content | |
3c87a1b1 | 448 | this._purgeTemplateContent($.proxy(function() { |
e5b88a7f | 449 | // render container |
ba133309 | 450 | if (this._shouldRender) { |
cb9e9c12 | 451 | this._dialog.wcfDialog('render'); |
0a3949d4 | 452 | } |
5e6179f1 | 453 | |
3c87a1b1 | 454 | // execute next step |
e5b88a7f AE |
455 | if (data.step && data.node) { |
456 | this._executeStep(data.step, data.node); | |
3c87a1b1 AE |
457 | } |
458 | }, this)); | |
459 | }, | |
460 | ||
599a39ba AE |
461 | /** |
462 | * Submits the dialog content. | |
463 | * | |
464 | * @param object data | |
465 | */ | |
b32a906e | 466 | _submit: function(data) { |
e098d212 AE |
467 | this._setIcon('spinner'); |
468 | ||
599a39ba | 469 | // collect form values |
cb6e5946 | 470 | var $additionalData = { }; |
599a39ba AE |
471 | $('#packageInstallationInnerContent input').each(function(index, inputElement) { |
472 | var $inputElement = $(inputElement); | |
473 | var $type = $inputElement.attr('type'); | |
474 | ||
3bbe83f0 MS |
475 | if (($type != 'checkbox' && $type != 'radio') || $inputElement.prop('checked')) { |
476 | var $name = $inputElement.attr('name'); | |
477 | if ($name.match(/(.*)\[([^[]*)\]$/)) { | |
478 | $name = RegExp.$1; | |
479 | $key = RegExp.$2; | |
480 | ||
481 | if ($additionalData[$name] === undefined) { | |
482 | if ($key) { | |
483 | $additionalData[$name] = { }; | |
484 | } | |
485 | else { | |
486 | $additionalData[$name] = [ ]; | |
487 | } | |
488 | } | |
489 | ||
c001b457 | 490 | if ($key) { |
3bbe83f0 | 491 | $additionalData[$name][$key] = $inputElement.val(); |
c001b457 AE |
492 | } |
493 | else { | |
3bbe83f0 | 494 | $additionalData[$name].push($inputElement.val()); |
c001b457 AE |
495 | } |
496 | } | |
c001b457 | 497 | else { |
3bbe83f0 | 498 | $additionalData[$name] = $inputElement.val(); |
c001b457 AE |
499 | } |
500 | } | |
599a39ba AE |
501 | }); |
502 | ||
503 | this._executeStep(data.step, data.node, $additionalData); | |
504 | }, | |
505 | ||
3c87a1b1 AE |
506 | /** |
507 | * Purges template content. | |
508 | * | |
509 | * @param function callback | |
510 | */ | |
511 | _purgeTemplateContent: function(callback) { | |
f027ba61 AE |
512 | if ($('#packageInstallationInnerContent').children().length) { |
513 | $('#packageInstallationInnerContentContainer').hide(); | |
514 | $('#packageInstallationInnerContent').empty(); | |
515 | ||
516 | this._shouldRender = true; | |
158bd3ca | 517 | } |
f027ba61 AE |
518 | |
519 | callback(); | |
158bd3ca TD |
520 | }, |
521 | ||
522 | /** | |
523 | * Executes the next installation step. | |
524 | * | |
525 | * @param string step | |
526 | * @param string node | |
527 | * @param object additionalData | |
528 | */ | |
529 | _executeStep: function(step, node, additionalData) { | |
cb6e5946 | 530 | if (!additionalData) additionalData = { }; |
158bd3ca | 531 | |
89aa80c1 | 532 | var $data = $.extend({}, this._additionalRequestParameters, { |
a698c064 AE |
533 | node: node, |
534 | queueID: this._queueID, | |
535 | step: step | |
158bd3ca | 536 | }, additionalData); |
9f959ced | 537 | |
e5b88a7f AE |
538 | this._proxy.setOption('data', $data); |
539 | this._proxy.sendRequest(); | |
e098d212 AE |
540 | }, |
541 | ||
e0a0fe54 MS |
542 | /** |
543 | * Sets the icon with the given name as the current installation status icon. | |
544 | * | |
545 | * @param string iconName | |
546 | */ | |
e098d212 | 547 | _setIcon: function(iconName) { |
e6286f54 AE |
548 | const icon = this._dialog.find('.jsPackageInstallationStatus fa-icon'); |
549 | if (icon.length === 1) { | |
550 | icon[0].setIcon(iconName); | |
551 | } | |
158bd3ca | 552 | } |
cb9e9c12 | 553 | }); |
158bd3ca | 554 | |
a45fa84d MS |
555 | /** |
556 | * Handles canceling the package installation at the package installation | |
557 | * confirm page. | |
558 | */ | |
559 | WCF.ACP.Package.Installation.Cancel = Class.extend({ | |
560 | /** | |
561 | * Creates a new instance of WCF.ACP.Package.Installation.Cancel. | |
562 | * | |
563 | * @param integer queueID | |
564 | */ | |
565 | init: function(queueID) { | |
566 | $('#backButton').click(function() { | |
567 | new WCF.Action.Proxy({ | |
568 | autoSend: true, | |
569 | data: { | |
570 | actionName: 'cancelInstallation', | |
571 | className: 'wcf\\data\\package\\installation\\queue\\PackageInstallationQueueAction', | |
572 | objectIDs: [ queueID ] | |
573 | }, | |
574 | success: function(data) { | |
575 | window.location = data.returnValues.url; | |
576 | } | |
577 | }); | |
578 | }); | |
579 | } | |
580 | }); | |
581 | ||
158bd3ca | 582 | /** |
cb9e9c12 | 583 | * Provides the package uninstallation. |
158bd3ca TD |
584 | * |
585 | * @param jQuery elements | |
74622428 | 586 | * @param string wcfPackageListURL |
158bd3ca | 587 | */ |
cb9e9c12 | 588 | WCF.ACP.Package.Uninstallation = WCF.ACP.Package.Installation.extend({ |
158bd3ca | 589 | /** |
cb9e9c12 AE |
590 | * list of uninstallation buttons |
591 | * @var jQuery | |
158bd3ca | 592 | */ |
cb9e9c12 | 593 | _elements: null, |
158bd3ca TD |
594 | |
595 | /** | |
cb9e9c12 AE |
596 | * current package id |
597 | * @var integer | |
598 | */ | |
599 | _packageID: 0, | |
600 | ||
601 | /** | |
602 | * Initializes the WCF.ACP.Package.Uninstallation class. | |
158bd3ca TD |
603 | * |
604 | * @param jQuery elements | |
605 | */ | |
f35150dd | 606 | init: function(elements) { |
cb9e9c12 AE |
607 | this._elements = elements; |
608 | this._packageID = 0; | |
158bd3ca | 609 | |
0acbb6be | 610 | if (this._elements !== undefined && this._elements.length) { |
2ef79140 | 611 | this._super(0, 'UninstallPackage'); |
cb9e9c12 | 612 | } |
158bd3ca TD |
613 | }, |
614 | ||
0acbb6be AE |
615 | /** |
616 | * Begins a package uninstallation without user action. | |
617 | * | |
618 | * @param integer packageID | |
619 | */ | |
620 | start: function(packageID) { | |
621 | this._actionName = 'UninstallPackage'; | |
622 | this._packageID = packageID; | |
623 | this._queueID = 0; | |
6207cc21 | 624 | this._dialogTitle = 'wcf.acp.package.uninstallation.title'; |
0acbb6be AE |
625 | |
626 | this._initProxy(); | |
627 | this.prepareInstallation(); | |
628 | }, | |
629 | ||
158bd3ca | 630 | /** |
cb9e9c12 AE |
631 | * @see WCF.ACP.Package.Installation.init() |
632 | */ | |
633 | _init: function() { | |
e3be0700 | 634 | this._elements.click($.proxy(this._showConfirmationDialog, this)); |
e852aa82 AE |
635 | }, |
636 | ||
637 | /** | |
638 | * Displays a confirmation dialog prior to package uninstallation. | |
639 | * | |
cec91f01 | 640 | * @param object event |
e852aa82 | 641 | */ |
cec91f01 | 642 | _showConfirmationDialog: function(event) { |
e3be0700 AE |
643 | var $element = $(event.currentTarget); |
644 | ||
cb9e9c12 | 645 | var self = this; |
e3be0700 | 646 | WCF.System.Confirmation.show($element.data('confirmMessage'), function(action) { |
cb9e9c12 | 647 | if (action === 'confirm') { |
e3be0700 | 648 | self._packageID = $element.data('objectID'); |
b32a906e | 649 | self.prepareInstallation(); |
cb9e9c12 | 650 | } |
23e43ac5 | 651 | }, undefined, undefined, true); |
29b533c8 AE |
652 | }, |
653 | ||
654 | /** | |
cb9e9c12 | 655 | * @see WCF.ACP.Package.Installation._getParameters() |
29b533c8 | 656 | */ |
cb9e9c12 AE |
657 | _getParameters: function() { |
658 | return { | |
659 | packageID: this._packageID, | |
660 | step: 'prepare' | |
661 | }; | |
158bd3ca | 662 | } |
cb9e9c12 | 663 | }); |
158bd3ca | 664 | |
66ed9925 | 665 | WCF.ACP.Package.Server = { }; |
298a7cd8 AE |
666 | |
667 | WCF.ACP.Package.Server.Installation = Class.extend({ | |
668 | _proxy: null, | |
669 | _selectedPackage: '', | |
670 | ||
671 | init: function() { | |
672 | this._dialog = null; | |
673 | this._selectedPackage = null; | |
674 | ||
675 | this._proxy = new WCF.Action.Proxy({ | |
676 | success: $.proxy(this._success, this) | |
677 | }); | |
678 | }, | |
679 | ||
680 | bind: function() { | |
681 | $('.jsButtonPackageInstall').removeClass('jsButtonPackageInstall').click($.proxy(this._click, this)); | |
682 | }, | |
683 | ||
684 | /** | |
685 | * Prepares a package installation. | |
686 | * | |
687 | * @param object event | |
688 | */ | |
689 | _click: function(event) { | |
690 | var $button = $(event.currentTarget); | |
691 | WCF.System.Confirmation.show($button.data('confirmMessage'), $.proxy(function(action) { | |
692 | if (action === 'confirm') { | |
693 | this._selectedPackage = $button.data('package'); | |
694 | this._selectedPackageVersion = $button.data('packageVersion'); | |
695 | this._prepareInstallation(); | |
696 | } | |
23e43ac5 | 697 | }, this), undefined, undefined, true); |
298a7cd8 AE |
698 | }, |
699 | ||
700 | /** | |
701 | * Handles successful AJAX requests. | |
702 | * | |
703 | * @param object data | |
704 | */ | |
705 | _success: function(data) { | |
706 | if (data.returnValues.queueID) { | |
707 | if (this._dialog !== null) { | |
708 | this._dialog.wcfDialog('close'); | |
709 | } | |
710 | ||
711 | var $installation = new WCF.ACP.Package.Installation(data.returnValues.queueID, undefined, false); | |
712 | $installation.prepareInstallation(); | |
713 | } | |
714 | else if (data.returnValues.template) { | |
715 | if (this._dialog === null) { | |
716 | this._dialog = $('<div>' + data.returnValues.template + '</div>').hide().appendTo(document.body); | |
717 | this._dialog.wcfDialog({ | |
718 | title: WCF.Language.get('wcf.acp.package.update.unauthorized') | |
719 | }); | |
720 | } | |
721 | else { | |
722 | this._dialog.html(data.returnValues.template).wcfDialog('open'); | |
723 | } | |
724 | ||
725 | this._dialog.find('.formSubmit > button').click($.proxy(this._submitAuthentication, this)); | |
726 | } | |
727 | }, | |
728 | ||
729 | /** | |
730 | * Submits authentication data for current update server. | |
731 | * | |
732 | * @param object event | |
733 | */ | |
734 | _submitAuthentication: function(event) { | |
735 | var $usernameField = $('#packageUpdateServerUsername'); | |
736 | var $passwordField = $('#packageUpdateServerPassword'); | |
737 | ||
738 | // remove error messages if any | |
739 | $usernameField.next('small.innerError').remove(); | |
740 | $passwordField.next('small.innerError').remove(); | |
741 | ||
742 | var $continue = true; | |
743 | if ($.trim($usernameField.val()) === '') { | |
744 | $('<small class="innerError">' + WCF.Language.get('wcf.global.form.error.empty') + '</small>').insertAfter($usernameField); | |
745 | $continue = false; | |
746 | } | |
747 | ||
748 | if ($.trim($passwordField.val()) === '') { | |
749 | $('<small class="innerError">' + WCF.Language.get('wcf.global.form.error.empty') + '</small>').insertAfter($passwordField); | |
750 | $continue = false; | |
751 | } | |
752 | ||
753 | if ($continue) { | |
754 | this._prepareInstallation($(event.currentTarget).data('packageUpdateServerID')); | |
755 | } | |
756 | }, | |
757 | ||
758 | /** | |
759 | * Prepares package installation. | |
760 | * | |
761 | * @param integer packageUpdateServerID | |
762 | */ | |
763 | _prepareInstallation: function(packageUpdateServerID) { | |
764 | var $parameters = { | |
765 | 'packages': { } | |
766 | }; | |
767 | $parameters['packages'][this._selectedPackage] = this._selectedPackageVersion; | |
768 | ||
769 | if (packageUpdateServerID) { | |
770 | $parameters.authData = { | |
771 | packageUpdateServerID: packageUpdateServerID, | |
772 | password: $.trim($('#packageUpdateServerPassword').val()), | |
773 | saveCredentials: ($('#packageUpdateServerSaveCredentials:checked').length ? true : false), | |
774 | username: $.trim($('#packageUpdateServerUsername').val()) | |
775 | }; | |
776 | } | |
777 | ||
778 | this._proxy.setOption('data', { | |
779 | actionName: 'prepareInstallation', | |
780 | className: 'wcf\\data\\package\\update\\PackageUpdateAction', | |
781 | parameters: $parameters | |
782 | }); | |
783 | this._proxy.sendRequest(); | |
784 | }, | |
2061c822 | 785 | }); |
298a7cd8 | 786 | |
3536d2fe AE |
787 | /** |
788 | * Namespace for package update related classes. | |
789 | */ | |
790 | WCF.ACP.Package.Update = { }; | |
791 | ||
3536d2fe AE |
792 | /** |
793 | * Searches for available updates. | |
60fe64f6 AE |
794 | * |
795 | * @param boolean bindOnExistingButtons | |
3536d2fe AE |
796 | */ |
797 | WCF.ACP.Package.Update.Search = Class.extend({ | |
be005df2 AE |
798 | /** @var {Element} */ |
799 | _button: null, | |
800 | ||
3536d2fe AE |
801 | /** |
802 | * dialog overlay | |
803 | * @var jQuery | |
804 | */ | |
805 | _dialog: null, | |
806 | ||
807 | /** | |
60fe64f6 AE |
808 | * Initializes the WCF.ACP.Package.SearchForUpdates class. |
809 | * | |
be005df2 | 810 | * @param {boolean} bindOnExistingButtons |
3536d2fe | 811 | */ |
60fe64f6 | 812 | init: function(bindOnExistingButtons) { |
3536d2fe AE |
813 | this._dialog = null; |
814 | ||
be005df2 | 815 | if (!bindOnExistingButtons === true) { |
925dad9f | 816 | $(`<li> |
58d5a1b5 | 817 | <button type="button" class="button jsButtonSearchForUpdates"> |
925dad9f AE |
818 | <fa-icon size="16" name="arrows-rotate"></fa-icon> |
819 | <span>${WCF.Language.get('wcf.acp.package.searchForUpdates')}</span> | |
820 | </button> | |
821 | </li>`).prependTo($('.contentHeaderNavigation > ul')); | |
60fe64f6 | 822 | } |
be005df2 AE |
823 | |
824 | this._button = elBySel('.jsButtonSearchForUpdates'); | |
490ef421 AE |
825 | if (this._button) { |
826 | this._button.addEventListener('click', this._click.bind(this)); | |
827 | ||
828 | const url = new URL(window.location.href); | |
829 | if (url.searchParams.has("searchForUpdates")) { | |
830 | this._click(); | |
831 | } | |
832 | } | |
3536d2fe AE |
833 | }, |
834 | ||
835 | /** | |
836 | * Handles clicks on the search button. | |
c93ced9f AE |
837 | * |
838 | * @param {Event} event | |
3536d2fe | 839 | */ |
c93ced9f | 840 | _click: function(event) { |
490ef421 | 841 | event?.preventDefault(); |
c93ced9f | 842 | |
be005df2 AE |
843 | if (this._button.classList.contains('disabled')) { |
844 | return; | |
845 | } | |
846 | ||
847 | this._button.classList.add('disabled'); | |
848 | ||
3536d2fe AE |
849 | if (this._dialog === null) { |
850 | new WCF.Action.Proxy({ | |
851 | autoSend: true, | |
852 | data: { | |
853 | actionName: 'searchForUpdates', | |
70e6f4e6 AE |
854 | className: 'wcf\\data\\package\\update\\PackageUpdateAction', |
855 | parameters: { | |
856 | ignoreCache: 1 | |
857 | } | |
3536d2fe AE |
858 | }, |
859 | success: $.proxy(this._success, this) | |
860 | }); | |
861 | } | |
862 | else { | |
863 | this._dialog.wcfDialog('open'); | |
864 | } | |
865 | }, | |
866 | ||
867 | /** | |
868 | * Handles successful AJAX requests. | |
869 | * | |
870 | * @param object data | |
871 | * @param string textStatus | |
872 | * @param jQuery jqXHR | |
873 | */ | |
874 | _success: function(data, textStatus, jqXHR) { | |
cdfed2c3 AE |
875 | if (typeof window._trackSearchForUpdates === 'function') { |
876 | window._trackSearchForUpdates(data); | |
877 | return; | |
878 | } | |
879 | ||
3536d2fe AE |
880 | if (data.returnValues.url) { |
881 | window.location = data.returnValues.url; | |
882 | } | |
883 | else { | |
884 | this._dialog = $('<div>' + WCF.Language.get('wcf.acp.package.searchForUpdates.noResults') + '</div>').hide().appendTo(document.body); | |
885 | this._dialog.wcfDialog({ | |
886 | title: WCF.Language.get('wcf.acp.package.searchForUpdates') | |
887 | }); | |
be005df2 AE |
888 | |
889 | this._button.classList.remove('disabled'); | |
3536d2fe AE |
890 | } |
891 | } | |
892 | }); | |
893 | ||
532f1173 AE |
894 | /** |
895 | * Worker support for ACP. | |
896 | * | |
897 | * @param string dialogID | |
898 | * @param string className | |
0cb0c522 AE |
899 | * @param string title |
900 | * @param object parameters | |
901 | * @param object callback | |
835354e5 AE |
902 | * |
903 | * @deprecated 3.1 - please use `WoltLabSuite/Core/Acp/Ui/Worker` instead | |
532f1173 | 904 | */ |
1f9100ba | 905 | WCF.ACP.Worker = Class.extend({ |
532f1173 AE |
906 | /** |
907 | * Initializes a new worker instance. | |
908 | * | |
909 | * @param string dialogID | |
910 | * @param string className | |
2cea2b5b AE |
911 | * @param string title |
912 | * @param object parameters | |
0cb0c522 | 913 | * @param object callback |
532f1173 | 914 | */ |
0cb0c522 | 915 | init: function(dialogID, className, title, parameters, callback) { |
835354e5 AE |
916 | if (typeof callback === 'function') { |
917 | throw new Error("The callback parameter is no longer supported, please migrate to 'WoltLabSuite/Core/Acp/Ui/Worker'."); | |
532f1173 AE |
918 | } |
919 | ||
835354e5 AE |
920 | require(['WoltLabSuite/Core/Acp/Ui/Worker'], function(AcpUiWorker) { |
921 | new AcpUiWorker({ | |
922 | // dialog | |
923 | dialogId: dialogID, | |
924 | dialogTitle: title, | |
925 | ||
926 | // ajax | |
927 | className: className, | |
928 | parameters: parameters | |
532f1173 | 929 | }); |
835354e5 | 930 | }); |
532f1173 | 931 | } |
1f9100ba | 932 | }); |
13d8b49b MS |
933 | |
934 | /** | |
935 | * Namespace for category-related functions. | |
936 | */ | |
cb6e5946 | 937 | WCF.ACP.Category = { }; |
13d8b49b MS |
938 | |
939 | /** | |
940 | * Handles collapsing categories. | |
941 | * | |
942 | * @param string className | |
943 | * @param integer objectTypeID | |
944 | */ | |
945 | WCF.ACP.Category.Collapsible = WCF.Collapsible.SimpleRemote.extend({ | |
946 | /** | |
947 | * @see WCF.Collapsible.Remote.init() | |
948 | */ | |
fc3d134b | 949 | init: function(className) { |
13d8b49b MS |
950 | var sortButton = $('.formSubmit > button[data-type="submit"]'); |
951 | if (sortButton) { | |
952 | sortButton.click($.proxy(this._sort, this)); | |
953 | } | |
954 | ||
955 | this._super(className); | |
956 | }, | |
9f959ced | 957 | |
13d8b49b MS |
958 | /** |
959 | * @see WCF.Collapsible.Remote._getButtonContainer() | |
960 | */ | |
961 | _getButtonContainer: function(containerID) { | |
962 | return $('#' + containerID + ' > .buttons'); | |
963 | }, | |
9f959ced | 964 | |
13d8b49b MS |
965 | /** |
966 | * @see WCF.Collapsible.Remote._getContainers() | |
967 | */ | |
968 | _getContainers: function() { | |
969 | return $('.jsCategory').has('ol').has('li'); | |
970 | }, | |
9f959ced | 971 | |
13d8b49b MS |
972 | /** |
973 | * @see WCF.Collapsible.Remote._getTarget() | |
974 | */ | |
975 | _getTarget: function(containerID) { | |
976 | return $('#' + containerID + ' > ol'); | |
977 | }, | |
978 | ||
979 | /** | |
980 | * Handles a click on the sort button. | |
981 | */ | |
982 | _sort: function() { | |
983 | // remove existing collapsible buttons | |
984 | $('.collapsibleButton').remove(); | |
985 | ||
986 | // reinit containers | |
cb6e5946 MS |
987 | this._containers = { }; |
988 | this._containerData = { }; | |
13d8b49b MS |
989 | |
990 | var $containers = this._getContainers(); | |
991 | if ($containers.length == 0) { | |
a0b60d23 | 992 | console.debug('[WCF.ACP.Category.Collapsible] Empty container set given, aborting.'); |
13d8b49b MS |
993 | } |
994 | $containers.each($.proxy(function(index, container) { | |
995 | var $container = $(container); | |
996 | var $containerID = $container.wcfIdentify(); | |
997 | this._containers[$containerID] = $container; | |
998 | ||
999 | this._initContainer($containerID); | |
1000 | }, this)); | |
1001 | } | |
1002 | }); | |
1003 | ||
71662ae8 AE |
1004 | /** |
1005 | * Provides the search dropdown for ACP | |
1006 | * | |
1007 | * @see WCF.Search.Base | |
1008 | */ | |
1009 | WCF.ACP.Search = WCF.Search.Base.extend({ | |
001740db AE |
1010 | _delay: 250, |
1011 | ||
c8f7b2a1 MW |
1012 | /** |
1013 | * name of the selected search provider | |
1014 | * @var string | |
1015 | */ | |
1016 | _providerName: '', | |
1017 | ||
71662ae8 AE |
1018 | /** |
1019 | * @see WCF.Search.Base.init() | |
1020 | */ | |
1021 | init: function() { | |
1022 | this._className = 'wcf\\data\\acp\\search\\provider\\ACPSearchProviderAction'; | |
6476e7a1 | 1023 | this._super('#pageHeaderSearch input[name=q]'); |
d6760827 MS |
1024 | |
1025 | // disable form submitting | |
6476e7a1 | 1026 | $('#pageHeaderSearch > form').on('submit', function(event) { |
d6760827 MS |
1027 | event.preventDefault(); |
1028 | }); | |
c8f7b2a1 MW |
1029 | |
1030 | var $dropdown = WCF.Dropdown.getDropdownMenu('pageHeaderSearchType'); | |
1031 | $dropdown.find('a[data-provider-name]').on('click', $.proxy(function(event) { | |
1032 | event.preventDefault(); | |
1033 | var $button = $(event.target); | |
f776bbc0 | 1034 | $('.pageHeaderSearchType > .button > .pageHeaderSearchTypeLabel').text($button.text()); |
c8f7b2a1 MW |
1035 | |
1036 | var $oldProviderName = this._providerName; | |
1037 | this._providerName = ($button.data('providerName') != 'everywhere' ? $button.data('providerName') : ''); | |
1038 | ||
1039 | if ($oldProviderName != this._providerName) { | |
1040 | var $searchString = $.trim(this._searchInput.val()); | |
1041 | if ($searchString) { | |
1042 | var $parameters = { | |
1043 | data: { | |
1044 | excludedSearchValues: this._excludedSearchValues, | |
1045 | searchString: $searchString | |
1046 | } | |
1047 | }; | |
1048 | this._queryServer($parameters); | |
1049 | } | |
c5dd767e | 1050 | } |
c8f7b2a1 | 1051 | }, this)); |
666e4579 AE |
1052 | |
1053 | const searchInput = document.querySelector("#pageHeaderSearch input[name=q]"); | |
1054 | document.addEventListener("keydown", (event) => { | |
1055 | if (event.key !== "s") { | |
1056 | return; | |
1057 | } | |
1058 | ||
1059 | if (!event.defaultPrevented && document.activeElement === document.body) { | |
1060 | searchInput.focus(); | |
1061 | ||
1062 | event.preventDefault(); | |
1063 | } | |
1064 | }, { | |
1065 | passive: false, | |
1066 | }); | |
1067 | ||
1068 | searchInput.addEventListener("keydown", (event) => { | |
1069 | if (event.key !== "Escape") { | |
1070 | return; | |
1071 | } | |
1072 | ||
1073 | if (!event.defaultPrevented && searchInput.value.trim() === "") { | |
1074 | event.preventDefault(); | |
1075 | ||
1076 | searchInput.blur(); | |
1077 | } | |
1078 | }, { | |
1079 | passive: false, | |
1080 | }); | |
71662ae8 AE |
1081 | }, |
1082 | ||
1083 | /** | |
1084 | * @see WCF.Search.Base._createListItem() | |
1085 | */ | |
1086 | _createListItem: function(resultList) { | |
1087 | // add a divider between result lists | |
1088 | if (this._list.children('li').length > 0) { | |
1089 | $('<li class="dropdownDivider" />').appendTo(this._list); | |
1090 | } | |
1091 | ||
1092 | // add caption | |
1093 | $('<li class="dropdownText">' + resultList.title + '</li>').appendTo(this._list); | |
1094 | ||
1095 | // add menu items | |
1096 | for (var $i in resultList.items) { | |
1097 | var $item = resultList.items[$i]; | |
1098 | ||
790aadd9 | 1099 | $('<li><a href="' + $item.link + '"><span>' + WCF.String.escapeHTML($item.title) + '</span>' + ($item.subtitle ? '<small>' + WCF.String.escapeHTML($item.subtitle) + '</small>' : '') + '</a></li>').appendTo(this._list); |
9a130ab4 AE |
1100 | |
1101 | this._itemCount++; | |
71662ae8 | 1102 | } |
9a130ab4 AE |
1103 | }, |
1104 | ||
71c70823 MS |
1105 | /** |
1106 | * @see WCF.Search.Base._openDropdown() | |
1107 | */ | |
1108 | _openDropdown: function() { | |
1109 | this._list.find('small').each(function(index, element) { | |
1110 | while (element.scrollWidth > element.clientWidth) { | |
1111 | element.innerText = '\u2026 ' + element.innerText.substr(3); | |
1112 | } | |
1113 | }); | |
1114 | }, | |
1115 | ||
c138555b AE |
1116 | /** |
1117 | * @see WCF.Search.Base._handleEmptyResult() | |
1118 | */ | |
1119 | _handleEmptyResult: function() { | |
1120 | $('<li class="dropdownText">' + WCF.Language.get('wcf.acp.search.noResults') + '</li>').appendTo(this._list); | |
1121 | ||
1122 | return true; | |
1123 | }, | |
1124 | ||
9a130ab4 AE |
1125 | /** |
1126 | * @see WCF.Search.Base._highlightSelectedElement() | |
1127 | */ | |
1128 | _highlightSelectedElement: function() { | |
1129 | this._list.find('li').removeClass('dropdownNavigationItem'); | |
1130 | this._list.find('li:not(.dropdownDivider):not(.dropdownText)').eq(this._itemIndex).addClass('dropdownNavigationItem'); | |
1131 | }, | |
1132 | ||
1133 | /** | |
1134 | * @see WCF.Search.Base._selectElement() | |
1135 | */ | |
1136 | _selectElement: function(event) { | |
c138555b AE |
1137 | if (this._itemIndex === -1) { |
1138 | return false; | |
1139 | } | |
1140 | ||
9a130ab4 | 1141 | window.location = this._list.find('li.dropdownNavigationItem > a').attr('href'); |
6476e7a1 AE |
1142 | }, |
1143 | ||
1144 | _success: function(data) { | |
1145 | this._super(data); | |
1146 | ||
7a6f4991 AE |
1147 | const container = document.getElementById("pageHeaderSearch").querySelector(".pageHeaderSearchInputContainer"); |
1148 | const { bottom } = container.getBoundingClientRect(); | |
1149 | this._list[0].style.setProperty("top", `${Math.trunc(bottom)}px`, "important"); | |
1150 | this._list[0].classList.add("acpSearchDropdown"); | |
1151 | this._list[0].dataset.dropdownIgnorePageScroll = "true"; | |
c8f7b2a1 MW |
1152 | }, |
1153 | ||
1154 | /** | |
1155 | * @see WCF.Search.Base._getParameters() | |
1156 | */ | |
1157 | _getParameters: function(parameters) { | |
1158 | parameters.data.providerName = this._providerName; | |
1159 | ||
1160 | return parameters; | |
71662ae8 AE |
1161 | } |
1162 | }); | |
11cf19be MW |
1163 | |
1164 | /** | |
1165 | * Namespace for user management. | |
1166 | */ | |
1167 | WCF.ACP.User = { }; | |
1168 | ||
1169 | /** | |
1170 | * Generic implementation to ban users. | |
1171 | */ | |
1172 | WCF.ACP.User.BanHandler = { | |
1173 | /** | |
1174 | * callback object | |
1175 | * @var object | |
1176 | */ | |
1177 | _callback: null, | |
1178 | ||
1179 | /** | |
1180 | * dialog overlay | |
1181 | * @var jQuery | |
1182 | */ | |
1183 | _dialog: null, | |
1184 | ||
1185 | /** | |
1186 | * action proxy | |
1187 | * @var WCF.Action.Proxy | |
1188 | */ | |
1189 | _proxy: null, | |
1190 | ||
1191 | /** | |
1192 | * Initializes WCF.ACP.User.BanHandler on first use. | |
1193 | */ | |
1194 | init: function() { | |
11cf19be MW |
1195 | this._proxy = new WCF.Action.Proxy({ |
1196 | success: $.proxy(this._success, this) | |
1197 | }); | |
1198 | ||
1199 | $('.jsBanButton').click($.proxy(function(event) { | |
1200 | var $button = $(event.currentTarget); | |
1201 | if ($button.data('banned')) { | |
1202 | this.unban([ $button.data('objectID') ]); | |
1203 | } | |
1204 | else { | |
1205 | this.ban([ $button.data('objectID') ]); | |
1206 | } | |
1207 | }, this)); | |
bbef7ed8 | 1208 | |
efcd047d MS |
1209 | require(['EventHandler'], function(EventHandler) { |
1210 | EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.user', this._clipboardAction.bind(this)); | |
1211 | }.bind(this)); | |
bbef7ed8 MW |
1212 | }, |
1213 | ||
1214 | /** | |
efcd047d MS |
1215 | * Reacts to executed clipboard actions. |
1216 | * | |
1217 | * @param {object<string, *>} actionData data of the executed clipboard action | |
bbef7ed8 | 1218 | */ |
efcd047d MS |
1219 | _clipboardAction: function(actionData) { |
1220 | if (actionData.data.actionName === 'com.woltlab.wcf.user.ban') { | |
1221 | this.ban(actionData.data.parameters.objectIDs); | |
bbef7ed8 | 1222 | } |
11cf19be MW |
1223 | }, |
1224 | ||
1225 | /** | |
1226 | * Unbans users. | |
1227 | * | |
1228 | * @param array<integer> userIDs | |
1229 | */ | |
1230 | unban: function(userIDs) { | |
1231 | this._proxy.setOption('data', { | |
1232 | actionName: 'unban', | |
1233 | className: 'wcf\\data\\user\\UserAction', | |
1234 | objectIDs: userIDs | |
1235 | }); | |
1236 | this._proxy.sendRequest(); | |
1237 | }, | |
1238 | ||
1239 | /** | |
1240 | * Bans users. | |
1241 | * | |
1242 | * @param array<integer> userIDs | |
1243 | */ | |
1244 | ban: function(userIDs) { | |
f034d0ec MS |
1245 | if (this._dialog === null) { |
1246 | // create dialog | |
1247 | this._dialog = $('<div />').hide().appendTo(document.body); | |
6f2bc235 | 1248 | this._dialog.append($('<div class="section"><dl><dt><label for="userBanReason">' + WCF.Language.get('wcf.acp.user.banReason') + '</label></dt><dd><textarea id="userBanReason" cols="40" rows="3" /><small>' + WCF.Language.get('wcf.acp.user.banReason.description') + '</small></dd></dl><dl><dt></dt><dd><label for="userBanNeverExpires"><input type="checkbox" name="userBanNeverExpires" id="userBanNeverExpires" checked> ' + WCF.Language.get('wcf.acp.user.ban.neverExpires') + '</label></dd></dl><dl id="userBanExpiresSettings" style="display: none;"><dt><label for="userBanExpires">' + WCF.Language.get('wcf.acp.user.ban.expires') + '</label></dt><dd><input type="date" name="userBanExpires" id="userBanExpires" class="medium" min="' + new Date(TIME_NOW * 1000).toISOString() + '" data-ignore-timezone="true" /><small>' + WCF.Language.get('wcf.acp.user.ban.expires.description') + '</small></dd></dl></div>')); |
58d5a1b5 | 1249 | this._dialog.append($('<div class="formSubmit"><button type="button" class="button buttonPrimary" accesskey="s">' + WCF.Language.get('wcf.global.button.submit') + '</button></div>')); |
f034d0ec MS |
1250 | |
1251 | this._dialog.find('#userBanNeverExpires').change(function() { | |
1252 | $('#userBanExpiresSettings').toggle(); | |
1253 | }); | |
1254 | ||
1255 | this._dialog.find('button').click($.proxy(this._submit, this)); | |
1256 | } | |
1257 | else { | |
1258 | // reset dialog | |
1259 | $('#userBanReason').val(''); | |
1260 | $('#userBanNeverExpires').prop('checked', true); | |
1261 | $('#userBanExpiresSettings').hide(); | |
1262 | $('#userBanExpiresDatePicker, #userBanExpires').val(''); | |
1263 | } | |
1264 | ||
1265 | this._dialog.data('userIDs', userIDs); | |
1266 | this._dialog.wcfDialog({ | |
1267 | title: WCF.Language.get('wcf.acp.user.ban.sure') | |
1268 | }); | |
1269 | }, | |
1270 | ||
1271 | /** | |
1272 | * Handles submitting the ban dialog. | |
1273 | */ | |
1274 | _submit: function() { | |
1275 | this._dialog.find('.innerError').remove(); | |
1276 | ||
1277 | var $banExpires = ''; | |
1278 | if (!$('#userBanNeverExpires').is(':checked')) { | |
1279 | var $banExpires = $('#userBanExpiresDatePicker').val(); | |
1280 | if (!$banExpires) { | |
1281 | this._dialog.find('#userBanExpiresSettings > dd > small').prepend($('<small class="innerError" />').text(WCF.Language.get('wcf.global.form.error.empty'))); | |
1282 | return | |
1283 | } | |
1284 | } | |
1285 | ||
1286 | this._proxy.setOption('data', { | |
1287 | actionName: 'ban', | |
1288 | className: 'wcf\\data\\user\\UserAction', | |
1289 | objectIDs: this._dialog.data('userIDs'), | |
1290 | parameters: { | |
1291 | banReason: $('#userBanReason').val(), | |
1292 | banExpires: $banExpires | |
11cf19be | 1293 | } |
f034d0ec MS |
1294 | }); |
1295 | this._proxy.sendRequest(); | |
11cf19be MW |
1296 | }, |
1297 | ||
1298 | /** | |
1299 | * Handles successful AJAX calls. | |
1300 | * | |
1301 | * @param object data | |
1302 | * @param string textStatus | |
1303 | * @param jQuery jqXHR | |
1304 | */ | |
1305 | _success: function(data, textStatus, jqXHR) { | |
47619e6c AE |
1306 | elBySelAll('.jsUserRow', undefined, function(userRow) { |
1307 | var userId = parseInt(elData(userRow, 'object-id'), 10); | |
1308 | if (data.objectIDs.indexOf(userId) !== -1) { | |
1309 | elData(userRow, 'banned', data.actionName === 'ban'); | |
1310 | } | |
1311 | }); | |
1312 | ||
11cf19be MW |
1313 | $('.jsBanButton').each(function(index, button) { |
1314 | var $button = $(button); | |
1315 | if (WCF.inArray($button.data('objectID'), data.objectIDs)) { | |
1316 | if (data.actionName == 'unban') { | |
0caf2e88 AE |
1317 | $button.data('banned', false).attr('data-tooltip', $button.data('banMessage')); |
1318 | $button[0].querySelector("fa-icon").setIcon("unlock"); | |
11cf19be MW |
1319 | } |
1320 | else { | |
0caf2e88 AE |
1321 | $button.data('banned', true).attr('data-tooltip', $button.data('unbanMessage')); |
1322 | $button[0].querySelector("fa-icon").setIcon("lock"); | |
11cf19be MW |
1323 | } |
1324 | } | |
1325 | }); | |
1326 | ||
1327 | var $notification = new WCF.System.Notification(); | |
1328 | $notification.show(); | |
bbef7ed8 MW |
1329 | |
1330 | WCF.Clipboard.reload(); | |
f034d0ec MS |
1331 | |
1332 | if (data.actionName == 'ban') { | |
1333 | this._dialog.wcfDialog('close'); | |
1334 | } | |
47619e6c AE |
1335 | |
1336 | WCF.System.Event.fireEvent('com.woltlab.wcf.acp.user', 'refresh', {userIds: data.objectIDs}); | |
11cf19be | 1337 | } |
bc3b71fd | 1338 | }; |
ef012ee1 | 1339 | |
2a5d6b57 MS |
1340 | /** |
1341 | * Namespace for user group management. | |
1342 | */ | |
1343 | WCF.ACP.User.Group = { }; | |
1344 | ||
1345 | /** | |
1346 | * Handles copying user groups. | |
1347 | */ | |
1348 | WCF.ACP.User.Group.Copy = Class.extend({ | |
1349 | /** | |
1350 | * id of the copied group | |
1351 | * @var integer | |
1352 | */ | |
1353 | _groupID: 0, | |
1354 | ||
1355 | /** | |
1356 | * Initializes a new instance of WCF.ACP.User.Group.Copy. | |
1357 | * | |
1358 | * @param integer groupID | |
1359 | */ | |
1360 | init: function(groupID) { | |
1361 | this._groupID = groupID; | |
1362 | ||
1363 | $('.jsButtonUserGroupCopy').click($.proxy(this._click, this)); | |
1364 | }, | |
1365 | ||
1366 | /** | |
1367 | * Handles clicking on a 'copy user group' button. | |
1368 | */ | |
1369 | _click: function() { | |
7730f067 | 1370 | var $template = $('<div class="section" />'); |
95961bdf MW |
1371 | $template.append($('<dl class="wide"><dt /><dd><label><input type="checkbox" id="copyMembers" value="1" /> ' + WCF.Language.get('wcf.acp.group.copy.copyMembers') + '</label><small>' + WCF.Language.get('wcf.acp.group.copy.copyMembers.description') + '</small></dd></dl>')); |
1372 | $template.append($('<dl class="wide"><dt /><dd><label><input type="checkbox" id="copyUserGroupOptions" value="1" /> ' + WCF.Language.get('wcf.acp.group.copy.copyUserGroupOptions') + '</label><small>' + WCF.Language.get('wcf.acp.group.copy.copyUserGroupOptions.description') + '</small></dd></dl>')); | |
1373 | $template.append($('<dl class="wide"><dt /><dd><label><input type="checkbox" id="copyACLOptions" value="1" /> ' + WCF.Language.get('wcf.acp.group.copy.copyACLOptions') + '</label><small>' + WCF.Language.get('wcf.acp.group.copy.copyACLOptions.description') + '</small></dd></dl>')); | |
2a5d6b57 MS |
1374 | |
1375 | WCF.System.Confirmation.show(WCF.Language.get('wcf.acp.group.copy.confirmMessage'), $.proxy(function(action) { | |
1376 | if (action === 'confirm') { | |
1377 | new WCF.Action.Proxy({ | |
1378 | autoSend: true, | |
1379 | data: { | |
1380 | actionName: 'copy', | |
1381 | className: 'wcf\\data\\user\\group\\UserGroupAction', | |
1382 | objectIDs: [ this._groupID ], | |
1383 | parameters: { | |
1384 | copyACLOptions: $('#copyACLOptions').is(':checked'), | |
1385 | copyMembers: $('#copyMembers').is(':checked'), | |
1386 | copyUserGroupOptions: $('#copyUserGroupOptions').is(':checked') | |
1387 | } | |
1388 | }, | |
1389 | success: function(data) { | |
1390 | window.location = data.returnValues.redirectURL; | |
1391 | } | |
1392 | }); | |
1393 | } | |
23e43ac5 | 1394 | }, this), '', $template, true); |
2a5d6b57 MS |
1395 | } |
1396 | }); | |
1397 | ||
ef012ee1 MW |
1398 | /** |
1399 | * Generic implementation to enable users. | |
1400 | */ | |
1401 | WCF.ACP.User.EnableHandler = { | |
1402 | /** | |
1403 | * action proxy | |
1404 | * @var WCF.Action.Proxy | |
1405 | */ | |
1406 | _proxy: null, | |
1407 | ||
1408 | /** | |
1409 | * Initializes WCF.ACP.User.EnableHandler on first use. | |
1410 | */ | |
1411 | init: function() { | |
1412 | this._proxy = new WCF.Action.Proxy({ | |
1413 | success: $.proxy(this._success, this) | |
1414 | }); | |
1415 | ||
1416 | $('.jsEnableButton').click($.proxy(function(event) { | |
1417 | var $button = $(event.currentTarget); | |
1418 | if ($button.data('enabled')) { | |
1419 | this.disable([ $button.data('objectID') ]); | |
1420 | } | |
1421 | else { | |
1422 | this.enable([ $button.data('objectID') ]); | |
1423 | } | |
1424 | }, this)); | |
1425 | ||
efcd047d MS |
1426 | require(['EventHandler'], function(EventHandler) { |
1427 | EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.user', this._clipboardAction.bind(this)); | |
1428 | }.bind(this)); | |
ef012ee1 MW |
1429 | }, |
1430 | ||
1431 | /** | |
efcd047d MS |
1432 | * Reacts to executed clipboard actions. |
1433 | * | |
1434 | * @param {object<string, *>} actionData data of the executed clipboard action | |
ef012ee1 | 1435 | */ |
efcd047d MS |
1436 | _clipboardAction: function(actionData) { |
1437 | if (actionData.data.actionName === 'com.woltlab.wcf.user.enable') { | |
1438 | this.enable(actionData.data.parameters.objectIDs); | |
ef012ee1 MW |
1439 | } |
1440 | }, | |
1441 | ||
1442 | /** | |
1443 | * Disables users. | |
1444 | * | |
1445 | * @param array<integer> userIDs | |
1446 | */ | |
1447 | disable: function(userIDs) { | |
1448 | this._proxy.setOption('data', { | |
1449 | actionName: 'disable', | |
1450 | className: 'wcf\\data\\user\\UserAction', | |
1451 | objectIDs: userIDs | |
1452 | }); | |
1453 | this._proxy.sendRequest(); | |
1454 | }, | |
1455 | ||
1456 | /** | |
1457 | * Enables users. | |
1458 | * | |
1459 | * @param array<integer> userIDs | |
1460 | */ | |
1461 | enable: function(userIDs) { | |
1462 | this._proxy.setOption('data', { | |
1463 | actionName: 'enable', | |
1464 | className: 'wcf\\data\\user\\UserAction', | |
1465 | objectIDs: userIDs | |
1466 | }); | |
1467 | this._proxy.sendRequest(); | |
1468 | }, | |
1469 | ||
1470 | /** | |
1471 | * Handles successful AJAX calls. | |
1472 | * | |
1473 | * @param object data | |
1474 | * @param string textStatus | |
1475 | * @param jQuery jqXHR | |
1476 | */ | |
1477 | _success: function(data, textStatus, jqXHR) { | |
47619e6c AE |
1478 | elBySelAll('.jsUserRow', undefined, function(userRow) { |
1479 | var userId = parseInt(elData(userRow, 'object-id'), 10); | |
1480 | if (data.objectIDs.indexOf(userId) !== -1) { | |
1481 | elData(userRow, 'enabled', data.actionName === 'enable'); | |
1482 | } | |
1483 | }); | |
1484 | ||
ef012ee1 MW |
1485 | $('.jsEnableButton').each(function(index, button) { |
1486 | var $button = $(button); | |
1487 | if (WCF.inArray($button.data('objectID'), data.objectIDs)) { | |
1488 | if (data.actionName == 'disable') { | |
0caf2e88 AE |
1489 | $button.data('enabled', false).attr('data-tooltip', $button.data('enableMessage')); |
1490 | $button[0].querySelector("fa-icon").setIcon("square"); | |
ef012ee1 MW |
1491 | } |
1492 | else { | |
0caf2e88 AE |
1493 | $button.data('enabled', true).attr('data-tooltip', $button.data('disableMessage')); |
1494 | $button[0].querySelector("fa-icon").setIcon("square-check"); | |
ef012ee1 MW |
1495 | } |
1496 | } | |
1497 | }); | |
1498 | ||
1499 | var $notification = new WCF.System.Notification(); | |
00ce5cf8 | 1500 | $notification.show(function() { window.location.reload(); }); |
47619e6c AE |
1501 | |
1502 | WCF.System.Event.fireEvent('com.woltlab.wcf.acp.user', 'refresh', {userIds: data.objectIDs}); | |
ef012ee1 MW |
1503 | } |
1504 | }; | |
1505 | ||
cb6e5946 MS |
1506 | /** |
1507 | * Handles the send new password clipboard action. | |
1508 | */ | |
1509 | WCF.ACP.User.SendNewPasswordHandler = { | |
cb6e5946 MS |
1510 | /** |
1511 | * Initializes WCF.ACP.User.SendNewPasswordHandler on first use. | |
1512 | */ | |
1513 | init: function() { | |
efcd047d MS |
1514 | require(['EventHandler'], function(EventHandler) { |
1515 | EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.user', this._clipboardAction.bind(this)); | |
1516 | }.bind(this)); | |
cb6e5946 MS |
1517 | }, |
1518 | ||
1519 | /** | |
efcd047d MS |
1520 | * Reacts to executed clipboard actions. |
1521 | * | |
1522 | * @param {object<string, *>} actionData data of the executed clipboard action | |
cb6e5946 | 1523 | */ |
efcd047d MS |
1524 | _clipboardAction: function(actionData) { |
1525 | if (actionData.data.actionName === 'com.woltlab.wcf.user.sendNewPassword') { | |
5a1e558d MS |
1526 | require(['Language', 'Ui/Confirmation', 'WoltLabSuite/Core/Acp/Ui/Worker'], function(Language, UiConfirmation, AcpUiWorker) { |
1527 | UiConfirmation.show({ | |
1528 | confirm: () => { | |
1529 | new AcpUiWorker({ | |
1530 | dialogId: 'sendingNewPasswords', | |
1531 | dialogTitle: Language.get('wcf.acp.user.sendNewPassword.workerTitle'), | |
1532 | className: 'wcf\\system\\worker\\SendNewPasswordWorker', | |
1533 | parameters: { | |
1534 | userIDs: actionData.data.parameters.objectIDs | |
1535 | }, | |
1536 | }); | |
1537 | }, | |
1538 | message: actionData.data.parameters.confirmMessage, | |
1539 | }) | |
cb6e5946 MS |
1540 | }); |
1541 | } | |
1542 | } | |
1543 | }; | |
1544 | ||
e1fe9453 MW |
1545 | /** |
1546 | * Namespace for stat-related classes. | |
1547 | */ | |
1548 | WCF.ACP.Stat = { }; | |
1549 | ||
1550 | /** | |
1551 | * Shows the daily stat chart. | |
1552 | */ | |
1553 | WCF.ACP.Stat.Chart = Class.extend({ | |
1554 | init: function() { | |
1555 | this._proxy = new WCF.Action.Proxy({ | |
1556 | success: $.proxy(this._success, this) | |
1557 | }); | |
1558 | ||
49ec07c5 | 1559 | $('#statRefreshButton').click($.proxy(this._refresh, this)); |
e1fe9453 | 1560 | |
49ec07c5 | 1561 | this._refresh(); |
e1fe9453 MW |
1562 | }, |
1563 | ||
49ec07c5 | 1564 | _refresh: function() { |
e1fe9453 MW |
1565 | var $objectTypeIDs = [ ]; |
1566 | $('input[name=objectTypeID]:checked').each(function() { | |
1567 | $objectTypeIDs.push($(this).val()); | |
1568 | }); | |
1569 | ||
49ec07c5 MW |
1570 | if (!$objectTypeIDs.length) return; |
1571 | ||
e1fe9453 MW |
1572 | this._proxy.setOption('data', { |
1573 | className: 'wcf\\data\\stat\\daily\\StatDailyAction', | |
1574 | actionName: 'getData', | |
1575 | parameters: { | |
1576 | startDate: $('#startDateDatePicker').val(), | |
1577 | endDate: $('#endDateDatePicker').val(), | |
1578 | value: $('input[name=value]:checked').val(), | |
49ec07c5 | 1579 | dateGrouping: $('input[name=dateGrouping]:checked').val(), |
e1fe9453 MW |
1580 | objectTypeIDs: $objectTypeIDs |
1581 | } | |
1582 | }); | |
1583 | this._proxy.sendRequest(); | |
1584 | }, | |
1585 | ||
1586 | _success: function(data) { | |
49ec07c5 MW |
1587 | switch ($('input[name=dateGrouping]:checked').val()) { |
1588 | case 'yearly': | |
1589 | var $minTickSize = [1, "year"]; | |
1590 | var $timeFormat = WCF.Language.get('wcf.acp.stat.timeFormat.yearly'); | |
1591 | break; | |
1592 | case 'monthly': | |
1593 | var $minTickSize = [1, "month"]; | |
1594 | var $timeFormat = WCF.Language.get('wcf.acp.stat.timeFormat.monthly'); | |
1595 | break; | |
1596 | case 'weekly': | |
1597 | var $minTickSize = [7, "day"]; | |
1598 | var $timeFormat = WCF.Language.get('wcf.acp.stat.timeFormat.weekly'); | |
1599 | break; | |
1600 | default: | |
1601 | var $minTickSize = [1, "day"]; | |
1602 | var $timeFormat = WCF.Language.get('wcf.acp.stat.timeFormat.daily'); | |
1603 | } | |
1604 | ||
e1fe9453 MW |
1605 | var options = { |
1606 | series: { | |
1607 | lines: { | |
1608 | show: true | |
1609 | }, | |
1610 | points: { | |
1611 | show: true | |
1612 | } | |
1613 | }, | |
1614 | grid: { | |
1615 | hoverable: true | |
1616 | }, | |
1617 | xaxis: { | |
1618 | mode: "time", | |
49ec07c5 MW |
1619 | minTickSize: $minTickSize, |
1620 | timeformat: $timeFormat, | |
1621 | monthNames: WCF.Language.get('__monthsShort') | |
e1fe9453 MW |
1622 | }, |
1623 | yaxis: { | |
1624 | min: 0, | |
1625 | tickDecimals: 0, | |
1626 | tickFormatter: function(val) { | |
1627 | return WCF.String.addThousandsSeparator(val); | |
1628 | } | |
a16e5980 | 1629 | } |
e1fe9453 MW |
1630 | }; |
1631 | ||
1632 | var $data = [ ]; | |
1633 | for (var $key in data.returnValues) { | |
1634 | var $row = data.returnValues[$key]; | |
1635 | for (var $i = 0; $i < $row.data.length; $i++) { | |
1636 | $row.data[$i][0] *= 1000; | |
1637 | } | |
1638 | ||
1639 | $data.push($row); | |
1640 | } | |
1641 | ||
1642 | $.plot("#chart", $data, options); | |
1643 | ||
a16e5980 MW |
1644 | require(['Ui/Alignment'], function (UiAlignment) { |
1645 | var span = elCreate('span'); | |
1646 | span.style.setProperty('position', 'absolute', ''); | |
1647 | document.body.appendChild(span); | |
1648 | $("#chart").on("plothover", function(event, pos, item) { | |
1649 | if (item) { | |
1650 | span.style.setProperty('top', item.pageY + 'px', ''); | |
1651 | span.style.setProperty('left', item.pageX + 'px', ''); | |
1652 | $("#chartTooltip").html(item.series.xaxis.tickFormatter(item.datapoint[0], item.series.xaxis) + ', ' + WCF.String.formatNumeric(item.datapoint[1]) + ' ' + item.series.label).show(); | |
1653 | UiAlignment.set($("#chartTooltip")[0], span, { | |
1654 | verticalOffset: 5, | |
b984a2b2 F |
1655 | horizontal: 'center', |
1656 | vertical: 'top' | |
a16e5980 MW |
1657 | }); |
1658 | } | |
1659 | else { | |
1660 | $("#chartTooltip").hide(); | |
1661 | } | |
1662 | }); | |
e1fe9453 | 1663 | }); |
7652dbb0 MW |
1664 | |
1665 | if (!$data.length) { | |
1666 | $('#chart').append('<p style="position: absolute; font-size: 1.2rem; text-align: center; top: 50%; margin-top: -20px; width: 100%">' + WCF.Language.get('wcf.acp.stat.noData') + '</p>'); | |
1667 | } | |
a59f3c51 MW |
1668 | |
1669 | elBySel('.contentHeader > .contentTitle').scrollIntoView({ behavior: 'smooth' }); | |
e1fe9453 | 1670 | } |
e72efaf9 | 1671 | }); |
e866b80e MS |
1672 | |
1673 | /** | |
1674 | * Namespace for ACP ad management. | |
1675 | */ | |
1676 | WCF.ACP.Ad = { }; | |
1677 | ||
1678 | /** | |
1679 | * Handles the location of an ad during ad creation/editing. | |
1680 | */ | |
1681 | WCF.ACP.Ad.LocationHandler = Class.extend({ | |
1682 | /** | |
1683 | * fieldset of the page conditions | |
1684 | * @var jQuery | |
1685 | */ | |
1686 | _pageConditions: null, | |
1687 | ||
1688 | /** | |
098aa5ee | 1689 | * select elements for the page controller condition |
0360f61b | 1690 | * @var jQuery[] |
e866b80e | 1691 | */ |
0360f61b | 1692 | _pageInputs: [], |
e866b80e | 1693 | |
098aa5ee MS |
1694 | /** |
1695 | * page controller condition container | |
1696 | * @var jQuery[] | |
1697 | */ | |
1698 | _pageSelectionContainer: null, | |
1699 | ||
e866b80e MS |
1700 | /** |
1701 | * Initializes a new WCF.ACP.Ad.LocationHandler object. | |
1949f2e3 MS |
1702 | * |
1703 | * @param {object} variablesDescriptions | |
e866b80e | 1704 | */ |
1949f2e3 MS |
1705 | init: function(variablesDescriptions) { |
1706 | this._variablesDescriptions = variablesDescriptions; | |
1707 | ||
e866b80e | 1708 | this._pageConditions = $('#pageConditions'); |
0360f61b | 1709 | this._pageInputs = $('input[name="pageIDs[]"]'); |
e866b80e | 1710 | |
1949f2e3 MS |
1711 | this._variablesDescriptionsList = $('#ad').next('small').children('ul'); |
1712 | ||
098aa5ee | 1713 | this._pageSelectionContainer = $(this._pageInputs[0]).parents('dl:eq(0)'); |
fff8c61a | 1714 | |
1c2e3dd9 | 1715 | // hide the page controller elements |
098aa5ee MS |
1716 | this._hidePageSelection(true); |
1717 | ||
1718 | $('#objectTypeID').on('change', $.proxy(this._setPageController, this)); | |
1719 | ||
1720 | this._setPageController(); | |
1721 | ||
1722 | $('#adForm').submit($.proxy(this._submit, this)); | |
1723 | }, | |
1724 | ||
1725 | /** | |
1726 | * Hides the page selection form field. | |
1727 | * | |
1728 | * @since 5.2 | |
1729 | */ | |
1730 | _hidePageSelection: function(addEventListeners) { | |
1731 | this._pageSelectionContainer.prev('dl').hide(); | |
1732 | this._pageSelectionContainer.hide(); | |
1733 | ||
1734 | // fix the margin of a potentially next page condition element | |
1735 | this._pageSelectionContainer.next('dl').css('margin-top', 0); | |
fff8c61a | 1736 | |
098aa5ee | 1737 | var section = this._pageSelectionContainer.parent('section'); |
0360f61b MS |
1738 | if (!section.children('dl:visible').length) { |
1739 | section.hide(); | |
098aa5ee MS |
1740 | |
1741 | var nextSection = section.next('section'); | |
1742 | if (nextSection) { | |
1743 | nextSection.css('margin-top', 0); | |
1744 | ||
1745 | if (addEventListeners) { | |
1746 | require(['EventHandler'], function(EventHandler) { | |
1747 | EventHandler.add('com.woltlab.wcf.pageConditionDependence', 'checkVisivility', function() { | |
1748 | if (section.is(':visible')) { | |
1749 | nextSection.css('margin-top', '40px'); | |
1750 | } | |
1751 | else { | |
1752 | nextSection.css('margin-top', 0); | |
1753 | } | |
1754 | }); | |
1755 | }); | |
1756 | } | |
1757 | } | |
fff8c61a | 1758 | } |
098aa5ee MS |
1759 | }, |
1760 | ||
1761 | /** | |
1762 | * Shows the page selection form field. | |
1763 | * | |
1764 | * @since 5.2 | |
1765 | */ | |
1766 | _showPageSelection: function() { | |
1767 | this._pageSelectionContainer.prev('dl').show(); | |
1768 | this._pageSelectionContainer.show(); | |
1769 | this._pageSelectionContainer.next('dl').css('margin-top', '40px'); | |
1770 | ||
1771 | var section = this._pageSelectionContainer.parent('section'); | |
1772 | section.show(); | |
fff8c61a | 1773 | |
0360f61b MS |
1774 | var nextSection = section.next('section'); |
1775 | if (nextSection) { | |
098aa5ee | 1776 | nextSection.css('margin-top', '40px'); |
fff8c61a | 1777 | } |
e866b80e MS |
1778 | }, |
1779 | ||
1780 | /** | |
1781 | * Sets the page controller based on the selected ad location. | |
1782 | */ | |
1783 | _setPageController: function() { | |
0360f61b | 1784 | var option = $('#objectTypeID').find('option:checked'); |
098aa5ee | 1785 | var parent = option.parent(); |
e866b80e | 1786 | |
098aa5ee MS |
1787 | // the page controller can be explicitly set for global positions |
1788 | if (parent.is('optgroup') && parent.data('categoryName') === 'com.woltlab.wcf.global') { | |
1789 | this._showPageSelection(); | |
1790 | } | |
1791 | else { | |
1792 | this._hidePageSelection(); | |
0360f61b | 1793 | |
098aa5ee MS |
1794 | require(['Core'], function(Core) { |
1795 | var input, triggerEvent; | |
0360f61b | 1796 | |
098aa5ee MS |
1797 | // select the related page |
1798 | for (var i = 0, length = this._pageInputs.length; i < length; i++) { | |
1799 | input = this._pageInputs[i]; | |
1800 | triggerEvent = false; | |
0360f61b | 1801 | |
098aa5ee MS |
1802 | if (option.data('page') && elData(input, 'identifier') === option.data('page')) { |
1803 | if (!input.checked) triggerEvent = true; | |
1804 | ||
1805 | input.checked = true; | |
1806 | } | |
1807 | else { | |
1808 | if (input.checked) triggerEvent = true; | |
1809 | ||
1810 | input.checked = false; | |
1811 | } | |
0360f61b | 1812 | |
098aa5ee | 1813 | if (triggerEvent) Core.triggerEvent(this._pageInputs[i], 'change'); |
0360f61b | 1814 | } |
098aa5ee MS |
1815 | }.bind(this)); |
1816 | } | |
1949f2e3 MS |
1817 | |
1818 | this._variablesDescriptionsList.children(':not(.jsDefaultItem)').remove(); | |
1819 | ||
1820 | var objectTypeId = $('#objectTypeID').val(); | |
1821 | if (objectTypeId in this._variablesDescriptions) { | |
1822 | this._variablesDescriptionsList[0].innerHTML += this._variablesDescriptions[objectTypeId]; | |
1823 | } | |
e866b80e MS |
1824 | }, |
1825 | ||
1826 | /** | |
1827 | * Handles submitting the ad form. | |
1828 | */ | |
1829 | _submit: function() { | |
1830 | if (this._pageConditions.is(':hidden')) { | |
1831 | // remove hidden page condition form elements to avoid creation | |
1832 | // of these conditions | |
1833 | this._pageConditions.find('select, input').remove(); | |
1834 | } | |
098aa5ee | 1835 | else if (this._pageSelectionContainer.is(':hidden')) { |
e866b80e MS |
1836 | // reset page controller conditions to avoid creation of |
1837 | // unnecessary conditions | |
0360f61b MS |
1838 | for (var i = 0, length = this._pageInputs.length; i < length; i++) { |
1839 | this._pageInputs[i].checked = false; | |
1840 | } | |
e866b80e MS |
1841 | } |
1842 | } | |
1843 | }); | |
ea3185a0 MS |
1844 | |
1845 | /** | |
1846 | * Initialize WCF.ACP.Tag namespace. | |
1847 | */ | |
1848 | WCF.ACP.Tag = { }; | |
1849 | ||
1850 | /** | |
1851 | * Handles setting tags as synonyms of another tag by clipboard. | |
1852 | */ | |
1853 | WCF.ACP.Tag.SetAsSynonymsHandler = Class.extend({ | |
1854 | /** | |
1855 | * dialog to select the "main" tag | |
1856 | * @var jQuery | |
1857 | */ | |
1858 | _dialog: null, | |
1859 | ||
1860 | /** | |
1861 | * ids of the selected tags | |
1862 | * @var array<integer> | |
1863 | */ | |
1864 | _objectIDs: [ ], | |
1865 | ||
1866 | /** | |
1867 | * Initializes the SetAsSynonymsHandler object. | |
ea3185a0 MS |
1868 | */ |
1869 | init: function() { | |
f8d9e485 MS |
1870 | require(['EventHandler'], function(EventHandler) { |
1871 | EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.tag', this._clipboardAction.bind(this)); | |
1872 | }.bind(this)); | |
ea3185a0 MS |
1873 | }, |
1874 | ||
1875 | /** | |
f8d9e485 MS |
1876 | * Reacts to executed clipboard actions. |
1877 | * | |
1878 | * @param {object<string, *>} actionData data of the executed clipboard action | |
ea3185a0 | 1879 | */ |
f8d9e485 MS |
1880 | _clipboardAction: function(actionData) { |
1881 | if (actionData.data.actionName === 'com.woltlab.wcf.tag.setAsSynonyms') { | |
1882 | this._objectIDs = actionData.data.parameters.objectIDs; | |
1883 | if (this._dialog === null) { | |
1884 | this._dialog = $('<div id="setAsSynonymsDialog" />').hide().appendTo(document.body); | |
1885 | this._dialog.wcfDialog({ | |
1886 | closable: false, | |
1887 | title: WCF.Language.get('wcf.acp.tag.setAsSynonyms') | |
1888 | }); | |
1889 | } | |
1890 | ||
1891 | this._dialog.html(actionData.data.parameters.template); | |
1892 | $button = this._dialog.find('button[data-type="submit"]').disable().click($.proxy(this._submit, this)); | |
1893 | this._dialog.find('input[type=radio]').change(function() { $button.enable(); }); | |
ea3185a0 | 1894 | } |
ea3185a0 MS |
1895 | }, |
1896 | ||
1897 | /** | |
1898 | * Saves the tags as synonyms. | |
1899 | */ | |
1900 | _submit: function() { | |
1901 | new WCF.Action.Proxy({ | |
1902 | autoSend: true, | |
1903 | data: { | |
1904 | actionName: 'setAsSynonyms', | |
1905 | className: 'wcf\\data\\tag\\TagAction', | |
1906 | objectIDs: this._objectIDs, | |
1907 | parameters: { | |
1908 | tagID: this._dialog.find('input[name="tagID"]:checked').val() | |
1909 | } | |
1910 | }, | |
1911 | success: $.proxy(function() { | |
1912 | this._dialog.wcfDialog('close'); | |
1913 | ||
1914 | new WCF.System.Notification().show(function() { | |
1915 | window.location.reload(); | |
1916 | }); | |
1917 | }, this) | |
1918 | }); | |
1919 | } | |
1920 | }); |