Admin.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. jQuery(document).ready(function() {
  8. jQuery('html').removeClass('no-js');
  9. if (window.SONATA_CONFIG && window.SONATA_CONFIG.CONFIRM_EXIT) {
  10. jQuery('.sonata-ba-form form').confirmExit();
  11. }
  12. Admin.setup_select2(document);
  13. Admin.setup_xeditable(document);
  14. Admin.add_pretty_errors(document);
  15. Admin.add_filters(document);
  16. Admin.set_object_field_value(document);
  17. Admin.setup_collection_buttons(document);
  18. Admin.setup_per_page_switcher(document);
  19. Admin.setup_form_tabs_for_errors(document);
  20. Admin.setup_inline_form_errors(document);
  21. });
  22. jQuery(document).on('sonata-admin-append-form-element', function(e) {
  23. Admin.setup_select2(e.target);
  24. });
  25. var Admin = {
  26. setup_select2: function(subject) {
  27. if (window.SONATA_CONFIG && window.SONATA_CONFIG.USE_SELECT2 && window.Select2) {
  28. jQuery('select:not([data-sonata-select2="false"])', subject).each(function() {
  29. var select = $(this);
  30. var allowClearEnabled = false;
  31. if (select.find('option[value=""]').length) {
  32. allowClearEnabled = true;
  33. }
  34. if (select.attr('data-sonata-select2-allow-clear')==='true') {
  35. allowClearEnabled = true;
  36. } else if (select.attr('data-sonata-select2-allow-clear')==='false') {
  37. allowClearEnabled = false;
  38. }
  39. select.select2({
  40. width: 'resolve',
  41. minimumResultsForSearch: 10,
  42. allowClear: allowClearEnabled
  43. });
  44. var popover = select.data('popover');
  45. if (undefined !== popover) {
  46. select
  47. .select2('container')
  48. .popover(popover.options)
  49. ;
  50. }
  51. });
  52. }
  53. },
  54. setup_xeditable: function(subject) {
  55. jQuery('.x-editable', subject).editable({
  56. emptyclass: 'editable-empty btn btn-sm',
  57. emptytext: '<i class="glyphicon glyphicon-edit"></i>',
  58. success: function(response) {
  59. if('KO' === response.status) {
  60. return response.message;
  61. }
  62. var html = jQuery(response.content);
  63. Admin.setup_xeditable(html);
  64. jQuery(this)
  65. .closest('td')
  66. .replaceWith(html)
  67. ;
  68. }
  69. });
  70. },
  71. /**
  72. * render log message
  73. * @param mixed
  74. */
  75. log: function() {
  76. var msg = '[Sonata.Admin] ' + Array.prototype.join.call(arguments,', ');
  77. if (window.console && window.console.log) {
  78. window.console.log(msg);
  79. } else if (window.opera && window.opera.postError) {
  80. window.opera.postError(msg);
  81. }
  82. },
  83. /**
  84. * display related errors messages
  85. *
  86. * @param subject
  87. */
  88. add_pretty_errors: function(subject) {
  89. Admin.setup_select2(subject);
  90. jQuery('div.sonata-ba-field-error', subject).each(function(index, element) {
  91. var input = jQuery(':input', element);
  92. if (!input.length) {
  93. return;
  94. }
  95. var message = jQuery('div.sonata-ba-field-error-messages', element).html();
  96. jQuery('div.sonata-ba-field-error-messages', element).remove();
  97. if (!message || message.length == 0) {
  98. return;
  99. }
  100. var target = input,
  101. fieldShortDescription = input.closest('.field-container').find('.field-short-description'),
  102. select2 = input.closest('.select2-container')
  103. ;
  104. if (fieldShortDescription.length) {
  105. target = fieldShortDescription;
  106. } else if (select2.length) {
  107. target= select2;
  108. }
  109. target.popover({
  110. content: message,
  111. trigger: 'hover',
  112. html: true,
  113. placement: 'top',
  114. template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><div class="popover-content alert-error"><p></p></div></div></div>'
  115. });
  116. });
  117. },
  118. stopEvent: function(event) {
  119. // https://github.com/sonata-project/SonataAdminBundle/issues/151
  120. //if it is a standard browser use preventDefault otherwise it is IE then return false
  121. if(event.preventDefault) {
  122. event.preventDefault();
  123. } else {
  124. event.returnValue = false;
  125. }
  126. //if it is a standard browser get target otherwise it is IE then adapt syntax and get target
  127. if (typeof event.target != 'undefined') {
  128. targetElement = event.target;
  129. } else {
  130. targetElement = event.srcElement;
  131. }
  132. return targetElement;
  133. },
  134. add_filters: function(subject) {
  135. jQuery('div.filter_container .sonata-filter-option', subject).hide();
  136. jQuery('h4.filter_legend', subject).click(function(event) {
  137. jQuery('div.filter_container .sonata-filter-option').toggle();
  138. });
  139. },
  140. /**
  141. * Change object field value
  142. * @param subject
  143. */
  144. set_object_field_value: function(subject) {
  145. this.log(jQuery('a.sonata-ba-edit-inline', subject));
  146. jQuery('a.sonata-ba-edit-inline', subject).click(function(event) {
  147. Admin.stopEvent(event);
  148. var subject = jQuery(this);
  149. jQuery.ajax({
  150. url: subject.attr('href'),
  151. type: 'POST',
  152. success: function(json) {
  153. if(json.status === "OK") {
  154. var elm = jQuery(subject).parent();
  155. elm.children().remove();
  156. // fix issue with html comment ...
  157. elm.html(jQuery(json.content.replace(/<!--[\s\S]*?-->/g, "")).html());
  158. elm.effect("highlight", {'color' : '#57A957'}, 2000);
  159. Admin.set_object_field_value(elm);
  160. } else {
  161. jQuery(subject).parent().effect("highlight", {'color' : '#C43C35'}, 2000);
  162. }
  163. }
  164. });
  165. });
  166. },
  167. setup_collection_buttons: function(subject) {
  168. jQuery(subject).on('click', '.sonata-collection-add', function(event) {
  169. Admin.stopEvent(event);
  170. var container = jQuery(this).closest('[data-prototype]');
  171. var proto = container.attr('data-prototype');
  172. var protoName = container.attr('data-prototype-name') || '__name__';
  173. // Set field id
  174. var idRegexp = new RegExp(container.attr('id')+'_'+protoName,'g');
  175. proto = proto.replace(idRegexp, container.attr('id')+'_'+(container.children().length - 1));
  176. // Set field name
  177. var parts = container.attr('id').split('_');
  178. var nameRegexp = new RegExp(parts[parts.length-1]+'\\]\\['+protoName,'g');
  179. proto = proto.replace(nameRegexp, parts[parts.length-1]+']['+(container.children().length - 1));
  180. jQuery(proto)
  181. .insertBefore(jQuery(this).parent())
  182. .trigger('sonata-admin-append-form-element')
  183. ;
  184. jQuery(this).trigger('sonata-collection-item-added');
  185. });
  186. jQuery(subject).on('click', '.sonata-collection-delete', function(event) {
  187. Admin.stopEvent(event);
  188. jQuery(this).trigger('sonata-collection-item-deleted');
  189. jQuery(this).closest('.sonata-collection-row').remove();
  190. });
  191. },
  192. setup_per_page_switcher: function(subject) {
  193. jQuery('select.per-page').change(function(event) {
  194. jQuery('input[type=submit]').hide();
  195. window.top.location.href=this.options[this.selectedIndex].value;
  196. });
  197. },
  198. setup_form_tabs_for_errors: function(subject) {
  199. // Switch to first tab with server side validation errors on page load
  200. jQuery('form', subject).each(function() {
  201. Admin.show_form_first_tab_with_errors(jQuery(this), '.sonata-ba-field-error');
  202. });
  203. // Switch to first tab with HTML5 errors on form submit
  204. jQuery(subject)
  205. .on('click', 'form [type="submit"]', function() {
  206. Admin.show_form_first_tab_with_errors(jQuery(this).closest('form'), ':invalid');
  207. })
  208. .on('keypress', 'form [type="text"]', function(e) {
  209. if (13 === e.which) {
  210. Admin.show_form_first_tab_with_errors(jQuery(this), ':invalid');
  211. }
  212. })
  213. ;
  214. },
  215. show_form_first_tab_with_errors: function(form, errorSelector) {
  216. var tabs = form.find('.nav-tabs a'),
  217. firstTabWithErrors;
  218. tabs.each(function() {
  219. var id = jQuery(this).attr('href'),
  220. tab = jQuery(this),
  221. icon = tab.find('.has-errors');
  222. if (jQuery(id).find(errorSelector).length > 0) {
  223. // Only show first tab with errors
  224. if (!firstTabWithErrors) {
  225. tab.tab('show');
  226. firstTabWithErrors = tab;
  227. }
  228. icon.removeClass('hide');
  229. } else {
  230. icon.addClass('hide');
  231. }
  232. });
  233. },
  234. setup_inline_form_errors: function(subject) {
  235. var deleteCheckboxSelector = '.sonata-ba-field-inline-table [id$="_delete"][type="checkbox"]';
  236. jQuery(deleteCheckboxSelector, subject).each(function() {
  237. Admin.switch_inline_form_errors(jQuery(this));
  238. });
  239. $(subject).on('change', deleteCheckboxSelector, function() {
  240. Admin.switch_inline_form_errors(jQuery(this));
  241. });
  242. },
  243. /**
  244. * Disable inline form errors when the row is marked for deletion
  245. */
  246. switch_inline_form_errors: function(deleteCheckbox) {
  247. var row = deleteCheckbox.closest('.sonata-ba-field-inline-table'),
  248. errors = row.find('.sonata-ba-field-error-messages')
  249. ;
  250. if (deleteCheckbox.is(':checked')) {
  251. row
  252. .find('[required]')
  253. .removeAttr('required')
  254. .attr('data-required', 'required')
  255. ;
  256. errors.hide();
  257. } else {
  258. row
  259. .find('[data-required]')
  260. .attr('required', 'required')
  261. ;
  262. errors.show();
  263. }
  264. }
  265. };