Skip to content

Commit dbace68

Browse files
committed
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. git-svn-id: https://develop.svn.wordpress.org/trunk@41376 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 1b74756 commit dbace68

32 files changed

Lines changed: 37794 additions & 347 deletions

Gruntfile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ module.exports = function(grunt) {
360360
'wp-includes/js/tinymce/plugins/wordpress/plugin.js',
361361
'wp-includes/js/tinymce/plugins/wp*/plugin.js',
362362
// Third party scripts
363+
'!wp-includes/js/codemirror/*.js',
363364
'!wp-admin/js/farbtastic.js',
364365
'!wp-includes/js/backbone*.js',
365366
'!wp-includes/js/swfobject.js',

src/wp-admin/css/code-editor.css

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
.wrap [class*="CodeMirror-lint-marker"],
2+
.wp-core-ui [class*="CodeMirror-lint-message"],
3+
.wrap .CodeMirror-lint-marker-multiple {
4+
background-image: none;
5+
}
6+
7+
.wrap [class*="CodeMirror-lint-marker"]:before {
8+
font: normal 18px/1 dashicons;
9+
position: relative;
10+
top: -2px;
11+
}
12+
13+
.wp-core-ui [class*="CodeMirror-lint-message"]:before {
14+
font: normal 16px/1 dashicons;
15+
left: 16px;
16+
position: absolute;
17+
}
18+
19+
.wp-core-ui .CodeMirror-lint-message-error,
20+
.wp-core-ui .CodeMirror-lint-message-warning {
21+
box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
22+
margin: 5px 0 2px;
23+
padding: 3px 12px 3px 28px;
24+
}
25+
26+
.wp-core-ui .CodeMirror-lint-message-warning {
27+
background-color: #fff8e5;
28+
border-left: 4px solid #ffb900;
29+
}
30+
31+
.wrap .CodeMirror-lint-marker-warning:before,
32+
.wp-core-ui .CodeMirror-lint-message-warning:before {
33+
content: "\f534";
34+
color: #f6a306;
35+
}
36+
37+
.wp-core-ui .CodeMirror-lint-message-error {
38+
background-color: #fbeaea;
39+
border-left: 4px solid #dc3232;
40+
}
41+
42+
.wrap .CodeMirror-lint-marker-error:before,
43+
.wp-core-ui .CodeMirror-lint-message-error:before {
44+
content: "\f153";
45+
color: #dc3232;
46+
}
47+
48+
.wp-core-ui .CodeMirror-lint-tooltip {
49+
background: none;
50+
border: none;
51+
border-radius: 0;
52+
direction: ltr;
53+
}
54+
55+
.wrap .CodeMirror .CodeMirror-matchingbracket {
56+
background: rgba(255, 150, 0, .3);
57+
color: inherit;
58+
}
59+
60+
.CodeMirror {
61+
text-align: left;
62+
}

src/wp-admin/css/common.css

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,7 +2200,7 @@ h1.nav-tab-wrapper, /* Back-compat for pre-4.4 */
22002200
visibility: visible;
22012201
}
22022202

2203-
#template div {
2203+
#template > div {
22042204
margin-right: 190px;
22052205
}
22062206

@@ -3015,13 +3015,18 @@ img {
30153015
#template textarea {
30163016
font-family: Consolas, Monaco, monospace;
30173017
font-size: 13px;
3018-
width: 97%;
30193018
background: #f9f9f9;
30203019
-moz-tab-size: 4;
30213020
-o-tab-size: 4;
30223021
tab-size: 4;
30233022
}
30243023

3024+
#template textarea,
3025+
#template .CodeMirror {
3026+
width: 97%;
3027+
height: calc( 100vh - 220px );
3028+
}
3029+
30253030
/* rtl:ignore */
30263031
#template textarea,
30273032
#docs-list {
@@ -3032,6 +3037,25 @@ img {
30323037
width: 97%;
30333038
}
30343039

3040+
#file-editor-linting-error {
3041+
margin-top: 1em;
3042+
margin-bottom: 1em;
3043+
}
3044+
#file-editor-linting-error > .notice {
3045+
margin: 0;
3046+
display: inline-block;
3047+
}
3048+
#file-editor-linting-error > .notice > p {
3049+
width: auto;
3050+
}
3051+
#template .submit {
3052+
margin-top: 1em;
3053+
padding: 0;
3054+
}
3055+
3056+
#template .submit input[type=submit][disabled] {
3057+
cursor: not-allowed;
3058+
}
30353059
#templateside {
30363060
float: right;
30373061
width: 190px;
@@ -3585,12 +3609,13 @@ img {
35853609
margin-top: -5px;
35863610
}
35873611

3588-
#template div {
3612+
#template > div {
35893613
float: none;
35903614
margin: 0;
35913615
width: auto;
35923616
}
35933617

3618+
#template .CodeMirror,
35943619
#template textarea {
35953620
width: 100%;
35963621
}

src/wp-admin/css/customize-controls.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,20 @@ p.customize-section-description {
550550
margin-top: 22px;
551551
margin-bottom: 0;
552552
}
553+
.customize-section-description ul {
554+
margin-left: 1em;
555+
}
556+
.customize-section-description ul > li {
557+
list-style: disc;
558+
}
559+
.section-description-buttons {
560+
text-align: right;
561+
}
562+
563+
.section-description-buttons button.button-link {
564+
color: #0073aa;
565+
text-decoration: underline;
566+
}
553567

554568
.customize-control {
555569
width: 100%;
@@ -1154,6 +1168,19 @@ p.customize-section-description {
11541168
margin-bottom: -12px;
11551169
}
11561170

1171+
.customize-section-description-container + #customize-control-custom_css:last-child .CodeMirror {
1172+
height: calc( 100vh - 185px );
1173+
}
1174+
.CodeMirror-lint-tooltip,
1175+
.CodeMirror-hints {
1176+
z-index: 500000 !important;
1177+
}
1178+
1179+
.customize-section-description-container + #customize-control-custom_css:last-child .customize-control-notifications-container {
1180+
margin-left: 12px;
1181+
margin-right: 12px;
1182+
}
1183+
11571184
@media screen and ( max-width: 640px ) {
11581185
.customize-section-description-container + #customize-control-custom_css:last-child {
11591186
margin-right: 0;

src/wp-admin/css/widgets.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,20 @@ div#widgets-right .widget-top:hover,
645645
line-height: 1.4em;
646646
}
647647

648+
.custom-html-widget-fields > p > .CodeMirror {
649+
border: 1px solid #e5e5e5;
650+
}
651+
.custom-html-widget-fields code {
652+
padding-top: 1px;
653+
padding-bottom: 1px;
654+
}
655+
ul.CodeMirror-hints {
656+
z-index: 101; /* Due to z-index 100 set on .widget.open */
657+
}
658+
.widget-control-actions .custom-html-widget-save-button.button.validation-blocked {
659+
cursor: not-allowed;
660+
}
661+
648662
/* =Media Queries
649663
-------------------------------------------------------------- */
650664

src/wp-admin/includes/user.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ function edit_user( $user_id = 0 ) {
9191
}
9292

9393
if ( $update ) {
94-
$user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' == $_POST['rich_editing'] ? 'false' : 'true';
94+
$user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' === $_POST['rich_editing'] ? 'false' : 'true';
95+
$user->syntax_highlighting = isset( $_POST['syntax_highlighting'] ) && 'false' === $_POST['syntax_highlighting'] ? 'false' : 'true';
9596
$user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh';
9697
$user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false';
9798
$user->locale = '';

0 commit comments

Comments
 (0)