Index: trunk/extensions/CodeReview/CodeReview.i18n.php |
— | — | @@ -40,6 +40,7 @@ |
41 | 41 | 'code-author-link' => 'link?', |
42 | 42 | 'code-author-unlink' => 'unlink?', |
43 | 43 | 'code-author-unlinksuccess' => 'Author $1 has been unlinked', |
| 44 | + 'code-browsing-path' => "Browsing revisions in '''$1'''", |
44 | 45 | 'code-field-id' => 'Revision', |
45 | 46 | 'code-field-author' => 'Author', |
46 | 47 | 'code-field-user' => 'Commenter', |
Index: trunk/extensions/CodeReview/backend/CodeRevision.php |
— | — | @@ -629,28 +629,49 @@ |
630 | 630 | return $out; |
631 | 631 | } |
632 | 632 | |
633 | | - public function getPrevious() { |
634 | | - // hack! |
635 | | - if ( $this->mId > 1 ) { |
636 | | - return $this->mId - 1; |
| 633 | + public function getPrevious( $path = '' ) { |
| 634 | + $dbr = wfGetDB( DB_SLAVE ); |
| 635 | + $encId = $dbr->addQuotes( $this->mId ); |
| 636 | + $tables = array( 'code_rev' ); |
| 637 | + if ( $path != '' ) { |
| 638 | + $conds = $this->getPathConds( $path ); |
| 639 | + $order = 'cp_rev_id DESC'; |
| 640 | + $tables[] = 'code_paths'; |
637 | 641 | } else { |
| 642 | + $conds = array( 'cr_repo_id' => $this->mRepoId ); |
| 643 | + $order = 'cr_id DESC'; |
| 644 | + } |
| 645 | + $conds[] = "cr_id < $encId"; |
| 646 | + $row = $dbr->selectRow( $tables, 'cr_id', |
| 647 | + $conds, |
| 648 | + __METHOD__, |
| 649 | + array( 'ORDER BY' => $order ) |
| 650 | + ); |
| 651 | + if ( $row ) { |
| 652 | + return intval( $row->cr_id ); |
| 653 | + } else { |
638 | 654 | return false; |
639 | 655 | } |
640 | 656 | } |
641 | 657 | |
642 | | - public function getNext() { |
| 658 | + public function getNext( $path = '' ) { |
643 | 659 | $dbr = wfGetDB( DB_SLAVE ); |
644 | 660 | $encId = $dbr->addQuotes( $this->mId ); |
645 | | - $row = $dbr->selectRow( 'code_rev', |
646 | | - 'cr_id', |
647 | | - array( |
648 | | - 'cr_repo_id' => $this->mRepoId, |
649 | | - "cr_id > $encId" ), |
| 661 | + $tables = array( 'code_rev' ); |
| 662 | + if ( $path != '' ) { |
| 663 | + $conds = $this->getPathConds( $path ); |
| 664 | + $order = 'cp_rev_id ASC'; |
| 665 | + $tables[] = 'code_paths'; |
| 666 | + } else { |
| 667 | + $conds = array( 'cr_repo_id' => $this->mRepoId ); |
| 668 | + $order = 'cr_id ASC'; |
| 669 | + } |
| 670 | + $conds[] = "cr_id > $encId"; |
| 671 | + $row = $dbr->selectRow( $tables, 'cr_id', |
| 672 | + $conds, |
650 | 673 | __METHOD__, |
651 | | - array( |
652 | | - 'ORDER BY' => 'cr_repo_id, cr_id', |
653 | | - 'LIMIT' => 1 ) ); |
654 | | - |
| 674 | + array( 'ORDER BY' => $order ) |
| 675 | + ); |
655 | 676 | if ( $row ) { |
656 | 677 | return intval( $row->cr_id ); |
657 | 678 | } else { |
— | — | @@ -658,19 +679,37 @@ |
659 | 680 | } |
660 | 681 | } |
661 | 682 | |
662 | | - public function getNextUnresolved() { |
| 683 | + protected function getPathConds( $path ) { |
663 | 684 | $dbr = wfGetDB( DB_SLAVE ); |
| 685 | + return array( |
| 686 | + 'cp_repo_id' => $this->mRepoId, |
| 687 | + 'cp_path LIKE ' . $dbr->addQuotes( $dbr->escapeLike( $path ) . '%' ), |
| 688 | + // performance |
| 689 | + 'cp_rev_id > ' . $this->mRepo->getLastStoredRev() - 20000, |
| 690 | + // join conds |
| 691 | + 'cr_repo_id = cp_repo_id', |
| 692 | + 'cr_id = cp_rev_id' |
| 693 | + ); |
| 694 | + } |
| 695 | + |
| 696 | + public function getNextUnresolved( $path = '' ) { |
| 697 | + $dbr = wfGetDB( DB_SLAVE ); |
664 | 698 | $encId = $dbr->addQuotes( $this->mId ); |
665 | | - $row = $dbr->selectRow( 'code_rev', |
666 | | - 'cr_id', |
667 | | - array( |
668 | | - 'cr_repo_id' => $this->mRepoId, |
669 | | - "cr_id > $encId", |
670 | | - 'cr_status' => array( 'new', 'fixme' ) ), |
| 699 | + $tables = array( 'code_rev' ); |
| 700 | + if ( $path != '' ) { |
| 701 | + $conds = $this->getPathConds( $path ); |
| 702 | + $order = 'cp_rev_id ASC'; |
| 703 | + $tables[] = 'code_paths'; |
| 704 | + } else { |
| 705 | + $conds = array( 'cr_repo_id' => $this->mRepoId ); |
| 706 | + $order = 'cr_id ASC'; |
| 707 | + } |
| 708 | + $conds[] = "cr_id > $encId"; |
| 709 | + $conds['cr_status'] = array( 'new', 'fixme' ); |
| 710 | + $row = $dbr->selectRow( $tables, 'cr_id', |
| 711 | + $conds, |
671 | 712 | __METHOD__, |
672 | | - array( |
673 | | - 'ORDER BY' => 'cr_repo_id, cr_id', |
674 | | - 'LIMIT' => 1 ) |
| 713 | + array( 'ORDER BY' => $order ) |
675 | 714 | ); |
676 | 715 | if ( $row ) { |
677 | 716 | return intval( $row->cr_id ); |
Index: trunk/extensions/CodeReview/ui/CodeRevisionCommitter.php |
— | — | @@ -53,9 +53,10 @@ |
54 | 54 | $dbw->commit(); |
55 | 55 | |
56 | 56 | // Return to rev page |
57 | | - if ( !$redirTitle ) { |
| 57 | + if ( !$redirTarget ) { |
58 | 58 | if ( $this->jumpToNext ) { |
59 | | - if ( $next = $this->mRev->getNextUnresolved() ) { |
| 59 | + $next = $this->mRev->getNextUnresolved( $this->mPath ); |
| 60 | + if ( $next ) { |
60 | 61 | $redirTitle = SpecialPage::getTitleFor( 'Code', $this->mRepo->getName() . '/' . $next ); |
61 | 62 | } else { |
62 | 63 | $redirTitle = SpecialPage::getTitleFor( 'Code', $this->mRepo->getName() ); |
— | — | @@ -65,7 +66,7 @@ |
66 | 67 | $redirTitle = $redirTarget ? $redirTarget : $this->revLink(); |
67 | 68 | } |
68 | 69 | } |
69 | | - $wgOut->redirect( $redirTitle->getFullUrl() ); |
| 70 | + $wgOut->redirect( $redirTitle->getFullUrl( array('path' => $this->mPath) ) ); |
70 | 71 | } |
71 | 72 | |
72 | 73 | public function validPost( $permission ) { |
Index: trunk/extensions/CodeReview/ui/CodeRevisionListView.php |
— | — | @@ -238,7 +238,10 @@ |
239 | 239 | case 'cr_id': |
240 | 240 | return $this->mView->mSkin->link( |
241 | 241 | SpecialPage::getTitleFor( 'Code', $this->mRepo->getName() . '/' . $value ), |
242 | | - htmlspecialchars( $value ) ); |
| 242 | + htmlspecialchars( $value ), |
| 243 | + array(), |
| 244 | + array( 'path' => $this->mView->mPath ) |
| 245 | + ); |
243 | 246 | case 'cr_status': |
244 | 247 | return $this->mView->mSkin->link( |
245 | 248 | SpecialPage::getTitleFor( 'Code', $this->mRepo->getName() . '/status/' . $value ), |
Index: trunk/extensions/CodeReview/ui/CodeRevisionView.php |
— | — | @@ -7,8 +7,14 @@ |
8 | 8 | global $wgRequest; |
9 | 9 | parent::__construct(); |
10 | 10 | $this->mRepo = CodeRepository::newFromName( $repoName ); |
11 | | - $this->mRev = $this->mRepo ? $this->mRepo->getRevision( intval( ltrim( $rev, 'r' ) ) ) : null; |
| 11 | + $this->mRev = $this->mRepo ? |
| 12 | + $this->mRepo->getRevision( intval( ltrim( $rev, 'r' ) ) ) : null; |
12 | 13 | $this->mPreviewText = false; |
| 14 | + # Search path for navigation links |
| 15 | + $this->mPath = htmlspecialchars( trim( $wgRequest->getVal( 'path' ) ) ); |
| 16 | + if ( strlen( $this->mPath ) && $this->mPath[0] !== '/' ) { |
| 17 | + $this->mPath = "/{$this->mPath}"; // make sure this is a valid path |
| 18 | + } |
13 | 19 | # URL params... |
14 | 20 | $this->mAddTags = $wgRequest->getText( 'wpTag' ); |
15 | 21 | $this->mRemoveTags = $wgRequest->getText( 'wpRemoveTag' ); |
— | — | @@ -74,7 +80,12 @@ |
75 | 81 | ); |
76 | 82 | $special = SpecialPage::getTitleFor( 'Code', $this->mRepo->getName() . '/' . $this->mRev->getId() ); |
77 | 83 | |
78 | | - $html = Xml::openElement( 'form', array( 'action' => $special->getLocalUrl(), 'method' => 'post' ) ); |
| 84 | + $html = ''; |
| 85 | + if( $this->mPath != '' ) { |
| 86 | + $html .= wfMsgExt( 'code-browsing-path', 'parse', $this->mPath ); |
| 87 | + } |
| 88 | + # Output form |
| 89 | + $html .= Xml::openElement( 'form', array( 'action' => $special->getLocalUrl(), 'method' => 'post' ) ); |
79 | 90 | |
80 | 91 | if ( $this->canPostComments() ) { |
81 | 92 | $html .= $this->addActionButtons(); |
— | — | @@ -134,15 +145,16 @@ |
135 | 146 | global $wgLang; |
136 | 147 | |
137 | 148 | $rev = $this->mRev->getId(); |
138 | | - $prev = $this->mRev->getPrevious(); |
139 | | - $next = $this->mRev->getNext(); |
| 149 | + $prev = $this->mRev->getPrevious( $this->mPath ); |
| 150 | + $next = $this->mRev->getNext( $this->mPath ); |
140 | 151 | $repo = $this->mRepo->getName(); |
141 | 152 | |
142 | 153 | $links = array(); |
143 | 154 | |
144 | 155 | if ( $prev ) { |
145 | 156 | $prevTarget = SpecialPage::getTitleFor( 'Code', "$repo/$prev" ); |
146 | | - $links[] = '< ' . $this->mSkin->link( $prevTarget, "r$prev" ); |
| 157 | + $links[] = '< ' . $this->mSkin->link( $prevTarget, "r$prev", |
| 158 | + array(), array('path' => $this->mPath) ); |
147 | 159 | } |
148 | 160 | |
149 | 161 | $revText = "<b>r$rev</b>"; |
— | — | @@ -156,7 +168,8 @@ |
157 | 169 | |
158 | 170 | if ( $next ) { |
159 | 171 | $nextTarget = SpecialPage::getTitleFor( 'Code', "$repo/$next" ); |
160 | | - $links[] = $this->mSkin->link( $nextTarget, "r$next" ) . ' >'; |
| 172 | + $links[] = $this->mSkin->link( $nextTarget, "r$next", |
| 173 | + array(), array('path' => $this->mPath) ) . ' >'; |
161 | 174 | } |
162 | 175 | |
163 | 176 | return $wgLang->pipeList( $links ); |
— | — | @@ -608,6 +621,7 @@ |
609 | 622 | return '<div class="mw-codereview-post-comment">' . |
610 | 623 | $preview . |
611 | 624 | Xml::hidden( 'wpEditToken', $wgUser->editToken() ) . |
| 625 | + Xml::hidden( 'path', $this->mPath ) . |
612 | 626 | ( $parent ? Xml::hidden( 'wpParent', $parent ) : '' ) . |
613 | 627 | '<div>' . |
614 | 628 | Xml::openElement( 'textarea', array( |