1d2bc79fe246c8a37a2ba25a2de00ce860fbbd83
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Resources / Public / JavaScript / Backend / FormManager / ViewModel.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/Form/Backend/FormManager/ViewModel
16 */
17 define(['jquery',
18 'TYPO3/CMS/Backend/Modal',
19 'TYPO3/CMS/Backend/Severity',
20 'TYPO3/CMS/Backend/Wizard',
21 'TYPO3/CMS/Backend/Icons',
22 'TYPO3/CMS/Backend/Notification'
23 ], function($, Modal, Severity, Wizard, Icons, Notification) {
24 'use strict';
25
26 return (function($, Modal, Severity, Wizard, Icons,Notification) {
27
28 /**
29 * @private
30 *
31 * @var object
32 */
33 var _formManagerApp = null;
34
35 /**
36 * @private
37 *
38 * @var object
39 */
40 var _domElementIdentifierCache = {};
41
42 /**
43 * @private
44 *
45 * @return void
46 */
47 function _domElementIdentifierCacheSetup() {
48 _domElementIdentifierCache = {
49 newFormModalTrigger: { identifier: '[data-identifier="newForm"]' },
50 duplicateFormModalTrigger: { identifier: '[data-identifier="duplicateForm"]' },
51 removeFormModalTrigger: { identifier: '[data-identifier="removeForm"]' },
52
53 newFormName: { identifier: '[data-identifier="newFormName"]' },
54 newFormSavePath: { identifier: '[data-identifier="newFormSavePath"]' },
55 advancedWizard: { identifier: '[data-identifier="advancedWizard"]' },
56 newFormPrototypeName: { identifier: '[data-identifier="newFormPrototypeName"]' },
57 newFormTemplate: { identifier: '[data-identifier="newFormTemplate"]' },
58
59 duplicateFormName: { identifier: '[data-identifier="duplicateFormName"]' },
60 duplicateFormSavePath: { identifier: '[data-identifier="duplicateFormSavePath"]' },
61
62 showReferences: { identifier: '[data-identifier="showReferences"]' },
63 referenceLink: { identifier: '[data-identifier="referenceLink"]' },
64
65 tooltip: { identifier: '[data-toggle="tooltip"]' }
66 }
67 };
68
69 /**
70 * @private
71 *
72 * @return void
73 * @throws 1477506500
74 * @throws 1477506501
75 * @throws 1477506502
76 */
77 function _newFormSetup() {
78 $(getDomElementIdentifier('newFormModalTrigger')).on('click', function(e) {
79 e.preventDefault();
80
81 /**
82 * Wizard step 1
83 */
84 Wizard.addSlide('new-form-step-1', TYPO3.lang['formManager.newFormWizard.step1.title'], '', Severity.info, function(slide) {
85 var advandecWizardHasOptions, folders, html, modal, nextButton, prototypes, savePathSelect, templates;
86
87 modal = Wizard.setup.$carousel.closest('.modal');
88 nextButton = modal.find('.modal-footer').find('button[name="next"]');
89
90 folders = _formManagerApp.getAccessibleFormStorageFolders();
91 if (folders.length === 0) {
92 html = '<div class="new-form-modal">'
93 + '<div class="form-horizontal">'
94 + '<div>'
95 + '<label class="control-label">' + TYPO3.lang['formManager.newFormWizard.step1.noStorages'] + '</label>'
96 + '</div>'
97 + '</div>'
98 + '</div>';
99
100 slide.html(html);
101 _formManagerApp.assert(false, 'No accessible form storage folders', 1477506500);
102 }
103
104 Wizard.set('savePath', folders[0]['value']);
105 if (folders.length > 1) {
106 savePathSelect = $('<select class="new-form-save-path form-control" data-identifier="newFormSavePath" />');
107 for (var i = 0, len = folders.length; i < len; ++i) {
108 var option = new Option(folders[i]['label'], folders[i]['value']);
109 $(savePathSelect).append(option);
110 }
111 }
112
113 prototypes = _formManagerApp.getPrototypes();
114
115 _formManagerApp.assert(prototypes.length > 0, 'No prototypes available', 1477506501);
116 Wizard.set('prototypeName', prototypes[0]['value']);
117
118 templates = _formManagerApp.getTemplatesForPrototype(prototypes[0]['value']);
119 _formManagerApp.assert(templates.length > 0, 'No templates available', 1477506502);
120 Wizard.set('templatePath', templates[0]['value']);
121
122 html = '<div class="new-form-modal">'
123 + '<div class="form-horizontal">'
124 + '<div>'
125 + '<label class="control-label">' + TYPO3.lang['formManager.form_name'] + '</label>'
126 + '<input class="new-form-name form-control has-error" data-identifier="newFormName" />';
127
128 if (savePathSelect) {
129 html += '<label class="control-label">' + TYPO3.lang['formManager.form_save_path'] + '</label>' + $(savePathSelect)[0].outerHTML;
130 }
131
132 if (prototypes.length > 1 || templates.length > 1) {
133 html += '<label class="control-label">' + TYPO3.lang['formManager.newFormWizard.step1.advanced'] + '</label>'
134 + '<div class="t3-form-controls"><input type="checkbox" class="new-form-advance-wizard" data-identifier="advancedWizard" /></div>';
135 }
136
137 html += '</div>'
138 + '</div>'
139 + '</div>';
140
141 slide.html(html);
142 $(getDomElementIdentifier('newFormName'), modal).focus();
143
144 $(getDomElementIdentifier('newFormName'), modal).on('keyup paste', function(e) {
145 if ($(this).val().length > 0) {
146 $(this).removeClass('has-error');
147 Wizard.unlockNextStep();
148 Wizard.set('formName', $(this).val());
149 } else {
150 $(this).addClass('has-error');
151 Wizard.lockNextStep();
152 }
153 });
154
155 $(getDomElementIdentifier('newFormSavePath'), modal).on('change', function(e) {
156 Wizard.set('savePath', $(getDomElementIdentifier('newFormSavePath') + ' option:selected', modal).val());
157 });
158
159 $(getDomElementIdentifier('advancedWizard'), modal).on('change', function(e) {
160 if ($(this).is(':checked')) {
161 Wizard.set('advancedWizard', true);
162 } else {
163 Wizard.set('advancedWizard', false);
164 }
165 });
166
167 nextButton.on('click', function() {
168 Wizard.setup.forceSelection = false;
169 Icons.getIcon('spinner-circle-dark', Icons.sizes.large, null, null).done(function(markup) {
170 slide.html($('<div />', {class: 'text-center'}).append(markup));
171 });
172 });
173 });
174
175 /**
176 * Wizard step 2
177 */
178 Wizard.addSlide('new-form-step-2', TYPO3.lang['formManager.newFormWizard.step2.title'], '', Severity.info, function(slide, settings) {
179 var addOnTemplateChangeEvents, html, modal, nextButton, prototypes, prototypeNameSelect, templates, templateSelect;
180
181 if (settings['advancedWizard'] !== true) {
182 Wizard.unlockNextStep().trigger('click');
183 return;
184 }
185
186 modal = Wizard.setup.$carousel.closest('.modal');
187 nextButton = modal.find('.modal-footer').find('button[name="next"]');
188
189 prototypeNameSelect = $('<select class="new-form-prototype-name form-control" data-identifier="newFormPrototypeName" />');
190 templateSelect = $('<select class="new-form-template form-control" data-identifier="newFormTemplate" />');
191
192 prototypes = _formManagerApp.getPrototypes();
193 templates = {};
194 if (prototypes.length > 0) {
195 for (var i = 0, len = prototypes.length; i < len; ++i) {
196 var option = new Option(prototypes[i]['label'], prototypes[i]['value']);
197 $(prototypeNameSelect).append(option);
198 }
199
200 templates = _formManagerApp.getTemplatesForPrototype(prototypes[0]['value']);
201 for (var i = 0, len = templates.length; i < len; ++i) {
202 var option = new Option(templates[i]['label'], templates[i]['value']);
203 $(templateSelect).append(option);
204 }
205 }
206
207 html = '<div class="new-form-modal">'
208 + '<div class="form-horizontal">'
209 + '<div>';
210
211 if (prototypes.length > 1) {
212 html += '<label class="control-label">' + TYPO3.lang['formManager.form_prototype'] + '</label>' + $(prototypeNameSelect)[0].outerHTML;
213 }
214 if (templates.length > 1) {
215 html += '<label class="control-label">' + TYPO3.lang['formManager.form_template'] + '</label>' + $(templateSelect)[0].outerHTML;
216 }
217
218 html += '</div>'
219 + '</div>'
220 + '</div>';
221
222 slide.html(html);
223 if (prototypes.length > 1) {
224 $(getDomElementIdentifier('newFormPrototypeName'), modal).focus();
225 } else if (templates.length > 1) {
226 $(getDomElementIdentifier('newFormTemplate'), modal).focus();
227 }
228
229 addOnTemplateChangeEvents = function() {
230 $(getDomElementIdentifier('newFormTemplate'), modal).on('change', function(e) {
231 Wizard.set('templatePath', $(getDomElementIdentifier('newFormTemplate') + ' option:selected', modal).val());
232 });
233 };
234
235 $(getDomElementIdentifier('newFormPrototypeName'), modal).on('change', function(e) {
236 Wizard.set('prototypeName', $(this).val());
237 templates = _formManagerApp.getTemplatesForPrototype($(this).val());
238 $(getDomElementIdentifier('newFormTemplate'), modal).off().empty();
239 for (var i = 0, len = templates.length; i < len; ++i) {
240 var option = new Option(templates[i]['label'], templates[i]['value']);
241 $(getDomElementIdentifier('newFormTemplate'), modal).append(option);
242 Wizard.set('templatePath', templates[0]['value']);
243 }
244 addOnTemplateChangeEvents();
245 });
246
247 addOnTemplateChangeEvents();
248
249 nextButton.on('click', function() {
250 Icons.getIcon('spinner-circle-dark', Icons.sizes.large, null, null).done(function(markup) {
251 slide.html($('<div />', {class: 'text-center'}).append(markup));
252 });
253 });
254 });
255
256 /**
257 * Wizard step 3
258 */
259 Wizard.addSlide('new-form-step-3', TYPO3.lang['formManager.newFormWizard.step3.title'], TYPO3.lang['formManager.newFormWizard.step3.message'], Severity.info);
260
261 /**
262 * Wizard step 4
263 */
264 Wizard.addFinalProcessingSlide(function() {
265 $.post(_formManagerApp.getAjaxEndpoint('create'), {
266 tx_form_web_formformbuilder: {
267 formName: Wizard.setup.settings['formName'],
268 templatePath: Wizard.setup.settings['templatePath'],
269 prototypeName: Wizard.setup.settings['prototypeName'],
270 savePath: Wizard.setup.settings['savePath']
271 }
272 }, function(data, textStatus, jqXHR) {
273 document.location = data;
274 Wizard.dismiss();
275 }).fail(function(jqXHR, textStatus, errorThrown) {
276 Notification.error(textStatus, errorThrown, 2);
277 Wizard.dismiss();
278 });
279 }).done(function() {
280 Wizard.show();
281 });
282 });
283 };
284
285 /**
286 * @private
287 *
288 * @return void
289 */
290 function _removeFormSetup() {
291 $(getDomElementIdentifier('removeFormModalTrigger')).on('click', function(e) {
292 var modalButtons = [], that;
293
294 e.preventDefault();
295 that = $(this)
296
297 modalButtons.push({
298 text: TYPO3.lang['formManager.cancel'],
299 active: true,
300 btnClass: 'btn-default',
301 name: 'cancel',
302 trigger: function () {
303 Modal.currentModal.trigger('modal-dismiss');
304 }
305 });
306
307 modalButtons.push({
308 text: TYPO3.lang['formManager.remove_form'],
309 active: true,
310 btnClass: 'btn-warning',
311 name: 'createform',
312 trigger: function () {
313 document.location = _formManagerApp.getAjaxEndpoint('delete') + '&tx_form_web_formformbuilder[formPersistenceIdentifier]=' + that.data('formPersistenceIdentifier');
314 Modal.currentModal.trigger('modal-dismiss');
315 }
316 });
317
318 Modal.show(
319 TYPO3.lang['formManager.remove_form_title'],
320 TYPO3.lang['formManager.remove_form_message'],
321 Severity.warning,
322 modalButtons
323 );
324 });
325 };
326
327 /**
328 * @private
329 *
330 * @return void
331 * @throws 1477649539
332 */
333 function _duplicateFormSetup() {
334 $(getDomElementIdentifier('duplicateFormModalTrigger')).on('click', function(e) {
335 var that;
336
337 e.preventDefault();
338 that = $(this);
339
340 /**
341 * Wizard step 1
342 */
343 Wizard.addSlide('duplicate-form-step-1', TYPO3.lang['formManager.duplicateFormWizard.step1.title'].replace('{0}', that.data('formName')), '', Severity.info, function(slide) {
344 var folders, html, modal, nextButton, savePathSelect;
345
346 modal = Wizard.setup.$carousel.closest('.modal');
347 nextButton = modal.find('.modal-footer').find('button[name="next"]');
348
349 folders = _formManagerApp.getAccessibleFormStorageFolders();
350 _formManagerApp.assert(folders.length > 0, 'No accessible form storage folders', 1477649539);
351
352 Wizard.set('formPersistenceIdentifier', that.data('formPersistenceIdentifier'));
353 Wizard.set('savePath', folders[0]['value']);
354 if (folders.length > 1) {
355 savePathSelect = $('<select class="duplicate-form-save-path form-control" data-identifier="duplicateFormSavePath" />');
356 for (var i = 0, len = folders.length; i < len; ++i) {
357 var option = new Option(folders[i]['label'], folders[i]['value']);
358 $(savePathSelect).append(option);
359 }
360 }
361
362 html = '<div class="duplicate-form-modal">'
363 + '<div class="form-horizontal">'
364 + '<div>'
365 + '<label class="control-label">' + TYPO3.lang['formManager.new_form_name'] + '</label>'
366 + '<input class="duplicate-form-name form-control has-error" data-identifier="duplicateFormName" />';
367
368 if (savePathSelect) {
369 html += '<label class="control-label">' + TYPO3.lang['formManager.form_save_path'] + '</label>' + $(savePathSelect)[0].outerHTML;
370 }
371
372 html += '</div>'
373 + '</div>'
374 + '</div>';
375
376 slide.html(html);
377 $(getDomElementIdentifier('duplicateFormName'), modal).focus();
378
379 $(getDomElementIdentifier('duplicateFormName'), modal).on('keyup paste', function(e) {
380 if ($(this).val().length > 0) {
381 $(this).removeClass('has-error');
382 Wizard.unlockNextStep();
383 Wizard.set('formName', $(this).val());
384 } else {
385 $(this).addClass('has-error');
386 Wizard.lockNextStep();
387 }
388 });
389
390 $(getDomElementIdentifier('duplicateFormSavePath'), modal).on('change', function(e) {
391 Wizard.set('savePath', $(getDomElementIdentifier('duplicateFormSavePath') + ' option:selected', modal).val());
392 });
393 });
394
395 /**
396 * Wizard step 2
397 */
398 Wizard.addFinalProcessingSlide(function() {
399 $.post(_formManagerApp.getAjaxEndpoint('duplicate'), {
400 tx_form_web_formformbuilder: {
401 formName: Wizard.setup.settings['formName'],
402 formPersistenceIdentifier: Wizard.setup.settings['formPersistenceIdentifier'],
403 savePath: Wizard.setup.settings['savePath']
404 }
405 }, function(data, textStatus, jqXHR) {
406 document.location = data;
407 Wizard.dismiss();
408 }).fail(function(jqXHR, textStatus, errorThrown) {
409 Notification.error(textStatus, errorThrown, 2);
410 Wizard.dismiss();
411 });
412 }).done(function() {
413 Wizard.show();
414 });
415 });
416 };
417
418 /**
419 * @private
420 *
421 * @return void
422 */
423 function _showReferencesSetup() {
424 $(getDomElementIdentifier('showReferences')).on('click', function(e) {
425 var that, url;
426
427 e.preventDefault();
428 that = this;
429 url = _formManagerApp.getAjaxEndpoint('references') + '&tx_form_web_formformbuilder[formPersistenceIdentifier]=' + $(this).data('formPersistenceIdentifier');
430
431 $.get(url, function(data, textStatus, jqXHR) {
432 var html, modalButtons = [], referencesLength;
433
434 modalButtons.push({
435 text: TYPO3.lang['formManager.cancel'],
436 active: true,
437 btnClass: 'btn-default',
438 name: 'cancel',
439 trigger: function () {
440 Modal.currentModal.trigger('modal-dismiss');
441 }
442 });
443
444 referencesLength = data['references'].length;
445 if (referencesLength > 0) {
446 html = '<div>'
447 + '<h3>' + TYPO3.lang['formManager.references.headline'].replace('{0}', $(that).data('formName')) + '</h3>'
448 + '</div>'
449 + '<div class="table-fit">'
450 + '<table id="forms" class="table table-striped table-condensed">'
451 + '<thead>'
452 + '<tr>'
453 + '<th>' + TYPO3.lang['formManager.page'] + '</th>'
454 + '<th>' + TYPO3.lang['formManager.record'] + '</th>'
455 + '</tr>'
456 + '</thead>'
457 + '<tbody>';
458
459 for (var i = 0, len = data['references'].length; i < len; ++i) {
460 html += '<tr>'
461 + '<td>' + data['references'][i]['recordPageTitle'] + '</td>'
462 + '<td>'
463 + data['references'][i]['recordIcon']
464 + '<a href="' + data['references'][i]['recordEditUrl'] + '" data-identifier="referenceLink">'
465 + data['references'][i]['recordTitle'] + ' (uid: ' + data['references'][i]['recordUid'] + ')'
466 + '</a>'
467 + '</td>'
468 + '</tr>';
469 }
470
471 html += '</tbody>'
472 + '</table>'
473 + '</div>';
474 } else {
475 html = '<div>'
476 + '<h1>' + TYPO3.lang['formManager.references.title'].replace('{0}', data['formPersistenceIdentifier']) + '</h1>'
477 + '</div>'
478 + '<div>' + TYPO3.lang['formManager.no_references'] + '</div>';
479 }
480
481 html = $(html);
482 $(getDomElementIdentifier('referenceLink'), html).on('click', function(e) {
483 e.preventDefault();
484 Modal.currentModal.trigger('modal-dismiss');
485 document.location = $(this).prop('href');
486 });
487
488 Modal.show(
489 TYPO3.lang['formManager.references.title'],
490 html,
491 Severity.info,
492 modalButtons
493 );
494 }).fail(function(jqXHR, textStatus, errorThrown) {
495 if (jqXHR.status !== 0) {
496 Notification.error(textStatus, errorThrown, 2);
497 }
498 });
499 });
500 };
501
502 /**
503 * @public
504 *
505 * @param string elementIdentifier
506 * @param string type
507 * @return mixed|undefined
508 * @throws 1477506413
509 * @throws 1477506414
510 */
511 function getDomElementIdentifier(elementIdentifier, type) {
512 _formManagerApp.assert(elementIdentifier.length > 0, 'Invalid parameter "elementIdentifier"', 1477506413);
513 _formManagerApp.assert(typeof _domElementIdentifierCache[elementIdentifier] !== "undefined", 'elementIdentifier "' + elementIdentifier + '" does not exist', 1477506414);
514 if (typeof type === "undefined") {
515 type = 'identifier';
516 }
517
518 return _domElementIdentifierCache[elementIdentifier][type] || undefined;
519 };
520
521 /**
522 * @public
523 *
524 * @param object formManagerApp
525 * @return void
526 */
527 function bootstrap(formManagerApp) {
528 _formManagerApp = formManagerApp;
529 _domElementIdentifierCacheSetup();
530 _removeFormSetup();
531 _newFormSetup();
532 _duplicateFormSetup();
533 _showReferencesSetup();
534 $(getDomElementIdentifier('tooltip')).tooltip();
535 };
536
537 /**
538 * Publish the public methods.
539 * Implements the "Revealing Module Pattern".
540 */
541 return {
542 bootstrap: bootstrap,
543 };
544 })($, Modal, Severity, Wizard, Icons, Notification);
545 });