<?php
/*
Plugin Name: WP-Cats
Plugin URI: http://www.uwmike.com/wordpress/wp-cats/
Description: Ajax-y category controls added to the Manage Posts screen
Author: Mike Purvis
Author URI: http://www.uwmike.com
Version: 0.13

Copyright 2006  Mike Purvis  (mike@uwmike.com)


This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/


$wp_cats_mozilla_columns = false;
$wp_cats_mozilla_column_height = '310px';



add_action('plugins_loaded', create_function('$a', 'global $wp_cats; $wp_cats = new wp_cats;'));
add_action('admin_head',	array(&$wp_cats, 'header_inserts'));
add_action('init',			array(&$wp_cats, 'hijack'));

class wp_cats {

	function header_inserts() {
		global $parent_file;

		if ('edit.php' == $parent_file) {
			echo '<script type="text/javascript">var wp_cats_category_title = \''.__('Categories').'\';</script>' . "\n";
			echo '<script type="text/javascript" src="' . get_bloginfo('url') . '/?wp-cats=js&v=00002"></script>' . "\n";
			echo '<link rel="stylesheet" type="text/css" href="' . get_bloginfo('url') . '/?wp-cats=css&v=00002" />';
		}
	}


	function hijack() {
		if (!isset($_GET['wp-cats'])) return;
		
		if ('cats' == $_GET['wp-cats']) {
			echo '<div id="wp-cats-visible-list">';
			wp_list_cats('hide_empty=false');
			echo '</div><div id="wp-cats-hidden-list">';
			remove_filter('list_cats', 'wptexturize');
			wp_list_cats('hide_empty=false');
			echo '</div>';
			die();
		}

		if ('modify' == $_GET['wp-cats']) {
			global $wp_query;

			if (!isset($_POST['post_id']) || !isset($_POST['cat_name']) || !isset($_POST['addremove']) ) die('<error>Request malformed.</error>');

			$post_id = (int)$_POST['post_id'];
			$cat_id = get_cat_id($_POST['cat_name']);

			if (!current_user_can('edit_post', $post_id)) die('<error>You don\'t have permission to modify this entry.</error>');
			
			$post_cats = wp_get_post_cats('', $post_id);			
			if (count($post_cats) == 1 && 'add' == $_POST['addremove'] && get_cat_name($post_cats[0]) == 'Uncategorized')
				unset($post_cats[0]);
			
			$cat_search = array_search($cat_id, $post_cats);

			if ('add' == $_POST['addremove'] and $cat_search === false) $post_cats[] = $cat_id;
			if ('remove' == $_POST['addremove'] and $cat_search !== false) unset($post_cats[$cat_search]);
				
			wp_set_post_cats('', $post_id, $post_cats);

			// Spoof "the_category" into thinking it's inside "the loop"
			global $post;
			$post = (object) NULL;
			$post->ID = $post_id;
			the_category(', ');
			
			die();
		}


		if ('js' == $_GET['wp-cats']) {
			header("Content-type: text/javascript");
			die($this->js());
		}
		
		if ('css' == $_GET['wp-cats']) {
			header("Content-type: text/css");
			die($this->css());
		}
	}

	function js()
	{
		return <<<EOJS

/* Javascript functions for WP-Cats */

var js_wp_catbox, js_wp_cats = '', js_wp_column_categories = 0;
var js_wp_catbox_closeit = function() {};

function js_wp_cats_make_link(title, f) {
	var new_link = document.createElement('a');
	new_link.className = 'wp-cats-button';
	if (title == '+') new_link.className += ' wp-cats-button-plus';
	new_link.innerHTML = title;
	new_link.href = '#';
	new_link.onclick = f;
	return new_link;
}

function wp_cats_linkify_row(this_row) {
	var post_id = this_row.getElementsByTagName('th')[0].innerHTML;
	var cats_cell = this_row.getElementsByTagName('td')[js_wp_column_categories - 1];
	var cat_links = cats_cell.getElementsByTagName('a');
	
	// Link to add categories
	var add_this = function() {
		cats_cell.insertBefore(js_wp_cats_make_link('+', function() {
			js_wp_cats_popup(post_id, cats_cell);
			return false;
		}), cats_cell.firstChild);
	};
	
	// Links to remove existing categories
	for (var link_iterate = cat_links.length - 1; link_iterate >= 0; link_iterate--) {
		var this_link = cat_links[link_iterate];
		
		add_this = (function(link, attached, last) {
				return function () {
					last();
					cats_cell.insertBefore(link, attached.nextSibling);
				}
			})(
				(function(post_id, category_name) {
					return js_wp_cats_make_link('-', function() {
						js_wp_cats_modify(post_id, category_name, cats_cell, 'remove');
						return false;
					});
				})(post_id, this_link.innerHTML), this_link, add_this);
	}
	
	add_this();
}

function js_wp_cats_setup() {
	var table, columns, rows;
	var new_link;
	if (!(table = document.getElementById('the-list-x'))) return;	// bail if there's no post list
	rows = table.getElementsByTagName('tr');
	columns = rows[0].getElementsByTagName('th');
	for (var column_iterate in columns) {
		if (columns[column_iterate].innerHTML == wp_cats_category_title) {
			js_wp_column_categories = column_iterate;
			break;
		}
	}
	if (js_wp_column_categories == 0) return; // bail if there's no column for categories

	for (var row_iterate = rows.length - 1; row_iterate > 0; row_iterate--) {
		wp_cats_linkify_row(rows[row_iterate]);
	}
}

