ea373784d3c5114797cf7f10c67e27623e37b1b5
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Resources / Public / JavaScript / Backend / FormEditor.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/FormEditor
16 */
17 define(['jquery',
18 'TYPO3/CMS/Form/Backend/FormEditor/Core'
19 ], function($, core) {
20 'use strict';
21
22 /**
23 * Return a static method named "getInstance".
24 * Use this method to create the formeditor app.
25 */
26 return (function(_core) {
27
28 /**
29 * @private
30 *
31 * Hold the instance (Singleton Pattern)
32 */
33 var _formEditorInstance = null;
34
35 /**
36 * @public
37 *
38 * @param object _configuration
39 * @param object _mediator
40 * @param object _viewModel
41 * @return object
42 */
43 function FormEditor(_configuration, _mediator, _viewModel) {
44
45 /**
46 * @private
47 *
48 * @var bool
49 */
50 var _isRunning = false;
51
52 /**
53 * @private
54 *
55 * @var bool
56 */
57 var _unsavedContent = false;
58
59 /**
60 * @private
61 *
62 * @var bool
63 */
64 var _previewMode = false;
65
66 /**
67 * @public
68 *
69 * @return object
70 */
71 function getPublisherSubscriber() {
72 return _core.getPublisherSubscriber();
73 };
74
75 /**
76 * @public
77 *
78 * @return void
79 */
80 function _saveApplicationState() {
81
82 _getApplicationStateStack().addAndReset({
83 formDefinition: _getApplicationStateStack().getCurrentState('formDefinition').clone(),
84 currentlySelectedPageIndex: _getApplicationStateStack().getCurrentState('currentlySelectedPageIndex'),
85 currentlySelectedFormElementIdentifierPath: _getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath')
86 });
87 };
88
89 /**
90 * @public
91 *
92 * @return void
93 */
94 function undoApplicationState() {
95 _getApplicationStateStack().incrementCurrentStackPointer();
96 };
97
98 /**
99 * @public
100 *
101 * @return void
102 */
103 function redoApplicationState() {
104 _getApplicationStateStack().decrementCurrentStackPointer();
105 };
106
107 /**
108 * @public
109 *
110 * @return int
111 */
112 function getMaximalApplicationStates() {
113 return _getApplicationStateStack().getMaximalStackSize();
114 };
115
116 /**
117 * @public
118 *
119 * @return int
120 */
121 function getCurrentApplicationStates() {
122 return _getApplicationStateStack().getCurrentStackSize();
123 };
124
125 /**
126 * @public
127 *
128 * @return int
129 */
130 function getCurrentApplicationStatePosition() {
131 return _getApplicationStateStack().getCurrentStackPointer();
132 };
133
134 /**
135 * @internal
136 *
137 * @return void
138 * @throws 1519855175
139 */
140 function setFormDefinition(formDefinition) {
141 assert('object' === $.type(formDefinition), 'Invalid parameter "formDefinition"', 1519855175);
142 _getApplicationStateStack().setCurrentState('formDefinition', _getFactory().createFormElement(formDefinition, undefined, undefined, true));
143 };
144
145 /**
146 * @public
147 *
148 * @param string type
149 * @return object
150 * @throws 1475378543
151 */
152 function getRunningAjaxRequest(type) {
153 assert(getUtility().isNonEmptyString(type), 'Invalid parameter "type"', 1475378543);
154 return _core.getRunningAjaxRequest(type);
155 };
156
157 /**
158 * @public
159 *
160 * @return object
161 */
162 function getUtility() {
163 return _core.getUtility();
164 };
165
166 /**
167 * @public
168 *
169 * @param mixed test
170 * @param string message
171 * @param int messageCode
172 * @return void
173 */
174 function assert(test, message, messageCode) {
175 getUtility().assert(test, message, messageCode);
176 };
177
178 /**
179 * @public
180 *
181 * @param string propertyPath
182 * @param string collectionElementIdentifier
183 * @param string collectionName
184 * @param object formElement
185 * @param boolean allowEmptyReturnValue
186 * @return string
187 */
188 function buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue) {
189 if (getUtility().isUndefinedOrNull(formElement)) {
190 formElement = getCurrentlySelectedFormElement();
191 }
192 formElement = _getRepository().findFormElement(formElement);
193 return getUtility().buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue);
194 };
195
196 /**
197 * @public
198 *
199 * @param string validatorIdentifier
200 * @param function func
201 * @return void
202 */
203 function addPropertyValidationValidator(validatorIdentifier, func) {
204 _getPropertyValidationService().addValidator(validatorIdentifier, func);
205 };
206
207 /**
208 * @public
209 *
210 * @param string propertyPath
211 * @return object
212 */
213 function validateCurrentlySelectedFormElementProperty(propertyPath) {
214 return validateFormElementProperty(
215 getCurrentlySelectedFormElement(),
216 propertyPath
217 );
218 };
219
220 /**
221 * @public
222 *
223 * @param object formElement
224 * @param string propertyPath
225 * @return object
226 */
227 function validateFormElementProperty(formElement, propertyPath) {
228 formElement = _getRepository().findFormElement(formElement);
229 return _getPropertyValidationService().validateFormElementProperty(formElement, propertyPath);
230 };
231
232 /**
233 * @public
234 *
235 * @param object formElement
236 * @return object
237 */
238 function validateFormElement(formElement) {
239 formElement = _getRepository().findFormElement(formElement);
240 return _getPropertyValidationService().validateFormElement(formElement);
241 };
242
243 /**
244 * @public
245 *
246 * @param object validationResults
247 * @return boolean
248 */
249 function validationResultsHasErrors(validationResults) {
250 return _getPropertyValidationService().validationResultsHasErrors(validationResults);
251 };
252
253 /**
254 * @public
255 *
256 * @param object formElement
257 * @param boolean returnAfterFirstMatch
258 * @return object
259 */
260 function validateFormElementRecursive(formElement, returnAfterFirstMatch) {
261 formElement = _getRepository().findFormElement(formElement);
262 return _getPropertyValidationService().validateFormElementRecursive(formElement, returnAfterFirstMatch);
263 };
264
265 /**
266 * @public
267 *
268 * @param bool unsavedContent
269 * @return void
270 * @throws 1475378544
271 */
272 function setUnsavedContent(unsavedContent) {
273 assert('boolean' === $.type(unsavedContent), 'Invalid parameter "unsavedContent"', 1475378544);
274 _unsavedContent = unsavedContent;
275 };
276
277 /**
278 * @public
279 *
280 * @return boolean
281 */
282 function getUnsavedContent() {
283 return _unsavedContent;
284 };
285
286 /**
287 * @public
288 *
289 * @return object
290 */
291 function getRootFormElement() {
292 return _getRepository().getRootFormElement();
293 };
294
295 /**
296 * @public
297 *
298 * @return string
299 */
300 function getCurrentlySelectedFormElement() {
301 return _getRepository().findFormElementByIdentifierPath(_getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath'));
302 };
303
304 /**
305 * @public
306 *
307 * @param string|object formElement
308 * @param boolean doNotRefreshCurrentlySelectedPageIndex
309 * @return void
310 * @publish core/currentlySelectedFormElementChanged
311 */
312 function setCurrentlySelectedFormElement(formElement, doNotRefreshCurrentlySelectedPageIndex) {
313 doNotRefreshCurrentlySelectedPageIndex = !!doNotRefreshCurrentlySelectedPageIndex;
314
315 formElement = _getRepository().findFormElement(formElement);
316 _getApplicationStateStack().setCurrentState('currentlySelectedFormElementIdentifierPath', formElement.get('__identifierPath'));
317
318 if (!doNotRefreshCurrentlySelectedPageIndex) {
319 refreshCurrentlySelectedPageIndex();
320 }
321 getPublisherSubscriber().publish('core/currentlySelectedFormElementChanged', [formElement]);
322 };
323
324 /**
325 * @public
326 *
327 * @param string identifierPath
328 * @return object
329 * @throws 1475378545
330 */
331 function getFormElementByIdentifierPath(identifierPath) {
332 assert(getUtility().isNonEmptyString(identifierPath), 'Invalid parameter "identifierPath"', 1475378545);
333 return _getRepository().findFormElementByIdentifierPath(identifierPath);
334 };
335
336 /**
337 * @public
338 *
339 * @param string identifierPath
340 * @return bool
341 */
342 function isFormElementIdentifierUsed(formElementIdentifier) {
343 return _getRepository().isFormElementIdentifierUsed(formElementIdentifier);
344 }
345
346 /**
347 * @public
348 *
349 * @param string formElementType
350 * @param string|object referenceFormElement
351 * @param boolean disablePublishersOnSet
352 * @return object
353 */
354 function createAndAddFormElement(formElementType, referenceFormElement, disablePublishersOnSet) {
355 var formElement;
356 formElement = addFormElement(createFormElement(formElementType, disablePublishersOnSet), referenceFormElement, disablePublishersOnSet);
357 formElement.set('renderables', formElement.get('renderables'));
358 return formElement;
359 };
360
361 /**
362 * @public
363 *
364 * @param object formElement
365 * @param string|object referenceFormElement
366 * @param boolean disablePublishersOnSet
367 * @return object
368 * @throws 1475434337
369 */
370 function addFormElement(formElement, referenceFormElement, disablePublishersOnSet) {
371 _saveApplicationState();
372
373 if (getUtility().isUndefinedOrNull(referenceFormElement)) {
374 referenceFormElement = getCurrentlySelectedFormElement();
375 }
376 referenceFormElement = _getRepository().findFormElement(referenceFormElement);
377 assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475434337);
378 return _getRepository().addFormElement(formElement, referenceFormElement, true, disablePublishersOnSet);
379 };
380
381 /**
382 * @public
383 *
384 * @param string formElementType
385 * @param boolean disablePublishersOnSet
386 * @return object
387 * @throws 1475434336
388 * @throws 1475435857
389 */
390 function createFormElement(formElementType, disablePublishersOnSet) {
391 var formElementDefinition, identifier;
392 assert(getUtility().isNonEmptyString(formElementType), 'Invalid parameter "formElementType"', 1475434336);
393
394 identifier = _getRepository().getNextFreeFormElementIdentifier(formElementType);
395 formElementDefinition = getFormElementDefinitionByType(formElementType);
396 return _getFactory().createFormElement({
397 type: formElementType,
398 identifier: identifier,
399 label: formElementDefinition['label'] || formElementType
400 }, undefined, undefined, undefined, disablePublishersOnSet);
401 };
402
403 /**
404 * @public
405 *
406 * @param string|object formElementToRemove
407 * @param boolean disablePublishersOnSet
408 * @return object
409 */
410 function removeFormElement(formElementToRemove, disablePublishersOnSet) {
411 var parentFormElement;
412 _saveApplicationState();
413
414 formElementToRemove = _getRepository().findFormElement(formElementToRemove);
415 parentFormElement = formElementToRemove.get('__parentRenderable');
416 _getRepository().removeFormElement(formElementToRemove, true, disablePublishersOnSet);
417 return parentFormElement;
418 };
419
420 /**
421 * @public
422 *
423 * @param string|object formElementToMove
424 * @param string position
425 * @param string|object referenceFormElement
426 * @param boolean disablePublishersOnSet
427 * @return string
428 * @throws 1475378551
429 */
430 function moveFormElement(formElementToMove, position, referenceFormElement, disablePublishersOnSet) {
431 _saveApplicationState();
432
433 formElementToMove = _getRepository().findFormElement(formElementToMove);
434 referenceFormElement = _getRepository().findFormElement(referenceFormElement);
435
436 assert('after' === position || 'before' === position || 'inside' === position, 'Invalid position "' + position + '"', 1475378551);
437
438 formElementToMove = _getRepository().moveFormElement(formElementToMove, position, referenceFormElement, true);
439 disablePublishersOnSet = !!disablePublishersOnSet;
440 if (!disablePublishersOnSet) {
441 formElementToMove.get('__parentRenderable').set('renderables', formElementToMove.get('__parentRenderable').get('renderables'));
442 }
443 return formElementToMove;
444 };
445
446 /**
447 * @public
448 *
449 * @param string collectionElementIdentifier
450 * @param string collectionName
451 * @param string formElement
452 * @return object (dereferenced)
453 * @throws 1475378555
454 * @throws 1475378556
455 * @throws 1475446108
456 */
457 function getPropertyCollectionElementConfiguration(collectionElementIdentifier, collectionName, formElement) {
458 var collection, collectionElement, formElementDefinition;
459 if (getUtility().isUndefinedOrNull(formElement)) {
460 formElement = getCurrentlySelectedFormElement();
461 }
462 formElement = _getRepository().findFormElement(formElement);
463
464 assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378555);
465 assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378556);
466
467 formElementDefinition = getFormElementDefinitionByType(formElement.get('type'));
468 if (!getUtility().isUndefinedOrNull(formElementDefinition['propertyCollections'])) {
469 collection = formElementDefinition['propertyCollections'][collectionName];
470 assert(!getUtility().isUndefinedOrNull(collection), 'Invalid collection name "' + collectionName + '"', 1475446108);
471 collectionElement = _getRepository().findCollectionElementByIdentifierPath(collectionElementIdentifier, collection);
472 return $.extend(true, {}, collectionElement);
473 } else {
474 return {};
475 }
476 };
477
478 /**
479 * @public
480 *
481 * @param string collectionElementIdentifier
482 * @param string collectionName
483 * @param string formElement
484 * @return int
485 * @throws 1475378557
486 * @throws 1475378558
487 */
488 function getIndexFromPropertyCollectionElement(collectionElementIdentifier, collectionName, formElement) {
489 var indexFromPropertyCollectionElement;
490 if (getUtility().isUndefinedOrNull(formElement)) {
491 formElement = getCurrentlySelectedFormElement();
492 }
493 formElement = _getRepository().findFormElement(formElement);
494
495 assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378557);
496 assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378558);
497
498 indexFromPropertyCollectionElement = _getRepository().getIndexFromPropertyCollectionElementByIdentifier(
499 collectionElementIdentifier,
500 collectionName,
501 formElement
502 );
503
504 return indexFromPropertyCollectionElement;
505 };
506
507 /**
508 * @public
509 *
510 * @param string collectionElementIdentifier
511 * @param string collectionName
512 * @param object formElement
513 * @param object collectionElementConfiguration
514 * @param string referenceCollectionElementIdentifier
515 * @return object
516 */
517 function createAndAddPropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, collectionElementConfiguration, referenceCollectionElementIdentifier) {
518 return addPropertyCollectionElement(createPropertyCollectionElement(collectionElementIdentifier, collectionName, collectionElementConfiguration), collectionName, formElement, referenceCollectionElementIdentifier);
519 };
520
521 /**
522 * @public
523 *
524 * @param object collectionElement
525 * @param string collectionName
526 * @param string|object formElement
527 * @param string referenceCollectionElementIdentifier
528 * @return object
529 * @throws 1475443300
530 * @throws 1475443301
531 */
532 function addPropertyCollectionElement(collectionElement, collectionName, formElement, referenceCollectionElementIdentifier) {
533 var collection;
534 _saveApplicationState();
535
536 if (getUtility().isUndefinedOrNull(formElement)) {
537 formElement = getCurrentlySelectedFormElement();
538 }
539 formElement = _getRepository().findFormElement(formElement);
540
541 assert('object' === $.type(collectionElement), 'Invalid parameter "collectionElement"', 1475443301);
542 assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475443300);
543
544 if (getUtility().isUndefinedOrNull(referenceCollectionElementIdentifier)) {
545 collection = formElement.get(collectionName);
546 if ('array' === $.type(collection) && collection.length > 0) {
547 referenceCollectionElementIdentifier = collection[collection.length - 1]['identifier'];
548 }
549 }
550
551 return _getRepository().addPropertyCollectionElement(
552 collectionElement,
553 collectionName,
554 formElement,
555 referenceCollectionElementIdentifier,
556 false
557 );
558 };
559
560 /**
561 * @public
562 *
563 * @param string collectionElementIdentifier
564 * @param string collectionName
565 * @param object collectionElementConfiguration
566 * @return void
567 * @throws 1475378559
568 * @throws 1475378560
569 */
570 function createPropertyCollectionElement(collectionElementIdentifier, collectionName, collectionElementConfiguration) {
571 assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378559);
572 assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378560);
573 if ('object' !== $.type(collectionElementConfiguration)) {
574 collectionElementConfiguration = {};
575 }
576
577 return _getFactory().createPropertyCollectionElement(collectionElementIdentifier, collectionElementConfiguration, collectionName);
578 };
579
580 /**
581 * @public
582 *
583 * @param string collectionElementIdentifier
584 * @param string collectionName
585 * @param string formElement
586 * @param bool disablePublishersOnSet
587 * @return void
588 * @throws 1475378561
589 * @throws 1475378562
590 */
591 function removePropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, disablePublishersOnSet) {
592 _saveApplicationState();
593
594 if (getUtility().isUndefinedOrNull(formElement)) {
595 formElement = getCurrentlySelectedFormElement();
596 }
597 formElement = _getRepository().findFormElement(formElement);
598
599 assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378561);
600 assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378562);
601
602 _getRepository().removePropertyCollectionElementByIdentifier(
603 formElement,
604 collectionElementIdentifier,
605 collectionName,
606 true
607 );
608
609 disablePublishersOnSet = !!disablePublishersOnSet;
610 if (!disablePublishersOnSet) {
611 getPublisherSubscriber().publish('core/formElement/somePropertyChanged', ['__fakeProperty']);
612 }
613 };
614
615 /**
616 * @public
617 *
618 * @param string collectionElementToMove
619 * @param string position
620 * @param string referenceCollectionElement
621 * @param string collectionName
622 * @param object formElement
623 * @param boolean disablePublishersOnSet
624 * @return string
625 * @throws 1477404352
626 * @throws 1477404353
627 * @throws 1477404354
628 * @throws 1477404355
629 */
630 function movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet) {
631 _saveApplicationState();
632
633 formElement = _getRepository().findFormElement(formElement);
634
635 assert('string' === $.type(collectionElementToMove), 'Invalid parameter "collectionElementToMove"', 1477404352);
636 assert('string' === $.type(referenceCollectionElement), 'Invalid parameter "referenceCollectionElement"', 1477404353);
637 assert('after' === position || 'before' === position, 'Invalid position "' + position + '"', 1477404354);
638 assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1477404355);
639
640 return _getRepository().movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet);
641 };
642
643 /**
644 * @public
645 *
646 * @param string elementType
647 * @param string formElementDefinitionKey
648 * @returnmixed
649 * @throws 1475378563
650 */
651 function getFormElementDefinitionByType(elementType, formElementDefinitionKey) {
652 var formElementDefinition;
653 assert(getUtility().isNonEmptyString(elementType), 'Invalid parameter "elementType"', 1475378563);
654
655 formElementDefinition = _getRepository().getFormEditorDefinition('formElements', elementType);
656
657 if (!getUtility().isUndefinedOrNull(formElementDefinitionKey)) {
658 formElementDefinition = formElementDefinition[formElementDefinitionKey];
659 }
660
661 if ('object' === $.type(formElementDefinition) || 'array' === $.type(formElementDefinition)) {
662 return $.extend(true, {}, formElementDefinition);
663 } else {
664 return formElementDefinition;
665 }
666 };
667
668 /**
669 * @public
670 *
671 * @param object formElement
672 * @param string formElementDefinitionKey
673 * @return mixed
674 */
675 function getFormElementDefinition(formElement, formElementDefinitionKey) {
676 formElement = _getRepository().findFormElement(formElement);
677 return getFormElementDefinitionByType(formElement.get('type'), formElementDefinitionKey);
678 };
679
680 /**
681 * @public
682 *
683 * @param string collectionName
684 * @param string collectionElementIdentifier
685 * @return mixed
686 */
687 function getFormEditorDefinition(definitionName, subject) {
688 return _getRepository().getFormEditorDefinition(definitionName, subject);
689 };
690
691 /**
692 * @public
693 *
694 * @param string validatorIdentifier
695 * @return object (dereferenced)
696 * @throws 1475672362
697 */
698 function getFormElementPropertyValidatorDefinition(validatorIdentifier) {
699 var validatorDefinition;
700 assert(getUtility().isNonEmptyString(validatorIdentifier), 'Invalid parameter "validatorIdentifier"', 1475672362);
701
702 validatorDefinition = _getRepository().getFormEditorDefinition('formElementPropertyValidators', validatorIdentifier);
703 return $.extend(true, {}, validatorDefinition);
704 };
705
706 /**
707 * @public
708 *
709 * @return int
710 */
711 function getCurrentlySelectedPageIndex() {
712 return _getApplicationStateStack().getCurrentState('currentlySelectedPageIndex');
713 };
714
715 /**
716 * @public
717 *
718 * @return void
719 */
720 function refreshCurrentlySelectedPageIndex() {
721 _getApplicationStateStack().setCurrentState('currentlySelectedPageIndex', getPageIndexFromFormElement(getCurrentlySelectedFormElement()));
722 };
723
724 /**
725 * @public
726 *
727 * @return object
728 * @throws 1477786068
729 */
730 function getCurrentlySelectedPage() {
731 var currentPage;
732
733 currentPage = _getRepository().getRootFormElement().get('renderables')[getCurrentlySelectedPageIndex()];
734 assert('object' === $.type(currentPage), 'No page found', 1477786068);
735 return currentPage;
736 };
737
738 /**
739 * @public
740 *
741 * @return object
742 */
743 function getLastTopLevelElementOnCurrentPage() {
744 var lastRenderable, renderables;
745
746 renderables = getCurrentlySelectedPage().get('renderables');
747 if (getUtility().isUndefinedOrNull(renderables)) {
748 return undefined;
749 }
750 lastRenderable = renderables[renderables.length - 1];
751 return lastRenderable;
752 };
753
754 /**
755 * @public
756 *
757 * @param object
758 * @return object
759 */
760 function getLastFormElementWithinParentFormElement(formElement) {
761 var lastElement;
762
763 formElement = _getRepository().findFormElement(formElement);
764 if (formElement.get('__identifierPath') === getRootFormElement().get('__identifierPath')) {
765 return formElement;
766 }
767 return formElement.get('__parentRenderable').get('renderables')[formElement.get('__parentRenderable').get('renderables').length - 1];
768 };
769
770 /**
771 * @public
772 *
773 * @param object
774 * @return int
775 */
776 function getPageIndexFromFormElement(formElement) {
777 formElement = _getRepository().findFormElement(formElement);
778
779 return _getRepository().getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement(
780 formElement
781 );
782 };
783
784 /**
785 * @public
786 *
787 * @return void
788 */
789 function renderCurrentFormPage() {
790 renderFormPage(getCurrentlySelectedPageIndex());
791 };
792
793 /**
794 * @public
795 *
796 * @param int pageIndex
797 * @return void
798 * @throws 1475446442
799 */
800 function renderFormPage(pageIndex) {
801 assert('number' === $.type(pageIndex), 'Invalid parameter "pageIndex"', 1475446442);
802 _getDataBackend().renderFormDefinitionPage(pageIndex);
803 };
804
805 /**
806 * @public
807 *
808 * @param object formElement
809 * @return object|null
810 */
811 function findEnclosingCompositeFormElementWhichIsNotOnTopLevel(formElement) {
812 return _getRepository().findEnclosingCompositeFormElementWhichIsNotOnTopLevel(
813 _getRepository().findFormElement(formElement)
814 );
815 };
816
817 /**
818 * @public
819 *
820 * @param object formElement
821 * @return object|null
822 */
823 function findEnclosingGridContainerFormElement(formElement) {
824 return _getRepository().findEnclosingGridContainerFormElement(
825 _getRepository().findFormElement(formElement)
826 );
827 };
828
829 /**
830 * @public
831 *
832 * @param object formElement
833 * @return object|null
834 */
835 function findEnclosingGridRowFormElement(formElement) {
836 return _getRepository().findEnclosingGridRowFormElement(
837 _getRepository().findFormElement(formElement)
838 );
839 };
840
841 /**
842 * @public
843 *
844 * @return object
845 */
846 function getNonCompositeNonToplevelFormElements() {
847 return _getRepository().getNonCompositeNonToplevelFormElements();
848 };
849
850 /**
851 * @public
852 *
853 * @return boolean
854 */
855 function isRootFormElementSelected() {
856 return (getCurrentlySelectedFormElement().get('__identifierPath') === getRootFormElement().get('__identifierPath'));
857 };
858
859 /**
860 * @public
861 *
862 * @return object
863 */
864 function getViewModel() {
865 return _viewModel;
866 };
867
868 /**
869 * @public
870 *
871 * @return void
872 */
873 function saveFormDefinition() {
874 _getDataBackend().saveFormDefinition();
875 };
876
877 /**
878 * @private
879 *
880 * @return object
881 */
882 function _getDataBackend() {
883 return _core.getDataBackend();
884 };
885
886 /**
887 * @private
888 *
889 * @return object
890 */
891 function _getFactory() {
892 return _core.getFactory();
893 };
894
895 /**
896 * @private
897 *
898 * @return object
899 */
900 function _getRepository() {
901 return _core.getRepository();
902 };
903
904 /**
905 * @private
906 *
907 * @return object
908 */
909 function _getPropertyValidationService() {
910 return _core.getPropertyValidationService();
911 };
912
913 /**
914 * @public
915 *
916 * @return object
917 */
918 function _getApplicationStateStack() {
919 return _core.getApplicationStateStack();
920 };
921
922 /**
923 * @private
924 *
925 * @return void
926 * @publish ajax/beforeSend
927 * @publish ajax/complete
928 */
929 function _ajaxSetup() {
930 $.ajaxSetup({
931 beforeSend: function() {
932 getPublisherSubscriber().publish('ajax/beforeSend');
933 },
934 complete: function() {
935 getPublisherSubscriber().publish('ajax/complete');
936 }
937 });
938 };
939
940 /**
941 * @private
942 *
943 * @param object endpoints
944 * @param string prototypeName
945 * @param string formPersistenceIdentifier
946 * @return void
947 * @throws 1475379748
948 * @throws 1475379749
949 * @throws 1475927876
950 */
951 function _dataBackendSetup(endpoints, prototypeName, formPersistenceIdentifier) {
952 assert('object' === $.type(endpoints), 'Invalid parameter "endpoints"', 1475379748);
953 assert(getUtility().isNonEmptyString(prototypeName), 'Invalid parameter "prototypeName"', 1475927876);
954 assert(getUtility().isNonEmptyString(formPersistenceIdentifier), 'Invalid parameter "formPersistenceIdentifier"', 1475379749);
955
956 _core.getDataBackend().setEndpoints(endpoints);
957 _core.getDataBackend().setPrototypeName(prototypeName);
958 _core.getDataBackend().setPersistenceIdentifier(formPersistenceIdentifier);
959 };
960
961 /**
962 * @private
963 *
964 * @param object formEditorDefinitions
965 * @return void
966 * @throws 1475379750
967 */
968 function _repositorySetup(formEditorDefinitions) {
969 assert('object' === $.type(formEditorDefinitions), 'Invalid parameter "formEditorDefinitions"', 1475379750);
970
971 _getRepository().setFormEditorDefinitions(formEditorDefinitions);
972 }
973
974 /**
975 * @private
976 *
977 * @param object additionalViewModelModules
978 * @return void
979 * @throws 1475379752
980 * @throws 1475492374
981 */
982 function _viewSetup(additionalViewModelModules) {
983 assert('function' === $.type(_viewModel.bootstrap), 'The view model does not implement the method "bootstrap"', 1475492374);
984
985 if (!getUtility().isUndefinedOrNull(additionalViewModelModules)) {
986 assert('array' === $.type(additionalViewModelModules), 'Invalid parameter "additionalViewModelModules"', 1475379752);
987 } else {
988 additionalViewModelModules = [];
989 }
990 _viewModel.bootstrap(_formEditorInstance, additionalViewModelModules);
991 };
992
993 /**
994 * @private
995 *
996 * @return void
997 * @throws 1475492032
998 */
999 function _mediatorSetup() {
1000 assert('function' === $.type(_mediator.bootstrap), 'The mediator does not implement the method "bootstrap"', 1475492032);
1001 _mediator.bootstrap(_formEditorInstance, _viewModel);
1002 };
1003
1004 /**
1005 * @private
1006 *
1007 * @param object rootFormElement
1008 * @param int maximumUndoSteps
1009 * @return void
1010 * @throws 1475379751
1011 */
1012 function _applicationStateStackSetup(rootFormElement, maximumUndoSteps) {
1013 assert('object' === $.type(rootFormElement), 'Invalid parameter "rootFormElement"', 1475379751);
1014
1015 if ('number' !== $.type(maximumUndoSteps)) {
1016 maximumUndoSteps = 10;
1017 }
1018 _getApplicationStateStack().setMaximalStackSize(maximumUndoSteps);
1019
1020 _getApplicationStateStack().addAndReset({
1021 currentlySelectedPageIndex: 0,
1022 currentlySelectedFormElementIdentifierPath: rootFormElement['identifier']
1023 }, true);
1024
1025 _getApplicationStateStack().setCurrentState('formDefinition', _getFactory().createFormElement(rootFormElement, undefined, undefined, true));
1026 };
1027
1028 /**
1029 * @private
1030 *
1031 * @return void
1032 */
1033 function _bootstrap() {
1034 _configuration = _configuration || {};
1035
1036 _mediatorSetup();
1037 _ajaxSetup();
1038 _dataBackendSetup(_configuration['endpoints'], _configuration['prototypeName'], _configuration['formPersistenceIdentifier']);
1039 _repositorySetup(_configuration['formEditorDefinitions']);
1040 _applicationStateStackSetup(_configuration['formDefinition'], _configuration['maximumUndoSteps']);
1041 setCurrentlySelectedFormElement(_getRepository().getRootFormElement());
1042
1043 _viewSetup(_configuration['additionalViewModelModules']);
1044 };
1045
1046 /**
1047 * @public
1048 *
1049 * @return TYPO3/CMS/Form/Backend/FormEditor
1050 * @throws 1473200696
1051 */
1052 function run() {
1053 if (_isRunning) {
1054 throw 'You can not run the app twice (1473200696)';
1055 }
1056
1057 _bootstrap();
1058 _isRunning = true;
1059 return this;
1060 };
1061
1062 /**
1063 * Publish the public methods.
1064 * Implements the "Revealing Module Pattern".
1065 */
1066 return {
1067 getRootFormElement: getRootFormElement,
1068
1069 createAndAddFormElement: createAndAddFormElement,
1070 createFormElement: createFormElement,
1071 addFormElement: addFormElement,
1072 moveFormElement: moveFormElement,
1073 removeFormElement: removeFormElement,
1074
1075 getCurrentlySelectedFormElement: getCurrentlySelectedFormElement,
1076 setCurrentlySelectedFormElement: setCurrentlySelectedFormElement,
1077
1078 getFormElementByIdentifierPath: getFormElementByIdentifierPath,
1079 isFormElementIdentifierUsed: isFormElementIdentifierUsed,
1080
1081 createAndAddPropertyCollectionElement: createAndAddPropertyCollectionElement,
1082 createPropertyCollectionElement: createPropertyCollectionElement,
1083 addPropertyCollectionElement: addPropertyCollectionElement,
1084 removePropertyCollectionElement: removePropertyCollectionElement,
1085 movePropertyCollectionElement: movePropertyCollectionElement,
1086 getIndexFromPropertyCollectionElement: getIndexFromPropertyCollectionElement,
1087 getPropertyCollectionElementConfiguration: getPropertyCollectionElementConfiguration,
1088
1089 saveFormDefinition: saveFormDefinition,
1090 renderCurrentFormPage: renderCurrentFormPage,
1091 renderFormPage: renderFormPage,
1092
1093 getCurrentlySelectedPageIndex: getCurrentlySelectedPageIndex,
1094 refreshCurrentlySelectedPageIndex: refreshCurrentlySelectedPageIndex,
1095 getPageIndexFromFormElement: getPageIndexFromFormElement,
1096 getCurrentlySelectedPage: getCurrentlySelectedPage,
1097 getLastTopLevelElementOnCurrentPage: getLastTopLevelElementOnCurrentPage,
1098 findEnclosingCompositeFormElementWhichIsNotOnTopLevel: findEnclosingCompositeFormElementWhichIsNotOnTopLevel,
1099 findEnclosingGridContainerFormElement: findEnclosingGridContainerFormElement,
1100 findEnclosingGridRowFormElement: findEnclosingGridRowFormElement,
1101 isRootFormElementSelected: isRootFormElementSelected,
1102 getLastFormElementWithinParentFormElement: getLastFormElementWithinParentFormElement,
1103 getNonCompositeNonToplevelFormElements: getNonCompositeNonToplevelFormElements,
1104
1105 getFormElementDefinitionByType: getFormElementDefinitionByType,
1106 getFormElementDefinition: getFormElementDefinition,
1107 getFormElementPropertyValidatorDefinition: getFormElementPropertyValidatorDefinition,
1108 getFormEditorDefinition: getFormEditorDefinition,
1109
1110 getPublisherSubscriber: getPublisherSubscriber,
1111 getRunningAjaxRequest: getRunningAjaxRequest,
1112
1113 setUnsavedContent: setUnsavedContent,
1114 getUnsavedContent: getUnsavedContent,
1115
1116 addPropertyValidationValidator: addPropertyValidationValidator,
1117 validateFormElementProperty: validateFormElementProperty,
1118 validateCurrentlySelectedFormElementProperty: validateCurrentlySelectedFormElementProperty,
1119 validateFormElement: validateFormElement,
1120 validateFormElementRecursive: validateFormElementRecursive,
1121 validationResultsHasErrors: validationResultsHasErrors,
1122
1123 getUtility: getUtility,
1124 assert: assert,
1125 buildPropertyPath: buildPropertyPath,
1126
1127 getViewModel: getViewModel,
1128 undoApplicationState: undoApplicationState,
1129 redoApplicationState: redoApplicationState,
1130 getMaximalApplicationStates: getMaximalApplicationStates,
1131 getCurrentApplicationStates: getCurrentApplicationStates,
1132 getCurrentApplicationStatePosition: getCurrentApplicationStatePosition,
1133 setFormDefinition: setFormDefinition,
1134
1135 run: run
1136 };
1137 };
1138
1139 /**
1140 * Emulation of static methods
1141 */
1142 return {
1143 /**
1144 * @public
1145 * @static
1146 *
1147 * Implement the "Singleton Pattern".
1148 *
1149 * Return a singleton instance of a
1150 * "FormEditor" object.
1151 *
1152 * @param object configuration
1153 * @param object mediator
1154 * @param object viewModel
1155 * @return object
1156 */
1157 getInstance: function(configuration, mediator, viewModel) {
1158 if (_formEditorInstance === null) {
1159 _formEditorInstance = new FormEditor(configuration, mediator, viewModel);
1160 }
1161 return _formEditorInstance;
1162 }
1163 };
1164 })(core);
1165 });