Commit 11b62b81 authored by Frank Nägler's avatar Frank Nägler Committed by Anja Leichsenring
Browse files

[TASK] Migrate TYPO3/CMS/Recordlist/* to TypeScript

Resolves: #87708
Releases: master
Change-Id: I5870f39805e2bd89c8ea57566e949c40620e389f
Reviewed-on: https://review.typo3.org/c/59697


Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: Andreas Fernandez's avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Andreas Fernandez's avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
parent c3738014
......@@ -109,6 +109,10 @@ declare module 'TYPO3/CMS/Core/Contrib/imagesloaded.pkgd.min' {
export = imagesloaded;
}
declare module 'TYPO3/CMS/Recordlist/LinkBrowser';
declare module 'TYPO3/CMS/Backend/LegacyTree';
declare module 'cm/lib/codemirror';
declare module 'moment';
......
......@@ -113,6 +113,15 @@ define(['jquery'], function($) {
highlightClass: 'active',
pageID: 0,
noop: function() {
// yes, this function is nearly useless, but wait...
// ... It happened at a time when people still wrote event handlers
// in the markup. Times to which onclick="..." were normal.
// For such legacies is this method, because modern TypeScript can not
// know that and removes components that seemingly are not needed.
// For such cases, this method can be called simply and the world is alright again.
},
// reloads a part of the page tree (useful when "expand" / "collapse")
load: function(params, isExpand, obj, scopeData, scopeHash) {
var $obj = $(obj);
......
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
import * as $ from 'jquery';
import ElementBrowser = require('./ElementBrowser');
/**
* Module: TYPO3/CMS/Recordlist/BrowseDatabase
* Database record selection
* @exports TYPO3/CMS/Recordlist/BrowseDatabase
*/
class BrowseDatabase {
constructor() {
$((): void => {
$('[data-close]').on('click', (event: JQueryEventObject): void => {
event.preventDefault();
const data = $(event.currentTarget).parents('span').data();
ElementBrowser.insertElement(
data.table,
data.uid,
'db',
data.title,
'',
'',
data.icon,
'',
parseInt($(event.currentTarget).data('close'), 10) === 1,
);
});
});
// adjust searchbox layout
const searchbox: HTMLElement = document.getElementById('db_list-searchbox-toolbar');
searchbox.style.display = 'block';
searchbox.style.position = 'relative';
}
}
export = new BrowseDatabase();
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
import * as $ from 'jquery';
import ElementBrowser = require('./ElementBrowser');
// Yes we really need this import, because Tree... is used in inline markup...
import Tree = require('TYPO3/CMS/Backend/LegacyTree');
interface LinkElement {
fileExt: string;
fileIcon: string;
fileName: string;
filePath: any;
table: string;
type: string;
uid: number;
}
interface LinkElementStorage {
[s: string]: LinkElement;
}
class BrowseFiles {
public static elements: LinkElementStorage;
public static File: File;
public static Selector: Selector;
constructor() {
// as long we use onclick attributes, we need the Tree component
Tree.noop();
BrowseFiles.File = new File();
BrowseFiles.Selector = new Selector();
$((): void => {
BrowseFiles.elements = $('body').data('elements');
$('[data-close]').on('click', (e: JQueryEventObject): void => {
e.preventDefault();
BrowseFiles.File.insertElement(
'file_' + $(e.currentTarget).data('fileIndex'),
parseInt($(e.currentTarget).data('close'), 10) === 1,
);
});
$('#t3js-importSelection').on('click', BrowseFiles.Selector.handle);
$('#t3js-toggleSelection').on('click', BrowseFiles.Selector.toggle);
});
}
}
class File {
/**
* @param {String} index
* @param {Boolean} close
*/
public insertElement(index: string, close?: boolean): boolean {
let result = false;
if (typeof BrowseFiles.elements[index] !== 'undefined') {
const element: LinkElement = BrowseFiles.elements[index];
result = ElementBrowser.insertElement(
element.table,
element.uid,
element.type,
element.fileName,
element.filePath,
element.fileExt,
element.fileIcon,
'',
close,
);
}
return result;
}
/**
* @param {Array} list
*/
public insertElementMultiple(list: Array<any>): void {
for (let i = 0, n = list.length; i < n; i++) {
if (typeof BrowseFiles.elements[list[i]] !== 'undefined') {
const element: LinkElement = BrowseFiles.elements[list[i]];
ElementBrowser.insertMultiple('sys_file', element.uid);
}
}
}
}
class Selector {
/**
* Toggle selection button is pressed
*
* @param {JQueryEventObject} e
*/
public toggle = (e: JQueryEventObject): void => {
e.preventDefault();
const items = this.getItems();
if (items.length) {
items.each((position: number, item: any): void => {
item.checked = (item.checked ? null : 'checked');
});
}
}
/**
* Import selection button is pressed
*
* @param {JQueryEventObject} e
*/
public handle = (e: JQueryEventObject): void => {
e.preventDefault();
const items: JQuery = this.getItems();
const selectedItems: Array<string> = [];
if (items.length) {
items.each((position: number, item: any): void => {
if (item.checked && item.name) {
selectedItems.push(item.name);
}
});
if (selectedItems.length > 0) {
if (ElementBrowser.hasActionMultipleCode) {
BrowseFiles.File.insertElementMultiple(selectedItems);
} else {
for (let i = 0; i < selectedItems.length; i++) {
BrowseFiles.File.insertElement(selectedItems[i]);
}
}
}
ElementBrowser.focusOpenerAndClose();
}
}
public getItems(): JQuery {
return $('#typo3-filelist').find('.typo3-bulk-item');
}
}
export = new BrowseFiles();
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
import * as $ from 'jquery';
import ElementBrowser = require('./ElementBrowser');
import Modal = require('TYPO3/CMS/Backend/Modal');
import Severity = require('TYPO3/CMS/Backend/Severity');
/**
* Module: TYPO3/CMS/Recordlist/BrowseFolders
* Folder selection
* @exports TYPO3/CMS/Recordlist/BrowseFolders
*/
class BrowseFolders {
constructor() {
$(() => {
$('[data-folder-id]').on('click', (event: JQueryEventObject): void => {
event.preventDefault();
const $element: JQuery = $(event.currentTarget);
const folderId = $element.data('folderId');
const close = parseInt($element.data('close'), 10) === 1;
ElementBrowser.insertElement('', folderId, 'folder', folderId, folderId, '', '', '', close);
});
$('.t3js-folderIdError').on('click', (event: JQueryEventObject): void => {
event.preventDefault();
Modal.confirm('', $(event.currentTarget).data('message'), Severity.error, [], []);
});
});
}
}
export = new BrowseFolders();
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
import * as $ from 'jquery';
import Modal = require('TYPO3/CMS/Backend/Modal');
interface RTESettings {
parameters: string;
configuration: string;
}
interface InlineSettings {
objectId: number;
checkUniqueAction: string;
addAction: string;
insertAction: string;
}
declare global {
interface Document {
list_frame: Window;
}
interface Window {
jumpToUrl: Function;
setFormValueFromBrowseWin: Function;
editform: any;
content: any;
group_change: any;
}
}
/**
* Module: TYPO3/CMS/Recordlist/ElementBrowser
* @exports TYPO3/CMS/Recordlist/ElementBrowser
* ElementBrowser communication with parent windows
*/
class ElementBrowser {
public hasActionMultipleCode: boolean = false;
private thisScriptUrl: string = '';
private mode: string = '';
private formFieldName: string = '';
private fieldReference: string = '';
private fieldReferenceSlashed: string = '';
private targetDoc: Window;
private elRef: Element;
private rte: RTESettings = {
parameters: '',
configuration: '',
};
private irre: InlineSettings = {
objectId: 0,
checkUniqueAction: '',
addAction: '',
insertAction: '',
};
constructor() {
$((): void => {
const data = $('body').data();
this.thisScriptUrl = data.thisScriptUrl;
this.mode = data.mode;
this.formFieldName = data.formFieldName;
this.fieldReference = data.fieldReference;
this.fieldReferenceSlashed = data.fieldReferenceSlashed;
this.rte.parameters = data.rteParameters;
this.rte.configuration = data.rteConfiguration;
this.irre.checkUniqueAction = data.irreCheckUniqueAction;
this.irre.addAction = data.irreAddAction;
this.irre.insertAction = data.irreInsertAction;
this.irre.objectId = data.irreObjectId;
this.hasActionMultipleCode = (this.irre.objectId > 0 && this.irre.insertAction !== '');
});
/**
* Global jumpTo function
*
* Used by tree implementation
*
* @param {String} URL
* @param {String} anchor
* @returns {Boolean}
*/
window.jumpToUrl = (URL: string, anchor?: string): boolean => {
if (URL.charAt(0) === '?') {
URL = this.thisScriptUrl + URL.substring(1);
}
const add_mode = URL.indexOf('mode=') === -1 ? '&mode=' + encodeURIComponent(this.mode) : '';
window.location.href = URL + add_mode + (typeof (anchor) === 'string' ? anchor : '');
return false;
};
}
public setReferences(): boolean {
if (this.getParent() && this.getParent().content && this.getParent().content.document.editform
&& this.getParent().content.document.editform[this.formFieldName]) {
this.targetDoc = this.getParent().content.document;
this.elRef = this.targetDoc.editform[this.formFieldName];
return true;
} else {
return false;
}
}
/**
* Dynamically calls a function on a given context object.
*/
public executeFunctionByName(functionName: string, context: any, ...args: Array<any>): any {
const namespaces = functionName.split('.');
const func = namespaces.pop();
for (let i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func].apply(context, args);
}
/**
* Returns the parent document object
*/
public getParent(): Window | null {
let opener: Window = null;
if (
typeof window.parent !== 'undefined' &&
typeof window.parent.document.list_frame !== 'undefined' &&
window.parent.document.list_frame.parent.document.querySelector('.t3js-modal-iframe') !== null
) {
opener = window.parent.document.list_frame;
} else if (
typeof window.parent !== 'undefined' &&
typeof window.parent.frames.list_frame !== 'undefined' &&
window.parent.frames.list_frame.parent.document.querySelector('.t3js-modal-iframe') !== null
) {
opener = window.parent.frames.list_frame;
} else if (
typeof window.frames !== 'undefined' &&
typeof window.frames.frameElement !== 'undefined' &&
window.frames.frameElement !== null &&
window.frames.frameElement.classList.contains('t3js-modal-iframe')
) {
opener = (<HTMLFrameElement>window.frames.frameElement).contentWindow.parent;
} else if (window.opener) {
opener = window.opener;
}
return opener;
}
public insertElement(
table: string,
uid: number,
type: string,
filename: string,
fp: string,
filetype: string,
imagefile: string,
action: string,
close: boolean,
): boolean {
let performAction = true;
// Call a check function in the opener window (e.g. for uniqueness handling):
if (this.irre.objectId && this.irre.checkUniqueAction) {
if (this.getParent()) {
const res = this.executeFunctionByName(this.irre.checkUniqueAction, this.getParent(), this.irre.objectId, table, uid, type);
if (!res.passed) {
if (res.message) {
alert(res.message);
}
performAction = false;
}
} else {
alert('Error - reference to main window is not set properly!');
this.focusOpenerAndClose();
}
}
// Call performing function and finish this action:
if (performAction) {
// Call helper function to manage data in the opener window:
if (this.irre.objectId && this.irre.addAction) {
if (this.getParent()) {
this.executeFunctionByName(
this.irre.addAction, this.getParent(), this.irre.objectId,
table, uid, type, this.fieldReferenceSlashed,
);
} else {
alert('Error - reference to main window is not set properly!');
this.focusOpenerAndClose();
}
}
if (this.irre.objectId && this.irre.insertAction) {
if (this.getParent()) {
this.executeFunctionByName(this.irre.insertAction, this.getParent(), this.irre.objectId, table, uid, type);
if (close) {
this.focusOpenerAndClose();
}
} else {
alert('Error - reference to main window is not set properly!');
if (close) {
this.focusOpenerAndClose();
}
}
} else if (this.fieldReference && !this.rte.parameters && !this.rte.configuration) {
this.addElement(filename, table + '_' + uid, fp, close);
} else {
if (
this.getParent() && this.getParent().content && this.getParent().content.document.editform
&& this.getParent().content.document.editform[this.formFieldName]
) {
this.getParent().group_change(
'add',
this.fieldReference,
this.rte.parameters,
this.rte.configuration,
this.targetDoc.editform[this.formFieldName],
this.getParent().content.document,
);
} else {
alert('Error - reference to main window is not set properly!');
}
if (close) {
this.focusOpenerAndClose();
}
}
}
return false;
}
public insertMultiple(table: string, uid: number): boolean {
let type = '';
if (this.irre.objectId && this.irre.insertAction) {
// Call helper function to manage data in the opener window:
if (this.getParent()) {
this.executeFunctionByName(
this.irre.insertAction + 'Multiple', this.getParent(),
this.irre.objectId, table, uid, type, this.fieldReference,
);
} else {
alert('Error - reference to main window is not set properly!');
this.focusOpenerAndClose();
}
}
return false;
}
public addElement(elName: string, elValue: string, altElValue: string, close: boolean): void {
if (this.getParent() && this.getParent().setFormValueFromBrowseWin) {
this.getParent().setFormValueFromBrowseWin(this.fieldReference, altElValue ? altElValue : elValue, elName);
if (close) {
this.focusOpenerAndClose();
}
} else {
alert('Error - reference to main window is not set properly!');
this.focusOpenerAndClose();
}
}
public focusOpenerAndClose = (): void => {
if (this.getParent()) {
this.getParent().focus();
}
Modal.dismiss();
close();
}
}
export = new ElementBrowser();
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
import * as $ from 'jquery';
/**
* Module: TYPO3/CMS/Recordlist/