Show More
@@ -252,7 +252,7 b' But please check this code' | |||
|
252 | 252 | var comment = $('#comment-'+commentId); |
|
253 | 253 | var commentData = comment.data(); |
|
254 | 254 | if (commentData.commentInline) { |
|
255 | this.createComment(comment, commentId) | |
|
255 | this.createComment(comment, f_path, line_no, commentId) | |
|
256 | 256 | } else { |
|
257 | 257 | Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId) |
|
258 | 258 | } |
@@ -383,6 +383,9 b' class RepoCommitsView(RepoAppView):' | |||
|
383 | 383 | text = self.request.POST.get('text') |
|
384 | 384 | comment_type = self.request.POST.get('comment_type') |
|
385 | 385 | resolves_comment_id = self.request.POST.get('resolves_comment_id', None) |
|
386 | f_path = self.request.POST.get('f_path') | |
|
387 | line_no = self.request.POST.get('line') | |
|
388 | target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path))) | |
|
386 | 389 | |
|
387 | 390 | if status: |
|
388 | 391 | text = text or (_('Status change %(transition_icon)s %(status)s') |
@@ -404,8 +407,8 b' class RepoCommitsView(RepoAppView):' | |||
|
404 | 407 | repo=self.db_repo.repo_id, |
|
405 | 408 | user=self._rhodecode_db_user.user_id, |
|
406 | 409 | commit_id=current_id, |
|
407 |
f_path= |
|
|
408 |
line_no= |
|
|
410 | f_path=f_path, | |
|
411 | line_no=line_no, | |
|
409 | 412 | status_change=(ChangesetStatus.get_status_lbl(status) |
|
410 | 413 | if status else None), |
|
411 | 414 | status_change_type=status, |
@@ -447,19 +450,20 b' class RepoCommitsView(RepoAppView):' | |||
|
447 | 450 | # finalize, commit and redirect |
|
448 | 451 | Session().commit() |
|
449 | 452 | |
|
450 | data = { | |
|
451 | 'target_id': h.safeid(h.safe_unicode( | |
|
452 | self.request.POST.get('f_path'))), | |
|
453 | } | |
|
453 | data = {} | |
|
454 | 454 | if comment: |
|
455 | comment_id = comment.comment_id | |
|
456 | data[comment_id] = { | |
|
457 | 'target_id': target_elem_id | |
|
458 | } | |
|
455 | 459 | c.co = comment |
|
456 | 460 | c.at_version_num = 0 |
|
457 | 461 | rendered_comment = render( |
|
458 | 462 | 'rhodecode:templates/changeset/changeset_comment_block.mako', |
|
459 | 463 | self._get_template_context(c), self.request) |
|
460 | 464 | |
|
461 | data.update(comment.get_dict()) | |
|
462 | data.update({'rendered_text': rendered_comment}) | |
|
465 | data[comment_id].update(comment.get_dict()) | |
|
466 | data[comment_id].update({'rendered_text': rendered_comment}) | |
|
463 | 467 | |
|
464 | 468 | comment_broadcast_channel = channelstream.comment_channel( |
|
465 | 469 | self.db_repo_name, commit_obj=commit) |
@@ -983,8 +983,9 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
983 | 983 | } |
|
984 | 984 | return data |
|
985 | 985 | |
|
986 | def _get_existing_ids(self, post_data): | |
|
987 | return filter(lambda e: e, map(safe_int, aslist(post_data.get('comments'), ','))) | |
|
986 | @classmethod | |
|
987 | def get_comment_ids(cls, post_data): | |
|
988 | return filter(lambda e: e > 0, map(safe_int, aslist(post_data.get('comments'), ','))) | |
|
988 | 989 | |
|
989 | 990 | @LoginRequired() |
|
990 | 991 | @NotAnonymous() |
@@ -1022,7 +1023,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1022 | 1023 | self.register_comments_vars(c, pull_request_latest, versions, include_drafts=False) |
|
1023 | 1024 | all_comments = c.inline_comments_flat + c.comments |
|
1024 | 1025 | |
|
1025 |
existing_ids = self. |
|
|
1026 | existing_ids = self.get_comment_ids(self.request.POST) | |
|
1026 | 1027 | return _render('comments_table', all_comments, len(all_comments), |
|
1027 | 1028 | existing_ids=existing_ids) |
|
1028 | 1029 | |
@@ -1064,7 +1065,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1064 | 1065 | .get_pull_request_resolved_todos(pull_request, include_drafts=False) |
|
1065 | 1066 | |
|
1066 | 1067 | all_comments = c.unresolved_comments + c.resolved_comments |
|
1067 |
existing_ids = self. |
|
|
1068 | existing_ids = self.get_comment_ids(self.request.POST) | |
|
1068 | 1069 | return _render('comments_table', all_comments, len(c.unresolved_comments), |
|
1069 | 1070 | todo_comments=True, existing_ids=existing_ids) |
|
1070 | 1071 | |
@@ -1518,6 +1519,150 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1518 | 1519 | self._rhodecode_user) |
|
1519 | 1520 | raise HTTPNotFound() |
|
1520 | 1521 | |
|
1522 | def _pull_request_comments_create(self, pull_request, comments): | |
|
1523 | _ = self.request.translate | |
|
1524 | data = {} | |
|
1525 | pull_request_id = pull_request.pull_request_id | |
|
1526 | if not comments: | |
|
1527 | return | |
|
1528 | ||
|
1529 | all_drafts = len([x for x in comments if str2bool(x['is_draft'])]) == len(comments) | |
|
1530 | ||
|
1531 | for entry in comments: | |
|
1532 | c = self.load_default_context() | |
|
1533 | comment_type = entry['comment_type'] | |
|
1534 | text = entry['text'] | |
|
1535 | status = entry['status'] | |
|
1536 | is_draft = str2bool(entry['is_draft']) | |
|
1537 | resolves_comment_id = entry['resolves_comment_id'] | |
|
1538 | close_pull_request = entry['close_pull_request'] | |
|
1539 | f_path = entry['f_path'] | |
|
1540 | line_no = entry['line'] | |
|
1541 | target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path))) | |
|
1542 | ||
|
1543 | # the logic here should work like following, if we submit close | |
|
1544 | # pr comment, use `close_pull_request_with_comment` function | |
|
1545 | # else handle regular comment logic | |
|
1546 | ||
|
1547 | if close_pull_request: | |
|
1548 | # only owner or admin or person with write permissions | |
|
1549 | allowed_to_close = PullRequestModel().check_user_update( | |
|
1550 | pull_request, self._rhodecode_user) | |
|
1551 | if not allowed_to_close: | |
|
1552 | log.debug('comment: forbidden because not allowed to close ' | |
|
1553 | 'pull request %s', pull_request_id) | |
|
1554 | raise HTTPForbidden() | |
|
1555 | ||
|
1556 | # This also triggers `review_status_change` | |
|
1557 | comment, status = PullRequestModel().close_pull_request_with_comment( | |
|
1558 | pull_request, self._rhodecode_user, self.db_repo, message=text, | |
|
1559 | auth_user=self._rhodecode_user) | |
|
1560 | Session().flush() | |
|
1561 | is_inline = comment.is_inline | |
|
1562 | ||
|
1563 | PullRequestModel().trigger_pull_request_hook( | |
|
1564 | pull_request, self._rhodecode_user, 'comment', | |
|
1565 | data={'comment': comment}) | |
|
1566 | ||
|
1567 | else: | |
|
1568 | # regular comment case, could be inline, or one with status. | |
|
1569 | # for that one we check also permissions | |
|
1570 | # Additionally ENSURE if somehow draft is sent we're then unable to change status | |
|
1571 | allowed_to_change_status = PullRequestModel().check_user_change_status( | |
|
1572 | pull_request, self._rhodecode_user) and not is_draft | |
|
1573 | ||
|
1574 | if status and allowed_to_change_status: | |
|
1575 | message = (_('Status change %(transition_icon)s %(status)s') | |
|
1576 | % {'transition_icon': '>', | |
|
1577 | 'status': ChangesetStatus.get_status_lbl(status)}) | |
|
1578 | text = text or message | |
|
1579 | ||
|
1580 | comment = CommentsModel().create( | |
|
1581 | text=text, | |
|
1582 | repo=self.db_repo.repo_id, | |
|
1583 | user=self._rhodecode_user.user_id, | |
|
1584 | pull_request=pull_request, | |
|
1585 | f_path=f_path, | |
|
1586 | line_no=line_no, | |
|
1587 | status_change=(ChangesetStatus.get_status_lbl(status) | |
|
1588 | if status and allowed_to_change_status else None), | |
|
1589 | status_change_type=(status | |
|
1590 | if status and allowed_to_change_status else None), | |
|
1591 | comment_type=comment_type, | |
|
1592 | is_draft=is_draft, | |
|
1593 | resolves_comment_id=resolves_comment_id, | |
|
1594 | auth_user=self._rhodecode_user, | |
|
1595 | send_email=not is_draft, # skip notification for draft comments | |
|
1596 | ) | |
|
1597 | is_inline = comment.is_inline | |
|
1598 | ||
|
1599 | if allowed_to_change_status: | |
|
1600 | # calculate old status before we change it | |
|
1601 | old_calculated_status = pull_request.calculated_review_status() | |
|
1602 | ||
|
1603 | # get status if set ! | |
|
1604 | if status: | |
|
1605 | ChangesetStatusModel().set_status( | |
|
1606 | self.db_repo.repo_id, | |
|
1607 | status, | |
|
1608 | self._rhodecode_user.user_id, | |
|
1609 | comment, | |
|
1610 | pull_request=pull_request | |
|
1611 | ) | |
|
1612 | ||
|
1613 | Session().flush() | |
|
1614 | # this is somehow required to get access to some relationship | |
|
1615 | # loaded on comment | |
|
1616 | Session().refresh(comment) | |
|
1617 | ||
|
1618 | PullRequestModel().trigger_pull_request_hook( | |
|
1619 | pull_request, self._rhodecode_user, 'comment', | |
|
1620 | data={'comment': comment}) | |
|
1621 | ||
|
1622 | # we now calculate the status of pull request, and based on that | |
|
1623 | # calculation we set the commits status | |
|
1624 | calculated_status = pull_request.calculated_review_status() | |
|
1625 | if old_calculated_status != calculated_status: | |
|
1626 | PullRequestModel().trigger_pull_request_hook( | |
|
1627 | pull_request, self._rhodecode_user, 'review_status_change', | |
|
1628 | data={'status': calculated_status}) | |
|
1629 | ||
|
1630 | comment_id = comment.comment_id | |
|
1631 | data[comment_id] = { | |
|
1632 | 'target_id': target_elem_id | |
|
1633 | } | |
|
1634 | Session().flush() | |
|
1635 | ||
|
1636 | c.co = comment | |
|
1637 | c.at_version_num = None | |
|
1638 | c.is_new = True | |
|
1639 | rendered_comment = render( | |
|
1640 | 'rhodecode:templates/changeset/changeset_comment_block.mako', | |
|
1641 | self._get_template_context(c), self.request) | |
|
1642 | ||
|
1643 | data[comment_id].update(comment.get_dict()) | |
|
1644 | data[comment_id].update({'rendered_text': rendered_comment}) | |
|
1645 | ||
|
1646 | Session().commit() | |
|
1647 | ||
|
1648 | # skip channelstream for draft comments | |
|
1649 | if all_drafts: | |
|
1650 | comment_broadcast_channel = channelstream.comment_channel( | |
|
1651 | self.db_repo_name, pull_request_obj=pull_request) | |
|
1652 | ||
|
1653 | comment_data = data | |
|
1654 | comment_type = 'inline' if is_inline else 'general' | |
|
1655 | if len(data) == 1: | |
|
1656 | msg = _('posted {} new {} comment').format(len(data), comment_type) | |
|
1657 | else: | |
|
1658 | msg = _('posted {} new {} comments').format(len(data), comment_type) | |
|
1659 | ||
|
1660 | channelstream.comment_channelstream_push( | |
|
1661 | self.request, comment_broadcast_channel, self._rhodecode_user, msg, | |
|
1662 | comment_data=comment_data) | |
|
1663 | ||
|
1664 | return data | |
|
1665 | ||
|
1521 | 1666 | @LoginRequired() |
|
1522 | 1667 | @NotAnonymous() |
|
1523 | 1668 | @HasRepoPermissionAnyDecorator( |
@@ -1529,9 +1674,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1529 | 1674 | def pull_request_comment_create(self): |
|
1530 | 1675 | _ = self.request.translate |
|
1531 | 1676 | |
|
1532 | pull_request = PullRequest.get_or_404( | |
|
1533 | self.request.matchdict['pull_request_id']) | |
|
1534 | pull_request_id = pull_request.pull_request_id | |
|
1677 | pull_request = PullRequest.get_or_404(self.request.matchdict['pull_request_id']) | |
|
1535 | 1678 | |
|
1536 | 1679 | if pull_request.is_closed(): |
|
1537 | 1680 | log.debug('comment: forbidden because pull request is closed') |
@@ -1543,130 +1686,17 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1543 | 1686 | log.debug('comment: forbidden because pull request is from forbidden repo') |
|
1544 | 1687 | raise HTTPForbidden() |
|
1545 | 1688 | |
|
1546 | c = self.load_default_context() | |
|
1547 | ||
|
1548 |
|
|
|
1549 |
|
|
|
1550 |
|
|
|
1551 | is_draft = str2bool(self.request.POST.get('draft')) | |
|
1552 | resolves_comment_id = self.request.POST.get('resolves_comment_id', None) | |
|
1553 |
|
|
|
1554 | ||
|
1555 | # the logic here should work like following, if we submit close | |
|
1556 | # pr comment, use `close_pull_request_with_comment` function | |
|
1557 | # else handle regular comment logic | |
|
1558 | ||
|
1559 | if close_pull_request: | |
|
1560 | # only owner or admin or person with write permissions | |
|
1561 | allowed_to_close = PullRequestModel().check_user_update( | |
|
1562 | pull_request, self._rhodecode_user) | |
|
1563 | if not allowed_to_close: | |
|
1564 | log.debug('comment: forbidden because not allowed to close ' | |
|
1565 | 'pull request %s', pull_request_id) | |
|
1566 | raise HTTPForbidden() | |
|
1567 | ||
|
1568 | # This also triggers `review_status_change` | |
|
1569 | comment, status = PullRequestModel().close_pull_request_with_comment( | |
|
1570 | pull_request, self._rhodecode_user, self.db_repo, message=text, | |
|
1571 | auth_user=self._rhodecode_user) | |
|
1572 | Session().flush() | |
|
1573 | is_inline = comment.is_inline | |
|
1574 | ||
|
1575 | PullRequestModel().trigger_pull_request_hook( | |
|
1576 | pull_request, self._rhodecode_user, 'comment', | |
|
1577 | data={'comment': comment}) | |
|
1578 | ||
|
1579 | else: | |
|
1580 | # regular comment case, could be inline, or one with status. | |
|
1581 | # for that one we check also permissions | |
|
1582 | # Additionally ENSURE if somehow draft is sent we're then unable to change status | |
|
1583 | allowed_to_change_status = PullRequestModel().check_user_change_status( | |
|
1584 | pull_request, self._rhodecode_user) and not is_draft | |
|
1585 | ||
|
1586 | if status and allowed_to_change_status: | |
|
1587 | message = (_('Status change %(transition_icon)s %(status)s') | |
|
1588 | % {'transition_icon': '>', | |
|
1589 | 'status': ChangesetStatus.get_status_lbl(status)}) | |
|
1590 | text = text or message | |
|
1591 | ||
|
1592 | comment = CommentsModel().create( | |
|
1593 | text=text, | |
|
1594 | repo=self.db_repo.repo_id, | |
|
1595 | user=self._rhodecode_user.user_id, | |
|
1596 | pull_request=pull_request, | |
|
1597 | f_path=self.request.POST.get('f_path'), | |
|
1598 | line_no=self.request.POST.get('line'), | |
|
1599 | status_change=(ChangesetStatus.get_status_lbl(status) | |
|
1600 | if status and allowed_to_change_status else None), | |
|
1601 | status_change_type=(status | |
|
1602 | if status and allowed_to_change_status else None), | |
|
1603 | comment_type=comment_type, | |
|
1604 | is_draft=is_draft, | |
|
1605 | resolves_comment_id=resolves_comment_id, | |
|
1606 | auth_user=self._rhodecode_user, | |
|
1607 | send_email=not is_draft, # skip notification for draft comments | |
|
1608 | ) | |
|
1609 | is_inline = comment.is_inline | |
|
1610 | ||
|
1611 | if allowed_to_change_status: | |
|
1612 | # calculate old status before we change it | |
|
1613 | old_calculated_status = pull_request.calculated_review_status() | |
|
1614 | ||
|
1615 | # get status if set ! | |
|
1616 | if status: | |
|
1617 | ChangesetStatusModel().set_status( | |
|
1618 | self.db_repo.repo_id, | |
|
1619 | status, | |
|
1620 | self._rhodecode_user.user_id, | |
|
1621 | comment, | |
|
1622 | pull_request=pull_request | |
|
1623 | ) | |
|
1624 | ||
|
1625 | Session().flush() | |
|
1626 | # this is somehow required to get access to some relationship | |
|
1627 | # loaded on comment | |
|
1628 | Session().refresh(comment) | |
|
1629 | ||
|
1630 | PullRequestModel().trigger_pull_request_hook( | |
|
1631 | pull_request, self._rhodecode_user, 'comment', | |
|
1632 | data={'comment': comment}) | |
|
1633 | ||
|
1634 | # we now calculate the status of pull request, and based on that | |
|
1635 | # calculation we set the commits status | |
|
1636 | calculated_status = pull_request.calculated_review_status() | |
|
1637 | if old_calculated_status != calculated_status: | |
|
1638 | PullRequestModel().trigger_pull_request_hook( | |
|
1639 | pull_request, self._rhodecode_user, 'review_status_change', | |
|
1640 | data={'status': calculated_status}) | |
|
1641 | ||
|
1642 | Session().commit() | |
|
1643 | ||
|
1644 | data = { | |
|
1645 | 'target_id': h.safeid(h.safe_unicode( | |
|
1646 | self.request.POST.get('f_path'))), | |
|
1689 | comment_data = { | |
|
1690 | 'comment_type': self.request.POST.get('comment_type'), | |
|
1691 | 'text': self.request.POST.get('text'), | |
|
1692 | 'status': self.request.POST.get('changeset_status', None), | |
|
1693 | 'is_draft': self.request.POST.get('draft'), | |
|
1694 | 'resolves_comment_id': self.request.POST.get('resolves_comment_id', None), | |
|
1695 | 'close_pull_request': self.request.POST.get('close_pull_request'), | |
|
1696 | 'f_path': self.request.POST.get('f_path'), | |
|
1697 | 'line': self.request.POST.get('line'), | |
|
1647 | 1698 | } |
|
1648 | ||
|
1649 | if comment: | |
|
1650 | c.co = comment | |
|
1651 | c.at_version_num = None | |
|
1652 | rendered_comment = render( | |
|
1653 | 'rhodecode:templates/changeset/changeset_comment_block.mako', | |
|
1654 | self._get_template_context(c), self.request) | |
|
1655 | ||
|
1656 | data.update(comment.get_dict()) | |
|
1657 | data.update({'rendered_text': rendered_comment}) | |
|
1658 | ||
|
1659 | # skip channelstream for draft comments | |
|
1660 | if not is_draft: | |
|
1661 | comment_broadcast_channel = channelstream.comment_channel( | |
|
1662 | self.db_repo_name, pull_request_obj=pull_request) | |
|
1663 | ||
|
1664 | comment_data = data | |
|
1665 | comment_type = 'inline' if is_inline else 'general' | |
|
1666 | channelstream.comment_channelstream_push( | |
|
1667 | self.request, comment_broadcast_channel, self._rhodecode_user, | |
|
1668 | _('posted a new {} comment').format(comment_type), | |
|
1669 | comment_data=comment_data) | |
|
1699 | data = self._pull_request_comments_create(pull_request, [comment_data]) | |
|
1670 | 1700 | |
|
1671 | 1701 | return data |
|
1672 | 1702 |
@@ -339,13 +339,12 b' def comment_channelstream_push(request, ' | |||
|
339 | 339 | |
|
340 | 340 | comment_data = kwargs.pop('comment_data', {}) |
|
341 | 341 | user_data = kwargs.pop('user_data', {}) |
|
342 |
comment_id = comment_data. |
|
|
342 | comment_id = comment_data.keys()[0] if comment_data else '' | |
|
343 | 343 | |
|
344 |
message = '<strong>{}</strong> {} #{} |
|
|
344 | message = '<strong>{}</strong> {} #{}'.format( | |
|
345 | 345 | user.username, |
|
346 | 346 | msg, |
|
347 | 347 | comment_id, |
|
348 | _reload_link(_('Reload page to see new comments')), | |
|
349 | 348 | ) |
|
350 | 349 | |
|
351 | 350 | message_obj = { |
@@ -1148,7 +1148,7 b' class DiffLimitExceeded(Exception):' | |||
|
1148 | 1148 | |
|
1149 | 1149 | # NOTE(marcink): if diffs.mako change, probably this |
|
1150 | 1150 | # needs a bump to next version |
|
1151 |
CURRENT_DIFF_VERSION = 'v |
|
|
1151 | CURRENT_DIFF_VERSION = 'v5' | |
|
1152 | 1152 | |
|
1153 | 1153 | |
|
1154 | 1154 | def _cleanup_cache_file(cached_diff_file): |
@@ -370,7 +370,7 b' input[type="button"] {' | |||
|
370 | 370 | color: @alert2; |
|
371 | 371 | |
|
372 | 372 | &:hover { |
|
373 | color: darken(@alert2,30%); | |
|
373 | color: darken(@alert2, 30%); | |
|
374 | 374 | } |
|
375 | 375 | |
|
376 | 376 | &:disabled { |
@@ -1002,7 +1002,7 b' input.filediff-collapse-state {' | |||
|
1002 | 1002 | .nav-chunk { |
|
1003 | 1003 | position: absolute; |
|
1004 | 1004 | right: 20px; |
|
1005 |
margin-top: -1 |
|
|
1005 | margin-top: -15px; | |
|
1006 | 1006 | } |
|
1007 | 1007 | |
|
1008 | 1008 | .nav-chunk.selected { |
@@ -4,7 +4,7 b'' | |||
|
4 | 4 | |
|
5 | 5 | |
|
6 | 6 | // Comments |
|
7 |
@comment-outdated-opacity: 0 |
|
|
7 | @comment-outdated-opacity: 1.0; | |
|
8 | 8 | |
|
9 | 9 | .comments { |
|
10 | 10 | width: 100%; |
@@ -64,32 +64,34 b' tr.inline-comments div {' | |||
|
64 | 64 | .comment-draft { |
|
65 | 65 | float: left; |
|
66 | 66 | margin-right: 10px; |
|
67 |
font-weight: |
|
|
68 |
color: @ |
|
|
67 | font-weight: 400; | |
|
68 | color: @color-draft; | |
|
69 | } | |
|
70 | ||
|
71 | .comment-new { | |
|
72 | float: left; | |
|
73 | margin-right: 10px; | |
|
74 | font-weight: 400; | |
|
75 | color: @color-new; | |
|
69 | 76 | } |
|
70 | 77 | |
|
71 | 78 | .comment-label { |
|
72 | 79 | float: left; |
|
73 | 80 | |
|
74 |
padding: 0 |
|
|
75 | margin: 2px 4px 0px 0px; | |
|
76 | display: inline-block; | |
|
81 | padding: 0 8px 0 0; | |
|
77 | 82 | min-height: 0; |
|
78 | 83 | |
|
79 | 84 | text-align: center; |
|
80 | 85 | font-size: 10px; |
|
81 | line-height: .8em; | |
|
82 | 86 | |
|
83 | 87 | font-family: @text-italic; |
|
84 | 88 | font-style: italic; |
|
85 | 89 | background: #fff none; |
|
86 | 90 | color: @grey3; |
|
87 | border: 1px solid @grey4; | |
|
88 | 91 | white-space: nowrap; |
|
89 | 92 | |
|
90 | 93 | text-transform: uppercase; |
|
91 | 94 | min-width: 50px; |
|
92 | border-radius: 4px; | |
|
93 | 95 | |
|
94 | 96 | &.todo { |
|
95 | 97 | color: @color5; |
@@ -277,64 +279,165 b' tr.inline-comments div {' | |||
|
277 | 279 | .comment-outdated { |
|
278 | 280 | opacity: @comment-outdated-opacity; |
|
279 | 281 | } |
|
282 | ||
|
283 | .comment-outdated-label { | |
|
284 | color: @grey3; | |
|
285 | padding-right: 4px; | |
|
286 | } | |
|
280 | 287 | } |
|
281 | 288 | |
|
282 | 289 | .inline-comments { |
|
283 | border-radius: @border-radius; | |
|
290 | ||
|
284 | 291 | .comment { |
|
285 | 292 | margin: 0; |
|
286 | border-radius: @border-radius; | |
|
287 | 293 | } |
|
294 | ||
|
288 | 295 | .comment-outdated { |
|
289 | 296 | opacity: @comment-outdated-opacity; |
|
290 | 297 | } |
|
291 | 298 | |
|
299 | .comment-outdated-label { | |
|
300 | color: @grey3; | |
|
301 | padding-right: 4px; | |
|
302 | } | |
|
303 | ||
|
292 | 304 | .comment-inline { |
|
305 | ||
|
306 | &:first-child { | |
|
307 | margin: 4px 4px 0 4px; | |
|
308 | border-top: 1px solid @grey5; | |
|
309 | border-bottom: 0 solid @grey5; | |
|
310 | border-left: 1px solid @grey5; | |
|
311 | border-right: 1px solid @grey5; | |
|
312 | .border-radius-top(4px); | |
|
313 | } | |
|
314 | ||
|
315 | &:only-child { | |
|
316 | margin: 4px 4px 0 4px; | |
|
317 | border-top: 1px solid @grey5; | |
|
318 | border-bottom: 0 solid @grey5; | |
|
319 | border-left: 1px solid @grey5; | |
|
320 | border-right: 1px solid @grey5; | |
|
321 | .border-radius-top(4px); | |
|
322 | } | |
|
323 | ||
|
293 | 324 | background: white; |
|
294 | 325 | padding: @comment-padding @comment-padding; |
|
295 | border: @comment-padding solid @grey6; | |
|
326 | margin: 0 4px 0 4px; | |
|
327 | border-top: 0 solid @grey5; | |
|
328 | border-bottom: 0 solid @grey5; | |
|
329 | border-left: 1px solid @grey5; | |
|
330 | border-right: 1px solid @grey5; | |
|
296 | 331 | |
|
297 | 332 | .text { |
|
298 | 333 | border: none; |
|
299 | 334 | } |
|
335 | ||
|
300 | 336 | .meta { |
|
301 | 337 | border-bottom: 1px solid @grey6; |
|
302 | 338 | margin: -5px 0px; |
|
303 | 339 | line-height: 24px; |
|
304 | 340 | } |
|
341 | ||
|
305 | 342 | } |
|
306 | 343 | .comment-selected { |
|
307 | 344 | border-left: 6px solid @comment-highlight-color; |
|
308 | 345 | } |
|
346 | ||
|
347 | .comment-inline-form-open { | |
|
348 | display: block !important; | |
|
349 | } | |
|
350 | ||
|
309 | 351 | .comment-inline-form { |
|
310 | padding: @comment-padding; | |
|
311 | 352 | display: none; |
|
312 | 353 | } |
|
313 | .cb-comment-add-button { | |
|
314 | margin: @comment-padding; | |
|
354 | ||
|
355 | .comment-inline-form-edit { | |
|
356 | padding: 0; | |
|
357 | margin: 0px 4px 2px 4px; | |
|
358 | } | |
|
359 | ||
|
360 | .reply-thread-container { | |
|
361 | display: table; | |
|
362 | width: 100%; | |
|
363 | padding: 0px 4px 4px 4px; | |
|
364 | } | |
|
365 | ||
|
366 | .reply-thread-container-wrapper { | |
|
367 | margin: 0 4px 4px 4px; | |
|
368 | border-top: 0 solid @grey5; | |
|
369 | border-bottom: 1px solid @grey5; | |
|
370 | border-left: 1px solid @grey5; | |
|
371 | border-right: 1px solid @grey5; | |
|
372 | .border-radius-bottom(4px); | |
|
373 | } | |
|
374 | ||
|
375 | .reply-thread-gravatar { | |
|
376 | display: table-cell; | |
|
377 | width: 24px; | |
|
378 | height: 24px; | |
|
379 | padding-top: 10px; | |
|
380 | padding-left: 10px; | |
|
381 | background-color: #eeeeee; | |
|
382 | vertical-align: top; | |
|
315 | 383 | } |
|
316 | /* hide add comment button when form is open */ | |
|
384 | ||
|
385 | .reply-thread-reply-button { | |
|
386 | display: table-cell; | |
|
387 | width: 100%; | |
|
388 | height: 33px; | |
|
389 | padding: 3px 8px; | |
|
390 | margin-left: 8px; | |
|
391 | background-color: #eeeeee; | |
|
392 | } | |
|
393 | ||
|
394 | .reply-thread-reply-button .cb-comment-add-button { | |
|
395 | border-radius: 4px; | |
|
396 | width: 100%; | |
|
397 | padding: 6px 2px; | |
|
398 | text-align: left; | |
|
399 | cursor: text; | |
|
400 | color: @grey3; | |
|
401 | } | |
|
402 | .reply-thread-reply-button .cb-comment-add-button:hover { | |
|
403 | background-color: white; | |
|
404 | color: @grey2; | |
|
405 | } | |
|
406 | ||
|
407 | .reply-thread-last { | |
|
408 | display: table-cell; | |
|
409 | width: 10px; | |
|
410 | } | |
|
411 | ||
|
412 | /* Hide reply box when it's a first element, | |
|
413 | can happen when drafts are saved but not shown to specific user, | |
|
414 | or there are outdated comments hidden | |
|
415 | */ | |
|
416 | .reply-thread-container-wrapper:first-child:not(.comment-form-active) { | |
|
417 | display: none; | |
|
418 | } | |
|
419 | ||
|
420 | .reply-thread-container-wrapper.comment-outdated { | |
|
421 | display: none | |
|
422 | } | |
|
423 | ||
|
424 | /* hide add comment button when form is open */ | |
|
317 | 425 | .comment-inline-form-open ~ .cb-comment-add-button { |
|
318 | 426 | display: none; |
|
319 | 427 | } |
|
320 | .comment-inline-form-open { | |
|
321 | display: block; | |
|
322 | } | |
|
323 | /* hide add comment button when form but no comments */ | |
|
324 | .comment-inline-form:first-child + .cb-comment-add-button { | |
|
325 | display: none; | |
|
326 | } | |
|
327 | /* hide add comment button when no comments or form */ | |
|
328 | .cb-comment-add-button:first-child { | |
|
329 | display: none; | |
|
330 | } | |
|
428 | ||
|
331 | 429 | /* hide add comment button when only comment is being deleted */ |
|
332 | 430 | .comment-deleting:first-child + .cb-comment-add-button { |
|
333 | 431 | display: none; |
|
334 | 432 | } |
|
433 | ||
|
434 | /* hide add comment button when form but no comments */ | |
|
435 | .comment-inline-form:first-child + .cb-comment-add-button { | |
|
436 | display: none; | |
|
437 | } | |
|
438 | ||
|
335 | 439 | } |
|
336 | 440 | |
|
337 | ||
|
338 | 441 | .show-outdated-comments { |
|
339 | 442 | display: inline; |
|
340 | 443 | color: @rcblue; |
@@ -387,23 +490,40 b' form.comment-form {' | |||
|
387 | 490 | } |
|
388 | 491 | |
|
389 | 492 | .comment-footer { |
|
390 | position: relative; | |
|
493 | display: table; | |
|
391 | 494 | width: 100%; |
|
392 |
|
|
|
495 | height: 42px; | |
|
393 | 496 | |
|
394 |
.status |
|
|
497 | .comment-status-box, | |
|
395 | 498 | .cancel-button { |
|
396 | float: left; | |
|
397 | 499 | display: inline-block; |
|
398 | 500 | } |
|
399 | 501 | |
|
400 |
.status |
|
|
502 | .comment-status-box { | |
|
401 | 503 | margin-left: 10px; |
|
402 | 504 | } |
|
403 | 505 | |
|
404 | 506 | .action-buttons { |
|
405 |
|
|
|
406 | display: inline-block; | |
|
507 | display: table-cell; | |
|
508 | padding: 5px 0 5px 2px; | |
|
509 | } | |
|
510 | ||
|
511 | .toolbar-text { | |
|
512 | height: 42px; | |
|
513 | display: table-cell; | |
|
514 | vertical-align: bottom; | |
|
515 | font-size: 11px; | |
|
516 | color: @grey4; | |
|
517 | text-align: right; | |
|
518 | ||
|
519 | a { | |
|
520 | color: @grey4; | |
|
521 | } | |
|
522 | ||
|
523 | p { | |
|
524 | padding: 0; | |
|
525 | margin: 0; | |
|
526 | } | |
|
407 | 527 | } |
|
408 | 528 | |
|
409 | 529 | .action-buttons-extra { |
@@ -434,10 +554,6 b' form.comment-form {' | |||
|
434 | 554 | margin-right: 0; |
|
435 | 555 | } |
|
436 | 556 | |
|
437 | .comment-footer { | |
|
438 | margin-bottom: 50px; | |
|
439 | margin-top: 10px; | |
|
440 | } | |
|
441 | 557 | } |
|
442 | 558 | |
|
443 | 559 | |
@@ -489,8 +605,8 b' form.comment-form {' | |||
|
489 | 605 | .injected_diff .comment-inline-form, |
|
490 | 606 | .comment-inline-form { |
|
491 | 607 | background-color: white; |
|
492 |
margin-top: |
|
|
493 |
margin-bottom: |
|
|
608 | margin-top: 4px; | |
|
609 | margin-bottom: 10px; | |
|
494 | 610 | } |
|
495 | 611 | |
|
496 | 612 | .inline-form { |
@@ -526,9 +642,6 b' form.comment-form {' | |||
|
526 | 642 | margin: 0px; |
|
527 | 643 | } |
|
528 | 644 | |
|
529 | .comment-inline-form .comment-footer { | |
|
530 | margin: 10px 0px 0px 0px; | |
|
531 | } | |
|
532 | 645 | |
|
533 | 646 | .hide-inline-form-button { |
|
534 | 647 | margin-left: 5px; |
@@ -554,6 +667,7 b' comment-area-text {' | |||
|
554 | 667 | |
|
555 | 668 | .comment-area-header { |
|
556 | 669 | height: 35px; |
|
670 | border-bottom: 1px solid @grey5; | |
|
557 | 671 | } |
|
558 | 672 | |
|
559 | 673 | .comment-area-header .nav-links { |
@@ -561,6 +675,7 b' comment-area-text {' | |||
|
561 | 675 | flex-flow: row wrap; |
|
562 | 676 | -webkit-flex-flow: row wrap; |
|
563 | 677 | width: 100%; |
|
678 | border: none; | |
|
564 | 679 | } |
|
565 | 680 | |
|
566 | 681 | .comment-area-footer { |
@@ -629,14 +744,3 b' comment-area-text {' | |||
|
629 | 744 | border-bottom: 2px solid transparent; |
|
630 | 745 | } |
|
631 | 746 | |
|
632 | .toolbar-text { | |
|
633 | float: right; | |
|
634 | font-size: 11px; | |
|
635 | color: @grey4; | |
|
636 | text-align: right; | |
|
637 | ||
|
638 | a { | |
|
639 | color: @grey4; | |
|
640 | } | |
|
641 | } | |
|
642 |
@@ -3212,7 +3212,12 b' details:not([open]) > :not(summary) {' | |||
|
3212 | 3212 | |
|
3213 | 3213 | .sidebar-element { |
|
3214 | 3214 | margin-top: 20px; |
|
3215 | } | |
|
3215 | ||
|
3216 | .icon-draft { | |
|
3217 | color: @color-draft | |
|
3218 | } | |
|
3219 | } | |
|
3220 | ||
|
3216 | 3221 | |
|
3217 | 3222 | .right-sidebar-collapsed-state { |
|
3218 | 3223 | display: flex; |
@@ -3235,5 +3240,4 b' details:not([open]) > :not(summary) {' | |||
|
3235 | 3240 | |
|
3236 | 3241 | .old-comments-marker td { |
|
3237 | 3242 | padding-top: 15px; |
|
3238 | border-bottom: 1px solid @grey5; | |
|
3239 | } | |
|
3243 | } |
@@ -47,6 +47,8 b'' | |||
|
47 | 47 | |
|
48 | 48 | // Highlight color for lines and colors |
|
49 | 49 | @comment-highlight-color: #ffd887; |
|
50 | @color-draft: darken(@alert3, 30%); | |
|
51 | @color-new: darken(@alert1, 5%); | |
|
50 | 52 | |
|
51 | 53 | // FONTS |
|
52 | 54 | @basefontsize: 13px; |
@@ -71,14 +71,20 b' export class RhodecodeApp extends Polyme' | |||
|
71 | 71 | if (elem) { |
|
72 | 72 | elem.handleNotification(data); |
|
73 | 73 | } |
|
74 | ||
|
75 | 74 | } |
|
76 | 75 | |
|
77 | 76 | handleComment(data) { |
|
78 | if (data.message.comment_id) { | |
|
77 | ||
|
78 | if (data.message.comment_data.length !== 0) { | |
|
79 | 79 | if (window.refreshAllComments !== undefined) { |
|
80 | 80 | refreshAllComments() |
|
81 | 81 | } |
|
82 | var json_data = data.message.comment_data; | |
|
83 | ||
|
84 | if (window.commentsController !== undefined) { | |
|
85 | ||
|
86 | window.commentsController.attachComment(json_data) | |
|
87 | } | |
|
82 | 88 | } |
|
83 | 89 | } |
|
84 | 90 |
@@ -364,12 +364,15 b' var _submitAjaxPOST = function(url, post' | |||
|
364 | 364 | postData['close_pull_request'] = true; |
|
365 | 365 | } |
|
366 | 366 | |
|
367 |
|
|
|
367 | // submitSuccess for general comments | |
|
368 | var submitSuccessCallback = function(json_data) { | |
|
368 | 369 | // reload page if we change status for single commit. |
|
369 | 370 | if (status && self.commitId) { |
|
370 | 371 | location.reload(true); |
|
371 | 372 | } else { |
|
372 | $('#injected_page_comments').append(o.rendered_text); | |
|
373 | // inject newly created comments, json_data is {<comment_id>: {}} | |
|
374 | self.attachGeneralComment(json_data) | |
|
375 | ||
|
373 | 376 | self.resetCommentFormState(); |
|
374 | 377 | timeagoActivate(); |
|
375 | 378 | tooltipActivate(); |
@@ -565,26 +568,6 b' var CommentsController = function() {' | |||
|
565 | 568 | var mainComment = '#text'; |
|
566 | 569 | var self = this; |
|
567 | 570 | |
|
568 | this.cancelComment = function (node) { | |
|
569 | var $node = $(node); | |
|
570 | var edit = $(this).attr('edit'); | |
|
571 | if (edit) { | |
|
572 | var $general_comments = null; | |
|
573 | var $inline_comments = $node.closest('div.inline-comments'); | |
|
574 | if (!$inline_comments.length) { | |
|
575 | $general_comments = $('#comments'); | |
|
576 | var $comment = $general_comments.parent().find('div.comment:hidden'); | |
|
577 | // show hidden general comment form | |
|
578 | $('#cb-comment-general-form-placeholder').show(); | |
|
579 | } else { | |
|
580 | var $comment = $inline_comments.find('div.comment:hidden'); | |
|
581 | } | |
|
582 | $comment.show(); | |
|
583 | } | |
|
584 | $node.closest('.comment-inline-form').remove(); | |
|
585 | return false; | |
|
586 | }; | |
|
587 | ||
|
588 | 571 | this.showVersion = function (comment_id, comment_history_id) { |
|
589 | 572 | |
|
590 | 573 | var historyViewUrl = pyroutes.url( |
@@ -682,6 +665,35 b' var CommentsController = function() {' | |||
|
682 | 665 | return self.scrollToComment(node, -1, true); |
|
683 | 666 | }; |
|
684 | 667 | |
|
668 | this.cancelComment = function (node) { | |
|
669 | var $node = $(node); | |
|
670 | var edit = $(this).attr('edit'); | |
|
671 | var $inlineComments = $node.closest('div.inline-comments'); | |
|
672 | ||
|
673 | if (edit) { | |
|
674 | var $general_comments = null; | |
|
675 | if (!$inlineComments.length) { | |
|
676 | $general_comments = $('#comments'); | |
|
677 | var $comment = $general_comments.parent().find('div.comment:hidden'); | |
|
678 | // show hidden general comment form | |
|
679 | $('#cb-comment-general-form-placeholder').show(); | |
|
680 | } else { | |
|
681 | var $comment = $inlineComments.find('div.comment:hidden'); | |
|
682 | } | |
|
683 | $comment.show(); | |
|
684 | } | |
|
685 | var $replyWrapper = $node.closest('.comment-inline-form').closest('.reply-thread-container-wrapper') | |
|
686 | $replyWrapper.removeClass('comment-form-active'); | |
|
687 | ||
|
688 | var lastComment = $inlineComments.find('.comment-inline').last(); | |
|
689 | if ($(lastComment).hasClass('comment-outdated')) { | |
|
690 | $replyWrapper.hide(); | |
|
691 | } | |
|
692 | ||
|
693 | $node.closest('.comment-inline-form').remove(); | |
|
694 | return false; | |
|
695 | }; | |
|
696 | ||
|
685 | 697 | this._deleteComment = function(node) { |
|
686 | 698 | var $node = $(node); |
|
687 | 699 | var $td = $node.closest('td'); |
@@ -751,7 +763,7 b' var CommentsController = function() {' | |||
|
751 | 763 | this.finalizeDrafts = function(commentIds) { |
|
752 | 764 | |
|
753 | 765 | SwalNoAnimation.fire({ |
|
754 | title: _ngettext('Submit {0} draft comment', 'Submit {0} draft comments', commentIds.length).format(commentIds.length), | |
|
766 | title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length), | |
|
755 | 767 | icon: 'warning', |
|
756 | 768 | showCancelButton: true, |
|
757 | 769 | confirmButtonText: _gettext('Yes, finalize drafts'), |
@@ -764,6 +776,7 b' var CommentsController = function() {' | |||
|
764 | 776 | }; |
|
765 | 777 | |
|
766 | 778 | this.toggleWideMode = function (node) { |
|
779 | ||
|
767 | 780 | if ($('#content').hasClass('wrapper')) { |
|
768 | 781 | $('#content').removeClass("wrapper"); |
|
769 | 782 | $('#content').addClass("wide-mode-wrapper"); |
@@ -778,16 +791,49 b' var CommentsController = function() {' | |||
|
778 | 791 | |
|
779 | 792 | }; |
|
780 | 793 | |
|
781 | this.toggleComments = function(node, show) { | |
|
794 | /** | |
|
795 | * Turn off/on all comments in file diff | |
|
796 | */ | |
|
797 | this.toggleDiffComments = function(node) { | |
|
798 | // Find closes filediff container | |
|
782 | 799 | var $filediff = $(node).closest('.filediff'); |
|
800 | if ($(node).hasClass('toggle-on')) { | |
|
801 | var show = false; | |
|
802 | } else if ($(node).hasClass('toggle-off')) { | |
|
803 | var show = true; | |
|
804 | } | |
|
805 | ||
|
806 | // Toggle each individual comment block, so we can un-toggle single ones | |
|
807 | $.each($filediff.find('.toggle-comment-action'), function(idx, val) { | |
|
808 | self.toggleLineComments($(val), show) | |
|
809 | }) | |
|
810 | ||
|
811 | // since we change the height of the diff container that has anchor points for upper | |
|
812 | // sticky header, we need to tell it to re-calculate those | |
|
813 | if (window.updateSticky !== undefined) { | |
|
814 | // potentially our comments change the active window size, so we | |
|
815 | // notify sticky elements | |
|
816 | updateSticky() | |
|
817 | } | |
|
818 | ||
|
819 | return false; | |
|
820 | } | |
|
821 | ||
|
822 | this.toggleLineComments = function(node, show) { | |
|
823 | ||
|
824 | var trElem = $(node).closest('tr') | |
|
825 | ||
|
783 | 826 | if (show === true) { |
|
784 | $filediff.removeClass('hide-comments'); | |
|
827 | // mark outdated comments as visible before the toggle; | |
|
828 | $(trElem).find('.comment-outdated').show(); | |
|
829 | $(trElem).removeClass('hide-line-comments'); | |
|
785 | 830 | } else if (show === false) { |
|
786 | $filediff.find('.hide-line-comments').removeClass('hide-line-comments'); | |
|
787 |
|
|
|
831 | $(trElem).find('.comment-outdated').hide(); | |
|
832 | $(trElem).addClass('hide-line-comments'); | |
|
788 | 833 | } else { |
|
789 | $filediff.find('.hide-line-comments').removeClass('hide-line-comments'); | |
|
790 | $filediff.toggleClass('hide-comments'); | |
|
834 | // mark outdated comments as visible before the toggle; | |
|
835 | $(trElem).find('.comment-outdated').show(); | |
|
836 | $(trElem).toggleClass('hide-line-comments'); | |
|
791 | 837 | } |
|
792 | 838 | |
|
793 | 839 | // since we change the height of the diff container that has anchor points for upper |
@@ -798,15 +844,6 b' var CommentsController = function() {' | |||
|
798 | 844 | updateSticky() |
|
799 | 845 | } |
|
800 | 846 | |
|
801 | return false; | |
|
802 | }; | |
|
803 | ||
|
804 | this.toggleLineComments = function(node) { | |
|
805 | self.toggleComments(node, true); | |
|
806 | var $node = $(node); | |
|
807 | // mark outdated comments as visible before the toggle; | |
|
808 | $(node.closest('tr')).find('.comment-outdated').show(); | |
|
809 | $node.closest('tr').toggleClass('hide-line-comments'); | |
|
810 | 847 | }; |
|
811 | 848 | |
|
812 | 849 | this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId, edit, comment_id){ |
@@ -960,64 +997,58 b' var CommentsController = function() {' | |||
|
960 | 997 | return commentForm; |
|
961 | 998 | }; |
|
962 | 999 | |
|
963 | this.editComment = function(node) { | |
|
1000 | this.editComment = function(node, line_no, f_path) { | |
|
1001 | self.edit = true; | |
|
964 | 1002 | var $node = $(node); |
|
1003 | var $td = $node.closest('td'); | |
|
1004 | ||
|
965 | 1005 | var $comment = $(node).closest('.comment'); |
|
966 | 1006 | var comment_id = $($comment).data('commentId'); |
|
967 | 1007 | var isDraft = $($comment).data('commentDraft'); |
|
968 |
var $ |
|
|
1008 | var $editForm = null | |
|
969 | 1009 | |
|
970 | 1010 | var $comments = $node.closest('div.inline-comments'); |
|
971 | 1011 | var $general_comments = null; |
|
972 | var lineno = null; | |
|
973 | 1012 | |
|
974 | 1013 | if($comments.length){ |
|
975 | 1014 | // inline comments setup |
|
976 |
$ |
|
|
977 | lineno = self.getLineNumber(node) | |
|
1015 | $editForm = $comments.find('.comment-inline-form'); | |
|
1016 | line_no = self.getLineNumber(node) | |
|
978 | 1017 | } |
|
979 | 1018 | else{ |
|
980 | 1019 | // general comments setup |
|
981 | 1020 | $comments = $('#comments'); |
|
982 |
$ |
|
|
983 | lineno = $comment[0].id | |
|
1021 | $editForm = $comments.find('.comment-inline-form'); | |
|
1022 | line_no = $comment[0].id | |
|
984 | 1023 | $('#cb-comment-general-form-placeholder').hide(); |
|
985 | 1024 | } |
|
986 | 1025 | |
|
987 | this.edit = true; | |
|
1026 | if ($editForm.length === 0) { | |
|
988 | 1027 | |
|
989 | if (!$form.length) { | |
|
990 | ||
|
1028 | // unhide all comments if they are hidden for a proper REPLY mode | |
|
991 | 1029 | var $filediff = $node.closest('.filediff'); |
|
992 | 1030 | $filediff.removeClass('hide-comments'); |
|
993 | var f_path = $filediff.attr('data-f-path'); | |
|
994 | ||
|
995 | // create a new HTML from template | |
|
996 | 1031 | |
|
997 | var tmpl = $('#cb-comment-inline-form-template').html(); | |
|
998 | tmpl = tmpl.format(escapeHtml(f_path), lineno); | |
|
999 | $form = $(tmpl); | |
|
1000 | $comment.after($form) | |
|
1032 | $editForm = self.createNewFormWrapper(f_path, line_no); | |
|
1033 | if(f_path && line_no) { | |
|
1034 | $editForm.addClass('comment-inline-form-edit') | |
|
1035 | } | |
|
1001 | 1036 | |
|
1002 | var _form = $($form[0]).find('form'); | |
|
1037 | $comment.after($editForm) | |
|
1038 | ||
|
1039 | var _form = $($editForm[0]).find('form'); | |
|
1003 | 1040 | var autocompleteActions = ['as_note',]; |
|
1004 | 1041 | var commentForm = this.createCommentForm( |
|
1005 | _form, lineno, '', autocompleteActions, resolvesCommentId, | |
|
1042 | _form, line_no, '', autocompleteActions, resolvesCommentId, | |
|
1006 | 1043 | this.edit, comment_id); |
|
1007 | 1044 | var old_comment_text_binary = $comment.attr('data-comment-text'); |
|
1008 | 1045 | var old_comment_text = b64DecodeUnicode(old_comment_text_binary); |
|
1009 | 1046 | commentForm.cm.setValue(old_comment_text); |
|
1010 | 1047 | $comment.hide(); |
|
1048 | tooltipActivate(); | |
|
1011 | 1049 | |
|
1012 | $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({ | |
|
1013 | form: _form, | |
|
1014 | parent: $comments, | |
|
1015 | lineno: lineno, | |
|
1016 | f_path: f_path} | |
|
1017 | ); | |
|
1018 | ||
|
1019 | // set a CUSTOM submit handler for inline comments. | |
|
1020 | commentForm.setHandleFormSubmit(function(o) { | |
|
1050 | // set a CUSTOM submit handler for inline comment edit action. | |
|
1051 | commentForm.setHandleFormSubmit(function(o) { | |
|
1021 | 1052 | var text = commentForm.cm.getValue(); |
|
1022 | 1053 | var commentType = commentForm.getCommentType(); |
|
1023 | 1054 | |
@@ -1048,7 +1079,7 b' var CommentsController = function() {' | |||
|
1048 | 1079 | var postData = { |
|
1049 | 1080 | 'text': text, |
|
1050 | 1081 | 'f_path': f_path, |
|
1051 | 'line': lineno, | |
|
1082 | 'line': line_no, | |
|
1052 | 1083 | 'comment_type': commentType, |
|
1053 | 1084 | 'draft': isDraft, |
|
1054 | 1085 | 'version': version, |
@@ -1056,7 +1087,7 b' var CommentsController = function() {' | |||
|
1056 | 1087 | }; |
|
1057 | 1088 | |
|
1058 | 1089 | var submitSuccessCallback = function(json_data) { |
|
1059 |
$ |
|
|
1090 | $editForm.remove(); | |
|
1060 | 1091 | $comment.show(); |
|
1061 | 1092 | var postData = { |
|
1062 | 1093 | 'text': text, |
@@ -1121,8 +1152,7 b' var CommentsController = function() {' | |||
|
1121 | 1152 | 'commit_id': templateContext.commit_data.commit_id}); |
|
1122 | 1153 | |
|
1123 | 1154 | _submitAjaxPOST( |
|
1124 | previewUrl, postData, successRenderCommit, | |
|
1125 | failRenderCommit | |
|
1155 | previewUrl, postData, successRenderCommit, failRenderCommit | |
|
1126 | 1156 | ); |
|
1127 | 1157 | |
|
1128 | 1158 | try { |
@@ -1178,49 +1208,103 b' var CommentsController = function() {' | |||
|
1178 | 1208 | }); |
|
1179 | 1209 | } |
|
1180 | 1210 | |
|
1181 |
$ |
|
|
1211 | $editForm.addClass('comment-inline-form-open'); | |
|
1182 | 1212 | }; |
|
1183 | 1213 | |
|
1184 |
this. |
|
|
1185 | var resolvesCommentId = resolutionComment || null; | |
|
1214 | this.attachComment = function(json_data) { | |
|
1215 | var self = this; | |
|
1216 | $.each(json_data, function(idx, val) { | |
|
1217 | var json_data_elem = [val] | |
|
1218 | var isInline = val.comment_f_path && val.comment_lineno | |
|
1219 | ||
|
1220 | if (isInline) { | |
|
1221 | self.attachInlineComment(json_data_elem) | |
|
1222 | } else { | |
|
1223 | self.attachGeneralComment(json_data_elem) | |
|
1224 | } | |
|
1225 | }) | |
|
1226 | ||
|
1227 | } | |
|
1228 | ||
|
1229 | this.attachGeneralComment = function(json_data) { | |
|
1230 | $.each(json_data, function(idx, val) { | |
|
1231 | $('#injected_page_comments').append(val.rendered_text); | |
|
1232 | }) | |
|
1233 | } | |
|
1234 | ||
|
1235 | this.attachInlineComment = function(json_data) { | |
|
1236 | ||
|
1237 | $.each(json_data, function (idx, val) { | |
|
1238 | var line_qry = '*[data-line-no="{0}"]'.format(val.line_no); | |
|
1239 | var html = val.rendered_text; | |
|
1240 | var $inlineComments = $('#' + val.target_id) | |
|
1241 | .find(line_qry) | |
|
1242 | .find('.inline-comments'); | |
|
1243 | ||
|
1244 | var lastComment = $inlineComments.find('.comment-inline').last(); | |
|
1245 | ||
|
1246 | if (lastComment.length === 0) { | |
|
1247 | // first comment, we append simply | |
|
1248 | $inlineComments.find('.reply-thread-container-wrapper').before(html); | |
|
1249 | } else { | |
|
1250 | $(lastComment).after(html) | |
|
1251 | } | |
|
1252 | ||
|
1253 | }) | |
|
1254 | ||
|
1255 | }; | |
|
1256 | ||
|
1257 | this.createNewFormWrapper = function(f_path, line_no) { | |
|
1258 | // create a new reply HTML form from template | |
|
1259 | var tmpl = $('#cb-comment-inline-form-template').html(); | |
|
1260 | tmpl = tmpl.format(escapeHtml(f_path), line_no); | |
|
1261 | return $(tmpl); | |
|
1262 | } | |
|
1263 | ||
|
1264 | this.createComment = function(node, f_path, line_no, resolutionComment) { | |
|
1265 | self.edit = false; | |
|
1186 | 1266 | var $node = $(node); |
|
1187 | 1267 | var $td = $node.closest('td'); |
|
1188 | var $form = $td.find('.comment-inline-form'); | |
|
1189 | this.edit = false; | |
|
1268 | var resolvesCommentId = resolutionComment || null; | |
|
1190 | 1269 | |
|
1191 | if (!$form.length) { | |
|
1270 | var $replyForm = $td.find('.comment-inline-form'); | |
|
1192 | 1271 | |
|
1193 | var $filediff = $node.closest('.filediff'); | |
|
1194 | $filediff.removeClass('hide-comments'); | |
|
1195 | var f_path = $filediff.attr('data-f-path'); | |
|
1196 | var lineno = self.getLineNumber(node); | |
|
1197 | // create a new HTML from template | |
|
1198 | var tmpl = $('#cb-comment-inline-form-template').html(); | |
|
1199 |
|
|
|
1200 | $form = $(tmpl); | |
|
1272 | // if form isn't existing, we're generating a new one and injecting it. | |
|
1273 | if ($replyForm.length === 0) { | |
|
1274 | ||
|
1275 | // unhide/expand all comments if they are hidden for a proper REPLY mode | |
|
1276 | self.toggleLineComments($node, true); | |
|
1277 | ||
|
1278 | $replyForm = self.createNewFormWrapper(f_path, line_no); | |
|
1201 | 1279 | |
|
1202 | 1280 | var $comments = $td.find('.inline-comments'); |
|
1203 | if (!$comments.length) { | |
|
1204 | $comments = $( | |
|
1205 | $('#cb-comments-inline-container-template').html()); | |
|
1206 | $td.append($comments); | |
|
1281 | ||
|
1282 | // There aren't any comments, we init the `.inline-comments` with `reply-thread-container` first | |
|
1283 | if ($comments.length===0) { | |
|
1284 | var replBtn = '<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, \'{0}\', \'{1}\', null)">Reply...</button>'.format(f_path, line_no) | |
|
1285 | var $reply_container = $('#cb-comments-inline-container-template') | |
|
1286 | $reply_container.find('button.cb-comment-add-button').replaceWith(replBtn); | |
|
1287 | $td.append($($reply_container).html()); | |
|
1207 | 1288 | } |
|
1208 | 1289 | |
|
1209 | $td.find('.cb-comment-add-button').before($form); | |
|
1290 | // default comment button exists, so we prepend the form for leaving initial comment | |
|
1291 | $td.find('.cb-comment-add-button').before($replyForm); | |
|
1292 | // set marker, that we have a open form | |
|
1293 | var $replyWrapper = $td.find('.reply-thread-container-wrapper') | |
|
1294 | $replyWrapper.addClass('comment-form-active'); | |
|
1210 | 1295 | |
|
1211 | var placeholderText = _gettext('Leave a comment on line {0}.').format(lineno); | |
|
1212 | var _form = $($form[0]).find('form'); | |
|
1296 | var lastComment = $comments.find('.comment-inline').last(); | |
|
1297 | if ($(lastComment).hasClass('comment-outdated')) { | |
|
1298 | $replyWrapper.show(); | |
|
1299 | } | |
|
1300 | ||
|
1301 | var _form = $($replyForm[0]).find('form'); | |
|
1213 | 1302 | var autocompleteActions = ['as_note', 'as_todo']; |
|
1214 | 1303 | var comment_id=null; |
|
1215 | var commentForm = this.createCommentForm( | |
|
1216 | _form, lineno, placeholderText, autocompleteActions, resolvesCommentId, this.edit, comment_id); | |
|
1217 | ||
|
1218 | $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({ | |
|
1219 | form: _form, | |
|
1220 | parent: $td[0], | |
|
1221 | lineno: lineno, | |
|
1222 | f_path: f_path} | |
|
1223 | ); | |
|
1304 | var placeholderText = _gettext('Leave a comment on file {0} line {1}.').format(f_path, line_no); | |
|
1305 | var commentForm = self.createCommentForm( | |
|
1306 | _form, line_no, placeholderText, autocompleteActions, resolvesCommentId, | |
|
1307 | self.edit, comment_id); | |
|
1224 | 1308 | |
|
1225 | 1309 | // set a CUSTOM submit handler for inline comments. |
|
1226 | 1310 | commentForm.setHandleFormSubmit(function(o) { |
@@ -1233,12 +1317,13 b' var CommentsController = function() {' | |||
|
1233 | 1317 | return; |
|
1234 | 1318 | } |
|
1235 | 1319 | |
|
1236 | if (lineno === undefined) { | |
|
1237 | alert('missing line !'); | |
|
1320 | if (line_no === undefined) { | |
|
1321 | alert('Error: unable to fetch line number for this inline comment !'); | |
|
1238 | 1322 | return; |
|
1239 | 1323 | } |
|
1324 | ||
|
1240 | 1325 | if (f_path === undefined) { |
|
1241 | alert('missing file path !'); | |
|
1326 | alert('Error: unable to fetch file path for this inline comment !'); | |
|
1242 | 1327 | return; |
|
1243 | 1328 | } |
|
1244 | 1329 | |
@@ -1249,7 +1334,7 b' var CommentsController = function() {' | |||
|
1249 | 1334 | var postData = { |
|
1250 | 1335 | 'text': text, |
|
1251 | 1336 | 'f_path': f_path, |
|
1252 | 'line': lineno, | |
|
1337 | 'line': line_no, | |
|
1253 | 1338 | 'comment_type': commentType, |
|
1254 | 1339 | 'draft': isDraft, |
|
1255 | 1340 | 'csrf_token': CSRF_TOKEN |
@@ -1258,32 +1343,32 b' var CommentsController = function() {' | |||
|
1258 | 1343 | postData['resolves_comment_id'] = resolvesCommentId; |
|
1259 | 1344 | } |
|
1260 | 1345 | |
|
1346 | // submitSuccess for inline commits | |
|
1261 | 1347 | var submitSuccessCallback = function(json_data) { |
|
1262 | $form.remove(); | |
|
1263 | try { | |
|
1264 | var html = json_data.rendered_text; | |
|
1265 | var lineno = json_data.line_no; | |
|
1266 | var target_id = json_data.target_id; | |
|
1348 | ||
|
1349 | $replyForm.remove(); | |
|
1350 | $td.find('.reply-thread-container-wrapper').removeClass('comment-form-active'); | |
|
1351 | ||
|
1352 | try { | |
|
1353 | ||
|
1354 | // inject newly created comments, json_data is {<comment_id>: {}} | |
|
1355 | self.attachInlineComment(json_data) | |
|
1267 | 1356 | |
|
1268 | $comments.find('.cb-comment-add-button').before(html); | |
|
1357 | //mark visually which comment was resolved | |
|
1358 | if (resolvesCommentId) { | |
|
1359 | commentForm.markCommentResolved(resolvesCommentId); | |
|
1360 | } | |
|
1269 | 1361 | |
|
1270 | //mark visually which comment was resolved | |
|
1271 | if (resolvesCommentId) { | |
|
1272 | commentForm.markCommentResolved(resolvesCommentId); | |
|
1362 | // run global callback on submit | |
|
1363 | commentForm.globalSubmitSuccessCallback({ | |
|
1364 | draft: isDraft, | |
|
1365 | comment_id: comment_id | |
|
1366 | }); | |
|
1367 | ||
|
1368 | } catch (e) { | |
|
1369 | console.error(e); | |
|
1273 | 1370 | } |
|
1274 | 1371 | |
|
1275 | // run global callback on submit | |
|
1276 | commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id}); | |
|
1277 | ||
|
1278 | } catch (e) { | |
|
1279 | console.error(e); | |
|
1280 | } | |
|
1281 | ||
|
1282 | // re trigger the linkification of next/prev navigation | |
|
1283 | linkifyComments($('.inline-comment-injected')); | |
|
1284 | timeagoActivate(); | |
|
1285 | tooltipActivate(); | |
|
1286 | ||
|
1287 | 1372 | if (window.updateSticky !== undefined) { |
|
1288 | 1373 | // potentially our comments change the active window size, so we |
|
1289 | 1374 | // notify sticky elements |
@@ -1297,19 +1382,27 b' var CommentsController = function() {' | |||
|
1297 | 1382 | |
|
1298 | 1383 | commentForm.setActionButtonsDisabled(false); |
|
1299 | 1384 | |
|
1385 | // re trigger the linkification of next/prev navigation | |
|
1386 | linkifyComments($('.inline-comment-injected')); | |
|
1387 | timeagoActivate(); | |
|
1388 | tooltipActivate(); | |
|
1300 | 1389 | }; |
|
1390 | ||
|
1301 | 1391 | var submitFailCallback = function(jqXHR, textStatus, errorThrown) { |
|
1302 | 1392 | var prefix = "Error while submitting comment.\n" |
|
1303 | 1393 | var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix); |
|
1304 | 1394 | ajaxErrorSwal(message); |
|
1305 | 1395 | commentForm.resetCommentFormState(text) |
|
1306 | 1396 | }; |
|
1397 | ||
|
1307 | 1398 | commentForm.submitAjaxPOST( |
|
1308 | 1399 | commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback); |
|
1309 | 1400 | }); |
|
1310 | 1401 | } |
|
1311 | 1402 | |
|
1312 | $form.addClass('comment-inline-form-open'); | |
|
1403 | // Finally "open" our reply form, since we know there are comments and we have the "attached" old form | |
|
1404 | $replyForm.addClass('comment-inline-form-open'); | |
|
1405 | tooltipActivate(); | |
|
1313 | 1406 | }; |
|
1314 | 1407 | |
|
1315 | 1408 | this.createResolutionComment = function(commentId){ |
@@ -1319,9 +1412,12 b' var CommentsController = function() {' | |||
|
1319 | 1412 | var comment = $('#comment-'+commentId); |
|
1320 | 1413 | var commentData = comment.data(); |
|
1321 | 1414 | if (commentData.commentInline) { |
|
1322 | this.createComment(comment, commentId) | |
|
1415 | var f_path = commentData.fPath; | |
|
1416 | var line_no = commentData.lineNo; | |
|
1417 | //TODO check this if we need to give f_path/line_no | |
|
1418 | this.createComment(comment, f_path, line_no, commentId) | |
|
1323 | 1419 | } else { |
|
1324 |
|
|
|
1420 | this.createGeneralComment('general', "$placeholder", commentId) | |
|
1325 | 1421 | } |
|
1326 | 1422 | |
|
1327 | 1423 | return false; |
@@ -1347,3 +1443,8 b' var CommentsController = function() {' | |||
|
1347 | 1443 | }; |
|
1348 | 1444 | |
|
1349 | 1445 | }; |
|
1446 | ||
|
1447 | window.commentHelp = function(renderer) { | |
|
1448 | var funcData = {'renderer': renderer} | |
|
1449 | return renderTemplate('commentHelpHovercard', funcData) | |
|
1450 | } No newline at end of file |
@@ -42,12 +42,22 b' window.toggleElement = function (elem, t' | |||
|
42 | 42 | var $elem = $(elem); |
|
43 | 43 | var $target = $(target); |
|
44 | 44 | |
|
45 | if ($target.is(':visible') || $target.length === 0) { | |
|
45 | if (target !== undefined) { | |
|
46 | var show = $target.is(':visible') || $target.length === 0; | |
|
47 | } else { | |
|
48 | var show = $elem.hasClass('toggle-off') | |
|
49 | } | |
|
50 | ||
|
51 | if (show) { | |
|
46 | 52 | $target.hide(); |
|
47 | 53 | $elem.html($elem.data('toggleOn')) |
|
54 | $elem.addClass('toggle-on') | |
|
55 | $elem.removeClass('toggle-off') | |
|
48 | 56 | } else { |
|
49 | 57 | $target.show(); |
|
50 | 58 | $elem.html($elem.data('toggleOff')) |
|
59 | $elem.addClass('toggle-off') | |
|
60 | $elem.removeClass('toggle-on') | |
|
51 | 61 | } |
|
52 | 62 | |
|
53 | 63 | return false |
@@ -1,7 +1,5 b'' | |||
|
1 | 1 | /__MAIN_APP__ - launched when rhodecode-app element is attached to DOM |
|
2 | 2 | /plugins/__REGISTER__ - launched after the onDomReady() code from rhodecode.js is executed |
|
3 | /ui/plugins/code/anchor_focus - launched when rc starts to scroll on load to anchor on PR/Codeview | |
|
4 | /ui/plugins/code/comment_form_built - launched when injectInlineForm() is executed and the form object is created | |
|
5 | 3 | /notifications - shows new event notifications |
|
6 | 4 | /connection_controller/subscribe - subscribes user to new channels |
|
7 | 5 | /connection_controller/presence - receives presence change messages |
@@ -1,4 +1,4 b'' | |||
|
1 | 1 | ## this is a dummy html file for partial rendering on server and sending |
|
2 | 2 | ## generated output via ajax after comment submit |
|
3 | 3 | <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/> |
|
4 | ${comment.comment_block(c.co, inline=c.co.is_inline)} | |
|
4 | ${comment.comment_block(c.co, inline=c.co.is_inline, is_new=c.is_new)} |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | %> |
|
11 | 11 | |
|
12 | 12 | |
|
13 | <%def name="comment_block(comment, inline=False, active_pattern_entries=None)"> | |
|
13 | <%def name="comment_block(comment, inline=False, active_pattern_entries=None, is_new=False)"> | |
|
14 | 14 | |
|
15 | 15 | <% |
|
16 | 16 | from rhodecode.model.comment import CommentsModel |
@@ -40,6 +40,7 b'' | |||
|
40 | 40 | data-comment-draft=${h.json.dumps(comment.draft)} |
|
41 | 41 | data-comment-renderer="${comment.renderer}" |
|
42 | 42 | data-comment-text="${comment.text | html_filters.base64,n}" |
|
43 | data-comment-f-path="${comment.f_path}" | |
|
43 | 44 | data-comment-line-no="${comment.line_no}" |
|
44 | 45 | data-comment-inline=${h.json.dumps(inline)} |
|
45 | 46 | style="${'display: none;' if outdated_at_ver else ''}"> |
@@ -47,8 +48,17 b'' | |||
|
47 | 48 | <div class="meta"> |
|
48 | 49 | <div class="comment-type-label"> |
|
49 | 50 | % if comment.draft: |
|
50 |
|
|
|
51 | <div class="tooltip comment-draft" title="${_('Draft comments are only visible to the author until submitted')}."> | |
|
52 | DRAFT | |
|
53 | </div> | |
|
51 | 54 | % endif |
|
55 | ||
|
56 | % if is_new: | |
|
57 | <div class="tooltip comment-new" title="${_('This comment was added while you browsed this page')}."> | |
|
58 | NEW | |
|
59 | </div> | |
|
60 | % endif | |
|
61 | ||
|
52 | 62 | <div class="comment-label ${comment.comment_type or 'note'}" id="comment-label-${comment.comment_id}"> |
|
53 | 63 | |
|
54 | 64 | ## TODO COMMENT |
@@ -176,7 +186,7 b'' | |||
|
176 | 186 | % if inline: |
|
177 | 187 | <a class="pr-version-inline" href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}"> |
|
178 | 188 | % if outdated_at_ver: |
|
179 |
<code class="tooltip pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}"> |
|
|
189 | <strong class="comment-outdated-label">outdated</strong> <code class="tooltip pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}">${'v{}'.format(comment_ver)}</code> | |
|
180 | 190 | <code class="action-divider">|</code> |
|
181 | 191 | % elif comment_ver: |
|
182 | 192 | <code class="tooltip pr-version-num" title="${_('Comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}">${'v{}'.format(comment_ver)}</code> |
@@ -222,12 +232,13 b'' | |||
|
222 | 232 | %if comment.immutable is False and (c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id): |
|
223 | 233 | <div class="dropdown-divider"></div> |
|
224 | 234 | <div class="dropdown-item"> |
|
225 | <a onclick="return Rhodecode.comments.editComment(this);" class="btn btn-link btn-sm edit-comment">${_('Edit')}</a> | |
|
235 | <a onclick="return Rhodecode.comments.editComment(this, '${comment.line_no}', '${comment.f_path}');" class="btn btn-link btn-sm edit-comment">${_('Edit')}</a> | |
|
226 | 236 | </div> |
|
227 | 237 | <div class="dropdown-item"> |
|
228 | 238 | <a onclick="return Rhodecode.comments.deleteComment(this);" class="btn btn-link btn-sm btn-danger delete-comment">${_('Delete')}</a> |
|
229 | 239 | </div> |
|
230 | % if comment.draft: | |
|
240 | ## Only available in EE edition | |
|
241 | % if comment.draft and c.rhodecode_edition_id == 'EE': | |
|
231 | 242 | <div class="dropdown-item"> |
|
232 | 243 | <a onclick="return Rhodecode.comments.finalizeDrafts([${comment.comment_id}]);" class="btn btn-link btn-sm finalize-draft-comment">${_('Submit draft')}</a> |
|
233 | 244 | </div> |
@@ -391,7 +402,7 b'' | |||
|
391 | 402 | |
|
392 | 403 | <div class="comment-area-write" style="display: block;"> |
|
393 | 404 | <div id="edit-container"> |
|
394 |
<div style="padding: |
|
|
405 | <div style="padding: 20px 0px 0px 0;"> | |
|
395 | 406 | ${_('You need to be logged in to leave comments.')} |
|
396 | 407 | <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a> |
|
397 | 408 | </div> |
@@ -450,7 +461,7 b'' | |||
|
450 | 461 | </div> |
|
451 | 462 | |
|
452 | 463 | <div class="comment-area-write" style="display: block;"> |
|
453 | <div id="edit-container_${lineno_id}"> | |
|
464 | <div id="edit-container_${lineno_id}" style="margin-top: -1px"> | |
|
454 | 465 | <textarea id="text_${lineno_id}" name="text" class="comment-block-ta ac-input"></textarea> |
|
455 | 466 | </div> |
|
456 | 467 | <div id="preview-container_${lineno_id}" class="clearfix" style="display: none;"> |
@@ -500,40 +511,47 b'' | |||
|
500 | 511 | <input class="btn btn-success comment-button-input submit-comment-action" id="save_${lineno_id}" name="save" type="submit" value="${_('Add comment')}" data-is-draft=false onclick="$(this).addClass('submitter')"> |
|
501 | 512 | |
|
502 | 513 | % if form_type == 'inline': |
|
503 | <input class="btn btn-warning comment-button-input submit-draft-action" id="save_draft_${lineno_id}" name="save_draft" type="submit" value="${_('Add draft')}" data-is-draft=true onclick="$(this).addClass('submitter')"> | |
|
514 | % if c.rhodecode_edition_id == 'EE': | |
|
515 | ## Disable the button for CE, the "real" validation is in the backend code anyway | |
|
516 | <input class="btn btn-warning comment-button-input submit-draft-action" id="save_draft_${lineno_id}" name="save_draft" type="submit" value="${_('Add draft')}" data-is-draft=true onclick="$(this).addClass('submitter')"> | |
|
517 | % else: | |
|
518 | <input class="tooltip btn btn-warning comment-button-input submit-draft-action disabled" type="submit" disabled="disabled" value="${_('Add draft')}" onclick="return false;" title="Draft comments only available in EE edition of RhodeCode"> | |
|
519 | % endif | |
|
520 | % endif | |
|
521 | ||
|
522 | % if review_statuses: | |
|
523 | <div class="comment-status-box"> | |
|
524 | <select id="change_status_${lineno_id}" name="changeset_status"> | |
|
525 | <option></option> ## Placeholder | |
|
526 | % for status, lbl in review_statuses: | |
|
527 | <option value="${status}" data-status="${status}">${lbl}</option> | |
|
528 | %if is_pull_request and change_status and status in ('approved', 'rejected'): | |
|
529 | <option value="${status}_closed" data-status="${status}">${lbl} & ${_('Closed')}</option> | |
|
530 | %endif | |
|
531 | % endfor | |
|
532 | </select> | |
|
533 | </div> | |
|
504 | 534 | % endif |
|
505 | 535 | |
|
506 | 536 | ## inline for has a file, and line-number together with cancel hide button. |
|
507 | 537 | % if form_type == 'inline': |
|
508 | 538 | <input type="hidden" name="f_path" value="{0}"> |
|
509 | 539 | <input type="hidden" name="line" value="${lineno_id}"> |
|
510 |
<button type="button" class=" |
|
|
540 | <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);"> | |
|
511 | 541 | <i class="icon-cancel-circled2"></i> |
|
512 | 542 | </button> |
|
513 | 543 | % endif |
|
514 | 544 | </div> |
|
515 | 545 |
|
|
516 | % if review_statuses: | |
|
517 | <div class="status_box"> | |
|
518 | <select id="change_status_${lineno_id}" name="changeset_status"> | |
|
519 | <option></option> ## Placeholder | |
|
520 | % for status, lbl in review_statuses: | |
|
521 | <option value="${status}" data-status="${status}">${lbl}</option> | |
|
522 | %if is_pull_request and change_status and status in ('approved', 'rejected'): | |
|
523 | <option value="${status}_closed" data-status="${status}">${lbl} & ${_('Closed')}</option> | |
|
524 | %endif | |
|
525 | % endfor | |
|
526 | </select> | |
|
527 | </div> | |
|
528 | % endif | |
|
529 | ||
|
530 | 546 | <div class="toolbar-text"> |
|
531 | 547 | <% renderer_url = '<a href="%s">%s</a>' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper()) %> |
|
532 |
${_(' |
|
|
533 | <span class="tooltip" title="${_('Use @username inside this text to send notification to this RhodeCode user')}">@mention</span> | |
|
534 | ${_('and')} | |
|
535 | <span class="tooltip" title="${_('Start typing with / for certain actions to be triggered via text box.')}">`/` autocomplete</span> | |
|
536 | ${_('actions supported.')} | |
|
548 | <p>${_('Styling with {} is supported.').format(renderer_url)|n} | |
|
549 | ||
|
550 | <i class="icon-info-circled tooltip-hovercard" | |
|
551 | data-hovercard-alt="ALT" | |
|
552 | data-hovercard-url="javascript:commentHelp('${c.visual.default_renderer.upper()}')" | |
|
553 | data-comment-json-b64='${h.b64(h.json.dumps({}))}'></i> | |
|
554 | </p> | |
|
537 | 555 | </div> |
|
538 | 556 | </div> |
|
539 | 557 |
@@ -1,3 +1,4 b'' | |||
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
|
1 | 2 | <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/> |
|
2 | 3 | |
|
3 | 4 | <%def name="diff_line_anchor(commit, filename, line, type)"><% |
@@ -74,24 +75,9 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
74 | 75 | |
|
75 | 76 | <div class="js-template" id="cb-comment-inline-form-template"> |
|
76 | 77 | <div class="comment-inline-form ac"> |
|
77 | ||
|
78 | %if c.rhodecode_user.username != h.DEFAULT_USER: | |
|
78 | %if not c.rhodecode_user.is_default: | |
|
79 | 79 | ## render template for inline comments |
|
80 | 80 | ${commentblock.comment_form(form_type='inline')} |
|
81 | %else: | |
|
82 | ${h.form('', class_='inline-form comment-form-login', method='get')} | |
|
83 | <div class="pull-left"> | |
|
84 | <div class="comment-help pull-right"> | |
|
85 | ${_('You need to be logged in to leave comments.')} <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a> | |
|
86 | </div> | |
|
87 | </div> | |
|
88 | <div class="comment-button pull-right"> | |
|
89 | <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);"> | |
|
90 | ${_('Cancel')} | |
|
91 | </button> | |
|
92 | </div> | |
|
93 | <div class="clearfix"></div> | |
|
94 | ${h.end_form()} | |
|
95 | 81 | %endif |
|
96 | 82 | </div> |
|
97 | 83 | </div> |
@@ -327,7 +313,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
327 | 313 | </label> |
|
328 | 314 | |
|
329 | 315 | ${diff_menu(filediff, use_comments=use_comments)} |
|
330 | <table data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}"> | |
|
316 | <table id="file-${h.safeid(h.safe_unicode(filediff.patch['filename']))}" data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}"> | |
|
331 | 317 | |
|
332 | 318 | ## new/deleted/empty content case |
|
333 | 319 | % if not filediff.hunks: |
@@ -626,8 +612,10 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
626 | 612 | |
|
627 | 613 | % if use_comments: |
|
628 | 614 | | |
|
629 |
<a href="#" onclick=" |
|
|
630 | <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span> | |
|
615 | <a href="#" onclick="Rhodecode.comments.toggleDiffComments(this);return toggleElement(this)" | |
|
616 | data-toggle-on="${_('Hide comments')}" | |
|
617 | data-toggle-off="${_('Show comments')}"> | |
|
618 | <span class="hide-comment-button">${_('Hide comments')}</span> | |
|
631 | 619 | </a> |
|
632 | 620 | % endif |
|
633 | 621 | |
@@ -637,23 +625,36 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
637 | 625 | </%def> |
|
638 | 626 | |
|
639 | 627 | |
|
640 | <%def name="inline_comments_container(comments, active_pattern_entries=None)"> | |
|
628 | <%def name="inline_comments_container(comments, active_pattern_entries=None, line_no='', f_path='')"> | |
|
641 | 629 | |
|
642 | 630 | <div class="inline-comments"> |
|
643 | 631 | %for comment in comments: |
|
644 | 632 | ${commentblock.comment_block(comment, inline=True, active_pattern_entries=active_pattern_entries)} |
|
645 | 633 | %endfor |
|
646 | % if comments and comments[-1].outdated: | |
|
647 | <span class="btn btn-secondary cb-comment-add-button comment-outdated}" style="display: none;}"> | |
|
648 | ${_('Add another comment')} | |
|
649 | </span> | |
|
650 | % else: | |
|
651 | <span onclick="return Rhodecode.comments.createComment(this)" class="btn btn-secondary cb-comment-add-button"> | |
|
652 | ${_('Add another comment')} | |
|
653 | </span> | |
|
654 | % endif | |
|
634 | ||
|
635 | <% | |
|
636 | extra_class = '' | |
|
637 | extra_style = '' | |
|
638 | ||
|
639 | if comments and comments[-1].outdated: | |
|
640 | extra_class = ' comment-outdated' | |
|
641 | extra_style = 'display: none;' | |
|
655 | 642 | |
|
643 | %> | |
|
644 | <div class="reply-thread-container-wrapper${extra_class}" style="${extra_style}"> | |
|
645 | <div class="reply-thread-container${extra_class}"> | |
|
646 | <div class="reply-thread-gravatar"> | |
|
647 | ${base.gravatar(c.rhodecode_user.email, 20, tooltip=True, user=c.rhodecode_user)} | |
|
648 | </div> | |
|
649 | <div class="reply-thread-reply-button"> | |
|
650 | ## initial reply button, some JS logic can append here a FORM to leave a first comment. | |
|
651 | <button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, '${f_path}', '${line_no}', null)">Reply...</button> | |
|
652 | </div> | |
|
653 | <div class="reply-thread-last"></div> | |
|
654 | </div> | |
|
655 | </div> | |
|
656 | 656 | </div> |
|
657 | ||
|
657 | 658 | </%def> |
|
658 | 659 | |
|
659 | 660 | <%! |
@@ -721,9 +722,9 b' def get_comments_for(diff_type, comments' | |||
|
721 | 722 | %endif |
|
722 | 723 | %if line_old_comments_no_drafts: |
|
723 | 724 | % if has_outdated: |
|
724 |
<i class="tooltip icon-comment-toggle" title="${_(' |
|
|
725 | <i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |
|
725 | 726 | % else: |
|
726 |
<i class="tooltip icon-comment" title="${_(' |
|
|
727 | <i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |
|
727 | 728 | % endif |
|
728 | 729 | %endif |
|
729 | 730 | </td> |
@@ -737,16 +738,18 b' def get_comments_for(diff_type, comments' | |||
|
737 | 738 | <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a> |
|
738 | 739 | %endif |
|
739 | 740 | </td> |
|
741 | ||
|
742 | <% line_no = 'o{}'.format(line.original.lineno) %> | |
|
740 | 743 | <td class="cb-content ${action_class(line.original.action)}" |
|
741 |
data-line-no=" |
|
|
744 | data-line-no="${line_no}" | |
|
742 | 745 | > |
|
743 | 746 | %if use_comments and line.original.lineno: |
|
744 | ${render_add_comment_button()} | |
|
747 | ${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])} | |
|
745 | 748 | %endif |
|
746 | 749 | <span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span> |
|
747 | 750 | |
|
748 | 751 | %if use_comments and line.original.lineno and line_old_comments: |
|
749 | ${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries)} | |
|
752 | ${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])} | |
|
750 | 753 | %endif |
|
751 | 754 | |
|
752 | 755 | </td> |
@@ -766,9 +769,9 b' def get_comments_for(diff_type, comments' | |||
|
766 | 769 | |
|
767 | 770 | %if line_new_comments_no_drafts: |
|
768 | 771 | % if has_outdated: |
|
769 |
<i class="tooltip icon-comment-toggle" title="${_(' |
|
|
772 | <i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |
|
770 | 773 | % else: |
|
771 |
<i class="tooltip icon-comment" title="${_(' |
|
|
774 | <i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |
|
772 | 775 | % endif |
|
773 | 776 | %endif |
|
774 | 777 | </div> |
@@ -783,22 +786,25 b' def get_comments_for(diff_type, comments' | |||
|
783 | 786 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a> |
|
784 | 787 | %endif |
|
785 | 788 | </td> |
|
789 | ||
|
790 | <% line_no = 'n{}'.format(line.modified.lineno) %> | |
|
786 | 791 | <td class="cb-content ${action_class(line.modified.action)}" |
|
787 |
data-line-no=" |
|
|
792 | data-line-no="${line_no}" | |
|
788 | 793 | > |
|
789 | 794 | %if use_comments and line.modified.lineno: |
|
790 | ${render_add_comment_button()} | |
|
795 | ${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])} | |
|
791 | 796 | %endif |
|
792 | 797 | <span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span> |
|
793 | %if use_comments and line.modified.lineno and line_new_comments: | |
|
794 | ${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries)} | |
|
795 | %endif | |
|
796 | 798 | % if line_action in ['+', '-'] and prev_line_action not in ['+', '-']: |
|
797 | 799 | <div class="nav-chunk" style="visibility: hidden"> |
|
798 | 800 | <i class="icon-eye" title="viewing diff hunk-${hunk.index}-${chunk_count}"></i> |
|
799 | 801 | </div> |
|
800 | 802 | <% chunk_count +=1 %> |
|
801 | 803 | % endif |
|
804 | %if use_comments and line.modified.lineno and line_new_comments: | |
|
805 | ${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])} | |
|
806 | %endif | |
|
807 | ||
|
802 | 808 | </td> |
|
803 | 809 | </tr> |
|
804 | 810 | %endfor |
@@ -830,9 +836,9 b' def get_comments_for(diff_type, comments' | |||
|
830 | 836 | |
|
831 | 837 | % if comments_no_drafts: |
|
832 | 838 | % if has_outdated: |
|
833 |
<i class="tooltip icon-comment-toggle" title="${_(' |
|
|
839 | <i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |
|
834 | 840 | % else: |
|
835 |
<i class="tooltip icon-comment" title="${_(' |
|
|
841 | <i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |
|
836 | 842 | % endif |
|
837 | 843 | % endif |
|
838 | 844 | </div> |
@@ -857,15 +863,16 b' def get_comments_for(diff_type, comments' | |||
|
857 | 863 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a> |
|
858 | 864 | %endif |
|
859 | 865 | </td> |
|
866 | <% line_no = '{}{}'.format(new_line_no and 'n' or 'o', new_line_no or old_line_no) %> | |
|
860 | 867 | <td class="cb-content ${action_class(action)}" |
|
861 | data-line-no="${(new_line_no and 'n' or 'o')}${(new_line_no or old_line_no)}" | |
|
868 | data-line-no="${line_no}" | |
|
862 | 869 | > |
|
863 | 870 | %if use_comments: |
|
864 | ${render_add_comment_button()} | |
|
871 | ${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])} | |
|
865 | 872 | %endif |
|
866 | 873 | <span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span> |
|
867 | 874 | %if use_comments and comments: |
|
868 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |
|
875 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])} | |
|
869 | 876 | %endif |
|
870 | 877 | </td> |
|
871 | 878 | </tr> |
@@ -886,10 +893,12 b' def get_comments_for(diff_type, comments' | |||
|
886 | 893 | </%def>file changes |
|
887 | 894 | |
|
888 | 895 | |
|
889 | <%def name="render_add_comment_button()"> | |
|
890 | <button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this)"> | |
|
896 | <%def name="render_add_comment_button(line_no='', f_path='')"> | |
|
897 | % if not c.rhodecode_user.is_default: | |
|
898 | <button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this, '${f_path}', '${line_no}', null)"> | |
|
891 | 899 | <span><i class="icon-comment"></i></span> |
|
892 | 900 | </button> |
|
901 | % endif | |
|
893 | 902 | </%def> |
|
894 | 903 | |
|
895 | 904 | <%def name="render_diffset_menu(diffset, range_diff_on=None, commit=None, pull_request_menu=None)"> |
@@ -456,7 +456,7 b'' | |||
|
456 | 456 | </div> |
|
457 | 457 | |
|
458 | 458 | <div class="markup-form-area-write" style="display: block;"> |
|
459 | <div id="edit-container_${form_id}"> | |
|
459 | <div id="edit-container_${form_id}" style="margin-top: -1px"> | |
|
460 | 460 | <textarea id="${form_id}" name="${form_id}" class="comment-block-ta ac-input">${form_text if form_text else ''}</textarea> |
|
461 | 461 | </div> |
|
462 | 462 | <div id="preview-container_${form_id}" class="clearfix" style="display: none;"> |
@@ -237,6 +237,24 b' if (show_disabled) {' | |||
|
237 | 237 | |
|
238 | 238 | </script> |
|
239 | 239 | |
|
240 | <script id="ejs_commentHelpHovercard" type="text/template" class="ejsTemplate"> | |
|
241 | ||
|
242 | <div> | |
|
243 | Use <strong>@username</strong> mention syntax to send direct notification to this RhodeCode user.<br/> | |
|
244 | Typing / starts autocomplete for certain action, e.g set review status, or comment type. <br/> | |
|
245 | <br/> | |
|
246 | Use <strong>Cmd/ctrl+enter</strong> to submit comment, or <strong>Shift+Cmd/ctrl+enter</strong> to submit a draft.<br/> | |
|
247 | <br/> | |
|
248 | <strong>Draft comments</strong> are private to the author, and trigger no notification to others.<br/> | |
|
249 | They are permanent until deleted, or converted to regular comments.<br/> | |
|
250 | <br/> | |
|
251 | <br/> | |
|
252 | </div> | |
|
253 | ||
|
254 | </script> | |
|
255 | ||
|
256 | ||
|
257 | ||
|
240 | 258 | ##// END OF EJS Templates |
|
241 | 259 | </div> |
|
242 | 260 |
@@ -846,6 +846,7 b' versionController.init();' | |||
|
846 | 846 | |
|
847 | 847 | reviewersController = new ReviewersController(); |
|
848 | 848 | commitsController = new CommitsController(); |
|
849 | commentsController = new CommentsController(); | |
|
849 | 850 | |
|
850 | 851 | updateController = new UpdatePrController(); |
|
851 | 852 | |
@@ -1002,6 +1003,8 b' window.setObserversData = ${c.pull_reque' | |||
|
1002 | 1003 | alert('okok !' + commentIds) |
|
1003 | 1004 | |
|
1004 | 1005 | } |
|
1006 | // register globally so inject comment logic can re-use it. | |
|
1007 | window.commentsController = commentsController; | |
|
1005 | 1008 | |
|
1006 | 1009 | }) |
|
1007 | 1010 | </script> |
General Comments 0
You need to be logged in to leave comments.
Login now