vendor/sonata-project/admin-bundle/src/Resources/views/CRUD/Association/edit_many_script.html.twig line 1

Open in your IDE?
  1. {#
  2. This file is part of the Sonata package.
  3. (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  4. For the full copyright and license information, please view the LICENSE
  5. file that was distributed with this source code.
  6. #}
  7. {#
  8. This code manages the many-to-[one|many] association field popup
  9. #}
  10. {% autoescape false %}
  11. {% set associationadmin = sonata_admin.field_description.associationadmin %}
  12. <!-- edit many association -->
  13. <script type="text/javascript">
  14.     {#
  15.       handle link click in a list :
  16.         - if the parent has an objectId defined then the related input get updated
  17.         - if the parent has NO object then an ajax request is made to refresh the popup
  18.     #}
  19.     var field_dialog_form_list_link_{{ id }} = function(event) {
  20.         initialize_popup_{{ id }}();
  21.         var target = jQuery(this);
  22.         if (target.attr('href').length === 0 || target.attr('href') === '#') {
  23.             return;
  24.         }
  25.         event.preventDefault();
  26.         event.stopPropagation();
  27.         Admin.log('[{{ id }}|field_dialog_form_list_link] handle link click in a list');
  28.         var element = jQuery(this).parents('#field_dialog_{{ id }} .sonata-ba-list-field');
  29.         // the user does not click on a row column
  30.         if (element.length == 0) {
  31.             Admin.log('[{{ id }}|field_dialog_form_list_link] the user does not click on a row column, make ajax call to retrieve inner html');
  32.             // make a recursive call (ie: reset the filter)
  33.             jQuery.ajax({
  34.                 type: 'GET',
  35.                 url: jQuery(this).attr('href'),
  36.                 dataType: 'html',
  37.                 success: function(html) {
  38.                     Admin.log('[{{ id }}|field_dialog_form_list_link] callback success, attach valid js event');
  39.                     field_dialog_content_{{ id }}.html(html);
  40.                     field_dialog_form_list_handle_action_{{ id }}();
  41.                     Admin.shared_setup(field_dialog_{{ id }});
  42.                 }
  43.             });
  44.             return;
  45.         }
  46.         Admin.log('[{{ id }}|field_dialog_form_list_link] the user select one element, update input and hide the modal');
  47.         jQuery('#{{ id }}').val(element.attr('objectId'));
  48.         jQuery('#{{ id }}').trigger('change');
  49.         field_dialog_{{ id }}.modal('hide');
  50.     };
  51.     // this function handle action on the modal list when inside a selected list
  52.     var field_dialog_form_list_handle_action_{{ id }}  =  function() {
  53.         Admin.log('[{{ id }}|field_dialog_form_list_handle_action] attaching valid js event');
  54.         // capture the submit event to make an ajax call, ie : POST data to the
  55.         // related create admin
  56.         jQuery('a', field_dialog_{{ id }}).on('click', field_dialog_form_list_link_{{ id }});
  57.         jQuery('form', field_dialog_{{ id }}).on('submit', function(event) {
  58.             event.preventDefault();
  59.             var form = jQuery(this);
  60.             Admin.log('[{{ id }}|field_dialog_form_list_handle_action] catching submit event, sending ajax request');
  61.             jQuery(form).ajaxSubmit({
  62.                 type: form.attr('method'),
  63.                 url: form.attr('action'),
  64.                 dataType: 'html',
  65.                 data: {_xml_http_request: true},
  66.                 success: function(html) {
  67.                     Admin.log('[{{ id }}|field_dialog_form_list_handle_action] form submit success, restoring event');
  68.                     field_dialog_content_{{ id }}.html(html);
  69.                     field_dialog_form_list_handle_action_{{ id }}();
  70.                     Admin.shared_setup(field_dialog_{{ id }});
  71.                 }
  72.             });
  73.         });
  74.     };
  75.     // handle the list link
  76.     var field_dialog_form_list_{{ id }} = function(event) {
  77.         initialize_popup_{{ id }}();
  78.         event.preventDefault();
  79.         event.stopPropagation();
  80.         Admin.log('[{{ id }}|field_dialog_form_list] open the list modal');
  81.         var a = jQuery(this);
  82.         field_dialog_content_{{ id }}.html('');
  83.         // retrieve the form element from the related admin generator
  84.         jQuery.ajax({
  85.             url: a.attr('href'),
  86.             dataType: 'html',
  87.             success: function(html) {
  88.                 Admin.log('[{{ id }}|field_dialog_form_list] retrieving the list content');
  89.                 // populate the popup container
  90.                 field_dialog_content_{{ id }}.html(html);
  91.                 {% if associationadmin.label is not empty %}
  92.                     field_dialog_title_{{ id }}.html("{{ associationadmin.label|trans({}, associationadmin.translationdomain) }}");
  93.                 {% endif %}
  94.                 Admin.shared_setup(field_dialog_{{ id }});
  95.                 field_dialog_form_list_handle_action_{{ id }}();
  96.                 // open the dialog in modal mode
  97.                 field_dialog_{{ id }}.modal();
  98.                 Admin.setup_list_modal(field_dialog_{{ id }});
  99.             }
  100.         });
  101.     };
  102.     // handle the add link
  103.     var field_dialog_form_add_{{ id }} = function(event) {
  104.         initialize_popup_{{ id }}();
  105.         event.preventDefault();
  106.         event.stopPropagation();
  107.         var a = jQuery(this);
  108.         field_dialog_content_{{ id }}.html('');
  109.         Admin.log('[{{ id }}|field_dialog_form_add] add link action');
  110.         // retrieve the form element from the related admin generator
  111.         jQuery.ajax({
  112.             url: a.attr('href'),
  113.             dataType: 'html',
  114.             success: function(html) {
  115.                 Admin.log('[{{ id }}|field_dialog_form_add] ajax success', field_dialog_{{ id }});
  116.                 // populate the popup container
  117.                 field_dialog_content_{{ id }}.html(html);
  118.                 {% if associationadmin.label is not empty %}
  119.                     field_dialog_title_{{ id }}.html("{{ associationadmin.label|trans({}, associationadmin.translationdomain) }}");
  120.                 {% endif %}
  121.                 Admin.shared_setup(field_dialog_{{ id }});
  122.                 // capture the submit event to make an ajax call, ie : POST data to the
  123.                 // related create admin
  124.                 jQuery(document).on('click','#field_dialog_{{ id }} a', field_dialog_form_action_{{ id }});
  125.                 jQuery('form', field_dialog_{{ id }}).on('submit', field_dialog_form_action_{{ id }});
  126.                 // open the dialog in modal mode
  127.                 field_dialog_{{ id }}.modal();
  128.                 Admin.setup_list_modal(field_dialog_{{ id }});
  129.             }
  130.         });
  131.     };
  132.     // handle the edit link
  133.     var field_dialog_form_edit_{{ id }} = function(event) {
  134.         initialize_popup_{{ id }}();
  135.         event.preventDefault();
  136.         event.stopPropagation();
  137.         var a = jQuery(this);
  138.         field_dialog_content_{{ id }}.html('');
  139.         Admin.log('[{{ id }}|field_dialog_form_edit] edit link action');
  140.         // retrieve the form element from the related admin generator
  141.         jQuery.ajax({
  142.             url: a.attr('href'),
  143.             dataType: 'html',
  144.             success: function(html) {
  145.                 Admin.log('[{{ id }}|field_dialog_form_edit] ajax success', field_dialog_{{ id }});
  146.                 // populate the popup container
  147.                 field_dialog_content_{{ id }}.html(html);
  148.                 {% if associationadmin.label is not empty %}
  149.                     field_dialog_title_{{ id }}.html("{{ associationadmin.label|trans({}, associationadmin.translationdomain) }}");
  150.                 {% endif %}
  151.                 Admin.shared_setup(field_dialog_{{ id }});
  152.                 // capture the submit event to make an ajax call, ie : POST data to the
  153.                 // related create admin
  154.                 jQuery(document).on('click','#field_dialog_{{ id }} a', field_dialog_form_action_{{ id }});
  155.                 jQuery('form', field_dialog_{{ id }}).on('submit', field_dialog_form_action_{{ id }});
  156.                 // open the dialog in modal mode
  157.                 field_dialog_{{ id }}.modal();
  158.                 Admin.setup_list_modal(field_dialog_{{ id }});
  159.             }
  160.         });
  161.     };
  162.     // handle the post data
  163.     var field_dialog_form_action_{{ id }} = function(event) {
  164.         var element = jQuery(this);
  165.         // return if the link is an anchor inside the same page
  166.         if (
  167.             this.nodeName === 'A'
  168.             && (
  169.                 element.attr('href').length === 0
  170.                 || element.attr('href')[0] === '#'
  171.                 || element.attr('href').substr(0, 11) === 'javascript:'
  172.             )
  173.         ) {
  174.             Admin.log('[{{ id }}|field_dialog_form_action] element is an anchor or a script, skipping action', this);
  175.             return;
  176.         }
  177.         event.preventDefault();
  178.         event.stopPropagation();
  179.         Admin.log('[{{ id }}|field_dialog_form_action] action catch', this);
  180.         initialize_popup_{{ id }}();
  181.         if (this.nodeName == 'FORM') {
  182.             var url  = element.attr('action');
  183.             var type = element.attr('method');
  184.         } else if (this.nodeName == 'A') {
  185.             var url  = element.attr('href');
  186.             var type = 'GET';
  187.         } else {
  188.             alert('unexpected element : @' + this.nodeName + '@');
  189.             return;
  190.         }
  191.         if (element.hasClass('sonata-ba-action')) {
  192.             Admin.log('[{{ id }}|field_dialog_form_action] reserved action stop catch all events');
  193.             return;
  194.         }
  195.         var data = {
  196.             _xml_http_request: true
  197.         }
  198.         var form = jQuery(this);
  199.         Admin.log('[{{ id }}|field_dialog_form_action] execute ajax call');
  200.         var oldErrorMessages = jQuery(field_dialog_content_{{ id }}).find('div.alert-danger');
  201.         // Remove old error messages.
  202.         if (oldErrorMessages.length > 0) {
  203.           oldErrorMessages.remove();
  204.         }
  205.         // the ajax post
  206.         jQuery(form).ajaxSubmit({
  207.             url: url,
  208.             type: type,
  209.             headers: {
  210.                 Accept: 'application/json'
  211.             },
  212.             data: data,
  213.             success: function(data) {
  214.                 Admin.log('[{{ id }}|field_dialog_form_action] ajax success');
  215.                 // if the crud action return ok, then the element has been added
  216.                 // so the widget container must be refresh with the last option available
  217.                 if (typeof data != 'string' && data.result == 'ok') {
  218.                     field_dialog_{{ id }}.modal('hide');
  219.                     {% if sonata_admin.edit == 'list' %}
  220.                         {#
  221.                            in this case we update the hidden input, and call the change event to
  222.                            retrieve the post information
  223.                         #}
  224.                         jQuery('#{{ id }}').val(data.objectId);
  225.                         jQuery('#{{ id }}').change();
  226.                     {% else %}
  227.                         // reload the form element
  228.                         jQuery('#field_widget_{{ id }}').closest('form').ajaxSubmit({
  229.                             url: '{{ path('sonata_admin_retrieve_form_element', {
  230.                                 '_sonata_admin': sonata_admin.admin.root.baseCodeRoute,
  231.                                 'elementId': id,
  232.                                 'subclass': sonata_admin.admin.hasActiveSubClass() ? sonata_admin.admin.getActiveSubclassCode() : null,
  233.                                 'objectId': sonata_admin.admin.root.id(sonata_admin.admin.root.subject),
  234.                                 'uniqid': sonata_admin.admin.root.uniqid,
  235.                             } + (
  236.                                 sonata_admin.admin.root.hasRequest()
  237.                                 ? sonata_admin.admin.root.request.attributes.get('_route_params', {})
  238.                                 : {}
  239.                             ) + app.request.query.all|default({})
  240.                             ) }}',
  241.                             data: {_xml_http_request: true },
  242.                             dataType: 'html',
  243.                             type: 'POST',
  244.                             success: function(html) {
  245.                                 jQuery('#field_container_{{ id }}').replaceWith(html);
  246.                                 var newElement = jQuery('#{{ id }} [value="' + data.objectId + '"]');
  247.                                 if (newElement.is("input")) {
  248.                                     newElement.attr('checked', 'checked');
  249.                                 } else {
  250.                                     newElement.attr('selected', 'selected');
  251.                                 }
  252.                                 jQuery('#field_container_{{ id }}').trigger('sonata-admin-append-form-element');
  253.                             }
  254.                         });
  255.                     {% endif %}
  256.                     return;
  257.                 }
  258.                 // otherwise, display form error
  259.                 field_dialog_content_{{ id }}.html(data);
  260.                 Admin.shared_setup(field_dialog_{{ id }});
  261.                 // reattach the event
  262.                 jQuery('form', field_dialog_{{ id }}).submit(field_dialog_form_action_{{ id }});
  263.             },
  264.             error: function(xhr) {
  265.                 var content = '';
  266.                 if ('application/json' === xhr.getResponseHeader('Content-Type')) {
  267.                     var jsonContent = JSON.parse(xhr.responseText);
  268.                     if (jsonContent.title) {
  269.                         content += '<div class="alert alert-danger alert-dismissable">'
  270.                             + '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>'
  271.                             + jsonContent.title
  272.                             + '</div>';
  273.                     }
  274.                     if (!jsonContent.violations) {
  275.                         return;
  276.                     }
  277.                     event.currentTarget.querySelectorAll('.help-block.sonata-ba-field-error-messages').forEach((element) => {
  278.                         element.remove();
  279.                     });
  280.                     event.currentTarget.querySelectorAll('.has-error').forEach((element) => {
  281.                         element.classList.remove('has-error');
  282.                     });
  283.                     event.currentTarget.querySelectorAll('button').forEach((element) => {
  284.                         element.removeAttribute('disabled');
  285.                     });
  286.                     jsonContent.violations.forEach((violation) => {
  287.                         const field = event.currentTarget.querySelector(`[name="${violation.propertyPath}"]`);
  288.                         if (!field) {
  289.                             content += '<div class="alert alert-danger alert-dismissable">'
  290.                                 + '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>'
  291.                                 + violation.title
  292.                                 + '</div>';
  293.                             return;
  294.                         }
  295.                         const formGroup = field.closest('.form-group');
  296.                         let errorList = formGroup.querySelector(
  297.                             '.help-block.sonata-ba-field-error-messages .list-unstyled'
  298.                         );
  299.                         if (!errorList) {
  300.                             const errorWrapper = document.createElement('div');
  301.                             errorWrapper.classList.add('help-block');
  302.                             errorWrapper.classList.add('sonata-ba-field-error-messages');
  303.                             errorList = document.createElement('ul');
  304.                             errorList.classList.add('list-unstyled');
  305.                             formGroup.classList.add('has-error');
  306.                             errorWrapper.appendChild(errorList);
  307.                             formGroup.appendChild(errorWrapper);
  308.                         }
  309.                         const errorItem = document.createElement('li');
  310.                         errorItem.innerHTML = `<i class="fas fa-exclamation-circle" aria-hidden="true"></i> ${violation.title}`;
  311.                         errorList.appendChild(errorItem);
  312.                     });
  313.                 } else {
  314.                     content += xhr.responseText;
  315.                 }
  316.                 // Display the error.
  317.                 field_dialog_content_{{ id }}.prepend(content);
  318.                 // Reset the submit buttons.
  319.                 $(form).find('button[type="submit"]').removeAttr('disabled');
  320.             }
  321.         });
  322.         return false;
  323.     };
  324.     var field_dialog_{{ id }}         = false;
  325.     var field_dialog_content_{{ id }} = false;
  326.     var field_dialog_title_{{ id }}   = false;
  327.     function initialize_popup_{{ id }}() {
  328.         // initialize component
  329.         if (!field_dialog_{{ id }}) {
  330.             field_dialog_{{ id }}         = jQuery("#field_dialog_{{ id }}");
  331.             field_dialog_content_{{ id }} = jQuery(".modal-body", "#field_dialog_{{ id }}");
  332.             field_dialog_title_{{ id }}   = jQuery(".modal-title", "#field_dialog_{{ id }}");
  333.             // move the dialog as a child of the root element, nested form breaks html ...
  334.             jQuery(document.body).append(field_dialog_{{ id }});
  335.             Admin.log('[{{ id }}|field_dialog] move dialog container as a document child');
  336.         }
  337.     }
  338.     {#
  339.         This code is used to define the "add" popup
  340.     #}
  341.     // this function initializes the popup
  342.     // this can be only done this way as popup can be cascaded
  343.     function start_field_dialog_form_add_{{ id }}(link) {
  344.         // remove the html event
  345.         link.onclick = null;
  346.         initialize_popup_{{ id }}();
  347.         // add the jQuery event to the a element
  348.         jQuery(link)
  349.             .click(field_dialog_form_add_{{ id }})
  350.             .trigger('click')
  351.         ;
  352.         return false;
  353.     }
  354.     {#
  355.         This code is used to define the "edit" popup
  356.     #}
  357.     // this function initializes the popup
  358.     // this can only be done this way as popup can be cascaded
  359.     function start_field_dialog_form_edit_{{ id }}(link) {
  360.         // remove the html event
  361.         link.onclick = null;
  362.         initialize_popup_{{ id }}();
  363.         // add the jQuery event to the a element
  364.         jQuery(link)
  365.             .click(field_dialog_form_edit_{{ id }})
  366.             .trigger('click')
  367.         ;
  368.         return false;
  369.     }
  370.     if (field_dialog_{{ id }}) {
  371.         Admin.shared_setup(field_dialog_{{ id }});
  372.     }
  373.     {% if sonata_admin.edit == 'list' %}
  374.         {#
  375.             This code is used to defined the "list" popup
  376.         #}
  377.         // this function initializes the popup
  378.         // this can be only done this way as popup can be cascaded
  379.         function start_field_dialog_form_list_{{ id }}(link) {
  380.             link.onclick = null;
  381.             initialize_popup_{{ id }}();
  382.             // add the jQuery event to the a element
  383.             jQuery(link)
  384.                 .click(field_dialog_form_list_{{ id }})
  385.                 .trigger('click')
  386.             ;
  387.             return false;
  388.         }
  389.         function remove_selected_element_{{ id }}(link) {
  390.             link.onclick = null;
  391.             jQuery(link)
  392.                 .click(field_remove_element_{{ id }})
  393.                 .trigger('click')
  394.             ;
  395.             return false;
  396.         }
  397.         function field_remove_element_{{ id }}(event) {
  398.             event.preventDefault();
  399.             if (jQuery('#{{ id }} option').get(0)) {
  400.                 jQuery('#{{ id }}').attr('selectedIndex', '-1').children("option:selected").attr("selected", false);
  401.             }
  402.             jQuery('#{{ id }}').val('');
  403.             jQuery('#{{ id }}').trigger('change');
  404.             return false;
  405.         }
  406.         {#
  407.           attach onchange event on the input
  408.         #}
  409.         // update the label
  410.         jQuery('#{{ id }}').on('change', function(event) {
  411.             Admin.log('[{{ id }}|on:change] update the label');
  412.             var objectId = jQuery(this).val();
  413.             // Skip short object information call if object is missing.
  414.             if (undefined === objectId || null === objectId || '' === objectId) {
  415.                 jQuery('#field_widget_{{ id }}').html('{{ 'short_object_description_placeholder'|trans({}, 'SonataAdminBundle') }}');
  416.                 {% if btn_edit %}
  417.                     jQuery('#field_actions_{{ id }} a.btn-warning').addClass('hidden');
  418.                 {% endif %}
  419.                 return;
  420.             }
  421.             jQuery('#field_widget_{{ id }}').html("<span><img src=\"{{ asset('bundles/sonataadmin/images/ajax-loader.gif') }}\" style=\"vertical-align: middle; margin-right: 10px\"/>{{ 'loading_information'|trans([], 'SonataAdminBundle') }}</span>");
  422.             jQuery.ajax({
  423.                 type: 'GET',
  424.                 url: '{{ path('sonata_admin_short_object_information',{
  425.                     '_sonata_admin': associationadmin.baseCodeRoute,
  426.                     'objectId': 'OBJECT_ID',
  427.                     'uniqid': associationadmin.uniqid,
  428.                     'linkParameters': sonata_admin.field_description.option('link_parameters', {})
  429.                 } + (
  430.                     associationadmin.hasRequest()
  431.                     ? associationadmin.request.attributes.get('_route_params', {})
  432.                     : {}
  433.                 ) + app.request.query.all|default({})
  434.                 )}}'.replace('OBJECT_ID', objectId),
  435.                 dataType: 'html',
  436.                 success: function(html) {
  437.                     jQuery('#field_widget_{{ id }}').html(html);
  438.                 }
  439.             });
  440.             {% if btn_edit %}
  441.                 var edit_button_url = '{{
  442.                     associationadmin.generateUrl('edit', {(associationadmin.idParameter) : 'OBJECT_ID'})
  443.                 }}'.replace('OBJECT_ID', objectId);
  444.                 jQuery('#field_actions_{{ id }} a.btn-warning').removeClass('hidden').attr('href', edit_button_url);
  445.             {% endif %}
  446.         });
  447.     {% endif %}
  448. </script>
  449. <!-- / edit many association -->
  450. {% endautoescape %}