SyntaxHighlighter. TIP: Don't use the Visual editor if you don't want your code mangled. TinyMCE will "clean up" your HTML. Author: Viper007Bond Author URI: http://www.viper007bond.com/ ************************************************************************** Thanks to: * Alex Gorbatchev for writing the Javascript-powered synatax highlighter script * Andrew Ozz for writing the TinyMCE plugin **************************************************************************/ class SyntaxHighlighter { // All of these variables are private. Filters are provided for things that can be modified. var $pluginver = '3.1.3'; // Plugin version var $agshver = false; // Alex Gorbatchev's SyntaxHighlighter version (dynamically set below due to v2 vs v3) var $shfolder = false; // Controls what subfolder to load SyntaxHighlighter from (v2 or v3) var $settings = array(); // Contains the user's settings var $defaultsettings = array(); // Contains the default settings var $brushes = array(); // Array of aliases => brushes var $shortcodes = array(); // Array of shortcodes to use var $themes = array(); // Array of themes var $usedbrushes = array(); // Stores used brushes so we know what to output var $encoded = false; // Used to mark that a character encode took place var $codeformat = false; // If set, SyntaxHighlighter::get_code_format() will return this value var $content_save_pre_ran = false; // It's possible for the "content_save_pre" filter to run multiple times, so keep track // Initalize the plugin by registering the hooks function __construct() { if ( ! function_exists( 'esc_html' ) ) return; // Load localization domain load_plugin_textdomain( 'syntaxhighlighter', false, '/syntaxhighlighter/localization' ); // Display hooks add_filter( 'the_content', array( &$this, 'parse_shortcodes' ), 7 ); // Posts add_filter( 'comment_text', array( &$this, 'parse_shortcodes_comment' ), 7 ); // Comments add_filter( 'bp_get_the_topic_post_content', array( &$this, 'parse_shortcodes' ), 7 ); // BuddyPress // Into the database add_filter( 'content_save_pre', array( &$this, 'encode_shortcode_contents_slashed_noquickedit' ), 1 ); // Posts add_filter( 'pre_comment_content', array( &$this, 'encode_shortcode_contents_slashed' ), 1 ); // Comments add_filter( 'group_forum_post_text_before_save', array( &$this, 'encode_shortcode_contents_slashed' ), 1 ); // BuddyPress add_filter( 'group_forum_topic_text_before_save', array( &$this, 'encode_shortcode_contents_slashed' ), 1 ); // BuddyPress // Out of the database for editing add_filter( 'the_editor_content', array( &$this, 'the_editor_content' ), 1 ); // Posts add_filter( 'comment_edit_pre', array( &$this, 'decode_shortcode_contents' ), 1 ); // Comments add_filter( 'bp_get_the_topic_text', array( &$this, 'decode_shortcode_contents' ), 1 ); // BuddyPress add_filter( 'bp_get_the_topic_post_edit_text', array( &$this, 'decode_shortcode_contents' ), 1 ); // BuddyPress // Outputting SyntaxHighlighter's JS and CSS add_action( 'wp_head', array( &$this, 'output_header_placeholder' ), 15 ); add_action( 'admin_head', array( &$this, 'output_header_placeholder' ), 15 ); // For comments add_action( 'wp_footer', array( &$this, 'maybe_output_scripts' ), 15 ); add_action( 'admin_footer', array( &$this, 'maybe_output_scripts' ), 15 ); // For comments // Admin hooks add_action( 'admin_init', array( &$this, 'register_setting' ) ); add_action( 'admin_menu', array( &$this, 'register_settings_page' ) ); add_action( 'admin_head', array( &$this, 'output_shortcodes_for_tinymce' ) ); add_filter( 'mce_external_plugins', array( &$this, 'add_tinymce_plugin' ) ); add_filter( 'tiny_mce_version', array( &$this, 'break_tinymce_cache' ) ); add_filter( 'save_post', array( &$this, 'mark_as_encoded' ), 10, 2 ); add_filter( 'plugin_action_links', array( &$this, 'settings_link' ), 10, 2 ); // Register widget hooks // Requires change added in WordPress 2.9 if ( class_exists('WP_Embed') ) { add_filter( 'widget_text', array( &$this, 'widget_text_output' ), 7, 2 ); add_filter( 'widget_update_callback', array( &$this, 'widget_text_save' ), 1, 4 ); add_filter( 'widget_form_callback', array( &$this, 'widget_text_form' ), 1, 2 ); } // Create array of default settings (you can use the filter to modify these) $this->defaultsettings = (array) apply_filters( 'syntaxhighlighter_defaultsettings', array( 'theme' => 'default', 'loadallbrushes' => 0, 'shversion' => 3, 'title' => '', 'autolinks' => 1, 'classname' => '', 'collapse' => 0, 'firstline' => 1, 'gutter' => 1, 'htmlscript' => 0, 'light' => 0, 'padlinenumbers' => 'false', 'smarttabs' => 1, 'tabsize' => 4, 'toolbar' => 0, 'wraplines' => 1, // 2.x only ) ); // Create the settings array by merging the user's settings and the defaults $usersettings = (array) get_option('syntaxhighlighter_settings'); $this->settings = wp_parse_args( $usersettings, $this->defaultsettings ); // Dynamically set folder and version names for SynaxHighlighter if ( 2 == $this->settings['shversion'] ) { $this->shfolder = 'syntaxhighlighter2'; $this->agshver = '2.1.364'; } else { $this->shfolder = 'syntaxhighlighter3'; $this->agshver = '3.0.83c'; } // Register brush scripts wp_register_script( 'syntaxhighlighter-core', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shCore.js'), array(), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-as3', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushAS3.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-bash', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushBash.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-coldfusion', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushColdFusion.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-cpp', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushCpp.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-csharp', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushCSharp.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-css', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushCss.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-delphi', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushDelphi.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-diff', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushDiff.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-erlang', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushErlang.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-groovy', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushGroovy.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-java', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushJava.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-javafx', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushJavaFX.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-jscript', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushJScript.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-perl', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPerl.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-php', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPhp.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-plain', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPlain.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-powershell', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPowerShell.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-python', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPython.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-ruby', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushRuby.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-scala', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushScala.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-sql', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushSql.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-vb', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushVb.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-xml', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushXml.js'), array('syntaxhighlighter-core'), $this->agshver ); // Register some popular third-party brushes wp_register_script( 'syntaxhighlighter-brush-clojure', plugins_url('syntaxhighlighter/third-party-brushes/shBrushClojure.js'), array('syntaxhighlighter-core'), '20090602' ); wp_register_script( 'syntaxhighlighter-brush-fsharp', plugins_url('syntaxhighlighter/third-party-brushes/shBrushFSharp.js'), array('syntaxhighlighter-core'), '20091003' ); wp_register_script( 'syntaxhighlighter-brush-latex', plugins_url('syntaxhighlighter/third-party-brushes/shBrushLatex.js'), array('syntaxhighlighter-core'), '20090613' ); wp_register_script( 'syntaxhighlighter-brush-matlabkey', plugins_url('syntaxhighlighter/third-party-brushes/shBrushMatlabKey.js'), array('syntaxhighlighter-core'), '20091209' ); wp_register_script( 'syntaxhighlighter-brush-objc', plugins_url('syntaxhighlighter/third-party-brushes/shBrushObjC.js'), array('syntaxhighlighter-core'), '20091207' ); wp_register_script( 'syntaxhighlighter-brush-r', plugins_url('syntaxhighlighter/third-party-brushes/shBrushR.js'), array('syntaxhighlighter-core'), '20100919' ); // Register theme stylesheets wp_register_style( 'syntaxhighlighter-core', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shCore.css'), array(), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-default', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeDefault.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-django', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeDjango.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-eclipse', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeEclipse.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-emacs', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeEmacs.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-fadetogrey', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeFadeToGrey.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-midnight', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeMidnight.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-rdark', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeRDark.css'), array('syntaxhighlighter-core'), $this->agshver ); // Create list of brush aliases and map them to their real brushes // The key is the language alias // The value is the script handle suffix: syntaxhighlighter-brush-ThisBitHere (your plugin needs to register the script itself) $this->brushes = (array) apply_filters( 'syntaxhighlighter_brushes', array( 'as3' => 'as3', 'actionscript3' => 'as3', 'bash' => 'bash', 'shell' => 'bash', 'coldfusion' => 'coldfusion', 'cf' => 'coldfusion', 'clojure' => 'clojure', 'clj' => 'clojure', 'cpp' => 'cpp', 'c' => 'cpp', 'c-sharp' => 'csharp', 'csharp' => 'csharp', 'css' => 'css', 'delphi' => 'delphi', 'pas' => 'delphi', 'pascal' => 'delphi', 'diff' => 'diff', 'patch' => 'diff', 'erl' => 'erlang', 'erlang' => 'erlang', 'fsharp' => 'fsharp', 'groovy' => 'groovy', 'java' => 'java', 'jfx' => 'javafx', 'javafx' => 'javafx', 'js' => 'jscript', 'jscript' => 'jscript', 'javascript' => 'jscript', 'latex' => 'latex', // Not used as a shortcode 'tex' => 'latex', 'matlab' => 'matlabkey', 'objc' => 'objc', 'obj-c' => 'objc', 'perl' => 'perl', 'pl' => 'perl', 'php' => 'php', 'plain' => 'plain', 'text' => 'plain', 'ps' => 'powershell', 'powershell' => 'powershell', 'py' => 'python', 'python' => 'python', 'r' => 'r', // Not used as a shortcode 'splus' => 'r', 'rails' => 'ruby', 'rb' => 'ruby', 'ror' => 'ruby', 'ruby' => 'ruby', 'scala' => 'scala', 'sql' => 'sql', 'vb' => 'vb', 'vbnet' => 'vb', 'xml' => 'xml', 'xhtml' => 'xml', 'xslt' => 'xml', 'html' => 'xml', 'xhtml' => 'xml', ) ); // Create a list of shortcodes to use. You can use the filter to add/remove ones. // If the language/lang parameter is left out, it's assumed the shortcode name is the language. // If that's invalid, then "plain" is used. $this->shortcodes = array( 'sourcecode', 'source', 'code' ); $this->shortcodes = array_merge( $this->shortcodes, array_keys( $this->brushes ) ); // Remove some shortcodes we don't want while still supporting them as language values unset( $this->shortcodes[array_search( 'latex', $this->shortcodes )] ); // Remove "latex" shortcode (it'll collide) unset( $this->shortcodes[array_search( 'r', $this->shortcodes )] ); // Remove "r" shortcode (too short) $this->shortcodes = (array) apply_filters( 'syntaxhighlighter_shortcodes', $this->shortcodes ); // Register each shortcode with a placeholder callback so that strip_shortcodes() will work // The proper callback and such is done in SyntaxHighlighter::shortcode_hack() foreach ( $this->shortcodes as $shortcode ) add_shortcode( $shortcode, '__return_true' ); // Create list of themes and their human readable names // Plugins can add to this list: http://www.viper007bond.com/wordpress-plugins/syntaxhighlighter/adding-a-new-theme/ $this->themes = (array) apply_filters( 'syntaxhighlighter_themes', array( 'default' => __( 'Default', 'syntaxhighlighter' ), 'django' => __( 'Django', 'syntaxhighlighter' ), 'eclipse' => __( 'Eclipse', 'syntaxhighlighter' ), 'emacs' => __( 'Emacs', 'syntaxhighlighter' ), 'fadetogrey' => __( 'Fade to Grey', 'syntaxhighlighter' ), 'midnight' => __( 'Midnight', 'syntaxhighlighter' ), 'rdark' => __( 'RDark', 'syntaxhighlighter' ), 'none' => __( '[None]', 'syntaxhighlighter' ), ) ); // Other special characters that need to be encoded before going into the database (namely to work around kses) $this->specialchars = (array) apply_filters( 'syntaxhighlighter_specialchars', array( '\0' => '\0', ) ); } // Register the settings page function register_settings_page() { add_options_page( __( 'SyntaxHighlighter Settings', 'syntaxhighlighter' ), __( 'SyntaxHighlighter', 'syntaxhighlighter' ), 'manage_options', 'syntaxhighlighter', array( &$this, 'settings_page' ) ); } // Register the plugin's setting function register_setting() { register_setting( 'syntaxhighlighter_settings', 'syntaxhighlighter_settings', array( &$this, 'validate_settings' ) ); } // Add the custom TinyMCE plugin which wraps plugin shortcodes in
 in TinyMCE
	function add_tinymce_plugin( $plugins ) {
		$plugins['syntaxhighlighter'] = plugins_url('syntaxhighlighter/syntaxhighlighter_mce.js');
		return $plugins;
	}


	// Break the TinyMCE cache
	function break_tinymce_cache( $version ) {
		return $version . '-sh' . $this->pluginver;
	}


	// Add a "Settings" link to the plugins page
	function settings_link( $links, $file ) {
		static $this_plugin;
		
		if( empty($this_plugin) )
			$this_plugin = plugin_basename(__FILE__);

		if ( $file == $this_plugin )
			$links[] = '' . __( 'Settings', 'syntaxhighlighter' ) . '';

		return $links;
	}


	// Output list of shortcode tags for the TinyMCE plugin
	function output_shortcodes_for_tinymce() {
		$shortcodes = array();

		foreach ( $this->shortcodes as $shortcode )
			$shortcodes[] = preg_quote( $shortcode );

		echo "\n";
	}


	// Additional CSS for the front end (to ensure themes don't screw too much with the code)
	function enforce_font_size() {
		echo '	' . "\n";
	}


	// A filter function that runs do_shortcode() but only with this plugin's shortcodes
	function shortcode_hack( $content, $callback ) {
		global $shortcode_tags;

		// Backup current registered shortcodes and clear them all out
		$orig_shortcode_tags = $shortcode_tags;
		remove_all_shortcodes();

		// Register all of this plugin's shortcodes
		foreach ( $this->shortcodes as $shortcode )
			add_shortcode( $shortcode, $callback );

		// Do the shortcodes (only this plugins's are registered)
		$content = $this->do_shortcode_keep_escaped_tags( $content );

		// Put the original shortcodes back
		$shortcode_tags = $orig_shortcode_tags;

		return $content;
	}


	// This is a clone of do_shortcode() that uses a different callback function
	// The new callback function will keep escaped tags escaped, i.e. [[foo]]
	// Up to date as of r18324 (3.2)
	function do_shortcode_keep_escaped_tags( $content ) {
		global $shortcode_tags;

		if (empty($shortcode_tags) || !is_array($shortcode_tags))
			return $content;

		$pattern = get_shortcode_regex();
		return preg_replace_callback('/'.$pattern.'/s', array( &$this, 'do_shortcode_tag_keep_escaped_tags' ), $content);
	}


	// Callback for above do_shortcode_keep_escaped_tags() function
	// It's a clone of core's do_shortcode_tag() function with a modification to the escaped shortcode return
	// Up to date as of r18324 (3.2)
	function do_shortcode_tag_keep_escaped_tags( $m ) {
		global $shortcode_tags;

		// allow [[foo]] syntax for escaping a tag
		if ( $m[1] == '[' && $m[6] == ']' ) {
			return $m[0]; // This line was modified for this plugin (no substr call)
		}

		$tag = $m[2];
		$attr = shortcode_parse_atts( $m[3] );

		if ( isset( $m[5] ) ) {
			// enclosing tag - extra parameter
			return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, $m[5], $tag ) . $m[6];
		} else {
			// self-closing tag
			return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, NULL,  $tag ) . $m[6];
		}
	}

	// The main filter for the post contents. The regular shortcode filter can't be used as it's post-wpautop().
	function parse_shortcodes( $content ) {
		return $this->shortcode_hack( $content, array( &$this, 'shortcode_callback' ) );
	}


	// HTML entity encode the contents of shortcodes
	function encode_shortcode_contents( $content ) {
		return $this->shortcode_hack( $content, array( &$this, 'encode_shortcode_contents_callback' ) );
	}


	// HTML entity encode the contents of shortcodes. Expects slashed content.
	function encode_shortcode_contents_slashed( $content ) {
		return addslashes( $this->encode_shortcode_contents( stripslashes( $content ) ) );
	}


	// HTML entity encode the contents of shortcodes. Expects slashed content. Aborts if AJAX.
	function encode_shortcode_contents_slashed_noquickedit( $content ) {

		// In certain weird circumstances, the content gets run through "content_save_pre" twice
		// Keep track and don't allow this filter to be run twice
		// I couldn't easily figure out why this happens and didn't bother looking into it further as this works fine
		if ( true == $this->content_save_pre_ran )
			return $content;
		$this->content_save_pre_ran = true;

		// Post quick edits aren't decoded for display, so we don't need to encode them (again)
		if ( !empty($_POST) && !empty($_POST['action']) && 'inline-save' == $_POST['action'] )
			return $content;

		return $this->encode_shortcode_contents_slashed( $content );
	}


	// HTML entity decode the contents of shortcodes
	function decode_shortcode_contents( $content ) {
		return $this->shortcode_hack( $content, array( &$this, 'decode_shortcode_contents_callback' ) );
	}


	// The callback function for SyntaxHighlighter::encode_shortcode_contents()
	function encode_shortcode_contents_callback( $atts, $code = '', $tag = false ) {
		$this->encoded = true;
		$code = str_replace( array_keys($this->specialchars), array_values($this->specialchars), htmlspecialchars( $code ) );
		return '[' . $tag . $this->atts2string( $atts ) . "]{$code}[/$tag]";
	}


	// The callback function for SyntaxHighlighter::decode_shortcode_contents()
	// Shortcode attribute values need to not be quoted with TinyMCE disabled for some reason (weird bug)
	function decode_shortcode_contents_callback( $atts, $code = '', $tag = false ) {
		$quotes = ( user_can_richedit() ) ? true : false;
		$code = str_replace(  array_values($this->specialchars), array_keys($this->specialchars), htmlspecialchars_decode( $code ) );
		return '[' . $tag . $this->atts2string( $atts, $quotes ) . "]{$code}[/$tag]";
	}


	// Dynamically format the post content for the edit form
	function the_editor_content( $content ) {
		global $post;

		// New code format (stored encoded in database)
		if ( 2 == $this->get_code_format( $post ) ) {
			// If TinyMCE is disabled or the HTML tab is set to be displayed first, we need to decode the HTML
			if ( !user_can_richedit() || 'html' == wp_default_editor() )
				$content = $this->decode_shortcode_contents( $content );
		}

		// Old code format (stored raw in database)
		else {
			// If TinyMCE is enabled and is set to be displayed first, we need to encode the HTML
			if ( user_can_richedit() && 'html' != wp_default_editor() )
				$content = $this->encode_shortcode_contents( $content );
		}

		return $content;
	}


	// Run SyntaxHighlighter::encode_shortcode_contents() on the contents of the text widget
	function widget_text_save( $instance, $new_instance, $old_instance, $widgetclass ) {
		if ( 'text' == $widgetclass->id_base ) {
			// Re-save the widget settings but this time with the shortcode contents encoded
			$new_instance['text'] = $this->encode_shortcode_contents( $new_instance['text'] );
			$instance = $widgetclass->update( $new_instance, $old_instance );

			// And flag it as encoded
			$instance['syntaxhighlighter_encoded'] = true;
		}

		return $instance;
	}


	// Run SyntaxHighlighter::decode_shortcode_contents_callback() on the contents of the text widget form
	function widget_text_form( $instance, $widgetclass ) {
		if ( 'text' == $widgetclass->id_base && !empty($instance['syntaxhighlighter_encoded']) ) {
			$instance['text'] = $this->shortcode_hack( $instance['text'], array( &$this, 'decode_shortcode_contents_callback' ) );
		}

		return $instance;
	}


	// Run SyntaxHighlighter::parse_shortcodes() on the contents of a text widget
	function widget_text_output( $content, $instance = false ) {
		$this->codeformat = ( false === $instance || empty($instance['syntaxhighlighter_encoded']) ) ? 1 : 2;
		$content = $this->parse_shortcodes( $content );
		$this->codeformat = false;

		return $content;
	}


	// Run SyntaxHighlighter::parse_shortcodes() on the contents of a comment
	function parse_shortcodes_comment( $content ) {
		$this->codeformat = 2;
		$content = $this->parse_shortcodes( $content );
		$this->codeformat = false;

		return $content;
	}


	// This function determines what version of SyntaxHighlighter was used when the post was written
	// This is because the code was stored differently for different versions of SyntaxHighlighter
	function get_code_format( $post ) {
		if ( false !== $this->codeformat )
			return $this->codeformat;

		if ( empty($post) )
			$post = new stdClass();

		if ( null !== $version = apply_filters( 'syntaxhighlighter_pre_getcodeformat', null, $post ) )
			return $version;

		$version = ( empty($post->ID) || get_post_meta( $post->ID, '_syntaxhighlighter_encoded', true ) || get_post_meta( $post->ID, 'syntaxhighlighter_encoded', true ) ) ? 2 : 1;

		return apply_filters( 'syntaxhighlighter_getcodeformat', $version, $post );
	}


	// Adds a post meta saying that HTML entities are encoded (for backwards compatibility)
	function mark_as_encoded( $post_ID, $post ) {
		if ( false == $this->encoded || 'revision' == $post->post_type )
			return;

		delete_post_meta( $post_ID, 'syntaxhighlighter_encoded' ); // Previously used
		add_post_meta( $post_ID, '_syntaxhighlighter_encoded', true, true );
	}


	// Transforms an attributes array into a 'key="value"' format (i.e. reverses the process)
	function atts2string( $atts, $quotes = true ) {
		if ( empty($atts) )
			return '';

		$atts = $this->attributefix( $atts );

		// Re-map [code="php"] style tags
		if ( isset($atts[0]) ) {
			if ( empty($atts['language']) )
				$atts['language'] = $atts[0];

			unset($atts[0]);
		}

		$strings = array();
		foreach ( $atts as $key => $value )
			$strings[] = ( $quotes ) ? $key . '="' . esc_attr( $value ) . '"' : $key . '=' . esc_attr( $value );

		return ' ' . implode( ' ', $strings );
	}


	// Simple function for escaping just single quotes (the original js_escape() escapes more than we need)
	function js_escape_singlequotes( $string ) {
		return str_replace( "'", "\'", $string );
	}


	// Output an anchor in the header for the Javascript to use
	// Might as well use it to output the version to help me debug people's sites
	function output_header_placeholder() {
		echo '' . "\n";
	}


	// Output any needed scripts. This is meant for the footer.
	function maybe_output_scripts() {
		global $wp_styles;

		if ( 1 == $this->settings['loadallbrushes'] )
			$this->usedbrushes = array_flip( array_values( $this->brushes ) );

		if ( empty($this->usedbrushes) )
			return;

		$scripts = array();
		foreach ( $this->usedbrushes as $brush => $unused )
			$scripts[] = 'syntaxhighlighter-brush-' . strtolower( $brush );

		wp_print_scripts( $scripts );

		// Stylesheets can't be in the footer, so inject them via Javascript
		echo "
's
	function shortcode_callback( $atts, $code = '', $tag = false ) {
		global $post;

		if ( false === $tag || empty($code) )
			return $code;

		// Avoid PHP notices
		if ( !isset($post) )
			$post = null;

		$code = apply_filters( 'syntaxhighlighter_precode', $code, $atts, $tag );

		// Error fixing for [tag="language"]
		if ( isset($atts[0]) ) {
			$atts = $this->attributefix( $atts );
			$atts['language'] = $atts[0];
			unset($atts[0]);
		}

		// Default out all of the available parameters to "false" (easy way to check if they're set or not)
		// Note this isn't the same as if the user passes the string "false" to the shortcode
		$atts = (array) apply_filters( 'syntaxhighlighter_shortcodeatts', shortcode_atts( array(
			'language'       => false,
			'lang'           => false,
			'type'           => false, // language alias
			'autolinks'      => false,
			'classname'      => false,
			'collapse'       => false,
			'firstline'      => false,
			'fontsize'       => false,
			'gutter'         => false,
			'highlight'      => false,
			'htmlscript'     => false,
			'light'          => false,
			'padlinenumbers' => false,
			'smarttabs'      => false,
			'tabsize'        => false,
			'title'          => $this->settings['title'],
			'toolbar'        => false,
			'wraplines'      => false,
		), $atts ) );

		// Check for language shortcode tag such as [php]code[/php]
		if ( isset($this->brushes[$tag]) ) {
			$lang = $tag;
		}

		// If a valid tag is not used, it must be sourcecode/source/code
		else {
			$atts = $this->attributefix( $atts );

			// Check for the "language" attribute
			if ( false !== $atts['language'] )
				$lang = $atts['language'];

			// Check for the "lang" attribute
			elseif ( false !== $atts['lang'] )
				$lang = $atts['lang'];

			// Default to plain text
			else
				$lang = 'text';

			// All language aliases are lowercase
			$lang = strtolower( $lang );

			// Validate passed attribute
			if ( !isset($this->brushes[$lang]) )
				return $code;
		}

		// Switch from the alias to the real brush name (so custom aliases can be used)
		$lang = $this->brushes[$lang];

		// Register this brush as used so it's script will be outputted
		$this->usedbrushes[$lang] = true;

		$params = array();
		$params[] = "brush: $lang;";

		// Fix bug that prevents collapse from working if the toolbar is off or light mode is on
		if ( 'true' == $atts['collapse'] || '1' === $atts['collapse'] || 1 == $this->settings['collapse'] ) {
			$atts['toolbar'] = 'true';
			$atts['light'] = 'false';
		}

		// Parameter renaming (the shortcode API doesn't like parameter names with dashes)
		$rename_map = array(
			'autolinks'      => 'auto-links',
			'classname'      => 'class-name',
			'firstline'      => 'first-line',
			'fontsize'       => 'font-size',
			'htmlscript'     => 'html-script',
			'padlinenumbers' => 'pad-line-numbers',
			'smarttabs'      => 'smart-tabs',
			'tabsize'        => 'tab-size',
			'wraplines'      => 'wrap-lines',
		);

		// Allowed configuration parameters and their type
		// Use the proper names (see above)
		$allowed_atts = (array) apply_filters( 'syntaxhighlighter_allowedatts', array(
			'auto-links'       => 'boolean',
			'class-name'       => 'other',
			'collapse'         => 'boolean',
			'first-line'       => 'integer',
			'font-size'        => 'integer',
			'gutter'           => 'boolean',
			'highlight'        => 'other',
			'html-script'      => 'boolean',
			'light'            => 'boolean',
			'pad-line-numbers' => 'other',
			'smart-tabs'       => 'boolean',
			'tab-size'         => 'integer',
			'title'            => 'other',
			'toolbar'          => 'boolean',
			'wrap-lines'       => 'boolean',
		) );

		$title = '';

		// Sanitize configuration parameters and such
		foreach ( $atts as $key => $value ) {
			$key = strtolower( $key );

			// Put back parameter names that have been renamed for shortcode use
			if ( !empty($rename_map[$key]) )
				$key = $rename_map[$key];

			// This this parameter if it's unknown, not set, or the language which was already handled
			if ( empty($allowed_atts[$key]) || false === $value || in_array( $key, array( 'language', 'lang' ) ) )
				continue;

			// Sanitize values
			switch ( $allowed_atts[$key] ) {
				case 'boolean':
					$value = strtolower( $value );
					if ( 'true' === $value || '1' === $value || 'on' == $value )
						$value = 'true';
					elseif ( 'false' === $value || '0' === $value || 'off' == $value )
						$value = 'false';
					else
						continue 2; // Invalid value, ditch parameter
					break;

				// integer
				case 'integer':
					$value = (int) $value;
					break;
			}

			// Sanitize the "classname" parameter
			if ( 'classname' == $key )
				$value = trim( preg_replace( '/[^a-zA-Z0-9 _-]/i', '', $value ) );

			// Special sanitization for "pad-line-numbers"
			if ( 'pad-line-numbers' == $key ) {
				$value = strtolower( $value );
				if ( 'true' === $value || '1' === $value )
					$value = 'true';
				elseif ( 'false' === $value || '0' === $value )
					$value = 'false';
				else
					$value = (int) $value;
			}

			// Add % sign to "font-size"
			if ( 'font-size' == $key )
				$value = $value . '%';

			// If "html-script", then include the XML brush as it's needed
			if ( 'html-script' == $key && 'true' == $value )
				$this->usedbrushes['xml'] = true;

			// Sanitize row highlights
			if ( 'highlight' == $key ) {
				if ( false === strpos( $value, ',' ) ) {
					$value = (int) $value;
				} else {
					$lines = explode( ',', $value );
					$highlights = array();

					foreach ( $lines as $line ) {
						// Line range
						if ( false !== strpos( $line, '-' ) ) {
							list( $range_start, $range_end ) = array_map( 'intval', explode( '-', $line ) );
							if ( ! $range_start || ! $range_end || $range_end <= $range_start )
								continue;

							for ( $i = $range_start; $i <= $range_end; $i++ )
								$highlights[] = $i;
						} else {
							$highlights[] = (int) $line;
						}
					}

					natsort( $highlights );

					$value = implode( ',', $highlights );
				}

				if ( empty( $value ) )
					continue;

				// Wrap highlight in [ ]
				$params[] = "$key: [$value];";
				continue;
			}

			$params[] = "$key: $value;";

			// Set the title variable if the title parameter is set (but not for feeds)
			if ( 'title' == $key && ! is_feed() )
				$title = ' title="' . esc_attr( $value ) . '"';
		}

		$code = ( false === strpos( $code, '<' ) && false === strpos( $code, '>' ) && 2 == $this->get_code_format($post) ) ? strip_tags( $code ) : htmlspecialchars( $code );

		$params[] = 'notranslate'; // For Google, see http://otto42.com/9k

		$params = apply_filters( 'syntaxhighlighter_cssclasses', $params ); // Use this to add additional CSS classes / SH parameters

		return apply_filters( 'syntaxhighlighter_htmlresult', '
' . $code . '
' );; } // Settings page function settings_page() { ?>











' . "\n"; echo '' . "\n"; } ?>

'; $title = ( empty( $this->settings['title'] ) && 1 != $this->settings['collapse'] ) ? ' title="Code example: (this example was added using the title parameter)"' : ''; // Site owners may opt to disable the short tags, i.e. [php] $democode = apply_filters( 'syntaxhighlighter_democode', '[sourcecode language="php" htmlscript="true" highlight="12"' . $title . '] PHP Code Example

' . __( 'PHP Code Example', 'syntaxhighlighter' ) . '

' . __( 'This line is highlighted.', 'syntaxhighlighter' ) . '

' . __( ' This is an example of smart tabs.', 'syntaxhighlighter' ) . '

' . __( 'WordPress' ) . '

[/sourcecode]' ); $this->codeformat = 1; echo $this->parse_shortcodes( $democode ); $this->codeformat = false; echo '
'; ?>

true', '1', 'false', '0' ); ?>

maybe_output_scripts(); ?> defaultsettings; $_REQUEST['_wp_http_referer'] = add_query_arg( 'defaults', 'true', $_REQUEST['_wp_http_referer'] ); } else { $settings['shversion'] = ( ! empty($settings['shversion']) && 2 == $settings['shversion'] ) ? 2 : 3; $settings['theme'] = ( ! empty($settings['theme']) && isset($this->themes[$settings['theme']]) ) ? strtolower($settings['theme']) : $this->defaultsettings['theme']; $settings['loadallbrushes'] = ( ! empty($settings['loadallbrushes']) ) ? 1 : 0; $settings['autolinks'] = ( ! empty($settings['autolinks']) ) ? 1 : 0; $settings['collapse'] = ( ! empty($settings['collapse']) ) ? 1 : 0; $settings['gutter'] = ( ! empty($settings['gutter']) ) ? 1 : 0; $settings['light'] = ( ! empty($settings['light']) ) ? 1 : 0; $settings['smarttabs'] = ( ! empty($settings['smarttabs']) ) ? 1 : 0; $settings['toolbar'] = ( ! empty($settings['toolbar']) ) ? 1 : 0; // May be overridden below $settings['wraplines'] = ( ! empty($settings['wraplines']) ) ? 1 : 0; // 2.x only for now // If the version changed, then force change the toolbar version setting if ( $settings['shversion'] != $this->settings['shversion'] ) { $settings['toolbar'] = ( 2 == $settings['shversion'] ) ? 1 : 0; } if ( 'true' != $settings['padlinenumbers'] && 'false' != $settings['padlinenumbers'] ) $settings['padlinenumbers'] = (int) $settings['padlinenumbers']; $settings['classname'] = ( !empty($settings['classname']) ) ? preg_replace( '/[^ A-Za-z0-9_-]*/', '', $settings['classname'] ) : ''; $settings['firstline'] = (int) ( !empty($settings['firstline']) ) ? $settings['firstline'] : $this->defaultsettings['firstline']; $settings['tabsize'] = (int) ( !empty($settings['tabsize']) ) ? $settings['tabsize'] : $this->defaultsettings['tabsize']; } return $settings; } // PHP4 compatibility function SyntaxHighlighter() { $this->__construct(); } } // Start this plugin once all other plugins are fully loaded add_action( 'init', 'SyntaxHighlighter', 5 ); function SyntaxHighlighter() { global $SyntaxHighlighter; $SyntaxHighlighter = new SyntaxHighlighter(); } ?>