1f514d6b7d934f8f072e30c0c56cc00a44560a65
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Resources / Public / JavaScript / Install.js
1 /*
2 * This file is part of the TYPO3 CMS project.
3 *
4 * It is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License, either version 2
6 * of the License, or any later version.
7 *
8 * For the full copyright and license information, please read the
9 * LICENSE.txt file that was distributed with this source code.
10 *
11 * The TYPO3 project - inspiring people to share!
12 */
13
14 /**
15 * Various JavaScript functions for the Install Tool
16 */
17
18 /**
19 * Handle core update
20 */
21 var TYPO3 = {};
22 TYPO3.Install = {};
23
24 TYPO3.Install.Cache = {
25 /**
26 * Ajax call to clear all caches.
27 */
28 clearCache: function() {
29 $.ajax({
30 url: location.href + '&install[controller]=ajax&install[action]=clearCache',
31 cache: false
32 });
33 }
34 };
35
36 TYPO3.Install.Scrolling = {
37 isScrolledIntoView: function(elem) {
38 var $window = $(window);
39 var docViewTop = $window.scrollTop();
40 var docViewBottom = docViewTop + $window.height();
41 var $elem = $(elem);
42 var elemTop = $elem.offset().top;
43 var elemBottom = elemTop + $elem.height();
44
45 return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
46 },
47 handleButtonScrolling: function() {
48 var $fixedFooterHandler = $('#fixed-footer-handler');
49 if ($fixedFooterHandler.length > 0) {
50 var $fixedFooter = $('#fixed-footer');
51 if (!this.isScrolledIntoView($fixedFooterHandler)) {
52 $fixedFooter.addClass('fixed');
53 $fixedFooter.width($('.content-area').width());
54 } else {
55 $fixedFooter.removeClass('fixed');
56 }
57 }
58 }
59 };
60
61 TYPO3.Install.ExtensionChecker = {
62 /**
63 * Call checkExtensionsCompatibility recursively on error
64 * so we can find all incompatible extensions
65 */
66 handleCheckExtensionsError: function() {
67 this.checkExtensionsCompatibility(false);
68 },
69 /**
70 * Send an ajax request to uninstall an extension (or multiple extensions)
71 *
72 * @param extension string of extension(s) - may be comma separated
73 */
74 uninstallExtension: function(extension) {
75 var self = this;
76 var url = location.href + '&install[controller]=ajax&install[action]=uninstallExtension' +
77 '&install[uninstallExtension][extensions]=' + extension;
78 $.ajax({
79 url: url,
80 cache: false,
81 success: function(data) {
82 if (data === 'OK') {
83 self.checkExtensionsCompatibility(true);
84 } else {
85 if (data === 'unauthorized') {
86 location.reload();
87 }
88 // workaround for xdebug returning 200 OK on fatal errors
89 if (data.substring(data.length - 2) === 'OK') {
90 self.checkExtensionsCompatibility(true);
91 } else {
92 $('.alert-loading', '#checkExtensions').hide();
93 $('.alert-error .messageText', '#checkExtensions').html(
94 'Something went wrong. Check failed.' + '<p>Message:<br />' + data + '</p>'
95 );
96 }
97 }
98 },
99 error: function(data) {
100 self.handleCheckExtensionsError();
101 }
102 });
103 },
104 /**
105 * Handles result of extension compatibility check.
106 * Displays uninstall buttons for non-compatible extensions.
107 */
108 handleCheckExtensionsSuccess: function() {
109 var self = this;
110 var $checkExtensions = $('#checkExtensions');
111
112 $.ajax({
113 url: $checkExtensions.data('protocolurl'),
114 cache: false,
115 success: function(data) {
116 if (data) {
117 $('.alert-danger .messageText', '#checkExtensions').html(
118 'The following extensions are not compatible. Please uninstall them and try again. '
119 );
120 var extensions = data.split(',');
121 var unloadButtonWrapper = $('<fieldset class="t3-install-form-submit"></fieldset>');
122 for (var i = 0; i < extensions.length; i++) {
123 var extension = extensions[i];
124 var unloadButton = $('<button />', {
125 text: 'Uninstall ' + $.trim(extension),
126 'class': 't3-js-uninstallSingle',
127 'data-extension': $.trim(extension)
128 });
129 var fullButton = unloadButtonWrapper.append(unloadButton);
130 $('.alert-danger .messageText', '#checkExtensions').append(fullButton);
131 }
132 if (extensions.length) {
133 $(document).on('click', 't3-js-uninstallSingle', function(e) {
134 self.uninstallExtension($(this).data('extension'));
135 e.preventDefault();
136 return false;
137 });
138 }
139 var unloadAllButton = $('<button />', {
140 text: 'Uninstall all incompatible extensions: ' + data,
141 click: function(e) {
142 $('.alert-loading', '#checkExtensions').show();
143 self.uninstallExtension(data);
144 e.preventDefault();
145 return false;
146 }
147 });
148 unloadButtonWrapper.append('<hr />');
149 var fullUnloadAllButton = unloadButtonWrapper.append(unloadAllButton);
150 $('.alert-danger .messageText', '#checkExtensions').append(fullUnloadAllButton);
151
152 $('.alert-loading', '#checkExtensions').hide();
153 $('button', '#checkExtensions').show();
154 $('.alert-danger', '#checkExtensions').show();
155 } else {
156 $('.t3js-message', '#checkExtensions').hide();
157 $('.alert-success', '#checkExtensions').show();
158 }
159 },
160 error: function() {
161 $('.t3js-message', '#checkExtensions').hide();
162 $('.alert-success', '#checkExtensions').show();
163 }
164 });
165 $.getJSON(
166 $checkExtensions.data('errorprotocolurl'),
167 function(data) {
168 $.each(data, function(i, error) {
169 var messageToDisplay = error.message + ' in ' + error.file + ' on line ' + error.line;
170 $checkExtensions.find('.t3js-message.alert-danger').before($(
171 '<div class="t3js-message alert-warning">' +
172 '<h4>' + error.type + '</h4><p class="messageText">' +
173 messageToDisplay + '</p></div><p></p>'
174 ));
175 });
176 }
177 );
178 },
179 /**
180 * Checks extension compatibility by trying to load ext_tables and ext_localconf via ajax.
181 *
182 * @param force
183 */
184 checkExtensionsCompatibility: function(force) {
185 var self = this;
186 var url = location.href + '&install[controller]=ajax&install[action]=extensionCompatibilityTester';
187 if (force) {
188 TYPO3.Install.Cache.clearCache();
189 url += '&install[extensionCompatibilityTester][forceCheck]=1';
190 } else {
191 url += '&install[extensionCompatibilityTester][forceCheck]=0';
192 }
193 $.ajax({
194 url: url,
195 cache: false,
196 success: function(data) {
197 if (data === 'OK') {
198 self.handleCheckExtensionsSuccess();
199 } else {
200 if (data === 'unauthorized') {
201 location.reload();
202 }
203 // workaround for xdebug returning 200 OK on fatal errors
204 if (data.substring(data.length - 2) === 'OK') {
205 self.handleCheckExtensionsSuccess();
206 } else {
207 self.handleCheckExtensionsError();
208 }
209 }
210 },
211 error: function() {
212 self.handleCheckExtensionsError();
213 }
214 });
215 }
216 };
217
218 TYPO3.Install.TcaIntegrityChecker = {
219
220 /**
221 * Default output messages
222 */
223 outputMessages: {
224 tcaMigrationsCheck: {
225 fatalTitle: 'Something went wrong',
226 fatalMessage: 'Use "Check for broken extensions!"',
227 loadingTitle: 'Loading…',
228 loadingMessage: '',
229 successTitle: 'No TCA migrations need to be applied',
230 successMessage: 'Your TCA looks good.',
231 warningTitle: 'TCA migrations need to be applied',
232 warningMessage: 'Check the following list and apply needed changes.'
233 },
234 tcaExtTablesCheck: {
235 fatalTitle: 'Something went wrong',
236 fatalMessage: 'Use "Check for broken extensions!"',
237 loadingTitle: 'Loading…',
238 loadingMessage: '',
239 successTitle: 'No TCA changes in ext_tables.php files. Good job!',
240 successMessage: '',
241 warningTitle: 'Extensions change TCA in ext_tables.php',
242 warningMessage: 'Check for ExtensionManagementUtility and $GLOBALS["TCA"].'
243 }
244 },
245
246 /**
247 * output DOM Container
248 */
249 outputContainer: {},
250
251 /**
252 * Clone of a DOM object acts as message template
253 */
254 messageTemplate: {},
255
256 /**
257 * Clone of the DOM object that contains the submit button
258 */
259 submitButton: {},
260
261 /**
262 * Fetching the templates out of the DOM
263 *
264 * @param tcaIntegrityCheckContainer DOM element id with all needed HTML in it
265 * @return boolean DOM container could be found and initialization finished
266 */
267 initialize: function(tcaIntegrityCheckContainer) {
268 var success = false;
269 this.outputContainer[tcaIntegrityCheckContainer] = $('#' + tcaIntegrityCheckContainer);
270
271 if (this.outputContainer[tcaIntegrityCheckContainer]) {
272 // submit button: save and delete
273 if(!this.submitButton[tcaIntegrityCheckContainer]) {
274 var submitButton = this.outputContainer[tcaIntegrityCheckContainer].find('button[type="submit"]');
275 this.submitButton[tcaIntegrityCheckContainer] = submitButton.clone();
276 // submitButton.remove();
277 }
278
279 // message template (for the output): save and delete
280 if(!this.messageTemplate[tcaIntegrityCheckContainer]) {
281 var messageTemplateSection = this.outputContainer[tcaIntegrityCheckContainer].find('.messageTemplate');
282 this.messageTemplate[tcaIntegrityCheckContainer] = messageTemplateSection.children().clone().show();
283 messageTemplateSection.remove();
284 }
285
286 // clear all messages from the run before
287 this.outputContainer[tcaIntegrityCheckContainer].find('.typo3-message:visible ').remove();
288
289 success = true;
290 }
291 return success;
292 },
293
294 checkTcaIntegrity: function(actionName) {
295 var self = this;
296 var url = location.href + '&install[controller]=ajax&install[action]=' + actionName;
297
298 var isInitialized = self.initialize(actionName);
299 if(isInitialized) {
300 self.addMessage(
301 'loading',
302 self.outputMessages[actionName].loadingTitle,
303 self.outputMessages[actionName].loadingMessage,
304 actionName
305 );
306
307 $.ajax({
308 url: url,
309 cache: false,
310 success: function(data) {
311
312 if(data.success === true && Array.isArray(data.status)) {
313 if(data.status.length > 0) {
314 self.outputContainer[actionName].find('.alert-loading').hide();
315 self.addMessage(
316 'warning',
317 self.outputMessages[actionName].warningTitle,
318 self.outputMessages[actionName].warningMessage,
319 actionName
320 );
321 data.status.forEach((function (element) {
322 self.addMessage(
323 element.severity,
324 element.title,
325 element.message,
326 actionName
327 );
328 }));
329 } else {
330 // nothing to complain, everything fine
331 self.outputContainer[actionName].find('.alert-loading').hide();
332 self.addMessage(
333 'success',
334 self.outputMessages[actionName].successTitle,
335 self.outputMessages[actionName].successMessage,
336 actionName
337 );
338 }
339 } else if (data === 'unauthorized') {
340 location.reload();
341 }
342 },
343 error: function() {
344 self.outputContainer[actionName].find('.alert-loading').hide();
345 self.addMessage(
346 'fatal',
347 self.outputMessages[actionName].fatalTitle,
348 self.outputMessages[actionName].fatalMessage,
349 actionName
350 );
351 }
352 });
353 }
354 },
355
356 /**
357 * Move the submit button to the end of the box
358 *
359 * @param tcaIntegrityCheckContainer DOM container name
360 */
361 moveSubmitButtonFurtherDown: function(tcaIntegrityCheckContainer) {
362 console.debug(this.outputContainer[tcaIntegrityCheckContainer], 'this.outputContainer['+[tcaIntegrityCheckContainer]+']');
363
364 // first remove the currently visible button
365 this.outputContainer[tcaIntegrityCheckContainer].find('button[type="submit"]').remove();
366 // then append the cloned template to the end
367 this.outputContainer[tcaIntegrityCheckContainer].append(this.submitButton[tcaIntegrityCheckContainer]);
368 },
369
370 /**
371 * Show a status message
372 *
373 * @param severity
374 * @param title
375 * @param message
376 * @param tcaIntegrityCheckContainer DOM container name
377 */
378 addMessage: function(severity, title, message, tcaIntegrityCheckContainer) {
379 var domMessage = this.messageTemplate[tcaIntegrityCheckContainer].clone();
380 if (severity) {
381 domMessage.addClass('alert-' + severity);
382 }
383 if (title) {
384 domMessage.find('h4').html(title);
385 }
386 if (message) {
387 domMessage.find('.messageText').html(message);
388 } else {
389 domMessage.find('.messageText').remove();
390 }
391 this.outputContainer[tcaIntegrityCheckContainer].append(domMessage);
392 this.moveSubmitButtonFurtherDown(tcaIntegrityCheckContainer);
393 }
394
395 };
396
397 TYPO3.Install.Status = {
398 getFolderStatus: function() {
399 var url = location.href + '&install[controller]=ajax&install[action]=folderStatus';
400 $.ajax({
401 url: url,
402 cache: false,
403 success: function(data) {
404 if (data > 0) {
405 $('.t3js-install-menu-folderStructure').append('<span class="badge badge-danger">' + data + '</span>');
406 }
407 }
408 });
409 },
410 getEnvironmentStatus: function() {
411 var url = location.href + '&install[controller]=ajax&install[action]=environmentStatus';
412 $.ajax({
413 url: url,
414 cache: false,
415 success: function(data) {
416 if (data > 0) {
417 $('.t3js-install-menu-systemEnvironment').append('<span class="badge badge-danger">' + data + '</span>');
418 }
419 }
420 });
421 }
422 };
423
424 TYPO3.Install.coreUpdate = {
425 /**
426 * The action queue defines what actions are called in which order
427 */
428 actionQueue: {
429 coreUpdateUpdateVersionMatrix: {
430 loadingMessage: 'Fetching list of released versions from typo3.org',
431 finishMessage: 'Fetched list of released versions',
432 nextActionName: 'coreUpdateIsUpdateAvailable'
433 },
434 coreUpdateIsUpdateAvailable: {
435 loadingMessage: 'Checking for possible regular or security update',
436 finishMessage: undefined,
437 nextActionName: undefined
438 },
439 coreUpdateCheckPreConditions: {
440 loadingMessage: 'Checking if update is possible',
441 finishMessage: 'System can be updated',
442 nextActionName: 'coreUpdateDownload'
443 },
444 coreUpdateDownload: {
445 loadingMessage: 'Downloading new core',
446 finishMessage: undefined,
447 nextActionName: 'coreUpdateVerifyChecksum'
448 },
449 coreUpdateVerifyChecksum: {
450 loadingMessage: 'Verifying checksum of downloaded core',
451 finishMessage: undefined,
452 nextActionName: 'coreUpdateUnpack'
453 },
454 coreUpdateUnpack: {
455 loadingMessage: 'Unpacking core',
456 finishMessage: undefined,
457 nextActionName: 'coreUpdateMove'
458 },
459 coreUpdateMove: {
460 loadingMessage: 'Moving core',
461 finishMessage: undefined,
462 nextActionName: 'clearCache'
463 },
464 clearCache: {
465 loadingMessage: 'Clearing caches',
466 finishMessage: 'Caches cleared',
467 nextActionName: 'coreUpdateActivate'
468 },
469 coreUpdateActivate: {
470 loadingMessage: 'Activating core',
471 finishMessage: 'Core updated - please reload your browser',
472 nextActionName: undefined
473 }
474 },
475
476 /**
477 * Clone of a DOM object acts as message template
478 */
479 messageTemplate: null,
480
481 /**
482 * Clone of a DOM object acts as button template
483 */
484 buttonTemplate: null,
485
486 /**
487 * Fetching the templates out of the DOM
488 */
489 initialize: function() {
490 var messageTemplateSection = $('#messageTemplate');
491 var buttonTemplateSection = $('#buttonTemplate');
492 this.messageTemplate = messageTemplateSection.children().clone();
493 this.buttonTemplate = buttonTemplateSection.children().clone();
494 messageTemplateSection.remove();
495 },
496
497 /**
498 * Public method checkForUpdate
499 */
500 checkForUpdate: function() {
501 this.callAction('coreUpdateUpdateVersionMatrix');
502 },
503
504 /**
505 * Public method updateDevelopment
506 */
507 updateDevelopment: function() {
508 this.update('development');
509 },
510
511 /**
512 * Public method updateRegular
513 */
514 updateRegular: function() {
515 this.update('regular');
516 },
517
518 /**
519 * Execute core update.
520 *
521 * @param type Either 'development' or 'regular'
522 */
523 update: function(type) {
524 if (type !== "development") {
525 type = 'regular';
526 }
527 this.callAction('coreUpdateCheckPreConditions', type);
528 },
529
530 /**
531 * Generic method to call actions from the queue
532 *
533 * @param actionName Name of the action to be called
534 * @param type Update type (optional)
535 */
536 callAction: function(actionName, type) {
537 var self = this;
538 var data = {
539 install: {
540 controller: 'ajax',
541 action: actionName
542 }
543 };
544 if (type !== undefined) {
545 data.install["type"] = type;
546 }
547 this.addLoadingMessage(this.actionQueue[actionName].loadingMessage);
548 $.ajax({
549 url: location.href,
550 data: data,
551 cache: false,
552 success: function(result) {
553 var canContinue = self.handleResult(result, self.actionQueue[actionName].finishMessage);
554 if (canContinue === true && (self.actionQueue[actionName].nextActionName !== undefined)) {
555 self.callAction(self.actionQueue[actionName].nextActionName, type);
556 }
557 },
558 error: function(result) {
559 self.handleResult(result);
560 }
561 });
562 },
563
564 /**
565 * Handle ajax result of core update step.
566 *
567 * @param data
568 * @param successMessage Optional success message
569 */
570 handleResult: function(data, successMessage) {
571 var canContinue = false;
572 this.removeLoadingMessage();
573 if (data.success === true) {
574 canContinue = true;
575 if (data.status && typeof(data.status) === 'object') {
576 this.showStatusMessages(data.status);
577 }
578 if (data.action && typeof(data.action) === 'object') {
579 this.showActionButton(data.action);
580 }
581 if (successMessage) {
582 this.addMessage('success', successMessage);
583 }
584 } else {
585 // Handle clearcache until it uses the new view object
586 if (data === "OK") {
587 canContinue = true;
588 if (successMessage) {
589 this.addMessage('success', successMessage);
590 }
591 } else {
592 canContinue = false;
593 if (data.status && typeof(data.status) === 'object') {
594 this.showStatusMessages(data.status);
595 } else {
596 this.addMessage('danger', 'General error');
597 }
598 }
599 }
600 return canContinue;
601 },
602
603 /**
604 * Add a loading message with some text.
605 *
606 * @param messageTitle
607 */
608 addLoadingMessage: function(messageTitle) {
609 var domMessage = this.messageTemplate.clone();
610 domMessage.find('h4').html(messageTitle);
611 domMessage.addClass('alert-notice');
612 domMessage.find('.messageText').remove();
613 $('#coreUpdate').append(domMessage);
614 },
615
616 /**
617 * Remove an enabled loading message
618 */
619 removeLoadingMessage: function() {
620 $('#coreUpdate').find('.alert-notice').closest('.alert').remove();
621 },
622
623 /**
624 * Show a list of status messages
625 *
626 * @param messages
627 */
628 showStatusMessages: function(messages) {
629 var self = this;
630 $.each(messages, function(index, element) {
631 var title = false;
632 var severity = false;
633 var message = false;
634 if (element.severity) {
635 severity = element.severity;
636 }
637 if (element.title) {
638 title = element.title;
639 }
640 if (element.message) {
641 message = element.message;
642 }
643 self.addMessage(severity, title, message);
644 });
645 },
646
647 /**
648 * Show an action button
649 *
650 * @param button
651 */
652 showActionButton: function(button) {
653 var title = false;
654 var action = false;
655 if (button.title) {
656 title = button.title;
657 }
658 if (button.action) {
659 action = button.action;
660 }
661 var domButton = this.buttonTemplate;
662 if (action) {
663 domButton.find('button').data('action', action);
664 }
665 if (title) {
666 domButton.find('button').html(title);
667 }
668 $('#coreUpdate').append(domButton);
669 },
670
671 /**
672 * Show a status message
673 *
674 * @param severity
675 * @param title
676 * @param message
677 */
678 addMessage: function(severity, title, message) {
679 var domMessage = this.messageTemplate.clone();
680 if (severity) {
681 domMessage.addClass('alert-' + severity);
682 }
683 if (title) {
684 domMessage.find('h4').html(title);
685 }
686 if (message) {
687 domMessage.find('.messageText').html(message);
688 } else {
689 domMessage.find('.messageText').remove();
690 }
691 $('#coreUpdate').append(domMessage);
692 }
693 };
694
695 $(function() {
696 // Used in database compare section to select/deselect checkboxes
697 $('.checkall').on('click', function() {
698 $(this).closest('fieldset').find(':checkbox').prop('checked', this.checked);
699 });
700
701 $('.item-description').find('a').on('click', function() {
702 var targetToggleGroupId = $(this.hash);
703 if (targetToggleGroupId) {
704 var $currentToggleGroup = $(this).closest('.toggleGroup');
705 var $targetToggleGroup = $(targetToggleGroupId).closest('.toggleGroup');
706 if ($targetToggleGroup !== $currentToggleGroup) {
707 $currentToggleGroup.removeClass('expanded');
708 $currentToggleGroup.find('.toggleData').hide();
709 $targetToggleGroup.addClass('expanded');
710 $targetToggleGroup.find('.toggleData').show();
711 TYPO3.Install.Scrolling.handleButtonScrolling();
712 }
713 }
714 });
715
716 $(document).on('click', '.t3js-all-configuration-toggle', function() {
717 var $panels = $('.panel-collapse', '#allConfiguration');
718 var action = ($panels.eq(0).hasClass('in')) ? 'hide' : 'show';
719 $panels.collapse(action);
720 });
721
722 if ($('#configSearch').length > 0) {
723 $(window).on('keydown', function(event) {
724 if (event.ctrlKey || event.metaKey) {
725 switch (String.fromCharCode(event.which).toLowerCase()) {
726 case 'f':
727 event.preventDefault();
728 $('#configSearch').focus();
729 break;
730 }
731 }
732 });
733 }
734
735 // Simple password strength indicator
736 $('.t3-install-form-password-strength').on('keyup', function() {
737 var value = $(this).val();
738 var strongRegex = new RegExp('^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$', 'g');
739 var mediumRegex = new RegExp('^(?=.{8,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$', 'g');
740 var enoughRegex = new RegExp('(?=.{8,}).*', 'g');
741
742 if (value.length === 0) {
743 $(this).attr('style', 'background-color:#FBB19B; border:1px solid #DC4C42');
744 } else if (!enoughRegex.test(value)) {
745 $(this).attr('style', 'background-color:#FBB19B; border:1px solid #DC4C42');
746 } else if (strongRegex.test(value)) {
747 $(this).attr('style', 'background-color:#CDEACA; border:1px solid #58B548');
748 } else if (mediumRegex.test(value)) {
749 $(this).attr('style', 'background-color:#FBFFB3; border:1px solid #C4B70D');
750 } else {
751 $(this).attr('style', 'background-color:#FBFFB3; border:1px solid #C4B70D');
752 }
753 });
754
755 // Install step database settings
756 $('#t3-install-step-type').change(function() {
757 var connectionType = $(this).val(),
758 hostField = $('#t3-install-step-host'),
759 portField = $('#t3-install-step-port'),
760 socketField = $('#t3-install-step-socket');
761
762 if (connectionType === 'socket') {
763 hostField.parents('.form-group').fadeOut();
764 hostField.val('localhost');
765 portField.parents('.form-group').fadeOut();
766 socketField.parents('.form-group').fadeIn();
767 } else {
768 hostField.parents('.form-group').fadeIn();
769 if (hostField.val() === 'localhost') {
770 hostField.val('127.0.0.1');
771 }
772 portField.parents('.form-group').fadeIn();
773 socketField.parents('.form-group').fadeOut();
774 }
775 }).trigger('change');
776
777 // Extension compatibility check
778 $('.t3js-message', '#checkExtensions').hide();
779 $('button', '#checkExtensions').click(function(e) {
780 $('button', '#checkExtensions').hide();
781 $('.t3js-message', '#checkExtensions').hide();
782 $('.alert-loading', '#checkExtensions').show();
783 TYPO3.Install.ExtensionChecker.checkExtensionsCompatibility(true);
784 e.preventDefault();
785 return false;
786 });
787
788 // Handle core update
789 var $coreUpdateSection = $('#coreUpdate');
790 if ($coreUpdateSection) {
791 TYPO3.Install.coreUpdate.initialize();
792 $coreUpdateSection.on('click', 'button', (function(e) {
793 e.preventDefault();
794 var action = $(e.target).data('action');
795 TYPO3.Install.coreUpdate[action]();
796 $(e.target).closest('.t3-install-form-submit').remove();
797 }));
798 }
799
800 // Handle TCA ext_tables check
801 var $tcaExtTablesCheckSection = $('#tcaExtTablesCheck');
802 if ($tcaExtTablesCheckSection) {
803 $tcaExtTablesCheckSection.on('click', 'button', (function(e) {
804 TYPO3.Install.TcaIntegrityChecker.checkTcaIntegrity('tcaExtTablesCheck');
805 e.preventDefault();
806 return false;
807 }));
808 }
809
810 // Handle TCA Migrations check
811 var $tcaMigrationsCheckSection = $('#tcaMigrationsCheck');
812 if ($tcaMigrationsCheckSection) {
813 $tcaMigrationsCheckSection.on('click', 'button', (function(e) {
814 TYPO3.Install.TcaIntegrityChecker.checkTcaIntegrity('tcaMigrationsCheck');
815 e.preventDefault();
816 return false;
817 }));
818 }
819
820 var $installLeft = $('.t3js-list-group-wrapper');
821 if ($installLeft.length > 0) {
822 TYPO3.Install.Status.getFolderStatus();
823 TYPO3.Install.Status.getEnvironmentStatus();
824 }
825 // This makes jquerys "contains" work case-insensitive
826 jQuery.expr[':'].contains = jQuery.expr.createPseudo(function(arg) {
827 return function(elem) {
828 return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
829 };
830 });
831 $('#configSearch').keyup(function() {
832 var typedQuery = $(this).val();
833 $('div.item').each(function() {
834 var $item = $(this);
835 if ($(':contains(' + typedQuery + ')', $item).length > 0 || $('input[value*="' + typedQuery + '"]', $item).length > 0) {
836 $item.removeClass('hidden').addClass('searchhit');
837 } else {
838 $item.removeClass('searchhit').addClass('hidden');
839 }
840 });
841 $('.searchhit').parent().collapse('show');
842 });
843 var $searchFields = $('#configSearch');
844 var searchResultShown = ('' !== $searchFields.first().val());
845
846 // make search field clearable
847 $searchFields.clearable({
848 onClear: function() {
849 if (searchResultShown) {
850 $(this).closest('form').submit();
851 }
852 }
853 });
854
855 // Define width of fixed menu
856 var $menuWrapper = $('#menuWrapper');
857 var $menuListGroup = $menuWrapper.children('.t3js-list-group-wrapper');
858 $menuWrapper.on('affixed.bs.affix', function() {
859 $menuListGroup.width($(this).parent().width());
860 });
861 $menuListGroup.width($menuWrapper.parent().width());
862 $(window).resize(function() {
863 $menuListGroup.width($('#menuWrapper').parent().width());
864 });
865 var $collapse = $('.collapse');
866 $collapse.on('shown.bs.collapse', function() {
867 TYPO3.Install.Scrolling.handleButtonScrolling();
868 });
869 $collapse.on('hidden.bs.collapse', function() {
870 TYPO3.Install.Scrolling.handleButtonScrolling();
871 });
872
873 // trigger 'handleButtonScrolling' on page scroll
874 // if the user scroll until page bottom, we need to remove 'position: fixed'
875 // so that the copyright info (footer) is not overlayed by the 'fixed button'
876 var scrollTimeout;
877 $(window).on('scroll', function() {
878 clearTimeout(scrollTimeout);
879 scrollTimeout = setTimeout(function() {
880 TYPO3.Install.Scrolling.handleButtonScrolling();
881 }, 50);
882 });
883
884 // automatically select the custom preset if a value in one of its input fields is changed
885 $('.t3js-custom-preset').on('input', function() {
886 $('#' + $(this).data('radio')).prop('checked', true);
887 });
888
889 TYPO3.Install.upgradeAnalysis.initialize();
890 });
891
892
893 TYPO3.Install.upgradeAnalysis = {
894 provideTags: function() {
895 $('#tagsort_tags_container').tagSort({
896 selector: '.upgrade_analysis_item_to_filter'
897 });
898 },
899
900 initialize: function() {
901 TYPO3.Install.upgradeAnalysis.provideTags();
902 }
903 };