Ticket #24048: 24048.10.diff
File 24048.10.diff, 29.8 KB (added by , 7 years ago) |
---|
-
src/wp-admin/css/common.css
diff --git src/wp-admin/css/common.css src/wp-admin/css/common.css index 1702e7736c..81c944dd80 100644
div.error { 1466 1466 .wrap #templateside .notice { 1467 1467 display: block; 1468 1468 margin: 0; 1469 padding: 5px 12px;1469 padding: 5px 8px; 1470 1470 font-weight: 600; 1471 1471 text-decoration: none; 1472 1472 } 1473 1473 1474 1474 .wrap #templateside span.notice { 1475 1475 margin-left: -12px; 1476 1476 } 1477 1477 1478 1478 #templateside li.notice a { 1479 1479 padding: 0; 1480 1480 } 1481 1481 1482 1482 /* Update icon. */ … … img { 3036 3036 width: 97%; 3037 3037 height: calc( 100vh - 280px ); 3038 3038 } 3039 3039 3040 #templateside { 3040 3041 margin-top: 31px; 3041 overflow: scroll; 3042 overflow: auto; 3043 padding: 2px; 3044 height: calc(100vh - 280px); 3045 } 3046 #templateside ul ul { 3047 padding-left: 12px; 3048 } 3049 3050 /* 3051 * Styles for Theme and Plugin editors. 3052 */ 3053 3054 /* Hide collapsed items. */ 3055 [role="treeitem"][aria-expanded="false"] > ul { 3056 display: none; 3042 3057 } 3043 3058 3059 /* Use arrow dashicons for folder states, but hide from screen readers. */ 3060 [role="treeitem"] span[aria-hidden] { 3061 display: inline; 3062 font-family: dashicons; 3063 font-size: 20px; 3064 position: absolute; 3065 pointer-events: none; 3066 } 3067 [role="treeitem"][aria-expanded="false"] > .folder-label .icon:after { 3068 content: "\f139"; 3069 } 3070 [role="treeitem"][aria-expanded="true"] > .folder-label .icon:after { 3071 content: "\f140"; 3072 } 3073 [role="treeitem"] .folder-label { 3074 display: block; 3075 padding: 3px 3px 3px 12px; 3076 cursor: pointer; 3077 } 3078 3079 /* Remove outline, and create our own focus and hover styles */ 3080 [role="treeitem"] { 3081 outline: 0; 3082 } 3083 [role="treeitem"] .folder-label.focus { 3084 color: #124964; 3085 box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); 3086 } 3087 [role="treeitem"].hover, 3088 [role="treeitem"] .folder-label.hover { 3089 background-color: #DDDDDD; 3090 } 3091 3092 .tree-folder { 3093 margin: 0; 3094 position: relative; 3095 } 3096 [role="treeitem"] li { 3097 position: relative; 3098 } 3099 3100 /* Styles for folder indicators/depth */ 3101 .tree-folder .tree-folder::after { 3102 content: ' '; 3103 display: block; 3104 position: absolute; 3105 left: 2px; 3106 border-left: 1px solid #ccc; 3107 top: -13px; 3108 bottom: 10px; 3109 } 3110 .tree-folder > li::before { 3111 content: ' '; 3112 position: absolute; 3113 display: block; 3114 border-left: 1px solid #ccc; 3115 left: 2px; 3116 top: -5px; 3117 height: 18px; 3118 width: 7px; 3119 border-bottom: 1px solid #ccc; 3120 } 3121 .tree-folder > li::after { 3122 content: ' '; 3123 position: absolute; 3124 display: block; 3125 border-left: 1px solid #ccc; 3126 left: 2px; 3127 bottom: -7px; 3128 top: 0; 3129 } 3130 3131 /* current-file needs to adjustment for .notice styles */ 3132 #templateside .current-file { 3133 margin: -4px 0 -2px; 3134 } 3135 .tree-folder > .current-file::before { 3136 left: 4px; 3137 height: 15px; 3138 width: 6px; 3139 border-left: none; 3140 top: 3px; 3141 } 3142 .tree-folder > .current-file::after { 3143 bottom: -4px; 3144 height: 7px; 3145 left: 2px; 3146 top: auto; 3147 } 3148 3149 /* Lines shouldn't continue on last item */ 3150 .tree-folder > li:last-child::after, 3151 .tree-folder li:last-child > .tree-folder::after { 3152 display: none; 3153 } 3154 3155 3044 3156 #theme-plugin-editor-label { 3045 3157 display: inline-block; 3046 3158 margin-bottom: 1em; … … img { 3653 3765 width: 100%; 3654 3766 } 3655 3767 3768 #templateside ul ul { 3769 padding-left: 1.5em; 3770 } 3771 [role="treeitem"] .folder-label { 3772 display: block; 3773 padding: 5px; 3774 } 3775 .tree-folder > li::before, 3776 .tree-folder > li::after, 3777 .tree-folder .tree-folder::after { 3778 left: -8px; 3779 } 3780 .tree-folder > li::before { 3781 top: 0px; 3782 height: 13px; 3783 } 3784 .tree-folder > .current-file::before { 3785 left: -5px; 3786 top: 7px; 3787 width: 4px; 3788 } 3789 .tree-folder > .current-file::after { 3790 height: 9px; 3791 left: -8px; 3792 } 3793 .wrap #templateside span.notice { 3794 margin-left: -14px; 3795 } 3796 3656 3797 .fileedit-sub .alignright { 3657 3798 margin-top: 15px; 3658 3799 } -
src/wp-admin/includes/misc.php
diff --git src/wp-admin/includes/misc.php src/wp-admin/includes/misc.php index c434b8d3ed..6ca915ad1f 100644
function update_recently_edited( $file ) { 269 269 update_option( 'recently_edited', $oldfiles ); 270 270 } 271 271 272 /** 273 * Makes a tree structure for the Theme Editor's file list. 274 * 275 * @since 4.9.0 276 * @access private 277 * 278 * @param array $allowed_files List of theme file paths. 279 * @return array Tree structure for listing theme files. 280 */ 281 function wp_make_theme_file_tree( $allowed_files ) { 282 $tree_list = array(); 283 foreach ( $allowed_files as $file_name => $absolute_filename ) { 284 $list = explode( '/', $file_name ); 285 $last_dir = &$tree_list; 286 foreach ( $list as $dir ) { 287 $last_dir =& $last_dir[ $dir ]; 288 } 289 $last_dir = $file_name; 290 } 291 return $tree_list; 292 } 293 294 /** 295 * Outputs the formatted file list for the Theme Editor. 296 * 297 * @since 4.9.0 298 * @access private 299 * 300 * @param array|string $tree List of file/folder paths, or filename. 301 * @param int $level The aria-level for the current iteration. 302 * @param int $size The aria-setsize for the current iteration. 303 * @param int $index The aria-posinset for the current iteration. 304 */ 305 function wp_print_theme_file_tree( $tree, $level = 2, $size = 1, $index = 1 ) { 306 global $relative_file, $stylesheet; 307 308 if ( is_array( $tree ) ) { 309 $index = 0; 310 $size = count( $tree ); 311 foreach ( $tree as $label => $theme_file ) : 312 $index++; 313 if ( ! is_array( $theme_file ) ) { 314 wp_print_theme_file_tree( $theme_file, $level, $index, $size ); 315 continue; 316 } 317 ?> 318 <li role="treeitem" aria-expanded="true" tabindex="-1" 319 aria-level="<?php echo esc_attr( $level ); ?>" 320 aria-setsize="<?php echo esc_attr( $size ); ?>" 321 aria-posinset="<?php echo esc_attr( $index ); ?>"> 322 <span class="folder-label"><?php echo esc_html( $label ); ?> <span class="screen-reader-text"><?php _e( 'folder' ); ?></span><span aria-hidden="true" class="icon"></span></span> 323 <ul role="group" class="tree-folder"><?php wp_print_theme_file_tree( $theme_file, $level + 1, $index, $size ); ?></ul> 324 </li> 325 <?php 326 endforeach; 327 } else { 328 $filename = $tree; 329 $url = add_query_arg( 330 array( 331 'file' => rawurlencode( $tree ), 332 'theme' => rawurlencode( $stylesheet ), 333 ), 334 admin_url( 'theme-editor.php' ) 335 ); 336 ?> 337 <li role="none" class="<?php echo esc_attr( $relative_file === $filename ? 'current-file' : '' ); ?>"> 338 <a role="treeitem" tabindex="<?php echo esc_attr( $relative_file === $filename ? '0' : '-1' ); ?>" 339 href="<?php echo esc_url( $url ); ?>" 340 aria-level="<?php echo esc_attr( $level ); ?>" 341 aria-setsize="<?php echo esc_attr( $size ); ?>" 342 aria-posinset="<?php echo esc_attr( $index ); ?>"> 343 <?php 344 $file_description = esc_html( get_file_description( $filename ) ); 345 if ( $file_description !== $filename && basename( $filename ) !== $file_description ) { 346 $file_description .= '<br /><span class="nonessential">(' . esc_html( $filename ) . ')</span>'; 347 } 348 349 if ( $relative_file === $filename ) { 350 echo '<span class="notice notice-info">' . $file_description . '</span>'; 351 } else { 352 echo $file_description; 353 } 354 ?> 355 </a> 356 </li> 357 <?php 358 } 359 } 360 361 /** 362 * Makes a tree structure for the Plugin Editor's file list. 363 * 364 * @since 4.9.0 365 * @access private 366 * 367 * @param string $plugin_editable_files List of plugin file paths. 368 * 369 * @return array Tree structure for listing plugin files. 370 */ 371 function wp_make_plugin_file_tree( $plugin_editable_files ) { 372 $tree_list = array(); 373 foreach ( $plugin_editable_files as $plugin_file ) { 374 $list = explode( '/', preg_replace( '#^.+?/#', '', $plugin_file ) ); 375 $last_dir = &$tree_list; 376 foreach ( $list as $dir ) { 377 $last_dir =& $last_dir[ $dir ]; 378 } 379 $last_dir = $plugin_file; 380 } 381 return $tree_list; 382 } 383 384 /** 385 * Outputs the formatted file list for the Plugin Editor. 386 * 387 * @since 4.9.0 388 * @access private 389 * 390 * @param array|string $tree List of file/folder paths, or filename. 391 * @param string $label Name of file or folder to print. 392 * @param int $level The aria-level for the current iteration. 393 * @param int $size The aria-setsize for the current iteration. 394 * @param int $index The aria-posinset for the current iteration. 395 */ 396 function wp_print_plugin_file_tree( $tree, $label = '', $level = 2, $size = 1, $index = 1 ) { 397 global $file, $plugin; 398 if ( is_array( $tree ) ) { 399 $index = 0; 400 $size = count( $tree ); 401 foreach ( $tree as $label => $plugin_file ) : 402 $index++; 403 if ( ! is_array( $plugin_file ) ) { 404 wp_print_plugin_file_tree( $plugin_file, $label, $level, $index, $size ); 405 continue; 406 } 407 ?> 408 <li role="treeitem" aria-expanded="true" tabindex="-1" 409 aria-level="<?php echo esc_attr( $level ); ?>" 410 aria-setsize="<?php echo esc_attr( $size ); ?>" 411 aria-posinset="<?php echo esc_attr( $index ); ?>"> 412 <span class="folder-label"><?php echo esc_html( $label ); ?> <span class="screen-reader-text"><?php _e( 'folder' ); ?></span><span aria-hidden="true" class="icon"></span></span> 413 <ul role="group" class="tree-folder"><?php wp_print_plugin_file_tree( $plugin_file, '', $level + 1, $index, $size ); ?></ul> 414 </li> 415 <?php 416 endforeach; 417 } else { 418 $url = add_query_arg( 419 array( 420 'file' => rawurlencode( $tree ), 421 'plugin' => rawurlencode( $plugin ), 422 ), 423 admin_url( 'plugin-editor.php' ) 424 ); 425 ?> 426 <li role="none" class="<?php echo esc_attr( $file === $tree ? 'current-file' : '' ); ?>"> 427 <a role="treeitem" tabindex="<?php echo esc_attr( $file === $tree ? '0' : '-1' ); ?>" 428 href="<?php echo esc_url( $url ); ?>" 429 aria-level="<?php echo esc_attr( $level ); ?>" 430 aria-setsize="<?php echo esc_attr( $size ); ?>" 431 aria-posinset="<?php echo esc_attr( $index ); ?>"> 432 <?php 433 if ( $file === $tree ) { 434 echo '<span class="notice notice-info">' . esc_html( $label ) . '</span>'; 435 } else { 436 echo esc_html( $label ); 437 } 438 ?> 439 </a> 440 </li> 441 <?php 442 } 443 } 444 272 445 /** 273 446 * Flushes rewrite rules if siteurl, home or page_on_front changed. 274 447 * -
src/wp-admin/js/theme-plugin-editor.js
diff --git src/wp-admin/js/theme-plugin-editor.js src/wp-admin/js/theme-plugin-editor.js index 683d7fb562..35f85494bc 100644
if ( ! window.wp ) { 6 6 7 7 wp.themePluginEditor = (function( $ ) { 8 8 'use strict'; 9 var component, TreeLinks; 9 10 10 varcomponent = {11 component = { 11 12 l10n: { 12 13 lintError: { 13 14 singular: '', … … wp.themePluginEditor = (function( $ ) { 66 67 } ); 67 68 } 68 69 70 $( component.initFileBrowser ); 71 69 72 $( window ).on( 'beforeunload', function() { 70 73 if ( component.dirty ) { 71 74 return component.l10n.saveAlert; … … wp.themePluginEditor = (function( $ ) { 86 89 pointer: component.themeOrPlugin + '_editor_notice' 87 90 }); 88 91 89 // hide modal92 // Hide modal. 90 93 component.warning.remove(); 91 94 $( 'body' ).removeClass( 'modal-open' ); 92 95 93 // return focus - is this a trap?96 // Return focus - is this a trap? 94 97 component.instance.codemirror.focus(); 95 98 }; 96 99 … … wp.themePluginEditor = (function( $ ) { 148 151 component.removeNotice( component.lastSaveNoticeCode ); 149 152 } 150 153 151 request.done( function 154 request.done( function( response ) { 152 155 component.lastSaveNoticeCode = 'file_saved'; 153 156 component.addNotice({ 154 157 code: component.lastSaveNoticeCode, … … wp.themePluginEditor = (function( $ ) { 159 162 component.dirty = false; 160 163 } ); 161 164 162 request.fail( function 165 request.fail( function( response ) { 163 166 var notice = $.extend( 164 167 { 165 168 code: 'save_error', … … wp.themePluginEditor = (function( $ ) { 350 353 component.instance = editor; 351 354 }; 352 355 356 /** 357 * Initialization of the file browser's folder states. 358 * 359 * @since 4.9.0 360 * @returns {void} 361 */ 362 component.initFileBrowser = function initFileBrowser() { 363 364 // Collapse all folders. 365 $( '#templateside [role="group"]' ).parent().attr( 'aria-expanded', false ); 366 367 // Expand ancestors to the current file. 368 $( '#templateside .notice' ).parents( '[aria-expanded]' ).attr( 'aria-expanded', true ); 369 370 // Find Tree elements and enhance them. 371 $( '#templateside [role="tree"]' ).each( function() { 372 var treeLinks = new TreeLinks( this ); 373 treeLinks.init(); 374 } ); 375 }; 376 377 /* jshint ignore:start */ 378 /* jscs:disable */ 379 /* eslint-disable */ 380 381 /** 382 * Creates a new TreeitemLink. 383 * 384 * @since 4.9.0 385 * @class 386 * @private 387 * @see {@link https://www.w3.org/TR/wai-aria-practices-1.1/examples/treeview/treeview-2/treeview-2b.html|W3C Treeview Example} 388 * @license W3C-20150513 389 */ 390 var TreeitemLink = (function () { 391 /** 392 * This content is licensed according to the W3C Software License at 393 * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document 394 * 395 * File: TreeitemLink.js 396 * 397 * Desc: Treeitem widget that implements ARIA Authoring Practices 398 * for a tree being used as a file viewer 399 * 400 * Author: Jon Gunderson, Ku Ja Eun and Nicholas Hoyt 401 */ 402 403 /** 404 * @constructor 405 * 406 * @desc 407 * Treeitem object for representing the state and user interactions for a 408 * treeItem widget 409 * 410 * @param node 411 * An element with the role=tree attribute 412 */ 413 414 var TreeitemLink = function (node, treeObj, group) { 415 416 // Check whether node is a DOM element 417 if (typeof node !== 'object') { 418 return; 419 } 420 421 node.tabIndex = -1; 422 this.tree = treeObj; 423 this.groupTreeitem = group; 424 this.domNode = node; 425 this.label = node.textContent.trim(); 426 this.stopDefaultClick = false; 427 428 if (node.getAttribute('aria-label')) { 429 this.label = node.getAttribute('aria-label').trim(); 430 } 431 432 this.isExpandable = false; 433 this.isVisible = false; 434 this.inGroup = false; 435 436 if (group) { 437 this.inGroup = true; 438 } 439 440 var elem = node.firstElementChild; 441 442 while (elem) { 443 444 if (elem.tagName.toLowerCase() == 'ul') { 445 elem.setAttribute('role', 'group'); 446 this.isExpandable = true; 447 break; 448 } 449 450 elem = elem.nextElementSibling; 451 } 452 453 this.keyCode = Object.freeze({ 454 RETURN: 13, 455 SPACE: 32, 456 PAGEUP: 33, 457 PAGEDOWN: 34, 458 END: 35, 459 HOME: 36, 460 LEFT: 37, 461 UP: 38, 462 RIGHT: 39, 463 DOWN: 40 464 }); 465 }; 466 467 TreeitemLink.prototype.init = function () { 468 this.domNode.tabIndex = -1; 469 470 if (!this.domNode.getAttribute('role')) { 471 this.domNode.setAttribute('role', 'treeitem'); 472 } 473 474 this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); 475 this.domNode.addEventListener('click', this.handleClick.bind(this)); 476 this.domNode.addEventListener('focus', this.handleFocus.bind(this)); 477 this.domNode.addEventListener('blur', this.handleBlur.bind(this)); 478 479 if (this.isExpandable) { 480 this.domNode.firstElementChild.addEventListener('mouseover', this.handleMouseOver.bind(this)); 481 this.domNode.firstElementChild.addEventListener('mouseout', this.handleMouseOut.bind(this)); 482 } 483 else { 484 this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this)); 485 this.domNode.addEventListener('mouseout', this.handleMouseOut.bind(this)); 486 } 487 }; 488 489 TreeitemLink.prototype.isExpanded = function () { 490 491 if (this.isExpandable) { 492 return this.domNode.getAttribute('aria-expanded') === 'true'; 493 } 494 495 return false; 496 497 }; 498 499 /* EVENT HANDLERS */ 500 501 TreeitemLink.prototype.handleKeydown = function (event) { 502 var tgt = event.currentTarget, 503 flag = false, 504 _char = event.key, 505 clickEvent; 506 507 function isPrintableCharacter(str) { 508 return str.length === 1 && str.match(/\S/); 509 } 510 511 function printableCharacter(item) { 512 if (_char == '*') { 513 item.tree.expandAllSiblingItems(item); 514 flag = true; 515 } 516 else { 517 if (isPrintableCharacter(_char)) { 518 item.tree.setFocusByFirstCharacter(item, _char); 519 flag = true; 520 } 521 } 522 } 523 524 this.stopDefaultClick = false; 525 526 if (event.altKey || event.ctrlKey || event.metaKey) { 527 return; 528 } 529 530 if (event.shift) { 531 if (event.keyCode == this.keyCode.SPACE || event.keyCode == this.keyCode.RETURN) { 532 event.stopPropagation(); 533 this.stopDefaultClick = true; 534 } 535 else { 536 if (isPrintableCharacter(_char)) { 537 printableCharacter(this); 538 } 539 } 540 } 541 else { 542 switch (event.keyCode) { 543 case this.keyCode.SPACE: 544 case this.keyCode.RETURN: 545 if (this.isExpandable) { 546 if (this.isExpanded()) { 547 this.tree.collapseTreeitem(this); 548 } 549 else { 550 this.tree.expandTreeitem(this); 551 } 552 flag = true; 553 } 554 else { 555 event.stopPropagation(); 556 this.stopDefaultClick = true; 557 } 558 break; 559 560 case this.keyCode.UP: 561 this.tree.setFocusToPreviousItem(this); 562 flag = true; 563 break; 564 565 case this.keyCode.DOWN: 566 this.tree.setFocusToNextItem(this); 567 flag = true; 568 break; 569 570 case this.keyCode.RIGHT: 571 if (this.isExpandable) { 572 if (this.isExpanded()) { 573 this.tree.setFocusToNextItem(this); 574 } 575 else { 576 this.tree.expandTreeitem(this); 577 } 578 } 579 flag = true; 580 break; 581 582 case this.keyCode.LEFT: 583 if (this.isExpandable && this.isExpanded()) { 584 this.tree.collapseTreeitem(this); 585 flag = true; 586 } 587 else { 588 if (this.inGroup) { 589 this.tree.setFocusToParentItem(this); 590 flag = true; 591 } 592 } 593 break; 594 595 case this.keyCode.HOME: 596 this.tree.setFocusToFirstItem(); 597 flag = true; 598 break; 599 600 case this.keyCode.END: 601 this.tree.setFocusToLastItem(); 602 flag = true; 603 break; 604 605 default: 606 if (isPrintableCharacter(_char)) { 607 printableCharacter(this); 608 } 609 break; 610 } 611 } 612 613 if (flag) { 614 event.stopPropagation(); 615 event.preventDefault(); 616 } 617 }; 618 619 TreeitemLink.prototype.handleClick = function (event) { 620 621 // only process click events that directly happened on this treeitem 622 if (event.target !== this.domNode && event.target !== this.domNode.firstElementChild) { 623 return; 624 } 625 626 if (this.isExpandable) { 627 if (this.isExpanded()) { 628 this.tree.collapseTreeitem(this); 629 } 630 else { 631 this.tree.expandTreeitem(this); 632 } 633 event.stopPropagation(); 634 } 635 }; 636 637 TreeitemLink.prototype.handleFocus = function (event) { 638 var node = this.domNode; 639 if (this.isExpandable) { 640 node = node.firstElementChild; 641 } 642 node.classList.add('focus'); 643 }; 644 645 TreeitemLink.prototype.handleBlur = function (event) { 646 var node = this.domNode; 647 if (this.isExpandable) { 648 node = node.firstElementChild; 649 } 650 node.classList.remove('focus'); 651 }; 652 653 TreeitemLink.prototype.handleMouseOver = function (event) { 654 event.currentTarget.classList.add('hover'); 655 }; 656 657 TreeitemLink.prototype.handleMouseOut = function (event) { 658 event.currentTarget.classList.remove('hover'); 659 }; 660 661 return TreeitemLink; 662 })(); 663 664 /** 665 * Creates a new TreeLinks. 666 * 667 * @since 4.9.0 668 * @class 669 * @private 670 * @see {@link https://www.w3.org/TR/wai-aria-practices-1.1/examples/treeview/treeview-2/treeview-2b.html|W3C Treeview Example} 671 * @license W3C-20150513 672 */ 673 TreeLinks = (function () { 674 /* 675 * This content is licensed according to the W3C Software License at 676 * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document 677 * 678 * File: TreeLinks.js 679 * 680 * Desc: Tree widget that implements ARIA Authoring Practices 681 * for a tree being used as a file viewer 682 * 683 * Author: Jon Gunderson, Ku Ja Eun and Nicholas Hoyt 684 */ 685 686 /* 687 * @constructor 688 * 689 * @desc 690 * Tree item object for representing the state and user interactions for a 691 * tree widget 692 * 693 * @param node 694 * An element with the role=tree attribute 695 */ 696 697 var TreeLinks = function (node) { 698 // Check whether node is a DOM element 699 if (typeof node !== 'object') { 700 return; 701 } 702 703 this.domNode = node; 704 705 this.treeitems = []; 706 this.firstChars = []; 707 708 this.firstTreeitem = null; 709 this.lastTreeitem = null; 710 711 }; 712 713 TreeLinks.prototype.init = function () { 714 715 function findTreeitems(node, tree, group) { 716 717 var elem = node.firstElementChild; 718 var ti = group; 719 720 while (elem) { 721 722 if ((elem.tagName.toLowerCase() === 'li' && elem.firstElementChild.tagName.toLowerCase() === 'span') || elem.tagName.toLowerCase() === 'a') { 723 ti = new TreeitemLink(elem, tree, group); 724 ti.init(); 725 tree.treeitems.push(ti); 726 tree.firstChars.push(ti.label.substring(0, 1).toLowerCase()); 727 } 728 729 if (elem.firstElementChild) { 730 findTreeitems(elem, tree, ti); 731 } 732 733 elem = elem.nextElementSibling; 734 } 735 } 736 737 // initialize pop up menus 738 if (!this.domNode.getAttribute('role')) { 739 this.domNode.setAttribute('role', 'tree'); 740 } 741 742 findTreeitems(this.domNode, this, false); 743 744 this.updateVisibleTreeitems(); 745 746 this.firstTreeitem.domNode.tabIndex = 0; 747 748 }; 749 750 TreeLinks.prototype.setFocusToItem = function (treeitem) { 751 752 for (var i = 0; i < this.treeitems.length; i++) { 753 var ti = this.treeitems[i]; 754 755 if (ti === treeitem) { 756 ti.domNode.tabIndex = 0; 757 ti.domNode.focus(); 758 } 759 else { 760 ti.domNode.tabIndex = -1; 761 } 762 } 763 764 }; 765 766 TreeLinks.prototype.setFocusToNextItem = function (currentItem) { 767 768 var nextItem = false; 769 770 for (var i = (this.treeitems.length - 1); i >= 0; i--) { 771 var ti = this.treeitems[i]; 772 if (ti === currentItem) { 773 break; 774 } 775 if (ti.isVisible) { 776 nextItem = ti; 777 } 778 } 779 780 if (nextItem) { 781 this.setFocusToItem(nextItem); 782 } 783 784 }; 785 786 TreeLinks.prototype.setFocusToPreviousItem = function (currentItem) { 787 788 var prevItem = false; 789 790 for (var i = 0; i < this.treeitems.length; i++) { 791 var ti = this.treeitems[i]; 792 if (ti === currentItem) { 793 break; 794 } 795 if (ti.isVisible) { 796 prevItem = ti; 797 } 798 } 799 800 if (prevItem) { 801 this.setFocusToItem(prevItem); 802 } 803 }; 804 805 TreeLinks.prototype.setFocusToParentItem = function (currentItem) { 806 807 if (currentItem.groupTreeitem) { 808 this.setFocusToItem(currentItem.groupTreeitem); 809 } 810 }; 811 812 TreeLinks.prototype.setFocusToFirstItem = function () { 813 this.setFocusToItem(this.firstTreeitem); 814 }; 815 816 TreeLinks.prototype.setFocusToLastItem = function () { 817 this.setFocusToItem(this.lastTreeitem); 818 }; 819 820 TreeLinks.prototype.expandTreeitem = function (currentItem) { 821 822 if (currentItem.isExpandable) { 823 currentItem.domNode.setAttribute('aria-expanded', true); 824 this.updateVisibleTreeitems(); 825 } 826 827 }; 828 829 TreeLinks.prototype.expandAllSiblingItems = function (currentItem) { 830 for (var i = 0; i < this.treeitems.length; i++) { 831 var ti = this.treeitems[i]; 832 833 if ((ti.groupTreeitem === currentItem.groupTreeitem) && ti.isExpandable) { 834 this.expandTreeitem(ti); 835 } 836 } 837 838 }; 839 840 TreeLinks.prototype.collapseTreeitem = function (currentItem) { 841 842 var groupTreeitem = false; 843 844 if (currentItem.isExpanded()) { 845 groupTreeitem = currentItem; 846 } 847 else { 848 groupTreeitem = currentItem.groupTreeitem; 849 } 850 851 if (groupTreeitem) { 852 groupTreeitem.domNode.setAttribute('aria-expanded', false); 853 this.updateVisibleTreeitems(); 854 this.setFocusToItem(groupTreeitem); 855 } 856 857 }; 858 859 TreeLinks.prototype.updateVisibleTreeitems = function () { 860 861 this.firstTreeitem = this.treeitems[0]; 862 863 for (var i = 0; i < this.treeitems.length; i++) { 864 var ti = this.treeitems[i]; 865 866 var parent = ti.domNode.parentNode; 867 868 ti.isVisible = true; 869 870 while (parent && (parent !== this.domNode)) { 871 872 if (parent.getAttribute('aria-expanded') == 'false') { 873 ti.isVisible = false; 874 } 875 parent = parent.parentNode; 876 } 877 878 if (ti.isVisible) { 879 this.lastTreeitem = ti; 880 } 881 } 882 883 }; 884 885 TreeLinks.prototype.setFocusByFirstCharacter = function (currentItem, _char) { 886 var start, index; 887 _char = _char.toLowerCase(); 888 889 // Get start index for search based on position of currentItem 890 start = this.treeitems.indexOf(currentItem) + 1; 891 if (start === this.treeitems.length) { 892 start = 0; 893 } 894 895 // Check remaining slots in the menu 896 index = this.getIndexFirstChars(start, _char); 897 898 // If not found in remaining slots, check from beginning 899 if (index === -1) { 900 index = this.getIndexFirstChars(0, _char); 901 } 902 903 // If match was found... 904 if (index > -1) { 905 this.setFocusToItem(this.treeitems[index]); 906 } 907 }; 908 909 TreeLinks.prototype.getIndexFirstChars = function (startIndex, _char) { 910 for (var i = startIndex; i < this.firstChars.length; i++) { 911 if (this.treeitems[i].isVisible) { 912 if (_char === this.firstChars[i]) { 913 return i; 914 } 915 } 916 } 917 return -1; 918 }; 919 920 return TreeLinks; 921 })(); 922 923 /* jshint ignore:end */ 924 /* jscs:enable */ 925 /* eslint-enable */ 926 353 927 return component; 354 928 })( jQuery ); -
src/wp-admin/plugin-editor.php
diff --git src/wp-admin/plugin-editor.php src/wp-admin/plugin-editor.php index 807cd5e09d..200ebe8f5d 100644
if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) { 231 231 </div> 232 232 233 233 <div id="templateside"> 234 <h2 ><?php _e( 'Plugin Files' ); ?></h2>234 <h2 id="plugin-files-label"><?php _e( 'Plugin Files' ); ?></h2> 235 235 236 236 <?php 237 237 $plugin_editable_files = array(); … … if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) { 241 241 } 242 242 } 243 243 ?> 244 <ul> 245 <?php foreach ( $plugin_editable_files as $plugin_file ) : ?> 246 <li class="<?php echo esc_attr( $file === $plugin_file ? 'notice notice-info' : '' ); ?>"> 247 <a href="plugin-editor.php?file=<?php echo urlencode( $plugin_file ); ?>&plugin=<?php echo urlencode( $plugin ); ?>"><?php echo esc_html( preg_replace( '#^.+?/#', '', $plugin_file ) ); ?></a> 248 </li> 249 <?php endforeach; ?> 244 <ul role="tree" aria-labelledby="plugin-files-label"> 245 <li role="treeitem" tabindex="-1" aria-expanded="true" 246 aria-level="1" 247 aria-posinset="1" 248 aria-setsize="1"> 249 <ul role="group" style="padding-left: 0;"> 250 <?php wp_print_plugin_file_tree( wp_make_plugin_file_tree( $plugin_editable_files ) ); ?> 251 </ul> 250 252 </ul> 251 253 </div> 252 254 <form name="template" id="template" action="plugin-editor.php" method="post"> -
src/wp-admin/theme-editor.php
diff --git src/wp-admin/theme-editor.php src/wp-admin/theme-editor.php index 70629d914d..e275af1fda 100644
foreach ( $file_types as $type ) { 89 89 } 90 90 } 91 91 92 // Move functions.php and style.css to the top. 93 if ( isset( $allowed_files['functions.php'] ) ) { 94 $allowed_files = array( 'functions.php' => $allowed_files['functions.php'] ) + $allowed_files; 95 } 96 if ( isset( $allowed_files['style.css'] ) ) { 97 $allowed_files = array( 'style.css' => $allowed_files['style.css'] ) + $allowed_files; 98 } 99 92 100 if ( empty( $file ) ) { 93 101 $relative_file = 'style.css'; 94 102 $file = $allowed_files['style.css']; … … foreach ( wp_get_themes( array( 'errors' => null ) ) as $a_stylesheet => $a_them 205 213 if ( $theme->errors() ) 206 214 echo '<div class="error"><p><strong>' . __( 'This theme is broken.' ) . '</strong> ' . $theme->errors()->get_error_message() . '</p></div>'; 207 215 ?> 208 <div id="templateside"> 209 <?php 210 if ( $allowed_files ) : 211 $previous_file_type = ''; 212 213 foreach ( $allowed_files as $filename => $absolute_filename ) : 214 $file_type = substr( $filename, strrpos( $filename, '.' ) ); 215 216 if ( $file_type !== $previous_file_type ) { 217 if ( '' !== $previous_file_type ) { 218 echo "\t</ul>\n"; 219 } 220 221 switch ( $file_type ) { 222 case '.php': 223 if ( $has_templates || $theme->parent() ) : 224 echo "\t<h2>" . __( 'Templates' ) . "</h2>\n"; 225 if ( $theme->parent() ) { 226 echo '<p class="howto">' . sprintf( __( 'This child theme inherits templates from a parent theme, %s.' ), 227 sprintf( '<a href="%s">%s</a>', 228 self_admin_url( 'theme-editor.php?theme=' . urlencode( $theme->get_template() ) ), 229 $theme->parent()->display( 'Name' ) 230 ) 231 ) . "</p>\n"; 232 } 233 endif; 234 break; 235 case '.css': 236 echo "\t<h2>" . _x( 'Styles', 'Theme stylesheets in theme editor' ) . "</h2>\n"; 237 break; 238 default: 239 /* translators: %s: file extension */ 240 echo "\t<h2>" . sprintf( __( '%s files' ), $file_type ) . "</h2>\n"; 241 break; 242 } 243 244 echo "\t<ul>\n"; 216 <div id="templateside"> 217 <h2 id="theme-files-label"><?php _e( 'Theme Files' ); ?></h2> 218 <?php 219 if ( $has_templates || $theme->parent() ) : 220 if ( $theme->parent() ) { 221 /* translators: %s: link to edit parent theme */ 222 echo '<p class="howto">' . sprintf( __( 'This child theme inherits templates from a parent theme, %s.' ), 223 sprintf( '<a href="%s">%s</a>', 224 self_admin_url( 'theme-editor.php?theme=' . urlencode( $theme->get_template() ) ), 225 $theme->parent()->display( 'Name' ) 226 ) 227 ) . "</p>\n"; 245 228 } 246 247 $file_description = esc_html( get_file_description( $filename ) ); 248 if ( $filename !== basename( $absolute_filename ) || $file_description !== $filename ) { 249 $file_description .= '<br /><span class="nonessential">(' . esc_html( $filename ) . ')</span>'; 250 } 251 252 if ( $absolute_filename === $file ) { 253 $file_description = '<span class="notice notice-info">' . $file_description . '</span>'; 254 } 255 256 $previous_file_type = $file_type; 257 ?> 258 <li><a href="theme-editor.php?file=<?php echo urlencode( $filename ) ?>&theme=<?php echo urlencode( $stylesheet ) ?>"><?php echo $file_description; ?></a></li> 259 <?php 260 endforeach; 261 ?> 262 </ul> 263 <?php endif; ?> 229 endif; 230 ?> 231 <ul role="tree" aria-labelledby="theme-files-label"> 232 <li role="treeitem" tabindex="-1" aria-expanded="true" 233 aria-level="1" 234 aria-posinset="1" 235 aria-setsize="1"> 236 <ul role="group" style="padding-left: 0;"> 237 <?php wp_print_theme_file_tree( wp_make_theme_file_tree( $allowed_files ) ); ?> 238 </ul> 239 </li> 240 </ul> 264 241 </div> 242 265 243 <?php if ( $error ) : 266 244 echo '<div class="error"><p>' . __('Oops, no such file exists! Double check the name and try again, merci.') . '</p></div>'; 267 245 else : ?>