You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

repo-projects.js 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. const {csrfToken} = window.config;
  2. async function initRepoProjectSortable() {
  3. const els = document.getElementsByClassName('board');
  4. if (!els.length) return;
  5. const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs');
  6. const boardColumns = document.getElementsByClassName('board-column');
  7. new Sortable(
  8. els[0],
  9. {
  10. group: 'board-column',
  11. draggable: '.board-column',
  12. animation: 150,
  13. ghostClass: 'card-ghost',
  14. onSort: () => {
  15. const board = document.getElementsByClassName('board')[0];
  16. const boardColumns = board.getElementsByClassName('board-column');
  17. boardColumns.forEach((column, i) => {
  18. if (parseInt($(column).data('sorting')) !== i) {
  19. $.ajax({
  20. url: $(column).data('url'),
  21. data: JSON.stringify({sorting: i, color: rgbToHex($(column).css('backgroundColor'))}),
  22. headers: {
  23. 'X-Csrf-Token': csrfToken,
  24. 'X-Remote': true,
  25. },
  26. contentType: 'application/json',
  27. method: 'PUT',
  28. });
  29. }
  30. });
  31. },
  32. },
  33. );
  34. for (const column of boardColumns) {
  35. new Sortable(
  36. column.getElementsByClassName('board')[0],
  37. {
  38. group: 'shared',
  39. animation: 150,
  40. ghostClass: 'card-ghost',
  41. onAdd: (e) => {
  42. $.ajax(`${e.to.dataset.url}/${e.item.dataset.issue}`, {
  43. headers: {
  44. 'X-Csrf-Token': csrfToken,
  45. 'X-Remote': true,
  46. },
  47. contentType: 'application/json',
  48. type: 'POST',
  49. error: () => {
  50. e.from.insertBefore(e.item, e.from.children[e.oldIndex]);
  51. },
  52. });
  53. },
  54. },
  55. );
  56. }
  57. }
  58. export default function initRepoProject() {
  59. if (!$('.repository.projects').length) {
  60. return;
  61. }
  62. const _promise = initRepoProjectSortable();
  63. $('.edit-project-board').each(function () {
  64. const projectHeader = $(this).closest('.board-column-header');
  65. const projectTitleLabel = projectHeader.find('.board-label');
  66. const projectTitleInput = $(this).find(
  67. '.content > .form > .field > .project-board-title',
  68. );
  69. const projectColorInput = $(this).find('.content > .form > .field #new_board_color');
  70. const boardColumn = $(this).closest('.board-column');
  71. if (boardColumn.css('backgroundColor')) {
  72. setLabelColor(projectHeader, rgbToHex(boardColumn.css('backgroundColor')));
  73. }
  74. $(this)
  75. .find('.content > .form > .actions > .red')
  76. .on('click', function (e) {
  77. e.preventDefault();
  78. $.ajax({
  79. url: $(this).data('url'),
  80. data: JSON.stringify({title: projectTitleInput.val(), color: projectColorInput.val()}),
  81. headers: {
  82. 'X-Csrf-Token': csrfToken,
  83. 'X-Remote': true,
  84. },
  85. contentType: 'application/json',
  86. method: 'PUT',
  87. }).done(() => {
  88. projectTitleLabel.text(projectTitleInput.val());
  89. projectTitleInput.closest('form').removeClass('dirty');
  90. if (projectColorInput.val()) {
  91. setLabelColor(projectHeader, projectColorInput.val());
  92. }
  93. boardColumn.attr('style', `background: ${projectColorInput.val()}!important`);
  94. $('.ui.modal').modal('hide');
  95. });
  96. });
  97. });
  98. $(document).on('click', '.set-default-project-board', async function (e) {
  99. e.preventDefault();
  100. await $.ajax({
  101. method: 'POST',
  102. url: $(this).data('url'),
  103. headers: {
  104. 'X-Csrf-Token': csrfToken,
  105. 'X-Remote': true,
  106. },
  107. contentType: 'application/json',
  108. });
  109. window.location.reload();
  110. });
  111. $('.delete-project-board').each(function () {
  112. $(this).click(function (e) {
  113. e.preventDefault();
  114. $.ajax({
  115. url: $(this).data('url'),
  116. headers: {
  117. 'X-Csrf-Token': csrfToken,
  118. 'X-Remote': true,
  119. },
  120. contentType: 'application/json',
  121. method: 'DELETE',
  122. }).done(() => {
  123. window.location.reload();
  124. });
  125. });
  126. });
  127. $('#new_board_submit').click(function (e) {
  128. e.preventDefault();
  129. const boardTitle = $('#new_board');
  130. const projectColorInput = $('#new_board_color_picker');
  131. $.ajax({
  132. url: $(this).data('url'),
  133. data: JSON.stringify({title: boardTitle.val(), color: projectColorInput.val()}),
  134. headers: {
  135. 'X-Csrf-Token': csrfToken,
  136. 'X-Remote': true,
  137. },
  138. contentType: 'application/json',
  139. method: 'POST',
  140. }).done(() => {
  141. boardTitle.closest('form').removeClass('dirty');
  142. window.location.reload();
  143. });
  144. });
  145. }
  146. function setLabelColor(label, color) {
  147. const red = getRelativeColor(parseInt(color.substr(1, 2), 16));
  148. const green = getRelativeColor(parseInt(color.substr(3, 2), 16));
  149. const blue = getRelativeColor(parseInt(color.substr(5, 2), 16));
  150. const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
  151. if (luminance > 0.179) {
  152. label.removeClass('light-label').addClass('dark-label');
  153. } else {
  154. label.removeClass('dark-label').addClass('light-label');
  155. }
  156. }
  157. /**
  158. * Inspired by W3C recommandation https://www.w3.org/TR/WCAG20/#relativeluminancedef
  159. */
  160. function getRelativeColor(color) {
  161. color /= 255;
  162. return color <= 0.03928 ? color / 12.92 : ((color + 0.055) / 1.055) ** 2.4;
  163. }
  164. function rgbToHex(rgb) {
  165. rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
  166. return `#${hex(rgb[1])}${hex(rgb[2])}${hex(rgb[3])}`;
  167. }
  168. function hex(x) {
  169. const hexDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
  170. return Number.isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
  171. }