Show More
@@ -45,16 +45,17 b' from rhodecode.lib.auth import (' | |||||
45 | from rhodecode.lib.channelstream import channelstream_request |
|
45 | from rhodecode.lib.channelstream import channelstream_request | |
46 | from rhodecode.lib.compat import OrderedDict |
|
46 | from rhodecode.lib.compat import OrderedDict | |
47 | from rhodecode.lib.utils import jsonify |
|
47 | from rhodecode.lib.utils import jsonify | |
48 |
from rhodecode.lib.utils2 import |
|
48 | from rhodecode.lib.utils2 import ( | |
|
49 | safe_int, safe_str, str2bool, safe_unicode, UnsafeAttributeDict) | |||
49 | from rhodecode.lib.vcs.backends.base import EmptyCommit, UpdateFailureReason |
|
50 | from rhodecode.lib.vcs.backends.base import EmptyCommit, UpdateFailureReason | |
50 | from rhodecode.lib.vcs.exceptions import ( |
|
51 | from rhodecode.lib.vcs.exceptions import ( | |
51 | EmptyRepositoryError, CommitDoesNotExistError, RepositoryRequirementError, |
|
52 | EmptyRepositoryError, CommitDoesNotExistError, RepositoryRequirementError, | |
52 | NodeDoesNotExistError) |
|
53 | NodeDoesNotExistError) | |
53 | from rhodecode.lib.diffs import LimitedDiffContainer |
|
54 | ||
54 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
55 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
55 | from rhodecode.model.comment import ChangesetCommentsModel |
|
56 | from rhodecode.model.comment import ChangesetCommentsModel | |
56 |
from rhodecode.model.db import PullRequest, ChangesetStatus, ChangesetComment, |
|
57 | from rhodecode.model.db import (PullRequest, ChangesetStatus, ChangesetComment, | |
57 | Repository |
|
58 | Repository, PullRequestVersion) | |
58 | from rhodecode.model.forms import PullRequestForm |
|
59 | from rhodecode.model.forms import PullRequestForm | |
59 | from rhodecode.model.meta import Session |
|
60 | from rhodecode.model.meta import Session | |
60 | from rhodecode.model.pull_request import PullRequestModel |
|
61 | from rhodecode.model.pull_request import PullRequestModel | |
@@ -675,46 +676,133 b' class PullrequestsController(BaseRepoCon' | |||||
675 | return redirect(url('my_account_pullrequests')) |
|
676 | return redirect(url('my_account_pullrequests')) | |
676 | raise HTTPForbidden() |
|
677 | raise HTTPForbidden() | |
677 |
|
678 | |||
|
679 | def _get_pr_version(self, pull_request_id, version=None): | |||
|
680 | pull_request_id = safe_int(pull_request_id) | |||
|
681 | at_version = None | |||
|
682 | if version: | |||
|
683 | pull_request_ver = PullRequestVersion.get_or_404(version) | |||
|
684 | pull_request_obj = pull_request_ver | |||
|
685 | _org_pull_request_obj = pull_request_ver.pull_request | |||
|
686 | at_version = pull_request_ver.pull_request_version_id | |||
|
687 | else: | |||
|
688 | _org_pull_request_obj = pull_request_obj = PullRequest.get_or_404(pull_request_id) | |||
|
689 | ||||
|
690 | class PullRequestDisplay(object): | |||
|
691 | """ | |||
|
692 | Special object wrapper for showing PullRequest data via Versions | |||
|
693 | It mimics PR object as close as possible. This is read only object | |||
|
694 | just for display | |||
|
695 | """ | |||
|
696 | def __init__(self, attrs): | |||
|
697 | self.attrs = attrs | |||
|
698 | # internal have priority over the given ones via attrs | |||
|
699 | self.internal = ['versions'] | |||
|
700 | ||||
|
701 | def __getattr__(self, item): | |||
|
702 | if item in self.internal: | |||
|
703 | return getattr(self, item) | |||
|
704 | try: | |||
|
705 | return self.attrs[item] | |||
|
706 | except KeyError: | |||
|
707 | raise AttributeError( | |||
|
708 | '%s object has no attribute %s' % (self, item)) | |||
|
709 | ||||
|
710 | def versions(self): | |||
|
711 | return pull_request_obj.versions.order_by( | |||
|
712 | PullRequestVersion.pull_request_version_id).all() | |||
|
713 | ||||
|
714 | def is_closed(self): | |||
|
715 | return pull_request_obj.is_closed() | |||
|
716 | ||||
|
717 | attrs = UnsafeAttributeDict(pull_request_obj.get_api_data()) | |||
|
718 | ||||
|
719 | attrs.author = UnsafeAttributeDict( | |||
|
720 | pull_request_obj.author.get_api_data()) | |||
|
721 | if pull_request_obj.target_repo: | |||
|
722 | attrs.target_repo = UnsafeAttributeDict( | |||
|
723 | pull_request_obj.target_repo.get_api_data()) | |||
|
724 | attrs.target_repo.clone_url = pull_request_obj.target_repo.clone_url | |||
|
725 | ||||
|
726 | if pull_request_obj.source_repo: | |||
|
727 | attrs.source_repo = UnsafeAttributeDict( | |||
|
728 | pull_request_obj.source_repo.get_api_data()) | |||
|
729 | attrs.source_repo.clone_url = pull_request_obj.source_repo.clone_url | |||
|
730 | ||||
|
731 | attrs.source_ref_parts = pull_request_obj.source_ref_parts | |||
|
732 | attrs.target_ref_parts = pull_request_obj.target_ref_parts | |||
|
733 | ||||
|
734 | attrs.shadow_merge_ref = _org_pull_request_obj.shadow_merge_ref | |||
|
735 | ||||
|
736 | pull_request_ver = PullRequestDisplay(attrs) | |||
|
737 | ||||
|
738 | return _org_pull_request_obj, pull_request_obj, \ | |||
|
739 | pull_request_ver, at_version | |||
|
740 | ||||
678 | @LoginRequired() |
|
741 | @LoginRequired() | |
679 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
742 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
680 | 'repository.admin') |
|
743 | 'repository.admin') | |
681 | def show(self, repo_name, pull_request_id): |
|
744 | def show(self, repo_name, pull_request_id): | |
682 | pull_request_id = safe_int(pull_request_id) |
|
745 | pull_request_id = safe_int(pull_request_id) | |
683 | c.pull_request = PullRequest.get_or_404(pull_request_id) |
|
746 | ||
|
747 | version = request.GET.get('version') | |||
|
748 | pull_request_latest, \ | |||
|
749 | pull_request, \ | |||
|
750 | pull_request_ver, \ | |||
|
751 | at_version = self._get_pr_version(pull_request_id, version=version) | |||
684 |
|
752 | |||
685 | c.template_context['pull_request_data']['pull_request_id'] = \ |
|
753 | c.template_context['pull_request_data']['pull_request_id'] = \ | |
686 | pull_request_id |
|
754 | pull_request_id | |
687 |
|
755 | |||
688 | # pull_requests repo_name we opened it against |
|
756 | # pull_requests repo_name we opened it against | |
689 | # ie. target_repo must match |
|
757 | # ie. target_repo must match | |
690 |
if repo_name != |
|
758 | if repo_name != pull_request.target_repo.repo_name: | |
691 | raise HTTPNotFound |
|
759 | raise HTTPNotFound | |
692 |
|
760 | |||
693 | c.allowed_to_change_status = PullRequestModel(). \ |
|
|||
694 | check_user_change_status(c.pull_request, c.rhodecode_user) |
|
|||
695 | c.allowed_to_update = PullRequestModel().check_user_update( |
|
|||
696 | c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() |
|
|||
697 | c.allowed_to_merge = PullRequestModel().check_user_merge( |
|
|||
698 | c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() |
|
|||
699 | c.shadow_clone_url = PullRequestModel().get_shadow_clone_url( |
|
761 | c.shadow_clone_url = PullRequestModel().get_shadow_clone_url( | |
700 |
|
|
762 | pull_request) | |
701 | c.allowed_to_delete = PullRequestModel().check_user_delete( |
|
763 | ||
702 | c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() |
|
764 | if at_version: | |
|
765 | c.allowed_to_change_status = False | |||
|
766 | else: | |||
|
767 | c.allowed_to_change_status = PullRequestModel(). \ | |||
|
768 | check_user_change_status(pull_request, c.rhodecode_user) | |||
|
769 | ||||
|
770 | if at_version: | |||
|
771 | c.allowed_to_update = False | |||
|
772 | else: | |||
|
773 | c.allowed_to_update = PullRequestModel().check_user_update( | |||
|
774 | pull_request, c.rhodecode_user) and not pull_request.is_closed() | |||
|
775 | ||||
|
776 | if at_version: | |||
|
777 | c.allowed_to_merge = False | |||
|
778 | else: | |||
|
779 | c.allowed_to_merge = PullRequestModel().check_user_merge( | |||
|
780 | pull_request, c.rhodecode_user) and not pull_request.is_closed() | |||
|
781 | ||||
|
782 | if at_version: | |||
|
783 | c.allowed_to_delete = False | |||
|
784 | else: | |||
|
785 | c.allowed_to_delete = PullRequestModel().check_user_delete( | |||
|
786 | pull_request, c.rhodecode_user) and not pull_request.is_closed() | |||
|
787 | ||||
|
788 | if at_version: | |||
|
789 | c.allowed_to_comment = False | |||
|
790 | else: | |||
|
791 | c.allowed_to_comment = not pull_request.is_closed() | |||
703 |
|
792 | |||
704 | cc_model = ChangesetCommentsModel() |
|
793 | cc_model = ChangesetCommentsModel() | |
705 |
|
794 | |||
706 |
c.pull_request_reviewers = |
|
795 | c.pull_request_reviewers = pull_request.reviewers_statuses() | |
707 |
|
796 | |||
708 |
c.pull_request_review_status = |
|
797 | c.pull_request_review_status = pull_request.calculated_review_status() | |
709 | c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status( |
|
798 | c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status( | |
710 |
|
|
799 | pull_request) | |
711 | c.approval_msg = None |
|
800 | c.approval_msg = None | |
712 | if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED: |
|
801 | if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED: | |
713 | c.approval_msg = _('Reviewer approval is pending.') |
|
802 | c.approval_msg = _('Reviewer approval is pending.') | |
714 | c.pr_merge_status = False |
|
803 | c.pr_merge_status = False | |
715 | # load compare data into template context |
|
804 | # load compare data into template context | |
716 |
enable_comments = not |
|
805 | enable_comments = not pull_request.is_closed() | |
717 |
|
||||
718 |
|
806 | |||
719 | # inline comments |
|
807 | # inline comments | |
720 | c.inline_comments = cc_model.get_inline_comments( |
|
808 | c.inline_comments = cc_model.get_inline_comments( | |
@@ -725,23 +813,26 b' class PullrequestsController(BaseRepoCon' | |||||
725 | c.inline_comments, version=at_version) |
|
813 | c.inline_comments, version=at_version) | |
726 |
|
814 | |||
727 | self._load_compare_data( |
|
815 | self._load_compare_data( | |
728 |
|
|
816 | pull_request, c.inline_comments, enable_comments=enable_comments) | |
729 |
|
817 | |||
730 | # outdated comments |
|
818 | # outdated comments | |
731 | c.outdated_comments = {} |
|
819 | c.outdated_comments = {} | |
732 | c.outdated_cnt = 0 |
|
820 | c.outdated_cnt = 0 | |
733 | if ChangesetCommentsModel.use_outdated_comments(c.pull_request): |
|
821 | ||
|
822 | if ChangesetCommentsModel.use_outdated_comments(pull_request): | |||
734 | c.outdated_comments = cc_model.get_outdated_comments( |
|
823 | c.outdated_comments = cc_model.get_outdated_comments( | |
735 | c.rhodecode_db_repo.repo_id, |
|
824 | c.rhodecode_db_repo.repo_id, | |
736 |
pull_request= |
|
825 | pull_request=pull_request) | |
|
826 | ||||
737 | # Count outdated comments and check for deleted files |
|
827 | # Count outdated comments and check for deleted files | |
738 | for file_name, lines in c.outdated_comments.iteritems(): |
|
828 | for file_name, lines in c.outdated_comments.iteritems(): | |
739 | for comments in lines.values(): |
|
829 | for comments in lines.values(): | |
|
830 | comments = [comm for comm in comments | |||
|
831 | if comm.outdated_at_version(at_version)] | |||
740 | c.outdated_cnt += len(comments) |
|
832 | c.outdated_cnt += len(comments) | |
741 | if file_name not in c.included_files: |
|
833 | if file_name not in c.included_files: | |
742 | c.deleted_files.append(file_name) |
|
834 | c.deleted_files.append(file_name) | |
743 |
|
835 | |||
744 |
|
||||
745 | # this is a hack to properly display links, when creating PR, the |
|
836 | # this is a hack to properly display links, when creating PR, the | |
746 | # compare view and others uses different notation, and |
|
837 | # compare view and others uses different notation, and | |
747 | # compare_commits.html renders links based on the target_repo. |
|
838 | # compare_commits.html renders links based on the target_repo. | |
@@ -760,6 +851,9 b' class PullrequestsController(BaseRepoCon' | |||||
760 | c.commit_statuses = statuses |
|
851 | c.commit_statuses = statuses | |
761 |
|
852 | |||
762 | c.ancestor = None # TODO: add ancestor here |
|
853 | c.ancestor = None # TODO: add ancestor here | |
|
854 | c.pull_request = pull_request_ver | |||
|
855 | c.pull_request_latest = pull_request_latest | |||
|
856 | c.at_version = at_version | |||
763 |
|
857 | |||
764 | return render('/pullrequests/pullrequest_show.html') |
|
858 | return render('/pullrequests/pullrequest_show.html') | |
765 |
|
859 | |||
@@ -813,8 +907,6 b' class PullrequestsController(BaseRepoCon' | |||||
813 | closing_pr=close_pr |
|
907 | closing_pr=close_pr | |
814 | ) |
|
908 | ) | |
815 |
|
909 | |||
816 |
|
||||
817 |
|
||||
818 | if allowed_to_change_status: |
|
910 | if allowed_to_change_status: | |
819 | old_calculated_status = pull_request.calculated_review_status() |
|
911 | old_calculated_status = pull_request.calculated_review_status() | |
820 | # get status if set ! |
|
912 | # get status if set ! |
@@ -656,6 +656,16 b' def extract_mentioned_users(s):' | |||||
656 | return sorted(list(usrs), key=lambda k: k.lower()) |
|
656 | return sorted(list(usrs), key=lambda k: k.lower()) | |
657 |
|
657 | |||
658 |
|
658 | |||
|
659 | class UnsafeAttributeDict(dict): | |||
|
660 | def __getattr__(self, attr): | |||
|
661 | try: | |||
|
662 | return self[attr] | |||
|
663 | except KeyError: | |||
|
664 | raise AttributeError('%s object has no attribute %s' % (self, attr)) | |||
|
665 | __setattr__ = dict.__setitem__ | |||
|
666 | __delattr__ = dict.__delitem__ | |||
|
667 | ||||
|
668 | ||||
659 | class AttributeDict(dict): |
|
669 | class AttributeDict(dict): | |
660 | def __getattr__(self, attr): |
|
670 | def __getattr__(self, attr): | |
661 | return self.get(attr, None) |
|
671 | return self.get(attr, None) |
@@ -90,7 +90,7 b' class BaseModel(object):' | |||||
90 | """ |
|
90 | """ | |
91 | Gets instance of given cls using some simple lookup mechanism. |
|
91 | Gets instance of given cls using some simple lookup mechanism. | |
92 |
|
92 | |||
93 | :param cls: class to fetch |
|
93 | :param cls: classes to fetch | |
94 | :param instance: int or Instance |
|
94 | :param instance: int or Instance | |
95 | :param callback: callback to call if all lookups failed |
|
95 | :param callback: callback to call if all lookups failed | |
96 | """ |
|
96 | """ | |
@@ -98,6 +98,9 b' class BaseModel(object):' | |||||
98 | if isinstance(instance, cls): |
|
98 | if isinstance(instance, cls): | |
99 | return instance |
|
99 | return instance | |
100 | elif isinstance(instance, (int, long)): |
|
100 | elif isinstance(instance, (int, long)): | |
|
101 | if isinstance(cls, tuple): | |||
|
102 | # if we pass multi instances we pick first to .get() | |||
|
103 | cls = cls[0] | |||
101 | return cls.get(instance) |
|
104 | return cls.get(instance) | |
102 | else: |
|
105 | else: | |
103 | if instance: |
|
106 | if instance: |
@@ -2933,6 +2933,12 b' class ChangesetComment(Base, BaseModel):' | |||||
2933 | def outdated(self): |
|
2933 | def outdated(self): | |
2934 | return self.display_state == self.COMMENT_OUTDATED |
|
2934 | return self.display_state == self.COMMENT_OUTDATED | |
2935 |
|
2935 | |||
|
2936 | def outdated_at_version(self, version): | |||
|
2937 | """ | |||
|
2938 | Checks if comment is outdated for given pull request version | |||
|
2939 | """ | |||
|
2940 | return self.outdated and self.pull_request_version_id != version | |||
|
2941 | ||||
2936 | def render(self, mentions=False): |
|
2942 | def render(self, mentions=False): | |
2937 | from rhodecode.lib import helpers as h |
|
2943 | from rhodecode.lib import helpers as h | |
2938 | return h.render(self.text, renderer=self.renderer, mentions=mentions) |
|
2944 | return h.render(self.text, renderer=self.renderer, mentions=mentions) | |
@@ -3117,34 +3123,6 b' class _PullRequestBase(BaseModel):' | |||||
3117 | else: |
|
3123 | else: | |
3118 | return None |
|
3124 | return None | |
3119 |
|
3125 | |||
3120 |
|
||||
3121 | class PullRequest(Base, _PullRequestBase): |
|
|||
3122 | __tablename__ = 'pull_requests' |
|
|||
3123 | __table_args__ = ( |
|
|||
3124 | {'extend_existing': True, 'mysql_engine': 'InnoDB', |
|
|||
3125 | 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, |
|
|||
3126 | ) |
|
|||
3127 |
|
||||
3128 | pull_request_id = Column( |
|
|||
3129 | 'pull_request_id', Integer(), nullable=False, primary_key=True) |
|
|||
3130 |
|
||||
3131 | def __repr__(self): |
|
|||
3132 | if self.pull_request_id: |
|
|||
3133 | return '<DB:PullRequest #%s>' % self.pull_request_id |
|
|||
3134 | else: |
|
|||
3135 | return '<DB:PullRequest at %#x>' % id(self) |
|
|||
3136 |
|
||||
3137 | reviewers = relationship('PullRequestReviewers', |
|
|||
3138 | cascade="all, delete, delete-orphan") |
|
|||
3139 | statuses = relationship('ChangesetStatus') |
|
|||
3140 | comments = relationship('ChangesetComment', |
|
|||
3141 | cascade="all, delete, delete-orphan") |
|
|||
3142 | versions = relationship('PullRequestVersion', |
|
|||
3143 | cascade="all, delete, delete-orphan") |
|
|||
3144 |
|
||||
3145 | def is_closed(self): |
|
|||
3146 | return self.status == self.STATUS_CLOSED |
|
|||
3147 |
|
||||
3148 | def get_api_data(self): |
|
3126 | def get_api_data(self): | |
3149 | from rhodecode.model.pull_request import PullRequestModel |
|
3127 | from rhodecode.model.pull_request import PullRequestModel | |
3150 | pull_request = self |
|
3128 | pull_request = self | |
@@ -3209,6 +3187,35 b' class PullRequest(Base, _PullRequestBase' | |||||
3209 |
|
3187 | |||
3210 | return data |
|
3188 | return data | |
3211 |
|
3189 | |||
|
3190 | ||||
|
3191 | class PullRequest(Base, _PullRequestBase): | |||
|
3192 | __tablename__ = 'pull_requests' | |||
|
3193 | __table_args__ = ( | |||
|
3194 | {'extend_existing': True, 'mysql_engine': 'InnoDB', | |||
|
3195 | 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, | |||
|
3196 | ) | |||
|
3197 | ||||
|
3198 | pull_request_id = Column( | |||
|
3199 | 'pull_request_id', Integer(), nullable=False, primary_key=True) | |||
|
3200 | ||||
|
3201 | def __repr__(self): | |||
|
3202 | if self.pull_request_id: | |||
|
3203 | return '<DB:PullRequest #%s>' % self.pull_request_id | |||
|
3204 | else: | |||
|
3205 | return '<DB:PullRequest at %#x>' % id(self) | |||
|
3206 | ||||
|
3207 | reviewers = relationship('PullRequestReviewers', | |||
|
3208 | cascade="all, delete, delete-orphan") | |||
|
3209 | statuses = relationship('ChangesetStatus') | |||
|
3210 | comments = relationship('ChangesetComment', | |||
|
3211 | cascade="all, delete, delete-orphan") | |||
|
3212 | versions = relationship('PullRequestVersion', | |||
|
3213 | cascade="all, delete, delete-orphan", | |||
|
3214 | lazy='dynamic') | |||
|
3215 | ||||
|
3216 | def is_closed(self): | |||
|
3217 | return self.status == self.STATUS_CLOSED | |||
|
3218 | ||||
3212 | def __json__(self): |
|
3219 | def __json__(self): | |
3213 | return { |
|
3220 | return { | |
3214 | 'revisions': self.revisions, |
|
3221 | 'revisions': self.revisions, | |
@@ -3243,6 +3250,24 b' class PullRequestVersion(Base, _PullRequ' | |||||
3243 | else: |
|
3250 | else: | |
3244 | return '<DB:PullRequestVersion at %#x>' % id(self) |
|
3251 | return '<DB:PullRequestVersion at %#x>' % id(self) | |
3245 |
|
3252 | |||
|
3253 | @property | |||
|
3254 | def reviewers(self): | |||
|
3255 | return self.pull_request.reviewers | |||
|
3256 | ||||
|
3257 | @property | |||
|
3258 | def versions(self): | |||
|
3259 | return self.pull_request.versions | |||
|
3260 | ||||
|
3261 | def is_closed(self): | |||
|
3262 | # calculate from original | |||
|
3263 | return self.pull_request.status == self.STATUS_CLOSED | |||
|
3264 | ||||
|
3265 | def calculated_review_status(self): | |||
|
3266 | return self.pull_request.calculated_review_status() | |||
|
3267 | ||||
|
3268 | def reviewers_statuses(self): | |||
|
3269 | return self.pull_request.reviewers_statuses() | |||
|
3270 | ||||
3246 |
|
3271 | |||
3247 | class PullRequestReviewers(Base, BaseModel): |
|
3272 | class PullRequestReviewers(Base, BaseModel): | |
3248 | __tablename__ = 'pull_request_reviewers' |
|
3273 | __tablename__ = 'pull_request_reviewers' |
@@ -208,8 +208,14 b' input[type="button"] {' | |||||
208 | color: @rcdarkblue; |
|
208 | color: @rcdarkblue; | |
209 | } |
|
209 | } | |
210 |
|
210 | |||
|
211 | //disabled buttons | |||
|
212 | //last; overrides any other styles | |||
211 | &:disabled { |
|
213 | &:disabled { | |
|
214 | opacity: .7; | |||
|
215 | cursor: auto; | |||
|
216 | background-color: white; | |||
212 | color: @grey4; |
|
217 | color: @grey4; | |
|
218 | text-shadow: none; | |||
213 | } |
|
219 | } | |
214 |
|
220 | |||
215 | // TODO: johbo: Check if we can avoid this, indicates that the structure |
|
221 | // TODO: johbo: Check if we can avoid this, indicates that the structure |
@@ -313,7 +313,7 b' table.code-difftable {' | |||||
313 | // Comments |
|
313 | // Comments | |
314 |
|
314 | |||
315 | div.comment:target { |
|
315 | div.comment:target { | |
316 | border-left: 6px solid @comment-highlight-color; |
|
316 | border-left: 6px solid @comment-highlight-color !important; | |
317 | padding-left: 3px; |
|
317 | padding-left: 3px; | |
318 | margin-left: -9px; |
|
318 | margin-left: -9px; | |
319 | } |
|
319 | } | |
@@ -737,6 +737,15 b' input.filediff-collapse-state {' | |||||
737 | } |
|
737 | } | |
738 | } |
|
738 | } | |
739 |
|
739 | |||
|
740 | /* Main comments*/ | |||
|
741 | #comments { | |||
|
742 | .comment-selected { | |||
|
743 | border-left: 6px solid @comment-highlight-color; | |||
|
744 | padding-left: 3px; | |||
|
745 | margin-left: -9px; | |||
|
746 | } | |||
|
747 | } | |||
|
748 | ||||
740 | .filediff { |
|
749 | .filediff { | |
741 | border: 1px solid @grey5; |
|
750 | border: 1px solid @grey5; | |
742 |
|
751 | |||
@@ -894,6 +903,7 b' input.filediff-collapse-state {' | |||||
894 | display: none; |
|
903 | display: none; | |
895 | } |
|
904 | } | |
896 | } |
|
905 | } | |
|
906 | ||||
897 | .inline-comments { |
|
907 | .inline-comments { | |
898 | border-radius: @border-radius; |
|
908 | border-radius: @border-radius; | |
899 | background: @grey6; |
|
909 | background: @grey6; | |
@@ -904,6 +914,7 b' input.filediff-collapse-state {' | |||||
904 | .comment-outdated { |
|
914 | .comment-outdated { | |
905 | opacity: 0.5; |
|
915 | opacity: 0.5; | |
906 | } |
|
916 | } | |
|
917 | ||||
907 | .comment-inline { |
|
918 | .comment-inline { | |
908 | background: white; |
|
919 | background: white; | |
909 | padding: (@comment-padding + 3px) @comment-padding; |
|
920 | padding: (@comment-padding + 3px) @comment-padding; |
@@ -170,22 +170,6 b' tr.inline-comments div {' | |||||
170 | color: @rcblue; |
|
170 | color: @rcblue; | |
171 | } |
|
171 | } | |
172 |
|
172 | |||
173 | .outdated { |
|
|||
174 | display: none; |
|
|||
175 | opacity: 0.6; |
|
|||
176 |
|
||||
177 | .comment { |
|
|||
178 | margin: 0 0 @padding; |
|
|||
179 |
|
||||
180 | .date:after { |
|
|||
181 | content: none; |
|
|||
182 | } |
|
|||
183 | } |
|
|||
184 | .outdated_comment_block { |
|
|||
185 | padding: 0 0 @space 0; |
|
|||
186 | } |
|
|||
187 | } |
|
|||
188 |
|
||||
189 | // Comment Form |
|
173 | // Comment Form | |
190 | div.comment-form { |
|
174 | div.comment-form { | |
191 | margin-top: 20px; |
|
175 | margin-top: 20px; |
@@ -1395,9 +1395,7 b' table.integrations {' | |||||
1395 | width: 92%; |
|
1395 | width: 92%; | |
1396 | margin-bottom: 1em; |
|
1396 | margin-bottom: 1em; | |
1397 | } |
|
1397 | } | |
1398 | #update_commits { |
|
1398 | ||
1399 | float: right; |
|
|||
1400 | } |
|
|||
1401 | .compare_view_commits tr{ |
|
1399 | .compare_view_commits tr{ | |
1402 | height: 20px; |
|
1400 | height: 20px; | |
1403 | } |
|
1401 | } |
@@ -48,58 +48,6 b' var tableTr = function(cls, body){' | |||||
48 | return _el.children[0].children[0].children[0]; |
|
48 | return _el.children[0].children[0].children[0]; | |
49 | }; |
|
49 | }; | |
50 |
|
50 | |||
51 | var removeInlineForm = function(form) { |
|
|||
52 | form.parentNode.removeChild(form); |
|
|||
53 | }; |
|
|||
54 |
|
||||
55 | var createInlineForm = function(parent_tr, f_path, line) { |
|
|||
56 | var tmpl = $('#comment-inline-form-template').html(); |
|
|||
57 | tmpl = tmpl.format(f_path, line); |
|
|||
58 | var form = tableTr('comment-form-inline', tmpl); |
|
|||
59 | var form_hide_button = $(form).find('.hide-inline-form'); |
|
|||
60 |
|
||||
61 | $(form_hide_button).click(function(e) { |
|
|||
62 | $('.inline-comments').removeClass('hide-comment-button'); |
|
|||
63 | var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode; |
|
|||
64 | if ($(newtr.nextElementSibling).hasClass('inline-comments-button')) { |
|
|||
65 | $(newtr.nextElementSibling).show(); |
|
|||
66 | } |
|
|||
67 | $(newtr).parents('.comment-form-inline').remove(); |
|
|||
68 | $(parent_tr).removeClass('form-open'); |
|
|||
69 | $(parent_tr).removeClass('hl-comment'); |
|
|||
70 | }); |
|
|||
71 |
|
||||
72 | return form; |
|
|||
73 | }; |
|
|||
74 |
|
||||
75 | var getLineNo = function(tr) { |
|
|||
76 | var line; |
|
|||
77 | // Try to get the id and return "" (empty string) if it doesn't exist |
|
|||
78 | var o = ($(tr).find('.lineno.old').attr('id')||"").split('_'); |
|
|||
79 | var n = ($(tr).find('.lineno.new').attr('id')||"").split('_'); |
|
|||
80 | if (n.length >= 2) { |
|
|||
81 | line = n[n.length-1]; |
|
|||
82 | } else if (o.length >= 2) { |
|
|||
83 | line = o[o.length-1]; |
|
|||
84 | } |
|
|||
85 | return line; |
|
|||
86 | }; |
|
|||
87 |
|
||||
88 | /** |
|
|||
89 | * make a single inline comment and place it inside |
|
|||
90 | */ |
|
|||
91 | var renderInlineComment = function(json_data, show_add_button) { |
|
|||
92 | show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; |
|
|||
93 | try { |
|
|||
94 | var html = json_data.rendered_text; |
|
|||
95 | var lineno = json_data.line_no; |
|
|||
96 | var target_id = json_data.target_id; |
|
|||
97 | placeInline(target_id, lineno, html, show_add_button); |
|
|||
98 | } catch (e) { |
|
|||
99 | console.error(e); |
|
|||
100 | } |
|
|||
101 | }; |
|
|||
102 |
|
||||
103 | function bindDeleteCommentButtons() { |
|
51 | function bindDeleteCommentButtons() { | |
104 | $('.delete-comment').one('click', function() { |
|
52 | $('.delete-comment').one('click', function() { | |
105 | var comment_id = $(this).data("comment-id"); |
|
53 | var comment_id = $(this).data("comment-id"); | |
@@ -110,115 +58,6 b' function bindDeleteCommentButtons() {' | |||||
110 | }); |
|
58 | }); | |
111 | } |
|
59 | } | |
112 |
|
60 | |||
113 | /** |
|
|||
114 | * Inject inline comment for on given TR this tr should be always an .line |
|
|||
115 | * tr containing the line. Code will detect comment, and always put the comment |
|
|||
116 | * block at the very bottom |
|
|||
117 | */ |
|
|||
118 | var injectInlineForm = function(tr){ |
|
|||
119 | if (!$(tr).hasClass('line')) { |
|
|||
120 | return; |
|
|||
121 | } |
|
|||
122 |
|
||||
123 | var _td = $(tr).find('.code').get(0); |
|
|||
124 | if ($(tr).hasClass('form-open') || |
|
|||
125 | $(tr).hasClass('context') || |
|
|||
126 | $(_td).hasClass('no-comment')) { |
|
|||
127 | return; |
|
|||
128 | } |
|
|||
129 | $(tr).addClass('form-open'); |
|
|||
130 | $(tr).addClass('hl-comment'); |
|
|||
131 | var node = $(tr.parentNode.parentNode.parentNode).find('.full_f_path').get(0); |
|
|||
132 | var f_path = $(node).attr('path'); |
|
|||
133 | var lineno = getLineNo(tr); |
|
|||
134 | var form = createInlineForm(tr, f_path, lineno); |
|
|||
135 |
|
||||
136 | var parent = tr; |
|
|||
137 | while (1) { |
|
|||
138 | var n = parent.nextElementSibling; |
|
|||
139 | // next element are comments ! |
|
|||
140 | if ($(n).hasClass('inline-comments')) { |
|
|||
141 | parent = n; |
|
|||
142 | } |
|
|||
143 | else { |
|
|||
144 | break; |
|
|||
145 | } |
|
|||
146 | } |
|
|||
147 | var _parent = $(parent).get(0); |
|
|||
148 | $(_parent).after(form); |
|
|||
149 | $('.comment-form-inline').prev('.inline-comments').addClass('hide-comment-button'); |
|
|||
150 | var f = $(form).get(0); |
|
|||
151 |
|
||||
152 | var _form = $(f).find('.inline-form').get(0); |
|
|||
153 |
|
||||
154 | var pullRequestId = templateContext.pull_request_data.pull_request_id; |
|
|||
155 | var commitId = templateContext.commit_data.commit_id; |
|
|||
156 |
|
||||
157 | var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false); |
|
|||
158 | var cm = commentForm.getCmInstance(); |
|
|||
159 |
|
||||
160 | // set a CUSTOM submit handler for inline comments. |
|
|||
161 | commentForm.setHandleFormSubmit(function(o) { |
|
|||
162 | var text = commentForm.cm.getValue(); |
|
|||
163 |
|
||||
164 | if (text === "") { |
|
|||
165 | return; |
|
|||
166 | } |
|
|||
167 |
|
||||
168 | if (lineno === undefined) { |
|
|||
169 | alert('missing line !'); |
|
|||
170 | return; |
|
|||
171 | } |
|
|||
172 | if (f_path === undefined) { |
|
|||
173 | alert('missing file path !'); |
|
|||
174 | return; |
|
|||
175 | } |
|
|||
176 |
|
||||
177 | var excludeCancelBtn = false; |
|
|||
178 | var submitEvent = true; |
|
|||
179 | commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent); |
|
|||
180 | commentForm.cm.setOption("readOnly", true); |
|
|||
181 | var postData = { |
|
|||
182 | 'text': text, |
|
|||
183 | 'f_path': f_path, |
|
|||
184 | 'line': lineno, |
|
|||
185 | 'csrf_token': CSRF_TOKEN |
|
|||
186 | }; |
|
|||
187 | var submitSuccessCallback = function(o) { |
|
|||
188 | $(tr).removeClass('form-open'); |
|
|||
189 | removeInlineForm(f); |
|
|||
190 | renderInlineComment(o); |
|
|||
191 | $('.inline-comments').removeClass('hide-comment-button'); |
|
|||
192 |
|
||||
193 | // re trigger the linkification of next/prev navigation |
|
|||
194 | linkifyComments($('.inline-comment-injected')); |
|
|||
195 | timeagoActivate(); |
|
|||
196 | bindDeleteCommentButtons(); |
|
|||
197 | commentForm.setActionButtonsDisabled(false); |
|
|||
198 |
|
||||
199 | }; |
|
|||
200 | var submitFailCallback = function(){ |
|
|||
201 | commentForm.resetCommentFormState(text) |
|
|||
202 | }; |
|
|||
203 | commentForm.submitAjaxPOST( |
|
|||
204 | commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback); |
|
|||
205 | }); |
|
|||
206 |
|
||||
207 | setTimeout(function() { |
|
|||
208 | // callbacks |
|
|||
209 | if (cm !== undefined) { |
|
|||
210 | cm.focus(); |
|
|||
211 | } |
|
|||
212 | }, 10); |
|
|||
213 |
|
||||
214 | $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({ |
|
|||
215 | form:_form, |
|
|||
216 | parent:_parent, |
|
|||
217 | lineno: lineno, |
|
|||
218 | f_path: f_path} |
|
|||
219 | ); |
|
|||
220 | }; |
|
|||
221 |
|
||||
222 | var deleteComment = function(comment_id) { |
|
61 | var deleteComment = function(comment_id) { | |
223 | var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id); |
|
62 | var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id); | |
224 | var postData = { |
|
63 | var postData = { | |
@@ -232,89 +71,6 b' var deleteComment = function(comment_id)' | |||||
232 | ajaxPOST(url, postData, success); |
|
71 | ajaxPOST(url, postData, success); | |
233 | }; |
|
72 | }; | |
234 |
|
73 | |||
235 | var createInlineAddButton = function(tr){ |
|
|||
236 | var label = _gettext('Add another comment'); |
|
|||
237 | var html_el = document.createElement('div'); |
|
|||
238 | $(html_el).addClass('add-comment'); |
|
|||
239 | html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label); |
|
|||
240 | var add = new $(html_el); |
|
|||
241 | add.on('click', function(e) { |
|
|||
242 | injectInlineForm(tr); |
|
|||
243 | }); |
|
|||
244 | return add; |
|
|||
245 | }; |
|
|||
246 |
|
||||
247 | var placeAddButton = function(target_tr){ |
|
|||
248 | if(!target_tr){ |
|
|||
249 | return; |
|
|||
250 | } |
|
|||
251 | var last_node = target_tr; |
|
|||
252 | // scan |
|
|||
253 | while (1){ |
|
|||
254 | var n = last_node.nextElementSibling; |
|
|||
255 | // next element are comments ! |
|
|||
256 | if($(n).hasClass('inline-comments')){ |
|
|||
257 | last_node = n; |
|
|||
258 | // also remove the comment button from previous |
|
|||
259 | var comment_add_buttons = $(last_node).find('.add-comment'); |
|
|||
260 | for(var i=0; i<comment_add_buttons.length; i++){ |
|
|||
261 | var b = comment_add_buttons[i]; |
|
|||
262 | b.parentNode.removeChild(b); |
|
|||
263 | } |
|
|||
264 | } |
|
|||
265 | else{ |
|
|||
266 | break; |
|
|||
267 | } |
|
|||
268 | } |
|
|||
269 | var add = createInlineAddButton(target_tr); |
|
|||
270 | // get the comment div |
|
|||
271 | var comment_block = $(last_node).find('.comment')[0]; |
|
|||
272 | // attach add button |
|
|||
273 | $(add).insertAfter(comment_block); |
|
|||
274 | }; |
|
|||
275 |
|
||||
276 | /** |
|
|||
277 | * Places the inline comment into the changeset block in proper line position |
|
|||
278 | */ |
|
|||
279 | var placeInline = function(target_container, lineno, html, show_add_button) { |
|
|||
280 | show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; |
|
|||
281 |
|
||||
282 | var lineid = "{0}_{1}".format(target_container, lineno); |
|
|||
283 | var target_line = $('#' + lineid).get(0); |
|
|||
284 | var comment = new $(tableTr('inline-comments', html)); |
|
|||
285 | // check if there are comments already ! |
|
|||
286 | if (target_line) { |
|
|||
287 | var parent_node = target_line.parentNode; |
|
|||
288 | var root_parent = parent_node; |
|
|||
289 |
|
||||
290 | while (1) { |
|
|||
291 | var n = parent_node.nextElementSibling; |
|
|||
292 | // next element are comments ! |
|
|||
293 | if ($(n).hasClass('inline-comments')) { |
|
|||
294 | parent_node = n; |
|
|||
295 | } |
|
|||
296 | else { |
|
|||
297 | break; |
|
|||
298 | } |
|
|||
299 | } |
|
|||
300 | // put in the comment at the bottom |
|
|||
301 | $(comment).insertAfter(parent_node); |
|
|||
302 | $(comment).find('.comment-inline').addClass('inline-comment-injected'); |
|
|||
303 | // scan nodes, and attach add button to last one |
|
|||
304 | if (show_add_button) { |
|
|||
305 | placeAddButton(root_parent); |
|
|||
306 | } |
|
|||
307 | addCommentToggle(target_line); |
|
|||
308 | } |
|
|||
309 |
|
||||
310 | return target_line; |
|
|||
311 | }; |
|
|||
312 |
|
||||
313 | var addCommentToggle = function(target_line) { |
|
|||
314 | // exposes comment toggle button |
|
|||
315 | $(target_line).siblings('.comment-toggle').addClass('active'); |
|
|||
316 | return; |
|
|||
317 | }; |
|
|||
318 |
|
74 | |||
319 | var bindToggleButtons = function() { |
|
75 | var bindToggleButtons = function() { | |
320 | $('.comment-toggle').on('click', function() { |
|
76 | $('.comment-toggle').on('click', function() { | |
@@ -348,37 +104,6 b' var linkifyComments = function(comments)' | |||||
348 |
|
104 | |||
349 | }; |
|
105 | }; | |
350 |
|
106 | |||
351 | /** |
|
|||
352 | * Iterates over all the inlines, and places them inside proper blocks of data |
|
|||
353 | */ |
|
|||
354 | var renderInlineComments = function(file_comments, show_add_button) { |
|
|||
355 | show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; |
|
|||
356 |
|
||||
357 | for (var i = 0; i < file_comments.length; i++) { |
|
|||
358 | var box = file_comments[i]; |
|
|||
359 |
|
||||
360 | var target_id = $(box).attr('target_id'); |
|
|||
361 |
|
||||
362 | // actually comments with line numbers |
|
|||
363 | var comments = box.children; |
|
|||
364 |
|
||||
365 | for (var j = 0; j < comments.length; j++) { |
|
|||
366 | var data = { |
|
|||
367 | 'rendered_text': comments[j].outerHTML, |
|
|||
368 | 'line_no': $(comments[j]).attr('line'), |
|
|||
369 | 'target_id': target_id |
|
|||
370 | }; |
|
|||
371 | renderInlineComment(data, show_add_button); |
|
|||
372 | } |
|
|||
373 | } |
|
|||
374 |
|
||||
375 | // since order of injection is random, we're now re-iterating |
|
|||
376 | // from correct order and filling in links |
|
|||
377 | linkifyComments($('.inline-comment-injected')); |
|
|||
378 | bindDeleteCommentButtons(); |
|
|||
379 | firefoxAnchorFix(); |
|
|||
380 | }; |
|
|||
381 |
|
||||
382 |
|
107 | |||
383 | /* Comment form for main and inline comments */ |
|
108 | /* Comment form for main and inline comments */ | |
384 | var CommentForm = (function() { |
|
109 | var CommentForm = (function() { | |
@@ -679,11 +404,13 b' var CommentsController = function() { /*' | |||||
679 | var $td = $node.closest('td'); |
|
404 | var $td = $node.closest('td'); | |
680 | $node.closest('.comment-inline-form').removeClass('comment-inline-form-open'); |
|
405 | $node.closest('.comment-inline-form').removeClass('comment-inline-form-open'); | |
681 | return false; |
|
406 | return false; | |
682 | } |
|
407 | }; | |
|
408 | ||||
683 | this.getLineNumber = function(node) { |
|
409 | this.getLineNumber = function(node) { | |
684 | var $node = $(node); |
|
410 | var $node = $(node); | |
685 | return $node.closest('td').attr('data-line-number'); |
|
411 | return $node.closest('td').attr('data-line-number'); | |
686 | } |
|
412 | }; | |
|
413 | ||||
687 | this.scrollToComment = function(node, offset) { |
|
414 | this.scrollToComment = function(node, offset) { | |
688 | if (!node) { |
|
415 | if (!node) { | |
689 | node = $('.comment-selected'); |
|
416 | node = $('.comment-selected'); | |
@@ -702,20 +429,23 b' var CommentsController = function() { /*' | |||||
702 | } |
|
429 | } | |
703 | var $next = $('.comment-current').eq(nextIdx); |
|
430 | var $next = $('.comment-current').eq(nextIdx); | |
704 | var $cb = $next.closest('.cb'); |
|
431 | var $cb = $next.closest('.cb'); | |
705 | $cb.removeClass('cb-collapsed') |
|
432 | $cb.removeClass('cb-collapsed'); | |
706 |
|
433 | |||
707 | var $filediffCollapseState = $cb.closest('.filediff').prev(); |
|
434 | var $filediffCollapseState = $cb.closest('.filediff').prev(); | |
708 | $filediffCollapseState.prop('checked', false); |
|
435 | $filediffCollapseState.prop('checked', false); | |
709 | $next.addClass('comment-selected'); |
|
436 | $next.addClass('comment-selected'); | |
710 | scrollToElement($next); |
|
437 | scrollToElement($next); | |
711 | return false; |
|
438 | return false; | |
712 | } |
|
439 | }; | |
|
440 | ||||
713 | this.nextComment = function(node) { |
|
441 | this.nextComment = function(node) { | |
714 | return self.scrollToComment(node, 1); |
|
442 | return self.scrollToComment(node, 1); | |
715 | } |
|
443 | }; | |
|
444 | ||||
716 | this.prevComment = function(node) { |
|
445 | this.prevComment = function(node) { | |
717 | return self.scrollToComment(node, -1); |
|
446 | return self.scrollToComment(node, -1); | |
718 | } |
|
447 | }; | |
|
448 | ||||
719 | this.deleteComment = function(node) { |
|
449 | this.deleteComment = function(node) { | |
720 | if (!confirm(_gettext('Delete this comment?'))) { |
|
450 | if (!confirm(_gettext('Delete this comment?'))) { | |
721 | return false; |
|
451 | return false; | |
@@ -744,7 +474,8 b' var CommentsController = function() { /*' | |||||
744 | return false; |
|
474 | return false; | |
745 | }; |
|
475 | }; | |
746 | ajaxPOST(url, postData, success, failure); |
|
476 | ajaxPOST(url, postData, success, failure); | |
747 | } |
|
477 | }; | |
|
478 | ||||
748 | this.toggleComments = function(node, show) { |
|
479 | this.toggleComments = function(node, show) { | |
749 | var $filediff = $(node).closest('.filediff'); |
|
480 | var $filediff = $(node).closest('.filediff'); | |
750 | if (show === true) { |
|
481 | if (show === true) { | |
@@ -757,12 +488,14 b' var CommentsController = function() { /*' | |||||
757 | $filediff.toggleClass('hide-comments'); |
|
488 | $filediff.toggleClass('hide-comments'); | |
758 | } |
|
489 | } | |
759 | return false; |
|
490 | return false; | |
760 | } |
|
491 | }; | |
|
492 | ||||
761 | this.toggleLineComments = function(node) { |
|
493 | this.toggleLineComments = function(node) { | |
762 | self.toggleComments(node, true); |
|
494 | self.toggleComments(node, true); | |
763 | var $node = $(node); |
|
495 | var $node = $(node); | |
764 | $node.closest('tr').toggleClass('hide-line-comments'); |
|
496 | $node.closest('tr').toggleClass('hide-line-comments'); | |
765 | } |
|
497 | }; | |
|
498 | ||||
766 | this.createComment = function(node) { |
|
499 | this.createComment = function(node) { | |
767 | var $node = $(node); |
|
500 | var $node = $(node); | |
768 | var $td = $node.closest('td'); |
|
501 | var $td = $node.closest('td'); | |
@@ -832,7 +565,6 b' var CommentsController = function() { /*' | |||||
832 | console.error(e); |
|
565 | console.error(e); | |
833 | } |
|
566 | } | |
834 |
|
567 | |||
835 |
|
||||
836 | // re trigger the linkification of next/prev navigation |
|
568 | // re trigger the linkification of next/prev navigation | |
837 | linkifyComments($('.inline-comment-injected')); |
|
569 | linkifyComments($('.inline-comment-injected')); | |
838 | timeagoActivate(); |
|
570 | timeagoActivate(); | |
@@ -863,7 +595,7 b' var CommentsController = function() { /*' | |||||
863 | } |
|
595 | } | |
864 |
|
596 | |||
865 | $form.addClass('comment-inline-form-open'); |
|
597 | $form.addClass('comment-inline-form-open'); | |
866 | } |
|
598 | }; | |
867 |
|
599 | |||
868 | this.renderInlineComments = function(file_comments) { |
|
600 | this.renderInlineComments = function(file_comments) { | |
869 | show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; |
|
601 | show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; | |
@@ -892,4 +624,4 b' var CommentsController = function() { /*' | |||||
892 | firefoxAnchorFix(); |
|
624 | firefoxAnchorFix(); | |
893 | }; |
|
625 | }; | |
894 |
|
626 | |||
895 | } No newline at end of file |
|
627 | }; No newline at end of file |
@@ -178,9 +178,8 b'' | |||||
178 |
|
178 | |||
179 | ## template for inline comment form |
|
179 | ## template for inline comment form | |
180 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
180 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> | |
181 | ${comment.comment_inline_form()} |
|
|||
182 |
|
181 | |||
183 |
## |
|
182 | ## render comments | |
184 | ${comment.generate_comments()} |
|
183 | ${comment.generate_comments()} | |
185 |
|
184 | |||
186 | ## main comment form and it status |
|
185 | ## main comment form and it status | |
@@ -210,12 +209,12 b'' | |||||
210 | if(button.hasClass("comments-visible")) { |
|
209 | if(button.hasClass("comments-visible")) { | |
211 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ |
|
210 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ | |
212 | $(this).hide(); |
|
211 | $(this).hide(); | |
213 | }) |
|
212 | }); | |
214 | button.removeClass("comments-visible"); |
|
213 | button.removeClass("comments-visible"); | |
215 | } else { |
|
214 | } else { | |
216 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ |
|
215 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ | |
217 | $(this).show(); |
|
216 | $(this).show(); | |
218 | }) |
|
217 | }); | |
219 | button.addClass("comments-visible"); |
|
218 | button.addClass("comments-visible"); | |
220 | } |
|
219 | } | |
221 | }); |
|
220 | }); | |
@@ -230,7 +229,7 b'' | |||||
230 | url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}', |
|
229 | url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}', | |
231 | success: function(data) { |
|
230 | success: function(data) { | |
232 | if(data.results.length === 0){ |
|
231 | if(data.results.length === 0){ | |
233 |
$('#child_link').html( |
|
232 | $('#child_link').html("${_('No Child Commits')}").addClass('disabled'); | |
234 | } |
|
233 | } | |
235 | if(data.results.length === 1){ |
|
234 | if(data.results.length === 1){ | |
236 | var commit = data.results[0]; |
|
235 | var commit = data.results[0]; | |
@@ -263,7 +262,7 b'' | |||||
263 | // >1 links show them to user to choose |
|
262 | // >1 links show them to user to choose | |
264 | if(!$('#parent_link').hasClass('disabled')){ |
|
263 | if(!$('#parent_link').hasClass('disabled')){ | |
265 | $.ajax({ |
|
264 | $.ajax({ | |
266 |
url: '${h.url( |
|
265 | url: '${h.url("changeset_parents",repo_name=c.repo_name, revision=c.commit.raw_id)}', | |
267 | success: function(data) { |
|
266 | success: function(data) { | |
268 | if(data.results.length === 0){ |
|
267 | if(data.results.length === 0){ | |
269 | $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled'); |
|
268 | $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled'); |
@@ -6,14 +6,14 b'' | |||||
6 | <%namespace name="base" file="/base/base.html"/> |
|
6 | <%namespace name="base" file="/base/base.html"/> | |
7 |
|
7 | |||
8 | <%def name="comment_block(comment, inline=False)"> |
|
8 | <%def name="comment_block(comment, inline=False)"> | |
9 | <div |
|
9 | <div class="comment | |
10 | class="comment |
|
10 | ${'comment-inline' if inline else ''} | |
11 | ${'comment-inline' if inline else ''} |
|
11 | ${'comment-outdated' if comment.outdated_at_version(getattr(c, 'at_version', None)) else 'comment-current'}" | |
12 | ${'comment-outdated' if comment.outdated else 'comment-current'}" |
|
12 | id="comment-${comment.comment_id}" | |
13 | " |
|
13 | line="${comment.line_no}" | |
14 |
id=" |
|
14 | data-comment-id="${comment.comment_id}" | |
15 | line="${comment.line_no}" |
|
15 | style="${'display: none;' if comment.outdated_at_version(getattr(c, 'at_version', None)) else ''}"> | |
16 | data-comment-id="${comment.comment_id}"> |
|
16 | ||
17 | <div class="meta"> |
|
17 | <div class="meta"> | |
18 | <div class="author"> |
|
18 | <div class="author"> | |
19 | ${base.gravatar_with_user(comment.author.email, 16)} |
|
19 | ${base.gravatar_with_user(comment.author.email, 16)} | |
@@ -22,21 +22,27 b'' | |||||
22 | ${h.age_component(comment.modified_at, time_is_local=True)} |
|
22 | ${h.age_component(comment.modified_at, time_is_local=True)} | |
23 | </div> |
|
23 | </div> | |
24 | <div class="status-change"> |
|
24 | <div class="status-change"> | |
25 | %if comment.pull_request: |
|
25 | % if comment.pull_request: | |
26 | <a href="${h.url('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id)}"> |
|
26 | % if comment.outdated: | |
27 | %if comment.status_change: |
|
27 | <a href="?version=${comment.pull_request_version_id}#comment-${comment.comment_id}"> | |
28 |
|
|
28 | ${_('Outdated comment from pull request version {}').format(comment.pull_request_version_id)} | |
29 |
|
|
29 | </a> | |
30 | ${_('Comment on pull request #%s') % comment.pull_request.pull_request_id} |
|
30 | % else: | |
31 | %endif |
|
31 | <a href="${h.url('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id)}"> | |
32 | </a> |
|
32 | %if comment.status_change: | |
33 | %else: |
|
33 | ${_('Vote on pull request #%s') % comment.pull_request.pull_request_id}: | |
34 |
|
|
34 | %else: | |
|
35 | ${_('Comment on pull request #%s') % comment.pull_request.pull_request_id} | |||
|
36 | %endif | |||
|
37 | </a> | |||
|
38 | % endif | |||
|
39 | % else: | |||
|
40 | % if comment.status_change: | |||
35 | ${_('Status change on commit')}: |
|
41 | ${_('Status change on commit')}: | |
36 | %else: |
|
42 | % else: | |
37 | ${_('Comment on commit')} |
|
43 | ${_('Comment on commit')} | |
38 | %endif |
|
44 | % endif | |
39 | %endif |
|
45 | % endif | |
40 | </div> |
|
46 | </div> | |
41 | %if comment.status_change: |
|
47 | %if comment.status_change: | |
42 | <div class="${'flag_status %s' % comment.status_change[0].status}"></div> |
|
48 | <div class="${'flag_status %s' % comment.status_change[0].status}"></div> | |
@@ -52,14 +58,19 b'' | |||||
52 | ## show delete comment if it's not a PR (regular comments) or it's PR that is not closed |
|
58 | ## show delete comment if it's not a PR (regular comments) or it's PR that is not closed | |
53 | ## only super-admin, repo admin OR comment owner can delete |
|
59 | ## only super-admin, repo admin OR comment owner can delete | |
54 | %if not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed()): |
|
60 | %if not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed()): | |
|
61 | ## permissions to delete | |||
55 | %if h.HasPermissionAny('hg.admin')() or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id: |
|
62 | %if h.HasPermissionAny('hg.admin')() or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id: | |
56 | ## TODO: dan: add edit comment here |
|
63 | ## TODO: dan: add edit comment here | |
57 |
<a onclick="return Rhodecode.comments.deleteComment(this);" class="delete-comment"> ${_('Delete')}</a> |
|
64 | <a onclick="return Rhodecode.comments.deleteComment(this);" class="delete-comment"> ${_('Delete')}</a> | |
58 | %if not comment.outdated: |
|
65 | %else: | |
59 | <a onclick="return Rhodecode.comments.prevComment(this);" class="prev-comment"> ${_('Prev')}</a> | |
|
66 | <button class="btn-link" disabled="disabled"> ${_('Delete')}</button> | |
60 | <a onclick="return Rhodecode.comments.nextComment(this);" class="next-comment"> ${_('Next')}</a> |
|
|||
61 | %endif |
|
|||
62 | %endif |
|
67 | %endif | |
|
68 | %else: | |||
|
69 | <button class="btn-link" disabled="disabled"> ${_('Delete')}</button> | |||
|
70 | %endif | |||
|
71 | %if not comment.outdated_at_version(getattr(c, 'at_version', None)): | |||
|
72 | | <a onclick="return Rhodecode.comments.prevComment(this);" class="prev-comment"> ${_('Prev')}</a> | |||
|
73 | | <a onclick="return Rhodecode.comments.nextComment(this);" class="next-comment"> ${_('Next')}</a> | |||
63 | %endif |
|
74 | %endif | |
64 |
|
75 | |||
65 | </div> |
|
76 | </div> | |
@@ -67,102 +78,9 b'' | |||||
67 | <div class="text"> |
|
78 | <div class="text"> | |
68 | ${comment.render(mentions=True)|n} |
|
79 | ${comment.render(mentions=True)|n} | |
69 | </div> |
|
80 | </div> | |
70 | </div> |
|
|||
71 | </%def> |
|
|||
72 |
|
81 | |||
73 | <%def name="comment_block_outdated(comment)"> |
|
|||
74 | <div class="comments" id="comment-${comment.comment_id}"> |
|
|||
75 | <div class="comment comment-wrapp"> |
|
|||
76 | <div class="meta"> |
|
|||
77 | <div class="author"> |
|
|||
78 | ${base.gravatar_with_user(comment.author.email, 16)} |
|
|||
79 | </div> |
|
|||
80 | <div class="date"> |
|
|||
81 | ${h.age_component(comment.modified_at, time_is_local=True)} |
|
|||
82 | </div> |
|
|||
83 | %if comment.status_change: |
|
|||
84 | <span class="changeset-status-container"> |
|
|||
85 | <span class="changeset-status-ico"> |
|
|||
86 | <div class="${'flag_status %s' % comment.status_change[0].status}"></div> |
|
|||
87 | </span> |
|
|||
88 | <span title="${_('Commit status')}" class="changeset-status-lbl"> ${comment.status_change[0].status_lbl}</span> |
|
|||
89 | </span> |
|
|||
90 | %endif |
|
|||
91 | <a class="permalink" href="#comment-${comment.comment_id}">¶</a> |
|
|||
92 | ## show delete comment if it's not a PR (regular comments) or it's PR that is not closed |
|
|||
93 | ## only super-admin, repo admin OR comment owner can delete |
|
|||
94 | %if not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed()): |
|
|||
95 | <div class="comment-links-block"> |
|
|||
96 | %if h.HasPermissionAny('hg.admin')() or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id: |
|
|||
97 | <div data-comment-id=${comment.comment_id} class="delete-comment">${_('Delete')}</div> |
|
|||
98 | %endif |
|
|||
99 | </div> |
|
|||
100 | %endif |
|
|||
101 | </div> |
|
|||
102 | <div class="text"> |
|
|||
103 | ${comment.render(mentions=True)|n} |
|
|||
104 | </div> |
|
|||
105 | </div> |
|
|||
106 | </div> |
|
82 | </div> | |
107 | </%def> |
|
83 | </%def> | |
108 |
|
||||
109 | <%def name="comment_inline_form()"> |
|
|||
110 | <div id="comment-inline-form-template" style="display: none;"> |
|
|||
111 | <div class="comment-inline-form ac"> |
|
|||
112 | %if c.rhodecode_user.username != h.DEFAULT_USER: |
|
|||
113 | ${h.form('#', class_='inline-form', method='get')} |
|
|||
114 | <div id="edit-container_{1}" class="clearfix"> |
|
|||
115 | <div class="comment-title pull-left"> |
|
|||
116 | ${_('Create a comment on line {1}.')} |
|
|||
117 | </div> |
|
|||
118 | <div class="comment-help pull-right"> |
|
|||
119 | ${(_('Comments parsed using %s syntax with %s support.') % ( |
|
|||
120 | ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())), |
|
|||
121 | ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user')) |
|
|||
122 | ) |
|
|||
123 | )|n |
|
|||
124 | } |
|
|||
125 | </div> |
|
|||
126 | <div style="clear: both"></div> |
|
|||
127 | <textarea id="text_{1}" name="text" class="comment-block-ta ac-input"></textarea> |
|
|||
128 | </div> |
|
|||
129 | <div id="preview-container_{1}" class="clearfix" style="display: none;"> |
|
|||
130 | <div class="comment-help"> |
|
|||
131 | ${_('Comment preview')} |
|
|||
132 | </div> |
|
|||
133 | <div id="preview-box_{1}" class="preview-box"></div> |
|
|||
134 | </div> |
|
|||
135 | <div class="comment-footer"> |
|
|||
136 | <div class="comment-button hide-inline-form-button cancel-button"> |
|
|||
137 | ${h.reset('hide-inline-form', _('Cancel'), class_='btn hide-inline-form', id_="cancel-btn_{1}")} |
|
|||
138 | </div> |
|
|||
139 | <div class="action-buttons"> |
|
|||
140 | <input type="hidden" name="f_path" value="{0}"> |
|
|||
141 | <input type="hidden" name="line" value="{1}"> |
|
|||
142 | <button id="preview-btn_{1}" class="btn btn-secondary">${_('Preview')}</button> |
|
|||
143 | <button id="edit-btn_{1}" class="btn btn-secondary" style="display: none;">${_('Edit')}</button> |
|
|||
144 | ${h.submit('save', _('Comment'), class_='btn btn-success save-inline-form')} |
|
|||
145 | </div> |
|
|||
146 | ${h.end_form()} |
|
|||
147 | </div> |
|
|||
148 | %else: |
|
|||
149 | ${h.form('', class_='inline-form comment-form-login', method='get')} |
|
|||
150 | <div class="pull-left"> |
|
|||
151 | <div class="comment-help pull-right"> |
|
|||
152 | ${_('You need to be logged in to comment.')} <a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a> |
|
|||
153 | </div> |
|
|||
154 | </div> |
|
|||
155 | <div class="comment-button pull-right"> |
|
|||
156 | ${h.reset('hide-inline-form', _('Hide'), class_='btn hide-inline-form')} |
|
|||
157 | </div> |
|
|||
158 | <div class="clearfix"></div> |
|
|||
159 | ${h.end_form()} |
|
|||
160 | %endif |
|
|||
161 | </div> |
|
|||
162 | </div> |
|
|||
163 | </%def> |
|
|||
164 |
|
||||
165 |
|
||||
166 | ## generate main comments |
|
84 | ## generate main comments | |
167 | <%def name="generate_comments(include_pull_request=False, is_pull_request=False)"> |
|
85 | <%def name="generate_comments(include_pull_request=False, is_pull_request=False)"> | |
168 | <div id="comments"> |
|
86 | <div id="comments"> | |
@@ -182,6 +100,7 b'' | |||||
182 |
|
100 | |||
183 | ## MAIN COMMENT FORM |
|
101 | ## MAIN COMMENT FORM | |
184 | <%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)"> |
|
102 | <%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)"> | |
|
103 | ||||
185 | %if is_compare: |
|
104 | %if is_compare: | |
186 | <% form_id = "comments_form_compare" %> |
|
105 | <% form_id = "comments_form_compare" %> | |
187 | %else: |
|
106 | %else: |
@@ -394,10 +394,13 b' from rhodecode.lib.diffs import NEW_FILE' | |||||
394 | %for comment in comments: |
|
394 | %for comment in comments: | |
395 | ${commentblock.comment_block(comment, inline=True)} |
|
395 | ${commentblock.comment_block(comment, inline=True)} | |
396 | %endfor |
|
396 | %endfor | |
|
397 | ||||
397 | <span onclick="return Rhodecode.comments.createComment(this)" |
|
398 | <span onclick="return Rhodecode.comments.createComment(this)" | |
398 |
class="btn btn-secondary cb-comment-add-button" |
|
399 | class="btn btn-secondary cb-comment-add-button ${'comment-outdated' if comments and comments[-1].outdated else ''}" | |
|
400 | style="${'display: none;' if comments and comments[-1].outdated else ''}"> | |||
399 | ${_('Add another comment')} |
|
401 | ${_('Add another comment')} | |
400 | </span> |
|
402 | </span> | |
|
403 | ||||
401 | </div> |
|
404 | </div> | |
402 | </%def> |
|
405 | </%def> | |
403 |
|
406 |
@@ -918,9 +918,6 b'' | |||||
918 | $(btns).each(fn_display); |
|
918 | $(btns).each(fn_display); | |
919 | }); |
|
919 | }); | |
920 |
|
920 | |||
921 | // inject comments into they proper positions |
|
|||
922 | var file_comments = $('.inline-comment-placeholder'); |
|
|||
923 | renderInlineComments(file_comments); |
|
|||
924 | var commentTotals = {}; |
|
921 | var commentTotals = {}; | |
925 | $.each(file_comments, function(i, comment) { |
|
922 | $.each(file_comments, function(i, comment) { | |
926 | var path = $(comment).attr('path'); |
|
923 | var path = $(comment).attr('path'); |
@@ -165,24 +165,62 b'' | |||||
165 | <div> |
|
165 | <div> | |
166 | <div class="comments-number"> |
|
166 | <div class="comments-number"> | |
167 | %if c.comments: |
|
167 | %if c.comments: | |
168 |
<a href="#comments">${ungettext("%d |
|
168 | <a href="#comments">${ungettext("%d General Comment", "%d General Comments", len(c.comments)) % len(c.comments)}</a>, | |
169 | %else: |
|
169 | %else: | |
170 |
${ungettext("%d |
|
170 | ${ungettext("%d General Comment", "%d General Comments", len(c.comments)) % len(c.comments)} | |
171 | %endif |
|
171 | %endif | |
|
172 | ||||
172 | %if c.inline_cnt: |
|
173 | %if c.inline_cnt: | |
173 | <a href="#" onclick="return Rhodecode.comments.nextComment();" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a> |
|
174 | <a href="#" onclick="return Rhodecode.comments.nextComment();" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a> | |
174 | %else: |
|
175 | %else: | |
175 | ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} |
|
176 | ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} | |
176 | %endif |
|
177 | %endif | |
177 |
|
178 | |||
178 |
|
179 | %if c.outdated_cnt: | ||
179 | % if c.outdated_cnt: |
|
180 | , ${ungettext("%d Outdated Comment", "%d Outdated Comments", c.outdated_cnt) % c.outdated_cnt} <span id="show-outdated-comments" class="btn btn-link">${_('(Show)')}</span> | |
180 | ,${ungettext("%d Outdated Comment", "%d Outdated Comments", c.outdated_cnt) % c.outdated_cnt} <span id="show-outdated-comments" class="btn btn-link">${_('(Show)')}</span> |
|
181 | %endif | |
181 | % endif |
|
|||
182 | </div> |
|
182 | </div> | |
183 | </div> |
|
183 | </div> | |
184 |
|
|
184 | </div> | |
|
185 | ||||
|
186 | </div> | |||
|
187 | ||||
|
188 | <div class="field"> | |||
|
189 | <div class="label-summary"> | |||
|
190 | <label>${_('Versions')}:</label> | |||
185 | </div> |
|
191 | </div> | |
|
192 | <div> | |||
|
193 | <table> | |||
|
194 | <tr> | |||
|
195 | <td> | |||
|
196 | % if c.at_version == None: | |||
|
197 | <i class="icon-ok link"></i> | |||
|
198 | % endif | |||
|
199 | </td> | |||
|
200 | <td><code><a href="${h.url.current()}">latest</a></code></td> | |||
|
201 | <td> | |||
|
202 | <code>${c.pull_request_latest.source_ref_parts.commit_id[:6]}</code> | |||
|
203 | </td> | |||
|
204 | <td>${_('created')} ${h.age_component(c.pull_request.created_on)}</td> | |||
|
205 | </tr> | |||
|
206 | % for ver in reversed(c.pull_request.versions()): | |||
|
207 | <tr> | |||
|
208 | <td> | |||
|
209 | % if c.at_version == ver.pull_request_version_id: | |||
|
210 | <i class="icon-ok link"></i> | |||
|
211 | % endif | |||
|
212 | </td> | |||
|
213 | <td><code><a href="${h.url.current(version=ver.pull_request_version_id)}">version ${ver.pull_request_version_id}</a></code></td> | |||
|
214 | <td> | |||
|
215 | <code>${ver.source_ref_parts.commit_id[:6]}</code> | |||
|
216 | </td> | |||
|
217 | <td>${_('created')} ${h.age_component(ver.created_on)}</td> | |||
|
218 | </tr> | |||
|
219 | % endfor | |||
|
220 | </table> | |||
|
221 | </div> | |||
|
222 | </div> | |||
|
223 | ||||
186 | <div id="pr-save" class="field" style="display: none;"> |
|
224 | <div id="pr-save" class="field" style="display: none;"> | |
187 | <div class="label-summary"></div> |
|
225 | <div class="label-summary"></div> | |
188 | <div class="input"> |
|
226 | <div class="input"> | |
@@ -291,7 +329,9 b'' | |||||
291 | % endif |
|
329 | % endif | |
292 | <div class="compare_view_commits_title"> |
|
330 | <div class="compare_view_commits_title"> | |
293 | % if c.allowed_to_update and not c.pull_request.is_closed(): |
|
331 | % if c.allowed_to_update and not c.pull_request.is_closed(): | |
294 |
<button id="update_commits" class="btn |
|
332 | <button id="update_commits" class="btn pull-right">${_('Update commits')}</button> | |
|
333 | % else: | |||
|
334 | <button class="btn disabled pull-right" disabled="disabled">${_('Update commits')}</button> | |||
295 | % endif |
|
335 | % endif | |
296 | % if len(c.commit_ranges): |
|
336 | % if len(c.commit_ranges): | |
297 | <h2>${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}</h2> |
|
337 | <h2>${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}</h2> | |
@@ -305,7 +345,7 b'' | |||||
305 | ${cbdiffs.render_diffset( |
|
345 | ${cbdiffs.render_diffset( | |
306 | c.diffset, use_comments=True, |
|
346 | c.diffset, use_comments=True, | |
307 | collapse_when_files_over=30, |
|
347 | collapse_when_files_over=30, | |
308 |
disable_new_comments= |
|
348 | disable_new_comments=not c.allowed_to_comment)} | |
309 |
|
349 | |||
310 | </div> |
|
350 | </div> | |
311 | % endif |
|
351 | % endif | |
@@ -313,9 +353,8 b'' | |||||
313 |
|
353 | |||
314 | ## template for inline comment form |
|
354 | ## template for inline comment form | |
315 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
355 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> | |
316 | ${comment.comment_inline_form()} |
|
|||
317 |
|
356 | |||
318 |
## render comments |
|
357 | ## render general comments | |
319 | ${comment.generate_comments(include_pull_request=True, is_pull_request=True)} |
|
358 | ${comment.generate_comments(include_pull_request=True, is_pull_request=True)} | |
320 |
|
359 | |||
321 | % if not c.pull_request.is_closed(): |
|
360 | % if not c.pull_request.is_closed(): | |
@@ -394,7 +433,7 b'' | |||||
394 | this.closeButton.hide(); |
|
433 | this.closeButton.hide(); | |
395 | this.addButton.hide(); |
|
434 | this.addButton.hide(); | |
396 | this.removeButtons.css('visibility', 'hidden'); |
|
435 | this.removeButtons.css('visibility', 'hidden'); | |
397 |
} |
|
436 | } | |
398 | }; |
|
437 | }; | |
399 |
|
438 | |||
400 | PRDetails.init(); |
|
439 | PRDetails.init(); | |
@@ -402,7 +441,7 b'' | |||||
402 |
|
441 | |||
403 | $('#show-outdated-comments').on('click', function(e){ |
|
442 | $('#show-outdated-comments').on('click', function(e){ | |
404 | var button = $(this); |
|
443 | var button = $(this); | |
405 | var outdated = $('.outdated'); |
|
444 | var outdated = $('.comment-outdated'); | |
406 | if (button.html() === "(Show)") { |
|
445 | if (button.html() === "(Show)") { | |
407 | button.html("(Hide)"); |
|
446 | button.html("(Hide)"); | |
408 | outdated.show(); |
|
447 | outdated.show(); | |
@@ -428,29 +467,6 b'' | |||||
428 | $(btns).each(fn_display); |
|
467 | $(btns).each(fn_display); | |
429 | }); |
|
468 | }); | |
430 |
|
469 | |||
431 | // inject comments into their proper positions |
|
|||
432 | var file_comments = $('.inline-comment-placeholder'); |
|
|||
433 | %if c.pull_request.is_closed(): |
|
|||
434 | renderInlineComments(file_comments, false); |
|
|||
435 | %else: |
|
|||
436 | renderInlineComments(file_comments, true); |
|
|||
437 | %endif |
|
|||
438 | var commentTotals = {}; |
|
|||
439 | $.each(file_comments, function(i, comment) { |
|
|||
440 | var path = $(comment).attr('path'); |
|
|||
441 | var comms = $(comment).children().length; |
|
|||
442 | if (path in commentTotals) { |
|
|||
443 | commentTotals[path] += comms; |
|
|||
444 | } else { |
|
|||
445 | commentTotals[path] = comms; |
|
|||
446 | } |
|
|||
447 | }); |
|
|||
448 | $.each(commentTotals, function(path, total) { |
|
|||
449 | var elem = $('.comment-bubble[data-path="'+ path +'"]'); |
|
|||
450 | elem.css('visibility', 'visible'); |
|
|||
451 | elem.html(elem.html() + ' ' + total ); |
|
|||
452 | }); |
|
|||
453 |
|
||||
454 | $('#merge_pull_request_form').submit(function() { |
|
470 | $('#merge_pull_request_form').submit(function() { | |
455 | if (!$('#merge_pull_request').attr('disabled')) { |
|
471 | if (!$('#merge_pull_request').attr('disabled')) { | |
456 | $('#merge_pull_request').attr('disabled', 'disabled'); |
|
472 | $('#merge_pull_request').attr('disabled', 'disabled'); |
General Comments 0
You need to be logged in to leave comments.
Login now