Skip to content

Commit

Permalink
[TASK] Replace $.ajax() in most of EXT:backend
Browse files Browse the repository at this point in the history
This patch replaces $.ajax() in EXT:backend either with our AJAX API
or with native XMLHttpRequest. The latter is required in the DragUploader
as we need to listen to the progress event which isn't supported by
fetch().

This patch skips Storage/Persistent, as this one needs some refactoring
due to the usage of synchronous(!) AJAX requests.

Resolves: #90597
Releases: master
Change-Id: Ifdf41c133929740f3e766ae992848ab99ca1f283
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63502
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Tested-by: Susanne Moog <look@susi.dev>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Susanne Moog <look@susi.dev>
  • Loading branch information
andreaskienast authored and susannemoog committed Feb 29, 2020
1 parent 4b20004 commit 9c1342d
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 136 deletions.
Expand Up @@ -11,16 +11,15 @@
* The TYPO3 project - inspiring people to share!
*/

/**
* Module: TYPO3/CMS/Backend/DragUploader
*/
import {SeverityEnum} from './Enum/Severity';
import * as $ from 'jquery';
import {AjaxResponse} from 'TYPO3/CMS/Core/Ajax/AjaxResponse';
import {SeverityEnum} from './Enum/Severity';
import {MessageUtility} from './Utility/MessageUtility';
import moment = require('moment');
import NProgress = require('nprogress');
import AjaxRequest = require('TYPO3/CMS/Core/Ajax/AjaxRequest');
import Modal = require('./Modal');
import Notification = require('./Notification');
import {MessageUtility} from './Utility/MessageUtility';

