Admin.js 12 KB

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