5b79c0753d3aadf243f83f60aa5d7775f44f6e69
[WebKit-https.git] / Websites / webkit.org / wp-content / plugins / table-of-contents.php
1 <?php
2 /*
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
6 Version: 1.0
7 Author: Jonathan Davis
8 */
9
10 WebKitTableOfContents::init();
11
12 class WebKitTableOfContents {
13
14     private static $editing = false;
15     private static $toc = array();
16     private static $attr_regex = '\{((?:[ ]*[#.][-_:a-zA-Z0-9]+){1,})[ ]*\}';
17
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' ) );
21     }
22
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 );
27     }
28
29     public static function filterIndex($value, $key) {
30         list($level, $anchor) = explode('::', $key);
31         if ( $level < 3 ) self::$toc[ $key ] = $value;
32     }
33
34     public static function renderMarkup() {
35         if ( ! is_page() ) return;
36
37         if ( empty(self::$toc) || ! self::hasIndex() )
38             return;
39
40         $depth = 0;
41         $parent = 0;
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>';
43
44         foreach ( self::$toc as $name => $heading ) {
45             list($level, $anchor) = explode('::', $name);
46             if ( empty($level) || $level > 3 ) continue;
47
48             if ( $level < $depth ) {
49                 $markup .= str_repeat('</ul></li>', $depth - $level);
50                 $depth = $level;
51             } elseif ( $level == $depth )
52                 $markup .= '</li>';
53
54
55
56             if ( $level > $depth ) {
57                 $markup .= '<ul class="level-' . $level . '">';
58                 $depth = $level;
59                 $parent = $depth;
60             }
61
62             $markup .= sprintf('<li><a href="#%s">%s</a>', $anchor, $heading);
63
64         }
65         $markup .= '</ul></menuitem></menu>';
66
67         return $markup;
68     }
69
70     public static function markup() {
71         echo self::renderMarkup();
72     }
73
74     public function wp_insert_post_data( $post_data, $record ) {
75
76         if ( ! in_array($post_data['post_type'], array('page')) )
77             return $post_data;
78
79         $post_data['post_content'] = self::parse($post_data['post_content']);
80
81         self::$editing = isset( $record['ID'] ) ? $record['ID'] : false;
82
83         return $post_data;
84     }
85
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);
90     }
91
92     public static function parse( $content ) {
93         $markup = preg_replace_callback('{
94                 ^<h([1-6])[^>]*>(.+?)<\/h[1-6]>* # HTML tags
95                 |
96                 ^(\#{1,6})    # $1 = string of #\'s
97                 [ ]*
98                 (.+?)        # $2 = Header text
99                 [ ]*
100                 \#*            # optional closing #\'s (not counted)
101                 (?:[ ]+ ' . self::$attr_regex . ' )?     # $3 = id/class attributes
102                 [ ]*
103                 \n+
104             }xm',
105             array('WebKitTableOfContents', 'index'),
106             $content
107         );
108
109         return $markup;
110     }
111
112     public static function index( $matches ) {
113         list($marked, $level, $heading) = $matches;
114         $anchor = sanitize_title_with_dashes($heading);
115         self::$toc[ "$level::$anchor" ] = $heading;
116         return sprintf('<h%2$d><a name="%1$s"></a>%3$s</h%2$d>', $anchor, $level, $heading);
117     }
118 }