main.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. (function ($) {
  2. $(document).ready(function() {
  3. var initFilters = function() {
  4. $('.changelist-filter-select').on('change', function () {
  5. var $select = $(this);
  6. var $selectedOption = $select.find('option:selected');
  7. var url = $selectedOption.data('url');
  8. var querysetLookup = $select.data('queryset--lookup');
  9. if (url) {
  10. document.location = $selectedOption.data('url');
  11. } else if (querysetLookup) {
  12. document.location = '?' + querysetLookup + '=' + $selectedOption.val();
  13. }
  14. });
  15. };
  16. var initChangeformTabs = function() {
  17. $('.changeform').each(function() {
  18. var $changeform = $(this);
  19. var $tabItems = $changeform.find('.changeform-tabs-item');
  20. var $modules = $changeform.find('.module');
  21. if ($tabItems.length == 0) {
  22. return;
  23. }
  24. var showTab = function(selector) {
  25. selector = selector.replace(/^#\/?/, '');
  26. var $module = selector.length > 0 ? $modules.filter('#' + selector) : $();
  27. if ($module && $module.length == 0) {
  28. selector = $tabItems.first().find('a').attr('href').replace(/^#\/?/, '');
  29. }
  30. var $tabItem = $tabItems.find('a[href="#/' + selector + '"]').closest('.changeform-tabs-item');
  31. $tabItems.removeClass('selected');
  32. $tabItem.addClass('selected');
  33. $module = $modules.removeClass('selected').filter('#' + selector).addClass('selected');
  34. $module.find('select').trigger('select:init');
  35. };
  36. $('.changeform-tabs-item-link').click(function (e) {
  37. var moduleSelector = $(this).attr('href');
  38. showTab(moduleSelector);
  39. });
  40. showTab(location.hash);
  41. });
  42. };
  43. var initCheckboxesWithoutLabel = function () {
  44. var uniqueCheckboxIdCounter = 0;
  45. var uniqueCheckboxIdPrefix = 'unique_checkbox_id_';
  46. var addLabelToCheckbox = function($checkbox) {
  47. var checkboxId = $checkbox.attr('id') ? $checkbox.attr('id') : uniqueCheckboxIdPrefix + uniqueCheckboxIdCounter++;
  48. var $label = $('<label>').attr('for', checkboxId);
  49. $checkbox.hide().attr('id', checkboxId);
  50. $label.insertAfter($checkbox);
  51. };
  52. var addLabelToCheckboxes = function() {
  53. var $containers = $('.action-checkbox, .action-checkbox-column').add('.tabular.inline-related .form-row');
  54. var $checkboxes = $containers.find('input[type="checkbox"]').add('.checkbox-without-label').add('label > input[type="checkbox"]');
  55. $checkboxes.each(function() {
  56. addLabelToCheckbox($(this));
  57. });
  58. };
  59. addLabelToCheckboxes();
  60. };
  61. var initUserTools = function() {
  62. var $userTools = $('.top-user-tools');
  63. var closeTimeout;
  64. $userTools.on('mouseenter', function() {
  65. if (closeTimeout) {
  66. clearTimeout(closeTimeout);
  67. }
  68. $userTools.addClass('opened');
  69. });
  70. $userTools.on('mouseleave', function() {
  71. closeTimeout = setTimeout(function() {
  72. $userTools.removeClass('opened');
  73. closeTimeout = null;
  74. }, 200);
  75. });
  76. };
  77. var initSideMenu = function() {
  78. var initPopupItems = function() {
  79. var $popupContainer = $('.sidebar-popup-container');
  80. var $popup = $('.sidebar-popup');
  81. var $popupItems = $('.sidebar-popup-item');
  82. var $popupLinks = $('.popup-item-link');
  83. var $popupLink;
  84. var t;
  85. var $currentPopupItem;
  86. var $currentPopupItemListItem;
  87. var $currentPopupItemListItems = function() { return $currentPopupItem.find('.sidebar-popup-list-item:visible') };
  88. var resetCurrentPopupItemListItems = function() {
  89. $currentPopupItemListItems().removeClass('selected');
  90. };
  91. var initPopupItemsSearch = function() {
  92. $popupItems.each(function() {
  93. var $popupItem = $(this);
  94. var $search = $popupItem.find('.sidebar-popup-search');
  95. var $items = $popupItem.find('.sidebar-popup-list-item');
  96. $search.on('change keyup', function() {
  97. var text = $(this).val();
  98. $items.hide();
  99. $popupItem
  100. .find('.sidebar-popup-list-item-link:icontains("' + text + '")')
  101. .closest('.sidebar-popup-list-item')
  102. .show();
  103. });
  104. });
  105. };
  106. var showPopup = function ($popupLink) {
  107. clearHideTimeout();
  108. var popupItemId = $popupLink.data('popup-item-id');
  109. var $popupItem = $('#' + popupItemId);
  110. var $search = $popupItem.find('.sidebar-popup-search');
  111. $popupItems.hide();
  112. $popupItem.show();
  113. $popupContainer.stop().fadeIn(200, 'swing');
  114. $popupLinks.removeClass('hovered');
  115. $popupLink.addClass('hovered');
  116. $('body').addClass('non-scrollable');
  117. $currentPopupItem = $popupItem;
  118. $currentPopupItemListItem = null;
  119. resetCurrentPopupItemListItems();
  120. $search.val('').trigger('change').focus();
  121. };
  122. var hidePopup = function () {
  123. t = setTimeout(function() {
  124. $popupItems.hide();
  125. $popupContainer.stop().fadeOut(200, 'swing');
  126. $popupLinks.removeClass('hovered');
  127. $('body').removeClass('non-scrollable');
  128. $currentPopupItem = null;
  129. }, 200);
  130. };
  131. var clearHideTimeout = function() {
  132. if (t != null) {
  133. clearTimeout(t);
  134. }
  135. t = null;
  136. };
  137. $popupLinks.on('mouseenter', function () {
  138. $popupLink = $(this);
  139. showPopup($popupLink);
  140. });
  141. $popupLinks.on('mouseleave', function (e) {
  142. var $toElement = $(e.toElement);
  143. if ($toElement.hasClass('sidebar-popup') || $toElement.parents('.sidebar-popup').length) {
  144. return;
  145. }
  146. hidePopup();
  147. });
  148. $popup.on('mouseenter', function (e) {
  149. clearHideTimeout();
  150. });
  151. $popup.on('mouseleave', function (e) {
  152. var $toElement = $(e.toElement);
  153. if ($toElement.hasClass('popup-item-link')
  154. && $popupLink.data('popup-item-id') == $toElement.data('popup-item-id')) {
  155. return;
  156. }
  157. hidePopup();
  158. });
  159. $popup.find('.sidebar-popup-list-item-link').on('mouseenter', function() {
  160. var $link = $(this);
  161. var $item = $link.closest('.sidebar-popup-list-item');
  162. $currentPopupItemListItem = $item;
  163. resetCurrentPopupItemListItems();
  164. $currentPopupItemListItem.addClass('selected');
  165. });
  166. var selectCurrentPopupItemListItem = function(next) {
  167. if ($currentPopupItemListItem != null) {
  168. $currentPopupItemListItem = next ? $currentPopupItemListItem.nextAll(':visible').first() : $currentPopupItemListItem.prevAll(':visible').first();
  169. }
  170. if ($currentPopupItemListItem == null || $currentPopupItemListItem.length == 0) {
  171. $currentPopupItemListItem = next ? $currentPopupItemListItems().first() : $currentPopupItemListItems().last();
  172. }
  173. resetCurrentPopupItemListItems();
  174. $currentPopupItemListItem.addClass('selected');
  175. };
  176. $(document).keydown(function(e) {
  177. if ($currentPopupItem == null) {
  178. return;
  179. }
  180. if (e.which == 38) { //up
  181. selectCurrentPopupItemListItem(false);
  182. } else if (e.which == 40) { //down
  183. selectCurrentPopupItemListItem(true);
  184. } else if (e.which == 13) {
  185. if ($currentPopupItemListItem) {
  186. document.location = $currentPopupItemListItem.find('a').attr('href');
  187. }
  188. } else {
  189. return;
  190. }
  191. e.preventDefault();
  192. });
  193. initPopupItemsSearch();
  194. };
  195. var initBookmarks = function() {
  196. var $addForm = $('#bookmarks-add-form');
  197. var $removeForm = $('#bookmarks-remove-form');
  198. var $addTitleInput = $addForm.find('input[name="title"]');
  199. var $addUrlInput = $addForm.find('input[name="url"]');
  200. var $removeIdInput = $removeForm.find('input[name="id"]');
  201. $('.bookmarks-add').on('click', function(e) {
  202. e.preventDefault();
  203. var $link = $(this);
  204. var defaultTitle = $link.data('title') ? $link.data('title') : document.title;
  205. var url = window.location.href;
  206. $addTitleInput.val(defaultTitle);
  207. $addUrlInput.val(url);
  208. var addBookmark = function() {
  209. $.ajax({
  210. url: $addForm.attr('action'),
  211. method: $addForm.attr('method'),
  212. dataType: 'json',
  213. data: $addForm.serialize(),
  214. success: function (result) {
  215. if (result.error) {
  216. return;
  217. }
  218. var $list = $('.bookmarks-list');
  219. var $item = $('.sidebar-menu-item-list-item.empty').clone().removeClass('empty');
  220. $item.find('.sidebar-menu-item-list-item-link')
  221. .attr('href', url)
  222. .append($addTitleInput.val());
  223. $item.find('.sidebar-menu-item-list-item-link-remove').attr('data-bookmark-id', result.id);
  224. $list.append($item);
  225. }
  226. });
  227. };
  228. var buttons = {};
  229. buttons[django.gettext('Add')] = function() {
  230. addBookmark();
  231. $(this).dialog('close');
  232. };
  233. buttons[django.gettext('Cancel')] = function() {
  234. $(this).dialog('close');
  235. };
  236. $('#bookmarks-add-dialog').dialog({
  237. resizable: false,
  238. modal: true,
  239. buttons: buttons
  240. });
  241. });
  242. $(document).on('click', '.bookmarks-remove', function(e) {
  243. e.preventDefault();
  244. var $remove = $(this);
  245. var bookmarkId = $remove.data('bookmark-id');
  246. var deleteBookmark = function() {
  247. $removeIdInput.val(bookmarkId);
  248. $.ajax({
  249. url: $removeForm.attr('action'),
  250. method: $removeForm.attr('method'),
  251. dataType: 'json',
  252. data: $removeForm.serialize(),
  253. success: function (result) {
  254. if (result.error) {
  255. return;
  256. }
  257. var $item = $remove.closest('.sidebar-menu-item-list-item');
  258. $item.remove();
  259. }
  260. });
  261. };
  262. var buttons = {};
  263. buttons[django.gettext('Delete')] = function() {
  264. deleteBookmark();
  265. $(this).dialog('close');
  266. };
  267. buttons[django.gettext('Cancel')] = function() {
  268. $(this).dialog('close');
  269. };
  270. $('#bookmarks-remove-dialog').dialog({
  271. resizable: false,
  272. modal: true,
  273. buttons: buttons
  274. });
  275. });
  276. };
  277. var initApplicationPinning = function() {
  278. var $appsList = $('.apps-list');
  279. var $pinnedAppsList = $('.apps-list-pinned');
  280. var $appsHide = $('.apps-hide');
  281. var updateAppsHide = function () {
  282. var text;
  283. if ($appsList.is(':visible')) {
  284. text = django.gettext('Hide applications');
  285. } else {
  286. text = django.gettext('Show hidden');
  287. }
  288. $appsHide.text(text);
  289. if (($appsList.children().length == 0 || $pinnedAppsList.children().length == 0) && $appsList.is(':visible')) {
  290. $appsHide.hide();
  291. } else {
  292. $appsHide.show();
  293. }
  294. };
  295. $appsHide.on('click', function (e) {
  296. e.preventDefault();
  297. $appsList.slideFadeToggle(200, 'swing', function () {
  298. localStorage['side_menu_apps_list_visible'] = $appsList.is(':visible');
  299. updateAppsHide();
  300. });
  301. });
  302. $('.app-item .pin-toggle').on('click', function (e) {
  303. var $appItem = $(this).closest('.app-item');
  304. var appLabel = $appItem.data('app-label');
  305. var $form = $('#toggle-application-pin-form');
  306. $form.find('input[name="app_label"]').val(appLabel);
  307. $.ajax({
  308. url: $form.attr('action'),
  309. method: $form.attr('method'),
  310. dataType: 'json',
  311. data: $form.serialize(),
  312. success: function (result) {
  313. if (result.error) {
  314. return;
  315. }
  316. var $target = result.pinned ? $('.apps-list-pinned') : $('.apps-list');
  317. if (result.pinned) {
  318. $appItem.addClass('pinned');
  319. } else {
  320. $appItem.removeClass('pinned');
  321. }
  322. $appItem.detach();
  323. $appItem.appendTo($target);
  324. updateAppsHide();
  325. }
  326. });
  327. e.preventDefault();
  328. });
  329. if (localStorage['side_menu_apps_list_visible'] === 'false') {
  330. if ($pinnedAppsList.children().length != 0) {
  331. $appsList.hide();
  332. } else {
  333. localStorage['side_menu_apps_list_visible'] = true;
  334. }
  335. }
  336. updateAppsHide();
  337. };
  338. initPopupItems();
  339. initBookmarks();
  340. initApplicationPinning();
  341. };
  342. var initDeleteObjects = function() {
  343. $('.delete-objects-list-item.collapsable').each(function() {
  344. var $item = $(this);
  345. var $link = $item.find('.delete-objects-list-item-row-collapse');
  346. var $collapsable = $item.find('.delete-objects-list-item-collapsable');
  347. $link.on('click', function(e) {
  348. e.preventDefault();
  349. $collapsable.slideToggle(200, 'swing');
  350. });
  351. });
  352. };
  353. var initjQueryCaseInsensitiveSelector = function() {
  354. $.expr[":"].icontains = $.expr.createPseudo(function (arg) {
  355. return function (elem) {
  356. return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
  357. };
  358. });
  359. };
  360. var initjQuerySlideFadeToggle = function() {
  361. $.fn.slideFadeToggle = function (speed, easing, callback) {
  362. return this.animate({opacity: 'toggle', height: 'toggle'}, speed, easing, callback);
  363. };
  364. };
  365. var initDateTimeWidgets = function() {
  366. var removePreviousSibling = function($element) {
  367. var node = $element[0].previousSibling;
  368. node.parentNode.removeChild(node);
  369. };
  370. var djangoDateTimeFormatToJs = function(format) {
  371. return format.toLowerCase().replace(/%\w/g, function(format) {
  372. format = format.replace(/%/,"");
  373. return format + format;
  374. });
  375. };
  376. var updateDatetimeLayout = function() {
  377. $('.form-row .datetime').each(function () {
  378. var $dateTime = $(this);
  379. var $dateField = $dateTime.find('.vDateField');
  380. var $timeField = $dateTime.find('.vTimeField');
  381. removePreviousSibling($dateField);
  382. removePreviousSibling($timeField);
  383. $dateField.nextAll('br').first().remove();
  384. });
  385. };
  386. var initDateWidget = function() {
  387. $('.form-row .vDateField').each(function () {
  388. var $dateField = $(this);
  389. var $dateLink = $('<a href="#">').addClass('vDateField-link');
  390. var $dateButton = $('<span>').addClass('icon-calendar');
  391. $dateLink.append($dateButton).insertAfter($dateField);
  392. $dateField.datepicker({
  393. dateFormat: djangoDateTimeFormatToJs(DATE_FORMAT),
  394. showButtonPanel: true,
  395. nextText: '',
  396. prevText: ''
  397. });
  398. $dateLink.on('click', function (e) {
  399. if ($dateField.datepicker('widget').is(':visible')) {
  400. $dateField.datepicker('hide');
  401. } else {
  402. $dateField.datepicker('show');
  403. }
  404. e.preventDefault();
  405. });
  406. });
  407. var old_goToToday = $.datepicker._gotoToday;
  408. $.datepicker._gotoToday = function(id) {
  409. old_goToToday.call(this,id);
  410. this._selectDate(id);
  411. };
  412. };
  413. var initTimeWidget = function() {
  414. $('.form-row .vTimeField').each(function () {
  415. var $timeField = $(this);
  416. var $timeLink = $('<a href="#">').addClass('vTimeField-link');
  417. var $timeButton = $('<span>').addClass('icon-clock');
  418. $timeLink.append($timeButton).insertAfter($timeField);
  419. $timeField.timepicker({
  420. showPeriodLabels: false,
  421. showCloseButton: true,
  422. showNowButton: true
  423. });
  424. $timeLink.on('click', function (e) {
  425. if ($timeField.datepicker('widget').is(':visible')) {
  426. $timeField.datepicker('hide');
  427. } else {
  428. $timeField.timepicker('show');
  429. }
  430. e.preventDefault();
  431. });
  432. });
  433. };
  434. updateDatetimeLayout();
  435. initDateWidget();
  436. initTimeWidget();
  437. };
  438. var initInlines = function() {
  439. $('.module').each(function() {
  440. var $module = $(this);
  441. var $items = function() { return $module.find('.stacked-inline-list-item'); };
  442. var $inlinesRelated = function() { return $module.find('.inline-related'); };
  443. $module.on('click', '.stacked-inline-list-item-link', function(e) {
  444. var $itemLink = $(this);
  445. var $item = $itemLink.closest('.stacked-inline-list-item');
  446. var moduleId = $itemLink.data('inline-related-id');
  447. $items().removeClass('selected');
  448. $item.addClass('selected');
  449. $inlinesRelated().removeClass('selected').filter('#' + moduleId).addClass('selected');
  450. e.preventDefault();
  451. });
  452. $module.on('click', '.stacked-inline-list-item-link-remove', function(e) {
  453. var $itemLink = $(this).closest('.stacked-inline-list-item-link');
  454. var $item = $itemLink.closest('.stacked-inline-list-item');
  455. var moduleId = $itemLink.data('inline-related-id');
  456. $item.remove();
  457. $inlinesRelated().filter('#' + moduleId).remove();
  458. e.preventDefault();
  459. });
  460. $module.find('.inline-related').each(function() {
  461. var $inline = $(this);
  462. $inline.find('.delete input').on('change', function(e) {
  463. var $input = $(this);
  464. var id = $inline.attr('id');
  465. var $link = $module.find('.stacked-inline-list-item-link[data-inline-related-id="' + id + '"]');
  466. var $item = $link.closest('.stacked-inline-list-item');
  467. if ($input.is(':checked')) {
  468. $item.addClass('delete');
  469. } else {
  470. $item.removeClass('delete');
  471. }
  472. });
  473. });
  474. $module.find('.add-row a').on('click', function() {
  475. $module.find('select').trigger('select:init');
  476. });
  477. });
  478. };
  479. var initChangelist = function() {
  480. var initChangelistHeaders = function() {
  481. var $originalThead = $('.results thead');
  482. if ($originalThead.length == 0) {
  483. return;
  484. }
  485. var $thead = $originalThead.clone();
  486. var $table = $('<table>').addClass('table helper').append($thead);
  487. $table.find('.action-checkbox-column').empty();
  488. $table.appendTo(document.body);
  489. var updateChangelistHeaderVisibility = function () {
  490. if ($(window).scrollTop() > $originalThead.offset().top) {
  491. $table.show();
  492. } else {
  493. $table.hide();
  494. }
  495. };
  496. var updateChangelistHeaderWidth = function () {
  497. var $originalTheadColumns = $originalThead.find('th');
  498. var $theadColumns = $thead.find('th');
  499. $originalTheadColumns.each(function (i) {
  500. $theadColumns.eq(i).css('width', $(this).width());
  501. });
  502. };
  503. $(window).on('scroll', updateChangelistHeaderVisibility);
  504. $(window).on('resize', updateChangelistHeaderWidth);
  505. updateChangelistHeaderWidth();
  506. };
  507. var initChangelistFooters = function() {
  508. var $changelistFooters = $('.changelist-footer');
  509. if ($changelistFooters.length == 0) {
  510. return;
  511. }
  512. var updateChangelistFooters = function () {
  513. $changelistFooters.each(function () {
  514. var $changelistFooter = $(this);
  515. var $results = $changelistFooter.siblings('.results');
  516. if ($(window).scrollTop() + $(window).height() < $(document).height()) {
  517. if (!$changelistFooter.hasClass('fixed')) {
  518. var previousScrollTop = $(window).scrollTop();
  519. $changelistFooter.addClass('fixed');
  520. $results.css('margin-bottom', ($changelistFooter.outerHeight(false) - 20 - 2) + 'px');
  521. $(window).scrollTop(previousScrollTop);
  522. }
  523. } else {
  524. if ($changelistFooter.hasClass('fixed')) {
  525. $changelistFooter.removeClass('fixed');
  526. $results.css('margin-bottom', 0);
  527. }
  528. }
  529. });
  530. };
  531. $(window).on('scroll', updateChangelistFooters);
  532. $(window).on('resize', updateChangelistFooters);
  533. updateChangelistFooters();
  534. };
  535. var initChangelistImages = function() {
  536. $('img[src$="admin/img/icon-yes.gif"]').after($('<span class="icon-tick">'));
  537. $('img[src$="admin/img/icon-no.gif"]').after($('<span class="icon-cross">'));
  538. $('img[src$="admin/img/icon-unknown.gif"]').after($('<span class="icon-question">'));
  539. };
  540. var initChangelistRowSelection = function() {
  541. $('#result_list tbody th, #result_list tbody td').on('click', function(e) {
  542. // Fix selection on clicking elements inside row (e.x. links)
  543. if (e.target != this) {
  544. return;
  545. }
  546. $(this).closest('tr').find('.action-checkbox .action-select').click();
  547. });
  548. };
  549. initChangelistHeaders();
  550. initChangelistFooters();
  551. initChangelistImages();
  552. initChangelistRowSelection();
  553. };
  554. var initTooltips = function() {
  555. $('a[title],.tooltip[title]').tooltip({
  556. track: true
  557. });
  558. };
  559. var initDashboard = function() {
  560. var updateDashboardModules = function () {
  561. var $form = $('#update-dashboard-modules-form');
  562. var modules = [];
  563. $('.dashboard-column').each(function () {
  564. var $column = $(this);
  565. var column = $column.closest('.dashboard-column-wrapper').index();
  566. $column.find('.dashboard-item').each(function () {
  567. var $item = $(this);
  568. var order = $item.index();
  569. var id = $item.data('module-id');
  570. modules.push({
  571. id: id,
  572. column: column,
  573. order: order
  574. });
  575. });
  576. });
  577. $form.find('[name="modules"]').val(JSON.stringify(modules));
  578. $.ajax({
  579. url: $form.attr('action'),
  580. method: $form.attr('method'),
  581. dataType: 'json',
  582. data: $form.serialize()
  583. });
  584. };
  585. $('.dashboard-column').droppable({
  586. activeClass: 'active',
  587. hoverClass: 'hovered',
  588. tolerance: 'pointer',
  589. accept: '.dashboard-item'
  590. }).sortable({
  591. items: '.dashboard-item',
  592. handle: '.dashboard-item-header',
  593. tolerance: 'pointer',
  594. connectWith: '.dashboard-column',
  595. cursor: 'move',
  596. placeholder: 'dashboard-item placeholder',
  597. forcePlaceholderSize: true,
  598. update: function (event, ui) {
  599. updateDashboardModules();
  600. }
  601. });
  602. $('.dashboard-item.collapsible').each(function () {
  603. var $item = $(this);
  604. var $link = $item.find('.dashboard-item-collapse');
  605. var $collapsible = $item.find('.dashboard-item-content');
  606. var $form = $('#update-dashboard-module-collapse-form');
  607. var moduleId = $item.data('module-id');
  608. $link.on('click', function (e) {
  609. e.preventDefault();
  610. $collapsible.slideFadeToggle(200, 'swing', function () {
  611. var collapsed = $collapsible.is(':visible') == false;
  612. if (collapsed) {
  613. $item.addClass('collapsed')
  614. } else {
  615. $item.removeClass('collapsed')
  616. }
  617. $form.find('[name="id"]').val(moduleId);
  618. $form.find('[name="collapsed"]').val(collapsed ? 'true' : 'false');
  619. $.ajax({
  620. url: $form.attr('action'),
  621. method: $form.attr('method'),
  622. dataType: 'json',
  623. data: $form.serialize()
  624. });
  625. });
  626. });
  627. });
  628. $('.dashboard-item.deletable').each(function () {
  629. var $item = $(this);
  630. var $link = $item.find('.dashboard-item-remove');
  631. var $form = $('#remove-dashboard-module-form');
  632. var moduleId = $item.data('module-id');
  633. $link.on('click', function (e) {
  634. e.preventDefault();
  635. var buttons = {};
  636. var deleteModule = function () {
  637. $item.fadeOut(200, 'swing', function () {
  638. $form.find('[name="id"]').val(moduleId);
  639. $.ajax({
  640. url: $form.attr('action'),
  641. method: $form.attr('method'),
  642. dataType: 'json',
  643. data: $form.serialize()
  644. });
  645. });
  646. };
  647. buttons[django.gettext('Delete')] = function () {
  648. deleteModule();
  649. $(this).dialog('close');
  650. };
  651. buttons[django.gettext('Cancel')] = function () {
  652. $(this).dialog('close');
  653. };
  654. $('#module-remove-dialog').dialog({
  655. resizable: false,
  656. modal: true,
  657. buttons: buttons
  658. });
  659. });
  660. });
  661. var $form = $('#add-dashboard-module-form');
  662. $form.find('.add-dashboard-link').on('click', function (e) {
  663. var $typeInput = $form.find('[name="type"]');
  664. var type = $form.find('[name="module"] option:selected').data('type');
  665. if (type) {
  666. $typeInput.val(type);
  667. $.ajax({
  668. url: $form.attr('action'),
  669. method: $form.attr('method'),
  670. dataType: 'json',
  671. data: $form.serialize(),
  672. success: function (result) {
  673. if (result.error) {
  674. return;
  675. }
  676. document.location = result.success_url;
  677. }
  678. });
  679. }
  680. e.preventDefault();
  681. });
  682. $('.dashboard-item.ajax').each(function () {
  683. var $item = $(this);
  684. var $content = $item.find('.dashboard-item-content');
  685. var url = $item.data('ajax-url');
  686. var moduleId = $item.data('module-id');
  687. $form.find('[name="id"]').val(moduleId);
  688. $.ajax({
  689. url: url,
  690. dataType: 'json',
  691. success: function (result) {
  692. if (result.error) {
  693. $content.empty();
  694. return;
  695. }
  696. var oldHeight = $content.height();
  697. $content.html(result.html);
  698. var newHeight = $content.height();
  699. $content.height(oldHeight);
  700. $content.animate({
  701. height: newHeight
  702. }, 250);
  703. },
  704. error: function() {
  705. $content.empty();
  706. }
  707. });
  708. });
  709. $('.reset-dashboard-link').on('click', function(e) {
  710. var buttons = {};
  711. var resetDashboard = function () {
  712. var $form = $('#reset-dashboard-form');
  713. $.ajax({
  714. url: $form.attr('action'),
  715. method: $form.attr('method'),
  716. dataType: 'json',
  717. data: $form.serialize(),
  718. success: function (result) {
  719. if (result.error) {
  720. return;
  721. }
  722. location.reload();
  723. }
  724. });
  725. };
  726. buttons[django.gettext('Yes')] = function() {
  727. resetDashboard();
  728. $(this).dialog('close');
  729. };
  730. buttons[django.gettext('Cancel')] = function() {
  731. $(this).dialog('close');
  732. };
  733. $('#reset-dashboard-dialog').dialog({
  734. resizable: false,
  735. modal: true,
  736. buttons: buttons
  737. });
  738. e.preventDefault();
  739. });
  740. };
  741. var initUnsavedChangesWarning = function() {
  742. var $changeform = $('.changeform');
  743. if ($changeform.length) {
  744. var $inputs = $changeform.find('input, textarea, select');
  745. var bound = false;
  746. var onBeforeUnload = function (){
  747. return django.gettext('Warning: you have unsaved changes');
  748. };
  749. var onChange = function () {
  750. $inputs.off('change', onChange);
  751. if (!bound) {
  752. $(window).bind('beforeunload', onBeforeUnload);
  753. bound = true;
  754. }
  755. };
  756. $(document).on('submit', 'form', function() {
  757. $(window).off('beforeunload', onBeforeUnload);
  758. });
  759. $inputs.on('change', onChange);
  760. }
  761. };
  762. var initScrollbars = function() {
  763. $('.sidebar-menu-wrapper').perfectScrollbar();
  764. };
  765. var initThemeChoosing = function() {
  766. $('.choose-theme').on('click', function () {
  767. var $link = $(this);
  768. $.cookie('JET_THEME', $link.data('theme'), { expires: 365, path: '/' });
  769. var cssToLoad = [
  770. { url: $link.data('base-stylesheet'), class: 'base-stylesheet' },
  771. { url: $link.data('select2-stylesheet'), class: 'select2-stylesheet' },
  772. { url: $link.data('jquery-ui-stylesheet'), class: 'jquery-ui-stylesheet' }
  773. ];
  774. var loadedCss = 0;
  775. var onCssLoaded = function() {
  776. ++loadedCss;
  777. if (loadedCss == cssToLoad.length) {
  778. $(document).trigger('theme:changed');
  779. }
  780. };
  781. cssToLoad.forEach(function(css) {
  782. $('<link>')
  783. .attr('rel', 'stylesheet')
  784. .addClass(css['class'])
  785. .attr('href', css['url'])
  786. .load(onCssLoaded)
  787. .appendTo('head');
  788. $('.' + css['class'])
  789. .slice(0, -2)
  790. .remove();
  791. });
  792. $('.choose-theme').removeClass('selected');
  793. $link.addClass('selected');
  794. });
  795. };
  796. var initRelatedPopups = function() {
  797. var closeRelatedPopup = function () {
  798. var $popups = $('.related-popup');
  799. var $container = $('.related-popup-container');
  800. var $popup = $popups.last();
  801. $popup.remove();
  802. if ($popups.length == 1) {
  803. $container.fadeOut(200, 'swing', function () {
  804. $('.related-popup-back').hide();
  805. $('body').removeClass('non-scrollable');
  806. });
  807. }
  808. };
  809. $('.related-popup-back').on('click', function (e) {
  810. e.preventDefault();
  811. closeRelatedPopup();
  812. });
  813. $(window).on('related-popup:close', function () {
  814. closeRelatedPopup();
  815. });
  816. };
  817. initjQueryCaseInsensitiveSelector();
  818. initjQuerySlideFadeToggle();
  819. initFilters();
  820. initChangeformTabs();
  821. initCheckboxesWithoutLabel();
  822. initUserTools();
  823. initSideMenu();
  824. initDeleteObjects();
  825. initDateTimeWidgets();
  826. initInlines();
  827. initChangelist();
  828. initTooltips();
  829. initDashboard();
  830. initUnsavedChangesWarning();
  831. initScrollbars();
  832. initThemeChoosing();
  833. initRelatedPopups();
  834. });
  835. })(jet.jQuery);