/**
* Possible actions for conflicts w/ existing files
Expand Down Expand Up @@ -261,32 +260,29 @@ class DragUploaderPlugin {
this.percentagePerFile = 1 / files.length;

// Check for each file if is already exist before adding it to the queue
const ajaxCalls: JQueryXHR[] = [];
$.each(files, (i: string, file: InternalFile) => {
ajaxCalls[parseInt(i, 10)] = $.ajax({
url: TYPO3.settings.ajaxUrls.file_exists,
data: {
fileName: file.name,
fileTarget: this.target,
},
cache: false,
success: (response: any) => {
const fileExists = typeof response.uid !== 'undefined';
if (fileExists) {
this.askForOverride.push({
original: response,
uploaded: file,
action: this.irreObjectUid ? Action.USE_EXISTING : Action.SKIP,
});
NProgress.inc(this.percentagePerFile);
} else {
new FileQueueItem(this, file, Action.SKIP);
}
},
const ajaxCalls: Promise<void>[] = [];
Array.from(files).forEach((file: InternalFile) => {
const request = new AjaxRequest(TYPO3.settings.ajaxUrls.file_exists).withQueryArguments({
fileName: file.name,
fileTarget: this.target,
}).get({cache: 'no-cache'}).then(async (response: AjaxResponse): Promise<void> => {
const data = await response.resolve();
const fileExists = typeof data.uid !== 'undefined';
if (fileExists) {
this.askForOverride.push({
original: data,
uploaded: file,
action: this.irreObjectUid ? Action.USE_EXISTING : Action.SKIP,
});
NProgress.inc(this.percentagePerFile);
} else {
new FileQueueItem(this, file, Action.SKIP);
}
});
ajaxCalls.push(request);
});

$.when.apply($, ajaxCalls).done(() => {
Promise.all(ajaxCalls).then((): void => {
this.drawOverrideModal();
NProgress.done();
});
Expand Down Expand Up @@ -322,14 +318,11 @@ class DragUploaderPlugin {
if (this.queueLength > 0) {
this.queueLength--;
if (this.queueLength === 0) {
$.ajax({
url: TYPO3.settings.ajaxUrls.flashmessages_render,
cache: false,
success: (data: any) => {
$.each(data, (index: number, flashMessage: { title: string, message: string, severity: number }) => {
Notification.showMessage(flashMessage.title, flashMessage.message, flashMessage.severity);
});
},
new AjaxRequest(TYPO3.settings.ajaxUrls.flashmessages_render).get({cache: 'no-cache'}).then(async (response: AjaxResponse): Promise<void> => {
const data = await response.resolve();
for (let flashMessage of data) {
Notification.showMessage(flashMessage.title, flashMessage.message, flashMessage.severity);
}
});
}
}
Expand Down Expand Up @@ -384,7 +377,7 @@ class DragUploaderPlugin {
.val(Action.SKIP).text(TYPO3.lang['file_upload.actions.skip']),
$('<option />', {'selected': this.defaultAction === Action.RENAME})
.val(Action.RENAME).text(TYPO3.lang['file_upload.actions.rename']),
$('<option />', {'selected': this.defaultAction === Action.OVERRIDE})
$('<option />', {'selected': this.defaultAction === Action.OVERRIDE})
.val(Action.OVERRIDE).text(TYPO3.lang['file_upload.actions.override']),
),
),
Expand Down Expand Up @@ -472,18 +465,17 @@ class DragUploaderPlugin {
}

class FileQueueItem {
private $row: JQuery;
private readonly $row: JQuery;
private readonly $progress: JQuery;
private readonly $progressContainer: JQuery;
private readonly file: InternalFile;
private readonly override: Action;
private $iconCol: JQuery;
private $fileName: JQuery;
private $progress: JQuery;
private $progressContainer: JQuery;
private $progressBar: JQuery;
private $progressPercentage: JQuery;
private $progressMessage: JQuery;
private dragUploader: DragUploaderPlugin;
private file: InternalFile;
private override: Action;
private upload: XMLHttpRequest;

constructor(dragUploader: DragUploaderPlugin, file: InternalFile, override: Action) {
this.dragUploader = dragUploader;
Expand Down Expand Up @@ -538,25 +530,20 @@ class FileQueueItem {
formData.append('redirect', '');
formData.append('upload_1', this.file);

const s = $.extend(true, {}, $.ajaxSettings, {
url: TYPO3.settings.ajaxUrls.file_process,
contentType: false,
processData: false,
data: formData,
cache: false,
type: 'POST',
success: (data: { upload?: UploadedFile[] }) => this.uploadSuccess(data),
error: (response: XMLHttpRequest) => this.uploadError(response),
});

s.xhr = () => {
const xhr = $.ajaxSettings.xhr();
xhr.upload.addEventListener('progress', (e: ProgressEvent) => this.updateProgress(e));
return xhr;
// We use XMLHttpRequest as we need the `progress` event which isn't supported by fetch()
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = (): void => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
this.uploadSuccess(JSON.parse(xhr.responseText));
} else {
this.uploadError(xhr);
}
}
};

// start upload
this.upload = $.ajax(s);
xhr.upload.addEventListener('progress', (e: ProgressEvent) => this.updateProgress(e));
xhr.open('POST', TYPO3.settings.ajaxUrls.file_process);
xhr.send(formData);
}
}

Expand Down
Expand Up @@ -11,8 +11,10 @@
* The TYPO3 project - inspiring people to share!
*/

import {SeverityEnum} from './Enum/Severity';
import * as $ from 'jquery';
import {AjaxResponse} from 'TYPO3/CMS/Core/Ajax/AjaxResponse';
import {SeverityEnum} from './Enum/Severity';
import AjaxRequest = require('TYPO3/CMS/Core/Ajax/AjaxRequest');
import Icons = require('./Icons');
import Wizard = require('./Wizard');

