Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2d695e1

Browse files
authoredApr 9, 2021
Merge pull request #85 from topcoder-platform/develop
v1.5
2 parents 38f6cc5 + 322e0d2 commit 2d695e1

File tree

13 files changed

+481
-61
lines changed

13 files changed

+481
-61
lines changed
 
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
use Garden\Web\Exception\ClientException;
4+
use Garden\Schema\Schema;
5+
use Vanilla\Utility\InstanceValidatorSchema;
6+
use Garden\Web\Data;
7+
use Garden\Web\Exception\NotFoundException;
8+
use Garden\Web\Exception\ServerException;
9+
use Vanilla\ApiUtils;
10+
11+
/**
12+
* SQL API Controller for the `/service` resource.
13+
*/
14+
class ServiceApiController extends AbstractApiController {
15+
/**
16+
*
17+
* @param array $query The query string.
18+
* @return Data
19+
*/
20+
public function get_tidewayslog($path='/var/log/tideways/daemon.log') {
21+
$this->permission('Garden.Settings.Manage');
22+
23+
if (file_exists($path)) {
24+
//Get file type and set it as Content Type
25+
$finfo = finfo_open(FILEINFO_MIME_TYPE);
26+
header('Content-Type: ' . finfo_file($finfo, $path));
27+
finfo_close($finfo);
28+
29+
header('Content-Description: File Transfer');
30+
header('Content-Disposition: attachment; filename='.basename($path));
31+
header('Expires: 0');
32+
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
33+
header('Pragma: public');
34+
header('Content-Length: ' . filesize($path));
35+
ob_clean();
36+
flush();
37+
readfile($path);
38+
exit;
39+
} else {
40+
throw notFoundException('File');
41+
}
42+
}
43+
44+
}

‎DebugPlugin/controllers/api/SqlApiController.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@ public function index(array $query) {
2222
$this->permission('Garden.Settings.Manage');
2323

2424
$in = $this->schema([
25-
'sql:s' => 'Sql query'
25+
'sql:s' => 'Sql query',
26+
'type:s' => 'Type'
2627
], 'in')->setDescription('Get a list of records.');
2728

2829
$query = $in->validate($query);
2930
$sql = $query['sql'];
31+
$type = $query['type'];
3032

31-
if (strpos(strtolower($sql), 'select') !== 0) {
32-
throw new ClientException('Unable to execute this query.');
33-
}
33+
// if (strpos(strtolower($sql), 'select') !== 0) {
34+
// throw new ClientException('Unable to execute this query.');
35+
// }
3436

35-
$data = Gdn::sql()->query($sql, 'select')->resultArray();
37+
$data = Gdn::sql()->query($sql, $type)->resultArray();
3638
return $data;
3739
}
3840

‎DebugPlugin/openapi/service.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
openapi: 3.0.2
2+
info: Vanilla Service API
3+
paths:
4+
/service/tidewayslog:
5+
get:
6+
responses:
7+
'200':
8+
content:
9+
'text/plain':
10+
schema:
11+
type: string
12+
description: Success
13+
tags:
14+
- Services
15+
summary: File.

‎DebugPlugin/openapi/sql.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ paths:
44
/sql:
55
get:
66
parameters:
7-
- description: SQL select query.
7+
- description: SQL query.
88
in: query
99
name: sql
1010
schema:
1111
type: string
12+
- description: SQL type query.
13+
in: query
14+
name: type
15+
schema:
16+
type: string
1217
responses:
1318
'200':
1419
content:

‎ReplyTo/class.replyto.plugin.php