//  Adds onclick handlers to the links in the popup selection box.
function wp_cats_linkify_popup(container, post_id) {
	var cat_links = container.getElementsByTagName('a');
	for (var link_iterate = cat_links.length - 1; link_iterate >= 0; link_iterate--) {
		cat_links[link_iterate].onclick = function() {
			// this is a hack to get around the texturized category names; a second list is kept
			// hidden, which contains the untexturized versions.
			var hidden_links = container.getElementsByTagName('a');
			var cat_name = '';
			for (var hidden_iterate = hidden_links.length - 1; hidden_iterate >= 0; hidden_iterate--) {
				if (hidden_links[hidden_iterate].href == this.href && hidden_links[hidden_iterate] != this) {
					cat_name = hidden_links[hidden_iterate].innerHTML;
				}
			}
			js_wp_cats_modify(post_id, cat_name, container.parentNode, 'add');
			js_wp_catbox_closeit();
			return false;
		}
	}

	return container;
}

function js_wp_cats_popup(post_id, clickedElement) {
	if ('' == js_wp_cats) {
		// first use this pageview; must fetch cat list/markup
		var xmlhttp = js_wp_cats_xmlhttp();
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4) {
				if (xmlhttp.status == 200) {
			 		js_wp_cats = '<ul>' + xmlhttp.responseText + '</ul>';
					js_wp_cats_popup(post_id, clickedElement);
				}
				else
					alert('Remote request error, please try clicking again.');
			}
		}

		var url =  ('' + window.location).split('#')[0].split('?')[0] + '?wp-cats=cats';
		xmlhttp.open("GET", url, true);
		xmlhttp.send(null);
		
		return;
	}
	
	var popupDiv = document.createElement('div');
	popupDiv.className = 'wp-cats-popup';
	popupDiv.innerHTML = js_wp_cats;
	clickedElement.appendChild(wp_cats_linkify_popup(popupDiv, post_id));
	
	var prevHandler = clickedElement.getElementsByTagName('a')[0].onclick;
	js_wp_catbox_closeit();

	js_wp_catbox_closeit = function() {
		clickedElement.removeChild(popupDiv);
		clickedElement.getElementsByTagName('a')[0].onclick = prevHandler;
		js_wp_catbox_closeit = function() {};
		return false;
	}
	
	clickedElement.getElementsByTagName('a')[0].onclick = js_wp_catbox_closeit;
}

function js_wp_cats_modify(post_id, category_name, container, addremove) {
	container.style.backgroundColor='#aaa';
	
	var xmlhttp = js_wp_cats_xmlhttp();
	var url =  ('' + window.location).split('#')[0].split('?')[0] + '?wp-cats=modify';
	xmlhttp.open("POST", url, true);
	
	xmlhttp.onreadystatechange = function() {
		if (xmlhttp.readyState == 4) {
			if (xmlhttp.status == 200) {
				var response = xmlhttp.responseText;
				var errorRegexp = /^<error>(.*)<\/error>$/;
				if (response.match(errorRegexp)) {
					var match = errorRegexp.exec(response);
					container.style.backgroundColor='';
					alert(match[1]);
					return;
				}
				container.innerHTML = response;
				container.style.backgroundColor='';
				wp_cats_linkify_row(container.parentNode);
			}
			else
			{
				container.style.backgroundColor='';
				alert('Remote request error, please try again.');
			}
		}
	}
	xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	xmlhttp.send('post_id='+post_id+'&cat_name='+category_name+'&addremove='+addremove);
}


// plundered from Jeremy Keith. Yarr.
function js_wp_cats_xmlhttp() {
	var xmlhttp = false;
	if (window.XMLHttpRequest) {
		xmlhttp = new XMLHttpRequest();
	} else if(window.ActiveXObject) {
		try {
			xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				xmlhttp = false;
			}
		}
	}
	return xmlhttp;
}


addLoadEvent(js_wp_cats_setup);

EOJS;
	}

	function css() {
		$css_extra = '';

		if (isset($_GET['foo'])) { die(var_dump($this)); }

		if ($GLOBALS['wp_cats_mozilla_columns'])
			$css_extra .= '.wp-cats-popup { height: ' . $GLOBALS['wp_cats_mozilla_column_height'] . '; -moz-column-width: 120px; padding-right: 135px; }';

		return <<<EOCSS

/* CSS for WP-Cats */

a.wp-cats-button  {
	padding: 0 3px;
	margin: 0 0 0 5px;
	background: #ccc;
	border: none;
	text-decoration: none;
}

a.wp-cats-button-plus {
	margin: 0 5px 0 0;
}
a.wp-cats-button:hover {
	background: #bbb;
}
.wp-cats-popup {
	position: absolute;
	background: white;
	border: 1px solid black;
	z-index: 10000;
	padding: 4px 0;
}

.wp-cats-popup ul {
	padding: 0;
	margin: 0;
	list-style: none;
}
.wp-cats-popup li {
	margin: 0;
	padding: 0;
	display: block;
}
.wp-cats-popup li a {
	display: block;
	font-size: 10px;
	border: 0;
	padding: 1px 7px 1px 7px;
}
.wp-cats-popup li li a { padding-left: 17px; }
.wp-cats-popup li li li a { padding-left: 27px; }
.wp-cats-popup li li li li a { padding-left: 37px; }
.wp-cats-popup li a:hover {
	background: #ddd;
}
.wp-cats-popup #wp-cats-hidden-list { display: none; }

* html .wp-cats-popup li a { display: inline; /* stupid IE */ }

$css_extra

EOCSS;
	}

}

?>
