[TASK] Improve install tool loading message
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Resources / Public / JavaScript / Modules / Router.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 * Module: TYPO3/CMS/Install/Router
16 */
17 define([
18 'jquery',
19 'TYPO3/CMS/Install/InfoBox',
20 'TYPO3/CMS/Install/Severity',
21 'TYPO3/CMS/Install/ProgressBar',
22 'TYPO3/CMS/Backend/Modal',
23 'TYPO3/CMS/Backend/Icons'
24 ], function($, InfoBox, Severity, ProgressBar, Modal, Icons) {
25 'use strict';
26
27 return {
28 selectorBody: '.t3js-body',
29 selectorMainContent: '.t3js-module-body',
30
31 initialize: function() {
32 var self = this;
33
34 this.registerInstallToolRoutes();
35
36 $(document).on('click', '.t3js-login-lockInstallTool', function(e) {
37 e.preventDefault();
38 self.logout();
39 });
40 $(document).on('click', '.t3js-login-login', function(e) {
41 e.preventDefault();
42 self.login();
43 });
44 $(document).on('keydown', '#t3-install-form-password', function(e) {
45 if (e.keyCode === 13) {
46 e.preventDefault();
47 $('.t3js-login-login').click();
48 }
49 });
50
51 $(document).on('click', '.card .btn', function(e) {
52 e.preventDefault();
53
54 var $me = $(e.currentTarget);
55 var requireModule = $me.data('require');
56 var inlineState = $me.data('inline');
57 var isInline = typeof inlineState !== 'undefined' && parseInt(inlineState) === 1;
58 if (isInline) {
59 require([requireModule], function(aModule) {
60 if (typeof aModule.initialize !== 'undefined') {
61 aModule.initialize($me);
62 }
63 });
64 } else {
65 var modalTitle = $me.closest('.card').find('.card-title').html();
66 var modalSize = $me.data('modalSize') || Modal.sizes.large;
67
68 Icons.getIcon('spinner-circle', Icons.sizes.default, null, null, Icons.markupIdentifiers.inline).done(function(icon) {
69 var configuration = {
70 type: Modal.types.default,
71 title: modalTitle,
72 size: modalSize,
73 content: '<div class="modal-loading">' + icon + '</div>',
74 additionalCssClasses: ['install-tool-modal'],
75 callback: function (currentModal) {
76 require([requireModule], function (aModule) {
77 if (typeof aModule.initialize !== 'undefined') {
78 aModule.initialize(currentModal);
79 }
80 });
81 }
82 };
83 Modal.advanced(configuration);
84 });
85 }
86 });
87
88 this.executeSilentConfigurationUpdate();
89 },
90
91 registerInstallToolRoutes: function() {
92 if (typeof TYPO3.settings === 'undefined') {
93 TYPO3.settings = {
94 ajaxUrls: {
95 icons: '?install[controller]=icon&install[action]=getIcon',
96 icons_cache: '?install[controller]=icon&install[action]=getCacheIdentifier'
97 }
98 }
99 }
100 },
101
102 getUrl: function(action, controller) {
103 var url = location.href;
104 var context = $(this.selectorBody).data('context');
105 url = url.replace(location.search, '');
106 if (controller === undefined) {
107 controller = $(this.selectorBody).data('controller');
108 }
109 url = url + '?install[controller]=' + controller;
110 if (context !== undefined && context !== '') {
111 url = url + '&install[context]=' + context;
112 }
113 if (action !== undefined) {
114 url = url + '&install[action]=' + action;
115 }
116 return url;
117 },
118
119 executeSilentConfigurationUpdate: function() {
120 var self = this;
121 this.updateLoadingInfo('Checking session and executing silent configuration update');
122 $.ajax({
123 url: this.getUrl('executeSilentConfigurationUpdate', 'layout'),
124 cache: false,
125 success: function(data) {
126 if (data.success === true) {
127 self.executeSilentLegacyExtConfExtensionConfigurationUpdate();
128 } else {
129 self.executeSilentConfigurationUpdate();
130 }
131 },
132 error: function(xhr) {
133 self.handleAjaxError(xhr);
134 }
135 });
136 },
137
138 /**
139 * Legacy layer to upmerge LocalConfiguration EXT/extConf serialized array keys
140 * to EXTENSIONS array in LocalConfiguration for initial update from v8 to v9.
141 *
142 * @deprecated since TYPO3 v9, will be removed with v10 - re-route executeSilentConfigurationUpdate()
143 * to executeSilentExtensionConfigurationUpdate() on removal of this function.
144 */
145 executeSilentLegacyExtConfExtensionConfigurationUpdate: function() {
146 var self = this;
147 this.updateLoadingInfo('Executing silent extension configuration update');
148 $.ajax({
149 url: this.getUrl('executeSilentLegacyExtConfExtensionConfigurationUpdate', 'layout'),
150 cache: false,
151 success: function(data) {
152 if (data.success === true) {
153 self.executeSilentExtensionConfigurationSynchronization();
154 } else {
155 var message = InfoBox.render(Severity.error, 'Something went wrong', '');
156 $outputContainer.empty().append(message);
157 }
158 },
159 error: function(xhr) {
160 self.handleAjaxError(xhr);
161 }
162 });
163 },
164
165 /**
166 * Extensions which come with new default settings in ext_conf_template.txt extension
167 * configuration files get their new defaults written to LocalConfiguration.
168 */
169 executeSilentExtensionConfigurationSynchronization: function() {
170 var self = this;
171 this.updateLoadingInfo('Executing silent extension configuration synchronization');
172 $.ajax({
173 url: this.getUrl('executeSilentExtensionConfigurationSynchronization', 'layout'),
174 cache: false,
175 success: function(data) {
176 if (data.success === true) {
177 self.loadMainLayout();
178 } else {
179 var message = InfoBox.render(Severity.error, 'Something went wrong', '');
180 $outputContainer.empty().append(message);
181 }
182 },
183 error: function(xhr) {
184 self.handleAjaxError(xhr);
185 }
186 });
187 },
188
189 loadMainLayout: function() {
190 var self = this;
191 var $outputContainer = $(this.selectorBody);
192 this.updateLoadingInfo('Loading main layout');
193 $.ajax({
194 url: this.getUrl('mainLayout', 'layout'),
195 cache: false,
196 success: function(data) {
197 if (data.success === true && data.html !== 'undefined' && data.html.length > 0) {
198 $outputContainer.empty().append(data.html);
199 // Mark main module as active in standalone
200 if ($(self.selectorBody).data('context') !== 'backend') {
201 var controller = $outputContainer.data('controller');
202 $outputContainer.find('.t3js-mainmodule[data-controller="' + controller + '"]').addClass('active');
203 }
204 self.loadCards();
205 } else {
206 var message = InfoBox.render(Severity.error, 'Something went wrong', '');
207 $outputContainer.empty().append(message);
208 }
209 },
210 error: function(xhr) {
211 self.handleAjaxError(xhr);
212 }
213 });
214 },
215
216 handleAjaxError: function(xhr, $outputContainer) {
217 var message = '';
218 if (xhr.status === 403) {
219 // Install tool session expired - depending on context render error message or login
220 var context = $(this.selectorBody).data('context');
221 if (context === 'backend') {
222 message = InfoBox.render(
223 Severity.error,
224 'The install tool session expired. Please reload the backend and try again.'
225 );
226 $(this.selectorBody).empty().append(message);
227 } else {
228 this.checkEnableInstallToolFile();
229 }
230 } else {
231 // @todo Recovery tests should be started here
232 var url = this.getUrl(undefined, 'upgrade');
233 message =
234 '<div class="t3js-infobox callout callout-sm callout-danger">'
235 + '<div class="callout-body">'
236 + '<p>Something went wrong. Please use <b><a href="' + url + '">Check for broken'
237 + ' extensions</a></b> to see if a loaded extension breaks this part of the install tool'
238 + ' and unload it.</p>'
239 + '<p>The box below may additionally reveal further details on what went wrong depending on your debug settings.'
240 + ' It may help to temporarily switch to debug mode using <b>Settings > Configuration Presets > Debug settings.</b></p>'
241 + '<p>If this error happens at an early state and no full exception back trace is shown, it may also help'
242 + ' to manually increase debugging output in <code>typo3conf/LocalConfiguration.php</code>:'
243 + '<code>[\'BE\'][\'debug\'] => true</code>, <code>[\'SYS\'][\'devIPmask\'] => \'*\'</code>, <code>[\'SYS\'][\'displayErrors\'] => 1</code>,'
244 + '<code>[\'SYS\][\'systemLogLevel\'] => 0</code>, <code>[\'SYS\'][\'exceptionalErrors\'] => 12290</code></p>'
245 + '</div>'
246 + '</div>'
247 + '<div class="panel-group" role="tablist" aria-multiselectable="true">'
248 + '<div class="panel panel-default panel-flat searchhit">'
249 + '<div class="panel-heading" role="tab" id="heading-error">'
250 + '<h3 class="panel-title">'
251 + '<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-error" aria-expanded="true" aria-controls="collapse-error" class="collapsed">'
252 + '<span class="caret"></span>'
253 + '<strong>Ajax error</strong>'
254 + '</a>'
255 +'</h3>'
256 + '</div>'
257 + '<div id="collapse-error" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-error">'
258 + '<div class="panel-body">'
259 + xhr.responseText
260 + '</div>'
261 + '</div>'
262 + '</div>';
263
264 if (typeof $outputContainer !== 'undefined') {
265 // Write to given output container. This is typically a modal if given
266 $outputContainer.empty().html(message);
267 } else {
268 // Else write to main frame
269 $(this.selectorBody).empty().html(message);
270 }
271 }
272 },
273
274 checkEnableInstallToolFile: function() {
275 var self = this;
276 $.ajax({
277 url: this.getUrl('checkEnableInstallToolFile'),
278 cache: false,
279 success: function(data) {
280 if (data.success === true) {
281 self.checkLogin();
282 } else {
283 self.showEnableInstallTool();
284 }
285 },
286 error: function(xhr) {
287 self.handleAjaxError(xhr);
288 }
289 });
290 },
291
292 showEnableInstallTool: function() {
293 var self = this;
294 $.ajax({
295 url: this.getUrl('showEnableInstallToolFile'),
296 cache: false,
297 success: function(data) {
298 if (data.success === true) {
299 $(self.selectorBody).empty().append(data.html);
300 }
301 },
302 error: function(xhr) {
303 self.handleAjaxError(xhr);
304 }
305 });
306 },
307
308 checkLogin: function() {
309 var self = this;
310 $.ajax({
311 url: this.getUrl('checkLogin'),
312 cache: false,
313 success: function(data) {
314 if (data.success === true) {
315 self.loadMainLayout();
316 } else {
317 self.showLogin();
318 }
319 },
320 error: function(xhr) {
321 self.handleAjaxError(xhr);
322 }
323 });
324 },
325
326 showLogin: function() {
327 var self = this;
328 $.ajax({
329 url: this.getUrl('showLogin'),
330 cache: false,
331 success: function(data) {
332 if (data.success === true) {
333 $(self.selectorBody).empty().append(data.html);
334 }
335 },
336 error: function(xhr) {
337 self.handleAjaxError(xhr);
338 }
339 });
340 },
341
342 login: function() {
343 var self = this;
344 var $outputContainer = $('.t3js-login-output');
345 var message = ProgressBar.render(Severity.loading, 'Loading...', '');
346 $outputContainer.empty().html(message);
347 $.ajax({
348 url: this.getUrl(),
349 cache: false,
350 method: 'POST',
351 data: {
352 'install': {
353 'action': 'login',
354 'token': $('[data-login-token]').data('login-token'),
355 'password': $('.t3-install-form-input-text').val()
356 }
357 },
358 success: function(data) {
359 if (data.success === true) {
360 self.loadMainLayout();
361 } else {
362 data.status.forEach(function(element) {
363 var message = InfoBox.render(element.severity, element.title, element.message);
364 $outputContainer.empty().html(message);
365 });
366 }
367 },
368 error: function(xhr) {
369 self.handleAjaxError(xhr);
370 }
371 });
372 },
373
374 logout: function() {
375 var self = this;
376 $.ajax({
377 url: self.getUrl('logout'),
378 cache: false,
379 success: function(data) {
380 if (data.success === true) {
381 self.showEnableInstallTool();
382 }
383 },
384 error: function(xhr) {
385 self.handleAjaxError(xhr);
386 }
387 });
388 },
389
390 loadCards: function() {
391 var self = this;
392 var outputContainer = $(this.selectorMainContent);
393 $.ajax({
394 url: this.getUrl('cards'),
395 cache: false,
396 success: function(data) {
397 if (data.success === true && data.html !== 'undefined' && data.html.length > 0) {
398 outputContainer.empty().append(data.html);
399 } else {
400 var message = InfoBox.render(Severity.error, 'Something went wrong', '');
401 outputContainer.empty().append(message);
402 }
403 },
404 error: function(xhr) {
405 self.handleAjaxError(xhr);
406 }
407 });
408 },
409
410 updateLoadingInfo: function(info) {
411 var $outputContainer = $(this.selectorBody);
412 $outputContainer.find('#t3js-ui-block-detail').text(info);
413 }
414 };
415 });