Lines changed: 105 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class ReplyToPlugin extends Gdn_Plugin {
1010
const QUERY_PARAMETER_VIEW='view';
1111
const VIEW_FLAT = 'flat';
1212
const VIEW_THREADED = 'threaded';
13+
const VIEW_MODE = 'ReplyTo.ViewMode';
1314

1415
private $replyToModel;
1516
/**
@@ -56,32 +57,110 @@ public function assetModel_styleCss_handler($sender) {
5657
// Set JS for this plugin.
5758
protected function prepareController(&$sender) {
5859
$sender->addJsFile('replyto.js', 'plugins/ReplyTo');
60+
}
61+
62+
/**
63+
* Set a view mode for Discussion Controller
64+
* View Mode is calculated from request url.
65+
* Flat mode is used - '/discussion/{DiscussionID}/p{Page}
66+
* Threaded mode is used by default
67+
*
68+
* @param $sender
69+
* @param $args
70+
*/
71+
public function discussionController_initialize_handler($sender, $args) {
72+
$viewMode = self::getViewMode();
73+
$sender->setData(self::VIEW_MODE, $viewMode);
74+
75+
}
76+
77+
/**
78+
* Set a view mode for Post Controller
79+
* Replying to a comment and leaving a comment are processed by Post Controller.
80+
* (the url 'post/comment/, 'post' method).
81+
* Use HTTP_REFERER to get the current view mode
82+
* @param $sender
83+
* @param $args
84+
*/
85+
public function postController_initialize_handler($sender, $args) {
86+
if(isset($_SERVER['HTTP_REFERER'])) {
87+
$url = $_SERVER['HTTP_REFERER'];
88+
}
89+
parse_str( parse_url( $url, PHP_URL_QUERY), $array );
90+
$viewMode = $array[self::QUERY_PARAMETER_VIEW];
91+
if(!$viewMode) {
92+
$viewMode = self::isPagingUrl($url)? self::VIEW_FLAT: self::VIEW_THREADED;
93+
}
94+
$sender->setData(self::VIEW_MODE, $viewMode);
5995
}
6096

6197
public function discussionController_render_before(&$sender) {
6298
$this->prepareController($sender);
6399
}
64100

101+
/**
102+
* After deleting a comment in a threaded view, the comment tree should be re-rendered
103+
* because tree left/right might be changed if a parent comment has been deleted.
104+
* deliveryType is VIEW in a threaded view
105+
* deliveryType is BOOL in a flat view. Don't re-render a view. Deleted comment
106+
* is hidden on the client.
107+
*
108+
* @param $sender
109+
* @param $args
110+
*/
111+
public function discussionController_AfterCommentDeleted_handler($sender, $args) {
112+
$viewMode = $sender->data('ReplyTo.ViewMode');
113+
if($sender->deliveryMethod() == DELIVERY_METHOD_JSON) {
114+
$discussionID = $args['DiscussionID'];
115+
$sender->json(self::VIEW_MODE, $viewMode);
116+
if ($viewMode == self::VIEW_THREADED) {
117+
// Show all comments
118+
$commentModel = new CommentModel();
119+
$CountComments = $commentModel->getCountByDiscussion($discussionID);
120+
$sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $CountComments, 0));
121+
$sender->ClassName = 'DiscussionController';
122+
$sender->ControllerName = 'discussion';
123+
$sender->View = 'comments';
124+
}
125+
}
126+
}
127+
65128
public function postController_render_before($sender) {
66129
$this->prepareController($sender);
67130
}
68131

69132
/**
70-
* Add View Mode before rendering comments
133+
* The 'beforeCommentRender' are fired by DiscussionController and PostController.
134+
* Re-render a comment tree if new comment is added in threaded view.
135+
*
71136
* @param $sender
72137
* @param $args
73138
*/
74-
public function base_beforeCommentsRender_handler($sender, $args) {
75-
$viewMode = self::getViewMode();
76-
$sender->setData('ViewMode', $viewMode);
139+
public function base_beforeCommentRender_handler($sender, $args) {
140+
// Editing existing comment or new comment added
141+
if ($sender->deliveryType() != DELIVERY_TYPE_DATA) {
142+
$sender->json('ReplyTo.ViewMode', $sender->data(self::VIEW_MODE));
143+
$isNewComment = $sender->data('NewComments');
144+
if($isNewComment) {
145+
$discussionID = val('DiscussionID', $args['Discussion']);
146+
$commentModel = new CommentModel();
147+
$countComments = $commentModel->getCountByDiscussion($discussionID);
148+
// FIX: https://github.com/topcoder-platform/forums/issues/511
149+
// Render a full comment tree in threaded mode
150+
if($sender->data(self::VIEW_MODE) == self::VIEW_THREADED) {
151+
// Show all comments
152+
$sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $countComments, 0));
153+
}
154+
}
155+
}
77156
}
78157