Expand Down Expand Up @@ -135,7 +137,8 @@ class Localization {
this.loadAvailableLanguages(
parseInt($triggerButton.data('pageId'), 10),
parseInt($triggerButton.data('languageId'), 10),
).done((result: Array<LanguageRecord>): void => {
).then(async (response: AjaxResponse): Promise<void> => {
const result: Array<LanguageRecord> = await response.resolve();
if (result.length === 1) {
// We only have one result, auto select the record and continue
this.sourceLanguage = result[0].uid;
Expand Down Expand Up @@ -189,7 +192,8 @@ class Localization {
this.getSummary(
parseInt($triggerButton.data('pageId'), 10),
parseInt($triggerButton.data('languageId'), 10),
).done((result: SummaryRecord): void => {
).then(async (response: AjaxResponse): Promise<void> => {
const result: SummaryRecord = await response.resolve();
$slide.empty();
this.records = [];

Expand Down Expand Up @@ -290,11 +294,11 @@ class Localization {
parseInt($triggerButton.data('pageId'), 10),
parseInt($triggerButton.data('languageId'), 10),
this.records,
).done((): void => {
).then((): void => {
Wizard.dismiss();
document.location.reload();
});
}).done((): void => {
}).then((): void => {
Wizard.show();

Wizard.getComponent().on('click', '.t3js-localization-option', (optionEvt: JQueryEventObject): void => {
Expand All @@ -320,34 +324,28 @@ class Localization {
*
* @param {number} pageId
* @param {number} languageId
* @returns {JQueryXHR}
* @returns {Promise<AjaxResponse>}
*/
private loadAvailableLanguages(pageId: number, languageId: number): JQueryXHR {
return $.ajax({
url: TYPO3.settings.ajaxUrls.page_languages,
data: {
pageId: pageId,
languageId: languageId,
},
});
private loadAvailableLanguages(pageId: number, languageId: number): Promise<AjaxResponse> {
return new AjaxRequest(TYPO3.settings.ajaxUrls.page_languages).withQueryArguments({
pageId: pageId,
languageId: languageId,
}).get();
}

/**
* Get summary for record processing
*
* @param {number} pageId
* @param {number} languageId
* @returns {JQueryXHR}
* @returns {Promise<AjaxResponse>}
*/
private getSummary(pageId: number, languageId: number): JQueryXHR {
return $.ajax({
url: TYPO3.settings.ajaxUrls.records_localize_summary,
data: {
pageId: pageId,
destLanguageId: languageId,
languageId: this.sourceLanguage,
},
});
private getSummary(pageId: number, languageId: number): Promise<AjaxResponse> {
return new AjaxRequest(TYPO3.settings.ajaxUrls.records_localize_summary).withQueryArguments({
pageId: pageId,
destLanguageId: languageId,
languageId: this.sourceLanguage,
}).get();
}

/**
Expand All @@ -356,19 +354,16 @@ class Localization {
* @param {number} pageId
* @param {number} languageId
* @param {Array<number>} uidList
* @returns {JQueryXHR}
* @returns {Promise<AjaxResponse>}
*/
private localizeRecords(pageId: number, languageId: number, uidList: Array<number>): JQueryXHR {
return $.ajax({
url: TYPO3.settings.ajaxUrls.records_localize,
data: {
pageId: pageId,
srcLanguageId: this.sourceLanguage,
destLanguageId: languageId,
action: this.localizationMode,
uidList: uidList,
},
});
private localizeRecords(pageId: number, languageId: number, uidList: Array<number>): Promise<AjaxResponse> {
return new AjaxRequest(TYPO3.settings.ajaxUrls.records_localize).withQueryArguments({
pageId: pageId,
srcLanguageId: this.sourceLanguage,
destLanguageId: languageId,
action: this.localizationMode,
uidList: uidList,
}).get();
}
}

Expand Down
Expand Up @@ -12,7 +12,9 @@
*/

import * as $ from 'jquery';
import {AjaxResponse} from 'TYPO3/CMS/Core/Ajax/AjaxResponse';
import Typo3Notification = require('TYPO3/CMS/Backend/Notification');
import AjaxRequest = require('TYPO3/CMS/Core/Ajax/AjaxRequest');

enum MarkupIdentifiers {
loginrefresh = 't3js-modal-loginrefresh',
Expand Down Expand Up @@ -157,14 +159,10 @@ class LoginRefresh {
*/
public showLoginForm(): void {
// log off for sure
$.ajax({
url: TYPO3.settings.ajaxUrls.logout,
method: 'GET',
success: () => {
TYPO3.configuration.showRefreshLoginPopup
? this.showLoginPopup()
: this.$loginForm.modal(this.options.modalConfig);
},
new AjaxRequest(TYPO3.settings.ajaxUrls.logout).get().then((): void => {
TYPO3.configuration.showRefreshLoginPopup
? this.showLoginPopup()
: this.$loginForm.modal(this.options.modalConfig);
});
}

Expand Down Expand Up @@ -234,12 +232,8 @@ class LoginRefresh {
class: 'btn btn-primary t3js-active',
'data-action': 'refreshSession',
}).text(TYPO3.lang['mess.refresh_login_refresh_button']).on('click', () => {
$.ajax({
url: TYPO3.settings.ajaxUrls.login_timedout,
method: 'GET',
success: () => {
this.hideTimeoutModal();
},
new AjaxRequest(TYPO3.settings.ajaxUrls.login_timedout).get().then((): void => {
this.hideTimeoutModal();
});
}),
);
Expand Down Expand Up @@ -389,22 +383,18 @@ class LoginRefresh {
const postData: any = {
login_status: 'login',
};
$.each($form.serializeArray(), function(i: number, field: any): void {
$.each($form.serializeArray(), function (i: number, field: any): void {
postData[field.name] = field.value;
});
$.ajax({
url: $form.attr('action'),
method: 'POST',
data: postData,
success: (response: { [key: string ]: any }) => {
if (response.login.success) {
// User is logged in
this.hideLoginForm();
} else {
Typo3Notification.error(TYPO3.lang['mess.refresh_login_failed'], TYPO3.lang['mess.refresh_login_failed_message']);
$passwordField.focus();
}
},
new AjaxRequest($form.attr('action')).post(postData).then(async (response: AjaxResponse): Promise<void> => {
const data = await response.resolve();
if (data.login.success) {
// User is logged in
this.hideLoginForm();
} else {
Typo3Notification.error(TYPO3.lang['mess.refresh_login_failed'], TYPO3.lang['mess.refresh_login_failed_message']);
$passwordField.focus();
}
});
}

Expand Down
Expand Up @@ -11,6 +11,7 @@
* The TYPO3 project - inspiring people to share!
*/

import {AjaxResponse} from 'TYPO3/CMS/Core/Ajax/AjaxResponse';
import {NavigationComponentInterface} from './Viewport/NavigationComponentInterface';
import {ScaffoldIdentifierEnum} from './Enum/Viewport/ScaffoldIdentifier';
import * as $ from 'jquery';
Expand All @@ -19,6 +20,7 @@ import Viewport = require('./Viewport');
import ClientRequest = require('./Event/ClientRequest');
import TriggerRequest = require('./Event/TriggerRequest');
import InteractionRequest = require('./Event/InteractionRequest');
import AjaxRequest = require('TYPO3/CMS/Core/Ajax/AjaxRequest');

interface Module {
name: string;
Expand Down Expand Up @@ -158,8 +160,9 @@ class ModuleMenu {
* Refresh the HTML by fetching the menu again
*/
public refreshMenu(): void {
$.ajax(TYPO3.settings.ajaxUrls.modulemenu).done((result: { [key: string]: string }): void => {
$('#menu').replaceWith(result.menu);
new AjaxRequest(TYPO3.settings.ajaxUrls.modulemenu).get().then(async (response: AjaxResponse): Promise<void> => {
const result = await response.resolve();
document.getElementById('menu').outerHTML = result.menu;
if (top.currentModuleLoaded) {
ModuleMenu.highlightModuleMenuItem(top.currentModuleLoaded);
}
Expand Down

0 comments on commit 9c1342d

Please sign in to comment.