3 Plugin Name: WebKit Table of Contents
4 Plugin URI: http://webkit.org
5 Description: Builds a table of contents with navigation anchors from headings
10 WebKitTableOfContents::init();
12 class WebKitTableOfContents {
14 private static $editing = false;
15 private static $toc = array();
16 private static $attr_regex = '\{((?:[ ]*[#.][-_:a-zA-Z0-9]+){1,})[ ]*\}';
18 public function init() {
19 add_filter( 'wp_insert_post_data', array( 'WebKitTableOfContents', 'wp_insert_post_data' ), 20, 2 );
20 add_action( 'wp_insert_post', array( 'WebKitTableOfContents', 'wp_insert_post' ) );
23 public static function hasIndex() {
24 $toc = get_post_meta( get_the_ID(), 'toc', true );
25 array_walk($toc, array('WebKitTableOfContents', 'filterIndex'));
26 return ( ! empty(self::$toc) && count(self::$toc) > 2 );
29 public static function filterIndex($value, $key) {
30 list($level, $anchor) = explode('::', $key);
31 if ( $level < 3 ) self::$toc[ $key ] = $value;
34 public static function renderMarkup() {
35 if ( ! is_page() ) return;
37 if ( empty(self::$toc) || ! self::hasIndex() )
42 $markup = '<input type="checkbox" id="table-of-contents-toggle" class="menu-toggle"><menu class="table-of-contents"><menuitem class="list"><h6><label for="table-of-contents-toggle">Contents</label></h6>';
44 foreach ( self::$toc as $name => $heading ) {
45 list($level, $anchor) = explode('::', $name);
46 if ( empty($level) || $level > 3 ) continue;
48 if ( $level < $depth ) {
49 $markup .= str_repeat('</ul></li>', $depth - $level);
51 } elseif ( $level == $depth )
56 if ( $level > $depth ) {
57 $markup .= '<ul class="level-' . $level . '">';
62 $markup .= sprintf('<li><a href="#%s">%s</a>', $anchor, $heading);
65 $markup .= '</ul></menuitem></menu>';
70 public static function markup() {
71 echo self::renderMarkup();
74 public function wp_insert_post_data( $post_data, $record ) {
76 if ( ! in_array($post_data['post_type'], array('page')) )
79 $post_data['post_content'] = self::parse($post_data['post_content']);
81 self::$editing = isset( $record['ID'] ) ? $record['ID'] : false;
86 public static function wp_insert_post( $post_id ) {
87 if ( empty(self::$toc) ) return;
88 if ( self::$editing && self::$editing != $post_id ) return;
89 update_post_meta($post_id, 'toc', self::$toc);
92 public static function parse( $content ) {
93 $markup = preg_replace_callback('{
94 ^<h([1-6])[^>]*>(.+?)<\/h[1-6]>* # HTML tags
96 array('WebKitTableOfContents', 'index'),
103 public static function index( $matches ) {
104 list($marked, $level, $heading) = $matches;
105 $anchor = sanitize_title_with_dashes($heading);
106 self::$toc[ "$level::$anchor" ] = $heading;
107 return sprintf('<h%2$d><a name="%1$s"></a>%3$s</h%2$d>', $anchor, $level, $heading);