code.gitea.io/gitea@v1.22.3/web_src/js/features/repo-projects.js (about)

     1  import $ from 'jquery';
     2  import {contrastColor} from '../utils/color.js';
     3  import {createSortable} from '../modules/sortable.js';
     4  import {POST, DELETE, PUT} from '../modules/fetch.js';
     5  
     6  function updateIssueCount(cards) {
     7    const parent = cards.parentElement;
     8    const cnt = parent.getElementsByClassName('issue-card').length;
     9    parent.getElementsByClassName('project-column-issue-count')[0].textContent = cnt;
    10  }
    11  
    12  async function createNewColumn(url, columnTitle, projectColorInput) {
    13    try {
    14      await POST(url, {
    15        data: {
    16          title: columnTitle.val(),
    17          color: projectColorInput.val(),
    18        },
    19      });
    20    } catch (error) {
    21      console.error(error);
    22    } finally {
    23      columnTitle.closest('form').removeClass('dirty');
    24      window.location.reload();
    25    }
    26  }
    27  
    28  async function moveIssue({item, from, to, oldIndex}) {
    29    const columnCards = to.getElementsByClassName('issue-card');
    30    updateIssueCount(from);
    31    updateIssueCount(to);
    32  
    33    const columnSorting = {
    34      issues: Array.from(columnCards, (card, i) => ({
    35        issueID: parseInt(card.getAttribute('data-issue')),
    36        sorting: i,
    37      })),
    38    };
    39  
    40    try {
    41      await POST(`${to.getAttribute('data-url')}/move`, {
    42        data: columnSorting,
    43      });
    44    } catch (error) {
    45      console.error(error);
    46      from.insertBefore(item, from.children[oldIndex]);
    47    }
    48  }
    49  
    50  async function initRepoProjectSortable() {
    51    const els = document.querySelectorAll('#project-board > .board.sortable');
    52    if (!els.length) return;
    53  
    54    // the HTML layout is: #project-board > .board > .project-column .cards > .issue-card
    55    const mainBoard = els[0];
    56    let boardColumns = mainBoard.getElementsByClassName('project-column');
    57    createSortable(mainBoard, {
    58      group: 'project-column',
    59      draggable: '.project-column',
    60      handle: '.project-column-header',
    61      delayOnTouchOnly: true,
    62      delay: 500,
    63      onSort: async () => {
    64        boardColumns = mainBoard.getElementsByClassName('project-column');
    65  
    66        const columnSorting = {
    67          columns: Array.from(boardColumns, (column, i) => ({
    68            columnID: parseInt(column.getAttribute('data-id')),
    69            sorting: i,
    70          })),
    71        };
    72  
    73        try {
    74          await POST(mainBoard.getAttribute('data-url'), {
    75            data: columnSorting,
    76          });
    77        } catch (error) {
    78          console.error(error);
    79        }
    80      },
    81    });
    82  
    83    for (const boardColumn of boardColumns) {
    84      const boardCardList = boardColumn.getElementsByClassName('cards')[0];
    85      createSortable(boardCardList, {
    86        group: 'shared',
    87        onAdd: moveIssue,
    88        onUpdate: moveIssue,
    89        delayOnTouchOnly: true,
    90        delay: 500,
    91      });
    92    }
    93  }
    94  
    95  export function initRepoProject() {
    96    if (!document.querySelector('.repository.projects')) {
    97      return;
    98    }
    99  
   100    const _promise = initRepoProjectSortable();
   101  
   102    for (const modal of document.getElementsByClassName('edit-project-column-modal')) {
   103      const projectHeader = modal.closest('.project-column-header');
   104      const projectTitleLabel = projectHeader?.querySelector('.project-column-title-label');
   105      const projectTitleInput = modal.querySelector('.project-column-title-input');
   106      const projectColorInput = modal.querySelector('#new_project_column_color');
   107      const boardColumn = modal.closest('.project-column');
   108      modal.querySelector('.edit-project-column-button')?.addEventListener('click', async function (e) {
   109        e.preventDefault();
   110        try {
   111          await PUT(this.getAttribute('data-url'), {
   112            data: {
   113              title: projectTitleInput?.value,
   114              color: projectColorInput?.value,
   115            },
   116          });
   117        } catch (error) {
   118          console.error(error);
   119        } finally {
   120          projectTitleLabel.textContent = projectTitleInput?.value;
   121          projectTitleInput.closest('form')?.classList.remove('dirty');
   122          const dividers = boardColumn.querySelectorAll(':scope > .divider');
   123          if (projectColorInput.value) {
   124            const color = contrastColor(projectColorInput.value);
   125            boardColumn.style.setProperty('background', projectColorInput.value, 'important');
   126            boardColumn.style.setProperty('color', color, 'important');
   127            for (const divider of dividers) {
   128              divider.style.setProperty('color', color);
   129            }
   130          } else {
   131            boardColumn.style.removeProperty('background');
   132            boardColumn.style.removeProperty('color');
   133            for (const divider of dividers) {
   134              divider.style.removeProperty('color');
   135            }
   136          }
   137          $('.ui.modal').modal('hide');
   138        }
   139      });
   140    }
   141  
   142    $('.default-project-column-modal').each(function () {
   143      const $boardColumn = $(this).closest('.project-column');
   144      const $showButton = $($boardColumn).find('.default-project-column-show');
   145      const $commitButton = $(this).find('.actions > .ok.button');
   146  
   147      $($commitButton).on('click', async (e) => {
   148        e.preventDefault();
   149  
   150        try {
   151          await POST($($showButton).data('url'));
   152        } catch (error) {
   153          console.error(error);
   154        } finally {
   155          window.location.reload();
   156        }
   157      });
   158    });
   159  
   160    $('.show-delete-project-column-modal').each(function () {
   161      const $deleteColumnModal = $(`${this.getAttribute('data-modal')}`);
   162      const $deleteColumnButton = $deleteColumnModal.find('.actions > .ok.button');
   163      const deleteUrl = this.getAttribute('data-url');
   164  
   165      $deleteColumnButton.on('click', async (e) => {
   166        e.preventDefault();
   167  
   168        try {
   169          await DELETE(deleteUrl);
   170        } catch (error) {
   171          console.error(error);
   172        } finally {
   173          window.location.reload();
   174        }
   175      });
   176    });
   177  
   178    $('#new_project_column_submit').on('click', (e) => {
   179      e.preventDefault();
   180      const $columnTitle = $('#new_project_column');
   181      const $projectColorInput = $('#new_project_column_color_picker');
   182      if (!$columnTitle.val()) {
   183        return;
   184      }
   185      const url = e.target.getAttribute('data-url');
   186      createNewColumn(url, $columnTitle, $projectColorInput);
   187    });
   188  }