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

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