9013950b8f3543a6ea406a5f3066240259c1e075
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Resources / Private / TypeScript / Localization.ts
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 import {SeverityEnum} from './Enum/Severity';
15 import * as $ from 'jquery';
16 import Icons = require('./Icons');
17 import Wizard = require('TYPO3/CMS/Backend/Wizard');
18
19 type LanguageRecord = {
20 uid: number;
21 title: string;
22 flagIcon: string;
23 };
24
25 type SummaryColumns = {
26 columns: { [key: number]: string };
27 columnList: Array<number>;
28 };
29
30 type SummaryColPosRecord = {
31 uid: number;
32 title: string;
33 icon: string;
34 };
35
36 type SummaryRecord = {
37 columns: SummaryColumns;
38 records: Array<Array<SummaryColPosRecord>>;
39 };
40
41 class Localization {
42 private triggerButton: string = '.t3js-localize';
43 private localizationMode: string = null;
44 private sourceLanguage: number = null;
45 private records: Array<any> = [];
46
47 constructor() {
48 $((): void => {
49 this.initialize();
50 });
51 }
52
53 private initialize(): void {
54 const me = this;
55 Icons.getIcon('actions-localize', Icons.sizes.large).done((localizeIconMarkup: string): void => {
56 Icons.getIcon('actions-edit-copy', Icons.sizes.large).done((copyIconMarkup: string): void => {
57 $(me.triggerButton).removeClass('disabled');
58
59 $(document).on('click', me.triggerButton, (e: JQueryEventObject): void => {
60 e.preventDefault();
61
62 const $triggerButton = $(e.currentTarget);
63 const actions: Array<string> = [];
64 let slideStep1: string = '';
65
66 if ($triggerButton.data('allowTranslate')) {
67 actions.push(
68 '<div class="row">'
69 + '<div class="btn-group col-sm-3">'
70 + '<label class="btn btn-block btn-default t3js-localization-option" data-helptext=".t3js-helptext-translate">'
71 + localizeIconMarkup
72 + '<input type="radio" name="mode" id="mode_translate" value="localize" style="display: none">'
73 + '<br>Translate</label>'
74 + '</div>'
75 + '<div class="col-sm-9">'
76 + '<p class="t3js-helptext t3js-helptext-translate text-muted">' + TYPO3.lang['localize.educate.translate'] + '</p>'
77 + '</div>'
78 + '</div>'
79 );
80 }
81
82 if ($triggerButton.data('allowCopy')) {
83 actions.push(
84 '<div class="row">'
85 + '<div class="col-sm-3 btn-group">'
86 + '<label class="btn btn-block btn-default t3js-localization-option" data-helptext=".t3js-helptext-copy">'
87 + copyIconMarkup
88 + '<input type="radio" name="mode" id="mode_copy" value="copyFromLanguage" style="display: none">'
89 + '<br>Copy</label>'
90 + '</div>'
91 + '<div class="col-sm-9">'
92 + '<p class="t3js-helptext t3js-helptext-copy text-muted">' + TYPO3.lang['localize.educate.copy'] + '</p>'
93 + '</div>'
94 + '</div>'
95 );
96 }
97
98 slideStep1 += '<div data-toggle="buttons">' + actions.join('<hr>') + '</div>';
99 Wizard.addSlide(
100 'localize-choose-action',
101 TYPO3.lang['localize.wizard.header_page']
102 .replace('{0}', $triggerButton.data('page'))
103 .replace('{1}', $triggerButton.data('languageName')),
104 slideStep1,
105 SeverityEnum.info
106 );
107 Wizard.addSlide(
108 'localize-choose-language',
109 TYPO3.lang['localize.view.chooseLanguage'],
110 '',
111 SeverityEnum.info,
112 ($slide: JQuery): void => {
113 Icons.getIcon('spinner-circle-dark', Icons.sizes.large).done((markup: string): void => {
114 $slide.html('<div class="text-center">' + markup + '</div>');
115
116 this.loadAvailableLanguages(
117 parseInt($triggerButton.data('pageId'), 10),
118 parseInt($triggerButton.data('languageId'), 10)
119 ).done((result: Array<LanguageRecord>): void => {
120 if (result.length === 1) {
121 // We only have one result, auto select the record and continue
122 this.sourceLanguage = result[0].uid;
123 Wizard.unlockNextStep().trigger('click');
124 return;
125 }
126
127 Wizard.getComponent().on('click', '.t3js-language-option', (optionEvt: JQueryEventObject): void => {
128 const $me = $(optionEvt.currentTarget);
129 const $radio = $me.find('input[type="radio"]');
130
131 this.sourceLanguage = $radio.val();
132 console.log('Localization.ts@132', this.sourceLanguage);
133 Wizard.unlockNextStep();
134 });
135
136 const $languageButtons = $('<div />', {class: 'row', 'data-toggle': 'buttons'});
137
138 for (const languageObject of result) {
139 $languageButtons.append(
140 $('<div />', {class: 'col-sm-4'}).append(
141 $('<label />', {class: 'btn btn-default btn-block t3js-language-option option'})
142 .text(' ' + languageObject.title)
143 .prepend(languageObject.flagIcon)
144 .prepend(
145 $('<input />', {
146 type: 'radio',
147 name: 'language',
148 id: 'language' + languageObject.uid,
149 value: languageObject.uid,
150 style: 'display: none;'
151 }
152 )
153 )
154 )
155 );
156 }
157 $slide.empty().append($languageButtons);
158 });
159 });
160 }
161 );
162 Wizard.addSlide(
163 'localize-summary',
164 TYPO3.lang['localize.view.summary'],
165 '',
166 SeverityEnum.info, ($slide: JQuery): void => {
167 Icons.getIcon('spinner-circle-dark', Icons.sizes.large).done((markup: string): void => {
168 $slide.html('<div class="text-center">' + markup + '</div>');
169 });
170 this.getSummary(
171 parseInt($triggerButton.data('pageId'), 10),
172 parseInt($triggerButton.data('languageId'), 10)
173 ).done((result: SummaryRecord): void => {
174 $slide.empty();
175 this.records = [];
176
177 const columns = result.columns.columns;
178 const columnList = result.columns.columnList;
179
180 columnList.forEach((colPos: number): void => {
181 if (typeof result.records[colPos] === 'undefined') {
182 return;
183 }
184
185 const column = columns[colPos];
186 const $row = $('<div />', {class: 'row'});
187
188 result.records[colPos].forEach((record: SummaryColPosRecord): void => {
189 const label = ' (' + record.uid + ') ' + record.title;
190 this.records.push(record.uid);
191
192 $row.append(
193 $('<div />', {'class': 'col-sm-6'}).append(
194 $('<div />', {'class': 'input-group'}).append(
195 $('<span />', {'class': 'input-group-addon'}).append(
196 $('<input />', {
197 type: 'checkbox',
198 'class': 't3js-localization-toggle-record',
199 id: 'record-uid-' + record.uid,
200 checked: 'checked',
201 'data-uid': record.uid,
202 'aria-label': label
203 })
204 ),
205 $('<label />', {
206 'class': 'form-control',
207 for: 'record-uid-' + record.uid
208 }).text(label).prepend(record.icon)
209 )
210 )
211 );
212 });
213
214 $slide.append(
215 $('<fieldset />', {
216 'class': 'localization-fieldset'
217 }).append(
218 $('<label />').text(column).prepend(
219 $('<input />', {
220 'class': 't3js-localization-toggle-column',
221 type: 'checkbox',
222 checked: 'checked'
223 })
224 ),
225 $row
226 )
227 );
228 });
229
230 Wizard.unlockNextStep();
231
232 Wizard.getComponent().on('change', '.t3js-localization-toggle-record', (cmpEvt: JQueryEventObject): void => {
233 const $me = $(cmpEvt.currentTarget);
234 const uid = $me.data('uid');
235 const $parent = $me.closest('fieldset');
236 const $columnCheckbox = $parent.find('.t3js-localization-toggle-column');
237
238 if ($me.is(':checked')) {
239 this.records.push(uid);
240 } else {
241 const index = this.records.indexOf(uid);
242 if (index > -1) {
243 this.records.splice(index, 1);
244 }
245 }
246
247 const $allChildren = $parent.find('.t3js-localization-toggle-record');
248 const $checkedChildren = $parent.find('.t3js-localization-toggle-record:checked');
249
250 $columnCheckbox.prop('checked', $checkedChildren.length > 0);
251 $columnCheckbox.prop('indeterminate', $checkedChildren.length > 0 && $checkedChildren.length < $allChildren.length);
252
253 if (this.records.length > 0) {
254 Wizard.unlockNextStep();
255 } else {
256 Wizard.lockNextStep();
257 }
258 }).on('change', '.t3js-localization-toggle-column', (toggleEvt): void => {
259 const $me = $(toggleEvt.currentTarget);
260 const $children = $me.closest('fieldset').find('.t3js-localization-toggle-record');
261
262 $children.prop('checked', $me.is(':checked'));
263 $children.trigger('change');
264 });
265 });
266 }
267 );
268
269 Wizard.addFinalProcessingSlide((): void => {
270 this.localizeRecords(
271 parseInt($triggerButton.data('pageId'), 10),
272 parseInt($triggerButton.data('languageId'), 10),
273 this.records
274 ).done((): void => {
275 Wizard.dismiss();
276 document.location.reload();
277 });
278 }).done((): void => {
279 Wizard.show();
280
281 Wizard.getComponent().on('click', '.t3js-localization-option', (optionEvt: JQueryEventObject): void => {
282 const $me = $(optionEvt.currentTarget);
283 const $radio = $me.find('input[type="radio"]');
284
285 if ($me.data('helptext')) {
286 const $container = $(optionEvt.delegateTarget);
287 $container.find('.t3js-helptext').addClass('text-muted');
288 $container.find($me.data('helptext')).removeClass('text-muted');
289 }
290 this.localizationMode = $radio.val();
291 Wizard.unlockNextStep();
292 });
293 });
294 });
295 });
296 });
297 }
298
299 /**
300 * Load available languages from page
301 *
302 * @param {number} pageId
303 * @param {number} languageId
304 * @returns {JQueryXHR}
305 */
306 private loadAvailableLanguages(pageId: number, languageId: number): JQueryXHR {
307 return $.ajax({
308 url: TYPO3.settings.ajaxUrls.page_languages,
309 data: {
310 pageId: pageId,
311 languageId: languageId
312 }
313 });
314 }
315
316 /**
317 * Get summary for record processing
318 *
319 * @param {number} pageId
320 * @param {number} languageId
321 * @returns {JQueryXHR}
322 */
323 private getSummary(pageId: number, languageId: number): JQueryXHR {
324 return $.ajax({
325 url: TYPO3.settings.ajaxUrls.records_localize_summary,
326 data: {
327 pageId: pageId,
328 destLanguageId: languageId,
329 languageId: this.sourceLanguage
330 }
331 });
332 }
333
334 /**
335 * Localize records
336 *
337 * @param {number} pageId
338 * @param {number} languageId
339 * @param {Array<number>} uidList
340 * @returns {JQueryXHR}
341 */
342 private localizeRecords(pageId: number, languageId: number, uidList: Array<number>): JQueryXHR {
343 return $.ajax({
344 url: TYPO3.settings.ajaxUrls.records_localize,
345 data: {
346 pageId: pageId,
347 srcLanguageId: this.sourceLanguage,
348 destLanguageId: languageId,
349 action: this.localizationMode,
350 uidList: uidList
351 }
352 });
353 }
354 }
355
356 export = new Localization();