7bb4513daaab3ab4d10859a5c68caa5b68fc24ed
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Resources / Public / JavaScript / Backend / FormEditor / InspectorComponent.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/InspectorComponent
16 */
17
18 /**
19 * Add legacy functions to be accessible in the global scope.
20 * This is needed by TYPO3/CMS/Recordlist/ElementBrowser
21 */
22 var setFormValueFromBrowseWin;
23
24 define(['jquery',
25 'TYPO3/CMS/Form/Backend/FormEditor/Helper',
26 'TYPO3/CMS/Backend/Icons',
27 'TYPO3/CMS/Backend/Notification',
28 'TYPO3/CMS/Form/Backend/Vendor/jquery.mjs.nestedSortable'
29 ], function($, Helper, Icons, Notification) {
30 'use strict';
31
32 return (function($, Helper, Icons, Notification) {
33
34 /**
35 * @private
36 *
37 * @var object
38 */
39 var _configuration = null;
40
41 /**
42 * @private
43 *
44 * @var object
45 */
46 var _defaultConfiguration = {
47 domElementClassNames: {
48 buttonFormElementRemove: 't3-form-remove-element-button',
49 collectionElement: 't3-form-collection-element',
50 finisherEditorPrefix: 't3-form-inspector-finishers-editor-',
51 inspectorEditor: 'form-editor',
52 inspectorInputGroup: 'input-group',
53 validatorEditorPrefix: 't3-form-inspector-validators-editor-'
54 },
55 domElementDataAttributeNames: {
56 contentElementSelectorTarget: 'data-insert-target',
57 finisher: 'data-finisher-identifier',
58 validator: 'data-validator-identifier'
59 },
60 domElementDataAttributeValues: {
61 collapse: 'actions-view-table-expand',
62 editorControlsInputGroup: 'inspectorEditorControlsGroup',
63 editorControlsWrapper: 'inspectorEditorControlsWrapper',
64 formElementHeaderEditor: 'inspectorFormElementHeaderEditor',
65 formElementSelectorControlsWrapper: 'inspectorEditorFormElementSelectorControlsWrapper',
66 formElementSelectorSplitButtonContainer: 'inspectorEditorFormElementSelectorSplitButtonContainer',
67 formElementSelectorSplitButtonListContainer: 'inspectorEditorFormElementSelectorSplitButtonListContainer',
68 iconNotAvailable: 'actions-message-error-close',
69 iconPage: 'apps-pagetree-page-default',
70 iconTtContent: 'mimetypes-x-content-text',
71 inspector: 'inspector',
72 'Inspector-CheckboxEditor': 'Inspector-CheckboxEditor',
73 'Inspector-CollectionElementHeaderEditor': 'Inspector-CollectionElementHeaderEditor',
74 'Inspector-FinishersEditor': 'Inspector-FinishersEditor',
75 'Inspector-FormElementHeaderEditor': 'Inspector-FormElementHeaderEditor',
76 'Inspector-PropertyGridEditor': 'Inspector-PropertyGridEditor',
77 'Inspector-RemoveElementEditor': 'Inspector-RemoveElementEditor',
78 'Inspector-RequiredValidatorEditor': 'Inspector-RequiredValidatorEditor',
79 'Inspector-SingleSelectEditor': 'Inspector-SingleSelectEditor',
80 'Inspector-MultiSelectEditor': 'Inspector-MultiSelectEditor',
81 'Inspector-TextareaEditor': 'Inspector-TextareaEditor',
82 'Inspector-TextEditor': 'Inspector-TextEditor',
83 'Inspector-Typo3WinBrowserEditor': 'Inspector-Typo3WinBrowserEditor',
84 'Inspector-ValidatorsEditor': 'Inspector-ValidatorsEditor',
85 inspectorFinishers: 'inspectorFinishers',
86 inspectorValidators: 'inspectorValidators',
87 propertyGridEditorAddRow: 'addRow',
88 propertyGridEditorAddRowItem: 'addRowItem',
89 propertyGridEditorContainer: 'propertyGridContainer',
90 propertyGridEditorDeleteRow: 'deleteRow',
91 propertyGridEditorLabel: 'label',
92 propertyGridEditorRowItem: 'rowItem',
93 propertyGridEditorSelectValue: 'selectValue',
94 propertyGridEditorSortRow: 'sortRow',
95 propertyGridEditorValue: 'value'
96 },
97 domElementIdNames: {
98 finisherPrefix: 't3-form-inspector-finishers-',
99 validatorPrefix: 't3-form-inspector-validators-'
100 },
101 isSortable: true
102 };
103
104 /**
105 * @private
106 *
107 * @var object
108 */
109 var _formEditorApp = null;
110
111 /* *************************************************************
112 * Private Methodes
113 * ************************************************************/
114
115 /**
116 * @private
117 *
118 * @return void
119 * @throws 1478268638
120 */
121 function _helperSetup() {
122 assert('function' === $.type(Helper.bootstrap),
123 'The view model helper does not implement the method "bootstrap"',
124 1478268638
125 );
126 Helper.bootstrap(getFormEditorApp());
127 };
128
129 /**
130 * @private
131 *
132 * @return object
133 */
134 function getFormEditorApp() {
135 return _formEditorApp;
136 };
137
138 /**
139 * @private
140 *
141 * @return object
142 */
143 function getViewModel() {
144 return getFormEditorApp().getViewModel();
145 };
146
147 /**
148 * @private
149 *
150 * @param object
151 * @return object
152 */
153 function getHelper(configuration) {
154 if (getUtility().isUndefinedOrNull(configuration)) {
155 return Helper.setConfiguration(_configuration);
156 }
157 return Helper.setConfiguration(configuration);
158 };
159
160 /**
161 * @private
162 *
163 * @return object
164 */
165 function getUtility() {
166 return getFormEditorApp().getUtility();
167 };
168
169 /**
170 * @private
171 *
172 * @param mixed test
173 * @param string message
174 * @param int messageCode
175 * @return void
176 */
177 function assert(test, message, messageCode) {
178 return getFormEditorApp().assert(test, message, messageCode);
179 };
180
181 /**
182 * @private
183 *
184 * @return object
185 */
186 function getCurrentlySelectedFormElement() {
187 return getFormEditorApp().getCurrentlySelectedFormElement();
188 };
189
190 /**
191 * @private
192 *
193 * @return object
194 */
195 function getRootFormElement() {
196 return getFormEditorApp().getRootFormElement();
197 };
198
199 /**
200 * @private
201 *
202 * @return object
203 */
204 function getPublisherSubscriber() {
205 return getFormEditorApp().getPublisherSubscriber();
206 };
207
208 /**
209 * @private
210 *
211 * @param object
212 * @param string
213 * @return mixed
214 */
215 function getFormElementDefinition(formElement, formElementDefinitionKey) {
216 return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey);
217 };
218
219 /**
220 * @private
221 *
222 * @param object
223 * @param object
224 * @param string
225 * @param string
226 * @return void
227 * @publish view/inspector/editor/insert/perform
228 */
229 function _renderEditorDispatcher(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
230 switch (editorConfiguration['templateName']) {
231 case 'Inspector-FormElementHeaderEditor':
232 renderFormElementHeaderEditor(
233 editorConfiguration,
234 editorHtml,
235 collectionElementIdentifier,
236 collectionName
237 );
238 break;
239 case 'Inspector-CollectionElementHeaderEditor':
240 renderCollectionElementHeaderEditor(
241 editorConfiguration,
242 editorHtml,
243 collectionElementIdentifier,
244 collectionName
245 );
246 break;
247 case 'Inspector-TextEditor':
248 renderTextEditor(
249 editorConfiguration,
250 editorHtml,
251 collectionElementIdentifier,
252 collectionName
253 );
254 break;
255 case 'Inspector-FinishersEditor':
256 renderCollectionElementSelectionEditor(
257 'finishers',
258 editorConfiguration,
259 editorHtml,
260 collectionElementIdentifier,
261 collectionName
262 );
263 break;
264 case 'Inspector-ValidatorsEditor':
265 renderCollectionElementSelectionEditor(
266 'validators',
267 editorConfiguration,
268 editorHtml,
269 collectionElementIdentifier,
270 collectionName
271 );
272 break;
273 case 'Inspector-RemoveElementEditor':
274 renderRemoveElementEditor(
275 editorConfiguration,
276 editorHtml,
277 collectionElementIdentifier,
278 collectionName
279 );
280 break;
281 case 'Inspector-RequiredValidatorEditor':
282 renderRequiredValidatorEditor(
283 editorConfiguration,
284 editorHtml,
285 collectionElementIdentifier,
286 collectionName
287 );
288 break;
289 case 'Inspector-CheckboxEditor':
290 renderCheckboxEditor(
291 editorConfiguration,
292 editorHtml,
293 collectionElementIdentifier,
294 collectionName
295 );
296 break;
297 case 'Inspector-SingleSelectEditor':
298 renderSingleSelectEditor(
299 editorConfiguration,
300 editorHtml,
301 collectionElementIdentifier,
302 collectionName
303 );
304 break;
305 case 'Inspector-MultiSelectEditor':
306 renderMultiSelectEditor(
307 editorConfiguration,
308 editorHtml,
309 collectionElementIdentifier,
310 collectionName
311 );
312 break;
313 case 'Inspector-PropertyGridEditor':
314 renderPropertyGridEditor(
315 editorConfiguration,
316 editorHtml,
317 collectionElementIdentifier,
318 collectionName
319 );
320 break;
321 case 'Inspector-TextareaEditor':
322 renderTextareaEditor(
323 editorConfiguration,
324 editorHtml,
325 collectionElementIdentifier,
326 collectionName
327 );
328 break;
329 case 'Inspector-Typo3WinBrowserEditor':
330 renderTypo3WinBrowserEditor(
331 editorConfiguration,
332 editorHtml,
333 collectionElementIdentifier,
334 collectionName
335 );
336 break;
337 }
338 getPublisherSubscriber().publish('view/inspector/editor/insert/perform', [
339 editorConfiguration, editorHtml, collectionElementIdentifier, collectionName
340 ]);
341 };
342
343 /**
344 * @private
345 *
346 * opens a popup window with the element browser
347 *
348 * @param string mode
349 * @param string params
350 * @param int width
351 * @param int height
352 */
353 function _openTypo3WinBrowser(mode, params, width, height) {
354 var openedPopupWindow, url;
355 url = TYPO3.settings.FormEditor.typo3WinBrowserUrl
356 + '&mode=' + mode + '&bparams=' + params;
357 openedPopupWindow = window.open(
358 url,
359 'Typo3WinBrowser',
360 'height=' + height + ',width=' + width + ',status=0,menubar=0,resizable=1,scrollbars=1'
361 );
362 openedPopupWindow.focus();
363 };
364
365 /**
366 * @private
367 *
368 * @param string
369 * @param string
370 * @return object
371 */
372 function _getCollectionElementClass(collectionName, collectionElementIdentifier) {
373 if (collectionName === 'finishers') {
374 return getHelper()
375 .getDomElementClassName('finisherEditorPrefix') + collectionElementIdentifier;
376 } else {
377 return getHelper()
378 .getDomElementClassName('validatorEditorPrefix') + collectionElementIdentifier;
379 }
380 };
381
382 /**
383 * @private
384 *
385 * @param string
386 * @param string
387 * @param bool
388 * @return object
389 */
390 function _getCollectionElementId(collectionName, collectionElementIdentifier, asSelector) {
391 if (collectionName === 'finishers') {
392 return getHelper()
393 .getDomElementIdName('finisherPrefix', asSelector) + collectionElementIdentifier;
394 } else {
395 return getHelper()
396 .getDomElementIdName('validatorPrefix', asSelector) + collectionElementIdentifier;
397 }
398 };
399
400 /**
401 * @private
402 *
403 * @param object
404 * @param string
405 * @return void
406 */
407 function _addSortableCollectionElementsEvents(sortableDomElement, collectionName) {
408 sortableDomElement.addClass(getHelper().getDomElementClassName('sortable')).sortable({
409 revert: 'true',
410 items: getHelper().getDomElementClassName('collectionElement', true),
411 cancel: getHelper().getDomElementClassName('jQueryUiStateDisabled', true) + ',input,select',
412 delay: 200,
413 update: function(e, o) {
414 var dataAttributeName, nextCollectionElementIdentifier, movedCollectionElementIdentifier, previousCollectionElementIdentifier;
415
416 if (collectionName === 'finishers') {
417 dataAttributeName = getHelper().getDomElementDataAttribute('finisher');
418 } else {
419 dataAttributeName = getHelper().getDomElementDataAttribute('validator');
420 }
421
422 movedCollectionElementIdentifier = $(o.item).attr(dataAttributeName);
423 previousCollectionElementIdentifier = $(o.item)
424 .prevAll(getHelper().getDomElementClassName('collectionElement', true))
425 .first()
426 .attr(dataAttributeName);
427 nextCollectionElementIdentifier = $(o.item)
428 .nextAll(getHelper().getDomElementClassName('collectionElement', true))
429 .first()
430 .attr(dataAttributeName);
431
432 getPublisherSubscriber().publish('view/inspector/collectionElements/dnd/update', [
433 movedCollectionElementIdentifier,
434 previousCollectionElementIdentifier,
435 nextCollectionElementIdentifier,
436 collectionName
437 ]);
438 }
439 });
440 };
441
442 /**
443 * @private
444 *
445 * @param object editorHtml
446 * @param bool multiSelection
447 * @param string propertyPath
448 * @param string propertyPathPrefix
449 * @return void
450 */
451 function _setPropertyGridData(editorHtml, multiSelection, propertyPath, propertyPathPrefix) {
452 var defaultValue, newPropertyData;
453
454 if (multiSelection) {
455 defaultValue = [];
456
457 $( getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer') + ' ' +
458 getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue') + ':checked',
459 $(editorHtml)
460 ).each(function(i) {
461 defaultValue.push(
462 $(this)
463 .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
464 .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
465 .val()
466 );
467 });
468 getCurrentlySelectedFormElement().set(propertyPathPrefix + 'defaultValue', defaultValue);
469 } else {
470 getCurrentlySelectedFormElement().set(
471 propertyPathPrefix + 'defaultValue',
472 $(
473 getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer') + ' ' +
474 getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue') + ':checked',
475 $(editorHtml)
476 ).first()
477 .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
478 .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
479 .val(),
480 true
481 );
482 }
483
484 newPropertyData = [];
485 $(
486 getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer') + ' ' +
487 getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'),
488 $(editorHtml)
489 ).each(function(i) {
490 var value, label, tmpObject;
491
492 value = $(this)
493 .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
494 .val();
495 label = $(this)
496 .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel'))
497 .val();
498
499 if ('' === value) {
500 value = label;
501 }
502
503 tmpObject = {};
504 tmpObject[value] = label;
505 newPropertyData.push({
506 _label: label,
507 _value: value
508 });
509 });
510
511 getCurrentlySelectedFormElement().set(propertyPathPrefix + propertyPath, newPropertyData);
512 };
513
514 /**
515 * @private
516 *
517 * @param object
518 * @return object
519 */
520 function _getEditorControlsWrapperDomElement(editorDomElement) {
521 return $(getHelper().getDomElementDataIdentifierSelector('editorControlsWrapper'), $(editorDomElement));
522 };
523
524 /**
525 * @private
526 *
527 * @param string
528 * @param object
529 * @return void
530 */
531 function _validateCollectionElement(propertyPath, editorHtml) {
532 var hasError, propertyPrefix, validationResults;
533
534 validationResults = getFormEditorApp().validateCurrentlySelectedFormElementProperty(propertyPath);
535
536 if (validationResults.length > 0) {
537 getHelper()
538 .getTemplatePropertyDomElement('validationErrors', editorHtml)
539 .text(validationResults[0]);
540 getViewModel().setElementValidationErrorClass(
541 getHelper().getTemplatePropertyDomElement('validationErrors', editorHtml)
542 );
543 getViewModel().setElementValidationErrorClass(
544 _getEditorControlsWrapperDomElement(editorHtml),
545 'hasError'
546 );
547 } else {
548 getHelper().getTemplatePropertyDomElement('validationErrors', editorHtml).text('');
549 getViewModel().removeElementValidationErrorClass(
550 getHelper().getTemplatePropertyDomElement('validationErrors', editorHtml)
551 );
552 getViewModel().removeElementValidationErrorClass(
553 _getEditorControlsWrapperDomElement(editorHtml),
554 'hasError'
555 );
556 }
557
558 validationResults = getFormEditorApp().validateFormElement(getCurrentlySelectedFormElement());
559 propertyPrefix = propertyPath.split('.');
560 propertyPrefix = propertyPrefix[0] + '.' + propertyPrefix[1];
561
562 hasError = false;
563 for (var i = 0, len = validationResults.length; i < len; ++i) {
564 if (
565 validationResults[i]['propertyPath'].indexOf(propertyPrefix, 0) === 0
566 && validationResults[i]['validationResults']
567 && validationResults[i]['validationResults'].length > 0
568 ) {
569 hasError = true;
570 break;
571 }
572 }
573
574 if (hasError) {
575 getViewModel().setElementValidationErrorClass(
576 _getEditorControlsWrapperDomElement(editorHtml).closest(getHelper().getDomElementClassName('collectionElement', true))
577 );
578 } else {
579 getViewModel().removeElementValidationErrorClass(
580 _getEditorControlsWrapperDomElement(editorHtml).closest(getHelper().getDomElementClassName('collectionElement', true))
581 );
582 }
583 };
584
585 /* *************************************************************
586 * Public Methodes
587 * ************************************************************/
588
589 /**
590 * @public
591 *
592 * callback from TYPO3/CMS/Recordlist/ElementBrowser
593 *
594 * @param string fieldReference
595 * @param string elValue
596 * @param string elName
597 * @return void
598 */
599 setFormValueFromBrowseWin = function(fieldReference, elValue, elName) {
600 var result;
601 result = elValue.split('_');
602
603 $(getHelper().getDomElementDataAttribute('contentElementSelectorTarget', 'bracesWithKeyValue', [fieldReference]))
604 .val(result.pop())
605 .trigger('paste');
606 };
607
608 /**
609 * @public
610 *
611 * @return object
612 */
613 function getInspectorDomElement() {
614 return $(getHelper().getDomElementDataIdentifierSelector('inspector'));
615 };
616
617 /**
618 * @public
619 *
620 * @return object
621 */
622 function getFinishersContainerDomElement() {
623 return $(getHelper().getDomElementDataIdentifierSelector('inspectorFinishers'), getInspectorDomElement());
624 };
625
626 /**
627 * @public
628 *
629 * @return object
630 */
631 function getValidatorsContainerDomElement() {
632 return $(getHelper().getDomElementDataIdentifierSelector('inspectorValidators'), getInspectorDomElement());
633 };
634
635 /**
636 * @public
637 *
638 * @param string
639 * @param string
640 * @return object
641 */
642 function getCollectionElementDomElement(collectionName, collectionElementIdentifier) {
643 if (collectionName === 'finishers') {
644 return $(getHelper().getDomElementDataAttribute(
645 'finisher',
646 'bracesWithKeyValue',
647 [collectionElementIdentifier]
648 ), getFinishersContainerDomElement());
649 } else {
650 return $(getHelper().getDomElementDataAttribute(
651 'validator',
652 'bracesWithKeyValue',
653 [collectionElementIdentifier]
654 ), getValidatorsContainerDomElement());
655 }
656 };
657
658 /**
659 * @public
660 *
661 * @param object
662 * @param function
663 * @return void
664 */
665 function renderEditors(formElement, callback) {
666 var formElementTypeDefinition;
667 if (getUtility().isUndefinedOrNull(formElement)) {
668 formElement = getCurrentlySelectedFormElement();
669 }
670
671 getInspectorDomElement().off().empty();
672
673 formElementTypeDefinition = getFormElementDefinition(formElement);
674 if ('array' !== $.type(formElementTypeDefinition['editors'])) {
675 return;
676 }
677
678 for (var i = 0, len = formElementTypeDefinition['editors'].length; i < len; ++i) {
679 var html, template;
680
681 template = getHelper()
682 .getTemplate(formElementTypeDefinition['editors'][i]['templateName'])
683 .clone();
684 if (!template.length) {
685 continue;
686 }
687 html = $(template.html());
688
689 $(html)
690 .first()
691 .addClass(getHelper().getDomElementClassName('inspectorEditor'));
692 getInspectorDomElement().append($(html));
693
694 _renderEditorDispatcher(formElementTypeDefinition['editors'][i], html);
695 }
696
697 if ('function' === $.type(callback)) {
698 callback();
699 }
700 };
701
702 /**
703 * @public
704 *
705 * @param string collectionName
706 * @param string collectionElementIdentifier
707 * @return void
708 * @publish view/inspector/collectionElements/dnd/update
709 * @throws 1478354853
710 * @throws 1478354854
711 */
712 function renderCollectionElementEditors(collectionName, collectionElementIdentifier) {
713 var collapseWrapper, collectionContainer, collectionContainerElementWrapper, collectionElementConfiguration, collectionElementEditorsLength;
714
715 assert(
716 getUtility().isNonEmptyString(collectionName),
717 'Invalid parameter "collectionName"',
718 1478354853
719 );
720 assert(
721 getUtility().isNonEmptyString(collectionElementIdentifier),
722 'Invalid parameter "collectionElementIdentifier"',
723 1478354854
724 );
725
726 collectionElementConfiguration = getFormEditorApp().getPropertyCollectionElementConfiguration(
727 collectionElementIdentifier,
728 collectionName
729 );
730 if ('array' !== $.type(collectionElementConfiguration['editors'])) {
731 return;
732 }
733
734 collectionContainerElementWrapper = $('<div></div>').
735 addClass(getHelper().getDomElementClassName('collectionElement'));
736 if (collectionName === 'finishers') {
737 collectionContainer = getFinishersContainerDomElement();
738 collectionContainerElementWrapper
739 .attr(getHelper().getDomElementDataAttribute('finisher'), collectionElementIdentifier);
740 } else {
741 collectionContainer = getValidatorsContainerDomElement();
742 collectionContainerElementWrapper
743 .attr(getHelper().getDomElementDataAttribute('validator'), collectionElementIdentifier);
744 }
745 collectionContainer.append(collectionContainerElementWrapper);
746
747 collectionElementEditorsLength = collectionElementConfiguration['editors'].length;
748 if (
749 collectionElementEditorsLength > 0
750 && collectionElementConfiguration['editors'][0]['identifier'] === 'header'
751 ) {
752 collapseWrapper = $('<div role="tabpanel"></div>')
753 .addClass('panel-collapse collapse')
754 .prop('id', _getCollectionElementId(
755 collectionName,
756 collectionElementIdentifier
757 ));
758 }
759
760 for (var i = 0; i < collectionElementEditorsLength; ++i) {
761 var html, template;
762
763 template = getHelper()
764 .getTemplate(collectionElementConfiguration['editors'][i]['templateName'])
765 .clone();
766 if (!template.length) {
767 continue;
768 }
769 html = $(template.html());
770
771 $(html).first()
772 .addClass(_getCollectionElementClass(
773 collectionName,
774 collectionElementConfiguration['editors'][i]['identifier']
775 ))
776 .addClass(getHelper().getDomElementClassName('inspectorEditor'));
777
778 if (i === 0 && collapseWrapper) {
779 getCollectionElementDomElement(collectionName, collectionElementIdentifier)
780 .append(html)
781 .append(collapseWrapper);
782 } else if (
783 i === (collectionElementEditorsLength - 1)
784 && collapseWrapper
785 && collectionElementConfiguration['editors'][i]['identifier'] === 'removeButton'
786 ) {
787 getCollectionElementDomElement(collectionName, collectionElementIdentifier).append(html);
788 } else if (i > 0 && collapseWrapper) {
789 collapseWrapper.append(html);
790 } else {
791 getCollectionElementDomElement(collectionName, collectionElementIdentifier).append(html);
792 }
793
794 _renderEditorDispatcher(
795 collectionElementConfiguration['editors'][i],
796 html,
797 collectionElementIdentifier,
798 collectionName
799 );
800 }
801
802 if (
803 collectionElementEditorsLength === 2
804 && collectionElementConfiguration['editors'][0]['identifier'] === 'header'
805 && collectionElementConfiguration['editors'][1]['identifier'] === 'removeButton'
806 ) {
807 $(getHelper().getDomElementDataIdentifierSelector('collapse'), collectionContainerElementWrapper).remove();
808 }
809
810 if (_configuration['isSortable']) {
811 _addSortableCollectionElementsEvents(collectionContainer, collectionName);
812 }
813 };
814
815 /**
816 * @public
817 *
818 * @string collectionName
819 * @param object editorConfiguration
820 * @param object editorHtml
821 * @return void
822 * @publish view/inspector/collectionElement/existing/selected
823 * @publish view/inspector/collectionElement/new/selected
824 * @throws 1475423098
825 * @throws 1475423099
826 * @throws 1475423100
827 * @throws 1475423101
828 * @throws 1478362968
829 */
830 function renderCollectionElementSelectionEditor(collectionName, editorConfiguration, editorHtml) {
831 var alreadySelectedCollectionElements, selectElement, collectionContainer;
832 assert(
833 getUtility().isNonEmptyString(collectionName),
834 'Invalid configuration "collectionName"',
835 1478362968
836 );
837 assert(
838 'object' === $.type(editorConfiguration),
839 'Invalid parameter "editorConfiguration"',
840 1475423098
841 );
842 assert(
843 'object' === $.type(editorHtml),
844 'Invalid parameter "editorHtml"',
845 1475423099
846 );
847 assert(
848 getUtility().isNonEmptyString(editorConfiguration['label']),
849 'Invalid configuration "label"',
850 1475423100
851 );
852 assert(
853 'array' === $.type(editorConfiguration['selectOptions']),
854 'Invalid configuration "selectOptions"',
855 1475423101
856 );
857
858 if (collectionName === 'finishers') {
859 collectionContainer = getFinishersContainerDomElement();
860 alreadySelectedCollectionElements = getRootFormElement().get(collectionName);
861 } else {
862 collectionContainer = getValidatorsContainerDomElement();
863 alreadySelectedCollectionElements = getCurrentlySelectedFormElement().get(collectionName);
864 }
865
866 collectionContainer.off().empty();
867
868 getHelper().getTemplatePropertyDomElement('label', editorHtml).text(editorConfiguration['label']);
869 selectElement = getHelper().getTemplatePropertyDomElement('selectOptions', editorHtml);
870
871 if (!getUtility().isUndefinedOrNull(alreadySelectedCollectionElements)) {
872 for (var i = 0, len = alreadySelectedCollectionElements.length; i < len; ++i) {
873 getPublisherSubscriber().publish('view/inspector/collectionElement/existing/selected', [
874 alreadySelectedCollectionElements[i]['identifier'],
875 collectionName
876 ]);
877 }
878 }
879
880 for (var i = 0, len1 = editorConfiguration['selectOptions'].length; i < len1; ++i) {
881 var appendOption = true;
882 if (!getUtility().isUndefinedOrNull(alreadySelectedCollectionElements)) {
883 for (var j = 0, len2 = alreadySelectedCollectionElements.length; j < len2; ++j) {
884 if (alreadySelectedCollectionElements[j]['identifier'] === editorConfiguration['selectOptions'][i]['value']) {
885 appendOption = false;
886 break;
887 }
888 }
889 }
890 if (appendOption) {
891 selectElement.append(new Option(
892 editorConfiguration['selectOptions'][i]['label'],
893 editorConfiguration['selectOptions'][i]['value']
894 ));
895 }
896 }
897
898 selectElement.on('change', function() {
899 if ($(this).val() !== '') {
900 var value = $(this).val();
901 $('option[value="' + value + '"]', $(this)).remove();
902
903 getFormEditorApp().getPublisherSubscriber().publish(
904 'view/inspector/collectionElement/new/selected',
905 [value, collectionName]
906 );
907 }
908 });
909 };
910
911 /**
912 * @public
913 *
914 * @param object editorConfiguration
915 * @param object editorHtml
916 * @param string collectionElementIdentifier
917 * @param string collectionName
918 * @return void
919 * @throws 1475421525
920 * @throws 1475421526
921 * @throws 1475421527
922 * @throws 1475421528
923 */
924 function renderFormElementHeaderEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
925 assert('object' === $.type(editorConfiguration), 'Invalid parameter "editorConfiguration"', 1475421525);
926 assert('object' === $.type(editorHtml), 'Invalid parameter "editorHtml"', 1475421526);
927
928 Icons.getIcon(
929 getFormElementDefinition(getCurrentlySelectedFormElement(), 'iconIdentifier'),
930 Icons.sizes.small,
931 null,
932 Icons.states.default
933 ).done(function(icon) {
934 getHelper().getTemplatePropertyDomElement('header-label', editorHtml)
935 .append($(icon).addClass(getHelper().getDomElementClassName('icon')))
936 .append(buildTitleByFormElement());
937 });
938 };
939
940 /**
941 * @public
942 *
943 * @param object editorConfiguration
944 * @param object editorHtml
945 * @param string collectionElementIdentifier
946 * @param string collectionName
947 * @return void
948 * @throws 1475421257
949 * @throws 1475421258
950 * @throws 1475421259
951 */
952 function renderCollectionElementHeaderEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
953 var collectionElementConfiguration, setData;
954
955 assert(
956 'object' === $.type(editorConfiguration),
957 'Invalid parameter "editorConfiguration"',
958 1475421258
959 );
960 assert(
961 getUtility().isNonEmptyString(editorConfiguration['label']),
962 'Invalid configuration "label"',
963 1475421257
964 );
965 assert(
966 'object' === $.type(editorHtml),
967 'Invalid parameter "editorHtml"',
968 1475421259
969 );
970
971 setData = function(icon) {
972 getHelper()
973 .getTemplatePropertyDomElement('header-label', editorHtml)
974 .prepend($(icon));
975
976 Icons.getIcon(
977 getHelper().getDomElementDataAttributeValue('collapse'),
978 Icons.sizes.small,
979 null,
980 Icons.states.default,
981 Icons.markupIdentifiers.inline
982 ).done(function(icon) {
983 var iconWrap;
984 iconWrap = $('<a></a>')
985 .attr('href', _getCollectionElementId(collectionName, collectionElementIdentifier, true))
986 .attr('data-toggle', 'collapse')
987 .attr('aria-expanded', 'true')
988 .attr('aria-controls', _getCollectionElementId(collectionName, collectionElementIdentifier))
989 .addClass('collapsed')
990 .append($(icon));
991
992 getHelper()
993 .getTemplatePropertyDomElement('header-label', editorHtml)
994 .prepend(iconWrap);
995 });
996 };
997
998 collectionElementConfiguration = getFormEditorApp().getFormEditorDefinition(collectionName, collectionElementIdentifier);
999 if (collectionName === 'validators') {
1000 Icons.getIcon(
1001 collectionElementConfiguration['iconIdentifier'],
1002 Icons.sizes.small,
1003 null,
1004 Icons.states.default
1005 ).done(function(icon) {
1006 setData(icon);
1007 });
1008 } else {
1009 Icons.getIcon(
1010 collectionElementConfiguration['iconIdentifier'],
1011 Icons.sizes.small,
1012 null,
1013 Icons.states.default
1014 ).done(function(icon) {
1015 setData(icon);
1016 });
1017 }
1018
1019 if (editorConfiguration['label']) {
1020 getHelper().getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
1021 }
1022 };
1023
1024 /**
1025 * @public
1026 *
1027 * @param object editorConfiguration
1028 * @param object editorHtml
1029 * @param string collectionElementIdentifier
1030 * @param string collectionName
1031 * @return void
1032 * @throws 1475421053
1033 * @throws 1475421054
1034 * @throws 1475421055
1035 * @throws 1475421056
1036 */
1037 function renderTextEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1038 var compatibilityPropertyData, compatibilityPropertyPath, propertyData, propertyPath;
1039 assert(
1040 'object' === $.type(editorConfiguration),
1041 'Invalid parameter "editorConfiguration"',
1042 1475421053
1043 );
1044 assert(
1045 'object' === $.type(editorHtml),
1046 'Invalid parameter "editorHtml"',
1047 1475421054
1048 );
1049 assert(
1050 getUtility().isNonEmptyString(editorConfiguration['label']),
1051 'Invalid configuration "label"',
1052 1475421055
1053 );
1054 assert(
1055 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1056 'Invalid configuration "propertyPath"',
1057 1475421056
1058 );
1059
1060 getHelper()
1061 .getTemplatePropertyDomElement('label', editorHtml)
1062 .append(editorConfiguration['label']);
1063 if (getUtility().isNonEmptyString(editorConfiguration['fieldExplanationText'])) {
1064 getHelper()
1065 .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
1066 .text(editorConfiguration['fieldExplanationText']);
1067 } else {
1068 getHelper()
1069 .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
1070 .remove();
1071 }
1072
1073 propertyPath = getFormEditorApp().buildPropertyPath(
1074 editorConfiguration['propertyPath'],
1075 collectionElementIdentifier,
1076 collectionName
1077 );
1078 propertyData = getCurrentlySelectedFormElement().get(propertyPath);
1079
1080 if (
1081 getUtility().isNonEmptyString(editorConfiguration['compatibilityPropertyPath'])
1082 && getUtility().isUndefinedOrNull(propertyData)
1083 ) {
1084 compatibilityPropertyPath = getFormEditorApp().buildPropertyPath(
1085 editorConfiguration['compatibilityPropertyPath'],
1086 collectionElementIdentifier,
1087 collectionName
1088 );
1089 compatibilityPropertyData = getCurrentlySelectedFormElement().get(compatibilityPropertyPath);
1090
1091 getCurrentlySelectedFormElement().set(propertyPath, compatibilityPropertyData, true);
1092 getCurrentlySelectedFormElement().unset(compatibilityPropertyPath, true);
1093 propertyData = compatibilityPropertyData;
1094 }
1095
1096 _validateCollectionElement(propertyPath, editorHtml);
1097
1098 getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).val(propertyData);
1099
1100 renderFormElementSelectorEditorAddition(editorConfiguration, editorHtml, propertyPath);
1101
1102 getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).on('keyup paste', function() {
1103 if (
1104 !!editorConfiguration['doNotSetIfPropertyValueIsEmpty']
1105 && !getUtility().isNonEmptyString($(this).val())
1106 ) {
1107 getCurrentlySelectedFormElement().unset(propertyPath);
1108 } else {
1109 getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
1110 }
1111 _validateCollectionElement(propertyPath, editorHtml);
1112 if (
1113 !getUtility().isUndefinedOrNull(editorConfiguration['additionalElementPropertyPaths'])
1114 && 'array' === $.type(editorConfiguration['additionalElementPropertyPaths'])
1115 ) {
1116 for (var i = 0, len = editorConfiguration['additionalElementPropertyPaths'].length; i < len; ++i) {
1117 if (
1118 !!editorConfiguration['doNotSetIfPropertyValueIsEmpty']
1119 && !getUtility().isNonEmptyString($(this).val())
1120 ) {
1121 getCurrentlySelectedFormElement().unset(editorConfiguration['additionalElementPropertyPaths'][i]);
1122 } else {
1123 getCurrentlySelectedFormElement().set(editorConfiguration['additionalElementPropertyPaths'][i], $(this).val());
1124 }
1125 }
1126 }
1127 });
1128 };
1129
1130 /**
1131 * @public
1132 *
1133 * @param object editorConfiguration
1134 * @param object editorHtml
1135 * @param string collectionElementIdentifier
1136 * @param string collectionName
1137 * @return void
1138 * @throws 1475421048
1139 * @throws 1475421049
1140 * @throws 1475421050
1141 * @throws 1475421051
1142 * @throws 1475421052
1143 */
1144 function renderSingleSelectEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1145 var propertyData, propertyPath, selectElement;
1146 assert(
1147 'object' === $.type(editorConfiguration),
1148 'Invalid parameter "editorConfiguration"',
1149 1475421048
1150 );
1151 assert(
1152 'object' === $.type(editorHtml),
1153 'Invalid parameter "editorHtml"',
1154 1475421049
1155 );
1156 assert(
1157 getUtility().isNonEmptyString(editorConfiguration['label']),
1158 'Invalid configuration "label"',
1159 1475421050
1160 );
1161 assert(
1162 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1163 'Invalid configuration "propertyPath"',
1164 1475421051
1165 );
1166 assert(
1167 'array' === $.type(editorConfiguration['selectOptions']),
1168 'Invalid configuration "selectOptions"',
1169 1475421052
1170 );
1171
1172 propertyPath = getFormEditorApp().buildPropertyPath(
1173 editorConfiguration['propertyPath'],
1174 collectionElementIdentifier,
1175 collectionName
1176 );
1177
1178 getHelper()
1179 .getTemplatePropertyDomElement('label', editorHtml)
1180 .append(editorConfiguration['label']);
1181
1182 selectElement = getHelper()
1183 .getTemplatePropertyDomElement('selectOptions', editorHtml);
1184
1185 propertyData = getCurrentlySelectedFormElement().get(propertyPath);
1186
1187 for (var i = 0, len = editorConfiguration['selectOptions'].length; i < len; ++i) {
1188 var option;
1189
1190 if (editorConfiguration['selectOptions'][i]['value'] === propertyData) {
1191 option = new Option(editorConfiguration['selectOptions'][i]['label'], i, false, true);
1192 } else {
1193 option = new Option(editorConfiguration['selectOptions'][i]['label'], i);
1194 }
1195 $(option).data({value: editorConfiguration['selectOptions'][i]['value']});
1196 selectElement.append(option);
1197 }
1198
1199 selectElement.on('change', function() {
1200 getCurrentlySelectedFormElement().set(propertyPath, $('option:selected', $(this)).data('value'));
1201 });
1202 };
1203
1204 /**
1205 * @public
1206 *
1207 * @param object editorConfiguration
1208 * @param object editorHtml
1209 * @param string collectionElementIdentifier
1210 * @param string collectionName
1211 * @return void
1212 * @throws 1485712399
1213 * @throws 1485712400
1214 * @throws 1485712401
1215 * @throws 1485712402
1216 * @throws 1485712403
1217 */
1218 function renderMultiSelectEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1219 var propertyData, propertyPath, selectElement;
1220 assert(
1221 'object' === $.type(editorConfiguration),
1222 'Invalid parameter "editorConfiguration"',
1223 1485712399
1224 );
1225 assert(
1226 'object' === $.type(editorHtml),
1227 'Invalid parameter "editorHtml"',
1228 1485712400
1229 );
1230 assert(
1231 getUtility().isNonEmptyString(editorConfiguration['label']),
1232 'Invalid configuration "label"',
1233 1485712401
1234 );
1235 assert(
1236 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1237 'Invalid configuration "propertyPath"',
1238 1485712402
1239 );
1240 assert(
1241 'array' === $.type(editorConfiguration['selectOptions']),
1242 'Invalid configuration "selectOptions"',
1243 1485712403
1244 );
1245
1246 propertyPath = getFormEditorApp().buildPropertyPath(
1247 editorConfiguration['propertyPath'],
1248 collectionElementIdentifier,
1249 collectionName
1250 );
1251
1252 getHelper()
1253 .getTemplatePropertyDomElement('label', editorHtml)
1254 .append(editorConfiguration['label']);
1255
1256 selectElement = getHelper()
1257 .getTemplatePropertyDomElement('selectOptions', editorHtml);
1258
1259 propertyData = getCurrentlySelectedFormElement().get(propertyPath);
1260
1261 for (var i = 0, len1 = editorConfiguration['selectOptions'].length; i < len1; ++i) {
1262 var option, value;
1263
1264 option = null;
1265 for (var propertyDataKey in propertyData) {
1266 if (!propertyData.hasOwnProperty(propertyDataKey)) {
1267 continue;
1268 }
1269 if (editorConfiguration['selectOptions'][i]['value'] === propertyData[propertyDataKey]) {
1270 option = new Option(editorConfiguration['selectOptions'][i]['label'], i, false, true);
1271 break;
1272 }
1273 }
1274
1275 if (!option) {
1276 option = new Option(editorConfiguration['selectOptions'][i]['label'], i);
1277 }
1278
1279 $(option).data({value: editorConfiguration['selectOptions'][i]['value']});
1280
1281 selectElement.append(option);
1282 }
1283
1284 selectElement.on('change', function() {
1285 var selectValues = [];
1286 $('option:selected', $(this)).each(function(i) {
1287 selectValues.push($(this).data('value'));
1288 });
1289
1290 getCurrentlySelectedFormElement().set(propertyPath, selectValues);
1291 });
1292 };
1293
1294 /**
1295 * @public
1296 *
1297 * @param object editorConfiguration
1298 * @param object editorHtml
1299 * @param string collectionElementIdentifier
1300 * @param string collectionName
1301 * @return void
1302 * @throws 1475419226
1303 * @throws 1475419227
1304 * @throws 1475419228
1305 * @throws 1475419229
1306 * @throws 1475419230
1307 * @throws 1475419231
1308 * @throws 1475419232
1309 */
1310 function renderPropertyGridEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1311 var addRowTemplate, defaultValue, multiSelection, propertyData, propertyPathPrefix, rowItemTemplate, setData;
1312 assert(
1313 'object' === $.type(editorConfiguration),
1314 'Invalid parameter "editorConfiguration"',
1315 1475419226
1316 );
1317 assert(
1318 'object' === $.type(editorHtml),
1319 'Invalid parameter "editorHtml"',
1320 1475419227
1321 );
1322 assert(
1323 'boolean' === $.type(editorConfiguration['enableAddRow']),
1324 'Invalid configuration "enableAddRow"',
1325 1475419228
1326 );
1327 assert(
1328 'boolean' === $.type(editorConfiguration['enableDeleteRow']),
1329 'Invalid configuration "enableDeleteRow"',
1330 1475419230
1331 );
1332 assert(
1333 'boolean' === $.type(editorConfiguration['isSortable']),
1334 'Invalid configuration "isSortable"',
1335 1475419229
1336 );
1337 assert(
1338 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1339 'Invalid configuration "propertyPath"',
1340 1475419231
1341 );
1342 assert(
1343 getUtility().isNonEmptyString(editorConfiguration['label']),
1344 'Invalid configuration "label"',
1345 1475419232
1346 );
1347
1348 getHelper().getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
1349 propertyPathPrefix = getFormEditorApp().buildPropertyPath(
1350 undefined,
1351 collectionElementIdentifier,
1352 collectionName,
1353 undefined,
1354 true
1355 );
1356 if (getUtility().isNonEmptyString(propertyPathPrefix)) {
1357 propertyPathPrefix = propertyPathPrefix + '.';
1358 }
1359
1360 if (getUtility().isUndefinedOrNull(editorConfiguration['multiSelection'])) {
1361 multiSelection = false;
1362 } else {
1363 multiSelection = !!editorConfiguration['multiSelection'];
1364 }
1365
1366 rowItemTemplate = $(
1367 getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'),
1368 $(editorHtml)
1369 ).clone();
1370 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'), $(editorHtml)).remove();
1371
1372 if (!!editorConfiguration['enableDeleteRow']) {
1373 $( getHelper().getDomElementDataIdentifierSelector('propertyGridEditorDeleteRow'),
1374 $(rowItemTemplate)
1375 ).on('click', function() {
1376 if ($(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'), $(editorHtml)).length > 1) {
1377 $(this)
1378 .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
1379 .off()
1380 .empty()
1381 .remove();
1382
1383 _setPropertyGridData(
1384 $(editorHtml),
1385 multiSelection,
1386 editorConfiguration['propertyPath'],
1387 propertyPathPrefix
1388 );
1389 } else {
1390 Notification.error(
1391 editorConfiguration['removeLastAvailableRowFlashMessageTitle'],
1392 editorConfiguration['removeLastAvailableRowFlashMessageMessage'],
1393 2
1394 );
1395 }
1396 });
1397 } else {
1398 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorDeleteRow'), $(rowItemTemplate))
1399 .parent()
1400 .off()
1401 .empty();
1402 }
1403
1404 if (!!editorConfiguration['isSortable']) {
1405 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer'), $(editorHtml))
1406 .addClass(getHelper().getDomElementClassName('sortable'))
1407 .sortable({
1408 revert: 'true',
1409 items: getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'),
1410 update: function(e, o) {
1411 _setPropertyGridData($(editorHtml), multiSelection, editorConfiguration['propertyPath'], propertyPathPrefix);
1412 }
1413 });
1414 } else {
1415 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSortRow'), $(rowItemTemplate))
1416 .parent()
1417 .off()
1418 .empty();
1419 }
1420
1421 $( getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue'),
1422 $(rowItemTemplate)
1423 ).on('change', function() {
1424 if (!multiSelection) {
1425 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue') + ':checked', $(editorHtml))
1426 .not($(this))
1427 .prop('checked', false);
1428 }
1429 _setPropertyGridData($(editorHtml), multiSelection, editorConfiguration['propertyPath'], propertyPathPrefix);
1430 });
1431
1432 $( getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel') + ',' +
1433 getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'),
1434 $(rowItemTemplate)
1435 ).on('keyup paste', function() {
1436 _setPropertyGridData($(editorHtml), multiSelection, editorConfiguration['propertyPath'], propertyPathPrefix);
1437 });
1438
1439 $( getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel'),
1440 $(rowItemTemplate)
1441 ).on('focusout', function() {
1442 if ('' === $(this)
1443 .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
1444 .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
1445 .val()
1446 ) {
1447 $(this)
1448 .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
1449 .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
1450 .val($(this).val());
1451 }
1452 });
1453
1454 if (!!editorConfiguration['enableAddRow']) {
1455 addRowTemplate = $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml)).clone();
1456 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml)).remove();
1457
1458 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRow'), $(addRowTemplate)).on('click', function() {
1459 $(this)
1460 .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'))
1461 .before($(rowItemTemplate).clone(true, true));
1462 });
1463 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer'), $(editorHtml))
1464 .prepend($(addRowTemplate).clone(true, true));
1465 } else {
1466 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml)).remove();
1467 }
1468
1469 defaultValue = {};
1470 if (multiSelection) {
1471 if (!getUtility().isUndefinedOrNull(getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue'))) {
1472 defaultValue = getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue');
1473 }
1474 } else {
1475 if (!getUtility().isUndefinedOrNull(getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue'))) {
1476 defaultValue = {0: getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue')};
1477 }
1478 }
1479 propertyData = getCurrentlySelectedFormElement().get(propertyPathPrefix + editorConfiguration['propertyPath']) || {};
1480
1481 setData = function(label, value) {
1482 var isPreselected, newRowTemplate;
1483
1484 isPreselected = false;
1485 newRowTemplate = $(rowItemTemplate).clone(true, true);
1486
1487 for (var defaultValueKey in defaultValue) {
1488 if (!defaultValue.hasOwnProperty(defaultValueKey)) {
1489 continue;
1490 }
1491 if (defaultValue[defaultValueKey] === value) {
1492 isPreselected = true;
1493 break;
1494 }
1495 }
1496
1497 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel'), $(newRowTemplate)).val(label);
1498 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'), $(newRowTemplate)).val(value);
1499 if (isPreselected) {
1500 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue'), $(newRowTemplate))
1501 .prop('checked', true);
1502 }
1503
1504 if (!!editorConfiguration['enableAddRow']) {
1505 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml))
1506 .before($(newRowTemplate));
1507 } else {
1508 $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer'), $(editorHtml))
1509 .prepend($(newRowTemplate));
1510 }
1511 };
1512
1513 if ('object' === $.type(propertyData)) {
1514 for (var propertyDataKey in propertyData) {
1515 if (!propertyData.hasOwnProperty(propertyDataKey)) {
1516 continue;
1517 }
1518 setData(propertyData[propertyDataKey], propertyDataKey);
1519 }
1520 } else if ('array' === $.type(propertyData)) {
1521 for (var propertyDataKey in propertyData) {
1522 if (!propertyData.hasOwnProperty(propertyDataKey)) {
1523 continue;
1524 }
1525 if (getUtility().isUndefinedOrNull(propertyData[propertyDataKey]['_label'])) {
1526 setData(propertyData[propertyDataKey], propertyDataKey);
1527 } else {
1528 setData(propertyData[propertyDataKey]['_label'], propertyData[propertyDataKey]['_value']);
1529 }
1530 }
1531 }
1532 };
1533
1534 /**
1535 * @public
1536 *
1537 * @param object editorConfiguration
1538 * @param object editorHtml
1539 * @param string collectionElementIdentifier
1540 * @param string collectionName
1541 * @return void
1542 * @publish view/inspector/collectionElement/new/selected
1543 * @publish view/inspector/removeCollectionElement/perform
1544 * @throws 1475417093
1545 * @throws 1475417094
1546 * @throws 1475417095
1547 * @throws 1475417096
1548 * @throws 1489319751
1549 * @throws 1489319752
1550 */
1551 function renderRequiredValidatorEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1552 var propertyPath, propertyValue, validatorIdentifier;
1553 assert(
1554 'object' === $.type(editorConfiguration),
1555 'Invalid parameter "editorConfiguration"',
1556 1475417093
1557 );
1558 assert(
1559 'object' === $.type(editorHtml),
1560 'Invalid parameter "editorHtml"',
1561 1475417094
1562 );
1563 assert(
1564 getUtility().isNonEmptyString(editorConfiguration['validatorIdentifier']),
1565 'Invalid configuration "validatorIdentifier"',
1566 1475417095
1567 );
1568 assert(
1569 getUtility().isNonEmptyString(editorConfiguration['label']),
1570 'Invalid configuration "label"',
1571 1475417096
1572 );
1573 assert(
1574 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1575 'Invalid configuration "propertyPath"',
1576 1489319751
1577 );
1578 assert(
1579 getUtility().isNonEmptyString(editorConfiguration['propertyValue']),
1580 'Invalid configuration "propertyValue"',
1581 1489319752
1582 );
1583
1584 validatorIdentifier = editorConfiguration['validatorIdentifier'];
1585 getHelper().getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
1586
1587 propertyPath = getFormEditorApp()
1588 .buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
1589 propertyValue = editorConfiguration['propertyValue'];
1590
1591 if (-1 !== getFormEditorApp().getIndexFromPropertyCollectionElement(validatorIdentifier, 'validators')) {
1592 $('input[type="checkbox"]', $(editorHtml)).prop('checked', true);
1593 getCurrentlySelectedFormElement().set(propertyPath, propertyValue);
1594 }
1595
1596 $('input[type="checkbox"]', $(editorHtml)).on('change', function() {
1597 if ($(this).is(":checked")) {
1598 getPublisherSubscriber().publish(
1599 'view/inspector/collectionElement/new/selected',
1600 [validatorIdentifier, 'validators']
1601 );
1602 getCurrentlySelectedFormElement().set(propertyPath, propertyValue);
1603 } else {
1604 getPublisherSubscriber().publish(
1605 'view/inspector/removeCollectionElement/perform',
1606 [validatorIdentifier, 'validators']
1607 );
1608 getCurrentlySelectedFormElement().unset(propertyPath);
1609 }
1610 });
1611 };
1612
1613 /**
1614 * @public
1615 *
1616 * @param object editorConfiguration
1617 * @param object editorHtml
1618 * @param string collectionElementIdentifier
1619 * @param string collectionName
1620 * @return void
1621 * @throws 1476218671
1622 * @throws 1476218672
1623 * @throws 1476218673
1624 * @throws 1476218674
1625 */
1626 function renderCheckboxEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1627 var propertyData, propertyPath;
1628 assert(
1629 'object' === $.type(editorConfiguration),
1630 'Invalid parameter "editorConfiguration"',
1631 1476218671
1632 );
1633 assert(
1634 'object' === $.type(editorHtml),
1635 'Invalid parameter "editorHtml"',
1636 1476218672
1637 );
1638 assert(
1639 getUtility().isNonEmptyString(editorConfiguration['label']),
1640 'Invalid configuration "label"',
1641 1476218673
1642 );
1643 assert(
1644 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1645 'Invalid configuration "propertyPath"',
1646 1476218674
1647 );
1648
1649 getHelper()
1650 .getTemplatePropertyDomElement('label', editorHtml)
1651 .append(editorConfiguration['label']);
1652
1653 propertyPath = getFormEditorApp()
1654 .buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
1655 propertyData = getCurrentlySelectedFormElement().get(propertyPath);
1656
1657 if (
1658 ('boolean' === $.type(propertyData) && propertyData)
1659 || propertyData === 'true'
1660 || propertyData === 1
1661 || propertyData === "1"
1662 ) {
1663 $('input[type="checkbox"]', $(editorHtml)).prop('checked', true);
1664 }
1665
1666 $('input[type="checkbox"]', $(editorHtml)).on('change', function() {
1667 if ($(this).is(":checked")) {
1668 getCurrentlySelectedFormElement().set(propertyPath, true);
1669 } else {
1670 getCurrentlySelectedFormElement().set(propertyPath, false);
1671 }
1672 });
1673 };
1674
1675 /**
1676 * @public
1677 *
1678 * @param object editorConfiguration
1679 * @param object editorHtml
1680 * @param string collectionElementIdentifier
1681 * @param string collectionName
1682 * @return void
1683 * @throws 1475412567
1684 * @throws 1475412568
1685 * @throws 1475416098
1686 * @throws 1475416099
1687 */
1688 function renderTextareaEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1689 var propertyPath, propertyData;
1690 assert(
1691 'object' === $.type(editorConfiguration),
1692 'Invalid parameter "editorConfiguration"',
1693 1475412567
1694 );
1695 assert(
1696 'object' === $.type(editorHtml),
1697 'Invalid parameter "editorHtml"',
1698 1475412568
1699 );
1700 assert(
1701 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1702 'Invalid configuration "propertyPath"',
1703 1475416098
1704 );
1705 assert(
1706 getUtility().isNonEmptyString(editorConfiguration['label']),
1707 'Invalid configuration "label"',
1708 1475416099
1709 );
1710
1711 propertyPath = getFormEditorApp()
1712 .buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
1713
1714 getHelper()
1715 .getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
1716
1717 if (getUtility().isNonEmptyString(editorConfiguration['fieldExplanationText'])) {
1718 getHelper()
1719 .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
1720 .text(editorConfiguration['fieldExplanationText']);
1721 } else {
1722 getHelper()
1723 .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
1724 .remove();
1725 }
1726
1727 propertyData = getCurrentlySelectedFormElement().get(propertyPath);
1728 $('textarea', $(editorHtml)).val(propertyData);
1729
1730 $('textarea', $(editorHtml)).on('keyup paste', function() {
1731 getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
1732 });
1733 };
1734
1735 /**
1736 * @public
1737 *
1738 * @param object editorConfiguration
1739 * @param object editorHtml
1740 * @param string collectionElementIdentifier
1741 * @param string collectionName
1742 * @return void
1743 * @throws 1477300587
1744 * @throws 1477300588
1745 * @throws 1477300589
1746 * @throws 1477300590
1747 * @throws 1477318981
1748 * @throws 1477319859
1749 */
1750 function renderTypo3WinBrowserEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1751 var iconType, propertyPath, propertyData;
1752 assert(
1753 'object' === $.type(editorConfiguration),
1754 'Invalid parameter "editorConfiguration"',
1755 1477300587
1756 );
1757 assert(
1758 'object' === $.type(editorHtml),
1759 'Invalid parameter "editorHtml"',
1760 1477300588
1761 );
1762 assert(
1763 getUtility().isNonEmptyString(editorConfiguration['label']),
1764 'Invalid configuration "label"',
1765 1477300589
1766 );
1767 assert(
1768 getUtility().isNonEmptyString(editorConfiguration['buttonLabel']),
1769 'Invalid configuration "buttonLabel"',
1770 1477318981
1771 );
1772 assert(
1773 getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
1774 'Invalid configuration "propertyPath"',
1775 1477300590
1776 );
1777 assert(
1778 'tt_content' === editorConfiguration['browsableType'] || 'pages' === editorConfiguration['browsableType'],
1779 'Invalid configuration "browsableType"',
1780 1477319859
1781 );
1782
1783 getHelper()
1784 .getTemplatePropertyDomElement('label', editorHtml)
1785 .append(editorConfiguration['label']);
1786 getHelper()
1787 .getTemplatePropertyDomElement('buttonLabel', editorHtml)
1788 .append(editorConfiguration['buttonLabel']);
1789
1790 if (getUtility().isNonEmptyString(editorConfiguration['fieldExplanationText'])) {
1791 getHelper()
1792 .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
1793 .text(editorConfiguration['fieldExplanationText']);
1794 } else {
1795 getHelper()
1796 .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
1797 .remove();
1798 }
1799
1800 $('form', $(editorHtml)).prop('name', editorConfiguration['propertyPath']);
1801
1802 iconType = ('tt_content' === editorConfiguration['browsableType'])
1803 ? getHelper().getDomElementDataAttributeValue('iconTtContent')
1804 : getHelper().getDomElementDataAttributeValue('iconPage');
1805 Icons.getIcon(iconType, Icons.sizes.small).done(function(icon) {
1806 getHelper().getTemplatePropertyDomElement('image', editorHtml).append($(icon));
1807 });
1808
1809 getHelper().getTemplatePropertyDomElement('onclick', editorHtml).on('click', function() {
1810 var insertTarget, randomIdentifier;
1811
1812 randomIdentifier = Math.floor((Math.random() * 100000) + 1);
1813 insertTarget = $(this)
1814 .closest(getHelper().getDomElementDataIdentifierSelector('editorControlsWrapper'))
1815 .find(getHelper().getDomElementDataAttribute('contentElementSelectorTarget', 'bracesWithKey'));
1816
1817 insertTarget.attr(getHelper().getDomElementDataAttribute('contentElementSelectorTarget'), randomIdentifier);
1818 _openTypo3WinBrowser('db', randomIdentifier + '|||' + editorConfiguration['browsableType']);
1819 });
1820
1821 propertyPath = getFormEditorApp().buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
1822 propertyData = getCurrentlySelectedFormElement().get(propertyPath);
1823
1824 _validateCollectionElement(propertyPath, editorHtml);
1825 getHelper()
1826 .getTemplatePropertyDomElement('propertyPath', editorHtml)
1827 .val(propertyData);
1828
1829 getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).on('keyup paste', function() {
1830 getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
1831 _validateCollectionElement(propertyPath, editorHtml);
1832 });
1833 };
1834
1835 /**
1836 * @public
1837 *
1838 * @param object editorConfiguration
1839 * @param object editorHtml
1840 * @param string collectionElementIdentifier
1841 * @param string collectionName
1842 * @return void
1843 * @throws 1475412563
1844 * @throws 1475412564
1845 */
1846 function renderRemoveElementEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
1847 assert('object' === $.type(editorConfiguration), 'Invalid parameter "editorConfiguration"', 1475412563);
1848 assert('object' === $.type(editorHtml), 'Invalid parameter "editorHtml"', 1475412564);
1849
1850 if (getUtility().isUndefinedOrNull(collectionElementIdentifier)) {
1851
1852 $('button', $(editorHtml))
1853 .addClass(
1854 getHelper().getDomElementClassName('buttonFormElementRemove') + ' ' +
1855 getHelper().getDomElementClassName('buttonFormEditor')
1856 );
1857 } else {
1858 $('button', $(editorHtml)).addClass(
1859 getHelper().getDomElementClassName('buttonCollectionElementRemove')
1860 );
1861 }
1862
1863 $('button', $(editorHtml)).on('click', function(e) {
1864 if (getUtility().isUndefinedOrNull(collectionElementIdentifier)) {
1865 getViewModel().showRemoveFormElementModal();
1866 } else {
1867 getViewModel().showRemoveCollectionElementModal(collectionElementIdentifier, collectionName);
1868 }
1869 });
1870 };
1871
1872 /**
1873 * @public
1874 *
1875 * @param object editorConfiguration
1876 * @param object editorHtml
1877 * @param string propertyPath
1878 * @return void
1879 * @throws 1484574704
1880 * @throws 1484574705
1881 * @throws 1484574706
1882 */
1883 function renderFormElementSelectorEditorAddition(editorConfiguration, editorHtml, propertyPath) {
1884 var nonCompositeNonToplevelFormElements, formElementSelectorControlsWrapper, formElementSelectorSplitButtonListContainer, itemTemplate;
1885
1886 assert(
1887 'object' === $.type(editorConfiguration),
1888 'Invalid parameter "editorConfiguration"',
1889 1484574704
1890 );
1891 assert(
1892 'object' === $.type(editorHtml),
1893 'Invalid parameter "editorHtml"',
1894 1484574705
1895 );
1896 assert(
1897 getUtility().isNonEmptyString(propertyPath),
1898 'Invalid parameter "propertyPath"',
1899 1484574706
1900 );
1901
1902 formElementSelectorControlsWrapper = $(
1903 getHelper().getDomElementDataIdentifierSelector('formElementSelectorControlsWrapper'), editorHtml
1904 );
1905
1906 if (editorConfiguration['enableFormelementSelectionButton'] === true) {
1907 if (formElementSelectorControlsWrapper.length === 0) {
1908 return;
1909 }
1910
1911 formElementSelectorSplitButtonListContainer = $(
1912 getHelper().getDomElementDataIdentifierSelector('formElementSelectorSplitButtonListContainer'), editorHtml
1913 );
1914
1915 formElementSelectorSplitButtonListContainer.off().empty();
1916 nonCompositeNonToplevelFormElements = getFormEditorApp().getNonCompositeNonToplevelFormElements();
1917
1918 if (nonCompositeNonToplevelFormElements.length === 0) {
1919 Icons.getIcon(
1920 getHelper().getDomElementDataAttributeValue('iconNotAvailable'),
1921 Icons.sizes.small,
1922 null,
1923 Icons.states.default
1924 ).done(function(icon) {
1925 itemTemplate = $('<li data-no-sorting>'
1926 + '<a href="#"></a>'
1927 + '</li>');
1928
1929 itemTemplate
1930 .append($(icon))
1931 .append(' ' + getFormElementDefinition(getRootFormElement(), 'inspectorEditorFormElementSelectorNoElements'));
1932 formElementSelectorSplitButtonListContainer.append(itemTemplate);
1933 });
1934 } else {
1935 for (var i = 0, len = nonCompositeNonToplevelFormElements.length; i < len; ++i) {
1936 var nonCompositeNonToplevelFormElement;
1937
1938 nonCompositeNonToplevelFormElement = nonCompositeNonToplevelFormElements[i];
1939 Icons.getIcon(
1940 getFormElementDefinition(nonCompositeNonToplevelFormElement, 'iconIdentifier'),
1941 Icons.sizes.small,
1942 null,
1943 Icons.states.default
1944 ).done(function(icon) {
1945 itemTemplate = $('<li data-no-sorting>'
1946 + '<a href="#" data-formelement-identifier="' + nonCompositeNonToplevelFormElement.get('identifier') + '">'
1947 + '</a>'
1948 + '</li>');
1949
1950 $('[data-formelement-identifier="' + nonCompositeNonToplevelFormElement.get('identifier') + '"]', itemTemplate)
1951 .append($(icon))
1952 .append(' ' + nonCompositeNonToplevelFormElement.get('label'));
1953
1954 $('a', itemTemplate).on('click', function() {
1955 var propertyData;
1956
1957 propertyData = getCurrentlySelectedFormElement().get(propertyPath);
1958
1959 if (propertyData.length === 0) {
1960 propertyData = '{' + $(this).attr('data-formelement-identifier') + '}';
1961 } else {
1962 propertyData = propertyData + ' ' + '{' + $(this).attr('data-formelement-identifier') + '}';
1963 }
1964
1965 getCurrentlySelectedFormElement().set(propertyPath, propertyData);
1966 getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).val(propertyData);
1967 _validateCollectionElement(propertyPath, editorHtml);
1968 });
1969
1970 formElementSelectorSplitButtonListContainer.append(itemTemplate);
1971 });
1972 }
1973 }
1974 } else {
1975 $(getHelper().getDomElementDataIdentifierSelector('editorControlsInputGroup'), editorHtml)
1976 .removeClass(getHelper().getDomElementClassName('inspectorInputGroup'));
1977 formElementSelectorControlsWrapper.off().empty().remove();
1978 }
1979 }
1980
1981 /**
1982 * @public
1983 *
1984 * @param string content
1985 * @return void
1986 */
1987 function setFormElementHeaderEditorContent(content) {
1988 if (getFormEditorApp().getUtility().isUndefinedOrNull(content)) {
1989 content = buildTitleByFormElement();
1990 }
1991
1992 $(getHelper()
1993 .getDomElementDataIdentifierSelector('formElementHeaderEditor'), getInspectorDomElement())
1994 .html(content);
1995 };
1996
1997 /**
1998 * @public
1999 *
2000 * @param object
2001 * @return object
2002 * @throws 1478967319
2003 */
2004 function buildTitleByFormElement(formElement) {
2005 var label;
2006 if (getUtility().isUndefinedOrNull(formElement)) {
2007 formElement = getCurrentlySelectedFormElement();
2008 }
2009 assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1478967319);
2010
2011 return $('<span></span>').text((formElement.get('label')
2012 ? formElement.get('label')
2013 : formElement.get('identifier')));
2014 };
2015
2016 /**
2017 * @public
2018 *
2019 * @param object
2020 * @param object
2021 * @return this
2022 */
2023 function bootstrap(formEditorApp, configuration) {
2024 _formEditorApp = formEditorApp;
2025 _configuration = $.extend(true, _defaultConfiguration, configuration || {});
2026 _helperSetup();
2027 return this;
2028 };
2029
2030 /**
2031 * Publish the public methods.
2032 * Implements the "Revealing Module Pattern".
2033 */
2034 return {
2035 bootstrap: bootstrap,
2036 buildTitleByFormElement: buildTitleByFormElement,
2037 getCollectionElementDomElement: getCollectionElementDomElement,
2038 getFinishersContainerDomElement: getFinishersContainerDomElement,
2039 getInspectorDomElement: getInspectorDomElement,
2040 getValidatorsContainerDomElement: getValidatorsContainerDomElement,
2041 renderCheckboxEditor: renderCheckboxEditor,
2042 renderCollectionElementEditors: renderCollectionElementEditors,
2043 renderCollectionElementHeaderEditor: renderCollectionElementHeaderEditor,
2044 renderCollectionElementSelectionEditor: renderCollectionElementSelectionEditor,
2045 renderEditors: renderEditors,
2046 renderFormElementHeaderEditor: renderFormElementHeaderEditor,
2047 renderFormElementSelectorEditorAddition: renderFormElementSelectorEditorAddition,
2048 renderPropertyGridEditor: renderPropertyGridEditor,
2049 renderRemoveElementEditor: renderRemoveElementEditor,
2050 renderRequiredValidatorEditor: renderRequiredValidatorEditor,
2051 renderSingleSelectEditor: renderSingleSelectEditor,
2052 renderMultiSelectEditor: renderMultiSelectEditor,
2053 renderTextareaEditor: renderTextareaEditor,
2054 renderTextEditor: renderTextEditor,
2055 renderTypo3WinBrowserEditor: renderTypo3WinBrowserEditor,
2056 setFormElementHeaderEditorContent: setFormElementHeaderEditorContent
2057 };
2058 })($, Helper, Icons, Notification);
2059 });