User:Cm~mediawikiwiki/SelectCategoryFunctions

From mediawiki.org
<?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 .= '&nbsp;&nbsp;';
				}
				//				$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;
	}
}