Index: trunk/extensions/BlogPage/Blog.alias.php |
— | — | @@ -0,0 +1,23 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Aliases for the BlogPage extension. |
| 5 | + * |
| 6 | + * @file |
| 7 | + * @ingroup Extensions |
| 8 | + */ |
| 9 | + |
| 10 | +$aliases = array(); |
| 11 | + |
| 12 | +/** English */ |
| 13 | +$aliases['en'] = array( |
| 14 | + 'ArticlesHome' => array( 'ArticlesHome' ), |
| 15 | + 'ArticleLists' => array( 'ArticleLists' ), |
| 16 | + 'CreateBlogPost' => array( 'CreateBlogPost' ), |
| 17 | +); |
| 18 | + |
| 19 | +/** Finnish (Suomi) */ |
| 20 | +$aliases['fi'] = array( |
| 21 | + 'ArticlesHome' => array( 'Artikkelien kotisivu' ), |
| 22 | + 'ArticleLists' => array( 'Artikkelilistat' ), |
| 23 | + 'CreateBlogPost' => array( 'Luo blogikirjoitus' ), |
| 24 | +); |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/Blog.alias.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 25 | + native |
Index: trunk/extensions/BlogPage/CreateBlogPost.css |
— | — | @@ -0,0 +1,38 @@ |
| 2 | +/* CSS for Special:CreateBlogPost */ |
| 3 | +.create-title { |
| 4 | + margin: 0px 0px 5px; |
| 5 | + color: rgb(51, 51, 51); |
| 6 | + font-size: 14px; |
| 7 | + font-weight: bold; |
| 8 | +} |
| 9 | + |
| 10 | +.categorytext { |
| 11 | + width: 700px; |
| 12 | +} |
| 13 | + |
| 14 | +/* Copyright stuff below the form, right above the submit button */ |
| 15 | +.copyright-warning { |
| 16 | + margin: 0px 0px 10px; |
| 17 | + width: 700px; |
| 18 | + color: rgb(51, 51, 51); |
| 19 | + font-size: 11px; |
| 20 | +} |
| 21 | + |
| 22 | +#editform .title { |
| 23 | + margin: 0px 0px 5px; |
| 24 | + color: rgb(120, 186, 93); |
| 25 | + font-size: 1.1em; |
| 26 | + font-weight: bold; |
| 27 | +} |
| 28 | + |
| 29 | +/* Category tag cloud */ |
| 30 | +#create-tagcloud { |
| 31 | + line-height: 25pt; |
| 32 | + padding-bottom: 15px; |
| 33 | + width: 600px; |
| 34 | +} |
| 35 | + |
| 36 | +a.tag-cloud-entry { |
| 37 | + cursor: pointer; |
| 38 | + text-decoration: underline; |
| 39 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/CreateBlogPost.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 40 | + native |
Index: trunk/extensions/BlogPage/SpecialCreateBlogPost.php |
— | — | @@ -0,0 +1,368 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * A special page to create new blog posts (pages in the NS_BLOG namespace). |
| 5 | + * Based on the CreateForms extension by Aaron Wright and David Pean. |
| 6 | + * |
| 7 | + * @file |
| 8 | + * @ingroup Extensions |
| 9 | + * @date 16 July 2011 |
| 10 | + */ |
| 11 | +class SpecialCreateBlogPost extends SpecialPage { |
| 12 | + |
| 13 | + public $tabCounter = 1; |
| 14 | + |
| 15 | + /** |
| 16 | + * Constructor -- set up the new special page |
| 17 | + */ |
| 18 | + public function __construct() { |
| 19 | + parent::__construct( 'CreateBlogPost', 'createblogpost' ); |
| 20 | + } |
| 21 | + |
| 22 | + /** |
| 23 | + * Show the special page |
| 24 | + * |
| 25 | + * @param $par Mixed: parameter passed to the special page or null |
| 26 | + */ |
| 27 | + public function execute( $par ) { |
| 28 | + global $wgOut, $wgUser, $wgRequest, $wgContLang, $wgScriptPath, $wgHooks; |
| 29 | + |
| 30 | + // If the user can't create blog posts, display an error |
| 31 | + if( !$wgUser->isAllowed( 'createblogpost' ) ) { |
| 32 | + $wgOut->permissionRequired( 'createblogpost' ); |
| 33 | + return; |
| 34 | + } |
| 35 | + |
| 36 | + // Show a message if the database is in read-only mode |
| 37 | + if ( wfReadOnly() ) { |
| 38 | + $wgOut->readOnlyPage(); |
| 39 | + return; |
| 40 | + } |
| 41 | + |
| 42 | + // If user is blocked, s/he doesn't need to access this page |
| 43 | + if( $wgUser->isBlocked() ) { |
| 44 | + $wgOut->blockedPage( false ); |
| 45 | + return false; |
| 46 | + } |
| 47 | + |
| 48 | + // Set page title, robot policies, etc. |
| 49 | + $this->setHeaders(); |
| 50 | + |
| 51 | + // i18n for JS |
| 52 | + $wgHooks['MakeGlobalVariablesScript'][] = 'SpecialCreateBlogPost::addJSGlobals'; |
| 53 | + |
| 54 | + // Add CSS & JS |
| 55 | + if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) { |
| 56 | + $wgOut->addModules( array( |
| 57 | + 'mediawiki.legacy.edit', 'ext.blogPage.create' |
| 58 | + ) ); |
| 59 | + } else { |
| 60 | + $wgOut->addExtensionStyle( $wgScriptPath . '/extensions/BlogPage/CreateBlogPost.css' ); |
| 61 | + $wgOut->addScriptFile( $wgScriptPath . '/extensions/BlogPage/CreateBlogPost.js' ); |
| 62 | + $wgOut->addScriptFile( 'edit.js' ); // for the edit toolbar |
| 63 | + } |
| 64 | + |
| 65 | + // If the request was POSTed, we haven't submitted a request yet AND |
| 66 | + // we have a title, create the page...otherwise just display the |
| 67 | + // creation form |
| 68 | + if( |
| 69 | + $wgRequest->wasPosted() && |
| 70 | + $_SESSION['alreadysubmitted'] == false |
| 71 | + ) |
| 72 | + { |
| 73 | + $_SESSION['alreadysubmitted'] = true; |
| 74 | + |
| 75 | + // Protect against cross-site request forgery (CSRF) |
| 76 | + if ( !$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) { |
| 77 | + $wgOut->addHTML( wfMsg( 'sessionfailure' ) ); |
| 78 | + return; |
| 79 | + } |
| 80 | + |
| 81 | + // Create a Title object, or try to, anyway |
| 82 | + $userSuppliedTitle = $wgRequest->getVal( 'title2' ); |
| 83 | + $title = Title::makeTitleSafe( NS_BLOG, $userSuppliedTitle ); |
| 84 | + |
| 85 | + // @todo CHECKME: are these still needed? The JS performs these |
| 86 | + // checks already but then again JS is also easy to fool... |
| 87 | + |
| 88 | + // The user didn't supply a title? Ask them to supply one. |
| 89 | + if ( !$userSuppliedTitle ) { |
| 90 | + $wgOut->setPageTitle( wfMsg( 'errorpagetitle' ) ); |
| 91 | + $wgOut->addWikiMsg( 'blog-create-error-need-title' ); |
| 92 | + $wgOut->addReturnTo( $this->getTitle() ); |
| 93 | + return; |
| 94 | + } |
| 95 | + |
| 96 | + // The user didn't supply the blog post text? Ask them to supply it. |
| 97 | + if ( !$wgRequest->getVal( 'pageBody' ) ) { |
| 98 | + $wgOut->setPageTitle( wfMsg( 'errorpagetitle' ) ); |
| 99 | + $wgOut->addWikiMsg( 'blog-create-error-need-content' ); |
| 100 | + $wgOut->addReturnTo( $this->getTitle() ); |
| 101 | + return; |
| 102 | + } |
| 103 | + |
| 104 | + // Localized variables that will be used when creating the page |
| 105 | + $localizedCatNS = $wgContLang->getNsText( NS_CATEGORY ); |
| 106 | + $today = $wgContLang->date( wfTimestampNow() ); |
| 107 | + |
| 108 | + // Create the blog page if it doesn't already exist |
| 109 | + $article = new Article( $title, 0 ); |
| 110 | + if ( $article->exists() ) { |
| 111 | + $wgOut->setPageTitle( wfMsg( 'errorpagetitle' ) ); |
| 112 | + $wgOut->addWikiMsg( 'blog-create-error-page-exists' ); |
| 113 | + $wgOut->addReturnTo( $this->getTitle() ); |
| 114 | + return; |
| 115 | + } else { |
| 116 | + // The blog post will be by default categorized into two |
| 117 | + // categories, "Articles by User $1" and "(today's date)", |
| 118 | + // but the user may supply some categories themselves, so |
| 119 | + // we need to take those into account, too. |
| 120 | + $categories = array( |
| 121 | + '[[' . $localizedCatNS . ':' . |
| 122 | + wfMsgForContent( |
| 123 | + 'blog-by-user-category', |
| 124 | + wfMsgForContent( 'blog-category' ) |
| 125 | + ) . wfMsgForContent( 'word-separator' ) . |
| 126 | + $wgUser->getName() . ']]', |
| 127 | + "[[{$localizedCatNS}:{$today}]]" |
| 128 | + ); |
| 129 | + |
| 130 | + $userSuppliedCategories = $wgRequest->getVal( 'pageCtg' ); |
| 131 | + if ( !empty( $userSuppliedCategories ) ) { |
| 132 | + // Explode along commas so that we will have an array that |
| 133 | + // we can loop over |
| 134 | + $userSuppliedCategories = explode( ',', $userSuppliedCategories ); |
| 135 | + foreach( $userSuppliedCategories as $cat ) { |
| 136 | + $cat = trim( $cat ); // GTFO@excess whitespace |
| 137 | + if ( !empty( $cat ) ) { |
| 138 | + $categories[] = "[[{$localizedCatNS}:{$cat}]]"; |
| 139 | + } |
| 140 | + } |
| 141 | + } |
| 142 | + |
| 143 | + // Convert the array into a string |
| 144 | + $wikitextCategories = implode( "\n", $categories ); |
| 145 | + |
| 146 | + // Perform the edit |
| 147 | + $article->doEdit( |
| 148 | + // Instead of <vote />, Wikia had Template:Blog Top over |
| 149 | + // here and Template:Blog Bottom at the bottom, where we |
| 150 | + // have the comments tag right now |
| 151 | + '<vote />' . "\n" . '<!--start text-->' . "\n" . |
| 152 | + $wgRequest->getVal( 'pageBody' ) . "\n\n" . |
| 153 | + '<comments />' . "\n\n" . $wikitextCategories . |
| 154 | + "\n__NOEDITSECTION__", |
| 155 | + wfMsgForContent( 'blog-create-summary' ) |
| 156 | + ); |
| 157 | + |
| 158 | + $articleId = $article->getID(); |
| 159 | + // Add a vote for the page |
| 160 | + // This was originally in its own global function, |
| 161 | + // wfFinishCreateBlog and after that in the BlogHooks class but |
| 162 | + // it just wouldn't work with Special:CreateBlogPost so I |
| 163 | + // decided to move it here since this is supposed to be like |
| 164 | + // the primary way of creating new blog posts... |
| 165 | + // Using OutputPageBeforeHTML hook, which, according to its |
| 166 | + // manual page, runs on *every* page view was such a stupid |
| 167 | + // idea IMHO. |
| 168 | + $vote = new Vote( $articleId ); |
| 169 | + $vote->insert( 1 ); |
| 170 | + |
| 171 | + $stats = new UserStatsTrack( $wgUser->getID(), $wgUser->getName() ); |
| 172 | + $stats->updateWeeklyPoints( $stats->point_values['opinions_created'] ); |
| 173 | + $stats->updateMonthlyPoints( $stats->point_values['opinions_created'] ); |
| 174 | + //if( $wgEnableFacebook ) { |
| 175 | + // BlogHooks::updateFacebookProfile(); |
| 176 | + //} |
| 177 | + //if( $wgSendNewArticleToFriends ) { |
| 178 | + // $invite = SpecialPage::getTitleFor( 'EmailNewArticle' ); |
| 179 | + // $wgOut->redirect( |
| 180 | + // $invite->getFullURL( 'page=' . $title->getPrefixedText() ) |
| 181 | + // ); |
| 182 | + //} |
| 183 | + |
| 184 | + // Redirect the user to the new blog post they just created |
| 185 | + $wgOut->redirect( $title->getFullURL() ); |
| 186 | + } |
| 187 | + } else { |
| 188 | + $_SESSION['alreadysubmitted'] = false; |
| 189 | + |
| 190 | + // Start building the HTML |
| 191 | + $output = ''; |
| 192 | + |
| 193 | + // Show the blog rules, if the message containing them ain't empty |
| 194 | + $message = trim( wfMsgExt( 'blog-create-rules', array( 'parse', 'content' ) ) ); |
| 195 | + // Yes, the strlen() is needed, I dunno why wfEmptyMsg() won't work |
| 196 | + if( !wfEmptyMsg( 'blog-create-rules', $message ) && strlen( $message ) > 0 ) { |
| 197 | + $output .= $message . '<br />'; |
| 198 | + } |
| 199 | + |
| 200 | + // Main form |
| 201 | + $output .= $this->displayForm(); |
| 202 | + |
| 203 | + // Show everything to the user |
| 204 | + $wgOut->addHTML( $output ); |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + /** |
| 209 | + * Show the input field where the user can enter the blog post title. |
| 210 | + * @return String: HTML |
| 211 | + */ |
| 212 | + function displayFormPageTitle() { |
| 213 | + $output = '<span class="create-title">' . wfMsg( 'blog-create-title' ) . |
| 214 | + '</span><br /><input class="createbox" type="text" tabindex="' . |
| 215 | + $this->tabCounter . '" name="title2" id="title" style="width: 500px;"><br /><br />'; |
| 216 | + $this->tabCounter++; |
| 217 | + return $output; |
| 218 | + } |
| 219 | + |
| 220 | + /** |
| 221 | + * Show the input field where the user can enter the blog post body. |
| 222 | + * @return String: HTML |
| 223 | + */ |
| 224 | + function displayFormPageText() { |
| 225 | + $output = '<span class="create-title">' . wfMsg( 'blog-create-text' ) . |
| 226 | + '</span><br />'; |
| 227 | + // The EditPage toolbar wasn't originally present here but I figured |
| 228 | + // that adding it might be more helpful than anything else. |
| 229 | + $output .= EditPage::getEditToolbar(); |
| 230 | + $output .= '<textarea class="createbox" tabindex="' . |
| 231 | + $this->tabCounter . '" accesskey="," name="pageBody" id="pageBody" rows="10" cols="80"></textarea><br /><br />'; |
| 232 | + $this->tabCounter++; |
| 233 | + return $output; |
| 234 | + } |
| 235 | + |
| 236 | + /** |
| 237 | + * Show the category cloud. |
| 238 | + * @return String: HTML |
| 239 | + */ |
| 240 | + function displayFormPageCategories() { |
| 241 | + $cloud = new BlogTagCloud( 20 ); |
| 242 | + |
| 243 | + $tagcloud = '<div id="create-tagcloud">'; |
| 244 | + $tagnumber = 0; |
| 245 | + foreach ( $cloud->tags as $tag => $att ) { |
| 246 | + $tag = trim( $tag ); |
| 247 | + $blogUserCat = wfMsgForContent( 'blog-by-user-category', |
| 248 | + wfMsgForContent( 'blog-category' ) ); |
| 249 | + // Ignore "Articles by User X" categories |
| 250 | + if ( !preg_match( '/' . $blogUserCat . '/', $tag ) ) { |
| 251 | + $slashedTag = $tag; // define variable |
| 252 | + // Fix for categories that contain an apostrophe |
| 253 | + if ( strpos( $tag, "'" ) ) { |
| 254 | + $slashedTag = str_replace( "'", "\'", $tag ); |
| 255 | + } |
| 256 | + $tagcloud .= " <span id=\"tag-{$tagnumber}\" style=\"font-size:{$cloud->tags[$tag]['size']}{$cloud->tags_size_type}\"> |
| 257 | + <a class=\"tag-cloud-entry\" onclick=\"javascript:CreateBlogPost.insertTag('" . $slashedTag . "',{$tagnumber});\">{$tag}</a> |
| 258 | + </span>"; |
| 259 | + $tagnumber++; |
| 260 | + } |
| 261 | + } |
| 262 | + $tagcloud .= '</div>'; |
| 263 | + |
| 264 | + $output = '<div class="create-title">' . |
| 265 | + wfMsg( 'blog-create-categories' ) . |
| 266 | + '</div> |
| 267 | + <div class="categorytext">' . |
| 268 | + wfMsg( 'blog-create-category-help' ) . |
| 269 | + '</div>' . "\n"; |
| 270 | + $output .= $tagcloud . "\n"; |
| 271 | + $output .= '<textarea class="createbox" tabindex="' . $this->tabCounter . |
| 272 | + '" accesskey="," name="pageCtg" id="pageCtg" rows="2" cols="80"></textarea><br /><br />'; |
| 273 | + $this->tabCounter++; |
| 274 | + |
| 275 | + return $output; |
| 276 | + } |
| 277 | + |
| 278 | + /** |
| 279 | + * Display the standard copyright notice that is shown on normal edit page, |
| 280 | + * on the upload form etc. |
| 281 | + * |
| 282 | + * @return String: HTML |
| 283 | + */ |
| 284 | + function displayCopyrightWarning() { |
| 285 | + global $wgRightsText; |
| 286 | + if ( $wgRightsText ) { |
| 287 | + $copywarnMsg = 'copyrightwarning'; |
| 288 | + $copywarnMsgParams = array( |
| 289 | + '[[' . wfMsgForContent( 'copyrightpage' ) . ']]', |
| 290 | + $wgRightsText |
| 291 | + ); |
| 292 | + } else { |
| 293 | + $copywarnMsg = 'copyrightwarning2'; |
| 294 | + $copywarnMsgParams = array( |
| 295 | + '[[' . wfMsgForContent( 'copyrightpage' ) . ']]' |
| 296 | + ); |
| 297 | + } |
| 298 | + return '<div class="copyright-warning">' . |
| 299 | + wfMsgExt( $copywarnMsg, 'parse', $copywarnMsgParams ) . |
| 300 | + '</div>'; |
| 301 | + } |
| 302 | + |
| 303 | + /** |
| 304 | + * Show the form for creating new blog posts. |
| 305 | + * @return String: HTML |
| 306 | + */ |
| 307 | + function displayForm() { |
| 308 | + global $wgUser; |
| 309 | + |
| 310 | + $output = '<form id="editform" name="editform" method="post" action="' . |
| 311 | + $this->getTitle()->escapeFullURL() . '" enctype="multipart/form-data">'; |
| 312 | + $output .= "\n" . $this->displayFormPageTitle() . "\n"; |
| 313 | + $output .= "\n" . $this->displayFormPageText() . "\n"; |
| 314 | + |
| 315 | + $output .= "\n" . $this->displayFormPageCategories() . "\n"; |
| 316 | + $output .= "\n" . $this->displayCopyrightWarning() . "\n"; |
| 317 | + $output .= '<input type="button" onclick="CreateBlogPost.performChecks()" value="' . |
| 318 | + wfMsg( 'blog-create-button' ) . '" name="wpSave" class="createsubmit site-button" accesskey="s" title="' . |
| 319 | + wfMsg( 'tooltip-save' ) . ' [alt-s]" /> |
| 320 | + <input type="hidden" value="" name="wpSection" /> |
| 321 | + <input type="hidden" value="" name="wpEdittime" /> |
| 322 | + <input type="hidden" value="" name="wpTextbox1" id="wpTextbox1" /> |
| 323 | + <input type="hidden" value="' . htmlspecialchars( $wgUser->editToken() ) . |
| 324 | + '" name="wpEditToken" />'; |
| 325 | + $output .= "\n" . '</form>' . "\n"; |
| 326 | + |
| 327 | + return $output; |
| 328 | + } |
| 329 | + |
| 330 | + /** |
| 331 | + * Check if there is already a blog post with the given title. |
| 332 | + * |
| 333 | + * @param $pageName String: page title to check |
| 334 | + * @return String: 'OK' when there isn't such a page, else 'Page exists' |
| 335 | + */ |
| 336 | + public static function checkTitleExistence( $pageName ) { |
| 337 | + // Construct page title object to convert to database key |
| 338 | + $pageTitle = Title::makeTitle( NS_MAIN, urldecode( $pageName ) ); |
| 339 | + $dbKey = $pageTitle->getDBkey(); |
| 340 | + |
| 341 | + // Database key would be in page title if the page already exists |
| 342 | + $dbr = wfGetDB( DB_MASTER ); |
| 343 | + $s = $dbr->selectRow( |
| 344 | + 'page', |
| 345 | + array( 'page_id' ), |
| 346 | + array( 'page_title' => $dbKey, 'page_namespace' => NS_BLOG ), |
| 347 | + __METHOD__ |
| 348 | + ); |
| 349 | + |
| 350 | + if ( $s !== false ) { |
| 351 | + return 'Page exists'; |
| 352 | + } else { |
| 353 | + return 'OK'; |
| 354 | + } |
| 355 | + } |
| 356 | + |
| 357 | + /** |
| 358 | + * Add i18n messages for the JS file. |
| 359 | + * |
| 360 | + * @param $vars Array: array of pre-existing JavaScript globals |
| 361 | + * @return Boolean: true |
| 362 | + */ |
| 363 | + public static function addJSGlobals( $vars ) { |
| 364 | + $vars['_BLOG_NEEDS_CONTENT'] = wfMsg( 'blog-js-create-error-need-content' ); |
| 365 | + $vars['_BLOG_NEEDS_TITLE'] = wfMsg( 'blog-js-create-error-need-title' ); |
| 366 | + $vars['_BLOG_PAGE_EXISTS'] = wfMsg( 'blog-js-create-error-page-exists' ); |
| 367 | + return true; |
| 368 | + } |
| 369 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/SpecialCreateBlogPost.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 370 | + native |
Index: trunk/extensions/BlogPage/images/comment.gif |
Cannot display: file marked as a binary type. |
svn:mime-type = image/gif |
Property changes on: trunk/extensions/BlogPage/images/comment.gif |
___________________________________________________________________ |
Added: svn:mime-type |
2 | 371 | + image/gif |
Index: trunk/extensions/BlogPage/images/voteIcon.gif |
Cannot display: file marked as a binary type. |
svn:mime-type = image/gif |
Property changes on: trunk/extensions/BlogPage/images/voteIcon.gif |
___________________________________________________________________ |
Added: svn:mime-type |
3 | 372 | + image/gif |
Index: trunk/extensions/BlogPage/ArticlesHome.css |
— | — | @@ -0,0 +1,251 @@ |
| 2 | +/* Articles Home */ |
| 3 | +/* Fix the issue with "X votes" boxes on Special:ArticlesHome -- |
| 4 | +NYC skins already include this class definition, as do some social tools, but |
| 5 | +core skins do not */ |
| 6 | +.cleared { |
| 7 | + clear: both; |
| 8 | +} |
| 9 | + |
| 10 | +h1.firstHeading { |
| 11 | + display: none; |
| 12 | +} |
| 13 | + |
| 14 | +#main { |
| 15 | + padding: 0px !important; |
| 16 | +} |
| 17 | + |
| 18 | +.main-page-left { |
| 19 | + float: left; |
| 20 | + width: 60%; |
| 21 | + padding: 10px 0px 0px 0px; |
| 22 | +} |
| 23 | + |
| 24 | +.main-page-right { |
| 25 | + float: right; |
| 26 | + width: 35%; |
| 27 | + padding: 10px 0px 0px 0px; |
| 28 | +} |
| 29 | + |
| 30 | +.main-page-sub-links a { |
| 31 | + color: #797979; |
| 32 | +} |
| 33 | + |
| 34 | +.side-articles { |
| 35 | + margin: 0px 0px 25px 0px; |
| 36 | +} |
| 37 | + |
| 38 | +.side-articles h2 { |
| 39 | + font-size: 1.5em; |
| 40 | + padding: 0px 0px 5px 0px; |
| 41 | + margin: 0px 0px 10px 0px !important; |
| 42 | + border-bottom: 1px solid #dcdcdc !important; |
| 43 | +} |
| 44 | + |
| 45 | +.side-articles .listpageItem { |
| 46 | + padding: 0px 0px 0px 0px; |
| 47 | + margin: 0px 0px 0px 0px; |
| 48 | + font-size: 11px; |
| 49 | + width: 350px; |
| 50 | +} |
| 51 | + |
| 52 | +.side-articles .showdetails a { |
| 53 | + font-size: 12px; |
| 54 | +} |
| 55 | + |
| 56 | +/* Logged-In Articles */ |
| 57 | +.logged-in-articles { |
| 58 | + margin: 0px 0px 18px 0px; |
| 59 | +} |
| 60 | + |
| 61 | +.logged-in-articles h2 { |
| 62 | + font-size: 1.5em; |
| 63 | + margin: 0px 0px 10px 0px; |
| 64 | + padding: 0px 0px 3px 0px; |
| 65 | + border-bottom: 1px solid #dcdcdc; |
| 66 | +} |
| 67 | + |
| 68 | +.logged-in-articles p { |
| 69 | + margin: 10px 0px 10px 0px !important; |
| 70 | +} |
| 71 | + |
| 72 | +.logged-in-articles .listpageItem { |
| 73 | + padding: 0px 0px 10px 0px; |
| 74 | + margin: 0px 0px 10px 0px; |
| 75 | + width: 600px; |
| 76 | +} |
| 77 | + |
| 78 | +.rss-feed { |
| 79 | + color: #797979; |
| 80 | + font-size: 10px; |
| 81 | + vertical-align: middle; |
| 82 | + margin: -1px 0px 0px 5px; |
| 83 | +} |
| 84 | + |
| 85 | +.rss-feed img { |
| 86 | + vertical-align: middle; |
| 87 | + margin: 0px 3px 0px 0px; |
| 88 | +} |
| 89 | + |
| 90 | +.side-articles .listpages-item { |
| 91 | + margin-top: 5px !important; |
| 92 | +} |
| 93 | + |
| 94 | +.side-articles a { |
| 95 | + font-size: 12px !important; |
| 96 | +} |
| 97 | + |
| 98 | +.main-page-left .listpages-item a { |
| 99 | + font-size: 16px; |
| 100 | +} |
| 101 | + |
| 102 | +.listpages-blurb { |
| 103 | + font-size: 11px !important; |
| 104 | + line-height: 14px !important; |
| 105 | +} |
| 106 | + |
| 107 | +.main-page-left .listpages-item .listpages-blurb a { |
| 108 | + font-size: 11px !important; |
| 109 | +} |
| 110 | +/* The following has been copypasted from Sports.css (the main CSS file for the ArmchairGM skin) */ |
| 111 | +/* ListPages */ |
| 112 | +.listpages-left { |
| 113 | + float: left; |
| 114 | + border: 1px solid #dcdcdc; |
| 115 | + width: 500px; |
| 116 | +} |
| 117 | + |
| 118 | +.listpages-link { |
| 119 | + margin: 0px; |
| 120 | + padding: 0px; |
| 121 | +} |
| 122 | + |
| 123 | +.listpages-item { |
| 124 | + margin-top: 10px; |
| 125 | +} |
| 126 | + |
| 127 | +.listpages-item a { |
| 128 | + text-decoration: underline; |
| 129 | + font-weight: bold; |
| 130 | +} |
| 131 | + |
| 132 | +.listpages-image { |
| 133 | + float: left; |
| 134 | + margin-right: 10px; |
| 135 | +} |
| 136 | + |
| 137 | +.listpages-categories { |
| 138 | + color: #78BA5D; |
| 139 | + font-size: 10px; |
| 140 | + font-weight: bold; |
| 141 | +} |
| 142 | + |
| 143 | +.listpages-categories a { |
| 144 | + color: #78BA5D; |
| 145 | + font-size: 10px; |
| 146 | + text-decoration: none; |
| 147 | + border-bottom: 1px dotted #78BA5D; |
| 148 | +} |
| 149 | + |
| 150 | +.listpages-date { |
| 151 | + color: #888; |
| 152 | + font-size: 10px; |
| 153 | +} |
| 154 | + |
| 155 | +.listpages-stats { |
| 156 | + color: #666; |
| 157 | + font-weight: bold; |
| 158 | + font-size: 11px; |
| 159 | +} |
| 160 | + |
| 161 | +.listpages-stats img { |
| 162 | + vertical-align: middle; |
| 163 | + margin: -2px 1px 0px 2px; |
| 164 | +} |
| 165 | + |
| 166 | +.listpages-votebox { |
| 167 | + float: left; |
| 168 | + margin: 0px 10px 3px 0px; |
| 169 | + text-align: center; |
| 170 | + width: 25px; |
| 171 | +} |
| 172 | + |
| 173 | +.rating-total { |
| 174 | + color: #666; |
| 175 | + font-weight: bold; |
| 176 | + font-size: 11px; |
| 177 | +} |
| 178 | + |
| 179 | +.listpages-votebox-number { |
| 180 | + background-color: #89C46F; |
| 181 | + color: #FFFFFF; |
| 182 | + padding: 3px 0px 0px; |
| 183 | + margin: 0px 0px 2px 0px; |
| 184 | + font-weight: bold; |
| 185 | + height: 22px; |
| 186 | +} |
| 187 | + |
| 188 | +.listpages-votebox-text { |
| 189 | + margin: -1px 0px 0px 0px; |
| 190 | + font-size: 9px; |
| 191 | + color: #777; |
| 192 | + line-height: 9px; |
| 193 | +} |
| 194 | + |
| 195 | +.listpages-commentbox-number { |
| 196 | + background-color: orange; |
| 197 | + color: #FFFFFF; |
| 198 | + font-weight: bold; |
| 199 | + height: 22px; |
| 200 | + margin: 0px 0px 2px; |
| 201 | + padding: 3px 0px 0px; |
| 202 | +} |
| 203 | + |
| 204 | +.listpages-blurb { |
| 205 | + margin: 0px 0px 2px 0px; |
| 206 | +} |
| 207 | + |
| 208 | +.listpages-blurb a { |
| 209 | + font-size: 11px; |
| 210 | + text-decoration: underline; |
| 211 | +} |
| 212 | + |
| 213 | +.listpages-nav-buttons { |
| 214 | + margin: 10px 0px 0px 0px; |
| 215 | +} |
| 216 | + |
| 217 | +.listpages-blurb-size-small { |
| 218 | + font-size: 11px; |
| 219 | + line-height: 15px; |
| 220 | +} |
| 221 | + |
| 222 | +.listpages-blurb-size-medium { |
| 223 | + font-size: 12px; |
| 224 | + line-height: 16px; |
| 225 | +} |
| 226 | + |
| 227 | +.listpages-blurb-size-large { |
| 228 | + font-size: 13px; |
| 229 | + line-height: 17px; |
| 230 | +} |
| 231 | + |
| 232 | +.listpage-button { |
| 233 | + background-color: #FAFAFA; |
| 234 | + border: 1px solid #DCDCDC; |
| 235 | + color: #376EA6; |
| 236 | + font-size: 12px; |
| 237 | + padding: 3px; |
| 238 | + margin: 0px 3px 0px 0px; |
| 239 | +} |
| 240 | + |
| 241 | +.listpage-button-off { |
| 242 | + background-color: #FAFAFA; |
| 243 | + border: 1px solid #DCDCDC; |
| 244 | + color: #797979; |
| 245 | + font-size: 12px; |
| 246 | + padding: 3px; |
| 247 | + margin: 0px 3px 0px 0px; |
| 248 | +} |
| 249 | + |
| 250 | +.listpages-nav-buttons a { |
| 251 | + margin: 0px 5px 0px 0px; |
| 252 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/ArticlesHome.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 253 | + native |
Index: trunk/extensions/BlogPage/BlogPage.php |
— | — | @@ -0,0 +1,1262 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Class for handling the viewing of pages in the NS_BLOG namespace. |
| 5 | + * |
| 6 | + * @file |
| 7 | + */ |
| 8 | +class BlogPage extends Article { |
| 9 | + |
| 10 | + var $title = null; |
| 11 | + var $authors = array(); |
| 12 | + |
| 13 | + function __construct( Title $title ) { |
| 14 | + parent::__construct( $title ); |
| 15 | + $this->setContent(); |
| 16 | + $this->getAuthors(); |
| 17 | + } |
| 18 | + |
| 19 | + function setContent() { |
| 20 | + // Get the page content for later use |
| 21 | + $this->pageContent = $this->getContent(); |
| 22 | + |
| 23 | + // If it's a redirect, in order to get the *real* content for later use, |
| 24 | + // we have to load the text for the real page |
| 25 | + // Note: If $this->getContent() is called anywhere before parent::view, |
| 26 | + // the real article text won't get loaded on the page |
| 27 | + if( $this->isRedirect( $this->pageContent ) ) { |
| 28 | + wfDebugLog( 'BlogPage', __METHOD__ ); |
| 29 | + |
| 30 | + $target = $this->followRedirect(); |
| 31 | + $rarticle = new Article( $target ); |
| 32 | + $this->pageContent = $rarticle->getContent(); |
| 33 | + |
| 34 | + // If we don't clear, the page content will be [[redirect-blah]], |
| 35 | + // and not the actual page |
| 36 | + $this->clear(); |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + function view() { |
| 41 | + global $wgOut, $wgUser, $wgTitle, $wgBlogPageDisplay; |
| 42 | + |
| 43 | + wfProfileIn( __METHOD__ ); |
| 44 | + |
| 45 | + $sk = $wgUser->getSkin(); |
| 46 | + |
| 47 | + wfDebugLog( 'BlogPage', __METHOD__ ); |
| 48 | + |
| 49 | + $wgOut->setHTMLTitle( $wgTitle->getText() ); |
| 50 | + $wgOut->setPageTitle( $wgTitle->getText() ); |
| 51 | + |
| 52 | + // Don't throw a bunch of E_NOTICEs when we're viewing the page of a |
| 53 | + // nonexistent blog post |
| 54 | + if ( !$this->getID() ) { |
| 55 | + parent::view(); |
| 56 | + return ''; |
| 57 | + } |
| 58 | + |
| 59 | + $wgOut->addHTML( "\t\t" . '<div id="blog-page-container">' . "\n" ); |
| 60 | + |
| 61 | + if ( $wgBlogPageDisplay['leftcolumn'] == true ) { |
| 62 | + $wgOut->addHTML( "\t\t\t" . '<div id="blog-page-left">' . "\n" ); |
| 63 | + |
| 64 | + $wgOut->addHTML( "\t\t\t\t" . '<div class="blog-left-units">' . "\n" ); |
| 65 | + |
| 66 | + $wgOut->addHTML( |
| 67 | + "\t\t\t\t\t" . '<h2>' . wfMsgExt( |
| 68 | + 'blog-author-title', |
| 69 | + 'parsemag', |
| 70 | + count( $this->authors ) ) . '</h2>' . "\n" |
| 71 | + ); |
| 72 | + // Why was this commented out? --ashley, 11 July 2011 |
| 73 | + if( count( $this->authors ) > 1 ) { |
| 74 | + $wgOut->addHTML( $this->displayMultipleAuthorsMessage() ); |
| 75 | + } |
| 76 | + |
| 77 | + // Output each author's box in the order that they appear in [[Category:Opinions by X]] |
| 78 | + for( $x = 0; $x <= count( $this->authors ); $x++ ) { |
| 79 | + $wgOut->addHTML( $this->displayAuthorBox( $x ) ); |
| 80 | + } |
| 81 | + |
| 82 | + $wgOut->addHTML( $this->recentEditors() ); |
| 83 | + $wgOut->addHTML( $this->recentVoters() ); |
| 84 | + $wgOut->addHTML( $this->embedWidget() ); |
| 85 | + |
| 86 | + $wgOut->addHTML( '</div>' . "\n" ); |
| 87 | + |
| 88 | + $wgOut->addHTML( $this->leftAdUnit() ); |
| 89 | + } |
| 90 | + |
| 91 | + $wgOut->addHTML( "\t\t\t" . '</div><!-- #blog-page-left -->' . "\n" ); |
| 92 | + |
| 93 | + $wgOut->addHTML( '<div id="blog-page-middle">' . "\n" ); |
| 94 | + global $wgUseEditButtonFloat; |
| 95 | + if( $wgUseEditButtonFloat == true && method_exists( $sk, 'editMenu' ) ) { |
| 96 | + $wgOut->addHTML( $sk->editMenu() ); |
| 97 | + } |
| 98 | + $wgOut->addHTML( "<h1 class=\"page-title\">{$wgTitle->getText()}</h1>\n" ); |
| 99 | + $wgOut->addHTML( $this->getByLine() ); |
| 100 | + |
| 101 | + $wgOut->addHTML( "\n<!--start Article::view-->\n" ); |
| 102 | + parent::view(); |
| 103 | + |
| 104 | + // Get categories |
| 105 | + $cat = $sk->getCategoryLinks(); |
| 106 | + if( $cat ) { |
| 107 | + $wgOut->addHTML( "\n<div id=\"catlinks\" class=\"catlinks\">{$cat}</div>\n" ); |
| 108 | + } |
| 109 | + |
| 110 | + $wgOut->addHTML( "\n<!--end Article::view-->\n" ); |
| 111 | + |
| 112 | + $wgOut->addHTML( '</div>' . "\n" ); |
| 113 | + |
| 114 | + if ( $wgBlogPageDisplay['rightcolumn'] == true ) { |
| 115 | + $wgOut->addHTML( '<div id="blog-page-right">' . "\n" ); |
| 116 | + |
| 117 | + $wgOut->addHTML( $this->getPopularArticles() ); |
| 118 | + $wgOut->addHTML( $this->getInTheNews() ); |
| 119 | + $wgOut->addHTML( $this->getCommentsOfTheDay() ); |
| 120 | + $wgOut->addHTML( $this->getRandomCasualGame() ); |
| 121 | + $wgOut->addHTML( $this->getNewArticles() ); |
| 122 | + |
| 123 | + $wgOut->addHTML( '</div>' . "\n" ); |
| 124 | + } |
| 125 | + |
| 126 | + $wgOut->addHTML( '<div class="cleared"></div>' . "\n" ); |
| 127 | + $wgOut->addHTML( '</div><!-- #blog-page-container -->' . "\n" ); |
| 128 | + |
| 129 | + wfProfileOut( __METHOD__ ); |
| 130 | + } |
| 131 | + |
| 132 | + /** |
| 133 | + * Get the authors of this blog post and store them in the authors member |
| 134 | + * variable. |
| 135 | + */ |
| 136 | + function getAuthors() { |
| 137 | + global $wgContLang; |
| 138 | + |
| 139 | + $articleText = $this->pageContent; |
| 140 | + $categoryName = $wgContLang->getNsText( NS_CATEGORY ); |
| 141 | + $blogCat = wfMsgForContent( 'blog-category' ); |
| 142 | + |
| 143 | + // This unbelievably weak and hacky regex is used to find out the |
| 144 | + // author's name from the category. See also getBlurb(), which uses a |
| 145 | + // similar regex. |
| 146 | + preg_match_all( |
| 147 | + "/\[\[(?:(?:c|C)ategory|{$categoryName}):\s?" . |
| 148 | + wfMsgForContent( 'blog-by-user-category', $blogCat ) . |
| 149 | + " (.*)\]\]/", |
| 150 | + $articleText, |
| 151 | + $matches |
| 152 | + ); |
| 153 | + $authors = $matches[1]; |
| 154 | + |
| 155 | + foreach( $authors as $author ) { |
| 156 | + $authorUserId = User::idFromName( $author ); |
| 157 | + $this->authors[] = array( |
| 158 | + 'user_name' => trim( $author ), |
| 159 | + 'user_id' => $authorUserId |
| 160 | + ); |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + /** |
| 165 | + * Get the creation date of the page with the given ID from the revision |
| 166 | + * table and cache it in memcached. |
| 167 | + * The return value of this function can be passed to the various $wgLang |
| 168 | + * methods for i18n-compatible code. |
| 169 | + * |
| 170 | + * @param $pageId Integer: page ID number |
| 171 | + * @return Integer: page creation date |
| 172 | + */ |
| 173 | + public static function getCreateDate( $pageId ) { |
| 174 | + global $wgMemc; |
| 175 | + |
| 176 | + // Try memcached first |
| 177 | + $key = wfMemcKey( 'page', 'create_date', $pageId ); |
| 178 | + $data = $wgMemc->get( $key ); |
| 179 | + |
| 180 | + if( !$data ) { |
| 181 | + wfDebugLog( 'BlogPage', "Loading create_date for page {$pageId} from database" ); |
| 182 | + $dbr = wfGetDB( DB_SLAVE ); |
| 183 | + $createDate = $dbr->selectField( |
| 184 | + 'revision', |
| 185 | + 'rev_timestamp',//'UNIX_TIMESTAMP(rev_timestamp) AS create_date', |
| 186 | + array( 'rev_page' => $pageId ), |
| 187 | + __METHOD__, |
| 188 | + array( 'ORDER BY' => 'rev_timestamp ASC' ) |
| 189 | + ); |
| 190 | + $wgMemc->set( $key, $createDate ); |
| 191 | + } else { |
| 192 | + wfDebugLog( 'BlogPage', "Loading create_date for page {$pageId} from cache" ); |
| 193 | + $createDate = $data; |
| 194 | + } |
| 195 | + |
| 196 | + return $createDate; |
| 197 | + } |
| 198 | + |
| 199 | + /** |
| 200 | + * Get the last edit date of the page with the given ID from the revision |
| 201 | + * table and cache it in memcached. |
| 202 | + * The return value of this function can be passed to the various $wgLang |
| 203 | + * methods for i18n-compatible code. |
| 204 | + * |
| 205 | + * @param $pageId Integer: page ID number |
| 206 | + * @return Integer: page creation date |
| 207 | + */ |
| 208 | + public static function getLastEditTimestamp( $pageId ) { |
| 209 | + global $wgMemc; |
| 210 | + |
| 211 | + // Try memcached first |
| 212 | + $key = wfMemcKey( 'page', 'last_edit_date', $pageId ); |
| 213 | + $data = $wgMemc->get( $key ); |
| 214 | + |
| 215 | + if( !$data ) { |
| 216 | + wfDebugLog( 'BlogPage', "Loading last_edit_date for page {$pageId} from database" ); |
| 217 | + $dbr = wfGetDB( DB_SLAVE ); |
| 218 | + $lastEditDate = $dbr->selectField( |
| 219 | + 'revision', |
| 220 | + 'MAX(rev_timestamp)', |
| 221 | + array( 'rev_page' => $pageId ), |
| 222 | + __METHOD__, |
| 223 | + array( 'ORDER BY' => 'rev_timestamp ASC' ) |
| 224 | + ); |
| 225 | + $wgMemc->set( $key, $lastEditDate ); |
| 226 | + } else { |
| 227 | + wfDebugLog( 'BlogPage', "Loading last_edit_date for page {$pageId} from cache" ); |
| 228 | + $lastEditDate = $data; |
| 229 | + } |
| 230 | + |
| 231 | + return $lastEditDate; |
| 232 | + } |
| 233 | + |
| 234 | + /** |
| 235 | + * Get the "by X, Y and Z" line, which also contains other nifty |
| 236 | + * information, such as the date of the last edit and the creation date. |
| 237 | + * |
| 238 | + * @return String |
| 239 | + */ |
| 240 | + function getByLine() { |
| 241 | + global $wgTitle, $wgLang; |
| 242 | + |
| 243 | + $count = 0; |
| 244 | + |
| 245 | + // Get date of last edit |
| 246 | + /* |
| 247 | + $year = substr( $wgTitle->getTouched(), 0, 4 ); |
| 248 | + $month = substr( $wgTitle->getTouched(), 4, 2 ); |
| 249 | + $day = substr( $wgTitle->getTouched(), 6, 2 ); |
| 250 | + $edit_date = date( 'F d, Y', mktime( 0, 0, 0, $month, $day, $year ) ); |
| 251 | + */ |
| 252 | + //$edit_date = $wgLang->timeanddate( $wgTitle->getTouched(), true ); |
| 253 | + // Title::getTouched() sucks, because apparently voting for a page |
| 254 | + // invalidates page cache, too... --ashley, 7 August 2011 |
| 255 | + $edit_date = $wgLang->timeanddate( |
| 256 | + self::getLastEditTimestamp( $wgTitle->getArticleID() ), |
| 257 | + true |
| 258 | + ); |
| 259 | + |
| 260 | + // Get date of when article was created |
| 261 | + #$create_date = date( 'F d, Y', $this->getCreateDate( $wgTitle->getArticleID() ) ); |
| 262 | + $create_date = $wgLang->timeanddate( |
| 263 | + self::getCreateDate( $wgTitle->getArticleID() ), |
| 264 | + true |
| 265 | + ); |
| 266 | + |
| 267 | + $output = '<div class="blog-byline">' . wfMsg( 'blog-by' ) . ' '; |
| 268 | + |
| 269 | + $authors = ''; |
| 270 | + foreach( $this->authors as $author ) { |
| 271 | + $count++; |
| 272 | + $userTitle = Title::makeTitle( NS_USER, $author['user_name'] ); |
| 273 | + if ( $authors && count( $this->authors ) > 2 ) { |
| 274 | + $authors .= ', '; |
| 275 | + } |
| 276 | + if ( $count == count( $this->authors ) && $count != 1 ) { |
| 277 | + $authors .= wfMsg( 'word-separator' ) . wfMsg( 'blog-and' ) . |
| 278 | + wfMsg( 'word-separator' ); |
| 279 | + } |
| 280 | + $authors .= "<a href=\"{$userTitle->escapeFullURL()}\">{$author['user_name']}</a>"; |
| 281 | + } |
| 282 | + |
| 283 | + $output .= $authors; |
| 284 | + |
| 285 | + $output .= '</div>'; |
| 286 | + |
| 287 | + $edit_text = ''; |
| 288 | + if( $create_date != $edit_date ) { |
| 289 | + $edit_text = ', ' . wfMsg( 'blog-last-edited', $edit_date ); |
| 290 | + } |
| 291 | + $output .= "\n" . '<div class="blog-byline-last-edited">' . |
| 292 | + wfMsg( 'blog-created', $create_date ) . " {$edit_text}</div>"; |
| 293 | + |
| 294 | + return $output; |
| 295 | + } |
| 296 | + |
| 297 | + function displayMultipleAuthorsMessage() { |
| 298 | + $count = 0; |
| 299 | + |
| 300 | + $authors = ''; |
| 301 | + foreach( $this->authors as $author ) { |
| 302 | + $count++; |
| 303 | + $userTitle = Title::makeTitle( NS_USER, $author['user_name'] ); |
| 304 | + if ( $authors && count( $this->authors ) > 2 ) { |
| 305 | + $authors .= ', '; |
| 306 | + } |
| 307 | + if ( $count == count( $this->authors ) ) { |
| 308 | + $authors .= wfMsg( 'word-separator' ) . wfMsg( 'blog-and' ) . |
| 309 | + wfMsg( 'word-separator' ); |
| 310 | + } |
| 311 | + $authors .= "<a href=\"{$userTitle->escapeFullURL()}\">{$author['user_name']}</a>"; |
| 312 | + } |
| 313 | + |
| 314 | + $output = '<div class="multiple-authors-message">' . |
| 315 | + wfMsg( 'blog-multiple-authors', $authors ) . |
| 316 | + '</div>'; |
| 317 | + |
| 318 | + return $output; |
| 319 | + } |
| 320 | + |
| 321 | + function displayAuthorBox( $author_index ) { |
| 322 | + global $wgOut, $wgBlogPageDisplay; |
| 323 | + |
| 324 | + if ( $wgBlogPageDisplay['author'] == false ) { |
| 325 | + return ''; |
| 326 | + } |
| 327 | + |
| 328 | + $author_user_name = $author_user_id = ''; |
| 329 | + if ( |
| 330 | + isset( $this->authors[$author_index] ) && |
| 331 | + isset( $this->authors[$author_index]['user_name'] ) |
| 332 | + ) |
| 333 | + { |
| 334 | + $author_user_name = $this->authors[$author_index]['user_name']; |
| 335 | + } |
| 336 | + if ( |
| 337 | + isset( $this->authors[$author_index] ) && |
| 338 | + isset( $this->authors[$author_index]['user_id'] ) |
| 339 | + ) |
| 340 | + { |
| 341 | + $author_user_id = $this->authors[$author_index]['user_id']; |
| 342 | + } |
| 343 | + |
| 344 | + if( empty( $author_user_id ) ) { |
| 345 | + return ''; |
| 346 | + } |
| 347 | + |
| 348 | + $authorTitle = Title::makeTitle( NS_USER, $author_user_name ); |
| 349 | + |
| 350 | + $profile = new UserProfile( $author_user_name ); |
| 351 | + $profileData = $profile->getProfile(); |
| 352 | + |
| 353 | + $avatar = new wAvatar( $author_user_id, 'm' ); |
| 354 | + |
| 355 | + $articles = $this->getAuthorArticles( $author_index ); |
| 356 | + $cssFix = ''; |
| 357 | + if( !$articles ) { |
| 358 | + $cssFix = ' author-container-fix'; |
| 359 | + } |
| 360 | + $output = "\t\t\t\t\t<div class=\"author-container$cssFix\"> |
| 361 | + <div class=\"author-info\"> |
| 362 | + <a href=\"" . $authorTitle->escapeFullURL() . "\" rel=\"nofollow\"> |
| 363 | + {$avatar->getAvatarURL()} |
| 364 | + </a> |
| 365 | + <div class=\"author-title\"> |
| 366 | + <a href=\"" . $authorTitle->escapeFullURL() . |
| 367 | + '" rel="nofollow">' . |
| 368 | + wordwrap( $author_user_name, 12, "<br />\n", true ) . |
| 369 | + '</a> |
| 370 | + </div>'; |
| 371 | + // If the user has supplied some information about themselves on their |
| 372 | + // social profile, show that data here. |
| 373 | + if( $profileData['about'] ) { |
| 374 | + $output .= $wgOut->parse( $profileData['about'], false ); |
| 375 | + } |
| 376 | + $output .= "\n\t\t\t\t\t\t</div><!-- .author-info --> |
| 377 | + <div class=\"cleared\"></div> |
| 378 | + </div><!-- .author-container --> |
| 379 | + {$this->getAuthorArticles( $author_index )}"; |
| 380 | + |
| 381 | + return $output; |
| 382 | + } |
| 383 | + |
| 384 | + function getAuthorArticles( $author_index ) { |
| 385 | + global $wgTitle, $wgOut, $wgBlogPageDisplay, $wgMemc; |
| 386 | + |
| 387 | + if ( $wgBlogPageDisplay['author_articles'] == false ) { |
| 388 | + return ''; |
| 389 | + } |
| 390 | + |
| 391 | + $user_name = $this->authors[$author_index]['user_name']; |
| 392 | + $user_id = $this->authors[$author_index]['user_id']; |
| 393 | + $blogCat = wfMsgForContent( 'blog-category' ); |
| 394 | + |
| 395 | + $archiveLink = Title::makeTitle( |
| 396 | + NS_CATEGORY, |
| 397 | + wfMsg( 'blog-by-user-category', $blogCat ) . " {$user_name}" |
| 398 | + ); |
| 399 | + |
| 400 | + $articles = array(); |
| 401 | + |
| 402 | + // Try cache first |
| 403 | + $key = wfMemcKey( 'blog', 'author', 'articles', $user_id ); |
| 404 | + $data = $wgMemc->get( $key ); |
| 405 | + |
| 406 | + if ( $data != '' ) { |
| 407 | + wfDebugLog( 'BlogPage', "Got blog author articles for user {$user_name} from cache" ); |
| 408 | + $articles = $data; |
| 409 | + } else { |
| 410 | + wfDebugLog( 'BlogPage', "Got blog author articles for user {$user_name} from DB" ); |
| 411 | + $dbr = wfGetDB( DB_SLAVE ); |
| 412 | + $categoryTitle = Title::newFromText( |
| 413 | + wfMsg( 'blog-by-user-category', $blogCat ) . " {$user_name}" |
| 414 | + ); |
| 415 | + $res = $dbr->select( |
| 416 | + array( 'page', 'categorylinks'), |
| 417 | + array( 'DISTINCT(page_id) AS page_id', 'page_title' ), |
| 418 | + /* WHERE */array( |
| 419 | + 'cl_to' => array( $categoryTitle->getDBkey() ), |
| 420 | + 'page_namespace' => NS_BLOG |
| 421 | + ), |
| 422 | + __METHOD__, |
| 423 | + array( |
| 424 | + 'ORDER BY' => 'page_id DESC', |
| 425 | + 'LIMIT' => 4 |
| 426 | + ), |
| 427 | + array( |
| 428 | + 'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ) |
| 429 | + ) |
| 430 | + ); |
| 431 | + |
| 432 | + $array_count = 0; |
| 433 | + |
| 434 | + foreach( $res as $row ) { |
| 435 | + if ( $row->page_id != $wgTitle->getArticleID() && $array_count < 3 ) { |
| 436 | + $articles[] = array( |
| 437 | + 'page_title' => $row->page_title, |
| 438 | + 'page_id' => $row->page_id |
| 439 | + ); |
| 440 | + |
| 441 | + $array_count++; |
| 442 | + } |
| 443 | + } |
| 444 | + |
| 445 | + // Cache for half an hour |
| 446 | + $wgMemc->set( $key, $articles, 60 * 30 ); |
| 447 | + } |
| 448 | + |
| 449 | + $output = ''; |
| 450 | + if ( count( $articles ) > 0 ) { |
| 451 | + $css_fix = ''; |
| 452 | + |
| 453 | + if( |
| 454 | + count( $this->getVotersList() ) == 0 && |
| 455 | + count( $this->getEditorsList() ) == 0 |
| 456 | + ) |
| 457 | + { |
| 458 | + $css_fix = ' more-container-fix'; |
| 459 | + } |
| 460 | + |
| 461 | + $output .= "<div class=\"more-container{$css_fix}\"> |
| 462 | + <h3>" . wfMsg( 'blog-author-more-by', $user_name ) . '</h3>'; |
| 463 | + |
| 464 | + $x = 1; |
| 465 | + |
| 466 | + foreach ( $articles as $article ) { |
| 467 | + $articleTitle = Title::makeTitle( NS_BLOG, $article['page_title'] ); |
| 468 | + |
| 469 | + $output .= '<div class="author-article-item"> |
| 470 | + <a href="' . $articleTitle->escapeFullURL() . "\">{$articleTitle->getText()}</a> |
| 471 | + <div class=\"author-item-small\">" . |
| 472 | + wfMsgExt( |
| 473 | + 'blog-author-votes', |
| 474 | + 'parsemag', |
| 475 | + BlogPage::getVotesForPage( $article['page_id'] ) |
| 476 | + ) . ', ' . |
| 477 | + wfMsgExt( |
| 478 | + 'blog-author-comments', |
| 479 | + 'parsemag', |
| 480 | + BlogPage::getCommentsForPage( $article['page_id'] ) |
| 481 | + ) . |
| 482 | + '</div> |
| 483 | + </div>'; |
| 484 | + |
| 485 | + $x++; |
| 486 | + } |
| 487 | + |
| 488 | + $output .= '<div class="author-archive-link"> |
| 489 | + <a href="' . $archiveLink->escapeFullURL() . '">' . |
| 490 | + wfMsg( 'blog-view-archive-link' ) . |
| 491 | + '</a> |
| 492 | + </div> |
| 493 | + </div>'; |
| 494 | + } |
| 495 | + |
| 496 | + return $output; |
| 497 | + } |
| 498 | + |
| 499 | + /** |
| 500 | + * Get the eight newest editors for the current blog post from the revision |
| 501 | + * table. |
| 502 | + * |
| 503 | + * @return Array: array containing each editors' user ID and user name |
| 504 | + */ |
| 505 | + function getEditorsList() { |
| 506 | + global $wgMemc, $wgTitle; |
| 507 | + |
| 508 | + $pageTitleId = $wgTitle->getArticleID(); |
| 509 | + |
| 510 | + $key = wfMemcKey( 'recenteditors', 'list', $pageTitleId ); |
| 511 | + $data = $wgMemc->get( $key ); |
| 512 | + $editors = array(); |
| 513 | + |
| 514 | + if( !$data ) { |
| 515 | + wfDebugLog( 'BlogPage', "Loading recent editors for page {$pageTitleId} from DB" ); |
| 516 | + $dbr = wfGetDB( DB_SLAVE ); |
| 517 | + |
| 518 | + $where = array( |
| 519 | + 'rev_page' => $pageTitleId, |
| 520 | + 'rev_user <> 0', // exclude anonymous editors |
| 521 | + "rev_user_text <> 'MediaWiki default'", // exclude MW default |
| 522 | + ); |
| 523 | + |
| 524 | + // Get authors and exclude them |
| 525 | + foreach( $this->authors as $author ) { |
| 526 | + $where[] = 'rev_user_text <> \'' . $author['user_name'] . '\''; |
| 527 | + } |
| 528 | + |
| 529 | + $res = $dbr->select( |
| 530 | + 'revision', |
| 531 | + array( 'DISTINCT rev_user', 'rev_user_text' ), |
| 532 | + $where, |
| 533 | + __METHOD__, |
| 534 | + array( 'ORDER BY' => 'rev_user_text ASC', 'LIMIT' => 8 ) |
| 535 | + ); |
| 536 | + |
| 537 | + foreach( $res as $row ) { |
| 538 | + $editors[] = array( |
| 539 | + 'user_id' => $row->rev_user, |
| 540 | + 'user_name' => $row->rev_user_text |
| 541 | + ); |
| 542 | + } |
| 543 | + |
| 544 | + // Store in memcached for five minutes |
| 545 | + $wgMemc->set( $key, $editors, 60 * 5 ); |
| 546 | + } else { |
| 547 | + wfDebugLog( 'BlogPage', "Loading recent editors for page {$pageTitleId} from cache" ); |
| 548 | + $editors = $data; |
| 549 | + } |
| 550 | + |
| 551 | + return $editors; |
| 552 | + } |
| 553 | + |
| 554 | + /** |
| 555 | + * Get the avatars of the people who recently edited this blog post, if |
| 556 | + * this feature is enabled in BlogPage config. |
| 557 | + * |
| 558 | + * @return String: HTML or nothing |
| 559 | + */ |
| 560 | + function recentEditors() { |
| 561 | + global $wgUploadPath, $wgBlogPageDisplay; |
| 562 | + |
| 563 | + if ( $wgBlogPageDisplay['recent_editors'] == false ) { |
| 564 | + return ''; |
| 565 | + } |
| 566 | + |
| 567 | + $editors = $this->getEditorsList(); |
| 568 | + |
| 569 | + $output = ''; |
| 570 | + |
| 571 | + if ( count( $editors ) > 0 ) { |
| 572 | + $output .= '<div class="recent-container"> |
| 573 | + <h2>' . wfMsg( 'blog-recent-editors' ) . '</h2> |
| 574 | + <div>' . wfMsg( 'blog-recent-editors-message' ) . '</div>'; |
| 575 | + |
| 576 | + foreach( $editors as $editor ) { |
| 577 | + $avatar = new wAvatar( $editor['user_id'], 'm' ); |
| 578 | + $userTitle = Title::makeTitle( NS_USER, $editor['user_name'] ); |
| 579 | + |
| 580 | + $output .= '<a href="' . $userTitle->escapeFullURL() . |
| 581 | + "\"><img src=\"{$wgUploadPath}/avatars/{$avatar->getAvatarImage()}\" alt=\"" . |
| 582 | + $userTitle->getText() . '" border="0" /></a>'; |
| 583 | + } |
| 584 | + |
| 585 | + $output .= '</div>'; |
| 586 | + } |
| 587 | + |
| 588 | + return $output; |
| 589 | + } |
| 590 | + |
| 591 | + /** |
| 592 | + * Get the eight newest voters for the current blog post from VoteNY's |
| 593 | + * Vote table. |
| 594 | + * |
| 595 | + * @return Array: array containing each voters' user ID and user name |
| 596 | + */ |
| 597 | + function getVotersList() { |
| 598 | + global $wgMemc, $wgTitle; |
| 599 | + |
| 600 | + // Gets the page ID for the query |
| 601 | + $pageTitleId = $wgTitle->getArticleID(); |
| 602 | + |
| 603 | + $key = wfMemcKey( 'recentvoters', 'list', $pageTitleId ); |
| 604 | + $data = $wgMemc->get( $key ); |
| 605 | + |
| 606 | + $voters = array(); |
| 607 | + if( !$data ) { |
| 608 | + wfDebugLog( 'BlogPage', "Loading recent voters for page {$pageTitleId} from DB" ); |
| 609 | + $dbr = wfGetDB( DB_SLAVE ); |
| 610 | + |
| 611 | + $where = array( |
| 612 | + 'vote_page_id' => $pageTitleId, |
| 613 | + 'vote_user_id <> 0' |
| 614 | + ); |
| 615 | + |
| 616 | + // Exclude the authors of the blog post from the list of recent |
| 617 | + // voters |
| 618 | + foreach( $this->authors as $author ) { |
| 619 | + $where[] = 'username <> \'' . $author['user_name'] . '\''; |
| 620 | + } |
| 621 | + |
| 622 | + $res = $dbr->select( |
| 623 | + 'Vote', |
| 624 | + array( 'DISTINCT username', 'vote_user_id', 'vote_page_id' ), |
| 625 | + $where, |
| 626 | + __METHOD__, |
| 627 | + array( 'ORDER BY' => 'vote_id DESC', 'LIMIT' => 8 ) |
| 628 | + ); |
| 629 | + |
| 630 | + foreach ( $res as $row ) { |
| 631 | + $voters[] = array( |
| 632 | + 'user_id' => $row->vote_user_id, |
| 633 | + 'user_name' => $row->username |
| 634 | + ); |
| 635 | + } |
| 636 | + |
| 637 | + $wgMemc->set( $key, $voters, 60 * 5 ); |
| 638 | + } else { |
| 639 | + wfDebugLog( 'BlogPage', "Loading recent voters for page {$pageTitleId} from cache" ); |
| 640 | + $voters = $data; |
| 641 | + } |
| 642 | + |
| 643 | + return $voters; |
| 644 | + } |
| 645 | + |
| 646 | + /** |
| 647 | + * Get the avatars of the people who recently voted for this blog post, if |
| 648 | + * this feature is enabled in BlogPage config. |
| 649 | + * |
| 650 | + * @return String: HTML or nothing |
| 651 | + */ |
| 652 | + function recentVoters() { |
| 653 | + global $wgBlogPageDisplay; |
| 654 | + |
| 655 | + if ( $wgBlogPageDisplay['recent_voters'] == false ) { |
| 656 | + return ''; |
| 657 | + } |
| 658 | + |
| 659 | + $voters = $this->getVotersList(); |
| 660 | + |
| 661 | + $output = ''; |
| 662 | + |
| 663 | + if( count( $voters ) > 0 ) { |
| 664 | + $output .= '<div class="recent-container bottom-fix"> |
| 665 | + <h2>' . wfMsg( 'blog-recent-voters' ) . '</h2> |
| 666 | + <div>' . wfMsg( 'blog-recent-voters-message' ) . '</div>'; |
| 667 | + |
| 668 | + foreach( $voters as $voter ) { |
| 669 | + $userTitle = Title::makeTitle( NS_USER, $voter['user_name'] ); |
| 670 | + $avatar = new wAvatar( $voter['user_id'], 'm' ); |
| 671 | + |
| 672 | + $output .= '<a href="' . $userTitle->escapeFullURL() . |
| 673 | + "\">{$avatar->getAvatarURL()}</a>"; |
| 674 | + } |
| 675 | + |
| 676 | + $output .= '</div>'; |
| 677 | + } |
| 678 | + |
| 679 | + return $output; |
| 680 | + } |
| 681 | + |
| 682 | + /** |
| 683 | + * Get the embed widget, if this feature is enabled in BlogPage config. |
| 684 | + * |
| 685 | + * @return String: HTML or nothing |
| 686 | + */ |
| 687 | + function embedWidget() { |
| 688 | + global $wgTitle, $wgBlogPageDisplay, $wgServer, $wgScriptPath; |
| 689 | + |
| 690 | + // Not enabled? ContentWidget not available? |
| 691 | + if ( |
| 692 | + $wgBlogPageDisplay['embed_widget'] == false || |
| 693 | + !is_dir( dirname( __FILE__ ) . '/../extensions/ContentWidget' ) |
| 694 | + ) |
| 695 | + { |
| 696 | + return ''; |
| 697 | + } |
| 698 | + |
| 699 | + $title = Title::makeTitle( $wgTitle->getNamespace(), $wgTitle->getText() ); |
| 700 | + |
| 701 | + $output = ''; |
| 702 | + $output .= '<div class="recent-container bottom-fix"><h2>' . |
| 703 | + wfMsg( 'blog-embed-title' ) . '</h2>'; |
| 704 | + $output .= '<div class="blog-widget-embed">'; |
| 705 | + $output .= "<p><input type='text' size='20' onclick='this.select();' value='" . |
| 706 | + '<object width="300" height="450" id="content_widget" align="middle"> <param name="movie" value="content_widget.swf" /><embed src="' . |
| 707 | + $wgServer . $wgScriptPath . '/extensions/ContentWidget/widget.swf?page=' . |
| 708 | + urlencode( $title->getFullText() ) . '" quality="high" bgcolor="#ffffff" width="300" height="450" name="content_widget"type="application/x-shockwave-flash" /> </object>' . "' /></p></div>"; |
| 709 | + $output .= '</div>'; |
| 710 | + |
| 711 | + return $output; |
| 712 | + } |
| 713 | + |
| 714 | + /** |
| 715 | + * Get an ad unit for the left side, if this feature is enabled in BlogPage |
| 716 | + * config. |
| 717 | + * |
| 718 | + * @return String: HTML or nothing |
| 719 | + */ |
| 720 | + function leftAdUnit() { |
| 721 | + global $wgBlogPageDisplay; |
| 722 | + |
| 723 | + if ( $wgBlogPageDisplay['left_ad'] == false ) { |
| 724 | + return ''; |
| 725 | + } |
| 726 | + |
| 727 | + $output = '<div class="article-ad"> |
| 728 | + <!-- BlogPage ad temporarily disabled --> |
| 729 | + </div>'; |
| 730 | + |
| 731 | + return $output; |
| 732 | + } |
| 733 | + |
| 734 | + /** |
| 735 | + * Get some random news items from MediaWiki:Inthenews, if this feature is |
| 736 | + * enabled in BlogPage config and that interface message has some content. |
| 737 | + * |
| 738 | + * @return String: HTML or nothing |
| 739 | + */ |
| 740 | + function getInTheNews() { |
| 741 | + global $wgBlogPageDisplay, $wgMemc, $wgOut; |
| 742 | + |
| 743 | + if ( $wgBlogPageDisplay['in_the_news'] == false ) { |
| 744 | + return ''; |
| 745 | + } |
| 746 | + |
| 747 | + $output = ''; |
| 748 | + $message = wfMsgForContent( 'inthenews' ); |
| 749 | + if ( !wfEmptyMsg( 'inthenews', $message ) ) { |
| 750 | + $newsArray = explode( "\n\n", $message ); |
| 751 | + $newsItem = $newsArray[array_rand( $newsArray )]; |
| 752 | + $output = '<div class="blog-container"> |
| 753 | + <h2>' . wfMsg( 'blog-in-the-news' ) . '</h2> |
| 754 | + <div>' . $wgOut->parse( $newsItem, false ) . '</div> |
| 755 | + </div>'; |
| 756 | + } |
| 757 | + |
| 758 | + return $output; |
| 759 | + } |
| 760 | + |
| 761 | + /** |
| 762 | + * Get the five most popular blog articles, if this feature is enabled in |
| 763 | + * BlogPage config. |
| 764 | + * |
| 765 | + * @return String: HTML or nothing |
| 766 | + */ |
| 767 | + function getPopularArticles() { |
| 768 | + global $wgMemc, $wgBlogPageDisplay; |
| 769 | + |
| 770 | + if ( $wgBlogPageDisplay['popular_articles'] == false ) { |
| 771 | + return ''; |
| 772 | + } |
| 773 | + |
| 774 | + // Try cache first |
| 775 | + $key = wfMemcKey( 'blog', 'popular', 'five' ); |
| 776 | + $data = $wgMemc->get( $key ); |
| 777 | + |
| 778 | + if( $data != '' ) { |
| 779 | + wfDebugLog( 'BlogPage', 'Got popular articles from cache' ); |
| 780 | + $popularBlogPosts = $data; |
| 781 | + } else { |
| 782 | + wfDebugLog( 'BlogPage', 'Got popular articles from DB' ); |
| 783 | + $blogCat = wfMsgForContent( 'blog-category' ); |
| 784 | + $dbr = wfGetDB( DB_SLAVE ); |
| 785 | + // Code sporked from Rob Church's NewestPages extension |
| 786 | + // @todo FIXME: adding categorylinks table and that one where |
| 787 | + // clause causes an error about "unknown column 'page_id' on ON |
| 788 | + // clause" |
| 789 | + $commentsTable = $dbr->tableName( 'Comments' ); |
| 790 | + $voteTable = $dbr->tableName( 'Vote' ); |
| 791 | + $res = $dbr->select( |
| 792 | + array( 'page', /*'categorylinks',*/ 'Comments', 'Vote' ), |
| 793 | + array( |
| 794 | + 'DISTINCT page_id', 'page_namespace', 'page_is_redirect', |
| 795 | + 'page_title', |
| 796 | + ), |
| 797 | + array( |
| 798 | + 'page_namespace' => NS_BLOG, |
| 799 | + 'page_is_redirect' => 0, |
| 800 | + 'page_id = Comment_Page_ID', |
| 801 | + 'page_id = vote_page_id', |
| 802 | + #'cl_to ' . $dbr->buildLike( /*$dbr->anyString(), */$blogCat, $dbr->anyString() ), |
| 803 | + // If you can figure out how to do this without a subquery, |
| 804 | + // please let me know. Until that... |
| 805 | + "((SELECT COUNT(*) FROM $voteTable WHERE vote_page_id = page_id) >= 5 OR |
| 806 | + (SELECT COUNT(*) FROM $commentsTable WHERE Comment_Page_ID = page_id) >= 5)", |
| 807 | + ), |
| 808 | + __METHOD__, |
| 809 | + array( |
| 810 | + 'ORDER BY' => 'page_id DESC', |
| 811 | + 'LIMIT' => 10 |
| 812 | + ), |
| 813 | + array( |
| 814 | + 'Comments' => array( 'INNER JOIN', 'page_id = Comment_Page_ID' ), |
| 815 | + 'Vote' => array( 'INNER JOIN', 'page_id = vote_page_id' ) |
| 816 | + ) |
| 817 | + ); |
| 818 | + |
| 819 | + $popularBlogPosts = array(); |
| 820 | + foreach ( $res as $row ) { |
| 821 | + $popularBlogPosts[] = array( |
| 822 | + 'title' => $row->page_title, |
| 823 | + 'id' => $row->page_id |
| 824 | + ); |
| 825 | + } |
| 826 | + |
| 827 | + // Cache in memcached for 15 minutes |
| 828 | + $wgMemc->set( $key, $popularBlogPosts, 60 * 15 ); |
| 829 | + } |
| 830 | + |
| 831 | + $html = '<div class="listpages-container">'; |
| 832 | + foreach( $popularBlogPosts as $popularBlogPost ) { |
| 833 | + $titleObj = Title::makeTitle( NS_BLOG, $popularBlogPost['title'] ); |
| 834 | + $html .= '<div class="listpages-item"> |
| 835 | + <a href="' . $titleObj->escapeFullURL() . '">' . |
| 836 | + $titleObj->getText() . |
| 837 | + '</a> |
| 838 | + </div> |
| 839 | + <div class="cleared"></div>'; |
| 840 | + } |
| 841 | + $html .= '</div>'; // .listpages-container |
| 842 | + |
| 843 | + $output = '<div class="blog-container"> |
| 844 | + <h2>' . wfMsg( 'blog-popular-articles' ) . '</h2> |
| 845 | + <div>' . $html . '</div> |
| 846 | + </div>'; |
| 847 | + |
| 848 | + return $output; |
| 849 | + } |
| 850 | + |
| 851 | + /** |
| 852 | + * Get the newest blog articles, if this feature is enabled in BlogPage |
| 853 | + * config. |
| 854 | + * |
| 855 | + * @return String: HTML or nothing |
| 856 | + */ |
| 857 | + function getNewArticles() { |
| 858 | + global $wgOut, $wgMemc, $wgBlogPageDisplay; |
| 859 | + |
| 860 | + if ( $wgBlogPageDisplay['new_articles'] == false ) { |
| 861 | + return ''; |
| 862 | + } |
| 863 | + |
| 864 | + // Try cache first |
| 865 | + $key = wfMemcKey( 'blog', 'new', 'five' ); |
| 866 | + $data = $wgMemc->get( $key ); |
| 867 | + |
| 868 | + if( $data != '' ) { |
| 869 | + wfDebugLog( 'BlogPage', 'Got new articles from cache' ); |
| 870 | + $newBlogPosts = $data; |
| 871 | + } else { |
| 872 | + wfDebugLog( 'BlogPage', 'Got new articles from DB' ); |
| 873 | + // We could do complicated LIKE stuff with the categorylinks table, |
| 874 | + // but I think we can safely assume that stuff in the NS_BLOG NS |
| 875 | + // is blog-related :) |
| 876 | + //$blogCat = wfMsgForContent( 'blog-category' ); |
| 877 | + $dbr = wfGetDB( DB_SLAVE ); |
| 878 | + // Code sporked from Rob Church's NewestPages extension |
| 879 | + $res = $dbr->select( |
| 880 | + 'page', |
| 881 | + array( 'page_namespace', 'page_title', 'page_is_redirect' ), |
| 882 | + array( 'page_namespace' => NS_BLOG, 'page_is_redirect' => 0 ), |
| 883 | + __METHOD__, |
| 884 | + array( 'ORDER BY' => 'page_id DESC', 'LIMIT' => 5 ) |
| 885 | + ); |
| 886 | + |
| 887 | + $newBlogPosts = array(); |
| 888 | + foreach ( $res as $row ) { |
| 889 | + $newBlogPosts[] = array( |
| 890 | + 'title' => $row->page_title, |
| 891 | + ); |
| 892 | + } |
| 893 | + |
| 894 | + // Cache in memcached for 15 minutes |
| 895 | + $wgMemc->set( $key, $newBlogPosts, 60 * 15 ); |
| 896 | + } |
| 897 | + |
| 898 | + $html = '<div class="listpages-container">'; |
| 899 | + foreach( $newBlogPosts as $newBlogPost ) { |
| 900 | + $titleObj = Title::makeTitle( NS_BLOG, $newBlogPost['title'] ); |
| 901 | + $html .= '<div class="listpages-item"> |
| 902 | + <a href="' . $titleObj->escapeFullURL() . '">' . |
| 903 | + $titleObj->getText() . |
| 904 | + '</a> |
| 905 | + </div> |
| 906 | + <div class="cleared"></div>'; |
| 907 | + } |
| 908 | + $html .= '</div>'; // .listpages-container |
| 909 | + |
| 910 | + $output = '<div class="blog-container bottom-fix"> |
| 911 | + <h2>' . wfMsg( 'blog-new-articles' ) . '</h2> |
| 912 | + <div>' . $html . '</div> |
| 913 | + </div>'; |
| 914 | + |
| 915 | + return $output; |
| 916 | + } |
| 917 | + |
| 918 | + /** |
| 919 | + * Get a random casual game, if this feature is enabled in BlogPage config |
| 920 | + * and the RandomGameUnit extension is installed. |
| 921 | + * |
| 922 | + * @return String: HTML or nothing |
| 923 | + */ |
| 924 | + function getRandomCasualGame() { |
| 925 | + global $wgBlogPageDisplay; |
| 926 | + |
| 927 | + if ( |
| 928 | + $wgBlogPageDisplay['games'] == false || |
| 929 | + !function_exists( 'wfGetRandomGameUnit' ) |
| 930 | + ) |
| 931 | + { |
| 932 | + return ''; |
| 933 | + } |
| 934 | + |
| 935 | + return wfGetRandomGameUnit(); |
| 936 | + } |
| 937 | + |
| 938 | + /** |
| 939 | + * Get comments of the day, if this feature is enabled in BlogPage config. |
| 940 | + * Requires the Comments extension. |
| 941 | + * |
| 942 | + * @return String: HTML or nothing |
| 943 | + */ |
| 944 | + function getCommentsOfTheDay() { |
| 945 | + global $wgBlogPageDisplay, $wgMemc, $wgLang; |
| 946 | + |
| 947 | + if ( $wgBlogPageDisplay['comments_of_day'] == false ) { |
| 948 | + return ''; |
| 949 | + } |
| 950 | + |
| 951 | + $comments = array(); |
| 952 | + |
| 953 | + // Try cache first |
| 954 | + $key = wfMemcKey( 'comments', 'plus', '24hours' ); |
| 955 | + $data = $wgMemc->get( $key ); |
| 956 | + |
| 957 | + if( $data != '' ) { |
| 958 | + wfDebugLog( 'BlogPage', 'Got comments of the day from cache' ); |
| 959 | + $comments = $data; |
| 960 | + } else { |
| 961 | + wfDebugLog( 'BlogPage', 'Got comments of the day from DB' ); |
| 962 | + $dbr = wfGetDB( DB_SLAVE ); |
| 963 | + $res = $dbr->select( |
| 964 | + array( 'Comments', 'page' ), |
| 965 | + array( |
| 966 | + 'Comment_Username', 'comment_ip', 'comment_text', |
| 967 | + 'comment_date', 'Comment_user_id', 'CommentID', |
| 968 | + 'IFNULL(Comment_Plus_Count - Comment_Minus_Count,0) AS Comment_Score', |
| 969 | + 'Comment_Plus_Count AS CommentVotePlus', |
| 970 | + 'Comment_Minus_Count AS CommentVoteMinus', |
| 971 | + 'Comment_Parent_ID', 'page_title', 'page_namespace' |
| 972 | + ), |
| 973 | + array( |
| 974 | + 'comment_page_id = page_id', |
| 975 | + 'UNIX_TIMESTAMP(comment_date) > ' . ( time() - ( 60 * 60 * 24 ) ), |
| 976 | + 'page_namespace' => NS_BLOG |
| 977 | + ), |
| 978 | + __METHOD__, |
| 979 | + array( 'ORDER BY' => 'Comment_Plus_Count DESC', 'LIMIT' => 5 ) |
| 980 | + ); |
| 981 | + |
| 982 | + foreach( $res as $row ) { |
| 983 | + $comments[] = array( |
| 984 | + 'user_name' => $row->Comment_Username, |
| 985 | + 'user_id' => $row->Comment_user_id, |
| 986 | + 'title' => $row->page_title, |
| 987 | + 'namespace' => $row->page_namespace, |
| 988 | + 'comment_id' => $row->CommentID, |
| 989 | + 'plus_count' => $row->CommentVotePlus, |
| 990 | + 'comment_text' => $row->comment_text |
| 991 | + ); |
| 992 | + } |
| 993 | + |
| 994 | + $wgMemc->set( $key, $comments, 60 * 15 ); |
| 995 | + } |
| 996 | + |
| 997 | + $output = ''; |
| 998 | + |
| 999 | + foreach( $comments as $comment ) { |
| 1000 | + $page_title = Title::makeTitle( $comment['namespace'], $comment['title'] ); |
| 1001 | + |
| 1002 | + if( $comment['user_id'] != 0 ) { |
| 1003 | + $commentPosterDisplay = $comment['user_name']; |
| 1004 | + } else { |
| 1005 | + $commentPosterDisplay = wfMsg( 'blog-anonymous-name' ); |
| 1006 | + } |
| 1007 | + |
| 1008 | + $comment['comment_text'] = strip_tags( $comment['comment_text'] ); |
| 1009 | + $comment_text = $wgLang->truncate( |
| 1010 | + $comment['comment_text'], |
| 1011 | + ( 70 - strlen( $commentPosterDisplay ) ) |
| 1012 | + ); |
| 1013 | + |
| 1014 | + $output .= '<div class="cod-item">'; |
| 1015 | + $output .= "<span class=\"cod-score\">{$comment['plus_count']}</span> "; |
| 1016 | + $output .= " <span class=\"cod-comment\"><a href=\"{$page_title->escapeFullURL()}#comment-{$comment['comment_id']}\" title=\"{$page_title->getText()}\" >{$comment_text}</a></span>"; |
| 1017 | + $output .= '</div>'; |
| 1018 | + } |
| 1019 | + |
| 1020 | + if ( count( $comments ) > 0 ) { |
| 1021 | + $output = '<div class="blog-container"> |
| 1022 | + <h2>' . wfMsg( 'blog-comments-of-day' ) . '</h2>' . |
| 1023 | + $output . |
| 1024 | + '</div>'; |
| 1025 | + } |
| 1026 | + |
| 1027 | + return $output; |
| 1028 | + } |
| 1029 | + |
| 1030 | + /** |
| 1031 | + * Get the amount (COUNT(*)) of comments for the given page, identified via |
| 1032 | + * its ID and cache this info in memcached for 15 minutes. |
| 1033 | + * |
| 1034 | + * @param $id Integer: page ID |
| 1035 | + * @return Integer: amount of comments |
| 1036 | + */ |
| 1037 | + public static function getCommentsForPage( $id ) { |
| 1038 | + global $wgMemc; |
| 1039 | + |
| 1040 | + // Try cache first |
| 1041 | + $key = wfMemcKey( 'blog', 'comments', 'count' ); |
| 1042 | + $data = $wgMemc->get( $key ); |
| 1043 | + |
| 1044 | + if( $data != '' ) { |
| 1045 | + wfDebugLog( 'BlogPage', "Got comments count for the page with ID {$id} from cache" ); |
| 1046 | + $commentCount = $data; |
| 1047 | + } else { |
| 1048 | + wfDebugLog( 'BlogPage', "Got comments count for the page with ID {$id} from DB" ); |
| 1049 | + $dbr = wfGetDB( DB_SLAVE ); |
| 1050 | + $commentCount = (int)$dbr->selectField( |
| 1051 | + 'Comments', |
| 1052 | + 'COUNT(*) AS count', |
| 1053 | + array( 'Comment_Page_ID' => intval( $id ) ), |
| 1054 | + __METHOD__ |
| 1055 | + ); |
| 1056 | + // Store in memcached for 15 minutes |
| 1057 | + $wgMemc->set( $key, $commentCount, 60 * 15 ); |
| 1058 | + } |
| 1059 | + |
| 1060 | + return $commentCount; |
| 1061 | + } |
| 1062 | + |
| 1063 | + /** |
| 1064 | + * Get the amount (COUNT(*)) of votes for the given page, identified via |
| 1065 | + * its ID and cache this info in memcached for 15 minutes. |
| 1066 | + * |
| 1067 | + * @param $id Integer: page ID |
| 1068 | + * @return Integer: amount of votes |
| 1069 | + */ |
| 1070 | + public static function getVotesForPage( $id ) { |
| 1071 | + global $wgMemc; |
| 1072 | + |
| 1073 | + // Try cache first |
| 1074 | + $key = wfMemcKey( 'blog', 'vote', 'count' ); |
| 1075 | + $data = $wgMemc->get( $key ); |
| 1076 | + |
| 1077 | + if( $data != '' ) { |
| 1078 | + wfDebugLog( 'BlogPage', "Got vote count for the page with ID {$id} from cache" ); |
| 1079 | + $voteCount = $data; |
| 1080 | + } else { |
| 1081 | + wfDebugLog( 'BlogPage', "Got vote count for the page with ID {$id} from DB" ); |
| 1082 | + $dbr = wfGetDB( DB_SLAVE ); |
| 1083 | + $voteCount = (int)$dbr->selectField( |
| 1084 | + 'Vote', |
| 1085 | + 'COUNT(*) AS count', |
| 1086 | + array( 'vote_page_id' => intval( $id ) ), |
| 1087 | + __METHOD__ |
| 1088 | + ); |
| 1089 | + // Store in memcached for 15 minutes |
| 1090 | + $wgMemc->set( $key, $voteCount, 60 * 15 ); |
| 1091 | + } |
| 1092 | + |
| 1093 | + return $voteCount; |
| 1094 | + } |
| 1095 | + |
| 1096 | + /** |
| 1097 | + * Get the first $maxChars characters of a page. |
| 1098 | + * |
| 1099 | + * @param $pageTitle String: page title |
| 1100 | + * @param $namespace Integer: namespace where the page is in |
| 1101 | + * @param $maxChars Integer: get the first this many characters of the page |
| 1102 | + * @param $fontSize String: small, medium or large |
| 1103 | + * @return String: first $maxChars characters from the page |
| 1104 | + */ |
| 1105 | + public static function getBlurb( $pageTitle, $namespace, $maxChars, $fontSize = 'small' ) { |
| 1106 | + global $wgTitle, $wgOut, $wgContLang; |
| 1107 | + |
| 1108 | + // Get raw text |
| 1109 | + $title = Title::makeTitle( $namespace, $pageTitle ); |
| 1110 | + $article = new Article( $title ); |
| 1111 | + $text = $article->getContent(); |
| 1112 | + |
| 1113 | + // Remove some problematic characters |
| 1114 | + $text = str_replace( '* ', '', $text ); |
| 1115 | + $text = str_replace( '===', '', $text ); |
| 1116 | + $text = str_replace( '==', '', $text ); |
| 1117 | + $text = str_replace( '{{Comments}}', '', $text ); // Template:Comments |
| 1118 | + $text = preg_replace( '@<youtube[^>]*?>.*?</youtube>@si', '', $text ); // <youtube> tags (provided by YouTube extension) |
| 1119 | + $text = preg_replace( '@<video[^>]*?>.*?</video>@si', '', $text ); // <video> tags (provided by Video extension) |
| 1120 | + $text = preg_replace( '@<comments[^>]*?>.*?</comments>@si', '', $text ); // <comments> tags (provided by Comments extension) |
| 1121 | + $text = preg_replace( '@<vote[^>]*?>.*?</vote>@si', '', $text ); // <vote> tags (provided by Vote extension) |
| 1122 | + if ( class_exists( 'Video' ) ) { |
| 1123 | + $videoNS = $wgContLang->getNsText( NS_VIDEO ); |
| 1124 | + if ( $videoNS === false ) { |
| 1125 | + $videoNS = 'Video'; |
| 1126 | + } |
| 1127 | + // [[Video:]] links (provided by Video extension) |
| 1128 | + $text = preg_replace( "@\[\[{$videoNS}:[^\]]*?].*?\]@si", '', $text ); |
| 1129 | + } |
| 1130 | + $localizedCategoryNS = $wgContLang->getNsText( NS_CATEGORY ); |
| 1131 | + $text = preg_replace( "@\[\[(?:(c|C)ategory|{$localizedCategoryNS}):[^\]]*?].*?\]@si", '', $text ); // categories |
| 1132 | + //$text = preg_replace( "@\[\[{$localizedCategoryNS}:[^\]]*?].*?\]@si", '', $text ); // original version of the above line |
| 1133 | + |
| 1134 | + // Start looking at text after content, and force no Table of Contents |
| 1135 | + $pos = strpos( $text, '<!--start text-->' ); |
| 1136 | + if( $pos !== false ) { |
| 1137 | + $text = substr( $text, $pos ); |
| 1138 | + } |
| 1139 | + |
| 1140 | + $text = '__NOTOC__ ' . $text; |
| 1141 | + |
| 1142 | + // Run text through parser |
| 1143 | + $blurbParser = new Parser(); |
| 1144 | + $blurbText = $blurbParser->parse( $text, $wgTitle, $wgOut->parserOptions(), true ); |
| 1145 | + $blurbText = strip_tags( $blurbText->getText() ); |
| 1146 | + |
| 1147 | + $blurbText = preg_replace( '/<comments><\/comments>/i', '', $blurbText ); |
| 1148 | + $blurbText = preg_replace( '/<vote><\/vote>/i', '', $blurbText ); |
| 1149 | + |
| 1150 | + //$blurbText = $text; |
| 1151 | + $pos = strpos( $blurbText, '[' ); |
| 1152 | + if( $pos !== false ) { |
| 1153 | + $blurbText = substr( $blurbText, 0, $pos ); |
| 1154 | + } |
| 1155 | + |
| 1156 | + // Take first N characters, and then make sure it ends on last full word |
| 1157 | + $max = 300; |
| 1158 | + if( strlen( $blurbText ) > $max ) { |
| 1159 | + $blurbText = strrev( strstr( strrev( substr( $blurbText, 0, $max ) ), ' ' ) ); |
| 1160 | + } |
| 1161 | + |
| 1162 | + // Prepare blurb font size |
| 1163 | + $blurbFont = '<span class="listpages-blurb-size-'; |
| 1164 | + if ( $fontSize == 'small' ) { |
| 1165 | + $blurbFont .= 'small'; |
| 1166 | + } elseif ( $fontSize == 'medium' ) { |
| 1167 | + $blurbFont .= 'medium'; |
| 1168 | + } elseif ( $fontSize == 'large' ) { |
| 1169 | + $blurbFont .= 'large'; |
| 1170 | + } |
| 1171 | + $blurbFont .= '">'; |
| 1172 | + |
| 1173 | + // Fix multiple whitespace, returns etc |
| 1174 | + $blurbText = trim( $blurbText ); // remove trailing spaces |
| 1175 | + $blurbText = preg_replace( '/\s(?=\s)/', '', $blurbText ); // remove double whitespace |
| 1176 | + $blurbText = preg_replace( '/[\n\r\t]/', ' ', $blurbText ); // replace any non-space whitespace with a space |
| 1177 | + |
| 1178 | + return $blurbFont . $blurbText. '. . . <a href="' . |
| 1179 | + $title->escapeFullURL() . '">' . wfMsg( 'blog-more' ) . |
| 1180 | + '</a></span>'; |
| 1181 | + } |
| 1182 | + |
| 1183 | + /** |
| 1184 | + * Get the image associated with the given page (via the page's ID). |
| 1185 | + * |
| 1186 | + * @param $pageId Integer: page ID number |
| 1187 | + * @return String: file name or nothing |
| 1188 | + */ |
| 1189 | + public static function getPageImage( $pageId ) { |
| 1190 | + global $wgMemc; |
| 1191 | + |
| 1192 | + $key = wfMemcKey( 'blog', 'page', 'image', $pageId ); |
| 1193 | + $data = $wgMemc->get( $key ); |
| 1194 | + |
| 1195 | + if( !$data ) { |
| 1196 | + $dbr = wfGetDB( DB_SLAVE ); |
| 1197 | + $il_to = $dbr->selectField( |
| 1198 | + 'imagelinks', |
| 1199 | + array( 'il_to' ), |
| 1200 | + array( 'il_from' => intval( $pageId ) ), |
| 1201 | + __METHOD__ |
| 1202 | + ); |
| 1203 | + // Cache in memcached for a minute |
| 1204 | + $wgMemc->set( $key, $il_to, 60 ); |
| 1205 | + } else { |
| 1206 | + wfDebugLog( 'BlogPage', "Loading image for page {$pageId} from cache\n" ); |
| 1207 | + $il_to = $data; |
| 1208 | + } |
| 1209 | + |
| 1210 | + return $il_to; |
| 1211 | + } |
| 1212 | + |
| 1213 | + /** |
| 1214 | + * Yes, these are those fucking time-related functions once more. |
| 1215 | + * You probably have seen these in UserBoard, Comments...god knows where. |
| 1216 | + * Seriously, this stuff is all over the place. |
| 1217 | + */ |
| 1218 | + static function dateDiff( $date1, $date2 ) { |
| 1219 | + $dtDiff = $date1 - $date2; |
| 1220 | + |
| 1221 | + $totalDays = intval( $dtDiff / ( 24 * 60 * 60 ) ); |
| 1222 | + $totalSecs = $dtDiff - ( $totalDays * 24 * 60 * 60 ); |
| 1223 | + $dif['w'] = intval( $totalDays / 7 ); |
| 1224 | + $dif['d'] = $totalDays; |
| 1225 | + $dif['h'] = $h = intval( $totalSecs / ( 60 * 60 ) ); |
| 1226 | + $dif['m'] = $m = intval( ( $totalSecs - ( $h * 60 * 60 ) ) / 60 ); |
| 1227 | + $dif['s'] = $totalSecs - ( $h * 60 * 60 ) - ( $m * 60 ); |
| 1228 | + |
| 1229 | + return $dif; |
| 1230 | + } |
| 1231 | + |
| 1232 | + static function getTimeOffset( $time, $timeabrv, $timename ) { |
| 1233 | + $timeStr = ''; |
| 1234 | + if( $time[$timeabrv] > 0 ) { |
| 1235 | + $timeStr = wfMsgExt( "blog-time-{$timename}", 'parsemag', $time[$timeabrv] ); |
| 1236 | + } |
| 1237 | + if( $timeStr ) { |
| 1238 | + $timeStr .= ' '; |
| 1239 | + } |
| 1240 | + return $timeStr; |
| 1241 | + } |
| 1242 | + |
| 1243 | + static function getTimeAgo( $time ) { |
| 1244 | + $timeArray = self::dateDiff( time(), $time ); |
| 1245 | + $timeStr = ''; |
| 1246 | + $timeStrD = self::getTimeOffset( $timeArray, 'd', 'days' ); |
| 1247 | + $timeStrH = self::getTimeOffset( $timeArray, 'h', 'hours' ); |
| 1248 | + $timeStrM = self::getTimeOffset( $timeArray, 'm', 'minutes' ); |
| 1249 | + $timeStrS = self::getTimeOffset( $timeArray, 's', 'seconds' ); |
| 1250 | + $timeStr = $timeStrD; |
| 1251 | + if( $timeStr < 2 ) { |
| 1252 | + $timeStr .= $timeStrH; |
| 1253 | + $timeStr .= $timeStrM; |
| 1254 | + if( !$timeStr ) { |
| 1255 | + $timeStr .= $timeStrS; |
| 1256 | + } |
| 1257 | + } |
| 1258 | + if( !$timeStr ) { |
| 1259 | + $timeStr = wfMsgExt( 'blog-time-seconds', 'parsemag', 1 ); |
| 1260 | + } |
| 1261 | + return $timeStr; |
| 1262 | + } |
| 1263 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/BlogPage.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 1264 | + native |
Index: trunk/extensions/BlogPage/SpecialArticlesHome.php |
— | — | @@ -0,0 +1,731 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Blogs homepage - blog articles will make it to this page when they receive a |
| 5 | + * certain number of votes and/or unique commentors commenting. |
| 6 | + * |
| 7 | + * In addition to the most popular blog posts, this page will display the |
| 8 | + * newest blog posts, the most commented and most voted blog posts within the |
| 9 | + * past 72 hours. |
| 10 | + * |
| 11 | + * @file |
| 12 | + * @ingroup Extensions |
| 13 | + */ |
| 14 | +class ArticlesHome extends SpecialPage { |
| 15 | + |
| 16 | + /** |
| 17 | + * Constructor -- set up the new special page |
| 18 | + */ |
| 19 | + public function __construct() { |
| 20 | + parent::__construct( 'ArticlesHome' ); |
| 21 | + } |
| 22 | + |
| 23 | + /** |
| 24 | + * Show the new special page |
| 25 | + * |
| 26 | + * @param $type String: what kind of articles to show? Default is 'popular' |
| 27 | + */ |
| 28 | + public function execute( $type ) { |
| 29 | + global $wgContLang, $wgOut, $wgScriptPath, $wgSupressPageTitle; |
| 30 | + |
| 31 | + $wgSupressPageTitle = true; |
| 32 | + |
| 33 | + // Add CSS |
| 34 | + if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) { |
| 35 | + $wgOut->addModules( 'ext.blogPage.articlesHome' ); |
| 36 | + } else { |
| 37 | + $wgOut->addExtensionStyle( $wgScriptPath . '/extensions/BlogPage/ArticlesHome.css' ); |
| 38 | + } |
| 39 | + |
| 40 | + if( !$type ) { |
| 41 | + $type = 'popular'; |
| 42 | + } |
| 43 | + |
| 44 | + // Get the category names for today and the past two days |
| 45 | + $dates_array = $this->getDatesFromElapsedDays( 2 ); |
| 46 | + $date_categories = ''; |
| 47 | + foreach ( $dates_array as $key => $value ) { |
| 48 | + if( $date_categories ) { |
| 49 | + $date_categories .= ','; |
| 50 | + } |
| 51 | + $date_categories .= $key; |
| 52 | + } |
| 53 | + |
| 54 | + // Determine the page title and set it |
| 55 | + if ( $type == 'popular' ) { |
| 56 | + $name = wfMsg( 'ah-popular-articles' ); |
| 57 | + $name_right = wfMsg( 'ah-new-articles' ); |
| 58 | + } else { |
| 59 | + $name = wfMsg( 'ah-new-articles' ); |
| 60 | + $name_right = wfMsg( 'ah-popular-articles' ); |
| 61 | + } |
| 62 | + |
| 63 | + $wgOut->setPageTitle( $name ); |
| 64 | + |
| 65 | + $today = $wgContLang->date( wfTimestampNow() ); |
| 66 | + |
| 67 | + // Start building the HTML output |
| 68 | + $output = '<div class="main-page-left">'; |
| 69 | + $output .= '<div class="logged-in-articles">'; |
| 70 | + $output .= '<h2>' . $name . '</h2>'; |
| 71 | + //$output .= '<h2>' . $name . ' <span class="rss-feed"><a href="http://feeds.feedburner.com/Armchairgm"><img src="http://www.armchairgm.com/images/a/a7/Rss-icon.gif" border="0" alt="RSS" /></a> ' . wfMsg( 'ah-feed-rss' ) . '</span></h2>'; |
| 72 | + $output .= '<p class="main-page-sub-links"><a href="' . |
| 73 | + SpecialPage::getTitleFor( 'CreateBlogPost' )->escapeFullURL() . '">' . |
| 74 | + wfMsg( 'ah-write-article' ) . '</a> - <a href="' . |
| 75 | + // original used date( 'F j, Y' ) which returned something like |
| 76 | + // December 5, 2008 |
| 77 | + Title::makeTitle( NS_CATEGORY, $today )->escapeFullURL() . '">' . |
| 78 | + wfMsg( 'ah-todays-articles' ) . '</a> - <a href="' . |
| 79 | + Title::newMainPage()->escapeFullURL() . '">' . |
| 80 | + wfMsg( 'mainpage' ) . '</a></p>' . "\n\n"; |
| 81 | + |
| 82 | + if ( $type == 'popular' ) { |
| 83 | + $output .= $this->getPopularPosts(); |
| 84 | + } else { |
| 85 | + $output .= $this->getNewestPosts(); |
| 86 | + } |
| 87 | + |
| 88 | + $output .= '</div>'; |
| 89 | + $output .= '</div>'; |
| 90 | + $output .= '<div class="main-page-right">'; |
| 91 | + |
| 92 | + // Side Articles |
| 93 | + $output .= '<div class="side-articles">'; |
| 94 | + $output .= '<h2>' . $name_right . '</h2>'; |
| 95 | + |
| 96 | + if ( $type == 'popular' ) { |
| 97 | + $output .= $this->displayNewestPages(); |
| 98 | + } else { |
| 99 | + $output .= $this->getPopularPostsForRightSide(); |
| 100 | + } |
| 101 | + |
| 102 | + $output .= '</div>'; |
| 103 | + |
| 104 | + wfDebugLog( 'BlogPage', 'ArticlesHome: date_categories=' . $date_categories ); |
| 105 | + |
| 106 | + // Most Votes |
| 107 | + $output .= '<div class="side-articles">'; |
| 108 | + $output .= '<h2>' . wfMsg( 'ah-most-votes' ) . '</h2>'; |
| 109 | + $output .= $this->displayMostVotedPages( $date_categories ); |
| 110 | + $output .= '</div>'; |
| 111 | + |
| 112 | + // Most Comments |
| 113 | + $output .= '<div class="side-articles">'; |
| 114 | + $output .= '<h2>' . wfMsg( 'ah-what-talking-about' ) . '</h2>'; |
| 115 | + $output .= $this->displayMostCommentedPages( $date_categories ); |
| 116 | + $output .= '</div>'; |
| 117 | + |
| 118 | + $output .= '</div>'; |
| 119 | + $output .= '<div class="cleared"></div>'; |
| 120 | + |
| 121 | + $wgOut->addHTML( $output ); |
| 122 | + } |
| 123 | + |
| 124 | + /** |
| 125 | + * @param $numberOfDays Integer: get this many days in addition to today |
| 126 | + * @return Array: array containing today and the past $numberOfDays days in |
| 127 | + * the wiki's content language |
| 128 | + */ |
| 129 | + function getDatesFromElapsedDays( $numberOfDays ) { |
| 130 | + global $wgContLang; |
| 131 | + $today = $wgContLang->date( wfTimestampNow() ); // originally date( 'F j, Y', time() ) |
| 132 | + $dates[$today] = 1; // Gets today's date string |
| 133 | + for( $x = 1; $x <= $numberOfDays; $x++ ) { |
| 134 | + $timeAgo = time() - ( 60 * 60 * 24 * $x ); |
| 135 | + // originally date( 'F j, Y', $timeAgo ); |
| 136 | + $dateString = $wgContLang->date( wfTimestamp( TS_MW, $timeAgo ) ); |
| 137 | + $dates[$dateString] = 1; |
| 138 | + } |
| 139 | + return $dates; |
| 140 | + } |
| 141 | + |
| 142 | + /** |
| 143 | + * Get the 25 most popular blog posts from the database and then cache them |
| 144 | + * in memcached for 15 minutes. |
| 145 | + * The definition of 'popular' is very arbitrary at the moment. |
| 146 | + * |
| 147 | + * @return String: HTML |
| 148 | + */ |
| 149 | + public function getPopularPosts() { |
| 150 | + global $wgMemc, $wgScriptPath; |
| 151 | + |
| 152 | + // Try cache first |
| 153 | + $key = wfMemcKey( 'blog', 'popular', 'twentyfive' ); |
| 154 | + $data = $wgMemc->get( $key ); |
| 155 | + |
| 156 | + if( $data != '' ) { |
| 157 | + wfDebugLog( 'BlogPage', 'Got popular posts in ArticlesHome from cache' ); |
| 158 | + $popularBlogPosts = $data; |
| 159 | + } else { |
| 160 | + wfDebugLog( 'BlogPage', 'Got popular posts in ArticlesHome from DB' ); |
| 161 | + $dbr = wfGetDB( DB_SLAVE ); |
| 162 | + // Code sporked from Rob Church's NewestPages extension |
| 163 | + $commentsTable = $dbr->tableName( 'Comments' ); |
| 164 | + $voteTable = $dbr->tableName( 'Vote' ); |
| 165 | + $res = $dbr->select( |
| 166 | + array( 'page', 'Comments', 'Vote' ), |
| 167 | + array( |
| 168 | + 'DISTINCT page_id', 'page_namespace', 'page_title', |
| 169 | + 'page_is_redirect', |
| 170 | + ), |
| 171 | + array( |
| 172 | + 'page_namespace' => NS_BLOG, |
| 173 | + 'page_is_redirect' => 0, |
| 174 | + // If you can figure out how to do this without a subquery, |
| 175 | + // please let me know. Until that... |
| 176 | + "((SELECT COUNT(*) FROM $voteTable WHERE vote_page_id = page_id) >= 5 OR |
| 177 | + (SELECT COUNT(*) FROM $commentsTable WHERE Comment_Page_ID = page_id) >= 5)", |
| 178 | + ), |
| 179 | + __METHOD__, |
| 180 | + array( |
| 181 | + 'ORDER BY' => 'page_id DESC', |
| 182 | + 'LIMIT' => 25 |
| 183 | + ), |
| 184 | + array( |
| 185 | + 'Comments' => array( 'INNER JOIN', 'page_id = Comment_Page_ID' ), |
| 186 | + 'Vote' => array( 'INNER JOIN', 'page_id = vote_page_id' ) |
| 187 | + ) |
| 188 | + ); |
| 189 | + |
| 190 | + $popularBlogPosts = array(); |
| 191 | + foreach ( $res as $row ) { |
| 192 | + $popularBlogPosts[] = array( |
| 193 | + 'title' => $row->page_title, |
| 194 | + 'ns' => $row->page_namespace, |
| 195 | + 'id' => $row->page_id |
| 196 | + ); |
| 197 | + } |
| 198 | + |
| 199 | + // Cache in memcached for 15 minutes |
| 200 | + $wgMemc->set( $key, $popularBlogPosts, 60 * 15 ); |
| 201 | + } |
| 202 | + |
| 203 | + $imgPath = $wgScriptPath . '/extensions/BlogPage/images/'; |
| 204 | + |
| 205 | + $output = '<div class="listpages-container">'; |
| 206 | + if ( empty( $popularBlogPosts ) ) { |
| 207 | + $output .= wfMsg( 'ah-no-results' ); |
| 208 | + } else { |
| 209 | + foreach( $popularBlogPosts as $popularBlogPost ) { |
| 210 | + $titleObj = Title::makeTitle( NS_BLOG, $popularBlogPost['title'] ); |
| 211 | + $output .= '<div class="listpages-item">'; |
| 212 | + $pageImage = BlogPage::getPageImage( $popularBlogPost['id'] ); |
| 213 | + if( $pageImage ) { |
| 214 | + // Load MediaWiki image object to get thumbnail tag |
| 215 | + $img = wfFindFile( $pageImage ); |
| 216 | + $imgTag = ''; |
| 217 | + if ( is_object( $img ) ) { |
| 218 | + $thumb = $img->getThumbnail( 65, 0, true ); |
| 219 | + $imgTag = $thumb->toHtml(); |
| 220 | + } |
| 221 | + |
| 222 | + $output .= "<div class=\"listpages-image\">{$imgTag}</div>\n"; |
| 223 | + } |
| 224 | + $output .= '<a href="' . $titleObj->escapeFullURL() . '">' . |
| 225 | + $titleObj->getText() . |
| 226 | + '</a> |
| 227 | + <div class="listpages-date">'; |
| 228 | + $output .= '(' . wfMsg( 'blog-created-ago', |
| 229 | + BlogPage::getTimeAgo( |
| 230 | + // need to strtotime() it because getCreateDate() now |
| 231 | + // returns the raw timestamp from the database; in the past |
| 232 | + // it converted it to UNIX timestamp via the SQL function |
| 233 | + // UNIX_TIMESTAMP but that was no good for our purposes |
| 234 | + strtotime( BlogPage::getCreateDate( $popularBlogPost['id'] ) ) |
| 235 | + ) ) . ')'; |
| 236 | + $output .= "</div> |
| 237 | + <div class=\"listpages-blurb\">\n" . |
| 238 | + BlogPage::getBlurb( |
| 239 | + $popularBlogPost['title'], |
| 240 | + $popularBlogPost['ns'], |
| 241 | + 300 |
| 242 | + ) . |
| 243 | + '</div><!-- .listpages-blurb --> |
| 244 | + <div class="listpages-stats">' . "\n"; |
| 245 | + $output .= "<img src=\"{$imgPath}voteIcon.gif\" alt=\"\" border=\"0\" /> " . |
| 246 | + wfMsgExt( |
| 247 | + 'blog-author-votes', |
| 248 | + 'parsemag', |
| 249 | + BlogPage::getVotesForPage( $popularBlogPost['id'] ) |
| 250 | + ); |
| 251 | + $output .= " <img src=\"{$imgPath}comment.gif\" alt=\"\" border=\"0\" /> " . |
| 252 | + wfMsgExt( |
| 253 | + 'blog-author-comments', |
| 254 | + 'parsemag', |
| 255 | + BlogPage::getCommentsForPage( $popularBlogPost['id'] ) |
| 256 | + ) . '</div><!-- . listpages-stats --> |
| 257 | + </div><!-- .listpages-item --> |
| 258 | + <div class="cleared"></div>' . "\n"; |
| 259 | + } |
| 260 | + } |
| 261 | + |
| 262 | + $output .= '</div>' . "\n"; // .listpages-container |
| 263 | + |
| 264 | + return $output; |
| 265 | + } |
| 266 | + |
| 267 | + /** |
| 268 | + * Get the list of the most voted pages within the last 72 hours. |
| 269 | + * |
| 270 | + * @param $dateCategories String: last three days (localized), separated |
| 271 | + * by commas |
| 272 | + * @return String: HTML |
| 273 | + */ |
| 274 | + function displayMostVotedPages( $dateCategories ) { |
| 275 | + global $wgMemc; |
| 276 | + |
| 277 | + // Try cache first |
| 278 | + $key = wfMemcKey( 'blog', 'mostvoted', 'ten' ); |
| 279 | + $data = $wgMemc->get( $key ); |
| 280 | + |
| 281 | + if( $data != '' ) { |
| 282 | + wfDebugLog( 'BlogPage', 'Got most voted posts in ArticlesHome from cache' ); |
| 283 | + $votedBlogPosts = $data; |
| 284 | + } else { |
| 285 | + wfDebugLog( 'BlogPage', 'Got most voted posts in ArticlesHome from DB' ); |
| 286 | + $dbr = wfGetDB( DB_SLAVE ); |
| 287 | + $kaboom = explode( ',', $dateCategories ); |
| 288 | + // Without constructing Titles for all the categories, they won't |
| 289 | + // have the underscores and thus the query will never match |
| 290 | + // anything...thankfully getDBkey returns the title with the |
| 291 | + // underscores |
| 292 | + $titleOne = Title::makeTitle( NS_CATEGORY, $kaboom[0] ); |
| 293 | + $titleTwo = Title::makeTitle( NS_CATEGORY, $kaboom[1] ); |
| 294 | + $titleThree = Title::makeTitle( NS_CATEGORY, $kaboom[2] ); |
| 295 | + $res = $dbr->select( |
| 296 | + array( 'page', 'categorylinks', 'Vote' ), |
| 297 | + array( 'DISTINCT page_id', 'page_title', 'page_namespace' ), |
| 298 | + array( |
| 299 | + 'cl_to' => array( |
| 300 | + $titleOne->getDBkey(), $titleTwo->getDBkey(), |
| 301 | + $titleThree->getDBkey() |
| 302 | + ), |
| 303 | + 'page_namespace' => NS_BLOG, |
| 304 | + 'page_id = vote_page_id', |
| 305 | + 'vote_date < "' . date( 'Y-m-d H:i:s' ) . '"' |
| 306 | + ), |
| 307 | + __METHOD__, |
| 308 | + array( 'LIMIT' => 10 ), |
| 309 | + array( |
| 310 | + 'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ), |
| 311 | + 'Vote' => array( 'LEFT JOIN', 'vote_page_id = page_id' ), |
| 312 | + ) |
| 313 | + ); |
| 314 | + |
| 315 | + $votedBlogPosts = array(); |
| 316 | + foreach ( $res as $row ) { |
| 317 | + $votedBlogPosts[] = array( |
| 318 | + 'title' => $row->page_title, |
| 319 | + 'ns' => $row->page_namespace, |
| 320 | + 'id' => $row->page_id |
| 321 | + ); |
| 322 | + } |
| 323 | + |
| 324 | + // Cache in memcached for 15 minutes |
| 325 | + $wgMemc->set( $key, $votedBlogPosts, 60 * 15 ); |
| 326 | + } |
| 327 | + |
| 328 | + // Here we output HTML |
| 329 | + $output = '<div class="listpages-container">' . "\n"; |
| 330 | + |
| 331 | + if ( empty( $votedBlogPosts ) ) { |
| 332 | + $output .= wfMsg( 'ah-no-results' ); |
| 333 | + } else { |
| 334 | + foreach ( $votedBlogPosts as $votedBlogPost ) { |
| 335 | + $titleObj = Title::makeTitle( NS_BLOG, $votedBlogPost['title'] ); |
| 336 | + $votes = BlogPage::getVotesForPage( $votedBlogPost['id'] ); |
| 337 | + $output .= '<div class="listpages-item">' . "\n"; |
| 338 | + $output .= '<div class="listpages-votebox">' . "\n"; |
| 339 | + $output .= '<div class="listpages-votebox-number">' . |
| 340 | + $votes . "</div>\n"; |
| 341 | + $output .= '<div class="listpages-votebox-text">' . |
| 342 | + wfMsgExt( |
| 343 | + 'blog-author-votes', |
| 344 | + 'parsemag', |
| 345 | + $votes |
| 346 | + ) . "</div>\n"; // .listpages-votebox-text |
| 347 | + $output .= '</div>' . "\n"; // .listpages-votebox |
| 348 | + $output .= '</div>' . "\n"; // .listpages-item |
| 349 | + $output .= '<a href="' . $titleObj->escapeFullURL() . '">' . |
| 350 | + $titleObj->getText() . '</a>'; |
| 351 | + $output .= '<div class="cleared"></div>'; |
| 352 | + } |
| 353 | + } |
| 354 | + |
| 355 | + $output .= "</div>\n"; // .listpages-container |
| 356 | + |
| 357 | + return $output; |
| 358 | + } |
| 359 | + |
| 360 | + /** |
| 361 | + * Get the list of the most commented pages within the last 72 hours. |
| 362 | + * |
| 363 | + * @param $dateCategories String: last three days (localized), separated |
| 364 | + * by commas |
| 365 | + * @return String: HTML |
| 366 | + */ |
| 367 | + function displayMostCommentedPages( $dateCategories ) { |
| 368 | + global $wgMemc; |
| 369 | + |
| 370 | + // Try cache first |
| 371 | + $key = wfMemcKey( 'blog', 'mostcommented', 'ten' ); |
| 372 | + $data = $wgMemc->get( $key ); |
| 373 | + |
| 374 | + if( $data != '' ) { |
| 375 | + wfDebugLog( 'BlogPage', 'Got most commented posts in ArticlesHome from cache' ); |
| 376 | + $commentedBlogPosts = $data; |
| 377 | + } else { |
| 378 | + wfDebugLog( 'BlogPage', 'Got most commented posts in ArticlesHome from DB' ); |
| 379 | + $dbr = wfGetDB( DB_SLAVE ); |
| 380 | + $kaboom = explode( ',', $dateCategories ); |
| 381 | + // Without constructing Titles for all the categories, they won't |
| 382 | + // have the underscores and thus the query will never match |
| 383 | + // anything...thankfully getDBkey returns the title with the |
| 384 | + // underscores |
| 385 | + $titleOne = Title::makeTitle( NS_CATEGORY, $kaboom[0] ); |
| 386 | + $titleTwo = Title::makeTitle( NS_CATEGORY, $kaboom[1] ); |
| 387 | + $titleThree = Title::makeTitle( NS_CATEGORY, $kaboom[2] ); |
| 388 | + $res = $dbr->select( |
| 389 | + array( 'page', 'categorylinks', 'Comments' ), |
| 390 | + array( 'DISTINCT page_id', 'page_title', 'page_namespace' ), |
| 391 | + array( |
| 392 | + 'cl_to' => array( |
| 393 | + $titleOne->getDBkey(), $titleTwo->getDBkey(), |
| 394 | + $titleThree->getDBkey() |
| 395 | + ), |
| 396 | + 'page_namespace' => NS_BLOG, |
| 397 | + 'page_id = Comment_Page_ID', |
| 398 | + 'Comment_Date < "' . date( 'Y-m-d H:i:s' ) . '"' |
| 399 | + ), |
| 400 | + __METHOD__, |
| 401 | + array( 'LIMIT' => 10 ), |
| 402 | + array( |
| 403 | + 'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ), |
| 404 | + 'Comments' => array( 'LEFT JOIN', 'Comment_Page_ID = page_id' ), |
| 405 | + ) |
| 406 | + ); |
| 407 | + |
| 408 | + $commentedBlogPosts = array(); |
| 409 | + foreach ( $res as $row ) { |
| 410 | + $commentedBlogPosts[] = array( |
| 411 | + 'title' => $row->page_title, |
| 412 | + 'ns' => $row->page_namespace, |
| 413 | + 'id' => $row->page_id |
| 414 | + ); |
| 415 | + } |
| 416 | + |
| 417 | + // Cache in memcached for 15 minutes |
| 418 | + $wgMemc->set( $key, $commentedBlogPosts, 60 * 15 ); |
| 419 | + } |
| 420 | + |
| 421 | + $output = '<div class="listpages-container">'; |
| 422 | + |
| 423 | + if ( empty( $commentedBlogPosts ) ) { |
| 424 | + $output .= wfMsg( 'ah-no-results' ); |
| 425 | + } else { |
| 426 | + foreach( $commentedBlogPosts as $commentedBlogPost ) { |
| 427 | + $titleObj = Title::makeTitle( NS_BLOG, $commentedBlogPost['title'] ); |
| 428 | + $output .= '<div class="listpages-item"> |
| 429 | + <div class="listpages-votebox"> |
| 430 | + <div class="listpages-commentbox-number">' . |
| 431 | + BlogPage::getCommentsForPage( $commentedBlogPost['id'] ) . |
| 432 | + '</div> |
| 433 | + </div> |
| 434 | + <a href="' . $titleObj->escapeFullURL() . '">' . |
| 435 | + $titleObj->getText() . |
| 436 | + '</a> |
| 437 | + </div><!-- .listpages-item --> |
| 438 | + <div class="cleared"></div>' . "\n"; |
| 439 | + } |
| 440 | + } |
| 441 | + |
| 442 | + $output .= '</div>' . "\n"; // .listpages-container |
| 443 | + |
| 444 | + return $output; |
| 445 | + } |
| 446 | + |
| 447 | + /** |
| 448 | + * Get the list of the ten newest pages in the NS_BLOG namespace. |
| 449 | + * This is used in the right side of the special page. |
| 450 | + * |
| 451 | + * @return String: HTML |
| 452 | + */ |
| 453 | + function displayNewestPages() { |
| 454 | + global $wgMemc; |
| 455 | + |
| 456 | + // Try cache first |
| 457 | + $key = wfMemcKey( 'blog', 'newest', 'ten' ); |
| 458 | + $data = $wgMemc->get( $key ); |
| 459 | + |
| 460 | + if( $data != '' ) { |
| 461 | + wfDebugLog( 'BlogPage', 'Got new articles in ArticlesHome from cache' ); |
| 462 | + $newBlogPosts = $data; |
| 463 | + } else { |
| 464 | + wfDebugLog( 'BlogPage', 'Got new articles in ArticlesHome from DB' ); |
| 465 | + $dbr = wfGetDB( DB_SLAVE ); |
| 466 | + // Code sporked from Rob Church's NewestPages extension |
| 467 | + $res = $dbr->select( |
| 468 | + 'page', |
| 469 | + array( |
| 470 | + 'page_namespace', 'page_title', 'page_is_redirect', |
| 471 | + 'page_id' |
| 472 | + ), |
| 473 | + array( 'page_namespace' => NS_BLOG, 'page_is_redirect' => 0 ), |
| 474 | + __METHOD__, |
| 475 | + array( 'ORDER BY' => 'page_id DESC', 'LIMIT' => 10 ) |
| 476 | + ); |
| 477 | + |
| 478 | + $newBlogPosts = array(); |
| 479 | + foreach ( $res as $row ) { |
| 480 | + $newBlogPosts[] = array( |
| 481 | + 'title' => $row->page_title, |
| 482 | + 'ns' => $row->page_namespace, |
| 483 | + 'id' => $row->page_id |
| 484 | + ); |
| 485 | + } |
| 486 | + |
| 487 | + // Cache in memcached for 15 minutes |
| 488 | + $wgMemc->set( $key, $newBlogPosts, 60 * 15 ); |
| 489 | + } |
| 490 | + |
| 491 | + $output = '<div class="listpages-container">' . "\n"; |
| 492 | + if ( empty( $newBlogPosts ) ) { |
| 493 | + $output .= wfMsg( 'ah-no-results' ); |
| 494 | + } else { |
| 495 | + foreach( $newBlogPosts as $newBlogPost ) { |
| 496 | + $titleObj = Title::makeTitle( NS_BLOG, $newBlogPost['title'] ); |
| 497 | + $votes = BlogPage::getVotesForPage( $newBlogPost['id'] ); |
| 498 | + $output .= "\t\t\t\t" . '<div class="listpages-item">'; |
| 499 | + $output .= '<div class="listpages-votebox">' . "\n"; |
| 500 | + $output .= '<div class="listpages-votebox-number">' . |
| 501 | + $votes . |
| 502 | + "</div>\n"; // .listpages-votebox-number |
| 503 | + $output .= '<div class="listpages-votebox-text">' . |
| 504 | + wfMsgExt( |
| 505 | + 'blog-author-votes', |
| 506 | + 'parsemag', |
| 507 | + $votes |
| 508 | + ) . "</div>\n"; // .listpages-votebox-text |
| 509 | + $output .= "</div>\n"; // .listpages-votebox |
| 510 | + $output .= '<a href="' . $titleObj->escapeFullURL() . '">' . |
| 511 | + $titleObj->getText() . |
| 512 | + '</a> |
| 513 | + </div><!-- .listpages-item --> |
| 514 | + <div class="cleared"></div>' . "\n"; |
| 515 | + } |
| 516 | + } |
| 517 | + $output .= '</div>' . "\n"; // .listpages-container |
| 518 | + return $output; |
| 519 | + } |
| 520 | + |
| 521 | + /** |
| 522 | + * Get the 25 newest blog posts from the database and then cache them in |
| 523 | + * memcached for 15 minutes. |
| 524 | + * |
| 525 | + * @return String: HTML |
| 526 | + */ |
| 527 | + public function getNewestPosts() { |
| 528 | + global $wgMemc, $wgScriptPath; |
| 529 | + |
| 530 | + // Try cache first |
| 531 | + $key = wfMemcKey( 'blog', 'newest', 'twentyfive' ); |
| 532 | + $data = $wgMemc->get( $key ); |
| 533 | + |
| 534 | + if( $data != '' ) { |
| 535 | + wfDebugLog( 'BlogPage', 'Got newest posts in ArticlesHome from cache' ); |
| 536 | + $newestBlogPosts = $data; |
| 537 | + } else { |
| 538 | + wfDebugLog( 'BlogPage', 'Got newest posts in ArticlesHome from DB' ); |
| 539 | + $dbr = wfGetDB( DB_SLAVE ); |
| 540 | + // Code sporked from Rob Church's NewestPages extension |
| 541 | + $res = $dbr->select( |
| 542 | + array( 'page' ), |
| 543 | + array( |
| 544 | + 'page_namespace', 'page_title', 'page_is_redirect', |
| 545 | + 'page_id', |
| 546 | + ), |
| 547 | + array( |
| 548 | + 'page_namespace' => NS_BLOG, |
| 549 | + 'page_is_redirect' => 0, |
| 550 | + ), |
| 551 | + __METHOD__, |
| 552 | + array( |
| 553 | + 'ORDER BY' => 'page_id DESC', |
| 554 | + 'LIMIT' => 25 |
| 555 | + ) |
| 556 | + ); |
| 557 | + |
| 558 | + $newestBlogPosts = array(); |
| 559 | + foreach ( $res as $row ) { |
| 560 | + $newestBlogPosts[] = array( |
| 561 | + 'title' => $row->page_title, |
| 562 | + 'ns' => $row->page_namespace, |
| 563 | + 'id' => $row->page_id |
| 564 | + ); |
| 565 | + } |
| 566 | + |
| 567 | + // Cache in memcached for 15 minutes |
| 568 | + $wgMemc->set( $key, $newestBlogPosts, 60 * 15 ); |
| 569 | + } |
| 570 | + |
| 571 | + $imgPath = $wgScriptPath . '/extensions/BlogPage/images/'; |
| 572 | + |
| 573 | + $output = '<div class="listpages-container">'; |
| 574 | + if ( empty( $newestBlogPosts ) ) { |
| 575 | + $output .= wfMsg( 'ah-no-results' ); |
| 576 | + } else { |
| 577 | + foreach( $newestBlogPosts as $newestBlogPost ) { |
| 578 | + $titleObj = Title::makeTitle( NS_BLOG, $newestBlogPost['title'] ); |
| 579 | + $output .= '<div class="listpages-item">'; |
| 580 | + $pageImage = BlogPage::getPageImage( $newestBlogPost['id'] ); |
| 581 | + if( $pageImage ) { |
| 582 | + // Load MediaWiki image object to get thumbnail tag |
| 583 | + $img = wfFindFile( $pageImage ); |
| 584 | + $imgTag = ''; |
| 585 | + if ( is_object( $img ) ) { |
| 586 | + $thumb = $img->getThumbnail( 65, 0, true ); |
| 587 | + $imgTag = $thumb->toHtml(); |
| 588 | + } |
| 589 | + |
| 590 | + $output .= "<div class=\"listpages-image\">{$imgTag}</div>\n"; |
| 591 | + } |
| 592 | + $output .= '<a href="' . $titleObj->escapeFullURL() . '">' . |
| 593 | + $titleObj->getText() . |
| 594 | + '</a> |
| 595 | + <div class="listpages-date">'; |
| 596 | + $output .= '(' . wfMsg( 'blog-created-ago', |
| 597 | + BlogPage::getTimeAgo( |
| 598 | + // need to strtotime() it because getCreateDate() now |
| 599 | + // returns the raw timestamp from the database; in the past |
| 600 | + // it converted it to UNIX timestamp via the SQL function |
| 601 | + // UNIX_TIMESTAMP but that was no good for our purposes |
| 602 | + strtotime( BlogPage::getCreateDate( $newestBlogPost['id'] ) ) |
| 603 | + ) ) . ')'; |
| 604 | + $output .= "</div> |
| 605 | + <div class=\"listpages-blurb\">\n" . |
| 606 | + BlogPage::getBlurb( |
| 607 | + $newestBlogPost['title'], |
| 608 | + $newestBlogPost['ns'], |
| 609 | + 300 |
| 610 | + ) . |
| 611 | + '</div><!-- .listpages-blurb --> |
| 612 | + <div class="listpages-stats">' . "\n"; |
| 613 | + $output .= "<img src=\"{$imgPath}voteIcon.gif\" alt=\"\" border=\"0\" /> " . |
| 614 | + wfMsgExt( |
| 615 | + 'blog-author-votes', |
| 616 | + 'parsemag', |
| 617 | + BlogPage::getVotesForPage( $newestBlogPost['id'] ) |
| 618 | + ); |
| 619 | + $output .= " <img src=\"{$imgPath}comment.gif\" alt=\"\" border=\"0\" /> " . |
| 620 | + wfMsgExt( |
| 621 | + 'blog-author-comments', |
| 622 | + 'parsemag', |
| 623 | + BlogPage::getCommentsForPage( $newestBlogPost['id'] ) |
| 624 | + ) . '</div><!-- . listpages-stats --> |
| 625 | + </div><!-- .listpages-item --> |
| 626 | + <div class="cleared"></div>' . "\n"; |
| 627 | + } |
| 628 | + } |
| 629 | + |
| 630 | + $output .= '</div>' . "\n"; // .listpages-container |
| 631 | + |
| 632 | + return $output; |
| 633 | + } |
| 634 | + |
| 635 | + /** |
| 636 | + * Get the 25 most popular blog posts from the database and then cache them |
| 637 | + * in memcached for 15 minutes. |
| 638 | + * The definition of 'popular' is very arbitrary at the moment. |
| 639 | + * |
| 640 | + * Fork of the original getPopularPosts() method, the only thing changed |
| 641 | + * here is the HTML output which was toned down and count changed from 25 |
| 642 | + * to 10. |
| 643 | + * |
| 644 | + * @return String: HTML |
| 645 | + */ |
| 646 | + public function getPopularPostsForRightSide() { |
| 647 | + global $wgMemc; |
| 648 | + |
| 649 | + // Try cache first |
| 650 | + $key = wfMemcKey( 'blog', 'popular', 'ten' ); |
| 651 | + $data = $wgMemc->get( $key ); |
| 652 | + |
| 653 | + if( $data != '' ) { |
| 654 | + wfDebugLog( 'BlogPage', 'Got popular posts in ArticlesHome from cache' ); |
| 655 | + $popularBlogPosts = $data; |
| 656 | + } else { |
| 657 | + wfDebugLog( 'BlogPage', 'Got popular posts in ArticlesHome from DB' ); |
| 658 | + $dbr = wfGetDB( DB_SLAVE ); |
| 659 | + $commentsTable = $dbr->tableName( 'Comments' ); |
| 660 | + $voteTable = $dbr->tableName( 'Vote' ); |
| 661 | + // Code sporked from Rob Church's NewestPages extension |
| 662 | + $res = $dbr->select( |
| 663 | + array( 'page', 'Comments', 'Vote' ), |
| 664 | + array( |
| 665 | + 'DISTINCT page_id', 'page_namespace', 'page_title', |
| 666 | + 'page_is_redirect', |
| 667 | + ), |
| 668 | + array( |
| 669 | + 'page_namespace' => NS_BLOG, |
| 670 | + 'page_is_redirect' => 0, |
| 671 | + 'page_id = Comment_Page_ID', |
| 672 | + 'page_id = vote_page_id', |
| 673 | + // If you can figure out how to do this without a subquery, |
| 674 | + // please let me know. Until that... |
| 675 | + "((SELECT COUNT(*) FROM $voteTable WHERE vote_page_id = page_id) >= 5 OR |
| 676 | + (SELECT COUNT(*) FROM $commentsTable WHERE Comment_Page_ID = page_id) >= 5)", |
| 677 | + ), |
| 678 | + __METHOD__, |
| 679 | + array( |
| 680 | + 'ORDER BY' => 'page_id DESC', |
| 681 | + 'LIMIT' => 10 |
| 682 | + ), |
| 683 | + array( |
| 684 | + 'Comments' => array( 'INNER JOIN', 'page_id = Comment_Page_ID' ), |
| 685 | + 'Vote' => array( 'INNER JOIN', 'page_id = vote_page_id' ) |
| 686 | + ) |
| 687 | + ); |
| 688 | + |
| 689 | + $popularBlogPosts = array(); |
| 690 | + foreach ( $res as $row ) { |
| 691 | + $popularBlogPosts[] = array( |
| 692 | + 'title' => $row->page_title, |
| 693 | + 'ns' => $row->page_namespace, |
| 694 | + 'id' => $row->page_id |
| 695 | + ); |
| 696 | + } |
| 697 | + |
| 698 | + // Cache in memcached for 15 minutes |
| 699 | + $wgMemc->set( $key, $popularBlogPosts, 60 * 15 ); |
| 700 | + } |
| 701 | + |
| 702 | + $output = '<div class="listpages-container">'; |
| 703 | + if ( empty( $popularBlogPosts ) ) { |
| 704 | + $output .= wfMsg( 'ah-no-results' ); |
| 705 | + } else { |
| 706 | + foreach( $popularBlogPosts as $popularBlogPost ) { |
| 707 | + $titleObj = Title::makeTitle( NS_BLOG, $popularBlogPost['title'] ); |
| 708 | + $votes = BlogPage::getVotesForPage( $popularBlogPost['id'] ); |
| 709 | + $output .= '<div class="listpages-item">'; |
| 710 | + $output .= '<div class="listpages-votebox">' . "\n"; |
| 711 | + $output .= '<div class="listpages-votebox-number">' . |
| 712 | + $votes . "</div>\n"; |
| 713 | + $output .= '<div class="listpages-votebox-text">' . |
| 714 | + wfMsgExt( |
| 715 | + 'blog-author-votes', |
| 716 | + 'parsemag', |
| 717 | + $votes |
| 718 | + ) . "</div>\n"; // .listpages-votebox-text |
| 719 | + $output .= '</div>' . "\n"; // .listpages-votebox |
| 720 | + $output .= '<a href="' . $titleObj->escapeFullURL() . '">' . |
| 721 | + $titleObj->getText() . |
| 722 | + '</a> |
| 723 | + </div><!-- .listpages-item --> |
| 724 | + <div class="cleared"></div>' . "\n"; |
| 725 | + } |
| 726 | + } |
| 727 | + |
| 728 | + $output .= '</div>' . "\n"; // .listpages-container |
| 729 | + |
| 730 | + return $output; |
| 731 | + } |
| 732 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/SpecialArticlesHome.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 733 | + native |
Index: trunk/extensions/BlogPage/Blog.i18n.php |
— | — | @@ -0,0 +1,157 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Internationalization file for the BlogPage extension. |
| 5 | + * |
| 6 | + * @file |
| 7 | + * @ingroup Extensions |
| 8 | + */ |
| 9 | + |
| 10 | +$messages = array(); |
| 11 | + |
| 12 | +/** English |
| 13 | + * @author David Pean |
| 14 | + */ |
| 15 | +$messages['en'] = array( |
| 16 | + 'blog-and' => 'and', |
| 17 | + 'blog-anonymous-name' => 'Anonymous Fanatic', |
| 18 | + 'blog-author-comments' => '$1 {{PLURAL:$1|comment|comments}}', |
| 19 | + 'blog-author-more-by' => 'More By $1', // $1 is a user name |
| 20 | + 'blog-author-points' => '$1 pts', |
| 21 | + 'blog-author-title' => 'About the {{PLURAL:$1|Author|Authors}}', |
| 22 | + 'blog-author-votes' => '$1 {{PLURAL:$1|vote|votes}}', |
| 23 | + 'blog-by' => 'by', |
| 24 | + 'blog-by-user-category' => '$1 by User', // $1 is MediaWiki:Blog-category |
| 25 | + 'blog-category' => 'Articles', // replaces $wgBlogCategory config variable |
| 26 | + 'blog-comments-of-day' => 'Comments of the Day', |
| 27 | + 'blog-created' => 'created $1', |
| 28 | + 'blog-created-ago' => 'created $1 ago', |
| 29 | + 'blog-embed-title' => 'Embed This On Your Site', |
| 30 | + 'blog-in-the-news' => 'In the News', |
| 31 | + 'blog-last-edited' => 'last edited $1', |
| 32 | + 'blog-login' => 'You have to [[Special:UserLogin|log in]] to create articles.', |
| 33 | + 'blog-login-edit' => 'You have to [[Special:UserLogin|log in]] to edit blog articles.', |
| 34 | + 'blog-new-articles' => 'New Articles', |
| 35 | + 'blog-permission-required' => 'You do not have the permission to create articles.', |
| 36 | + 'blog-popular-articles' => 'Don\'t Miss', |
| 37 | + 'blog-multiple-authors' => 'This article was written collaboratively by $1', |
| 38 | + 'blog-recent-editors' => 'Other recent contributors', |
| 39 | + 'blog-recent-editors-message' => 'Make this page better by editing it.', |
| 40 | + 'blog-recent-voters' => 'Other recent voters', |
| 41 | + 'blog-recent-voters-message' => 'If you like the article, vote for it.', |
| 42 | + 'blog-view-archive-link' => 'View All', |
| 43 | + // Duplicates RandomGameUnit's messages, I dunno why |
| 44 | + 'game-unit-quiz-title' => 'Never Ending Quiz', |
| 45 | + 'game-unit-poll-title' => 'Take a Poll', |
| 46 | + 'game-unit-picturegame-title' => 'Play the Picture Game', |
| 47 | + // ArticlesHome |
| 48 | + // title of Special:ArticleLists, as shown on Special:SpecialPages. |
| 49 | + // I could've used ah-new-articles but I figured that people will mistake |
| 50 | + // it to wiki articles as opposed to blog articles so I decided to create a |
| 51 | + // new message instead. |
| 52 | + 'articlelists' => 'New Blog Articles', |
| 53 | + 'ah-no-results' => 'No pages found.', |
| 54 | + 'ah-popular-articles' => 'Popular Articles', |
| 55 | + 'ah-new-articles' => 'New Articles', |
| 56 | + 'ah-rss-feed' => 'RSS feed', |
| 57 | + 'ah-write-article' => 'Write an Article', |
| 58 | + 'ah-todays-articles' => 'Today\'s Articles', |
| 59 | + 'ah-most-votes' => 'Most Votes (72 hours)', |
| 60 | + 'ah-what-talking-about' => 'Most Comments (72 hours)', |
| 61 | + 'articleshome' => 'Blog Homepage', |
| 62 | + // Special:CreateBlogPost |
| 63 | + 'createblogpost' => 'Create Blog Post', |
| 64 | + 'blog-create-rules' => '', // rules shown above the title field; do not translate! |
| 65 | + 'blog-tagcloud-blacklist' => '', // list of categories that won't be shown on the tagcloud; format is: * cat name\n* another |
| 66 | + 'blog-create-category-help' => 'Categories help organize information on the site. To add multiple categories, separate them by commas.', |
| 67 | + 'blog-create-title' => 'Title', |
| 68 | + 'blog-create-text' => 'Text', |
| 69 | + 'blog-create-categories' => 'Categories', |
| 70 | + 'blog-create-button' => 'Create!', |
| 71 | + 'blog-create-summary' => 'New blog post created.', |
| 72 | + 'blog-create-error-need-content' => "'''Error:''' Your blog post must have some content!", |
| 73 | + 'blog-create-error-need-title' => "'''Error:''' You need to supply a title for the blog post!", |
| 74 | + 'blog-create-error-page-exists' => "'''Error:''' There is already a blog post with that title. Please choose a different title for your blog post.", |
| 75 | + 'blog-js-create-error-need-content' => 'Your blog post must have some content!', |
| 76 | + 'blog-js-create-error-need-title' => 'You need to supply a title for the blog post!', |
| 77 | + 'blog-js-create-error-page-exists' => 'There is already a blog post with that title. Please choose a different title for your blog post.', |
| 78 | + // Ported from ListPages |
| 79 | + 'blog-more' => 'more', |
| 80 | + 'blog-time-ago' => '$1 ago', |
| 81 | + 'blog-time-days' => '{{PLURAL:$1|one day|$1 days}}', |
| 82 | + 'blog-time-hours' => '{{PLURAL:$1|one hour|$1 hours}}', |
| 83 | + 'blog-time-minutes' => '{{PLURAL:$1|one minute|$1 minutes}}', |
| 84 | + 'blog-time-seconds' => '{{PLURAL:$1|one second|$1 seconds}}', |
| 85 | + 'right-createblogpost' => '[[Special:CreateBlogPost|Create new blog posts]]', |
| 86 | + // Integration with UserProfile |
| 87 | + // These messages didn't originally have the blog- prefix |
| 88 | + 'blog-user-articles-title' => 'Blogs', |
| 89 | + 'blog-user-articles-votes' => '{{PLURAL:$1|one vote|$1 votes}}', |
| 90 | + 'blog-user-article-comment' => '{{PLURAL:$1|one comment|$1 comments}}', |
| 91 | +); |
| 92 | + |
| 93 | +/** Finnish (Suomi) |
| 94 | + * @author Jack Phoenix <jack@countervandalism.net> |
| 95 | + */ |
| 96 | +$messages['fi'] = array( |
| 97 | + 'blog-and' => 'ja', |
| 98 | + 'blog-anonymous-name' => 'Anonyymi fanaatikko', |
| 99 | + 'blog-author-comments' => '$1 {{PLURAL:$1|kommentti|kommenttia}}', |
| 100 | + 'blog-author-more-by' => 'Lisää kirjoituksia käyttäjältä $1', |
| 101 | + 'blog-author-title' => 'Tietoa {{PLURAL:$1|tekijästä|tekijöistä}}', |
| 102 | + 'blog-author-votes' => '$1 {{PLURAL:$1|ääni|ääntä}}', |
| 103 | + 'blog-by' => 'kirjoittanut', |
| 104 | + 'blog-by-user-category' => '$1, jotka on kirjoittanut', |
| 105 | + 'blog-category' => 'Artikkelit', |
| 106 | + 'blog-comments-of-day' => 'Päivän kommentit', |
| 107 | + 'blog-created' => 'luotu $1', |
| 108 | + 'blog-created-ago' => 'luotu $1 sitten', |
| 109 | + 'blog-in-the-news' => 'Uutisissa', |
| 110 | + 'blog-last-edited' => 'viimeisin muokkaus $1', |
| 111 | + 'blog-login' => 'Sinun tulee [[Special:UserLogin|kirjautua sisään]] luodaksesi artikkeleita.', |
| 112 | + 'blog-login-edit' => 'Sinun tulee [[Special:UserLogin|kirjautua sisään]] muokataksesi blogiartikkeleita.', |
| 113 | + 'blog-more' => 'lisää', |
| 114 | + 'blog-new-articles' => 'Uudet artikkelit', |
| 115 | + 'blog-permission-required' => 'Sinulla ei ole oikeutta luoda artikkeleita.', |
| 116 | + 'blog-popular-articles' => 'Älä unohda', |
| 117 | + 'blog-multiple-authors' => 'Tämän artikkelin kirjoittivat yhdessä $1', |
| 118 | + 'blog-recent-editors' => 'Muut tuoreet muokkaajat', |
| 119 | + 'blog-recent-editors-message' => 'Tee tästä sivusta parempi muokkaamalla sitä.', |
| 120 | + 'blog-recent-voters' => 'Muut tuoreet äänestäjät', |
| 121 | + 'blog-recent-voters-message' => 'Jos pidit artikkelista, äänestä sitä.', |
| 122 | + 'blog-time-ago' => '$1 sitten', |
| 123 | + 'blog-time-days' => '{{PLURAL:$1|päivä|$1 päivää}}', |
| 124 | + 'blog-time-hours' => '{{PLURAL:$1|tunti|$1 tuntia}}', |
| 125 | + 'blog-time-minutes' => '{{PLURAL:$1|minuutti|$1 minuuttia}}', |
| 126 | + 'blog-time-seconds' => '{{PLURAL:$1|sekunti|$1 sekuntia}}', |
| 127 | + 'blog-view-archive-link' => 'Katso kaikki', |
| 128 | + 'game-unit-poll-title' => 'Ota osaa äänestykseen', |
| 129 | + 'game-unit-quiz-title' => 'Pelaa tietovisapeliä', |
| 130 | + 'game-unit-picturegame-title' => 'Pelaa kuvapeliä', |
| 131 | + 'articlelists' => 'Uudet blogiartikkelit', |
| 132 | + 'ah-no-results' => 'Sivuja ei löytynyt.', |
| 133 | + 'ah-popular-articles' => 'Suositut artikkelit', |
| 134 | + 'ah-new-articles' => 'Uudet artikkelit', |
| 135 | + 'ah-rss-feed' => 'RSS-syöte', |
| 136 | + 'ah-write-article' => 'Kirjoita artikkeli', |
| 137 | + 'ah-todays-articles' => 'Tämänpäiväiset artikkelit', |
| 138 | + 'ah-most-votes' => 'Eniten ääniä (72 tuntia)', |
| 139 | + 'ah-what-talking-about' => 'Eniten kommentteja (72 tuntia)', |
| 140 | + 'articleshome' => 'Blogien kotisivu', |
| 141 | + 'createblogpost' => 'Luo blogikirjoitus', |
| 142 | + 'blog-create-category-help' => 'Luokat auttavat järjestämään tämän sivuston tietoa. Lisätäksesi useampia luokkia erottele ne pilkuin.', |
| 143 | + 'blog-create-title' => 'Otsikko', |
| 144 | + 'blog-create-text' => 'Teksti', |
| 145 | + 'blog-create-categories' => 'Luokat', |
| 146 | + 'blog-create-button' => 'Luo!', |
| 147 | + 'blog-create-summary' => 'Uusi blogikirjoitus luotu.', |
| 148 | + 'blog-create-error-need-content' => "'''Virhe:''' Blogikirjoituksellasi tulee olla myös sisältöä!", |
| 149 | + 'blog-create-error-need-title' => "'''Virhe:''' Sinun tulee antaa otsikko blogikirjoituksellesi!", |
| 150 | + 'blog-create-error-page-exists' => "'''Virhe:''' Olemassaolevalla blogikirjoituksella on jo sama otsikko. Annathan erilaisen otsikon blogikirjoituksellesi.", |
| 151 | + 'blog-js-create-error-need-content' => 'Blogikirjoituksellasi tulee olla myös sisältöä!', |
| 152 | + 'blog-js-create-error-need-title' => 'Sinun tulee antaa otsikko blogikirjoituksellesi!', |
| 153 | + 'blog-js-create-error-page-exists' => 'Olemassaolevalla blogikirjoituksella on jo sama otsikko. Annathan erilaisen otsikon blogikirjoituksellesi.', |
| 154 | + 'right-createblogpost' => '[[Special:CreateBlogPost|Luoda uusia blogikirjoituksia]]', |
| 155 | + 'blog-user-articles-title' => 'Blogit', |
| 156 | + 'blog-user-articles-votes' => '{{PLURAL:$1|yksi ääni|$1 ääntä}}', |
| 157 | + 'blog-user-article-comment' => '{{PLURAL:$1|yksi kommentti|$1 kommenttia}}', |
| 158 | +); |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/Blog.i18n.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 159 | + native |
Index: trunk/extensions/BlogPage/Blog.namespaces.php |
— | — | @@ -0,0 +1,65 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Translations of the Blog namespace. |
| 5 | + * |
| 6 | + * @file |
| 7 | + */ |
| 8 | + |
| 9 | +$namespaceNames = array(); |
| 10 | + |
| 11 | +// For wikis where the BlogPage extension is not installed. |
| 12 | +if( !defined( 'NS_BLOG' ) ) { |
| 13 | + define( 'NS_BLOG', 500 ); |
| 14 | +} |
| 15 | + |
| 16 | +if( !defined( 'NS_BLOG_TALK' ) ) { |
| 17 | + define( 'NS_BLOG_TALK', 501 ); |
| 18 | +} |
| 19 | + |
| 20 | +/** English */ |
| 21 | +$namespaceNames['en'] = array( |
| 22 | + NS_BLOG => 'Blog', |
| 23 | + NS_BLOG_TALK => 'Blog_talk', |
| 24 | +); |
| 25 | + |
| 26 | +/** German (Deutsch) */ |
| 27 | +$namespaceNames['de'] = array( |
| 28 | + NS_BLOG => 'Blog', |
| 29 | + NS_BLOG_TALK => 'Blog_Diskussion' |
| 30 | +); |
| 31 | + |
| 32 | +/** Spanish (Español) */ |
| 33 | +$namespaceNames['es'] = array( |
| 34 | + NS_BLOG => 'Blog', |
| 35 | + NS_BLOG_TALK => 'Blog_Discusión' |
| 36 | +); |
| 37 | + |
| 38 | +/** Finnish (Suomi) */ |
| 39 | +$namespaceNames['fi'] = array( |
| 40 | + NS_BLOG => 'Blogi', |
| 41 | + NS_BLOG_TALK => 'Keskustelu_blogista', |
| 42 | +); |
| 43 | + |
| 44 | +/** Dutch (Nederlands) */ |
| 45 | +$namespaceNames['nl'] = array( |
| 46 | + NS_BLOG => 'Blog', |
| 47 | + NS_BLOG_TALK => 'Overleg_blog', |
| 48 | +); |
| 49 | + |
| 50 | +/** Norwegian Nynorsk (Norsk (nynorsk)) */ |
| 51 | +$namespaceNames['nn'] = array( |
| 52 | + NS_BLOG => 'Blogg', |
| 53 | + NS_BLOG_TALK => 'Bloggdiskusjon' |
| 54 | +); |
| 55 | + |
| 56 | +/** Norwegian (bokmål) (Norsk (bokmål)) */ |
| 57 | +$namespaceNames['no'] = array( |
| 58 | + NS_BLOG => 'Blogg', |
| 59 | + NS_BLOG_TALK => 'Bloggdiskusjon' |
| 60 | +); |
| 61 | + |
| 62 | +/** Russian (Русский) */ |
| 63 | +$namespaceNames['ru'] = array( |
| 64 | + NS_BLOG => 'Блог', |
| 65 | + NS_BLOG_TALK => 'Обсуждение_блога' |
| 66 | +); |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/Blog.namespaces.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 67 | + native |
Index: trunk/extensions/BlogPage/BlogPage.css |
— | — | @@ -0,0 +1,379 @@ |
| 2 | +h1.firstHeading { |
| 3 | + display: none; |
| 4 | +} |
| 5 | + |
| 6 | +#main { |
| 7 | + padding: 0px 0px 0px 0px !important; |
| 8 | +} |
| 9 | + |
| 10 | +#main p { |
| 11 | + font-size: 12px; |
| 12 | + font-weight: normal; |
| 13 | + line-height: 16px; |
| 14 | +} |
| 15 | + |
| 16 | +#blog-page-left { |
| 17 | + position: absolute; |
| 18 | + right: 0px; |
| 19 | + top: 0px; |
| 20 | + width: 20%; |
| 21 | +} |
| 22 | + |
| 23 | +#blog-page-middle { |
| 24 | + margin: 0px; |
| 25 | + width: 75%; |
| 26 | + float: none; |
| 27 | + overflow: visible; |
| 28 | + padding: 0px; |
| 29 | +} |
| 30 | + |
| 31 | +#blog-page-right { |
| 32 | + float: right;/*left;*/ |
| 33 | + width: 179px; |
| 34 | + padding: 8px 0px 0px 0px; |
| 35 | + background-color: #F2F4F7; |
| 36 | + border-left: 1px solid #dcdcdc; |
| 37 | + border-bottom: 1px solid #dcdcdc; |
| 38 | + padding: 10px; |
| 39 | + overflow: hidden; |
| 40 | +} |
| 41 | + |
| 42 | +#blog-page-middle h1.page-title { |
| 43 | + margin: 5px 0px 0px 0px !important; |
| 44 | + line-height: 22px; |
| 45 | +} |
| 46 | + |
| 47 | +#blog-page-middle #edit-menu { |
| 48 | + margin: 0px 0px 0px 7px !important; |
| 49 | +} |
| 50 | + |
| 51 | +.blog-left-units { |
| 52 | + background-color: #F2F4F7; |
| 53 | + padding: 10px 10px 5px 10px; |
| 54 | + border-bottom: 1px solid #dcdcdc; |
| 55 | +} |
| 56 | + |
| 57 | +.blog-container { |
| 58 | + padding: 0px 0px 10px 0px; |
| 59 | + margin: 0px 0px 10px 0px; |
| 60 | + border-bottom: 1px solid #dcdcdc; |
| 61 | +} |
| 62 | + |
| 63 | +.blog-container h2 { |
| 64 | + margin: 0px 0px 8px 0px !important; |
| 65 | + font-size: 16px; |
| 66 | + letter-spacing: -1px; |
| 67 | + color: #333; |
| 68 | +} |
| 69 | + |
| 70 | +.bottom-fix { |
| 71 | + border-bottom: none !important; |
| 72 | + padding-bottom: 5px !important; |
| 73 | + margin-bottom: 0px !important; |
| 74 | +} |
| 75 | + |
| 76 | +/* Author */ |
| 77 | +.author-container-fix { |
| 78 | + margin: 0px 0px 10px 0px; |
| 79 | +} |
| 80 | + |
| 81 | +.more-container { |
| 82 | + margin: 0px 0px 10px 0px; |
| 83 | + padding: 7px 0px 5px 0px; |
| 84 | + border-bottom: 1px solid #dcdcdc; |
| 85 | +} |
| 86 | + |
| 87 | +.more-container-fix { |
| 88 | + margin:0px !important; |
| 89 | + border:none !important; |
| 90 | +} |
| 91 | + |
| 92 | +.blog-left-units h2 { |
| 93 | + letter-spacing: -1px; |
| 94 | + padding: 0px !important; |
| 95 | + margin: 0px !important; |
| 96 | + color: #333; |
| 97 | +} |
| 98 | + |
| 99 | +.author-info { |
| 100 | + font-size: 11px; |
| 101 | + color: #333; |
| 102 | + line-height: 14px; |
| 103 | + margin: 10px 0px 0px 0px; |
| 104 | +} |
| 105 | + |
| 106 | +.author-info img { |
| 107 | + float: left; |
| 108 | + border: 1px solid #dcdcdc; |
| 109 | + padding: 3px; |
| 110 | + background-color: #fff; |
| 111 | + display: block; |
| 112 | + text-align: justify; |
| 113 | + margin: 0px 10px 0px 0px; |
| 114 | +} |
| 115 | + |
| 116 | +.author-articles { |
| 117 | + margin: 4px 0px 0px 0px; |
| 118 | +} |
| 119 | + |
| 120 | +.more-container h3 { |
| 121 | + margin: 0px 0px 5px 0px !important; |
| 122 | + font-size: 11px; |
| 123 | + letter-spacing: -1px; |
| 124 | + color: #555; |
| 125 | +} |
| 126 | + |
| 127 | +.author-title { |
| 128 | + margin: 0px 0px 6px 0px; |
| 129 | +} |
| 130 | + |
| 131 | +.author-title a { |
| 132 | + text-decoration: none; |
| 133 | + font-size: 14px; |
| 134 | + font-weight: bold; |
| 135 | +} |
| 136 | + |
| 137 | +.author-article-item { |
| 138 | + line-height: 12px; |
| 139 | + margin: 0px 0px 4px 0px; |
| 140 | +} |
| 141 | + |
| 142 | +.author-article-item a { |
| 143 | + text-decoration: none; |
| 144 | + font-size: 11px; |
| 145 | +} |
| 146 | + |
| 147 | +.author-item-small { |
| 148 | + font-size: 10px; |
| 149 | + color: #888; |
| 150 | +} |
| 151 | + |
| 152 | +.author-archive-link { |
| 153 | + text-align: right; |
| 154 | + font-size: 10px; |
| 155 | +} |
| 156 | + |
| 157 | +/* Recent Container */ |
| 158 | +.recent-container { |
| 159 | + margin: 0px 0px 10px; |
| 160 | + padding: 0px 0px 10px; |
| 161 | + font-size: 11px; |
| 162 | + border-bottom: 1px solid #dcdcdc; |
| 163 | +} |
| 164 | + |
| 165 | +.recent-container div { |
| 166 | + font-size: 10px; |
| 167 | + margin: 0px 0px 5px 0px; |
| 168 | + line-height: 11px; |
| 169 | + color: #888; |
| 170 | +} |
| 171 | + |
| 172 | +.recent-container h2 { |
| 173 | + letter-spacing: -1px; |
| 174 | + font-size: 14px; |
| 175 | + margin: 0px 0px 1px 0px !important; |
| 176 | + color: #333; |
| 177 | +} |
| 178 | + |
| 179 | +.recent-item { |
| 180 | + margin: 0px 0px 0px 0px; |
| 181 | +} |
| 182 | + |
| 183 | +.recent-title { |
| 184 | + color: #444; |
| 185 | + font-size: 12px; |
| 186 | + line-height: 13px; |
| 187 | + font-weight: bold; |
| 188 | + margin: 0px 0px 10px 0px; |
| 189 | +} |
| 190 | + |
| 191 | +.recent-container img { |
| 192 | + padding: 2px; |
| 193 | + border: 1px solid #dcdcdc; |
| 194 | + background-color: #fff; |
| 195 | + margin:2 px 2px 0px 0px |
| 196 | +} |
| 197 | + |
| 198 | +.recent-container a { |
| 199 | + text-decoration: none; |
| 200 | +} |
| 201 | + |
| 202 | +/* Comment of the Day */ |
| 203 | +.cod-score { |
| 204 | + font-weight: bold; |
| 205 | + color: #fff; |
| 206 | + background-color: orange; |
| 207 | + padding: 0px 3px; |
| 208 | + margin: 0px 4px 0px 0px; |
| 209 | +} |
| 210 | + |
| 211 | +.cod-poster a { |
| 212 | + font-size: 12px; |
| 213 | + text-decoration: none; |
| 214 | +} |
| 215 | + |
| 216 | +.cod-comment a { |
| 217 | + text-decoration: none; |
| 218 | + font-size: 12px; |
| 219 | +} |
| 220 | + |
| 221 | +.cod-comment { |
| 222 | + line-height: 13px; |
| 223 | +} |
| 224 | + |
| 225 | +.cod-item { |
| 226 | + margin: 0px 0px 5px 0px; |
| 227 | + overflow: hidden; |
| 228 | +} |
| 229 | + |
| 230 | +.cod-item img { |
| 231 | + padding: 1px; |
| 232 | + background-color: #fff; |
| 233 | + border: 1px solid #dcdcdc; |
| 234 | + vertical-align: middle; |
| 235 | +} |
| 236 | + |
| 237 | +/* Ad Unit */ |
| 238 | +.article-ad { |
| 239 | + margin: 10px 0px 0px 0px; |
| 240 | + text-align: center; |
| 241 | +} |
| 242 | + |
| 243 | +.article-ad a { |
| 244 | + text-align: center; |
| 245 | +} |
| 246 | + |
| 247 | +/* Casual Game */ |
| 248 | +.game-unit-container { |
| 249 | + padding: 0px 0px 10px 0px; |
| 250 | + margin: 0px 0px 10px 0px; |
| 251 | + border-bottom: 1px solid #dcdcdc; |
| 252 | + overflow: hidden; |
| 253 | +} |
| 254 | + |
| 255 | +.game-unit-container h2 { |
| 256 | + margin: 0px 0px 8px 0px !important; |
| 257 | + font-size: 16px; |
| 258 | + letter-spacing: -1px; |
| 259 | + color: #333; |
| 260 | +} |
| 261 | + |
| 262 | +.poll-unit-title { |
| 263 | + font-size: 12px; |
| 264 | + line-height: 13px; |
| 265 | + font-weight: bold; |
| 266 | + color: #777; |
| 267 | + margin: 0px 0px 8px 0px; |
| 268 | +} |
| 269 | + |
| 270 | +.poll-unit-choices a { |
| 271 | + text-decoration: none; |
| 272 | + font-weight: bold; |
| 273 | + font-size: 12px; |
| 274 | + display: block; |
| 275 | +} |
| 276 | + |
| 277 | +.poll-unit-image { |
| 278 | + margin: 0px 0px 8px 0px; |
| 279 | +} |
| 280 | + |
| 281 | +.poll-unit-image img { |
| 282 | + padding: 3px; |
| 283 | + background-color: #fff; |
| 284 | + border: 1px solid #dcdcdc; |
| 285 | +} |
| 286 | + |
| 287 | +.poll-unit-choices input { |
| 288 | + margin: 0px 5px 0px 0px; |
| 289 | +} |
| 290 | + |
| 291 | +.quiz-unit-image { |
| 292 | + margin: 8px 0px 0px 0px; |
| 293 | +} |
| 294 | + |
| 295 | +.quiz-unit-image img { |
| 296 | + padding: 3px; |
| 297 | + background-color: #fff; |
| 298 | + border: 1px solid #dcdcdc; |
| 299 | +} |
| 300 | + |
| 301 | +.quiz-unit-title a { |
| 302 | + font-size: 13px; |
| 303 | + text-decoration: none; |
| 304 | + font-weight: bold; |
| 305 | +} |
| 306 | + |
| 307 | +.pg-unit-title { |
| 308 | + font-size: 12px; |
| 309 | + line-height: 13px; |
| 310 | + font-weight: bold; |
| 311 | + color: #777; |
| 312 | + margin: 0px 0px 8px 0px; |
| 313 | +} |
| 314 | + |
| 315 | +.pg-unit-pictures img { |
| 316 | + float: left; |
| 317 | + background-color: #fff; |
| 318 | + border: 1px solid #dcdcdc; |
| 319 | + padding: 3px; |
| 320 | + margin: 0px 3px 0px 0px; |
| 321 | +} |
| 322 | + |
| 323 | +.pickem-unit-game { |
| 324 | + /*border-bottom: 1px solid #dcdcdc;*/ |
| 325 | + padding: 8px 0px; |
| 326 | +} |
| 327 | + |
| 328 | +.pickem-unit-date { |
| 329 | + font-weight: bold; |
| 330 | +} |
| 331 | + |
| 332 | +.pickem-unit-visitor, .pickem-unit-home { |
| 333 | + margin: 5px 0px 0px 0px; |
| 334 | + cursor: pointer; |
| 335 | +} |
| 336 | + |
| 337 | +.pickem-unit-visitor img, .pickem-unit-home img{ |
| 338 | + vertical-align: middle; |
| 339 | + border: 1px solid #dcdcdc; |
| 340 | + margin: 0px 5px 0px 0px; |
| 341 | +} |
| 342 | + |
| 343 | +.pickem-unit-nogame { |
| 344 | + font-weight: bold; |
| 345 | + color: #FF0000; |
| 346 | +} |
| 347 | + |
| 348 | +/* List Pages */ |
| 349 | +#blog-page-right .listpages-item { |
| 350 | + line-height: 14px; |
| 351 | +} |
| 352 | + |
| 353 | +#blog-page-right .listpages-item a { |
| 354 | + font-size: 12px !important; |
| 355 | + font-weight: normal !important; |
| 356 | + text-decoration: none !important; |
| 357 | +} |
| 358 | + |
| 359 | +#blog-page-right .listpages-item { |
| 360 | + margin: 0px 0px 6px 0px !important; |
| 361 | +} |
| 362 | + |
| 363 | +/* By Line */ |
| 364 | +.blog-byline { |
| 365 | + font-weight: bold; |
| 366 | + margin: 8px 0px 0px 0px; |
| 367 | + color: #555; |
| 368 | + font-size: 13px; |
| 369 | +} |
| 370 | + |
| 371 | +.blog-byline-last-edited { |
| 372 | + font-size: 11px; |
| 373 | + color: #888; |
| 374 | + margin: 0px 0px 15px 0px; |
| 375 | +} |
| 376 | + |
| 377 | +/* Categories */ |
| 378 | +#categories { |
| 379 | + padding: 10px 0px; |
| 380 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/BlogPage.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 381 | + native |
Index: trunk/extensions/BlogPage/CreateBlogPost.js |
— | — | @@ -0,0 +1,48 @@ |
| 2 | +var CreateBlogPost = { |
| 3 | + /** |
| 4 | + * Insert a tag (category) from the category cloud into the inputbox below |
| 5 | + * it on Special:CreateBlogPost |
| 6 | + * |
| 7 | + * @param tagname String: category name |
| 8 | + * @param tagnumber Integer |
| 9 | + */ |
| 10 | + insertTag: function( tagname, tagnumber ) { |
| 11 | + document.getElementById( 'tag-' + tagnumber ).style.color = '#CCCCCC'; |
| 12 | + document.getElementById( 'tag-' + tagnumber ).innerHTML = tagname; |
| 13 | + // Funny...if you move this getElementById call into a variable and use |
| 14 | + // that variable here, this won't work as intended |
| 15 | + document.getElementById( 'pageCtg' ).value += |
| 16 | + ( ( document.getElementById( 'pageCtg' ).value ) ? ', ' : '' ) + |
| 17 | + tagname; |
| 18 | + }, |
| 19 | + |
| 20 | + /** |
| 21 | + * Check that the user has given a title for the blog post and has supplied |
| 22 | + * some content; then check the existence of the title and notify the user |
| 23 | + * if there's already a blog post with the same name as their blog post. |
| 24 | + */ |
| 25 | + performChecks: function() { |
| 26 | + // In PHP, we need to use $wgRequest->getVal( 'title2' ); 'title' |
| 27 | + // contains the current special page's name instead of the blog post |
| 28 | + // name |
| 29 | + var title = document.getElementById( 'title' ).value; |
| 30 | + if ( !title || title == '' ) { |
| 31 | + alert( _BLOG_NEEDS_TITLE ); |
| 32 | + return ''; |
| 33 | + } |
| 34 | + var pageBody = document.getElementById( 'pageBody' ).value; |
| 35 | + if ( !pageBody || pageBody == '' ) { |
| 36 | + alert( _BLOG_NEEDS_CONTENT ); |
| 37 | + return ''; |
| 38 | + } |
| 39 | + |
| 40 | + sajax_request_type = 'POST'; |
| 41 | + sajax_do_call( 'SpecialCreateBlogPost::checkTitleExistence', [ title ], function( r ) { |
| 42 | + if( r.responseText.indexOf( 'OK' ) >= 0 ) { |
| 43 | + document.editform.submit(); |
| 44 | + } else { |
| 45 | + alert( _BLOG_PAGE_EXISTS ); |
| 46 | + } |
| 47 | + }); |
| 48 | + } |
| 49 | +}; |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/CreateBlogPost.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 50 | + native |
Index: trunk/extensions/BlogPage/Blog.php |
— | — | @@ -0,0 +1,142 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * BlogPage -- introduces a new namespace, NS_BLOG (numeric index is 500 by |
| 5 | + * default) and some special handling for the pages in this namespace |
| 6 | + * |
| 7 | + * @file |
| 8 | + * @ingroup Extensions |
| 9 | + * @version 2.0 |
| 10 | + * @author David Pean <david.pean@gmail.com> |
| 11 | + * @author Jack Phoenix <jack@countervandalism.net> |
| 12 | + * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
| 13 | + * @link http://www.mediawiki.org/wiki/Extension:BlogPage Documentation |
| 14 | + */ |
| 15 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 16 | + die(); |
| 17 | +} |
| 18 | + |
| 19 | +// Extension credits that will show up on Special:Version |
| 20 | +$wgExtensionCredits['other'][] = array( |
| 21 | + 'name' => 'BlogPage', |
| 22 | + 'version' => '2.0', |
| 23 | + 'author' => array( 'David Pean', 'Jack Phoenix' ), |
| 24 | + 'description' => 'Blogging system with commenting and voting features, ' . |
| 25 | + '[[Special:CreateBlogPost|a special page to create blog posts]] and ' . |
| 26 | + '[[Special:ArticlesHome|a special page to list blog posts]]', |
| 27 | + 'url' => 'http://www.mediawiki.org/wiki/Extension:BlogPage', |
| 28 | +); |
| 29 | + |
| 30 | +// Define the namespace constants |
| 31 | +define( 'NS_BLOG', 500 ); |
| 32 | +define( 'NS_BLOG_TALK', 501 ); |
| 33 | + |
| 34 | +// ResourceLoader support for MediaWiki 1.17+ |
| 35 | +$blogResourceTemplate = array( |
| 36 | + 'localBasePath' => dirname( __FILE__ ), |
| 37 | + 'remoteExtPath' => 'BlogPage' |
| 38 | +); |
| 39 | + |
| 40 | +// Main module, used on *all* blog pages (see the hooks file) |
| 41 | +$wgResourceModules['ext.blogPage'] = $blogResourceTemplate + array( |
| 42 | + 'styles' => 'BlogPage.css' |
| 43 | +); |
| 44 | + |
| 45 | +// Used on Special:ArticlesHome & Special:ArticleLists |
| 46 | +$wgResourceModules['ext.blogPage.articlesHome'] = $blogResourceTemplate + array( |
| 47 | + 'styles' => 'ArticlesHome.css' |
| 48 | +); |
| 49 | + |
| 50 | +// Used on Special:CreateBlogPost |
| 51 | +$wgResourceModules['ext.blogPage.create'] = $blogResourceTemplate + array( |
| 52 | + 'styles' => 'CreateBlogPost.css', |
| 53 | + 'scripts' => 'CreateBlogPost.js', |
| 54 | + 'messages' => array( |
| 55 | + 'blog-js-create-error-need-content', 'blog-js-create-error-need-title', |
| 56 | + 'blog-js-create-error-page-exists' |
| 57 | + ), |
| 58 | + 'position' => 'top' // available since r85616 |
| 59 | +); |
| 60 | + |
| 61 | +// Default setup for displaying sections |
| 62 | +$wgBlogPageDisplay = array( |
| 63 | + // Output the left-hand column? This column contains the list of authors, |
| 64 | + // recent editors (if enabled), recent voters (if enabled), embed widget |
| 65 | + // (if enabled) and left-side advertisement (if enabled). |
| 66 | + 'leftcolumn' => true, |
| 67 | + // Output the right-hand column? This column contains the list of popular |
| 68 | + // blog articles (if enabled), in the news section (if enabled), comments |
| 69 | + // of the day (if enabled), a random casual game (if enabled) and a list of |
| 70 | + // new blog articles. |
| 71 | + 'rightcolumn' => true, |
| 72 | + // Display the box that contains some information about the author of the |
| 73 | + // blog post? |
| 74 | + 'author' => true, |
| 75 | + // Display some (three, to be exact) other blog articles written by the |
| 76 | + // same user? |
| 77 | + 'author_articles' => true, |
| 78 | + // Display a list of people (complete with their avatars) who recently |
| 79 | + // edited this blog post? |
| 80 | + 'recent_editors' => true, |
| 81 | + // Display a list of people (complete with their avatars) who recently |
| 82 | + // voted for this blog post? |
| 83 | + 'recent_voters' => true, |
| 84 | + // Show an advertisement in the left-hand column? |
| 85 | + 'left_ad' => false, |
| 86 | + // Show a listing of the most popular blog posts? |
| 87 | + 'popular_articles' => true, |
| 88 | + // Should we display some random news items from [[MediaWiki:Inthenews]]? |
| 89 | + 'in_the_news' => true, |
| 90 | + // Show comments of the day (comments with the most votes) in the sidebar |
| 91 | + // on a blog post page? |
| 92 | + 'comments_of_day' => true, |
| 93 | + // Display a random casual game (picture game, poll or quiz)? |
| 94 | + // Requires the RandomGameUnit extension. |
| 95 | + 'games' => true, |
| 96 | + // Show a listing of the newest blog posts in blog pages? |
| 97 | + 'new_articles' => true, |
| 98 | + // Display the widget that allows you to embed the blog post on another |
| 99 | + // site? Off by default since it requires the ContentWidget extension, |
| 100 | + // which is currently ArmchairGM-specific. |
| 101 | + 'embed_widget' => false |
| 102 | +); |
| 103 | + |
| 104 | +// Set up everything |
| 105 | +$dir = dirname( __FILE__ ) . '/'; |
| 106 | +$wgExtensionMessagesFiles['Blog'] = $dir . 'Blog.i18n.php'; |
| 107 | +$wgExtensionAliasesFiles['Blog'] = $dir . 'Blog.alias.php'; |
| 108 | +// Namespace translations |
| 109 | +$wgExtensionMessagesFiles['BlogNamespaces'] = $dir . 'Blog.namespaces.php'; |
| 110 | + |
| 111 | +// Autoload the class which is used when rendering pages in the NS_BLOG NS |
| 112 | +$wgAutoloadClasses['BlogPage'] = $dir . 'BlogPage.php'; |
| 113 | + |
| 114 | +// Special pages |
| 115 | +$wgAutoloadClasses['ArticlesHome'] = $dir . 'SpecialArticlesHome.php'; |
| 116 | +$wgAutoloadClasses['ArticleLists'] = $dir . 'SpecialArticleLists.php'; |
| 117 | +$wgSpecialPages['ArticlesHome'] = 'ArticlesHome'; |
| 118 | +$wgSpecialPages['ArticleLists'] = 'ArticleLists'; |
| 119 | + |
| 120 | +// Special page for creating new blog posts + yet another copy of TagCloud class |
| 121 | +$wgAutoloadClasses['BlogTagCloud'] = $dir . 'TagCloudClass.php'; |
| 122 | +$wgAutoloadClasses['SpecialCreateBlogPost'] = $dir . 'SpecialCreateBlogPost.php'; |
| 123 | +$wgSpecialPages['CreateBlogPost'] = 'SpecialCreateBlogPost'; |
| 124 | + |
| 125 | +$wgAjaxExportList[] = 'SpecialCreateBlogPost::checkTitleExistence'; |
| 126 | + |
| 127 | +// New user right, required to create new blog posts via the new special page |
| 128 | +$wgAvailableRights[] = 'createblogpost'; |
| 129 | +$wgGroupPermissions['*']['createblogpost'] = false; |
| 130 | +$wgGroupPermissions['user']['createblogpost'] = true; |
| 131 | + |
| 132 | +// Hooked functions |
| 133 | +$wgAutoloadClasses['BlogHooks'] = $dir . 'BlogHooks.php'; |
| 134 | + |
| 135 | +$wgHooks['ArticleFromTitle'][] = 'BlogHooks::blogFromTitle'; |
| 136 | +$wgHooks['ArticleSaveComplete'][] = 'BlogHooks::updateCreatedOpinionsCount'; |
| 137 | +$wgHooks['ArticleSave'][] = 'BlogHooks::updateCreatedOpinionsCount'; |
| 138 | +$wgHooks['AlternateEdit'][] = 'BlogHooks::allowShowEditBlogPage'; |
| 139 | +$wgHooks['CanonicalNamespaces'][] = 'BlogHooks::onCanonicalNamespaces'; |
| 140 | +// UserProfile integration |
| 141 | +$wgHooks['UserProfileRightSideAfterActivity'][] = 'BlogHooks::getArticles'; |
| 142 | +// Show blogs in profiles; this needs to be defined to prevent "undefined index" notices |
| 143 | +$wgUserProfileDisplay['articles'] = true; |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/Blog.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 144 | + native |
Index: trunk/extensions/BlogPage/SpecialArticleLists.php |
— | — | @@ -0,0 +1,138 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * A special page that displays the 25 most recent blog posts. |
| 5 | + * |
| 6 | + * @file |
| 7 | + * @ingroup Extensions |
| 8 | + */ |
| 9 | +class ArticleLists extends IncludableSpecialPage { |
| 10 | + |
| 11 | + /** |
| 12 | + * Constructor -- set up the new special page |
| 13 | + */ |
| 14 | + public function __construct() { |
| 15 | + parent::__construct( 'ArticleLists' ); |
| 16 | + } |
| 17 | + |
| 18 | + /** |
| 19 | + * Show the new special page |
| 20 | + * |
| 21 | + * @param $limit Integer: show this many entries (LIMIT for SQL) |
| 22 | + */ |
| 23 | + public function execute( $limit ) { |
| 24 | + global $wgMemc, $wgOut, $wgScriptPath; |
| 25 | + |
| 26 | + $wgOut->setPageTitle( wfMsg( 'ah-new-articles' ) ); |
| 27 | + |
| 28 | + if ( empty( $limit ) ) { |
| 29 | + $limit = 25; |
| 30 | + } elseif ( !empty( $limit ) ) { |
| 31 | + $limit = intval( $limit ); |
| 32 | + } |
| 33 | + |
| 34 | + // Add some CSS for ListPages |
| 35 | + // @todo FIXME: this should be loaded when including the special page, |
| 36 | + // too, but if ( $this->including() ) does nothing, prolly because of |
| 37 | + // the parser cache |
| 38 | + if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) { |
| 39 | + $wgOut->addModules( 'ext.blogPage.articlesHome' ); |
| 40 | + } else { |
| 41 | + $wgOut->addExtensionStyle( $wgScriptPath . '/extensions/BlogPage/ArticlesHome.css' ); |
| 42 | + } |
| 43 | + |
| 44 | + $imgPath = $wgScriptPath . '/extensions/BlogPage/images/'; |
| 45 | + |
| 46 | + $output = '<div class="left-articles">'; |
| 47 | + if ( !$this->including() ) { |
| 48 | + $output .= '<h2>' . wfMsg( 'ah-new-articles' ) . '</h2>'; |
| 49 | + } |
| 50 | + |
| 51 | + // Try cache first |
| 52 | + $key = wfMemcKey( 'blog', 'new', 'twentyfive' ); |
| 53 | + $data = $wgMemc->get( $key ); |
| 54 | + |
| 55 | + if( $data != '' ) { |
| 56 | + wfDebugLog( 'BlogPage', 'Got new articles in ArticleLists from cache' ); |
| 57 | + $newBlogPosts = $data; |
| 58 | + } else { |
| 59 | + wfDebugLog( 'BlogPage', 'Got new articles in ArticleLists from DB' ); |
| 60 | + $dbr = wfGetDB( DB_SLAVE ); |
| 61 | + // Code sporked from Rob Church's NewestPages extension |
| 62 | + // You rock, dude! |
| 63 | + $res = $dbr->select( |
| 64 | + 'page', |
| 65 | + array( |
| 66 | + 'page_namespace', 'page_title', 'page_is_redirect', |
| 67 | + 'page_id' |
| 68 | + ), |
| 69 | + array( 'page_namespace' => NS_BLOG, 'page_is_redirect' => 0 ), |
| 70 | + __METHOD__, |
| 71 | + array( 'ORDER BY' => 'page_id DESC', 'LIMIT' => $limit ) |
| 72 | + ); |
| 73 | + |
| 74 | + $newBlogPosts = array(); |
| 75 | + foreach ( $res as $row ) { |
| 76 | + $newBlogPosts[] = array( |
| 77 | + 'title' => $row->page_title, |
| 78 | + 'ns' => $row->page_namespace, |
| 79 | + 'id' => $row->page_id |
| 80 | + ); |
| 81 | + } |
| 82 | + |
| 83 | + // Cache in memcached for 15 minutes |
| 84 | + $wgMemc->set( $key, $newBlogPosts, 60 * 15 ); |
| 85 | + } |
| 86 | + |
| 87 | + $output .= '<div class="listpages-container">' . "\n"; |
| 88 | + if ( empty( $newBlogPosts ) ) { |
| 89 | + $output .= wfMsg( 'ah-no-results' ); |
| 90 | + } else { |
| 91 | + foreach( $newBlogPosts as $newBlogPost ) { |
| 92 | + $titleObj = Title::makeTitle( NS_BLOG, $newBlogPost['title'] ); |
| 93 | + $output .= "\t\t\t\t" . '<div class="listpages-item">'; |
| 94 | + $pageImage = BlogPage::getPageImage( $newBlogPost['id'] ); |
| 95 | + if( $pageImage ) { |
| 96 | + // Load MediaWiki image object to get thumbnail tag |
| 97 | + $img = wfFindFile( $pageImage ); |
| 98 | + $imgTag = ''; |
| 99 | + if ( is_object( $img ) ) { |
| 100 | + $thumb = $img->getThumbnail( 65, 0, true ); |
| 101 | + $imgTag = $thumb->toHtml(); |
| 102 | + } |
| 103 | + |
| 104 | + $output .= "<div class=\"listpages-image\">{$imgTag}</div>\n"; |
| 105 | + } |
| 106 | + $output .= '<a href="' . $titleObj->escapeFullURL() . '">' . |
| 107 | + $titleObj->getText() . |
| 108 | + "</a> |
| 109 | + <div class=\"listpages-blurb\">\n" . |
| 110 | + BlogPage::getBlurb( |
| 111 | + $newBlogPost['title'], |
| 112 | + $newBlogPost['ns'], |
| 113 | + 300 |
| 114 | + ) . |
| 115 | + '</div><!-- .listpages-blurb --> |
| 116 | + <div class="listpages-stats">' . "\n"; |
| 117 | + $output .= "<img src=\"{$imgPath}voteIcon.gif\" alt=\"\" border=\"0\" /> " . |
| 118 | + wfMsgExt( |
| 119 | + 'blog-author-votes', |
| 120 | + 'parsemag', |
| 121 | + BlogPage::getVotesForPage( $newBlogPost['id'] ) |
| 122 | + ); |
| 123 | + $output .= " <img src=\"{$imgPath}comment.gif\" alt=\"\" border=\"0\" /> " . |
| 124 | + wfMsgExt( |
| 125 | + 'blog-author-comments', |
| 126 | + 'parsemag', |
| 127 | + BlogPage::getCommentsForPage( $newBlogPost['id'] ) |
| 128 | + ) . '</div><!-- . listpages-stats --> |
| 129 | + </div><!-- .listpages-item --> |
| 130 | + <div class="cleared"></div>' . "\n"; |
| 131 | + } |
| 132 | + } |
| 133 | + $output .= '</div>' . "\n"; // .listpages-container |
| 134 | + $output .= '</div>' . "\n"; // .left-articles |
| 135 | + |
| 136 | + $wgOut->addHTML( $output ); |
| 137 | + } |
| 138 | + |
| 139 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/SpecialArticleLists.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 140 | + native |
Index: trunk/extensions/BlogPage/BlogHooks.php |
— | — | @@ -0,0 +1,399 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * All BlogPage's hooked functions. These were previously scattered all over |
| 5 | + * the place in various files. |
| 6 | + * |
| 7 | + * @file |
| 8 | + */ |
| 9 | +class BlogHooks { |
| 10 | + |
| 11 | + /** |
| 12 | + * Calls BlogPage instead of standard Article for pages in the NS_BLOG |
| 13 | + * namespace. |
| 14 | + * |
| 15 | + * @param $title Object: instance of Title |
| 16 | + * @param $article Object: instance of Article that we convert into a BlogPage |
| 17 | + * @return Boolean: true |
| 18 | + */ |
| 19 | + public static function blogFromTitle( &$title, &$article ) { |
| 20 | + global $wgRequest, $wgOut, $wgParser, $wgHooks, $wgScriptPath; |
| 21 | + global $wgSupressPageTitle, $wgSupressSubTitle, $wgSupressPageCategories; |
| 22 | + |
| 23 | + if ( $title->getNamespace() == NS_BLOG ) { |
| 24 | + if( !$wgRequest->getVal( 'action' ) ) { |
| 25 | + $wgSupressPageTitle = true; |
| 26 | + } |
| 27 | + |
| 28 | + $wgSupressSubTitle = true; |
| 29 | + $wgSupressPageCategories = true; |
| 30 | + |
| 31 | + // This will suppress category links in SkinTemplate-based skins |
| 32 | + $wgHooks['SkinTemplateOutputPageBeforeExec'][] = function( $sk, $tpl ) { |
| 33 | + $tpl->set( 'catlinks', '' ); |
| 34 | + return true; |
| 35 | + }; |
| 36 | + |
| 37 | + $wgOut->enableClientCache( false ); |
| 38 | + $wgParser->disableCache(); |
| 39 | + |
| 40 | + // Add CSS |
| 41 | + if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) { |
| 42 | + $wgOut->addModules( 'ext.blogPage' ); |
| 43 | + } else { |
| 44 | + $wgOut->addExtensionStyle( $wgScriptPath . '/extensions/BlogPage/BlogPage.css' ); |
| 45 | + } |
| 46 | + |
| 47 | + // This originally used $wgTitle but I saw no point in that, so I |
| 48 | + // changed that as per Chad et al. |
| 49 | + $article = new BlogPage( $title ); |
| 50 | + } |
| 51 | + |
| 52 | + return true; |
| 53 | + } |
| 54 | + |
| 55 | + /** |
| 56 | + * Checks that the user is logged is, is not blocked via Special:Block and has |
| 57 | + * the 'edit' user right when they're trying to edit a page in the NS_BLOG NS. |
| 58 | + * |
| 59 | + * @param $editPage Object: instance of EditPage |
| 60 | + * @return Boolean: true if the user should be allowed to continue, else false |
| 61 | + */ |
| 62 | + public static function allowShowEditBlogPage( $editPage ) { |
| 63 | + global $wgOut, $wgUser; |
| 64 | + if( $editPage->mTitle->getNamespace() == NS_BLOG ) { |
| 65 | + if( $wgUser->isAnon() ) { // anons can't edit blog pages |
| 66 | + if( !$editPage->mTitle->exists() ) { |
| 67 | + $wgOut->addWikiMsg( 'blog-login' ); |
| 68 | + } else { |
| 69 | + $wgOut->addWikiMsg( 'blog-login-edit' ); |
| 70 | + } |
| 71 | + return false; |
| 72 | + } |
| 73 | + |
| 74 | + if ( !$wgUser->isAllowed( 'edit' ) || $wgUser->isBlocked() ) { |
| 75 | + $wgOut->addHTML( wfMsg( 'blog-permission-required' ) ); |
| 76 | + return false; |
| 77 | + } |
| 78 | + } |
| 79 | + return true; |
| 80 | + } |
| 81 | + |
| 82 | + /** |
| 83 | + * This function was originally in the UserStats directory, in the file |
| 84 | + * CreatedOpinionsCount.php. |
| 85 | + * This function here updates the stats_opinions_created column in the |
| 86 | + * user_stats table every time the user creates a new blog post. |
| 87 | + * |
| 88 | + * This is hooked into two separate hooks (todo: find out why), ArticleSave |
| 89 | + * and ArticleSaveComplete. Their arguments are mostly the same and both |
| 90 | + * have $article as the first argument. |
| 91 | + * |
| 92 | + * @param $article Object: Article object representing the page that was/is |
| 93 | + * (being) saved |
| 94 | + * @return Boolean: true |
| 95 | + */ |
| 96 | + public static function updateCreatedOpinionsCount( &$article ) { |
| 97 | + global $wgOut, $wgUser; |
| 98 | + |
| 99 | + $aid = $article->getTitle()->getArticleID(); |
| 100 | + // Shortcut, in order not to perform stupid queries (cl_from = 0...) |
| 101 | + if ( $aid == 0 ) { |
| 102 | + return true; |
| 103 | + } |
| 104 | + |
| 105 | + $dbr = wfGetDB( DB_SLAVE ); |
| 106 | + $res = $dbr->select( |
| 107 | + 'categorylinks', |
| 108 | + 'cl_to', |
| 109 | + // Chad was right, $wgTitle is pure satan; this used to use that |
| 110 | + // and as a result this was completely busted |
| 111 | + array( 'cl_from' => $aid ), |
| 112 | + __METHOD__ |
| 113 | + ); |
| 114 | + |
| 115 | + foreach ( $res as $row ) { |
| 116 | + $ctg = Title::makeTitle( NS_CATEGORY, $row->cl_to ); |
| 117 | + $ctgname = $ctg->getText(); |
| 118 | + $blogCat = wfMsgForContent( 'blog-category' ); |
| 119 | + $userBlogCat = wfMsgForContent( 'blog-by-user-category', $blogCat ); |
| 120 | + |
| 121 | + if( strpos( $ctgname, $userBlogCat ) !== false ) { |
| 122 | + $user_name = trim( str_replace( $userBlogCat, '', $ctgname ) ); |
| 123 | + $u = User::idFromName( $user_name ); |
| 124 | + |
| 125 | + if( $u ) { |
| 126 | + $stats = new UserStatsTrack( $u, $user_name ); |
| 127 | + // Copied from UserStatsTrack::updateCreatedOpinionsCount() |
| 128 | + // Throughout this code, we could use $u and $user_name |
| 129 | + // instead of $stats->user_id and $stats->user_name but |
| 130 | + // there's no point in doing that because we have to call |
| 131 | + // clearCache() in any case |
| 132 | + if ( !$wgUser->isAnon() && $stats->user_id ) { |
| 133 | + $ctg = $userBlogCat . ' '. $stats->user_name; |
| 134 | + $parser = new Parser(); |
| 135 | + $ctgTitle = Title::newFromText( |
| 136 | + $parser->preprocess( |
| 137 | + trim( $ctg ), |
| 138 | + $wgOut->parserOptions() |
| 139 | + ) |
| 140 | + ); |
| 141 | + $ctgTitle = $ctgTitle->getDBkey(); |
| 142 | + $dbw = wfGetDB( DB_MASTER ); |
| 143 | + |
| 144 | + $opinions = $dbw->select( |
| 145 | + array( 'page', 'categorylinks' ), |
| 146 | + array( 'COUNT(*) AS CreatedOpinions' ), |
| 147 | + array( |
| 148 | + 'cl_to' => $ctgTitle, |
| 149 | + 'page_namespace' => NS_BLOG // paranoia |
| 150 | + ), |
| 151 | + __METHOD__, |
| 152 | + array(), |
| 153 | + array( |
| 154 | + 'categorylinks' => array( |
| 155 | + 'INNER JOIN', |
| 156 | + 'page_id = cl_from' |
| 157 | + ) |
| 158 | + ) |
| 159 | + ); |
| 160 | + |
| 161 | + // Please die in a fire, PHP. |
| 162 | + // selectField() would be ideal above but it returns |
| 163 | + // insane results (over 300 when the real count is |
| 164 | + // barely 10) so we have to fuck around with a |
| 165 | + // foreach() loop that we don't even need in theory |
| 166 | + // just because PHP is...PHP. |
| 167 | + $opinionsCreated = 0; |
| 168 | + foreach ( $opinions as $opinion ) { |
| 169 | + $opinionsCreated = $opinion->CreatedOpinions; |
| 170 | + } |
| 171 | + |
| 172 | + $res = $dbw->update( |
| 173 | + 'user_stats', |
| 174 | + array( 'stats_opinions_created' => $opinionsCreated ), |
| 175 | + array( 'stats_user_id' => $stats->user_id ), |
| 176 | + __METHOD__ |
| 177 | + ); |
| 178 | + |
| 179 | + $stats->clearCache(); |
| 180 | + } |
| 181 | + } |
| 182 | + } |
| 183 | + } |
| 184 | + |
| 185 | + return true; |
| 186 | + } |
| 187 | + |
| 188 | + /** |
| 189 | + * Show a list of this user's blog articles in their user profile page. |
| 190 | + * |
| 191 | + * @param $userProfile Object: instance of UserProfilePage |
| 192 | + * @return Boolean: true |
| 193 | + */ |
| 194 | + public static function getArticles( $userProfile ) { |
| 195 | + global $wgUserProfileDisplay, $wgMemc, $wgOut; |
| 196 | + |
| 197 | + if ( !$wgUserProfileDisplay['articles'] ) { |
| 198 | + return ''; |
| 199 | + } |
| 200 | + |
| 201 | + $user_name = $userProfile->user_name; |
| 202 | + $output = ''; |
| 203 | + |
| 204 | + // Try cache first |
| 205 | + $key = wfMemcKey( 'user', 'profile', 'articles', $userProfile->user_id ); |
| 206 | + $data = $wgMemc->get( $key ); |
| 207 | + $articles = array(); |
| 208 | + |
| 209 | + if( $data != '' ) { |
| 210 | + wfDebugLog( |
| 211 | + 'BlogPage', |
| 212 | + "Got UserProfile articles for user {$user_name} from cache\n" |
| 213 | + ); |
| 214 | + $articles = $data; |
| 215 | + } else { |
| 216 | + wfDebugLog( |
| 217 | + 'BlogPage', |
| 218 | + "Got UserProfile articles for user {$user_name} from DB\n" |
| 219 | + ); |
| 220 | + $categoryTitle = Title::newFromText( |
| 221 | + wfMsgForContent( |
| 222 | + 'blog-by-user-category', |
| 223 | + wfMsgForContent( 'blog-category' ) |
| 224 | + ) . " {$user_name}" |
| 225 | + ); |
| 226 | + |
| 227 | + $dbr = wfGetDB( DB_SLAVE ); |
| 228 | + /** |
| 229 | + * I changed the original query a bit, since it wasn't returning |
| 230 | + * what it should've. |
| 231 | + * I added the DISTINCT to prevent one page being listed five times |
| 232 | + * and added the page_namespace to the WHERE clause to get only |
| 233 | + * blog pages and the cl_from = page_id to the WHERE clause so that |
| 234 | + * the cl_to stuff actually, y'know, works :) |
| 235 | + */ |
| 236 | + $res = $dbr->select( |
| 237 | + array( 'page', 'categorylinks' ), |
| 238 | + array( 'DISTINCT page_id', 'page_title', 'page_namespace' ), |
| 239 | + /* WHERE */array( |
| 240 | + 'cl_from = page_id', |
| 241 | + 'cl_to' => array( $categoryTitle->getDBkey() ), |
| 242 | + 'page_namespace' => NS_BLOG |
| 243 | + ), |
| 244 | + __METHOD__, |
| 245 | + array( 'ORDER BY' => 'page_id DESC', 'LIMIT' => 5 ) |
| 246 | + ); |
| 247 | + |
| 248 | + foreach ( $res as $row ) { |
| 249 | + $articles[] = array( |
| 250 | + 'page_title' => $row->page_title, |
| 251 | + 'page_namespace' => $row->page_namespace, |
| 252 | + 'page_id' => $row->page_id |
| 253 | + ); |
| 254 | + } |
| 255 | + |
| 256 | + $wgMemc->set( $key, $articles, 60 ); |
| 257 | + } |
| 258 | + |
| 259 | + // Load opinion count via user stats; |
| 260 | + $stats = new UserStats( $userProfile->user_id, $user_name ); |
| 261 | + $stats_data = $stats->getUserStats(); |
| 262 | + $articleCount = $stats_data['opinions_created']; |
| 263 | + |
| 264 | + $articleLink = Title::makeTitle( |
| 265 | + NS_CATEGORY, |
| 266 | + wfMsgForContent( |
| 267 | + 'blog-by-user-category', |
| 268 | + wfMsgForContent( 'blog-category' ) |
| 269 | + ) . " {$user_name}" |
| 270 | + ); |
| 271 | + |
| 272 | + if ( count( $articles ) > 0 ) { |
| 273 | + $output .= '<div class="user-section-heading"> |
| 274 | + <div class="user-section-title">' . |
| 275 | + wfMsg( 'blog-user-articles-title' ) . |
| 276 | + '</div> |
| 277 | + <div class="user-section-actions"> |
| 278 | + <div class="action-right">'; |
| 279 | + if( $articleCount > 5 ) { |
| 280 | + $output .= '<a href="' . $articleLink->escapeFullURL() . |
| 281 | + '" rel="nofollow">' . wfMsg( 'user-view-all' ) . '</a>'; |
| 282 | + } |
| 283 | + $output .= '</div> |
| 284 | + <div class="action-left">' . wfMsgExt( |
| 285 | + 'user-count-separator', |
| 286 | + 'parsemag', |
| 287 | + count( $articles ), |
| 288 | + $articleCount |
| 289 | + ) . '</div> |
| 290 | + <div class="cleared"></div> |
| 291 | + </div> |
| 292 | + </div> |
| 293 | + <div class="cleared"></div> |
| 294 | + <div class="user-articles-container">'; |
| 295 | + |
| 296 | + $x = 1; |
| 297 | + |
| 298 | + foreach( $articles as $article ) { |
| 299 | + $articleTitle = Title::makeTitle( |
| 300 | + $article['page_namespace'], |
| 301 | + $article['page_title'] |
| 302 | + ); |
| 303 | + $voteCount = BlogPage::getVotesForPage( $article['page_id'] ); |
| 304 | + $commentCount = BlogPage::getCommentsForPage( $article['page_id'] ); |
| 305 | + |
| 306 | + if ( $x == 1 ) { |
| 307 | + $divClass = 'article-item-top'; |
| 308 | + } else { |
| 309 | + $divClass = 'article-item'; |
| 310 | + } |
| 311 | + $output .= '<div class="' . $divClass . "\"> |
| 312 | + <div class=\"number-of-votes\"> |
| 313 | + <div class=\"vote-number\">{$voteCount}</div> |
| 314 | + <div class=\"vote-text\">" . |
| 315 | + wfMsgExt( |
| 316 | + 'blog-user-articles-votes', |
| 317 | + 'parsemag', |
| 318 | + $voteCount |
| 319 | + ) . |
| 320 | + '</div> |
| 321 | + </div> |
| 322 | + <div class="article-title"> |
| 323 | + <a href="' . $articleTitle->escapeFullURL() . |
| 324 | + "\">{$articleTitle->getText()}</a> |
| 325 | + <span class=\"item-small\">" . |
| 326 | + wfMsgExt( |
| 327 | + 'blog-user-article-comment', |
| 328 | + 'parsemag', |
| 329 | + $commentCount |
| 330 | + ) . '</span> |
| 331 | + </div> |
| 332 | + <div class="cleared"></div> |
| 333 | + </div>'; |
| 334 | + |
| 335 | + $x++; |
| 336 | + } |
| 337 | + |
| 338 | + $output .= '</div>'; |
| 339 | + } |
| 340 | + |
| 341 | + $wgOut->addHTML( $output ); |
| 342 | + |
| 343 | + return true; |
| 344 | + } |
| 345 | + |
| 346 | + /** |
| 347 | + * Register the canonical names for our namespace and its talkspace. |
| 348 | + * |
| 349 | + * @param $list Array: array of namespace numbers with corresponding |
| 350 | + * canonical names |
| 351 | + * @return Boolean: true |
| 352 | + */ |
| 353 | + public static function onCanonicalNamespaces( &$list ) { |
| 354 | + $list[NS_BLOG] = 'Blog'; |
| 355 | + $list[NS_BLOG_TALK] = 'Blog_talk'; |
| 356 | + return true; |
| 357 | + } |
| 358 | + |
| 359 | + /* optimization :) |
| 360 | + public static function updateFacebookProfile() { |
| 361 | + global $wgUser, $IP, $wgTitle, $wgServer, $wgSitename; |
| 362 | + |
| 363 | + // Check if the current user has the app installed |
| 364 | + $dbr = wfGetDB( DB_SLAVE ); |
| 365 | + $s = $dbr->selectRow( |
| 366 | + 'fb_link_view_opinions', |
| 367 | + array( 'fb_user_id', 'fb_user_session_key' ), |
| 368 | + array( 'fb_user_id_wikia' => $wgUser->getID() ), |
| 369 | + __METHOD__ |
| 370 | + ); |
| 371 | + |
| 372 | + if ( $s !== false ) { |
| 373 | + require_once "$IP/extensions/Facebook/appinclude.php"; |
| 374 | + $facebook = new Facebook( $appapikey, $appsecret ); |
| 375 | + //$facebook->api_client->auth_getSession( 'QR1YVV' ); |
| 376 | + //$facebook->api_client->session_key = 'QR1YVV'; |
| 377 | + |
| 378 | + // Update Facebook profile |
| 379 | + try { |
| 380 | + $facebook->api_client->session_key = $infinite_session_key; |
| 381 | + $facebook->api_client->fbml_refreshRefUrl( |
| 382 | + "http://sports.box8.tpa.wikia-inc.com/index.php?title=Special:FacebookGetOpinions&id={$s->fb_user_id}" |
| 383 | + ); |
| 384 | + } catch( exception $ex ) { |
| 385 | + } |
| 386 | + |
| 387 | + $feedTitle = '<fb:userlink uid="' . $s->fb_user_id . |
| 388 | + '" /> wrote a new article on <a href="' . $wgServer . '">' . |
| 389 | + $wgSitename . '</a>'; |
| 390 | + $feedBody = "<a href=\"{$wgTitle->getFullURL()}\">{$wgTitle->getText()}</a>"; |
| 391 | + try{ |
| 392 | + $facebook->api_client->feed_publishActionOfUser( $feedTitle, $feedBody ); |
| 393 | + } catch( exception $ex ) { |
| 394 | + } |
| 395 | + } |
| 396 | + |
| 397 | + return true; |
| 398 | + } |
| 399 | + */ |
| 400 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/BlogHooks.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 401 | + native |
Index: trunk/extensions/BlogPage/TagCloudClass.php |
— | — | @@ -0,0 +1,72 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * @file |
| 5 | + * @copyright Copyright © 2007, Wikia Inc. |
| 6 | + * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
| 7 | + */ |
| 8 | +class BlogTagCloud { |
| 9 | + var $tags_min_pts = 8; |
| 10 | + var $tags_max_pts = 32; |
| 11 | + var $tags_highest_count = 0; |
| 12 | + var $tags_size_type = 'pt'; |
| 13 | + |
| 14 | + public function __construct( $limit = 10 ) { |
| 15 | + $this->limit = $limit; |
| 16 | + $this->initialize(); |
| 17 | + } |
| 18 | + |
| 19 | + public function initialize() { |
| 20 | + $dbr = wfGetDB( DB_MASTER ); |
| 21 | + $res = $dbr->select( |
| 22 | + 'categorylinks', |
| 23 | + array( 'cl_to', 'COUNT(*) AS count' ), |
| 24 | + array(), |
| 25 | + __METHOD__, |
| 26 | + array( |
| 27 | + 'GROUP BY' => 'cl_to', |
| 28 | + 'ORDER BY' => 'count DESC', |
| 29 | + 'LIMIT' => $this->limit |
| 30 | + ) |
| 31 | + ); |
| 32 | + |
| 33 | + $message = trim( wfMsgForContent( 'blog-tagcloud-blacklist' ) ); |
| 34 | + $catsExcluded = array(); |
| 35 | + // Yes, the strlen() is needed, I dunno why wfEmptyMsg() won't work |
| 36 | + if( !wfEmptyMsg( 'blog-tagcloud-blacklist', $message ) && strlen( $message ) > 0 ) { |
| 37 | + $catsExcluded = explode( "\n* ", wfMsgForContent( 'blog-tagcloud-blacklist' ) ); |
| 38 | + } |
| 39 | + |
| 40 | + wfSuppressWarnings(); // prevent PHP from bitching about strtotime() |
| 41 | + foreach( $res as $row ) { |
| 42 | + $tag_name = Title::makeTitle( NS_CATEGORY, $row->cl_to ); |
| 43 | + $tag_text = $tag_name->getText(); |
| 44 | + // Exclude dates and blacklisted categories |
| 45 | + if( |
| 46 | + !in_array( $tag_text, $catsExcluded ) && |
| 47 | + strtotime( $tag_text ) == '' |
| 48 | + ) |
| 49 | + { |
| 50 | + if( $row->count > $this->tags_highest_count ) { |
| 51 | + $this->tags_highest_count = $row->count; |
| 52 | + } |
| 53 | + $this->tags[$tag_text] = array( 'count' => $row->count ); |
| 54 | + } |
| 55 | + } |
| 56 | + wfRestoreWarnings(); |
| 57 | + |
| 58 | + // sort tag array by key (tag name) |
| 59 | + if( $this->tags_highest_count == 0 ) { |
| 60 | + return; |
| 61 | + } |
| 62 | + ksort( $this->tags ); |
| 63 | + /* and what if we have _1_ category? like on a new wiki with nteen articles, mhm? */ |
| 64 | + if( $this->tags_highest_count == 1 ) { |
| 65 | + $coef = $this->tags_max_pts - $this->tags_min_pts; |
| 66 | + } else { |
| 67 | + $coef = ( $this->tags_max_pts - $this->tags_min_pts ) / ( ( $this->tags_highest_count - 1 ) * 2 ); |
| 68 | + } |
| 69 | + foreach( $this->tags as $tag => $att ) { |
| 70 | + $this->tags[$tag]['size'] = $this->tags_min_pts + ( $this->tags[$tag]['count'] - 1 ) * $coef; |
| 71 | + } |
| 72 | + } |
| 73 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/BlogPage/TagCloudClass.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 74 | + native |