6791aba261caf45d140bce850401c48a3abf2a9e
[Packages/TYPO3.CMS.git] / typo3 / sysext / lang / Resources / Public / JavaScript / LangModule.js
1 var languageModule = {
2
3 /**
4 * @var array
5 */
6 elementStack: [],
7
8 /**
9 * @var integer
10 */
11 errorCount: 0,
12
13 /**
14 * @var object
15 */
16 states: {
17 notAvailable: 0,
18 available: 1,
19 failed: 2,
20 ok: 3,
21 invalid: 4,
22 updated: 5
23 },
24
25 /**
26 * @var object
27 */
28 tableSetup: {
29 iDisplayLength: 1000,
30 bPaginate: false,
31 bSearch: false,
32 bInfo: false,
33 bFilter: false,
34 sScrollY: '96px',
35 aoColumnDefs: [{
36 bSortable: false,
37 aTargets: ['notSortable']
38 }],
39 "fnCookieCallback": function (sNameFile, oData, sExpires, sPath) {
40 // append mod.php to cookiePath to avoid sending cookie-data to images etc. without reason
41 return sNameFile + "=" + encodeURIComponent($.fn.dataTableExt.oApi._fnJsonString(oData)) + "; expires=" + sExpires +"; path=" + sPath + "mod.php";
42 }
43 },
44
45 /**
46 * @var jqXHR
47 */
48 currentRequest: null,
49
50 /**
51 * @var array
52 */
53 tables: new Array,
54
55 /**
56 * Initialize the language module
57 *
58 * @return void
59 */
60 initialize: function() {
61 // Initialize dataTable for selection and translation list
62 languageModule.tableSetup.sScrollY = languageModule.calculateTableHeight();
63 jQuery('.selectionList, .translationList').dataTable(languageModule.tableSetup);
64
65 // Prevent "jumping" style of the tables while generating
66 jQuery('.languageSelectionListContainer').css('visibility', 'visible');
67 jQuery('.translationUpdateListContainer').css('visibility', 'visible');
68
69 // Enable event handlers
70 languageModule.toggleEventHandlers('on');
71
72 // Resize tables on window resize
73 jQuery(window).resize(function() {
74 jQuery('div.dataTables_scrollBody').css('height', languageModule.calculateTableHeight());
75 });
76 },
77
78 /**
79 * Execute AJAX call for given cell of the translation matrix
80 *
81 * @param mixed cell The cell to process
82 * @return void
83 */
84 processCell: function(cell) {
85 // Initialize
86 var $cell = jQuery(cell);
87 languageModule.toggleEventHandlers('off');
88 languageModule.errorCount = 0;
89 $cell.html(jQuery('#stateIconChecking').html());
90
91 // Process AJAX call
92 languageModule.executeAjaxCall($cell.data('updateurl'), function(response, error) {
93 var state = 'Error';
94 if (error === undefined || error === null) {
95 var locale = $cell.data('locale');
96 if (!response.locales[locale].error) {
97 state = parseInt(response.locales[locale].state);
98 }
99 } else if (error === 'abort') {
100 languageModule.displayInformation('flashmessage.canceled');
101 languageModule.toggleEventHandlers('on');
102 return;
103 }
104 languageModule.updateCellState($cell, state);
105 languageModule.displaySuccess('flashmessage.updateComplete');
106 languageModule.toggleEventHandlers('on');
107 });
108 },
109
110 /**
111 * Execute AJAX calls for given rows of the translation matrix
112 *
113 * @param mixed rows Rows to process
114 * @return void
115 */
116 processRows: function(rows) {
117 // Intialize processing within first run
118 if (rows) {
119 languageModule.addElementsToStack(rows);
120 languageModule.toggleEventHandlers('off');
121 languageModule.errorCount = 0;
122 }
123
124 // Stop processing if stack is empty
125 if (languageModule.isStackEmpty()) {
126 languageModule.displaySuccess('flashmessage.updateComplete');
127 languageModule.toggleEventHandlers('on');
128 return;
129 }
130
131 // Find row to process
132 var $row = languageModule.getElementFromStack();
133 if ($row === null) {
134 languageModule.toggleEventHandlers('on');
135 return;
136 }
137
138 // Find all cells in row
139 var $cells = $row.find('.translationListCell');
140 $cells.html(jQuery('#stateIconChecking').html());
141
142 // Process AJAX call
143 languageModule.executeAjaxCall($row.data('updateurl'), function(response, error) {
144 if (error !== undefined && error !== null) {
145 $cells.html(jQuery('#stateIconError').html());
146 if (error === 'abort') {
147 languageModule.displayInformation('flashmessage.canceled');
148 languageModule.toggleEventHandlers('on');
149 return;
150 }
151 } else {
152 $cells.each(function(index, element) {
153 var $cell = jQuery(this);
154 var state = 'Error';
155 if (error === undefined || error === null) {
156 var locale = $cell.data('locale');
157 if (!response.locales[locale].error) {
158 state = parseInt(response.locales[locale].state);
159 }
160 }
161 languageModule.updateCellState($cell, state);
162 });
163 }
164 languageModule.processRows();
165 });
166 },
167
168 /**
169 * Update the state of a cell of the translation matrix
170 *
171 * @param mixed cell The cell to process
172 * @param string state Switch to this state
173 * @return void
174 */
175 updateCellState: function(cell, state) {
176 var $icon = jQuery('#stateIcon' + state);
177 if ($icon === undefined) {
178 $icon = jQuery('#stateIconError');
179 }
180 jQuery(cell)
181 .removeClass('languageStateNone')
182 .addClass('languageState' + state)
183 .html($icon.html());
184 },
185
186 /**
187 * Execute AJAX call
188 *
189 * @param string url The url to call
190 * @param string callback Callback function
191 * @param boolean ignoreErrors Ignore errors
192 * @return void
193 */
194 executeAjaxCall: function(url, callback, ignoreErrors) {
195 if (url === undefined || callback === undefined) {
196 return;
197 }
198 languageModule.currentRequest = jQuery.ajax({
199 url: url,
200 dataType: 'json',
201 cache: false,
202 success: function(response) {
203 callback(response);
204 },
205 error: function(response, status, error) {
206 if (ignoreErrors !== false && error !== 'abort') {
207 languageModule.errorCount++;
208 if (languageModule.errorCount >= 3) {
209 languageModule.displayError('flashmessage.multipleErrors');
210 languageModule.clearElementStack();
211 return;
212 } else {
213 languageModule.displayError(error);
214 }
215 }
216 callback(response, error);
217 }
218 });
219 },
220
221 /**
222 * Bind / unbind event handlers
223 *
224 * @param string action The value "on" or "off"
225 * @return void
226 */
227 toggleEventHandlers: function(action) {
228 var className = 'waiting';
229 var fadeSpeed = 150;
230 if (action === 'on') {
231 jQuery('.updateItem').on('click', languageModule.updateTranslations).removeClass(className);
232 jQuery('.cancelItem').off().fadeOut(fadeSpeed);
233 jQuery('.selectionList input, .selectionList label').off().parent().removeClass(className);
234 jQuery('.selectionList input:checkbox').on('change', languageModule.submitSelectionForm);
235 jQuery('.selectionList tr, .selectionList td').removeClass(className);
236 jQuery('.translationList tr, .translationList td').removeClass(className);
237 jQuery('.languageStateNone').on('click', function() {
238 languageModule.updateSingleTranslation(this);
239 });
240 } else {
241 jQuery('.updateItem').off().addClass(className);
242 jQuery('.cancelItem').on('click', languageModule.cancelProcess).fadeIn(fadeSpeed);
243 jQuery('.selectionList input:checkbox').off();
244 jQuery('.selectionList input, .selectionList label').on('click', function(event) {
245 event.preventDefault();
246 }).parent().addClass(className);
247 jQuery('.selectionList tr, .selectionList td').addClass(className);
248 jQuery('.translationList tr, .translationList td').addClass(className);
249 jQuery('.languageStateNone').off();
250 }
251 },
252
253 /**
254 * Display error flash message
255 *
256 * @param string label The label to show
257 * @return void
258 */
259 displayError: function(label) {
260 if (typeof label !== 'string' || label === '') {
261 return;
262 }
263 top.TYPO3.Flashmessage.display(
264 top.TYPO3.Severity.error,
265 TYPO3.l10n.localize('flashmessage.error'),
266 TYPO3.l10n.localize(label),
267 5
268 );
269 },
270
271 /**
272 * Display information flash message
273 *
274 * @param string label The label to show
275 * @return void
276 */
277 displayInformation: function(label) {
278 if (typeof label !== 'string' || label === '') {
279 return;
280 }
281 top.TYPO3.Flashmessage.display(
282 top.TYPO3.Severity.info,
283 TYPO3.l10n.localize('flashmessage.information'),
284 TYPO3.l10n.localize(label),
285 3
286 );
287 },
288
289 /**
290 * Display success flash message
291 *
292 * @param string label The label to show
293 * @return void
294 */
295 displaySuccess: function(label) {
296 if (typeof label !== 'string' || label === '') {
297 return;
298 }
299 top.TYPO3.Flashmessage.display(
300 top.TYPO3.Severity.ok,
301 TYPO3.l10n.localize('flashmessage.success'),
302 TYPO3.l10n.localize(label),
303 3
304 );
305 },
306
307 /**
308 * Calculate the height of data tables
309 *
310 * @return void
311 */
312 calculateTableHeight: function() {
313 var documentHeight = parseInt(jQuery(document).height());
314 var tableTop = parseInt(jQuery('.selectionList').offset().top);
315 var result = documentHeight - tableTop - 50;
316 return (result > 96 ? result : 96);
317 },
318
319 /**
320 * Submit language selection form
321 *
322 * @return void
323 */
324 submitSelectionForm: function() {
325 jQuery('form[name="languageSelectionForm"]').submit();
326 },
327
328 /**
329 * Update translations
330 *
331 * @return void
332 */
333 updateTranslations: function() {
334 languageModule.processRows('.translationListRow');
335 },
336
337 /**
338 * Update translation for a single element
339 *
340 * @param mixed element The element to process
341 * @return void
342 */
343 updateSingleTranslation: function(element) {
344 languageModule.processCell(element);
345 },
346
347 /**
348 * Cancel current process
349 *
350 * @return void
351 */
352 cancelProcess: function() {
353 languageModule.clearElementStack();
354 if (languageModule.currentRequest) {
355 languageModule.currentRequest.abort();
356 }
357 },
358
359 /**
360 * Fill call stack
361 *
362 * @param string elements Element identificator
363 * @return void
364 */
365 addElementsToStack: function(elements) {
366 jQuery(elements).each(function(i, element) {
367 languageModule.elementStack.push(element);
368 });
369 },
370
371 /**
372 * Get and remove first element from stack
373 *
374 * @return object The element
375 */
376 getElementFromStack: function() {
377 var element = languageModule.elementStack.shift();
378 if (element !== undefined) {
379 return jQuery(element);
380 }
381 return null;
382 },
383
384 /**
385 * Clear element stack
386 *
387 * @return void
388 */
389 clearElementStack: function() {
390 languageModule.elementStack = [];
391 },
392
393 /**
394 * Check if stack contains elements
395 *
396 * @return boolean False if empty
397 */
398 isStackEmpty: function() {
399 return languageModule.elementStack.length ? false : true;
400 }
401
402 }
403
404
405 /**
406 * Initialize when DOM is ready
407 */
408 jQuery(document).ready(function($) {
409 languageModule.initialize();
410 });