<?php
# Implementation of the SelectCategory extension, an extension of the
# edit box of MediaWiki to provide an easy way to add category links
# to a specific page.
# @addtogroup Extensions
# @author Leon Weber <leon@leonweber.de> & Manuel Schneider <manuel.schneider@wikimedia.ch>
# @copyright ĂŠ 2006 by Leon Weber & Manuel Schneider
# @licence GNU General Public Licence 2.0 or later
# Extended by Cynthia Mattingly @ Marketing Factory Consulting
# * If editing a category page, the category and its subcategories are not options
# * User can also enter a new category in a text box
if( !defined( 'MEDIAWIKI' ) ) {
echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
die();
}
## Entry point for the hook and main worker function for editing the page:
function fnSelectCategoryShowHook( $m_isUpload = false, &$m_pageObj ) {
global $wgContLang;
$what = get_class($m_pageObj);
if ($what == 'EditPage') {
$a = $m_pageObj->getArticle();
}
# check if we should do anything or sleep
if ( fnSelectCategoryCheckConditions( $m_isUpload, &$m_pageObj ) ) {
# Register CSS file for our select box:
global $wgOut, $wgScriptPath;
$wgOut->addLink(
array(
'rel' => 'stylesheet',
'type' => 'text/css',
'href' => "$wgScriptPath/extensions/SelectCategory/SelectCategory.css"
)
);
# Get all categories from wiki:
$m_allCats = fnSelectCategoryGetAllCategories();
# Load system messages:
wfLoadExtensionMessages( 'SelectCategory' );
# Get the right member variables, depending on if we're on an upload form or not:
if( !$m_isUpload ) {
# Extract all categorylinks from page:
$m_pageCats = fnSelectCategoryGetPageCategories( $m_pageObj );
# Never ever use editFormTextTop here as it resides outside the <form> so we will never get contents
$m_place = 'editFormTextAfterWarn';
# Print the localised title for the select box:
$m_textBefore = '<b>'. wfMsg( 'selectcategory-title' ) . '</b>:';
} else {
# No need to get categories:
$m_pageCats = array();
# Place output at the right place:
$m_place = 'uploadFormTextAfterSummary';
# Print the part of the table including the localised title for the select box:
$m_textBefore = "\n</td></tr><tr><td align='right'><label for='wpSelectCategory'>" . wfMsg( 'selectcategory-title' ) .":</label></td><td align='left'>";
}
# Introduce the output:
$m_pageObj->$m_place .= "<!-- SelectCategory begin -->\n";
# Print the select box:
$m_pageObj->$m_place .= "\n$m_textBefore";
# # First come up with the JavaScript version of the select boxes:
# $m_pageObj->$m_place .= "<script type=\"text/javascript\" src=\"'/extensions/SelectCategory/SelectCategory.js\"></script>\n";
# # Then the "old-style" select box for those without JavaScript:
# $m_pageObj->$m_place .= "<noscript>\n";
# $m_pageObj->$m_place .= "</noscript>\n";
if ($what == 'EditPage' && (get_class($a) == 'CategoryPage' || get_class($a) == 'CategoryTreeCategoryPage')) {
//we are editing a category page, so we want to exclude the current category
//and its subcategories from the list!
$m_catString = strtolower( $wgContLang->getNsText( NS_CATEGORY ) );
# The regular expression to find the current category name:
$m_pattern = "({$m_catString}|category):([^\|\]]*)(\|{{PAGENAME}}|)";
preg_match( "/{$m_pattern}/i", $a->getTitle(), $cat);
if (is_array($cat) && count($cat) > 0) {
$currentcategory = $cat[2];
}
} else {
$currentcategory = '';
}
$excludeuntillevel = '';
$m_pageObj->$m_place .= "<ul id='SelectCategoryList'>";
$text = '';
foreach( $m_allCats as $m_cat => $m_depth ) {
$checkbox = true;
if ($currentcategory == $m_cat) {
$excludeuntillevel = $m_depth;
$checkbox = false;
} elseif ($excludeuntillevel !== '' && $m_depth > $excludeuntillevel) {
$checkbox = false;
} elseif ($excludeuntillevel !== '' && $m_depth == $excludeuntillevel) {
$excludeuntillevel = '';
}
$checked = '';
if (isset($m_pageCats[$m_cat])) {
$checked = "checked='checked'";
}
$category = htmlspecialchars( $m_cat );
# Indent subcategories
$indention = '';
for ($i = 0; $i < $m_depth; $i++) {
$indention .= ' ';
}
// $text .=
if ($checkbox) {
$m_pageObj->$m_place .= "
<li>
$indention<input type='checkbox' name='SelectCategoryList[]'
value='$category' class='checkbox' $checked />
$category
</li>";
} else {
$m_pageObj->$m_place .= "
<li>
$indention<input type='checkbox' name='SelectCategoryList[]'
value='$category' class='checkbox' $checked disabled />
$category
</li>";
}
}
#die();
$m_pageObj->$m_place .= '</ul>';
$m_pageObj->$m_place .= "<label for='wpEnterCategory'><b>".wfMsg( 'entercategory-title' ).'</b></label> '.
'<input name="wpEnterCategory" id="wpEnterCategory">'.'<br><br>';
# Print localised help string:
$m_pageObj->$m_place .= "<!-- SelectCategory end -->\n";
}
# Return true to let the rest work:
return true;
}
## Entry point for the hook and main worker function for saving the page:
function fnSelectCategorySaveHook( $m_isUpload, &$m_pageObj ) {
global $wgContLang;
global $wgTitle;
# check if we should do anything or sleep
if ( fnSelectCategoryCheckConditions( $m_isUpload, &$m_pageObj ) ) {
# Get localised namespace string:
$m_catString = $wgContLang->getNsText( NS_CATEGORY );
# default sort key is page name with stripped namespace name,
# otherwise sorting is ugly.
if ($wgTitle->getNamespace() == NS_MAIN) {
$default_sortkey = "";
} else {
$default_sortkey = "|{{PAGENAME}}";
}
# Get some distance from the rest of the content:
$m_text = "\n";
# Iterate through all selected category entries:
if (array_key_exists('SelectCategoryList', $_POST)) {
foreach( $_POST['SelectCategoryList'] as $m_cat ) {
$m_text .= "\n[[$m_catString:$m_cat$default_sortkey]]";
}
}
if (array_key_exists('wpEnterCategory', $_POST) && trim($_POST['wpEnterCategory']) != '') {
$m_text .= "\n[[$m_catString:".$_POST['wpEnterCategory']."]]";
}
# If it is an upload we have to call a different method:
if ( $m_isUpload ) {
$m_pageObj->mUploadDescription .= $m_text;
} else{
$m_pageObj->textbox1 .= $m_text;
}
}
# Return to the let MediaWiki do the rest of the work:
return true;
}
## Get all categories from the wiki - starting with a given root or otherwise detect root automagically (expensive)
## Returns an array like this:
## array (
## 'Name' => (int) Depth,
## ...
## )
function fnSelectCategoryGetAllCategories() {
global $wgTitle;
global $wgSelectCategoryRoot;
# Get current namespace (save duplicate call of method):
$m_namespace = $wgTitle->getNamespace();
if( $m_namespace >= 0 && $wgSelectCategoryRoot[$m_namespace] ) {
# Include root and step into the recursion:
$m_allCats = array_merge( array( $wgSelectCategoryRoot[$m_namespace] => 0 ), fnSelectCategoryGetChildren( $wgSelectCategoryRoot[$m_namespace] ) );
} else {
# Initialize return value:
$m_allCats = array();
# Get a database object:
$m_dbObj =& wfGetDB( DB_SLAVE );
# Get table names to access them in SQL query:
$m_tblCatLink = $m_dbObj->tableName( 'categorylinks' );
$m_tblPage = $m_dbObj->tableName( 'page' );
# Automagically detect root categories:
$m_sql = " SELECT tmpSelectCat1.cl_to AS title
FROM $m_tblCatLink AS tmpSelectCat1
LEFT JOIN $m_tblPage AS tmpSelectCatPage ON (tmpSelectCat1.cl_to = tmpSelectCatPage.page_title AND tmpSelectCatPage.page_namespace = 14)
LEFT JOIN $m_tblCatLink AS tmpSelectCat2 ON tmpSelectCatPage.page_id = tmpSelectCat2.cl_from
WHERE tmpSelectCat2.cl_from IS NULL GROUP BY tmpSelectCat1.cl_to";
# Run the query:
$m_res = $m_dbObj->query( $m_sql, __METHOD__ );
# Process the resulting rows:
while ( $m_row = $m_dbObj->fetchRow( $m_res ) ) {
$m_allCats += array( $m_row['title'] => 0 );
$m_allCats += fnSelectCategoryGetChildren( $m_row['title'] );
}
# Free result:
$m_dbObj->freeResult( $m_res );
}
# Afterwards return the array to the caller:
return $m_allCats;
}
function fnSelectCategoryGetChildren( $m_root, $m_depth = 1 ) {
# Initialize return value:
$m_allCats = array();
# Get a database object:
$m_dbObj =& wfGetDB( DB_SLAVE );
# Get table names to access them in SQL query:
$m_tblCatLink = $m_dbObj->tableName( 'categorylinks' );
$m_tblPage = $m_dbObj->tableName( 'page' );
# The normal query to get all children of a given root category:
$m_sql = " SELECT tmpSelectCatPage.page_title AS title
FROM $m_tblCatLink AS tmpSelectCat
LEFT JOIN $m_tblPage AS tmpSelectCatPage ON tmpSelectCat.cl_from = tmpSelectCatPage.page_id
WHERE tmpSelectCat.cl_to LIKE " . $m_dbObj->addQuotes( $m_root ) . " AND tmpSelectCatPage.page_namespace = 14";
# Run the query:
$m_res = $m_dbObj->query( $m_sql, __METHOD__ );
# Process the resulting rows:
while ( $m_row = $m_dbObj->fetchRow( $m_res ) ) {
# Survive category link loops:
if( $m_root == $m_row['title'] ) {
continue;
}
$m_row['title'] = str_replace(array('_'), ' ', $m_row['title']);
# Add current entry to array:
$m_allCats += array( $m_row['title'] => $m_depth );
$m_allCats += fnSelectCategoryGetChildren( $m_row['title'], $m_depth + 1 );
}
# Free result:
$m_dbObj->freeResult( $m_res );
# Afterwards return the array to the upper recursion level:
return $m_allCats;
}
## Returns an array with the categories the articles is in.
## Also removes them from the text the user views in the editbox.
function fnSelectCategoryGetPageCategories( $m_pageObj ) {
if (array_key_exists('SelectCategoryList', $_POST)) {
# We have already extracted the categories, return them instead
# of extracting zero categories from the page text.
$m_catLinks = array();
foreach( $_POST['SelectCategoryList'] as $m_cat ) {
$m_catLinks[ $m_cat ] = true;
}
return $m_catLinks;
}
global $wgContLang;
# Get page contents:
$m_pageText = $m_pageObj->textbox1;
# Get localised namespace string:
$m_catString = strtolower( $wgContLang->getNsText( NS_CATEGORY ) );
# The regular expression to find the category links:
$m_pattern = "\[\[({$m_catString}|category):([^\|\]]*)(\|{{PAGENAME}}|)\]\]";
$m_replace = "$2";
# The container to store all found category links:
$m_catLinks = array ();
# The container to store the processed text:
$m_cleanText = '';
# Check linewise for category links:
foreach( explode( "\n", $m_pageText ) as $m_textLine ) {
# Filter line through pattern and store the result:
$m_cleanText .= preg_replace( "/{$m_pattern}/i", "", $m_textLine ) . "\n";
# Check if we have found a category, else proceed with next line:
if( !preg_match( "/{$m_pattern}/i", $m_textLine) ) continue;
# Get the category link from the original text and store it in our list:
$m_catLinks[ str_replace( ' ', '_', preg_replace( "/.*{$m_pattern}/i", $m_replace, $m_textLine ) ) ] = true;
}
# Place the cleaned text into the text box:
$m_pageObj->textbox1 = trim( $m_cleanText );
# Return the list of categories as an array:
return $m_catLinks;
}
# Function that checks if we meet the run conditions of the extension
function fnSelectCategoryCheckConditions ($m_isUpload, &$m_pageObj ) {
global $wgSelectCategoryNamespaces;
global $wgSelectCategoryEnableSubpages;
global $wgTitle;
# Run only if we are in an upload, an activated namespace or if page is
# a subpage and subpages are enabled (unfortunately we can't use
# implication in PHP) but not if we do a sectionedit:
if ($m_isUpload == true) {
return true;
}
$ns = $wgTitle->getNamespace();
if (array_key_exists ($ns, $wgSelectCategoryNamespaces)) {
$enabledForNamespace = $wgSelectCategoryNamespaces[$ns];
} else {
$enabledForNamespace = false;
}
# Check if page is subpage once to save method calls below:
$m_isSubpage = $wgTitle->isSubpage();
if ($enabledForNamespace
&& (!$m_isSubpage
|| $m_isSubpage && $wgSelectCategoryEnableSubpage)
&& $m_pageObj->section == false) {
return true;
}
}