79158
/**
80159
* Render View options for a discussion
81160
* @param $sender
82161
* @param $args
83162
*/
84-
public function base_InlineDiscussionOptionsLeft_handler($sender, $args){
163+
public function discussionController_InlineDiscussionOptionsLeft_handler($sender, $args){
85164
$discussion = $sender->data('Discussion');
86165
if (!$discussion) {
87166
return;
@@ -92,7 +171,7 @@ public function base_InlineDiscussionOptionsLeft_handler($sender, $args){
92171
}
93172

94173
$discussionUrl = discussionUrl($discussion, '', '/');
95-
$viewMode = self::getViewMode();
174+
$viewMode = $sender->data(self::VIEW_MODE);
96175

97176
echo '<span class="ReplyViewOptions">';
98177
echo '<span class="MLabel">View:&nbsp</span>';
@@ -143,8 +222,16 @@ public function commentModel_deleteComment_handler(&$Sender) {
143222
$this->replyToModel->onDeleteComment($Comment);
144223
}
145224

225+
/**
226+
* Set offset and limit depends on view mode.
227+
* In the threaded mode, all comments are displayed.
228+
* In the flat mode, comments are displayed with pagination.
229+
* The hook is used when rendering a discussion page with comments
230+
* @param $sender
231+
* @param $args
232+
*/
146233
public function discussionController_BeforeCalculatingOffsetLimit_handler($sender, $args) {
147-
$viewMode = self::getViewMode();
234+
$viewMode = $sender->data(self::VIEW_MODE);
148235
// $offsetProvided = $args['OffsetProvided'];
149236
$discussion = $args['Discussion'];
150237
$offset = & $args['Offset'];
@@ -179,7 +266,7 @@ public function discussionController_beforeDiscussionRender_handler($sender, $ar
179266
return;
180267
}
181268

182-
$viewMode = self::getViewMode();
269+
$viewMode = $sender->data(self::VIEW_MODE);
183270
if($viewMode == self::VIEW_FLAT) {
184271
return;
185272
}
@@ -222,19 +309,16 @@ public function base_commentOptions_handler($sender, $args) {
222309
'Class' => 'ReplyComment'
223310
];
224311

225-
$viewMode = self::getViewMode();
312+
$viewMode = $sender->data(self::VIEW_MODE);
313+
$deliveryType = $viewMode == self::VIEW_THREADED? DELIVERY_TYPE_VIEW : DELIVERY_TYPE_BOOL;
226314
foreach ($options as $key => $value) {
227-
$currentUrl = $options[$key]['Url'];
228-
if (strpos($currentUrl, '?') !== false ) {
229-
if (strpos($currentUrl, 'Target') !== false) {
230-
$options[$key]['Url'] = $currentUrl.urlencode('?view='.$viewMode);
231-
} else {
232-
$options[$key]['Url'] = $currentUrl. '&view=' . $viewMode;
233-
}
234-
} else {
235-
$options[$key]['Url'] = $currentUrl.'?view='.$viewMode;
315+
$options[$key]['Url'] = strpos($options[$key]['Url'], '?') !== false ? $options[$key]['Url']: $options[$key]['Url'].'?';
316+
$options[$key]['Url'] .= '&view=' . $viewMode;
317+
if($key == 'DeleteComment') {
318+
$options[$key]['Url'] .='&deliveryType='.$deliveryType;
236319
}
237320
}
321+
238322
}
239323

240324
/**
@@ -276,7 +360,7 @@ public function base_inlineDiscussionOptions_handler($sender, $args) {
276360
* @param $args
277361
*/
278362
public function base_beforeCommentDisplay_handler($sender, $args) {
279-
if($sender->deliveryType() != DELIVERY_TYPE_ALL) {
363+
if($sender->deliveryType() != DELIVERY_TYPE_ALL) { // Editing a comment is processed by PostController
280364
// Ajax request to post new comments or update comments
281365
if(isset($_SERVER['HTTP_REFERER'])) {
282366
$previous = $_SERVER['HTTP_REFERER'];
@@ -286,13 +370,13 @@ public function base_beforeCommentDisplay_handler($sender, $args) {
286370
if(!$viewMode) {
287371
$viewMode = self::isPagingUrl($previous) ? self::VIEW_FLAT : self::VIEW_THREADED;
288372
}
289-
$sender->setData('ViewMode', $viewMode);
373+
$sender->setData(self::VIEW_MODE, $viewMode);
290374
if($viewMode == self::VIEW_THREADED) {
291375
$this->buildCommentReplyToCssClasses($sender);
292376
}
293377
}
294378
} else {
295-
$viewMode = self::getViewMode();
379+
$viewMode = $sender->data(self::VIEW_MODE);
296380
if($viewMode == self::VIEW_THREADED) {
297381
$this->buildCommentReplyToCssClasses($sender);
298382
}

‎ReplyTo/js/replyto.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ jQuery(document).ready(function($) {
44
return (href.split(name + '=')[1] || '').split('&')[0];
55
}
66

7-
//If view is not flat, reload a page to rebuild a tree
8-
function reloadPage() {
9-
var currentView = param(window.location.href, 'view');
10-
return currentView == 'threaded';
11-
}
12-
137
$(document).on('click','a.ReplyComment', function(ev) {
148
var btn = this;
159
var parent = $(btn).parents('.MainContent');
@@ -61,25 +55,6 @@ jQuery(document).ready(function($) {
6155
return false;
6256
});
6357

64-
65-
// Comment was added.
66-
$(document).on('CommentAdded',function(ev) {
67-
if (reloadPage() === true) {
68-
window.location.reload();
69-
return false;
70-
}
71-
return false;
72-
});
73-
74-
// Comment was deleted.
75-
$(document).on('CommentDeleted',function(ev) {
76-
if (reloadPage() === true) {
77-
window.location.reload();
78-
return false;
79-
}
80-
return false;
81-
});
82-
8358
$(document).on('click','a.CancelReplyComment', function(ev) {
8459
clearReplyCommentForm(this);
8560
return false;

‎Topcoder/class.topcoder.plugin.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,6 +1892,10 @@ private static function topcoderUserTopcoderCache($userFields) {
18921892
return $cached;
18931893
}
18941894

1895+
public static function isUnclickableUser($userName) {
1896+
return strtolower($userName) == 'tcadmin';
1897+
}
1898+
18951899
public static function log($message, $data = []) {
18961900
if (c('Vanilla.SSO.Debug') || c('Debug')) {
18971901
Logger::event(
@@ -2046,7 +2050,8 @@ function userPhoto($user, $options = []) {
20462050

20472051
$isTopcoderAdmin = val('IsAdmin', $topcoderProfile);
20482052
$photoUrl = isset($photoUrl) && !empty(trim($photoUrl)) ? $photoUrl: UserModel::getDefaultAvatarUrl();
2049-
$href = (val('NoLink', $options)) ? '' : ' href="'.url($userLink).'"';
2053+
$isUnlickableUser = TopcoderPlugin::isUnclickableUser($name);
2054+
$href = (val('NoLink', $options)) || $isUnlickableUser ? '' : ' href="'.url($userLink).'"';
20502055

20512056
Gdn::controller()->EventArguments['User'] = $user;
20522057
Gdn::controller()->EventArguments['Title'] =& $title;
@@ -2136,7 +2141,8 @@ function userAnchor($user, $cssClass = null, $options = null) {
21362141
}
21372142

21382143
// Go to Topcoder user profile link instead of Vanilla profile link
2139-
$userUrl = topcoderUserUrl($user, $px);
2144+
$isUnlickableUser = TopcoderPlugin::isUnclickableUser($name);
2145+
$userUrl = $isUnlickableUser? '#' : topcoderUserUrl($user, $px);
21402146

21412147
$topcoderProfile = TopcoderPlugin::getTopcoderUser($userID);
21422148
$topcoderRating = val('Rating',$topcoderProfile, false);
@@ -2150,6 +2156,11 @@ function userAnchor($user, $cssClass = null, $options = null) {
21502156
$attributes['class'] = $attributes['class'].' '. 'topcoderAdmin' ;
21512157
}
21522158

2159+
if($isUnlickableUser) {
2160+
$attributes['class'] = $attributes['class'].' '. 'disabledLink' ;
2161+
}
2162+
2163+
21532164
Gdn::controller()->EventArguments['User'] = $user;
21542165
Gdn::controller()->EventArguments['IsTopcoderAdmin'] =$isTopcoderAdmin;
21552166
Gdn::controller()->EventArguments['Text'] =& $text;
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php
2+
/**
3+
* Watching controller
4+
*
5+
*/
6+
7+
/**
8+
* Handles displaying watched discussions and watched categories
9+
*
10+
*/
11+
class WatchingController extends VanillaController {
12+
13+
/** @var arrayModels to include. */
14+
public $Uses = ['Database', 'DiscussionModel', 'Form'];
15+
16+
/**
17+
* Highlight route and include JS, CSS, and modules used by all methods.
18+
*
19+
* Always called by dispatcher before controller's requested method.
20+
*
21+
* @since 2.0.0
22+
* @access public
23+
*/
24+
public function initialize() {
25+
parent::initialize();
26+
$this->Menu->highlightRoute('/watching');
27+
28+
/**
29+
* The default Cache-Control header does not include no-store, which can cause issues (e.g. inaccurate unread
30+
* status or new comment counts) when users visit the discussion list via the browser's back button. The same
31+
* check is performed here as in Gdn_Controller before the Cache-Control header is added, but this value
32+
* includes the no-store specifier.
33+
*/
34+
if (Gdn::session()->isValid()) {
35+
$this->setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate');
36+
}
37+
38+
$this->CountCommentsPerPage = c('Vanilla.Comments.PerPage', 30);
39+
$this->fireEvent('AfterInitialize');
40+
}
41+
42+
/**
43+
* Display categorioes and discussions the user has watched
44+
*
45+
* @param string $cp Category page
46+
* @param string $dp Discussion page
47+
* @throws Exception
48+
*/
49+
public function index($cp = '', $dp = '') {
50+
$this->addJsFile('jquery.gardenmorepager.js');
51+
$this->addJsFile('topcoder.js');
52+
$this->permission('Garden.SignIn.Allow');
53+
Gdn_Theme::section('CategoryList');
54+
55+
// Sort filter is used for categories and discussions
56+
$sort = Gdn::request()->get('sort', null);
57+
$saveSorting = $sort !== null && Gdn::request()->get('save') && Gdn::session()->validateTransientKey(Gdn::request()->get('TransientKey', ''));
58+
if($saveSorting) {
59+
Gdn::session()->setPreference('CategorySort', $sort);
60+
}
61+
$sort = Gdn::session()->getPreference('CategorySort', false);
62+
$this->setData('CategorySort', $sort);
63+
64+
$userMetaModel = new UserMetaModel();
65+
list($cp, $categoryLimit) = offsetLimit($cp, 30);
66+
67+
// Validate Category Page
68+
if (!is_numeric($cp) || $cp < 0) {
69+
$cp = 0;
70+
}
71+
$categorySort = $sort == 'old'? 'asc': 'desc';
72+
$watchedCategoryIDs = $userMetaModel->getWatchedCategories(Gdn::session()->UserID, $categorySort, $categoryLimit, $cp);
73+
$countOfWatchedCategories = $userMetaModel->userWatchedCategoriesCount(Gdn::session()->UserID);
74+
75+
$categories = [];
76+
$categoryModel = new CategoryModel();
77+
foreach ($watchedCategoryIDs as $item) {
78+
$category = CategoryModel::categories(val('CategoryID', $item));
79+
// $category['Archived']
80+
// if (!$category['PermsDiscussionsView']) {
81+
// continue;
82+
// }
83+
$categories[] = $category;
84+
}
85+
$categoryModel->joinRecent($categories);
86+
$this->setData('WatchedCategories', $categories);
87+
$this->setData('CountWatchedCategories', $countOfWatchedCategories);
88+
89+
$pagerFactory = new Gdn_PagerFactory();
90+
$this->WatchedCategoriesPager = $pagerFactory->getPager('MorePager', $this);
91+
$this->WatchedCategoriesPager->ClientID='WatchingCategories';
92+
$this->WatchedCategoriesPager->MoreCode = 'More Categories';
93+
$this->WatchedCategoriesPager->configure($cp,
94+
$categoryLimit,
95+
$countOfWatchedCategories,
96+
'watching?cp={Page}'
97+
);
98+
99+
Gdn_Theme::section('DiscussionList');
100+
101+
list($dp, $discussionlimit) = offsetLimit($dp, 30);
102+
if (!is_numeric($dp) || $dp < 0) {
103+
$dp = 0;
104+
}
105+
106+
$discussionModel = new DiscussionModel();
107+
$discussionModel->setSort($sort);
108+
$discussionModel->setFilters(Gdn::request()->get());
109+
$wheres = [
110+
'w.Bookmarked' => '1',
111+
'w.UserID' => Gdn::session()->UserID
112+
];
113+
114+
$this->DiscussionData = $discussionModel->get($dp, $discussionlimit, $wheres);
115+
$this->setData('Discussions', $this->DiscussionData);
116+
$countDiscussions = $discussionModel->getCount($wheres);
117+
$this->setData('CountDiscussions', $countDiscussions);
118+
119+
$pagerFactory = new Gdn_PagerFactory();
120+
$this->DiscussionPager = $pagerFactory->getPager('MorePager', $this);
121+
$this->DiscussionPager->ClientID='WatchingDiscussions';
122+
$this->DiscussionPager->MoreCode = 'More Discussions';
123+
$this->DiscussionPager->configure($dp,
124+
$discussionlimit,
125+
$countDiscussions,
126+
'watching?dp={Page}');
127+
128+
$this->allowJSONP(true);
129+
130+
// Deliver JSON data if necessary
131+
if ($this->deliveryType() != DELIVERY_TYPE_ALL) {
132+
if ($dp > 0) {
133+
//$this->setJson('LessRow', $this->DiscussionPager->toString('less'));
134+
$this->setJson('MoreRow', $this->DiscussionPager->toString('more'));
135+
$this->setJson('Loading', $dp.' to '.$discussionlimit);
136+
$this->View = 'discussions';
137+
} else if($cp > 0) {
138+
//$this->setJson('LessRow', $this->WatchedCategoriesPager->toString('less'));
139+
$this->setJson('MoreRow', $this->WatchedCategoriesPager->toString('more'));
140+
$this->setJson('Loading', $cp.' to '.$categoryLimit);
141+
$this->View = 'categories';
142+
}
143+
144+
}
145+
146+
$this->canonicalUrl(url('/watching', true));
147+
148+
// Add modules
149+
$this->addModule('DiscussionFilterModule');
150+
151+
// Render default view
152+
$this->setData('Title', t('Watching'));
153+
$this->setData('Breadcrumbs', [['Name' => t('Watching'), 'Url' => '/watching']]);
154+
155+
$this->render();
156+
}
157+
}

‎Topcoder/design/topcoder.css

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,44 +69,59 @@ a.coderRatingRed:hover, a.coderRatingYellow:hover, a.coderRatingBlue:hover, a.co
6969
.MessageList .ItemDiscussion .Username.coderRatingRed, .MessageList .ItemDiscussion .Username.coderRatingRed:hover,
7070
.Content.MainContent .MessageList.DataList.Comments li.Item .Item-Header.CommentHeader .Username.coderRatingRed,
7171
.Flyout.Flyout a.coderRatingRed, .Flyout.Flyout a.coderRatingRed:link, .Flyout.Flyout a.coderRatingRed:hover, .Flyout.Flyout a.coderRatingRed:active, .Flyout.Flyout a.coderRatingRed:visited,
72-
.userContent p a.coderRatingRed, .userContent p a.coderRatingRed:link, .userContent p a.coderRatingRed:hover, .userContent p a.coderRatingRed:active, .userContent p a.coderRatingRed:visited { color: #EE0000 !important; }
72+
.userContent p a.coderRatingRed, .userContent p a.coderRatingRed:link, .userContent p a.coderRatingRed:hover, .userContent p a.coderRatingRed:active, .userContent p a.coderRatingRed:visited,
73+
.InformMessages .InformMessage .coderRatingRed, .InformMessages .InformMessage .coderRatingRed:link, .InformMessages .InformMessage .coderRatingRed:hover, .InformMessages .InformMessage .coderRatingRed:active, .InformMessages .InformMessage .coderRatingRed:visited
74+
{ color: #EE0000 !important; }
7375
/* Yellow */
7476
.DataList .MItem a.coderRatingYellow, .DataList .MItem a.coderRatingYellow:link, .DataList .MItem a.coderRatingYellow:hover, .DataList .MItem a.coderRatingYellow:visited,
7577
.MessageList .ItemDiscussion .Username.coderRatingYellow, .MessageList .ItemDiscussion .Username.coderRatingYellow:hover,
7678
.Content.MainContent .MessageList.DataList.Comments li.Item .Item-Header.CommentHeader .Username.coderRatingYellow,
7779
.Flyout.Flyout a.coderRatingYellow, .Flyout.Flyout a.coderRatingYellow:link, .Flyout.Flyout a.coderRatingYellow:hover, .Flyout.Flyout a.coderRatingYellow:active, .Flyout.Flyout a.coderRatingYellow:visited,
78-
.userContent p a.coderRatingYellow, .userContent p a.coderRatingYellow:link, .userContent p a.coderRatingYellow:hover, .userContent p a.coderRatingYellow:active, .userContent p a.coderRatingYellow:visited { color: #DDCC00 !important; }
80+
.userContent p a.coderRatingYellow, .userContent p a.coderRatingYellow:link, .userContent p a.coderRatingYellow:hover, .userContent p a.coderRatingYellow:active, .userContent p a.coderRatingYellow:visited,
81+
.InformMessages .InformMessage .coderRatingYellow, .InformMessages .InformMessage .coderRatingYellow:link, .InformMessages .InformMessage .coderRatingYellow:hover, .InformMessages .InformMessage .coderRatingYellow:active, .InformMessages .InformMessage .coderRatingYellow:visited
82+
{ color: #DDCC00 !important; }
7983
/* Blue */
8084
.DataList .MItem a.coderRatingBlue, .DataList .MItem a.coderRatingBlue:link, .DataList .MItem a.coderRatingBlue:hover, .DataList .MItem a.coderRatingBlue:visited,
8185
.MessageList .ItemDiscussion .Username.coderRatingBlue, .MessageList .ItemDiscussion .Username.coderRatingBlue:hover,
8286
.Content.MainContent .MessageList.DataList.Comments li.Item .Item-Header.CommentHeader .Username.coderRatingBlue,
8387
.Flyout.Flyout a.coderRatingBlue, .Flyout.Flyout a.coderRatingBlue:link, .Flyout.Flyout a.coderRatingBlue:active, .Flyout.Flyout a.coderRatingBlue:hover, .Flyout.Flyout a.coderRatingBlue:visited,
84-
.userContent p a.coderRatingBlue, .userContent p a.coderRatingBlue:link, .userContent p a.coderRatingBlue:active, .userContent p a.coderRatingBlue:hover, .userContent p a.coderRatingBlue:visited{ color: #6666FF !important; }
88+
.userContent p a.coderRatingBlue, .userContent p a.coderRatingBlue:link, .userContent p a.coderRatingBlue:active, .userContent p a.coderRatingBlue:hover, .userContent p a.coderRatingBlue:visited,
89+
.InformMessages .InformMessage .coderRatingBlue, .InformMessages .InformMessage .coderRatingBlue:link, .InformMessages .InformMessage .coderRatingBlue:hover, .InformMessages .InformMessage .coderRatingBlue:active, .InformMessages .InformMessage .coderRatingBlue:visited
90+
{ color: #6666FF !important; }
91+
8592
/* Green */
8693
.DataList .MItem a.coderRatingGreen, .DataList .MItem a.coderRatingGreen:link, .DataList .MItem a.coderRatingGreen:hover, .DataList .MItem a.coderRatingGreen:visited,
8794
.MessageList .ItemDiscussion .Username.coderRatingGreen,.MessageList .ItemDiscussion .Username.coderRatingGreen:hover,
8895
.Content.MainContent .MessageList.DataList.Comments li.Item .Item-Header.CommentHeader .Username.coderRatingGreen,
8996
.Flyout.Flyout a.coderRatingGreen, .Flyout.Flyout a.coderRatingGreen:link, .Flyout.Flyout a.coderRatingGreen:active, .Flyout.Flyout a.coderRatingGreen:hover, .Flyout.Flyout a.coderRatingGreen:visited,
90-
.userContent p a.coderRatingGreen, .userContent p a.coderRatingGreen:link, .userContent p a.coderRatingGreen:active, .userContent p a.coderRatingGreen:hover, .userContent p a.coderRatingGreen:visited { color: #00A900 !important; }
97+
.userContent p a.coderRatingGreen, .userContent p a.coderRatingGreen:link, .userContent p a.coderRatingGreen:active, .userContent p a.coderRatingGreen:hover, .userContent p a.coderRatingGreen:visited,
98+
.InformMessages .InformMessage .coderRatingGreen, .InformMessages .InformMessage .coderRatingGreen:link, .InformMessages .InformMessage .coderRatingGreen:hover, .InformMessages .InformMessage .coderRatingGreen:active, .InformMessages .InformMessage .coderRatingGreen:visited
99+
{ color: #00A900 !important; }
91100
/* Gray */
92101
.DataList .MItem a.coderRatingGrey, .DataList .MItem a.coderRatingGrey:link, .DataList .MItem a.coderRatingGrey:hover, .DataList .MItem a.coderRatingGrey:visited,
93102
.MessageList .ItemDiscussion .Username.coderRatingGrey,.MessageList .ItemDiscussion .Username.coderRatingGrey:hover,
94103
.Content.MainContent .MessageList.DataList.Comments li.Item .Item-Header.CommentHeader .Username.coderRatingGrey,
95104
.Flyout.Flyout a.coderRatingGrey, .Flyout.Flyout a.coderRatingGrey:link, .Flyout.Flyout a.coderRatingGrey:active, .Flyout.Flyout a.coderRatingGrey:hover, .Flyout.Flyout a.coderRatingGrey:visited,
96-
.userContent p a.coderRatingGrey, .userContent p a.coderRatingGrey:link, .userContent p a.coderRatingGrey:active, .userContent p a.coderRatingGrey:hover, .userContent p a.coderRatingGrey:visited{ color: #999999 !important; }
105+
.userContent p a.coderRatingGrey, .userContent p a.coderRatingGrey:link, .userContent p a.coderRatingGrey:active, .userContent p a.coderRatingGrey:hover, .userContent p a.coderRatingGrey:visited,
106+
.InformMessages .InformMessage .coderRatingGrey, .InformMessages .InformMessage .coderRatingGrey:link, .InformMessages .InformMessage .coderRatingGrey:hover, .InformMessages .InformMessage .coderRatingGrey:active, .InformMessages .InformMessage .coderRatingGrey:visited
107+
{ color: #999999 !important; }
97108

98109
.DataList .MItem a.coderRatingNone, .DataList .MItem a.coderRatingNone:link, .DataList .MItem a.coderRatingNone:hover, .DataList .MItem a.coderRatingNone:visited,
99110
.MessageList .ItemDiscussion .Username.coderRatingNone, .MessageList .ItemDiscussion .Username.coderRatingNone:hover,
100111
.Content.MainContent .MessageList.DataList.Comments li.Item .Item-Header.CommentHeader .Username.coderRatingNone,
101112
.Flyout.Flyout a.coderRatingNone, .Flyout.Flyout a.coderRatingNone:link, .Flyout.Flyout a.coderRatingNone:active, .Flyout.Flyout a.coderRatingNone:hover, .Flyout.Flyout a.coderRatingNone:visited,
102-
.userContent p a.coderRatingNone, .userContent p a.coderRatingNone:link, .userContent p a.coderRatingNone:active, .userContent p a.coderRatingNone:hover, .userContent p a.coderRatingNone:visited { color: #000000; !important;}
113+
.userContent p a.coderRatingNone, .userContent p a.coderRatingNone:link, .userContent p a.coderRatingNone:active, .userContent p a.coderRatingNone:hover, .userContent p a.coderRatingNone:visited,
114+
.InformMessages .InformMessage .coderRatingNone, .InformMessages .InformMessage .coderRatingNone:link, .InformMessages .InformMessage .coderRatingNone:hover, .InformMessages .InformMessage .coderRatingNone:active, .InformMessages .InformMessage .coderRatingNone:visited
115+
{ color: #000000; !important;}
103116

104117
/* Topcoder Admin */
105118
.DataList .MItem a.topcoderAdmin, .DataList .MItem a.topcoderAdmin:link, .DataList .MItem a.topcoderAdmin:hover, .DataList .MItem a.topcoderAdmin:visited,
106119
.MessageList .ItemDiscussion .Username.topcoderAdmin, .MessageList .ItemDiscussion .Username.topcoderAdmin:hover,
107120
.Content.MainContent .MessageList.DataList.Comments li.Item .Item-Header.CommentHeader .Username.topcoderAdmin,
108121
.Flyout.Flyout a.topcoderAdmin, .Flyout.Flyout a.topcoderAdmin:link,.Flyout.Flyout a.topcoderAdmin:visited, .Flyout.Flyout a.topcoderAdmin:hover, .Flyout.Flyout a.topcoderAdmin:active,
109-
.userContent p a.topcoderAdmin, .userContent p a.topcoderAdmin:link, .userContent p a.topcoderAdmin:visited, .userContent p a.topcoderAdmin:hover, .userContent p a.topcoderAdmin:active { color: #ff9900 !important; }
122+
.userContent p a.topcoderAdmin, .userContent p a.topcoderAdmin:link, .userContent p a.topcoderAdmin:visited, .userContent p a.topcoderAdmin:hover, .userContent p a.topcoderAdmin:active,
123+
.InformMessages .InformMessage .topcoderAdmin, .InformMessages .InformMessage .topcoderAdmin:link, .InformMessages .InformMessage .topcoderAdmin:hover, .InformMessages .InformMessage .topcoderAdmin:active, .InformMessages .InformMessage .topcoderAdmin:visited
124+
{ color: #ff9900 !important; }
110125

111126
a:hover span.topcoderHandle{
112127
text-decoration: underline;
@@ -126,3 +141,26 @@ a:hover span.challengeRoles {
126141
padding: 0px 0px;
127142
text-transform: none;
128143
}
144+
145+
.Topcoder h2.HomepageTitle {
146+
font-family: Barlow_Condensed, Helvetica, Arial, sans-serif;
147+
font-weight: 500;
148+
color: #2a2a2a !important;
149+
font-size: 24px !important;
150+
font-weight: 500 !important;
151+
line-height: 28px !important;
152+
text-transform: uppercase !important;
153+
}
154+
.Topcoder h1.HomepageTitle {
155+
font-family: Barlow_Condensed, Helvetica, Arial, sans-serif;
156+
font-weight: 500;
157+
color: #2a2a2a !important;
158+
font-size: 34px !important;
159+
font-weight: 500 !important;
160+
line-height: 38px !important;
161+
text-transform: uppercase !important;
162+
}
163+
164+
.disabledLink {
165+
pointer-events:none
166+
}

‎Topcoder/js/topcoder.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
jQuery(document).ready(function($) {
2+
3+
// Set up paging
4+
if ($.morepager) {
5+
6+
$('#WatchingDiscussionsMore').morepager({
7+
pageContainerSelector: 'ul.Discussions:last',
8+
afterPageLoaded: function() {
9+
$(document).trigger('DiscussionPagingComplete');
10+
}
11+
});
12+
13+
// profile/discussions paging
14+
$('#WatchingCategoriesMore').morepager({
15+
pageContainerSelector: 'ul.WatchedCategoryList:last',
16+
afterPageLoaded: function() {
17+
$(document).trigger('DiscussionPagingComplete');
18+
}
19+
});
20+
}
21+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php if (!defined('APPLICATION')) exit();
2+
$Session = Gdn::session();
3+
include_once $this->fetchViewLocation('helper_functions', 'categories', 'vanilla');
4+
5+
if($this->data('WatchedCategories')) {
6+
$categories = $this->data('WatchedCategories');
7+
?>
8+
<?php
9+
foreach ($categories as $category) {
10+
writeListItem($category, 1);
11+
}
12+
?>
13+
<?php
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php if (!defined('APPLICATION')) exit();
2+
$Session = Gdn::session();
3+
include_once $this->fetchViewLocation('helper_functions', 'discussions', 'vanilla');
4+
5+
if ($this->data('Discussions')->numRows() > 0) {
6+
?>
7+
8+
<?php include($this->fetchViewLocation('discussions', 'Discussions', 'Vanilla')); ?>
9+
10+
<?php
11+
}

‎Topcoder/views/watching/index.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php if (!defined('APPLICATION')) exit();
2+
$Session = Gdn::session();
3+
include_once $this->fetchViewLocation('helper_functions', 'discussions', 'vanilla');
4+
include_once $this->fetchViewLocation('helper_functions', 'categories', 'vanilla');
5+
6+
echo '<h1 class="H HomepageTitle">'.
7+
adminCheck(NULL, ['', ' ']).
8+
$this->data('Title').
9+
'</h1>';
10+
11+
$this->fireEvent('AfterPageTitle');
12+
echo '<div class="PageControls Top">';
13+
echo categorySorts();
14+
echo '</div>';
15+
16+
if($this->data('WatchedCategories')) {
17+
echo '<h2 class="H HomepageTitle">Categories</h2>';
18+
$categories = $this->data('WatchedCategories');
19+
?>
20+
<ul class="DataList CategoryList WatchedCategoryList">
21+
<?php
22+
foreach ($categories as $category) {
23+
writeListItem($category, 1);
24+
}
25+
?>
26+
</ul>
27+
<?php
28+
echo $this->WatchedCategoriesPager->toString('more');
29+
}
30+
31+
if ($this->data('Discussions')->numRows() > 0) {
32+
echo '<h2 class="H HomepageTitle">Discussions</h2>';
33+
?>
34+
<ul class="DataList Discussions">
35+
<?php include($this->fetchViewLocation('discussions', 'Discussions', 'Vanilla'));
36+
?>
37+
</ul>
38+
<?php
39+
echo $this->DiscussionPager->toString('more');
40+
}
41+
42+
43+

0 commit comments

Comments
 (0)
Please sign in to comment.