Make WordPress Core


Ignore:
Timestamp:
09/13/2017 06:07:48 AM (8 years ago)
Author:
westonruter
Message:

Editor: Add CodeMirror-powered code editor with syntax highlighting, linting, and auto-completion.

  • Code editor is integrated into the Theme/Plugin Editor, Additional CSS in Customizer, and Custom HTML widget. Code editor is not yet integrated into the post editor, and it may not be until accessibility concerns are addressed.
  • The CodeMirror component in the Custom HTML widget is integrated in a similar way to TinyMCE being integrated into the Text widget, adopting the same approach for integrating dynamic JavaScript-initialized fields.
  • Linting is performed for JS, CSS, HTML, and JSON via JSHint, CSSLint, HTMLHint, and JSONLint respectively. Linting is not yet supported for PHP.
  • When user lacks unfiltered_html the capability, the Custom HTML widget will report any Kses-invalid elements and attributes as errors via a custom Kses rule for HTMLHint.
  • When linting errors are detected, the user will be prevented from saving the code until the errors are fixed, reducing instances of broken websites.
  • The placeholder value is removed from Custom CSS in favor of a fleshed-out section description which now auto-expands when the CSS field is empty. See #39892.
  • The CodeMirror library is included as wp.CodeMirror to prevent conflicts with any existing CodeMirror global.
  • An wp.codeEditor.initialize() API in JS is provided to convert a textarea into CodeMirror, with a wp_enqueue_code_editor() function in PHP to manage enqueueing the assets and settings needed to edit a given type of code.
  • A user preference is added to manage whether or not "syntax highlighting" is enabled. The feature is opt-out, being enabled by default.
  • Allowed file extensions in the theme and plugin editors have been updated to include formats which CodeMirror has modes for: conf, css, diff, patch, html, htm, http, js, json, jsx, less, md, php, phtml, php3, php4, php5, php7, phps, scss, sass, sh, bash, sql, svg, xml, yml, yaml, txt.

Props westonruter, georgestephanis, obenland, melchoyce, pixolin, mizejewski, michelleweber, afercia, grahamarmfield, samikeijonen, rianrietveld, iseulde.
See #38707.
Fixes #12423, #39892.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/customize/custom-css-setting.php

    r39919 r41376  
    356356        $this->assertTrue( $result );
    357357
    358         // Check for Unclosed Comment.
    359         $unclosed_comment = $basic_css . ' /* This is a comment. ';
     358        // Check for markup.
     359        $unclosed_comment = $basic_css . '</style>';
    360360        $result = $this->setting->validate( $unclosed_comment );
    361         $this->assertTrue( array_key_exists( 'unclosed_comment', $result->errors ) );
    362 
    363         // Check for Unopened Comment.
    364         $unclosed_comment = $basic_css . ' This is a comment.*/';
    365         $result = $this->setting->validate( $unclosed_comment );
    366         $this->assertTrue( array_key_exists( 'imbalanced_comments', $result->errors ) );
    367 
    368         // Check for Unclosed Curly Brackets.
    369         $unclosed_curly_bracket = $basic_css . '  a.link { text-decoration: none;';
    370         $result = $this->setting->validate( $unclosed_curly_bracket );
    371         $this->assertTrue( array_key_exists( 'imbalanced_curly_brackets', $result->errors ) );
    372 
    373         // Check for Unopened Curly Brackets.
    374         $unopened_curly_bracket = $basic_css . '  a.link text-decoration: none; }';
    375         $result = $this->setting->validate( $unopened_curly_bracket );
    376         $this->assertTrue( array_key_exists( 'imbalanced_curly_brackets', $result->errors ) );
    377 
    378         // Check for Unclosed Braces.
    379         $unclosed_brace = $basic_css . '  input[type="text" { color: #f00; } ';
    380         $result = $this->setting->validate( $unclosed_brace );
    381         $this->assertTrue( array_key_exists( 'imbalanced_braces', $result->errors ) );
    382 
    383         // Check for Unopened Braces.
    384         $unopened_brace = $basic_css . ' inputtype="text"] { color: #f00; } ';
    385         $result = $this->setting->validate( $unopened_brace );
    386         $this->assertTrue( array_key_exists( 'imbalanced_braces', $result->errors ) );
    387 
    388         // Check for Imbalanced Double Quotes.
    389         $imbalanced_double_quotes = $basic_css . ' div.background-image { background-image: url( "image.jpg ); } ';
    390         $result = $this->setting->validate( $imbalanced_double_quotes );
    391         $this->assertTrue( array_key_exists( 'unequal_double_quotes', $result->errors ) );
    392 
    393         // Check for Unclosed Parentheses.
    394         $unclosed_parentheses = $basic_css . ' div.background-image { background-image: url( "image.jpg" ; } ';
    395         $result = $this->setting->validate( $unclosed_parentheses );
    396         $this->assertTrue( array_key_exists( 'imbalanced_parentheses', $result->errors ) );
    397 
    398         // Check for Unopened Parentheses.
    399         $unopened_parentheses = $basic_css . ' div.background-image { background-image: url "image.jpg" ); } ';
    400         $result = $this->setting->validate( $unopened_parentheses );
    401         $this->assertTrue( array_key_exists( 'imbalanced_parentheses', $result->errors ) );
    402 
    403         // A basic Content declaration with no other errors should not throw an error.
    404         $content_declaration = $basic_css . ' a:before { content: ""; display: block; }';
    405         $result = $this->setting->validate( $content_declaration );
    406         $this->assertTrue( $result );
    407 
    408         // An error, along with a Content declaration will throw two errors.
    409         // In this case, we're using an extra opening brace.
    410         $content_declaration = $basic_css . ' a:before { content: "["; display: block; }';
    411         $result = $this->setting->validate( $content_declaration );
    412         $this->assertTrue( array_key_exists( 'imbalanced_braces', $result->errors ) );
    413         $this->assertTrue( array_key_exists( 'possible_false_positive', $result->errors ) );
    414 
    415         $css = 'body { background: #f00; } h1.site-title { font-size: 36px; } a:hover { text-decoration: none; } input[type="text"] { padding: 1em; } /* This is a comment */';
    416         $this->assertTrue( $this->setting->validate( $css ) );
    417 
    418         $validity = $this->setting->validate( $css . ' /* This is another comment.' );
    419         $this->assertInstanceOf( 'WP_Error', $validity );
    420         $this->assertContains( 'unclosed code comment', join( ' ', $validity->get_error_messages() ) );
    421 
    422         $css = '/* This is comment one. */  /* This is comment two. */';
    423         $this->assertTrue( $this->setting->validate( $css ) );
    424 
    425         $basic_css = 'body { background: #f00; } h1.site-title { font-size: 36px; } a:hover { text-decoration: none; } input[type="text"] { padding: 1em; }';
    426         $this->assertTrue( $this->setting->validate( $basic_css ) );
    427 
    428         $css = $basic_css . ' .link:before { content: "*"; display: block; }';
    429         $this->assertTrue( $this->setting->validate( $css ) );
    430 
    431         $css .= ' ( trailing';
    432         $validity = $this->setting->validate( $css );
    433         $this->assertWPError( $validity );
    434         $this->assertNotEmpty( $result->get_error_message( 'possible_false_positive' ) );
     361        $this->assertTrue( array_key_exists( 'illegal_markup', $result->errors ) );
    435362    }
    436363}
Note: See TracChangeset for help on using the changeset viewer.