742e2cb6e69bbb611dd1b818db5c647f4f14dadb
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Resources / Public / JavaScript / Backend / FormEditor / Core.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/Core
16 */
17 define(['jquery'], function($) {
18 'use strict';
19
20 return (function($) {
21
22 /**
23 * @private
24 *
25 * @var object
26 */
27 var _dataBackendEndpoints = {};
28
29 /**
30 * @private
31 *
32 * @var string
33 */
34 var _dataBackendPrototypeName = null;
35
36 /**
37 * @private
38 *
39 * @var string
40 */
41 var _dataBackendPersistenceIdentifier = null;
42
43 /**
44 * @private
45 *
46 * @var object
47 */
48 var _publisherSubscriberTopics = {};
49
50 /**
51 * @private
52 *
53 * @var int
54 */
55 var _publisherSubscriberUid = -1;
56
57 /**
58 * @private
59 *
60 * @var object
61 */
62 var _repositoryFormEditorDefinitions = {};
63
64 /**
65 * @private
66 *
67 * @var object
68 */
69 var _runningAjaxRequests = [];
70
71 /**
72 * @private
73 *
74 * @var object
75 */
76 var _propertyValidationServiceValidators = {};
77
78 /**
79 * @private
80 *
81 * @var int
82 */
83 var _applicationStateStackSize = 10;
84
85 /**
86 * @private
87 *
88 * @var int
89 */
90 var _applicationStateStackPointer = 0;
91
92 /**
93 * @private
94 *
95 * @var object
96 */
97 var _applicationStateStack = [];
98
99 /**
100 * @public
101 *
102 * @return object
103 */
104 function utility() {
105
106 /**
107 * @public
108 *
109 * @param mixed test
110 * @param string message
111 * @param int messageCode
112 * @return void
113 */
114 function assert(test, message, messageCode) {
115 if ('function' === $.type(test)) {
116 test = (test() !== false);
117 }
118 if (!test) {
119 message = message || "Assertion failed";
120 if (messageCode) {
121 message = message + ' (' + messageCode + ')';
122 }
123 if ('undefined' !== typeof Error) {
124 throw new Error(message);
125 }
126 throw message;
127 }
128 };
129
130 /**
131 * @public
132 *
133 * @param mixed value
134 * @return bool
135 */
136 function isUndefinedOrNull(value) {
137 return ('undefined' === $.type(value) || 'null' === $.type(value));
138 };
139
140 /**
141 * @public
142 *
143 * @param mixed value
144 * @return bool
145 */
146 function isNonEmptyString(value) {
147 return ('string' === $.type(value) && value.length > 0);
148 };
149
150 /**
151 * @public
152 *
153 * @param string propertyPath
154 * @param string collectionElementIdentifier
155 * @param string collectionName
156 * @param object formElement
157 * @param boolean allowEmptyReturnValue
158 * @return string
159 * @throws 1475412569
160 * @throws 1475412570
161 * @throws 1475415988
162 * @throws 1475663210
163 */
164 function buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue) {
165 var newPropertyPath = '';
166
167 allowEmptyReturnValue = !!allowEmptyReturnValue;
168 if (isNonEmptyString(collectionElementIdentifier) || isNonEmptyString(collectionName)) {
169 assert(isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475412569);
170 assert(isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475412570);
171 newPropertyPath = collectionName + '.' + repository().getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement);
172 } else {
173 newPropertyPath = '';
174 }
175
176 if (!isUndefinedOrNull(propertyPath)) {
177 assert(isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475415988);
178 if (isNonEmptyString(newPropertyPath)) {
179 newPropertyPath = newPropertyPath + '.' + propertyPath;
180 } else {
181 newPropertyPath = propertyPath;
182 }
183 }
184
185 if (!allowEmptyReturnValue) {
186 assert(isNonEmptyString(newPropertyPath), 'The property path could not be resolved', 1475663210);
187 }
188 return newPropertyPath;
189 };
190
191 /**
192 * @public
193 *
194 * @param object formElement
195 * @return object
196 * @throws 1475377782
197 */
198 function convertToSimpleObject(formElement) {
199 var childFormElements, simpleObject, objectData;
200 assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475377782);
201
202 simpleObject = {};
203 objectData = ('function' === $.type(formElement.getObjectData)) ? formElement.getObjectData() : formElement;
204 childFormElements = objectData['renderables'];
205 delete objectData['renderables'];
206
207 for (var key in objectData) {
208 if (!objectData.hasOwnProperty(key)) {
209 continue;
210 }
211 var value = objectData[key];
212 if (key.match(/^__/)) {
213 continue;
214 }
215
216 if ('object' === $.type(value)) {
217 simpleObject[key] = convertToSimpleObject(value);
218 } else if ('function' !== $.type(value) && 'undefined' !== $.type(value)) {
219 simpleObject[key] = value;
220 }
221 }
222
223 if ('array' === $.type(childFormElements)) {
224 simpleObject['renderables'] = [];
225 for (var i = 0, len = childFormElements.length; i < len; ++i) {
226 simpleObject['renderables'].push(convertToSimpleObject(childFormElements[i]));
227 }
228 }
229
230 return simpleObject;
231 };
232
233 /**
234 * Publish the public methods.
235 */
236 return {
237 assert: assert,
238 convertToSimpleObject: convertToSimpleObject,
239 isNonEmptyString: isNonEmptyString,
240 isUndefinedOrNull: isUndefinedOrNull,
241 buildPropertyPath: buildPropertyPath
242 };
243 };
244
245 /**
246 * @public
247 *
248 * @return object
249 */
250 function propertyValidationService() {
251
252 /**
253 * @public
254 *
255 * @param object formElement
256 * @param object validators
257 * @param string propertyPath
258 * @param string collectionElementIdentifier
259 * @param string collectionName
260 * @param object configuration
261 * @return void
262 * @throws 1475661025
263 * @throws 1475661026
264 * @throws 1479238074
265 */
266 function addValidatorIdentifiersToFormElementProperty(formElement, validators, propertyPath, collectionElementIdentifier, collectionName, configuration) {
267 var formElementIdentifierPath, propertyPath, propertyValidationServiceRegisteredValidators;
268 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475661025);
269 utility().assert('array' === $.type(validators), 'Invalid parameter "validators"', 1475661026);
270 utility().assert('array' === $.type(validators), 'Invalid parameter "validators"', 1479238074);
271
272 formElementIdentifierPath = formElement.get('__identifierPath');
273 propertyPath = utility().buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement);
274
275 propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
276 if (utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])) {
277 propertyValidationServiceRegisteredValidators[formElementIdentifierPath] = {};
278 }
279 if (utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath])) {
280 propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath] = {
281 validators: [],
282 configuration: configuration
283 };
284 }
285 for (var i = 0, len = validators.length; i < len; ++i) {
286 if (propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].indexOf(validators[i]) === -1) {
287 propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].push(validators[i]);
288 }
289 }
290 getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
291 };
292
293 /**
294 * @public
295 *
296 * @param object formElement
297 * @param string propertyPath
298 * @return void
299 * @throws 1475700618
300 * @throws 1475706896
301 */
302 function removeValidatorIdentifiersFromFormElementProperty(formElement, propertyPath) {
303 var formElementIdentifierPath, propertyValidationServiceRegisteredValidators, registeredValidators;
304 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475700618);
305 utility().assert(utility().isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475706896);
306
307 formElementIdentifierPath = formElement.get('__identifierPath');
308
309 registeredValidators = {};
310 propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
311 for (var registeredPropertyPath in propertyValidationServiceRegisteredValidators[formElementIdentifierPath]) {
312 if (
313 !propertyValidationServiceRegisteredValidators[formElementIdentifierPath].hasOwnProperty(registeredPropertyPath)
314 || registeredPropertyPath.indexOf(propertyPath) > -1
315 ) {
316 continue;
317 }
318 registeredValidators[registeredPropertyPath] = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][registeredPropertyPath];
319 }
320 propertyValidationServiceRegisteredValidators[formElementIdentifierPath] = registeredValidators;
321 getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
322 };
323
324 /**
325 * @public
326 *
327 * @param string|object formElement
328 * @return void
329 * @throws 1475668189
330 */
331 function removeAllValidatorIdentifiersFromFormElement(formElement) {
332 var propertyValidationServiceRegisteredValidators, registeredValidators;
333 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475668189);
334
335 registeredValidators = {};
336 propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
337 for (var formElementIdentifierPath in propertyValidationServiceRegisteredValidators) {
338 if (
339 !propertyValidationServiceRegisteredValidators.hasOwnProperty(formElementIdentifierPath)
340 || formElementIdentifierPath === formElement.get('__identifierPath')
341 || formElementIdentifierPath.indexOf(formElement.get('__identifierPath') + '/') > -1
342 ) {
343 continue;
344 }
345 registeredValidators[formElementIdentifierPath] = propertyValidationServiceRegisteredValidators[formElementIdentifierPath];
346 }
347 getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', registeredValidators);
348 };
349
350 /**
351 * @public
352 *
353 * @param string validatorIdentifier
354 * @param function func
355 * @return void
356 * @throws 1475669143
357 * @throws 1475669144
358 * @throws 1475669145
359 */
360 function addValidator(validatorIdentifier, func) {
361 utility().assert(utility().isNonEmptyString(validatorIdentifier), 'Invalid parameter "validatorIdentifier"', 1475669143);
362 utility().assert('function' === $.type(func), 'Invalid parameter "func"', 1475669144);
363 utility().assert('function' !== $.type(_propertyValidationServiceValidators[validatorIdentifier]), 'The validator "' + validatorIdentifier + '" is already registered', 1475669145);
364
365 _propertyValidationServiceValidators[validatorIdentifier] = func;
366 };
367
368 /**
369 * @public
370 *
371 * @param object formElement
372 * @param string propertyPath
373 * @param string errorMessage
374 * @return object
375 * @throws 1475676517
376 * @throws 1475676518
377 */
378 function validateFormElementProperty(formElement, propertyPath) {
379 var configuration, formElementIdentifierPath, propertyValidationServiceRegisteredValidators, validationResults;
380 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475676517);
381 utility().assert(utility().isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475676518);
382
383 formElementIdentifierPath = formElement.get('__identifierPath');
384
385 validationResults = [];
386 propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
387 configuration = {
388 propertyValidatorsMode: 'AND'
389 };
390
391 if (
392 !utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])
393 && 'object' === $.type(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath])
394 && 'array' === $.type(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'])
395 ) {
396 configuration = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['configuration'];
397 for (var i = 0, len = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].length; i < len; ++i) {
398 var validatorIdentifier, validationResult;
399
400 validatorIdentifier = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'][i];
401 if ('function' !== $.type(_propertyValidationServiceValidators[validatorIdentifier])) {
402 continue;
403 }
404 validationResult = _propertyValidationServiceValidators[validatorIdentifier](formElement, propertyPath);
405
406 if (utility().isNonEmptyString(validationResult)) {
407 validationResults.push(validationResult);
408 }
409 }
410 }
411
412 if (
413 validationResults.length > 0
414 && configuration['propertyValidatorsMode'] === 'OR'
415 && validationResults.length !== propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].length
416 ) {
417 return [];
418 }
419
420 return validationResults;
421 };
422
423 /**
424 * @public
425 *
426 * @param object formElement
427 * @return object
428 * @throws 1475749668
429 */
430 function validateFormElement(formElement) {
431 var formElementIdentifierPath, propertyValidationServiceRegisteredValidators, validationResults;
432 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475749668);
433
434 formElementIdentifierPath = formElement.get('__identifierPath');
435
436 validationResults = [];
437 propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
438 if (!utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])) {
439 for (var registeredPropertyPath in propertyValidationServiceRegisteredValidators[formElementIdentifierPath]) {
440 var validationResult;
441 if (!propertyValidationServiceRegisteredValidators[formElementIdentifierPath].hasOwnProperty(registeredPropertyPath)) {
442 continue;
443 }
444 validationResult = {
445 propertyPath: registeredPropertyPath,
446 validationResults: validateFormElementProperty(formElement, registeredPropertyPath)
447 };
448 validationResults.push(validationResult);
449 }
450 }
451 return validationResults;
452 };
453
454 /**
455 * @public
456 *
457 * @param array validationResults
458 * @return bool
459 * @throws 1478613477
460 */
461 function validationResultsHasErrors(validationResults) {
462 utility().assert('array' === $.type(validationResults), 'Invalid parameter "validationResults"', 1478613477);
463
464 for (var i = 0, len = validationResults.length; i < len; ++i) {
465 for (var j = 0, len2 = validationResults[i]['validationResults'].length; j < len2; ++j) {
466 if (
467 validationResults[i]['validationResults'][j]['validationResults']
468 && validationResults[i]['validationResults'][j]['validationResults'].length > 0
469 ) {
470 return true;
471 }
472 }
473 }
474 return false;
475 };
476
477 /**
478 * @public
479 *
480 * @param object formElement
481 * @param boolean returnAfterFirstMatch
482 * @param object validationResults
483 * @return object
484 * @throws 1475749668
485 */
486 function validateFormElementRecursive(formElement, returnAfterFirstMatch, validationResults) {
487 var formElements, validationResult, validationResults;
488 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475756764);
489 returnAfterFirstMatch = !!returnAfterFirstMatch;
490
491 validationResults = validationResults || [];
492 validationResult = {
493 formElementIdentifierPath: formElement.get('__identifierPath'),
494 validationResults: validateFormElement(formElement)
495 };
496 validationResults.push(validationResult);
497
498 if (returnAfterFirstMatch && validationResultsHasErrors(validationResults)) {
499 return validationResults;
500 }
501
502 formElements = formElement.get('renderables');
503 if ('array' === $.type(formElements)) {
504 for (var i = 0, len = formElements.length; i < len; ++i) {
505 validateFormElementRecursive(formElements[i], returnAfterFirstMatch, validationResults);
506 if (returnAfterFirstMatch && validationResultsHasErrors(validationResults)) {
507 return validationResults;
508 }
509 }
510 }
511
512 return validationResults;
513 }
514
515 /**
516 * @public
517 *
518 * @param object formElement
519 * @return void
520 * @throws 1475707334
521 */
522 function addValidatorIdentifiersFromFormElementPropertyCollections(formElement) {
523 var formElementTypeDefinition;
524 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475707334);
525
526 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
527
528 if (!utility().isUndefinedOrNull(formElementTypeDefinition['propertyCollections'])) {
529 for (var collectionName in formElementTypeDefinition['propertyCollections']) {
530 if (
531 !formElementTypeDefinition['propertyCollections'].hasOwnProperty(collectionName)
532 || 'array' !== $.type(formElementTypeDefinition['propertyCollections'][collectionName])
533 ) {
534 continue;
535 }
536 for (var i = 0, len1 = formElementTypeDefinition['propertyCollections'][collectionName].length; i < len1; ++i) {
537 if (
538 'array' !== $.type(formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'])
539 || repository().getIndexFromPropertyCollectionElementByIdentifier(formElementTypeDefinition['propertyCollections'][collectionName][i]['identifier'], collectionName, formElement) === -1
540 ) {
541 continue;
542 }
543 for (var j = 0, len2 = formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'].length; j < len2; ++j) {
544 var configuration = {};
545
546 if ('array' !== $.type(formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidators'])) {
547 continue;
548 }
549
550 if (
551 !utility().isUndefinedOrNull(formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidatorsMode'])
552 && formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidatorsMode'] === 'OR'
553 ) {
554 configuration['propertyValidatorsMode'] = 'OR';
555 } else {
556 configuration['propertyValidatorsMode'] = 'AND';
557 }
558 addValidatorIdentifiersToFormElementProperty(
559 formElement,
560 formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidators'],
561 formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyPath'],
562 formElementTypeDefinition['propertyCollections'][collectionName][i]['identifier'],
563 collectionName,
564 configuration
565 );
566 }
567 }
568 }
569 }
570 };
571
572 /**
573 * Publish the public methods.
574 */
575 return {
576 addValidatorIdentifiersToFormElementProperty: addValidatorIdentifiersToFormElementProperty,
577 removeValidatorIdentifiersFromFormElementProperty: removeValidatorIdentifiersFromFormElementProperty,
578 removeAllValidatorIdentifiersFromFormElement: removeAllValidatorIdentifiersFromFormElement,
579 validateFormElementProperty: validateFormElementProperty,
580 validateFormElement: validateFormElement,
581 validateFormElementRecursive: validateFormElementRecursive,
582 validationResultsHasErrors: validationResultsHasErrors,
583 addValidator: addValidator,
584 addValidatorIdentifiersFromFormElementPropertyCollections: addValidatorIdentifiersFromFormElementPropertyCollections
585 };
586 };
587
588 /**
589 * @public
590 *
591 * @param string ajaxRequestIdentifier
592 * @return object|null
593 * @throws 1475358064
594 */
595 function getRunningAjaxRequest(ajaxRequestIdentifier) {
596 utility().assert(utility().isNonEmptyString(ajaxRequestIdentifier), 'Invalid parameter "ajaxRequestIdentifier"', 1475358064);
597 return _runningAjaxRequests[ajaxRequestIdentifier] || null;
598 };
599
600 /**
601 * @public
602 *
603 * Implements the "Publish/Subscribe Pattern"
604 *
605 * @return object
606 * @credits Addy Osmani https://addyosmani.com/resources/essentialjsdesignpatterns/book/#highlighter_634280
607 */
608 function publisherSubscriber() {
609
610 /**
611 * @public
612 *
613 * @param string topic
614 * @param mixed args
615 * @return void
616 * @throws 1475358066
617 */
618 function publish(topic, args) {
619 utility().assert(utility().isNonEmptyString(topic), 'Invalid parameter "topic"', 1475358066);
620 if (utility().isUndefinedOrNull(_publisherSubscriberTopics[topic])) {
621 return;
622 }
623
624 for (var i = 0, len = _publisherSubscriberTopics[topic].length; i < len; ++i) {
625 _publisherSubscriberTopics[topic][i].func(topic, args);
626 }
627 };
628
629 /**
630 * @public
631 *
632 * @param string topic
633 * @param function func
634 * @return string
635 * @throws 1475358067
636 */
637 function subscribe(topic, func) {
638 utility().assert(utility().isNonEmptyString(topic), 'Invalid parameter "topic"', 1475358067);
639 utility().assert('function' === $.type(func), 'Invalid parameter "func"', 1475411986);
640
641 if (utility().isUndefinedOrNull(_publisherSubscriberTopics[topic])) {
642 _publisherSubscriberTopics[topic] = [];
643 }
644
645 var token = (++_publisherSubscriberUid).toString();
646 _publisherSubscriberTopics[topic].push({
647 token: token,
648 func: func
649 });
650 return token;
651 };
652
653 /**
654 * @public
655 *
656 * @param string token
657 * @return null|string
658 * @throws 1475358068
659 */
660 function unsubscribe(token) {
661 utility().assert(utility().isNonEmptyString(token), 'Invalid parameter "token"', 1475358068);
662
663 for (var key in _publisherSubscriberTopics) {
664 if (!_publisherSubscriberTopics.hasOwnProperty(key)) {
665 continue;
666 }
667 for (var i = 0, len = _publisherSubscriberTopics[key].length; i < len; ++i) {
668 if (_publisherSubscriberTopics[key][i].token === token) {
669 _publisherSubscriberTopics[key].splice(i, 1);
670 return token;
671 }
672 }
673 }
674 return null;
675 };
676
677 /**
678 * Publish the public methods.
679 */
680 return {
681 publish: publish,
682 subscribe: subscribe,
683 unsubscribe: unsubscribe
684 };
685 };
686
687 /**
688 * @private
689 *
690 * @param object modelToExtend
691 * @param object modelExtension
692 * @param string pathPrefix
693 * @return void
694 * @throws 1474640022
695 * @throws 1475358069
696 * @throws 1475358070
697 * @publish core/formElement/somePropertyChanged
698 */
699 function extendModel(modelToExtend, modelExtension, pathPrefix, disablePublishersOnSet) {
700 utility().assert('object' === $.type(modelToExtend), 'Invalid parameter "modelToExtend"', 1475358069);
701 utility().assert('object' === $.type(modelExtension) || 'array' === $.type(modelExtension), 'Invalid parameter "modelExtension"', 1475358070);
702
703 disablePublishersOnSet = !!disablePublishersOnSet;
704 pathPrefix = pathPrefix || '';
705
706 if ($.isEmptyObject(modelExtension)) {
707 utility().assert('' !== pathPrefix, 'Empty path is not allowed', 1474640022);
708 modelToExtend.on(pathPrefix, 'core/formElement/somePropertyChanged');
709 modelToExtend.set(pathPrefix, modelExtension, disablePublishersOnSet);
710 } else {
711 for (var key in modelExtension) {
712 if (!modelExtension.hasOwnProperty(key)) {
713 continue;
714 }
715 var path = (pathPrefix === '') ? key : pathPrefix + '.' + key;
716
717 modelToExtend.on(path, 'core/formElement/somePropertyChanged');
718
719 if ('object' === $.type(modelExtension[key]) || 'array' === $.type(modelExtension[key])) {
720 extendModel(modelToExtend, modelExtension[key], path, disablePublishersOnSet);
721 } else {
722 modelToExtend.set(path, modelExtension[key], disablePublishersOnSet);
723 }
724 }
725 }
726 };
727
728 /**
729 * @private
730 *
731 * @param object modelExtension
732 * @return object
733 */
734 function createModel(modelExtension) {
735 var newModel;
736
737 modelExtension = modelExtension || {};
738
739 function M() {
740
741 /**
742 * @private
743 */
744 var _objectData = {};
745
746 /**
747 * @private
748 */
749 var _publisherTopics = {};
750
751 /**
752 * @public
753 *
754 * @param string key
755 * @return mixed|undefined
756 * @throws 1475361755
757 */
758 function get(key) {
759 var firstPartOfPath, obj;
760 utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361755);
761
762 obj = _objectData;
763 while (key.indexOf('.') > 0) {
764 firstPartOfPath = key.slice(0, key.indexOf('.'));
765 key = key.slice(firstPartOfPath.length + 1);
766 if (!obj.hasOwnProperty(firstPartOfPath)) {
767 return undefined;
768 }
769 obj = obj[firstPartOfPath];
770 }
771
772 return obj[key];
773 };
774
775 /**
776 * @public
777 *
778 * @param string key
779 * @param mixed value
780 * @param bool disablePublishersOnSet
781 * @return void
782 * @throws 1475361756
783 * @publish mixed
784 */
785 function set(key, value, disablePublishersOnSet) {
786 var obj, oldValue, path;
787 utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361756);
788 disablePublishersOnSet = !!disablePublishersOnSet;
789
790 oldValue = get(key);
791 obj = _objectData;
792 path = key;
793
794 while (path.indexOf('.') > 0) {
795 var firstPartOfPath, nextPartOfPath;
796
797 firstPartOfPath = path.slice(0, path.indexOf('.'));
798 path = path.slice(firstPartOfPath.length + 1);
799 if ($.isNumeric(firstPartOfPath)) {
800 firstPartOfPath = parseInt(firstPartOfPath);
801 }
802 if ('undefined' === $.type(obj[firstPartOfPath])) {
803 nextPartOfPath = path.slice(0, path.indexOf('.'));
804 if ($.isNumeric(nextPartOfPath)) {
805 obj[firstPartOfPath] = [];
806 } else {
807 obj[firstPartOfPath] = {};
808 }
809 }
810 obj = obj[firstPartOfPath];
811 }
812 obj[path] = value;
813
814 if (!utility().isUndefinedOrNull(_publisherTopics[key]) && !disablePublishersOnSet) {
815 for (var i = 0, len = _publisherTopics[key].length; i < len; ++i) {
816 publisherSubscriber().publish(_publisherTopics[key][i], [key, value, oldValue, _objectData['__identifierPath']]);
817 }
818 }
819 };
820
821 /**
822 * @public
823 *
824 * @param string key
825 * @param bool disablePublishersOnSet
826 * @return void
827 * @throws 1489321637
828 * @throws 1489319753
829 * @publish mixed
830 */
831 function unset(key, disablePublishersOnSet) {
832 var obj, oldValue, parentPropertyData, parentPropertyPath, propertyToRemove;
833 utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1489321637);
834 disablePublishersOnSet = !!disablePublishersOnSet;
835
836 oldValue = get(key);
837
838 if (key.indexOf('.') > 0) {
839 parentPropertyPath = key.split('.');
840 propertyToRemove = parentPropertyPath.pop();
841 parentPropertyPath = parentPropertyPath.join('.');
842 parentPropertyData = get(parentPropertyPath);
843 delete parentPropertyData[propertyToRemove];
844 } else {
845 assert(false, 'remove toplevel properties is not supported', 1489319753);
846 }
847
848 if (!utility().isUndefinedOrNull(_publisherTopics[key]) && !disablePublishersOnSet) {
849 for (var i = 0, len = _publisherTopics[key].length; i < len; ++i) {
850 publisherSubscriber().publish(_publisherTopics[key][i], [key, undefined, oldValue, _objectData['__identifierPath']]);
851 }
852 }
853 };
854
855 /**
856 * @public
857 *
858 * @param string key
859 * @param string topicName
860 * @return void
861 * @throws 1475361757
862 * @throws 1475361758
863 */
864 function on(key, topicName) {
865 utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361757);
866 utility().assert(utility().isNonEmptyString(topicName), 'Invalid parameter "topicName"', 1475361758);
867
868 if ('array' !== $.type(_publisherTopics[key])) {
869 _publisherTopics[key] = [];
870 }
871 if (_publisherTopics[key].indexOf(topicName) === -1) {
872 _publisherTopics[key].push(topicName);
873 }
874 };
875
876 /**
877 * @public
878 *
879 * @param string key
880 * @param string topicName
881 * @return void
882 * @throws 1475361759
883 * @throws 1475361760
884 */
885 function off(key, topicName) {
886 utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361759);
887 utility().assert(utility().isNonEmptyString(topicName), 'Invalid parameter "topicName"', 1475361760);
888
889 if ('array' === $.type(_publisherTopics[key])) {
890 _publisherTopics[key] = _publisherTopics[key].filter(function (topicName) {
891 return topicName !== topicName;
892 });
893 }
894 };
895
896 /**
897 * @public
898 *
899 * @return object (dereferenced)
900 */
901 function getObjectData() {
902 return $.extend(true, {}, _objectData);
903 };
904
905 /**
906 * @public
907 *
908 * @return string
909 */
910 function toString() {
911 var childFormElements, objectData;
912
913 objectData = getObjectData();
914 childFormElements = objectData['renderables'] || null;
915 delete objectData['renderables'];
916
917 if (!utility().isUndefinedOrNull(objectData['__parentRenderable'])) {
918 objectData['__parentRenderable'] = objectData['__parentRenderable'].getObjectData()['__identifierPath'] + ' (filtered)';
919 }
920
921 if (null !== childFormElements) {
922 objectData['renderables'] = [];
923 for (var i = 0, len = childFormElements.length; i < len; ++i) {
924 var childFormElement = childFormElements[i];
925 objectData['renderables'].push(JSON.parse(childFormElement.toString()));
926 }
927 }
928
929 return JSON.stringify(objectData, null, 2);
930 };
931
932 /**
933 * @public
934 *
935 * @return object
936 */
937 function clone() {
938 var childFormElements, newModel, newRenderables, objectData;
939
940 objectData = getObjectData();
941 childFormElements = objectData['renderables'] || null;
942 delete objectData['renderables'];
943 delete objectData['__parentRenderable'];
944 objectData['renderables'] = (childFormElements) ? true : null,
945
946 newModel = new M();
947 extendModel(newModel, objectData, '', true);
948
949 if (null !== childFormElements) {
950 newRenderables = [];
951 for (var i = 0, len = childFormElements.length; i < len; ++i) {
952 var childFormElement = childFormElements[i];
953
954 childFormElement = childFormElement.clone();
955 childFormElement.set('__parentRenderable', newModel, true);
956 newRenderables.push(childFormElement);
957 }
958 newModel.set('renderables', newRenderables, true);
959 }
960
961 return newModel;
962 };
963
964 /**
965 * Publish the public methods.
966 */
967 return {
968 get: get,
969 set: set,
970 unset: unset,
971
972 on: on,
973 off: off,
974
975 getObjectData: getObjectData,
976 toString: toString,
977 clone: clone
978 };
979 };
980
981 newModel = new M();
982 extendModel(newModel, modelExtension, '', true);
983
984 return newModel;
985 };
986
987 /**
988 * @public
989 *
990 * @return object
991 */
992 function repository() {
993
994 /**
995 * @public
996 *
997 * @param object typeDefinitions
998 * @return void
999 * @throws 1475364394
1000 */
1001 function setFormEditorDefinitions(formEditorDefinitions) {
1002 utility().assert('object' === $.type(formEditorDefinitions), 'Invalid parameter "formEditorDefinitions"', 1475364394);
1003
1004 for (var key1 in formEditorDefinitions) {
1005 if (!formEditorDefinitions.hasOwnProperty(key1) || 'object' !== $.type(formEditorDefinitions[key1])) {
1006 continue;
1007 }
1008 for (var key2 in formEditorDefinitions[key1]) {
1009 if (!formEditorDefinitions[key1].hasOwnProperty(key2)) {
1010 continue;
1011 }
1012 if ('object' !== $.type(formEditorDefinitions[key1][key2])) {
1013 formEditorDefinitions[key1][key2] = {};
1014 }
1015 }
1016 }
1017 _repositoryFormEditorDefinitions = formEditorDefinitions;
1018 };
1019
1020 /**
1021 * @public
1022 *
1023 * @param string typeName
1024 * @param string subject
1025 * @return object (dereferenced)
1026 * @throws 1475364952
1027 * @throws 1475364953
1028 */
1029 function getFormEditorDefinition(definitionName, subject) {
1030 utility().assert(utility().isNonEmptyString(definitionName), 'Invalid parameter "definitionName"', 1475364952);
1031 utility().assert(utility().isNonEmptyString(subject), 'Invalid parameter "subject"', 1475364953);
1032 return $.extend(true, {}, _repositoryFormEditorDefinitions[definitionName][subject]);
1033 };
1034
1035 /**
1036 * @public
1037 *
1038 * @return object
1039 */
1040 function getRootFormElement() {
1041 return getApplicationStateStack().getCurrentState('formDefinition');
1042 };
1043
1044 /**
1045 * @public
1046 *
1047 * @param object formElement
1048 * @param object referenceFormElement
1049 * @param boolean registerPropertyValidators
1050 * @param boolean disablePublishersOnSet
1051 * @return object
1052 * @throws 1475436224
1053 * @throws 1475364956
1054 */
1055 function addFormElement(formElement, referenceFormElement, registerPropertyValidators, disablePublishersOnSet) {
1056 var enclosingCompositeFormElement, identifier, formElementTypeDefinition, parentFormElementsArray, referenceFormElementElements, referenceFormElementTypeDefinition;
1057 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475436224);
1058 utility().assert('object' === $.type(referenceFormElement), 'Invalid parameter "referenceFormElement"', 1475364956);
1059
1060 if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
1061 disablePublishersOnSet = true;
1062 }
1063 disablePublishersOnSet = !!disablePublishersOnSet;
1064
1065 registerPropertyValidators = !!registerPropertyValidators;
1066 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
1067 referenceFormElementTypeDefinition = repository().getFormEditorDefinition('formElements', referenceFormElement.get('type'));
1068
1069 if (!formElementTypeDefinition['_isTopLevelFormElement'] && referenceFormElementTypeDefinition['_isCompositeFormElement']) {
1070 if ('array' !== $.type(referenceFormElement.get('renderables'))) {
1071 referenceFormElement.set('renderables', [], disablePublishersOnSet);
1072 }
1073
1074 formElement.set('__parentRenderable', referenceFormElement, disablePublishersOnSet);
1075 formElement.set('__identifierPath', referenceFormElement.get('__identifierPath') + '/' + formElement.get('identifier'), disablePublishersOnSet);
1076 referenceFormElement.get('renderables').push(formElement);
1077 } else {
1078 if (referenceFormElement.get('__identifierPath') === getApplicationStateStack().getCurrentState('formDefinition').get('__identifierPath')) {
1079 referenceFormElementElements = referenceFormElement.get('renderables');
1080 referenceFormElement = referenceFormElementElements[referenceFormElementElements.length - 1];
1081 } else if (formElementTypeDefinition['_isTopLevelFormElement'] && !referenceFormElementTypeDefinition['_isTopLevelFormElement']) {
1082 referenceFormElement = findEnclosingCompositeFormElementWhichIsOnTopLevel(referenceFormElement);
1083 } else if (formElementTypeDefinition['_isCompositeFormElement']) {
1084 enclosingCompositeFormElement = findEnclosingCompositeFormElementWhichIsNotOnTopLevel(referenceFormElement);
1085 if (enclosingCompositeFormElement) {
1086 referenceFormElement = enclosingCompositeFormElement;
1087 }
1088 }
1089
1090 formElement.set('__parentRenderable', referenceFormElement.get('__parentRenderable'), disablePublishersOnSet);
1091 formElement.set('__identifierPath', referenceFormElement.get('__parentRenderable').get('__identifierPath') + '/' + formElement.get('identifier'), disablePublishersOnSet);
1092 parentFormElementsArray = referenceFormElement.get('__parentRenderable').get('renderables');
1093 parentFormElementsArray.splice(parentFormElementsArray.indexOf(referenceFormElement) + 1, 0, formElement);
1094 }
1095
1096 if (registerPropertyValidators) {
1097 if ('array' === $.type(formElementTypeDefinition['editors'])) {
1098 for (var i = 0, len1 = formElementTypeDefinition['editors'].length; i < len1; ++i) {
1099 var configuration = {};
1100
1101 if ('array' !== $.type(formElementTypeDefinition['editors'][i]['propertyValidators'])) {
1102 continue;
1103 }
1104
1105 if (
1106 !utility().isUndefinedOrNull(formElementTypeDefinition['editors'][i]['propertyValidatorsMode'])
1107 && formElementTypeDefinition['editors'][i]['propertyValidatorsMode'] === 'OR'
1108 ) {
1109 configuration['propertyValidatorsMode'] = 'OR';
1110 } else {
1111 configuration['propertyValidatorsMode'] = 'AND';
1112 }
1113
1114 propertyValidationService().addValidatorIdentifiersToFormElementProperty(
1115 formElement,
1116 formElementTypeDefinition['editors'][i]['propertyValidators'],
1117 formElementTypeDefinition['editors'][i]['propertyPath'],
1118 undefined,
1119 undefined,
1120 configuration
1121 );
1122 }
1123 }
1124 }
1125
1126 return formElement;
1127 };
1128
1129 /**
1130 * @param object formElement
1131 * @param boolean removeRegisteredPropertyValidators
1132 * @param boolean disablePublishersOnSet
1133 * @return void
1134 * @throws 1472553024
1135 * @throws 1475364957
1136 */
1137 function removeFormElement(formElement, removeRegisteredPropertyValidators, disablePublishersOnSet) {
1138 var parentFormElementElements;
1139
1140 if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
1141 disablePublishersOnSet = true;
1142 }
1143 disablePublishersOnSet = !!disablePublishersOnSet;
1144 removeRegisteredPropertyValidators = !!removeRegisteredPropertyValidators;
1145
1146 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364957);
1147 utility().assert('object' === $.type(formElement.get('__parentRenderable')), 'Removing the root element is not allowed', 1472553024);
1148
1149 parentFormElementElements = formElement.get('__parentRenderable').get('renderables');
1150 parentFormElementElements.splice(parentFormElementElements.indexOf(formElement), 1);
1151 formElement.get('__parentRenderable').set('renderables', parentFormElementElements, disablePublishersOnSet);
1152
1153 if (removeRegisteredPropertyValidators) {
1154 propertyValidationService().removeAllValidatorIdentifiersFromFormElement(formElement);
1155 }
1156 };
1157
1158 /**
1159 * @param object formElementToMove
1160 * @param string position
1161 * @param object referenceFormElement
1162 * @param boolean disablePublishersOnSet
1163 * @return object
1164 * @throws 1475364958
1165 * @throws 1475364959
1166 * @throws 1475364960
1167 * @throws 1475364961
1168 * @throws 1475364962
1169 * @throws 1476993731
1170 * @throws 1476993732
1171 */
1172 function moveFormElement(formElementToMove, position, referenceFormElement, disablePublishersOnSet) {
1173 var formElementToMoveTypeDefinition, referenceFormElementParentElements, referenceFormElementElements, referenceFormElementIndex, referenceFormElementTypeDefinition, reSetIdentifierPath;
1174 utility().assert('object' === $.type(formElementToMove), 'Invalid parameter "formElementToMove"', 1475364958);
1175 utility().assert('after' === position || 'before' === position || 'inside' === position, 'Invalid position "' + position + '"', 1475364959);
1176 utility().assert('object' === $.type(referenceFormElement), 'Invalid parameter "referenceFormElement"', 1475364960);
1177
1178 if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
1179 disablePublishersOnSet = true;
1180 }
1181 disablePublishersOnSet = !!disablePublishersOnSet;
1182
1183 formElementToMoveTypeDefinition = repository().getFormEditorDefinition('formElements', formElementToMove.get('type'));
1184 referenceFormElementTypeDefinition = repository().getFormEditorDefinition('formElements', referenceFormElement.get('type'));
1185
1186 removeFormElement(formElementToMove, false);
1187 reSetIdentifierPath = function(formElement, pathPrefix) {
1188 var formElements, newIdentifierPath, oldIdentifierPath, propertyValidationServiceRegisteredValidators;
1189 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364961);
1190 utility().assert(utility().isNonEmptyString(pathPrefix), 'Invalid parameter "pathPrefix"', 1475364962);
1191
1192 oldIdentifierPath = formElement.get('__identifierPath');
1193 newIdentifierPath = pathPrefix + '/' + formElement.get('identifier');
1194
1195 propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
1196 if (!utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[oldIdentifierPath])) {
1197 propertyValidationServiceRegisteredValidators[newIdentifierPath] = propertyValidationServiceRegisteredValidators[oldIdentifierPath];
1198 delete propertyValidationServiceRegisteredValidators[oldIdentifierPath];
1199 }
1200 getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
1201
1202 formElement.set('__identifierPath', newIdentifierPath, disablePublishersOnSet);
1203 formElements = formElement.get('renderables');
1204 if ('array' === $.type(formElements)) {
1205 for (var i = 0, len = formElements.length; i < len; ++i) {
1206 reSetIdentifierPath(formElements[i], formElement.get('__identifierPath'));
1207 }
1208 }
1209 };
1210
1211 /**
1212 * This is true on:
1213 * * Drag a Element on a Page Element (tree)
1214 * * Drag a Element on a Section Element (tree)
1215 */
1216 if (position === 'inside') {
1217 utility().assert(!formElementToMoveTypeDefinition['_isTopLevelFormElement'], 'This move is not allowed', 1476993731);
1218 utility().assert(referenceFormElementTypeDefinition['_isCompositeFormElement'], 'This move is not allowed', 1476993732);
1219
1220 formElementToMove.set('__parentRenderable', referenceFormElement, disablePublishersOnSet);
1221 reSetIdentifierPath(formElementToMove, referenceFormElement.get('__identifierPath'));
1222
1223 referenceFormElementElements = referenceFormElement.get('renderables');
1224 if (utility().isUndefinedOrNull(referenceFormElementElements)) {
1225 referenceFormElementElements = [];
1226 }
1227 referenceFormElementElements.splice(0, 0, formElementToMove);
1228 referenceFormElement.set('renderables', referenceFormElementElements, disablePublishersOnSet);
1229 } else {
1230 /**
1231 * This is true on:
1232 * * Drag a Page before another Page (tree)
1233 * * Drag a Page after another Page (tree)
1234 */
1235 if (formElementToMoveTypeDefinition['_isTopLevelFormElement'] && referenceFormElementTypeDefinition['_isTopLevelFormElement']) {
1236 referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
1237 referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
1238
1239 if (position === 'after') {
1240 referenceFormElementParentElements.splice(referenceFormElementIndex + 1, 0, formElementToMove);
1241 } else {
1242 referenceFormElementParentElements.splice(referenceFormElementIndex, 0, formElementToMove);
1243 }
1244
1245 referenceFormElement.get('__parentRenderable').set('renderables', referenceFormElementParentElements, disablePublishersOnSet);
1246 } else {
1247 /**
1248 * This is true on:
1249 * * Drag a Element before another Element within the same level (tree)
1250 * * Drag a Element after another Element within the same level (tree)
1251 * * Drag a Element before another Element (stage)
1252 * * Drag a Element after another Element (stage)
1253 */
1254 if (formElementToMove.get('__parentRenderable').get('identifier') === referenceFormElement.get('__parentRenderable').get('identifier')) {
1255 referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
1256 referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
1257 } else {
1258 /**
1259 * This is true on:
1260 * * Drag a Element before an Element on another page (tree)
1261 * * Drag a Element after an Element on another page (tree)
1262 */
1263 formElementToMove.set('__parentRenderable', referenceFormElement.get('__parentRenderable'), disablePublishersOnSet);
1264 reSetIdentifierPath(formElementToMove, referenceFormElement.get('__parentRenderable').get('__identifierPath'));
1265
1266 referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
1267 referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
1268 }
1269
1270 if (position === 'after') {
1271 referenceFormElementParentElements.splice(referenceFormElementIndex + 1, 0, formElementToMove);
1272 } else {
1273 referenceFormElementParentElements.splice(referenceFormElementIndex, 0, formElementToMove);
1274 }
1275
1276 referenceFormElement.get('__parentRenderable').set('renderables', referenceFormElementParentElements, disablePublishersOnSet);
1277 }
1278 }
1279
1280 return formElementToMove;
1281 };
1282
1283 /**
1284 * @param object formElement
1285 * @return int
1286 * @throws 1475364963
1287 */
1288 function getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement(formElement) {
1289 var enclosingCompositeFormElementWhichIsOnTopLevel, formElementTypeDefinition;
1290 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364963);
1291
1292 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
1293
1294 if (formElementTypeDefinition['_isTopLevelFormElement'] && formElementTypeDefinition['_isCompositeFormElement']) {
1295 enclosingCompositeFormElementWhichIsOnTopLevel = formElement;
1296 } else if (formElement.get('__identifierPath') === getApplicationStateStack().getCurrentState('formDefinition').get('__identifierPath')) {
1297 enclosingCompositeFormElementWhichIsOnTopLevel = getApplicationStateStack().getCurrentState('formDefinition').get('renderables')[0];
1298 } else {
1299 enclosingCompositeFormElementWhichIsOnTopLevel = findEnclosingCompositeFormElementWhichIsOnTopLevel(formElement);
1300 }
1301 return enclosingCompositeFormElementWhichIsOnTopLevel.get('__parentRenderable').get('renderables').indexOf(enclosingCompositeFormElementWhichIsOnTopLevel);
1302 };
1303
1304 /**
1305 * @param object formElement
1306 * @return object
1307 * @throws 1472556223
1308 * @throws 1475364964
1309 */
1310 function findEnclosingCompositeFormElementWhichIsOnTopLevel(formElement) {
1311 var formElementTypeDefinition;
1312 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364964);
1313 utility().assert('object' === $.type(formElement.get('__parentRenderable')), 'The root element is never encloused by anything', 1472556223);
1314
1315 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
1316 while (!formElementTypeDefinition['_isTopLevelFormElement']) {
1317 formElement = formElement.get('__parentRenderable');
1318 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
1319 }
1320
1321 return formElement;
1322 };
1323
1324 /**
1325 * @param object formElement
1326 * @return object|null
1327 * @throws 1475364965
1328 */
1329 function findEnclosingCompositeFormElementWhichIsNotOnTopLevel(formElement) {
1330 var formElementTypeDefinition;
1331 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364965);
1332
1333 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
1334 while (!formElementTypeDefinition['_isCompositeFormElement']) {
1335 if (formElementTypeDefinition['_isTopLevelFormElement']) {
1336 return null;
1337 }
1338 formElement = formElement.get('__parentRenderable');
1339 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
1340 }
1341 if (formElementTypeDefinition['_isTopLevelFormElement']) {
1342 return null;
1343 }
1344 return formElement;
1345 };
1346
1347 /**
1348 * @return object
1349 */
1350 function getNonCompositeNonToplevelFormElements() {
1351 var collect, nonCompositeNonToplevelFormElements;
1352
1353 collect = function(formElement) {
1354 var formElements, formElementTypeDefinition;
1355 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364961);
1356
1357 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
1358
1359 if (!formElementTypeDefinition['_isTopLevelFormElement'] && !formElementTypeDefinition['_isCompositeFormElement']) {
1360 nonCompositeNonToplevelFormElements.push(formElement);
1361 }
1362
1363 formElements = formElement.get('renderables');
1364 if ('array' === $.type(formElements)) {
1365 for (var i = 0, len = formElements.length; i < len; ++i) {
1366 collect(formElements[i]);
1367 }
1368 }
1369 };
1370
1371 nonCompositeNonToplevelFormElements = [];
1372 collect(getRootFormElement());
1373 return nonCompositeNonToplevelFormElements;
1374 };
1375
1376 /**
1377 * @param string identifier
1378 * @returl bool
1379 * @throws 1475364966
1380 */
1381 function isFormElementIdentifierUsed(identifier) {
1382 var checkIdentifier, identifierFound;
1383 utility().assert(utility().isNonEmptyString(identifier), 'Invalid parameter "identifier"', 1475364966);
1384
1385 checkIdentifier = function(formElement) {
1386 var formElements;
1387
1388 if (formElement.get('identifier') === identifier) {
1389 identifierFound = true;
1390 }
1391
1392 if (!identifierFound) {
1393 formElements = formElement.get('renderables');
1394 if ('array' === $.type(formElements)) {
1395 for (var i = 0, len = formElements.length; i < len; ++i) {
1396 checkIdentifier(formElements[i]);
1397 if (identifierFound) {
1398 break;
1399 }
1400 }
1401 }
1402 }
1403 }
1404
1405 checkIdentifier(getApplicationStateStack().getCurrentState('formDefinition'));
1406 return identifierFound;
1407 };
1408
1409 /**
1410 * @param string formElementType
1411 * @return string
1412 * @throws 1475373676
1413 */
1414 function getNextFreeFormElementIdentifier(formElementType) {
1415 var i, prefix;
1416 utility().assert(utility().isNonEmptyString(formElementType), 'Invalid parameter "formElementType"', 1475373676);
1417
1418 prefix = formElementType.toLowerCase().replace(/[^a-z0-9]/g, '-') + '-';
1419 i = 1;
1420 while (isFormElementIdentifierUsed(prefix + i)) {
1421 i++;
1422 }
1423 return prefix + i;
1424 };
1425
1426 /**
1427 * @param string identifierPath
1428 * @return object
1429 * @throws 1472424333
1430 * @throws 1472424334
1431 * @throws 1472424330
1432 * @throws 1475373677
1433 */
1434 function findFormElementByIdentifierPath(identifierPath) {
1435 var obj, pathParts, pathPartsLength, formElement, formElements;
1436
1437 utility().assert(utility().isNonEmptyString(identifierPath), 'Invalid parameter "identifierPath"', 1475373677);
1438
1439 formElement = getApplicationStateStack().getCurrentState('formDefinition');
1440 pathParts = identifierPath.split('/');
1441 pathPartsLength = pathParts.length;
1442
1443 for (var i = 0; i < pathPartsLength; ++i) {
1444 var key = pathParts[i];
1445 if (i === 0 || i === pathPartsLength) {
1446 utility().assert(key === formElement.get('identifier'), '"' + key + '" does not exist in path "' + identifierPath + '"', 1472424333);
1447 continue;
1448 }
1449
1450 formElements = formElement.get('renderables');
1451 if ('array' === $.type(formElements)) {
1452 obj = null;
1453 for (var j = 0, len = formElements.length; j < len; ++j) {
1454 if (key === formElements[j].get('identifier')) {
1455 obj = formElements[j];
1456 break;
1457 }
1458 }
1459
1460 utility().assert('null' !== $.type(obj), 'Could not find form element "' + key + '" in path "' + identifierPath + '"', 1472424334);
1461 formElement = obj;
1462 } else {
1463 utility().assert(false, 'No form elements found', 1472424330);
1464 }
1465 }
1466 return formElement;
1467 };
1468
1469 /**
1470 * @param string|object formElement
1471 * @return object
1472 */
1473 function findFormElement(formElement) {
1474 if ('object' === $.type(formElement)) {
1475 formElement = formElement.get('__identifierPath');
1476 }
1477 return findFormElementByIdentifierPath(formElement);
1478 };
1479
1480 /**
1481 * @public
1482 *
1483 * @param string collectionElementIdentifier
1484 * @param object collection
1485 * @return undefined|object
1486 * @throws 1475375281
1487 * @throws 1475375282
1488 */
1489 function findCollectionElementByIdentifierPath(collectionElementIdentifier, collection) {
1490 utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375281);
1491 utility().assert('array' === $.type(collection), 'Invalid parameter "collection"', 1475375282);
1492
1493 for (var i = 0, len = collection.length; i < len; ++i) {
1494 if (collection[i]['identifier'] === collectionElementIdentifier) {
1495 return collection[i];
1496 }
1497 }
1498
1499 return undefined;
1500 };
1501
1502 /**
1503 * @public
1504 *
1505 * @param string collectionElementIdentifier
1506 * @param string collectionName
1507 * @param object formElement
1508 * @return int
1509 * @throws 1475375283
1510 * @throws 1475375284
1511 * @throws 1475375285
1512 */
1513 function getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement) {
1514 var collection;
1515 utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375283);
1516 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375284);
1517 utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375285);
1518
1519 collection = formElement.get(collectionName);
1520 if ('array' === $.type(collection)) {
1521 for (var i = 0, len = collection.length; i < len; ++i) {
1522 if (collection[i]['identifier'] === collectionElementIdentifier) {
1523 return i;
1524 }
1525 }
1526 }
1527 return -1;
1528 };
1529
1530 /**
1531 * @public
1532 *
1533 * @param object collectionElementToAdd
1534 * @param string collectionName
1535 * @param object formElement
1536 * @param string referenceCollectionElementIdentifier
1537 * @param boolean disablePublishersOnSet
1538 * @return object
1539 * @throws 1475375686
1540 * @throws 1475375687
1541 * @throws 1475375688
1542 * @throws 1477413154
1543 */
1544 function addPropertyCollectionElement(collectionElementToAdd, collectionName, formElement, referenceCollectionElementIdentifier, disablePublishersOnSet) {
1545 var collection, formElementTypeDefinition, newCollection, newCollectionElementIndex;
1546 utility().assert('object' === $.type(collectionElementToAdd), 'Invalid parameter "collectionElementToAdd"', 1475375686);
1547 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375687);
1548 utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375688);
1549
1550 if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
1551 disablePublishersOnSet = true;
1552 }
1553 disablePublishersOnSet = !!disablePublishersOnSet;
1554
1555 collection = formElement.get(collectionName);
1556 if ('array' !== $.type(collection)) {
1557 extendModel(formElement, [], collectionName, true);
1558 collection = formElement.get(collectionName);
1559 }
1560
1561 if (utility().isUndefinedOrNull(referenceCollectionElementIdentifier)) {
1562 newCollectionElementIndex = 0;
1563 } else {
1564 newCollectionElementIndex = getIndexFromPropertyCollectionElementByIdentifier(referenceCollectionElementIdentifier, collectionName, formElement) + 1;
1565 utility().assert(-1 < newCollectionElementIndex, 'Could not find collection element ' + referenceCollectionElementIdentifier + ' within collection ' + collectionName, 1477413154);
1566 }
1567
1568 collection.splice(newCollectionElementIndex, 0, collectionElementToAdd);
1569 formElement.set(collectionName, collection, true);
1570
1571 propertyValidationService().removeValidatorIdentifiersFromFormElementProperty(formElement, collectionName);
1572
1573 for (var i = 0, len = collection.length; i < len; ++i) {
1574 extendModel(formElement, collection[i], collectionName + '.' + i, true);
1575 }
1576
1577 formElement.set(collectionName, collection, true);
1578 propertyValidationService().addValidatorIdentifiersFromFormElementPropertyCollections(formElement);
1579 formElement.set(collectionName, collection, disablePublishersOnSet);
1580
1581 return formElement;
1582 };
1583
1584 /**
1585 * @public
1586 *
1587 * @param object formElement
1588 * @param string collectionElementIdentifier
1589 * @param string collectionName
1590 * @param boolean disablePublishersOnSet
1591 * @return void
1592 * @throws 1475375689
1593 * @throws 1475375690
1594 * @throws 1475375691
1595 * @throws 1475375692
1596 */
1597 function removePropertyCollectionElementByIdentifier(formElement, collectionElementIdentifier, collectionName, disablePublishersOnSet) {
1598 var collection, collectionElementIndex;
1599 utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375689);
1600 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375690);
1601 utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375691);
1602
1603 collection = formElement.get(collectionName);
1604 utility().assert('array' === $.type(collection), 'The collection "' + collectionName + '" does not exist', 1475375692);
1605
1606 if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
1607 disablePublishersOnSet = true;
1608 }
1609 disablePublishersOnSet = !!disablePublishersOnSet;
1610
1611 propertyValidationService().removeValidatorIdentifiersFromFormElementProperty(formElement, collectionName);
1612 collectionElementIndex = getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement);
1613 collection.splice(collectionElementIndex, 1);
1614 formElement.set(collectionName, collection, disablePublishersOnSet);
1615 propertyValidationService().addValidatorIdentifiersFromFormElementPropertyCollections(formElement);
1616 };
1617
1618 /**
1619 * @param string collectionElementToMoveIdentifier
1620 * @param string position
1621 * @param string referenceCollectionElementIdentifier
1622 * @param string position
1623 * @param object formElement
1624 * @param boolean disablePublishersOnSet
1625 * @return void
1626 * @throws 1477404484
1627 * @throws 1477404485
1628 * @throws 1477404486
1629 * @throws 1477404488
1630 * @throws 1477404489
1631 * @throws 1477404490
1632 */
1633 function movePropertyCollectionElement(collectionElementToMoveIdentifier, position, referenceCollectionElementIdentifier, collectionName, formElement, disablePublishersOnSet) {
1634 var collection, collectionElementToMove, referenceCollectionElement, referenceCollectionElementIndex;
1635
1636 utility().assert('after' === position || 'before' === position, 'Invalid position "' + position + '"', 1477404485);
1637 utility().assert('string' === $.type(referenceCollectionElementIdentifier), 'Invalid parameter "referenceCollectionElementIdentifier"', 1477404486);
1638 utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1477404488);
1639
1640 collection = formElement.get(collectionName);
1641 utility().assert('array' === $.type(collection), 'The collection "' + collectionName + '" does not exist', 1477404490);
1642
1643 collectionElementToMove = findCollectionElementByIdentifierPath(collectionElementToMoveIdentifier, collection);
1644 utility().assert('object' === $.type(collectionElementToMove), 'Invalid parameter "collectionElementToMove"', 1477404484);
1645
1646 removePropertyCollectionElementByIdentifier(formElement, collectionElementToMoveIdentifier, collectionName);
1647
1648 referenceCollectionElementIndex = getIndexFromPropertyCollectionElementByIdentifier(referenceCollectionElementIdentifier, collectionName, formElement);
1649 utility().assert(-1 < referenceCollectionElementIndex, 'Could not find collection element ' + referenceCollectionElementIdentifier + ' within collection ' + collectionName, 1477404489);
1650
1651 if ('before' === position) {
1652 referenceCollectionElement = collection[referenceCollectionElementIndex - 1];
1653 if (utility().isUndefinedOrNull(referenceCollectionElement)) {
1654 referenceCollectionElementIdentifier = undefined;
1655 } else {
1656 referenceCollectionElementIdentifier = referenceCollectionElement['identifier'];
1657 }
1658 }
1659
1660 addPropertyCollectionElement(collectionElementToMove, collectionName, formElement, referenceCollectionElementIdentifier, disablePublishersOnSet)
1661 };
1662
1663 /**
1664 * Publish the public methods.
1665 */
1666 return {
1667 getRootFormElement: getRootFormElement,
1668
1669 getFormEditorDefinition: getFormEditorDefinition,
1670 setFormEditorDefinitions: setFormEditorDefinitions,
1671
1672 findFormElement: findFormElement,
1673 findFormElementByIdentifierPath: findFormElementByIdentifierPath,
1674 findEnclosingCompositeFormElementWhichIsNotOnTopLevel: findEnclosingCompositeFormElementWhichIsNotOnTopLevel,
1675 findEnclosingCompositeFormElementWhichIsOnTopLevel: findEnclosingCompositeFormElementWhichIsOnTopLevel,
1676 getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement: getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement,
1677 getNonCompositeNonToplevelFormElements: getNonCompositeNonToplevelFormElements,
1678
1679 getNextFreeFormElementIdentifier: getNextFreeFormElementIdentifier,
1680 isFormElementIdentifierUsed: isFormElementIdentifierUsed,
1681
1682 addFormElement: addFormElement,
1683 moveFormElement: moveFormElement,
1684 removeFormElement: removeFormElement,
1685
1686 findCollectionElementByIdentifierPath: findCollectionElementByIdentifierPath,
1687 getIndexFromPropertyCollectionElementByIdentifier: getIndexFromPropertyCollectionElementByIdentifier,
1688 addPropertyCollectionElement: addPropertyCollectionElement,
1689 removePropertyCollectionElementByIdentifier: removePropertyCollectionElementByIdentifier,
1690 movePropertyCollectionElement: movePropertyCollectionElement
1691 };
1692 };
1693
1694 /**
1695 * @public
1696 *
1697 * @return object
1698 */
1699 function factory() {
1700
1701 /**
1702 * @public
1703 *
1704 * @param object configuration
1705 * @param string identifierPathPrefix
1706 * @param object parentFormElement
1707 * @param boolean registerPropertyValidators
1708 * @param boolean disablePublishersOnSet
1709 * @return object
1710 * @throws 1475375693
1711 * @throws 1475436040
1712 * @throws 1475604050
1713 */
1714 function createFormElement(configuration, identifierPathPrefix, parentFormElement, registerPropertyValidators, disablePublishersOnSet) {
1715 var currentChildFormElements, collections, formElementTypeDefinition, identifierPath, rawChildFormElements, formElement, predefinedDefaults;
1716 utility().assert('object' === $.type(configuration), 'Invalid parameter "configuration"', 1475375693);
1717 utility().assert(utility().isNonEmptyString(configuration['identifier']), '"identifier" must not be empty', 1475436040);
1718 utility().assert(utility().isNonEmptyString(configuration['type']), '"type" must not be empty', 1475604050);
1719
1720 registerPropertyValidators = !!registerPropertyValidators;
1721 if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
1722 disablePublishersOnSet = true;
1723 }
1724 disablePublishersOnSet = !!disablePublishersOnSet;
1725
1726 formElementTypeDefinition = repository().getFormEditorDefinition('formElements', configuration['type']);
1727 rawChildFormElements = configuration['renderables'];
1728 delete configuration['renderables'];
1729
1730 collections = {};
1731 predefinedDefaults = formElementTypeDefinition['predefinedDefaults'] || {};
1732 for (var collectionName in configuration) {
1733 if (!configuration.hasOwnProperty(collectionName)) {
1734 continue;
1735 }
1736 if (utility().isUndefinedOrNull(_repositoryFormEditorDefinitions[collectionName])) {
1737 continue;
1738 }
1739
1740 predefinedDefaults[collectionName] = predefinedDefaults[collectionName] || {};
1741 collections[collectionName] = $.extend(
1742 predefinedDefaults[collectionName] || {},
1743 configuration[collectionName]
1744 );
1745
1746 delete predefinedDefaults[collectionName];
1747 delete configuration[collectionName];
1748 }
1749
1750 identifierPathPrefix = identifierPathPrefix || '';
1751 identifierPath = (identifierPathPrefix === '') ? configuration['identifier'] : identifierPathPrefix + '/' + configuration['identifier'];
1752
1753 configuration = $.extend(
1754 formElementTypeDefinition['predefinedDefaults'] || {},
1755 configuration,
1756 {
1757 renderables: (rawChildFormElements) ? true : null,
1758 __parentRenderable: null,
1759 __identifierPath: identifierPath
1760 }
1761 );
1762
1763 formElement = createModel(configuration);
1764 formElement.set('__parentRenderable', parentFormElement || null, disablePublishersOnSet);
1765
1766 for (var collectionName in collections) {
1767 if (!collections.hasOwnProperty(collectionName)) {
1768 continue;
1769 }
1770
1771 for (var i in collections[collectionName]) {
1772 var previousCreatePropertyCollectionElementIdentifier, propertyCollectionElement;
1773 if (!collections[collectionName].hasOwnProperty(i)) {
1774 continue;
1775 }
1776 propertyCollectionElement = createPropertyCollectionElement(
1777 collections[collectionName][i]['identifier'],
1778 collections[collectionName][i],
1779 collectionName
1780 );
1781 if (i > 0) {
1782 previousCreatePropertyCollectionElementIdentifier = collections[collectionName][i - 1]['identifier']
1783 }
1784 repository().addPropertyCollectionElement(propertyCollectionElement, collectionName, formElement, previousCreatePropertyCollectionElementIdentifier, true);
1785 }
1786 }
1787
1788 if (registerPropertyValidators) {
1789 if ('array' === $.type(formElementTypeDefinition['editors'])) {
1790 for (var i = 0, len1 = formElementTypeDefinition['editors'].length; i < len1; ++i) {
1791 var configuration = {};
1792
1793 if ('array' !== $.type(formElementTypeDefinition['editors'][i]['propertyValidators'])) {
1794 continue;
1795 }
1796
1797 if (
1798 !utility().isUndefinedOrNull(formElementTypeDefinition['editors'][i]['propertyValidatorsMode'])
1799 && formElementTypeDefinition['editors'][i]['propertyValidatorsMode'] === 'OR'
1800 ) {
1801 configuration['propertyValidatorsMode'] = 'OR';
1802 } else {
1803 configuration['propertyValidatorsMode'] = 'AND';
1804 }
1805
1806 propertyValidationService().addValidatorIdentifiersToFormElementProperty(
1807 formElement,
1808 formElementTypeDefinition['editors'][i]['propertyValidators'],
1809 formElementTypeDefinition['editors'][i]['propertyPath'],
1810 undefined,
1811 undefined,
1812 configuration
1813 );
1814 }
1815 }
1816 }
1817
1818 if ('array' === $.type(rawChildFormElements)) {
1819 currentChildFormElements = [];
1820 for (var i = 0, len = rawChildFormElements.length; i < len; ++i) {
1821 currentChildFormElements.push(createFormElement(rawChildFormElements[i], identifierPath, formElement, registerPropertyValidators, disablePublishersOnSet));
1822 }
1823 formElement.set('renderables', currentChildFormElements, disablePublishersOnSet);
1824 }
1825 return formElement;
1826 };
1827
1828 /**
1829 * @public
1830 *
1831 * @param string collectionElementIdentifier
1832 * @param object collectionElementConfiguration
1833 * @param string collectionName
1834 * @return object
1835 * @throws 1475377160
1836 * @throws 1475377161
1837 * @throws 1475377162
1838 */
1839 function createPropertyCollectionElement(collectionElementIdentifier, collectionElementConfiguration, collectionName) {
1840 var collectionDefinition, collectionElementPresets;
1841 utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475377160);
1842 utility().assert('object' === $.type(collectionElementConfiguration), 'Invalid parameter "collectionElementConfiguration"', 1475377161);
1843 utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475377162);
1844
1845 collectionElementConfiguration['identifier'] = collectionElementIdentifier;
1846 collectionDefinition = repository().getFormEditorDefinition(collectionName, collectionElementIdentifier);
1847 if (collectionDefinition['predefinedDefaults']) {
1848 collectionElementPresets = collectionDefinition['predefinedDefaults'];
1849 } else {
1850 collectionElementPresets = {};
1851 }
1852
1853 return $.extend(collectionElementPresets, collectionElementConfiguration);
1854 };
1855
1856 /**
1857 * Publish the public methods.
1858 */
1859 return {
1860 createFormElement: createFormElement,
1861 createPropertyCollectionElement: createPropertyCollectionElement
1862 };
1863 };
1864
1865 /**
1866 * @public
1867 *
1868 * @return object
1869 */
1870 function dataBackend() {
1871
1872 /**
1873 * @public
1874 *
1875 * @param object endpoints
1876 * @return void
1877 * @throws 1475377488
1878 */
1879 function setEndpoints(endpoints) {
1880 utility().assert('object' === $.type(endpoints), 'Invalid parameter "endpoints"', 1475377488);
1881 _dataBackendEndpoints = endpoints;
1882 };
1883
1884 /**
1885 * @public
1886 *
1887 * @param string prototypeName
1888 * @return void
1889 * @throws 1475377489
1890 */
1891 function setPrototypeName(prototypeName) {
1892 utility().assert(utility().isNonEmptyString(prototypeName), 'Invalid parameter "prototypeName"', 1475928095);
1893 _dataBackendPrototypeName = prototypeName;
1894 };
1895
1896 /**
1897 * @public
1898 *
1899 * @param string persistenceIdentifier
1900 * @return void
1901 * @throws 1475377489
1902 */
1903 function setPersistenceIdentifier(persistenceIdentifier) {
1904 utility().assert(utility().isNonEmptyString(persistenceIdentifier), 'Invalid parameter "persistenceIdentifier"', 1475377489);
1905 _dataBackendPersistenceIdentifier = persistenceIdentifier;
1906 };
1907
1908 /**
1909 * @public
1910 *
1911 * @return void
1912 * @publish core/ajax/saveFormDefinition/success
1913 * @publish core/ajax/error
1914 * @throws 1475520918
1915 */
1916 function saveFormDefinition() {
1917 utility().assert(utility().isNonEmptyString(_dataBackendEndpoints['saveForm']), 'The endpoint "saveForm" is not configured', 1475520918);
1918
1919 if (_runningAjaxRequests['saveForm']) {
1920 _runningAjaxRequests['saveForm'].abort();
1921 }
1922
1923 _runningAjaxRequests['saveForm'] = $.post(_dataBackendEndpoints['saveForm'], {
1924 tx_form_web_formformbuilder: {
1925 formPersistenceIdentifier: _dataBackendPersistenceIdentifier,
1926 formDefinition: utility().convertToSimpleObject(getApplicationStateStack().getCurrentState('formDefinition'))
1927 }
1928 }, function(data, textStatus, jqXHR) {
1929 if (_runningAjaxRequests['saveForm'] !== jqXHR) {
1930 return;
1931 }
1932 _runningAjaxRequests['saveForm'] = null;
1933 publisherSubscriber().publish('core/ajax/saveFormDefinition/success', [data]);
1934 }).fail(function(jqXHR, textStatus, errorThrown) {
1935 publisherSubscriber().publish('core/ajax/error', [jqXHR, textStatus, errorThrown]);
1936 });
1937 };
1938
1939 /**
1940 * @public
1941 *
1942 * @param int pageIndex
1943 * @return void
1944 * @publish core/ajax/renderFormDefinitionPage/success
1945 * @publish core/ajax/error
1946 * @throws 1473447677
1947 * @throws 1475377781
1948 * @throws 1475377782
1949 */
1950 function renderFormDefinitionPage(pageIndex) {
1951 utility().assert($.isNumeric(pageIndex), 'Invalid parameter "pageIndex"', 1475377781);
1952 utility().assert(utility().isNonEmptyString(_dataBackendEndpoints['formPageRenderer']), 'The endpoint "formPageRenderer" is not configured', 1473447677);
1953
1954 if (_runningAjaxRequests['renderFormDefinitionPage']) {
1955 _runningAjaxRequests['renderFormDefinitionPage'].abort();
1956 }
1957
1958 _runningAjaxRequests['renderFormDefinitionPage'] = $.post(_dataBackendEndpoints['formPageRenderer'], {
1959 tx_form_web_formformbuilder: {
1960 formDefinition: utility().convertToSimpleObject(getApplicationStateStack().getCurrentState('formDefinition')),
1961 pageIndex: pageIndex,
1962 prototypeName: _dataBackendPrototypeName
1963 }
1964 }, function(data, textStatus, jqXHR) {
1965 if (_runningAjaxRequests['renderFormDefinitionPage'] !== jqXHR) {
1966 return;
1967 }
1968 _runningAjaxRequests['renderFormDefinitionPage'] = null;
1969 publisherSubscriber().publish('core/ajax/renderFormDefinitionPage/success', [data, pageIndex]);
1970 }).fail(function(jqXHR, textStatus, errorThrown) {
1971 publisherSubscriber().publish('core/ajax/error', [jqXHR, textStatus, errorThrown]);
1972 });
1973 };
1974
1975 /**
1976 * Publish the public methods.
1977 */
1978 return {
1979 renderFormDefinitionPage: renderFormDefinitionPage,
1980 saveFormDefinition: saveFormDefinition,
1981 setEndpoints: setEndpoints,
1982 setPersistenceIdentifier: setPersistenceIdentifier,
1983 setPrototypeName: setPrototypeName
1984 };
1985 };
1986
1987 /**
1988 * @public
1989 *
1990 * @return object
1991 */
1992 function getApplicationStateStack() {
1993
1994 /**
1995 * @public
1996 *
1997 * @param object applicationState
1998 * @param bool disablePublishersOnSet
1999 * @return void
2000 * @publish core/applicationState/add
2001 * @throws 1477847415
2002 */
2003 function add(applicationState, disablePublishersOnSet) {
2004 utility().assert('object' === $.type(applicationState), 'Invalid parameter "applicationState"', 1477847415);
2005 disablePublishersOnSet = !!disablePublishersOnSet;
2006
2007 $.extend(applicationState, {
2008 propertyValidationServiceRegisteredValidators: $.extend(true, {}, getCurrentState('propertyValidationServiceRegisteredValidators'))
2009 });
2010
2011 _applicationStateStack.splice(0, 0, applicationState);
2012 if (_applicationStateStack.length > _applicationStateStackSize) {
2013 _applicationStateStack.splice(_applicationStateStackSize - 1, (_applicationStateStack.length - _applicationStateStackSize));
2014 }
2015
2016 if (!disablePublishersOnSet) {
2017 publisherSubscriber().publish('core/applicationState/add', [applicationState, getCurrentStackPointer(), getCurrentStackSize()]);
2018 }
2019 };
2020
2021 /**
2022 * @public
2023 *
2024 * @param applicationState
2025 * @param bool disablePublishersOnSet
2026 * @return void
2027 * @publish core/applicationState/add
2028 * @throws 1477872641
2029 */
2030 function addAndReset(applicationState, disablePublishersOnSet) {
2031 utility().assert('object' === $.type(applicationState), 'Invalid parameter "applicationState"', 1477872641);
2032
2033 if (_applicationStateStackPointer > 0) {
2034 _applicationStateStack.splice(0, _applicationStateStackPointer);
2035 }
2036
2037 _applicationStateStackPointer = 0;
2038 add(applicationState, true);
2039
2040 if (!disablePublishersOnSet) {
2041 publisherSubscriber().publish('core/applicationState/add', [getCurrentState(), getCurrentStackPointer(), getCurrentStackSize()]);
2042 }
2043 };
2044
2045 /**
2046 * @public
2047 *
2048 * @param string
2049 * @return object
2050 * @throws 1477932754
2051 */
2052 function getCurrentState(type) {
2053 if (!utility().isUndefinedOrNull(type)) {
2054 utility().assert(
2055 'formDefinition' === type
2056 || 'currentlySelectedPageIndex' === type
2057 || 'currentlySelectedFormElementIdentifierPath' === type
2058 || 'propertyValidationServiceRegisteredValidators' === type,
2059
2060 'Invalid parameter "type"', 1477932754
2061 );
2062
2063 if ('undefined' === $.type(_applicationStateStack[_applicationStateStackPointer])) {
2064 return undefined;
2065 }
2066 return _applicationStateStack[_applicationStateStackPointer][type];
2067 }
2068 return _applicationStateStack[_applicationStateStackPointer];
2069 };
2070
2071 /**
2072 * @public
2073 *
2074 * @param string
2075 * @param mixed
2076 * @return void
2077 * @throws 1477934111
2078 */
2079 function setCurrentState(type, value) {
2080 utility().assert(
2081 'formDefinition' === type
2082 || 'currentlySelectedPageIndex' === type
2083 || 'currentlySelectedFormElementIdentifierPath' === type
2084 || 'propertyValidationServiceRegisteredValidators' === type,
2085
2086 'Invalid parameter "type"', 1477934111
2087 );
2088 _applicationStateStack[_applicationStateStackPointer][type] = value;
2089 };
2090
2091 /**
2092 * @public
2093 *
2094 * @param int
2095 * @return void
2096 * @throws 1477846933
2097 */
2098 function setMaximalStackSize(stackSize) {
2099 utility().assert('number' === $.type(stackSize), 'Invalid parameter "size"', 1477846933);
2100 _applicationStateStackSize = stackSize;
2101 };
2102
2103 /**
2104 * @public
2105 *
2106 * @return int
2107 */
2108 function getMaximalStackSize() {
2109 return _applicationStateStackSize;
2110 };
2111
2112 /**
2113 * @public
2114 *
2115 * @return int
2116 */
2117 function getCurrentStackSize() {
2118 return _applicationStateStack.length;
2119 };
2120
2121 /**
2122 * @public
2123 *
2124 * @return object
2125 */
2126 function getCurrentStackPointer() {
2127 return _applicationStateStackPointer;
2128 };
2129
2130 /**
2131 * @public
2132 *
2133 * @param int
2134 * @return void
2135 * @throws 1477852138
2136 */
2137 function setCurrentStackPointer(stackPointer) {
2138 utility().assert('number' === $.type(stackPointer), 'Invalid parameter "size"', 1477852138);
2139 if (stackPointer < 0) {
2140 _applicationStateStackPointer = 0;
2141 } else if (stackPointer > _applicationStateStack.length - 1) {
2142 _applicationStateStackPointer = _applicationStateStack.length - 1;
2143 } else {
2144 _applicationStateStackPointer = stackPointer;
2145 }
2146 };
2147
2148
2149 /**
2150 * @public
2151 *
2152 * @return void
2153 */
2154 function decrementCurrentStackPointer() {
2155 setCurrentStackPointer(--_applicationStateStackPointer);
2156 };
2157
2158 /**
2159 * @public
2160 *
2161 * @return void
2162 */
2163 function incrementCurrentStackPointer() {
2164 setCurrentStackPointer(++_applicationStateStackPointer);
2165 };
2166
2167 /**
2168 * Publish the public methods.
2169 */
2170 return {
2171 add: add,
2172 addAndReset: addAndReset,
2173 getCurrentState: getCurrentState,
2174 setCurrentState: setCurrentState,
2175 getCurrentStackPointer: getCurrentStackPointer,
2176 setCurrentStackPointer: setCurrentStackPointer,
2177 decrementCurrentStackPointer: decrementCurrentStackPointer,
2178 incrementCurrentStackPointer: incrementCurrentStackPointer,
2179 setMaximalStackSize: setMaximalStackSize,
2180 getMaximalStackSize: getMaximalStackSize,
2181 getCurrentStackSize: getCurrentStackSize
2182 };
2183 };
2184
2185 /**
2186 * Publish the public methods.
2187 * Implements the "Revealing Module Pattern".
2188 */
2189 return {
2190 getDataBackend: dataBackend,
2191 getFactory: factory,
2192 getPublisherSubscriber: publisherSubscriber,
2193 getRepository: repository,
2194 getUtility: utility,
2195 getPropertyValidationService: propertyValidationService,
2196 getRunningAjaxRequest: getRunningAjaxRequest,
2197 getApplicationStateStack: getApplicationStateStack
2198 };
2199 })($);
2200 });