Added a dark mode color scheme.
[WebKit-https.git] / Websites / webkit.org / wp-content / themes / webkit / functions.php
index bc846ce..b10e7f9 100644 (file)
@@ -3,14 +3,20 @@
 // Declare theme features
 add_theme_support( 'post-thumbnails' );
 
-function register_menus() {
-}
 add_action( 'init', function () {
     register_nav_menu('site-nav', __( 'Site Navigation' ));
     register_nav_menu('footer-nav', __( 'Footer Navigation' ));
     register_nav_menu('sitemap', __( 'Site Map Page' ));
+    register_nav_menu('feature-subnav', __( 'Feature Page Buttons' ));
 } );
 
+//add_action( 'wp_header', 'include_invert_lightness_filter');
+
+add_action( 'wp_dashboard_setup', function () {
+    $SurveyWidget = new WebKit_Nightly_Survey();
+    $SurveyWidget->add_widget();
+});
+
 function modify_contact_methods($profile_fields) {
 
     // Add new fields
@@ -22,6 +28,42 @@ function modify_contact_methods($profile_fields) {
     return $profile_fields;
 }
 
+function get_nightly_build ($type = 'builds') {
+    if (!class_exists('SyncWebKitNightlyBuilds'))
+        return false;
+
+    $WebKitBuilds = SyncWebKitNightlyBuilds::object();
+    $build = $WebKitBuilds->latest($type);
+    return $build;
+}
+
+function get_nightly_source () {
+    return get_nightly_build('source');
+}
+
+function get_nightly_archives ($limit) {
+    if (!class_exists('SyncWebKitNightlyBuilds'))
+        return array();
+
+    $WebKitBuilds = SyncWebKitNightlyBuilds::object();
+    $builds = $WebKitBuilds->records('builds', $limit);
+    return (array)$builds;
+}
+
+function get_nightly_builds_json () {
+    if (!class_exists('SyncWebKitNightlyBuilds'))
+        return '';
+
+    $WebKitBuilds = SyncWebKitNightlyBuilds::object();
+    $records = $WebKitBuilds->records('builds', 100000);
+    $builds = array();
+    foreach ( $records as $build ) {
+        $builds[] = $build[0];
+    }
+    $json = json_encode($builds);
+    return empty($json) ? "''" : $json;
+}
+
 add_filter('user_contactmethods', function ($fields) {
     // Add Twitter field to user profiles
     $fields['twitter'] = 'Twitter Handle';
@@ -45,12 +87,106 @@ add_action('init', function () {
     ));
 } );
 
+// Start Page internal rewrite handling
+add_action('after_setup_theme', function () {
+    add_rewrite_rule(
+        'nightly/start/([^/]+)/([0-9]+)/?$',
+        'index.php?pagename=nightly/start&nightly_branch=$matches[1]&nightly_build=$matches[2]',
+        'top'
+    );
+});
+
+add_filter('query_vars', function( $query_vars ) {
+    $query_vars[] = 'nightly_build';
+    $query_vars[] = 'nightly_branch';
+    return $query_vars;
+});
+
 add_filter('the_title', function( $title ) {
     if ( is_admin() ) return $title;
-    $title = str_replace(": ", ":<br>", $title);
+    if ( is_feed() ) return $title;
+
+    $title = str_replace(": ", ": <br>", $title);
+
+    $nowrap_strings = array();
+    if ($nowrap_setting = get_option("webkit_org_nowrap_strings")) {
+        $nowrap_strings = explode("\n", $nowrap_setting);
+    } else add_option("webkit_org_nowrap_strings", "\n");
+
+    foreach ($nowrap_strings as $token) {
+        $nobreak = str_replace(" ", " ", trim($token));
+        $title = str_replace(trim($token), $nobreak, $title);
+    }
+
     return $title;
 });
 
+// For RSS feeds, convert relative URIs to absolute
+add_filter('the_content', function($content) {
+    if (!is_feed()) return $content;
+    $base = trailingslashit(get_site_url());
+    $content = preg_replace('/<a([^>]*) href="\/([^"]*)"/', '<a$1 href="' . $base . '$2"', $content);
+    $content = preg_replace('/<img([^>]*) src="\/([^"]*)"/', '<img$1 src="' . $base . '$2"', $content);
+    return $content;
+});
+
+add_action('wp_head', function () {
+    if (!is_single()) return;
+
+    $style = get_post_meta(get_the_ID(), 'style', true);
+    if (!empty($style))
+        echo '<style type="text/css">' . $style . '</style>';
+
+    $script = get_post_meta(get_the_ID(), 'script', true);
+    if (!empty($script))
+        echo '<script type="text/javascript">' . $script . '</script>';
+});
+
+add_action('the_post', function($post) {
+    global $pages;
+
+    if (!(is_single() || is_page())) return;
+
+    $content = $post->post_content;
+    if (strpos($content, 'abovetitle') === false) return;
+    if (strpos($content, '<img') !== 0) return;
+
+    $post->post_title_img = substr($content, 0, strpos($content, ">\n") + 3);
+    $post->post_content = str_replace($post->post_title_img, '', $content);
+    $pages = array($post->post_content);
+});
+
+add_action('the_post', function($post) {
+    global $pages;
+
+    if (!(is_single() || is_page())) return;
+
+    $foreword = get_post_meta(get_the_ID(), 'foreword', true);
+    if ( ! $foreword ) return;
+
+    $content = $post->post_content;
+    // Transform Markdown
+    $Markdown = WPCom_Markdown::get_instance();
+    $foreword = wp_unslash( $Markdown->transform($foreword) );
+
+    $post->post_content = '<div class="foreword">' . $foreword . '</div>' . $content;
+    $pages = array($post->post_content);
+});
+
+add_filter('the_author', function($display_name) {
+    $post = get_post();
+    if (!(is_single() || is_page())) return;
+    $byline = get_post_meta(get_the_ID(), 'byline', true);
+    return empty($byline) ? $display_name : $byline;
+});
+
+function before_the_title() {
+    $post = get_post();
+
+    if ( isset($post->post_title_img) )
+        echo wp_make_content_images_responsive($post->post_title_img);
+}
+
 // Hide category 41: Legacy from archives
 add_filter('pre_get_posts', function ($query) {
     if ( $query->is_home() )
@@ -58,12 +194,6 @@ add_filter('pre_get_posts', function ($query) {
     return $query;
 });
 
-
-include('widgets/post.php');
-include('widgets/icon.php');
-include('widgets/twitter.php');
-include('widgets/page.php');
-
 add_filter( 'get_the_excerpt', function( $excerpt ) {
     $sentences = preg_split( '/(\.|!|\?)\s/', $excerpt, 2, PREG_SPLIT_DELIM_CAPTURE );
 
@@ -74,6 +204,16 @@ add_filter( 'get_the_excerpt', function( $excerpt ) {
 
 });
 
+function show_404_page() {
+    status_header(404);
+    return include( get_query_template( '404' ) );
+}
+
+include('widgets/post.php');
+include('widgets/icon.php');
+include('widgets/twitter.php');
+include('widgets/page.php');
+
 function table_of_contents() {
     if ( class_exists('WebKitTableOfContents') )
         WebKitTableOfContents::markup();
@@ -97,7 +237,33 @@ function is_super_cache_enabled() {
     return (isset($super_cache_enabled) && true === $super_cache_enabled);
 }
 
-function tag_post_image_luminance( $post_id ) {
+function include_post_icons() {
+    echo WebKit_Post_Icons::parse_icons();
+}
+
+function include_invert_lightness_filter() {
+    include('images/invert-lightness.svg');
+}
+
+function get_post_icon() {
+
+    $categories = get_the_category();
+    if (isset($categories[0]))
+        $slug = $categories[0]->slug;
+
+    if ('web-inspector' == $slug) {
+        $tags = get_the_tags();
+        if (isset($tags[0]))
+            $slug = $tags[0]->slug;
+    }
+
+    if (!WebKit_Post_Icons::has_icon($slug))
+        return 'default';
+
+    return $slug;
+}
+
+function tag_post_image_luminance($post_id) {
     $threshold = 128;
     $tags = array();
 
@@ -124,6 +290,9 @@ function tag_post_image_luminance( $post_id ) {
 }
 
 function calculate_image_luminance($image_url) {
+    if (!function_exists('ImageCreateFromString'))
+        return 1;
+
     // Get original image dimensions
     $size = getimagesize($image_url);
 
@@ -170,7 +339,7 @@ function html_select_options(array $list, $selected = null, $values = false, $ap
             if ( is_array($text) ) {
                 $label = $value;
                 $_ .= '<optgroup label="' . esc_attr($label) . '">';
-                $_ .= self::menuoptions($text, $selected, $values);
+                $_ .= html_select_options($text, $selected, $values);
                 $_ .= '</optgroup>';
                 continue;
             } else $_ .= "<option$value_attr$selected_attr>$text</option>";
@@ -188,8 +357,6 @@ add_filter('previous_post_link', function ( $format ) {
     return str_replace('href=', 'class="page-numbers prev-post" href=', $format);
 });
 
-
-
 // Queue global scripts
 add_action( 'wp_enqueue_scripts', function () {
     wp_register_script(
@@ -290,6 +457,31 @@ class Responsive_Toggle_Walker_Nav_Menu extends Walker_Nav_Menu {
 
 }
 
+class WebKit_Post_Icons {
+
+    private static $registry = array();
+
+    public static function parse_icons() {
+        if (!empty(self::$registry))
+            return '';
+
+        $svg_string = file_get_contents(get_stylesheet_directory() . '/images/icons.svg');
+        $svg = new SimpleXMLElement( $svg_string );
+        $svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
+
+        $matches = $svg->xpath('//svg:symbol/@id');
+        foreach ($matches as $symbol)
+            self::$registry[(string)$symbol['id']] = true;
+
+        return $svg_string;
+    }
+
+    public static function has_icon($id) {
+        return isset(self::$registry[$id]);
+    }
+
+}
+
 class Front_Page_Posts {
 
     private static $object;     // Singleton instance
@@ -301,7 +493,7 @@ class Front_Page_Posts {
             self::$object = new self;
 
         if ( empty(self::$wp_query) )
-            self::$wp_query = new WP_Query(array('post_type' => 'post'));
+            self::$wp_query = new WP_Query(array('post_type' => 'post', 'posts_per_page' => 16));
 
         return self::$object;
     }
@@ -310,4 +502,145 @@ class Front_Page_Posts {
         return self::$wp_query;
     }
 
+}
+
+class WebKit_Nightly_Survey {
+
+    const COOKIE_PREFIX = 'webkitnightlysurvey_';
+    const DATA_SETTING_NAME = 'webkit_nightly_survey_data';
+    const SURVEY_FILENAME = 'survey.json';
+
+    public function add_widget() {
+
+        wp_add_dashboard_widget(
+            'webkit_nightly_survey_results', // Widget slug
+            'WebKit Nightly Survey Results', // Title
+            array($this, 'display_widget')   // Display function
+        );
+
+        if (isset($_GET['wksurvey']) && $_GET['wksurvey'] == 'download')
+            $this->download() && exit;
+
+    }
+
+    public function display_widget() {
+        $data = get_option(self::DATA_SETTING_NAME);
+        $styles = "
+            <style>
+            .survey_table .question {
+                text-align: left;
+            }
+            .survey_table .score {
+                font-size: 15px;
+                min-width: 30px;
+                text-align: right;
+                vertical-align: top;
+                padding-right: 10px;
+            }
+            .survey_table .others {
+                font-style: italic;
+            }
+            </style>
+        ";
+
+        $response_limit = 10;
+        $table = '';
+        foreach ($data as $question => $responses) {
+            $question_row = '<tr><th colspan="2" class="question">' . $question . '</th></tr>';
+            $response_rows = '';
+            arsort($responses);
+            $response_count = 0;
+            $total_responses = count($responses);
+            foreach ($responses as $response => $votes) {
+                $response_rows .= '<tr><td class="score">' . intval($votes) . '</td><td class="response">' . stripslashes($response) . '</td></tr>';
+                if ( ++$response_count >= $response_limit && $response_count < $total_responses) {
+                    $response_rows .= '<tr><td class="score others">' . intval($total_responses - $response_limit) . '</td><td class="response others">more "other" responses</td></tr>';
+                    break;
+                }
+            }
+            $table .= $question_row . $response_rows;
+        }
+        echo $styles;
+        echo '<table class="survey_table">' . $table . '</table>';
+        echo '<p class="textright"><a class="button button-primary" href="' . add_query_arg('wksurvey','download',admin_url()) . '">Download Results as CSV</a></p>';
+    }
+
+    private function download() {
+        $data = get_option(self::DATA_SETTING_NAME);
+        $table = '';
+
+        header('Content-type: text/csv; charset=UTF-8');
+        header('Content-Disposition: attachment; filename="webkit_nightly_survey.csv"');
+        header('Content-Description: Delivered by webkit.org');
+        header('Cache-Control: maxage=1');
+        header('Pragma: public');
+
+        foreach ($data as $question => $responses) {
+            $question_row = 'Score,' . $question . "\n";
+            $response_rows = '';
+            arsort($responses);
+            foreach ($responses as $response => $votes) {
+                $response_rows .= intval($votes) . ',' . stripslashes($response) . "\n";
+            }
+            $table .= $question_row . $response_rows . "\n";
+        }
+        echo $table;
+
+        exit;
+    }
+
+    public function process() {
+        if ( empty($_POST) ) return;
+
+        if ( ! wp_verify_nonce($_POST['_nonce'], self::SURVEY_FILENAME) )
+            wp_die('Invalid WebKit Nightly Survey submission.');
+
+        $score = $data = get_option(self::DATA_SETTING_NAME);
+        $Survey = self::survey();
+        foreach ($Survey as $id => $SurveyQuestion) {
+            if ( ! isset($score[ $SurveyQuestion->question ]) )
+                $score[ $SurveyQuestion->question ] = array();
+            $response = $_POST['questions'][ $id ];
+            $answer = empty($SurveyQuestion->responses[ $response ]) ? $response : $SurveyQuestion->responses[ $response ];
+            if ($answer == 'Other:')
+                $answer = $_POST['other'][ $id ];
+            $score[ $SurveyQuestion->question ][ $answer ]++;
+        }
+
+        if ( $data === false ) {
+            $deprecated = null;
+            $autoload = 'no';
+            add_option(self::DATA_SETTING_NAME, $score, $deprecated, $autoload);
+        } else {
+            update_option(self::DATA_SETTING_NAME, $score);
+        }
+
+        $httponly = false;
+        $secure = false;
+        setcookie(self::cookie_name(), 1, time() + YEAR_IN_SECONDS, '/', WP_HOST, $secure, $httponly );
+        $_COOKIE[ self::cookie_name() ] = 1;
+    }
+
+    public static function responded() {
+        return isset($_COOKIE[ self::cookie_name() ]);
+    }
+
+    private static function cookie_name() {
+        return self::COOKIE_PREFIX . COOKIEHASH;
+    }
+
+    public static function survey_file() {
+        return dirname(__FILE__) . '/' . self::SURVEY_FILENAME;
+    }
+
+    public static function form_nonce() {
+        return '<input type="hidden" name="_nonce" value="' . wp_create_nonce( self::SURVEY_FILENAME ) . '">';
+    }
+
+    public static function survey () {
+        $survey_json = file_get_contents(self::survey_file());
+        $Decoded = json_decode($survey_json);
+        return isset($Decoded->survey) ? $Decoded->survey : array();
+    }
+
 }
\ No newline at end of file