Skip to:
Content

bbPress.org

Changeset 2789


Ignore:
Timestamp:
01/09/2011 10:06:53 PM (16 years ago)
Author:
johnjamesjacoby
Message:

Introduce views API into plugin. Allows for creating specific topic views with code rather than with templates. The 'no-replies' view is included as default. Props GautamGupta via Google Code-in

Location:
branches/plugin
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • branches/plugin/bbp-admin/bbp-admin.php

    r2787 r2789  
    224224                add_settings_field( '_bbp_user_slug',       __( 'User base',     'bbpress' ), 'bbp_admin_setting_callback_user_slug',       'bbpress', 'bbp_slugs' );
    225225                register_setting  ( 'bbpress',              '_bbp_user_slug',                 'sanitize_title'                                                     );
     226
     227                // View slug setting
     228                add_settings_field( '_bbp_view_slug',       __( 'View base',     'bbpress' ), 'bbp_admin_setting_callback_view_slug',       'bbpress', 'bbp_slugs' );
     229                register_setting  ( 'bbpress',              '_bbp_view_slug',                 'sanitize_title'                                                     );
    226230
    227231                // Forum slug setting
  • branches/plugin/bbp-admin/bbp-settings.php

    r2787 r2789  
    207207
    208208                        <input name="_bbp_user_slug" type="text" id="_bbp_user_slug" value="<?php form_option( '_bbp_user_slug' ); ?>" />
     209
     210<?php
     211}
     212
     213/**
     214 * View slug setting field
     215 *
     216 * @since bbPress (r2789)
     217 *
     218 * @uses form_option() To output the option value
     219 */
     220function bbp_admin_setting_callback_view_slug() {
     221?>
     222
     223                        <input name="_bbp_view_slug" type="text" id="_bbp_view_slug" value="<?php form_option( '_bbp_view_slug' ); ?>" />
    209224
    210225<?php
  • branches/plugin/bbp-includes/bbp-functions.php

    r2788 r2789  
    275275
    276276        return $reason;
     277}
     278
     279/** Views *********************************************************************/
     280
     281/**
     282 * Get the registered views
     283 *
     284 * Does nothing much other than return the {@link $bbp->views} variable
     285 *
     286 * @since bbPress (r2789)
     287 *
     288 * @return array Views
     289 */
     290function bbp_get_views() {
     291        global $bbp;
     292
     293        return $bbp->views;
     294}
     295
     296/**
     297 * Register a bbPress view
     298 *
     299 * @todo Implement feeds - See {@link http://trac.bbpress.org/ticket/1422}
     300 *
     301 * @since bbPress (r2789)
     302 *
     303 * @param string $view View name
     304 * @param string $title View title
     305 * @param mixed $query_args {@link bbp_has_topics()} arguments.
     306 * @param bool $feed Have a feed for the view? Defaults to true. NOT IMPLEMENTED
     307 * @uses sanitize_title() To sanitize the view name
     308 * @uses esc_html() To sanitize the view title
     309 * @return array The just registered (but processed) view
     310 */
     311function bbp_register_view( $view, $title, $query_args = '', $feed = true ) {
     312        global $bbp;
     313
     314        $view  = sanitize_title( $view );
     315        $title = esc_html( $title );
     316
     317        if ( empty( $view ) || empty( $title ) )
     318                return false;
     319
     320        $query_args = wp_parse_args( $query_args );
     321
     322        // Set ignore_sticky_topics to true if it wasn't supplied
     323        if ( !isset( $query_args['ignore_sticky_topics'] ) )
     324                $query_args['ignore_sticky_topics'] = true;
     325
     326        $bbp->views[$view]['title'] = $title;
     327        $bbp->views[$view]['query'] = $query_args;
     328        $bbp->views[$view]['feed']  = $feed;
     329
     330        return $bbp->views[$view];
     331}
     332
     333/**
     334 * Deregister a bbPress view
     335 *
     336 * @since bbPress (r2789)
     337 *
     338 * @param string $view View name
     339 * @uses sanitize_title() To sanitize the view name
     340 * @return bool False if the view doesn't exist, true on success
     341 */
     342function bbp_deregister_view( $view ) {
     343        global $bbp;
     344
     345        $view = sanitize_title( $view );
     346
     347        if ( !isset( $bbp->views[$view] ) )
     348                return false;
     349
     350        unset( $bbp->views[$view] );
     351
     352        return true;
     353}
     354
     355/**
     356 * Run the view's query
     357 *
     358 * @since bbPress (r2789)
     359 *
     360 * @param string $view Optional. View id
     361 * @param mixed $new_args New arguments. See {@link bbp_has_topics()}
     362 * @uses bbp_get_view_id() To get the view id
     363 * @uses bbp_get_view_query_args() To get the view query args
     364 * @uses sanitize_title() To sanitize the view name
     365 * @uses bbp_has_topics() To make the topics query
     366 * @return bool False if the view doesn't exist, otherwise if topics are there
     367 */
     368function bbp_view_query( $view = '', $new_args = '' ) {
     369        global $bbp;
     370
     371        if ( !$view = bbp_get_view_id( $view ) )
     372                return false;
     373
     374        $query_args = bbp_get_view_query_args( $view );
     375
     376        if ( !empty( $new_args ) ) {
     377                $new_args   = wp_parse_args( $new_args );
     378                $query_args = array_merge( $query_args, $new_args );
     379        }
     380
     381        return bbp_has_topics( $query_args );
     382}
     383
     384/**
     385 * Run the view's query's arguments
     386 *
     387 * @since bbPress (r2789)
     388 *
     389 * @param string $view View name
     390 * @uses bbp_get_view_id() To get the view id
     391 * @uses sanitize_title() To sanitize the view name
     392 * @return array Query arguments
     393 */
     394function bbp_get_view_query_args( $view ) {
     395        global $bbp;
     396
     397        if ( !$views = bbp_get_view_id( $view ) )
     398                return false;
     399
     400        return $bbp->views[$view]['query'];
    277401}
    278402
    … …  
    18581982 * Load bbPress custom templates
    18591983 *
    1860  * Loads custom templates for bbPress user profile, user edit, topic edit and
    1861  * reply edit pages.
     1984 * Loads custom templates for bbPress view page, user profile, user edit, topic
     1985 * edit and reply edit pages.
    18621986 *
    18631987 * @since bbPress (r2753)
    … …  
    18832007                $template = array( 'user-edit.php', 'user.php', 'author.php', 'index.php' );
    18842008
     2009        // View page
     2010        } elseif ( bbp_is_view() ) {
     2011                $template = array( 'view-' . bbp_get_view_id(), 'view.php', 'index.php' );
     2012
    18852013        // Editing a topic
    18862014        } elseif ( bbp_is_topic_edit() ) {
    … …  
    19032031
    19042032/**
    1905  * Add checks for user page, user edit, topic edit and reply edit pages.
     2033 * Add checks for view page, user page, user edit, topic edit and reply edit
     2034 * pages.
    19062035 *
    19072036 * If it's a user page, WP_Query::bbp_is_user_profile_page is set to true.
    … …  
    19142043 * If it's a topic edit, WP_Query::bbp_is_topic_edit is set to true and
    19152044 * similarly, if it's a reply edit, WP_Query::bbp_is_reply_edit is set to true.
     2045 *
     2046 * If it's a view page, WP_Query::bbp_is_view is set to true
    19162047 *
    19172048 * @since bbPress (r2688)
    … …  
    19292060
    19302061        $bbp_user = get_query_var( 'bbp_user' );
     2062        $bbp_view = get_query_var( 'bbp_view' );
    19312063        $is_edit  = get_query_var( 'edit'     );
    19322064
     2065        // Profile page
    19332066        if ( !empty( $bbp_user ) ) {
    19342067
    … …  
    19722105                // Set the displayed user global to this user
    19732106                $bbp->displayed_user = $user;
     2107
     2108        // View Page
     2109        } elseif ( !empty( $bbp_view ) ) {
     2110
     2111                // Check if the view exists by checking if there are query args are set or not
     2112                $view_args = bbp_get_view_query_args( $bbp_view );
     2113
     2114                // Stop if view args is false - means the view isn't registered
     2115                if ( false === $view_args ) {
     2116                        $wp_query->set_404();
     2117                        return;
     2118                }
     2119
     2120                $wp_query->bbp_is_view = true;
     2121
     2122        // Topic/Reply Edit Page
    19742123        } elseif ( !empty( $is_edit ) ) {
    19752124
    … …  
    20462195                $title = bbp_get_reply_title();
    20472196
     2197        // Topic tag page
    20482198        } elseif ( is_tax( $bbp->topic_tag_id ) ) {
    20492199
    20502200                $term  = get_queried_object();
    20512201                $title = sprintf( __( 'Topic Tag: %s', 'bbpress' ), $term->name );
     2202
     2203        // Views
     2204        } elseif ( bbp_is_view() ) {
     2205
     2206                $title = sprintf( __( 'View: %s', 'bbpress' ), bbp_get_view_title() );
    20522207
    20532208        }
  • branches/plugin/bbp-includes/bbp-general-template.php

    r2782 r2789  
    297297
    298298        if ( !empty( $wp_query->bbp_is_user_profile_edit ) && $wp_query->bbp_is_user_profile_edit == true )
     299                return true;
     300
     301        return false;
     302}
     303
     304/**
     305 * Check if current page is a view page
     306 *
     307 * @since bbPress (r2789)
     308 *
     309 * @uses WP_Query Checks if WP_Query::bbp_is_view is true
     310 * @return bool Is it a view page?
     311 */
     312function bbp_is_view() {
     313        global $wp_query;
     314
     315        if ( !empty( $wp_query->bbp_is_view ) && $wp_query->bbp_is_view == true )
    299316                return true;
    300317
    … …  
    597614/** END Form Functions ********************************************************/
    598615
     616/** Start Views ***************************************************************/
     617
     618/**
     619 * Output the view id
     620 *
     621 * @since bbPress (r2789)
     622 *
     623 * @param string $view Optional. View id
     624 * @uses bbp_get_view_id() To get the view id
     625 */
     626function bbp_view_id( $view = '' ) {
     627        echo bbp_get_view_id( $view );
     628}
     629
     630        /**
     631         * Get the view id
     632         *
     633         * If a view id is supplied, that is used. Otherwise the 'bbp_view'
     634         * query var is checked for.
     635         *
     636         * @since bbPress (r2789)
     637         *
     638         * @param string $view Optional. View id.
     639         * @uses sanitize_title() To sanitize the view id
     640         * @uses get_query_var() To get the view id from query var 'bbp_view'
     641         * @return bool|string ID on success, false on failure
     642         */
     643        function bbp_get_view_id( $view = '' ) {
     644                global $bbp;
     645
     646                $view = !empty( $view ) ? sanitize_title( $view ) : get_query_var( 'bbp_view' );
     647
     648                if ( array_key_exists( $view, $bbp->views ) )
     649                        return $view;
     650
     651                return false;
     652        }
     653
     654/**
     655 * Output the view name aka title
     656 *
     657 * @since bbPress (r2789)
     658 *
     659 * @param string $view Optional. View id
     660 * @uses bbp_get_view_title() To get the view title
     661 */
     662function bbp_view_title( $view = '' ) {
     663        echo bbp_get_view_title( $view );
     664}
     665
     666        /**
     667         * Get the view name aka title
     668         *
     669         * If a view id is supplied, that is used. Otherwise the bbp_view
     670         * query var is checked for.
     671         *
     672         * @since bbPress (r2789)
     673         *
     674         * @param string $view Optional. View id
     675         * @uses bbp_get_view_id() To get the view id
     676         * @return bool|string Title on success, false on failure
     677         */
     678        function bbp_get_view_title( $view = '' ) {
     679                global $bbp;
     680
     681                if ( !$view = bbp_get_view_id( $view ) )
     682                        return false;
     683
     684                return $bbp->views[$view]['title'];
     685        }
     686
     687/**
     688 * Output the view url
     689 *
     690 * @since bbPress (r2789)
     691 *
     692 * @param string $view Optional. View id
     693 * @uses bbp_get_view_url() To get the view url
     694 */
     695function bbp_view_url( $view = false ) {
     696        echo bbp_get_view_url( $view );
     697}
     698        /**
     699         * Return the view url
     700         *
     701         * @since bbPress (r2789)
     702         *
     703         * @param string $view Optional. View id
     704         * @uses sanitize_title() To sanitize the view id
     705         * @uses home_url() To get blog home url
     706         * @uses add_query_arg() To add custom args to the url
     707         * @uses apply_filters() Calls 'bbp_get_view_url' with the view url,
     708         *                        used view id
     709         * @return string View url (or home url if the view was not found)
     710         */
     711        function bbp_get_view_url( $view = false ) {
     712                global $bbp, $wp_rewrite;
     713
     714                if ( !$view = bbp_get_view_id( $view ) )
     715                        return home_url();
     716
     717                if ( !empty( $wp_rewrite->permalink_structure ) ) {
     718                        $url = $wp_rewrite->front . $bbp->view_slug . '/' . $view;
     719                        $url = home_url( user_trailingslashit( $url ) );
     720                } else {
     721                        $url = add_query_arg( array( 'bbp_view' => $view ), home_url( '/' ) );
     722                }
     723
     724                return apply_filters( 'bbp_get_view_link', $url, $view );
     725        }
     726
     727/** End Views *****************************************************************/
     728
    599729/** Start General Functions ***************************************************/
    600730
    … …  
    712842                return apply_filters( 'bbp_get_breadcrumb', $trail . get_the_title() );
    713843        }
    714        
     844
    715845/**
    716846 * Output all of the allowed tags in HTML format with attributes.
    … …  
    721851 * @since bbPress (r2780)
    722852 *
    723  * @uses bbp_get_allowed_tags() 
     853 * @uses bbp_get_allowed_tags()
    724854 */
    725855function bbp_allowed_tags() {
  • branches/plugin/bbp-includes/bbp-hooks.php

    r2788 r2789  
    5959add_action( 'bbp_init', 'bbp_register_textdomain',    10  );
    6060add_action( 'bbp_init', 'bbp_add_rewrite_tags',       12  );
     61add_action( 'bbp_init', 'bbp_register_views',         14  );
    6162add_action( 'bbp_init', 'bbp_ready',                  999 );
    6263
  • branches/plugin/bbp-includes/bbp-loader.php

    r2753 r2789  
    145145
    146146/**
     147 * Register the default bbPress views
     148 *
     149 * @since bbPress (r2789)
     150 *
     151 * @uses do_action() Calls 'bbp_register_views'
     152 */
     153function bbp_register_views() {
     154        do_action ( 'bbp_register_views' );
     155}
     156
     157/**
    147158 * Add the bbPress-specific rewrite tags
    148159 *
  • branches/plugin/bbp-includes/bbp-options.php

    r2787 r2789  
    5757                '_bbp_user_slug'            => 'users',
    5858
     59                // View slug
     60                '_bbp_view_slug'            => 'view',
     61
    5962                // Forum slug
    6063                '_bbp_forum_slug'           => 'forum',
  • branches/plugin/bbp-includes/bbp-topic-template.php

    r2788 r2789  
    7373        if ( empty( $default['post_parent'] ) ) {
    7474                unset( $default['post_parent'] );
    75                 if ( !bbp_is_user_profile_page() && !bbp_is_user_profile_edit() )
     75                if ( !bbp_is_user_profile_page() && !bbp_is_user_profile_edit() && !bbp_is_view() )
    7676                        $post_parent = get_the_ID();
    7777        }
    … …  
    167167
    168168                // If pretty permalinks are enabled, make our pagination pretty
    169                 if ( $wp_rewrite->using_permalinks() && bbp_is_user_profile_page() )
    170                         $base = $base = user_trailingslashit( trailingslashit( bbp_get_user_profile_url( bbp_get_displayed_user_id() ) ) . 'page/%#%/' );
    171                 elseif ( $wp_rewrite->using_permalinks() )
    172                         $base = user_trailingslashit( trailingslashit( get_permalink( $post_parent ) ) . 'page/%#%/' );
    173                 else
     169                if ( $wp_rewrite->using_permalinks() ) {
     170                        if ( bbp_is_user_profile_page() )
     171                                $base = user_trailingslashit( trailingslashit( bbp_get_user_profile_url( bbp_get_displayed_user_id() ) ) . 'page/%#%/' );
     172                        elseif ( bbp_is_view() )
     173                                $base = user_trailingslashit( trailingslashit( bbp_get_view_url() ) . 'page/%#%/' );
     174                        else
     175                                $base = user_trailingslashit( trailingslashit( get_permalink( $post_parent ) ) . 'page/%#%/' );
     176                } else {
    174177                        $base = add_query_arg( 'paged', '%#%' );
     178                }
    175179
    176180
  • branches/plugin/bbpress.php

    r2786 r2789  
    11<?php
     2/**
     3 * The bbPress Plugin
     4 *
     5 * bbPress is forum software with a twist from the creators of WordPress.
     6 *
     7 * @package bbPress
     8 * @subpackage Main
     9 */
     10
    211/**
    312 * Plugin Name: bbPress
    … …  
    1019
    1120/**
    12  * The bbPress Plugin
    13  *
    14  * bbPress is forum software with a twist from the creators of WordPress.
    15  *
    16  * @package bbPress
    17  * @subpackage Main
    18  */
    19 /**
    2021 * bbPress vesion
    2122 *
    … …  
    103104        var $user_slug;
    104105
     106        /**
     107         * @var string View slug
     108         */
     109        var $view_slug;
     110
    105111        // Absolute Paths
    106112
    … …  
    191197         */
    192198        var $errors;
     199
     200        // Views
     201
     202        /**
     203         * @var array An array of registered bbPress views
     204         */
     205        var $views;
    193206
    194207        /**
    … …  
    222235
    223236                // bbPress root directory
    224                 $this->file              = __FILE__;
    225                 $this->plugin_dir        = plugin_dir_path( $this->file );
    226                 $this->plugin_url        = plugin_dir_url ( $this->file );
     237                $this->file             = __FILE__;
     238                $this->plugin_dir       = plugin_dir_path( $this->file );
     239                $this->plugin_url       = plugin_dir_url ( $this->file );
    227240
    228241                // Images
    229                 $this->images_url        = $this->plugin_url . 'bbp-images';
     242                $this->images_url       = $this->plugin_url . 'bbp-images';
    230243
    231244                // Themes
    232                 $this->themes_dir        = WP_PLUGIN_DIR . '/' . basename( dirname( __FILE__ ) ) . '/bbp-themes';
    233                 $this->themes_url        = $this->plugin_url . 'bbp-themes';
     245                $this->themes_dir       = WP_PLUGIN_DIR . '/' . basename( dirname( __FILE__ ) ) . '/bbp-themes';
     246                $this->themes_url       = $this->plugin_url . 'bbp-themes';
    234247
    235248                /** Identifiers ***********************************************/
    236249
    237250                // Post type identifiers
    238                 $this->forum_id           = apply_filters( 'bbp_forum_post_type',  'bbp_forum'     );
    239                 $this->topic_id           = apply_filters( 'bbp_topic_post_type',  'bbp_topic'     );
    240                 $this->reply_id           = apply_filters( 'bbp_reply_post_type',  'bbp_reply'     );
    241                 $this->topic_tag_id       = apply_filters( 'bbp_topic_tag_id',     'bbp_topic_tag' );
     251                $this->forum_id         = apply_filters( 'bbp_forum_post_type',  'bbp_forum'     );
     252                $this->topic_id         = apply_filters( 'bbp_topic_post_type',  'bbp_topic'     );
     253                $this->reply_id         = apply_filters( 'bbp_reply_post_type',  'bbp_reply'     );
     254                $this->topic_tag_id     = apply_filters( 'bbp_topic_tag_id',     'bbp_topic_tag' );
    242255
    243256                // Status identifiers
    … …  
    249262
    250263                // Root forum slug
    251                 $this->root_slug          = apply_filters( 'bbp_root_slug',      get_option( '_bbp_root_slug', 'forums' ) );
     264                $this->root_slug        = apply_filters( 'bbp_root_slug',      get_option( '_bbp_root_slug', 'forums' ) );
    252265
    253266                // Should we include the root slug in front of component slugs
    … …  
    255268
    256269                // Component slugs
    257                 $this->user_slug          = apply_filters( 'bbp_user_slug',      get_option( '_bbp_user_slug',      $prefix . 'user'  ) );
    258                 $this->forum_slug         = apply_filters( 'bbp_forum_slug',     get_option( '_bbp_forum_slug',     $prefix . 'forum' ) );
    259                 $this->topic_slug         = apply_filters( 'bbp_topic_slug',     get_option( '_bbp_topic_slug',     $prefix . 'topic' ) );
    260                 $this->reply_slug         = apply_filters( 'bbp_reply_slug',     get_option( '_bbp_reply_slug',     $prefix . 'reply' ) );
    261                 $this->topic_tag_slug     = apply_filters( 'bbp_topic_tag_slug', get_option( '_bbp_topic_tag_slug', $prefix . 'tag'   ) );
     270                $this->user_slug        = apply_filters( 'bbp_user_slug',      $prefix . get_option( '_bbp_user_slug',      'user'  ) );
     271                $this->view_slug        = apply_filters( 'bbp_view_slug',      $prefix . get_option( '_bbp_view_slug',      'view'  ) );
     272                $this->forum_slug       = apply_filters( 'bbp_forum_slug',     $prefix . get_option( '_bbp_forum_slug',     'forum' ) );
     273                $this->topic_slug       = apply_filters( 'bbp_topic_slug',     $prefix . get_option( '_bbp_topic_slug',     'topic' ) );
     274                $this->reply_slug       = apply_filters( 'bbp_reply_slug',     $prefix . get_option( '_bbp_reply_slug',     'reply' ) );
     275                $this->topic_tag_slug   = apply_filters( 'bbp_topic_tag_slug', $prefix . get_option( '_bbp_topic_tag_slug', 'tag'   ) );
    262276
    263277                /** Misc ******************************************************/
    … …  
    265279                // Errors
    266280                $this->errors = new WP_Error();
     281
     282                // Views
     283                $this->views  = array();
    267284        }
    268285
    … …  
    326343                add_action( 'bbp_register_taxonomies',      array( $this, 'register_taxonomies'      ), 10, 2 );
    327344
    328                 // Register theme directory
     345                // Register the views
     346                add_action( 'bbp_register_views',           array( $this, 'register_views'           ), 10, 2 );
     347
     348                // Register the theme directory
    329349                add_action( 'bbp_register_theme_directory', array( $this, 'register_theme_directory' ), 10, 2 );
    330350
    … …  
    651671
    652672        /**
     673         * Register the bbPress views
     674         *
     675         * @since bbPress (r2789)
     676         *
     677         * @uses bbp_register_view() To register the views
     678         */
     679        function register_views() {
     680
     681                // Topics with no replies
     682                $no_replies = apply_filters( 'bbp_register_view_no_replies', array(
     683                        'meta_key'     => '_bbp_topic_reply_count',
     684                        'meta_value'   => 1,
     685                        'meta_compare' => '<',
     686                        'orderby'      => ''
     687                ) );
     688
     689                bbp_register_view( 'no-replies', __( 'Topics with no replies', 'bbpress' ), $no_replies );
     690
     691        }
     692
     693        /**
    653694         * Setup the currently logged-in user
    654695         *
    … …  
    679720                // User Profile tag
    680721                add_rewrite_tag( '%bbp_user%', '([^/]+)'   );
     722
     723                // View Page tag
     724                add_rewrite_tag( '%bbp_view%', '([^/]+)'   );
    681725
    682726                // Edit Page tag
    … …  
    705749                        // Profile Page
    706750                        $this->user_slug . '/([^/]+)/page/?([0-9]{1,})/?$' => 'index.php?bbp_user=' . $wp_rewrite->preg_index( 1 ) . '&paged=' . $wp_rewrite->preg_index( 2 ),
    707                         $this->user_slug . '/([^/]+)/?$'                   => 'index.php?bbp_user=' . $wp_rewrite->preg_index( 1 )
     751                        $this->user_slug . '/([^/]+)/?$'                   => 'index.php?bbp_user=' . $wp_rewrite->preg_index( 1 ),
     752
     753                        // @todo - view feeds
     754                        //$this->view_slug . '/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?bbp_view=' . $wp_rewrite->preg_index( 1 ) . '&feed='  . $wp_rewrite->preg_index( 2 ),
     755
     756                        // View Page
     757                        $this->view_slug . '/([^/]+)/page/?([0-9]{1,})/?$' => 'index.php?bbp_view=' . $wp_rewrite->preg_index( 1 ) . '&paged=' . $wp_rewrite->preg_index( 2 ),
     758                        $this->view_slug . '/([^/]+)/?$'                   => 'index.php?bbp_view=' . $wp_rewrite->preg_index( 1 )
    708759                );
    709760
Note: See TracChangeset for help on using the changeset viewer.