Ticket #24048: 24048.9.diff
File 24048.9.diff, 28.3 KB (added by , 7 years ago) |
---|
-
src/wp-admin/css/common.css
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. */ … … 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); 3042 3045 } 3046 #templateside ul ul { 3047 padding-left: 12px; 3048 } 3043 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; 3057 } 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; … … 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
270 270 } 271 271 272 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 445 /** 273 446 * Flushes rewrite rules if siteurl, home or page_on_front changed. 274 447 * 275 448 * @since 2.1.0 -
src/wp-admin/js/theme-plugin-editor.js
66 66 } ); 67 67 } 68 68 69 $( component.initFileBrowser ) 70 69 71 $( window ).on( 'beforeunload', function() { 70 72 if ( component.dirty ) { 71 73 return component.l10n.saveAlert; … … 350 352 component.instance = editor; 351 353 }; 352 354 355 /** 356 * Creates a new TreeitemLink. 357 * 358 * @since 4.9.0 359 * @class 360 * @private 361 * @see {@link https://www.w3.org/TR/wai-aria-practices-1.1/examples/treeview/treeview-2/treeview-2b.html|W3C Treeview Example} 362 * @license W3C-20150513 363 */ 364 var TreeitemLink = (function () { 365 /** 366 * This content is licensed according to the W3C Software License at 367 * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document 368 * 369 * File: TreeitemLink.js 370 * 371 * Desc: Treeitem widget that implements ARIA Authoring Practices 372 * for a tree being used as a file viewer 373 * 374 * Author: Jon Gunderson, Ku Ja Eun and Nicholas Hoyt 375 */ 376 377 /** 378 * @constructor 379 * 380 * @desc 381 * Treeitem object for representing the state and user interactions for a 382 * treeItem widget 383 * 384 * @param node 385 * An element with the role=tree attribute 386 */ 387 388 var TreeitemLink = function (node, treeObj, group) { 389 390 // Check whether node is a DOM element 391 if (typeof node !== 'object') { 392 return; 393 } 394 395 node.tabIndex = -1; 396 this.tree = treeObj; 397 this.groupTreeitem = group; 398 this.domNode = node; 399 this.label = node.textContent.trim(); 400 this.stopDefaultClick = false; 401 402 if (node.getAttribute('aria-label')) { 403 this.label = node.getAttribute('aria-label').trim(); 404 } 405 406 this.isExpandable = false; 407 this.isVisible = false; 408 this.inGroup = false; 409 410 if (group) { 411 this.inGroup = true; 412 } 413 414 var elem = node.firstElementChild; 415 416 while (elem) { 417 418 if (elem.tagName.toLowerCase() == 'ul') { 419 elem.setAttribute('role', 'group'); 420 this.isExpandable = true; 421 break; 422 } 423 424 elem = elem.nextElementSibling; 425 } 426 427 this.keyCode = Object.freeze({ 428 RETURN: 13, 429 SPACE: 32, 430 PAGEUP: 33, 431 PAGEDOWN: 34, 432 END: 35, 433 HOME: 36, 434 LEFT: 37, 435 UP: 38, 436 RIGHT: 39, 437 DOWN: 40 438 }); 439 }; 440 441 TreeitemLink.prototype.init = function () { 442 this.domNode.tabIndex = -1; 443 444 if (!this.domNode.getAttribute('role')) { 445 this.domNode.setAttribute('role', 'treeitem'); 446 } 447 448 this.domNode.addEventListener('keydown', this.handleKeydown.bind(this)); 449 this.domNode.addEventListener('click', this.handleClick.bind(this)); 450 this.domNode.addEventListener('focus', this.handleFocus.bind(this)); 451 this.domNode.addEventListener('blur', this.handleBlur.bind(this)); 452 453 if (this.isExpandable) { 454 this.domNode.firstElementChild.addEventListener('mouseover', this.handleMouseOver.bind(this)); 455 this.domNode.firstElementChild.addEventListener('mouseout', this.handleMouseOut.bind(this)); 456 } 457 else { 458 this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this)); 459 this.domNode.addEventListener('mouseout', this.handleMouseOut.bind(this)); 460 } 461 }; 462 463 TreeitemLink.prototype.isExpanded = function () { 464 465 if (this.isExpandable) { 466 return this.domNode.getAttribute('aria-expanded') === 'true'; 467 } 468 469 return false; 470 471 }; 472 473 /* EVENT HANDLERS */ 474 475 TreeitemLink.prototype.handleKeydown = function (event) { 476 var tgt = event.currentTarget, 477 flag = false, 478 char = event.key, 479 clickEvent; 480 481 function isPrintableCharacter(str) { 482 return str.length === 1 && str.match(/\S/); 483 } 484 485 function printableCharacter(item) { 486 if (char == '*') { 487 item.tree.expandAllSiblingItems(item); 488 flag = true; 489 } 490 else { 491 if (isPrintableCharacter(char)) { 492 item.tree.setFocusByFirstCharacter(item, char); 493 flag = true; 494 } 495 } 496 } 497 498 this.stopDefaultClick = false; 499 500 if (event.altKey || event.ctrlKey || event.metaKey) { 501 return; 502 } 503 504 if (event.shift) { 505 if (event.keyCode == this.keyCode.SPACE || event.keyCode == this.keyCode.RETURN) { 506 event.stopPropagation(); 507 this.stopDefaultClick = true; 508 } 509 else { 510 if (isPrintableCharacter(char)) { 511 printableCharacter(this); 512 } 513 } 514 } 515 else { 516 switch (event.keyCode) { 517 case this.keyCode.SPACE: 518 case this.keyCode.RETURN: 519 if (this.isExpandable) { 520 if (this.isExpanded()) { 521 this.tree.collapseTreeitem(this); 522 } 523 else { 524 this.tree.expandTreeitem(this); 525 } 526 flag = true; 527 } 528 else { 529 event.stopPropagation(); 530 this.stopDefaultClick = true; 531 } 532 break; 533 534 case this.keyCode.UP: 535 this.tree.setFocusToPreviousItem(this); 536 flag = true; 537 break; 538 539 case this.keyCode.DOWN: 540 this.tree.setFocusToNextItem(this); 541 flag = true; 542 break; 543 544 case this.keyCode.RIGHT: 545 if (this.isExpandable) { 546 if (this.isExpanded()) { 547 this.tree.setFocusToNextItem(this); 548 } 549 else { 550 this.tree.expandTreeitem(this); 551 } 552 } 553 flag = true; 554 break; 555 556 case this.keyCode.LEFT: 557 if (this.isExpandable && this.isExpanded()) { 558 this.tree.collapseTreeitem(this); 559 flag = true; 560 } 561 else { 562 if (this.inGroup) { 563 this.tree.setFocusToParentItem(this); 564 flag = true; 565 } 566 } 567 break; 568 569 case this.keyCode.HOME: 570 this.tree.setFocusToFirstItem(); 571 flag = true; 572 break; 573 574 case this.keyCode.END: 575 this.tree.setFocusToLastItem(); 576 flag = true; 577 break; 578 579 default: 580 if (isPrintableCharacter(char)) { 581 printableCharacter(this); 582 } 583 break; 584 } 585 } 586 587 if (flag) { 588 event.stopPropagation(); 589 event.preventDefault(); 590 } 591 }; 592 593 TreeitemLink.prototype.handleClick = function (event) { 594 595 // only process click events that directly happened on this treeitem 596 if (event.target !== this.domNode && event.target !== this.domNode.firstElementChild) { 597 return; 598 } 599 600 if (this.isExpandable) { 601 if (this.isExpanded()) { 602 this.tree.collapseTreeitem(this); 603 } 604 else { 605 this.tree.expandTreeitem(this); 606 } 607 event.stopPropagation(); 608 } 609 }; 610 611 TreeitemLink.prototype.handleFocus = function (event) { 612 var node = this.domNode; 613 if (this.isExpandable) { 614 node = node.firstElementChild; 615 } 616 node.classList.add('focus'); 617 }; 618 619 TreeitemLink.prototype.handleBlur = function (event) { 620 var node = this.domNode; 621 if (this.isExpandable) { 622 node = node.firstElementChild; 623 } 624 node.classList.remove('focus'); 625 }; 626 627 TreeitemLink.prototype.handleMouseOver = function (event) { 628 event.currentTarget.classList.add('hover'); 629 }; 630 631 TreeitemLink.prototype.handleMouseOut = function (event) { 632 event.currentTarget.classList.remove('hover'); 633 }; 634 635 return TreeitemLink; 636 })(); 637 638 /** 639 * Creates a new TreeLinks. 640 * 641 * @since 4.9.0 642 * @class 643 * @private 644 * @see {@link https://www.w3.org/TR/wai-aria-practices-1.1/examples/treeview/treeview-2/treeview-2b.html|W3C Treeview Example} 645 * @license W3C-20150513 646 */ 647 var TreeLinks = (function () { 648 /* 649 * This content is licensed according to the W3C Software License at 650 * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document 651 * 652 * File: TreeLinks.js 653 * 654 * Desc: Tree widget that implements ARIA Authoring Practices 655 * for a tree being used as a file viewer 656 * 657 * Author: Jon Gunderson, Ku Ja Eun and Nicholas Hoyt 658 */ 659 660 /* 661 * @constructor 662 * 663 * @desc 664 * Tree item object for representing the state and user interactions for a 665 * tree widget 666 * 667 * @param node 668 * An element with the role=tree attribute 669 */ 670 671 var TreeLinks = function (node) { 672 // Check whether node is a DOM element 673 if (typeof node !== 'object') { 674 return; 675 } 676 677 this.domNode = node; 678 679 this.treeitems = []; 680 this.firstChars = []; 681 682 this.firstTreeitem = null; 683 this.lastTreeitem = null; 684 685 }; 686 687 TreeLinks.prototype.init = function () { 688 689 function findTreeitems(node, tree, group) { 690 691 var elem = node.firstElementChild; 692 var ti = group; 693 694 while (elem) { 695 696 if ((elem.tagName.toLowerCase() === 'li' && elem.firstElementChild.tagName.toLowerCase() === 'span') || elem.tagName.toLowerCase() === 'a') { 697 ti = new TreeitemLink(elem, tree, group); 698 ti.init(); 699 tree.treeitems.push(ti); 700 tree.firstChars.push(ti.label.substring(0, 1).toLowerCase()); 701 } 702 703 if (elem.firstElementChild) { 704 findTreeitems(elem, tree, ti); 705 } 706 707 elem = elem.nextElementSibling; 708 } 709 } 710 711 // initialize pop up menus 712 if (!this.domNode.getAttribute('role')) { 713 this.domNode.setAttribute('role', 'tree'); 714 } 715 716 findTreeitems(this.domNode, this, false); 717 718 this.updateVisibleTreeitems(); 719 720 this.firstTreeitem.domNode.tabIndex = 0; 721 722 }; 723 724 TreeLinks.prototype.setFocusToItem = function (treeitem) { 725 726 for (var i = 0; i < this.treeitems.length; i++) { 727 var ti = this.treeitems[i]; 728 729 if (ti === treeitem) { 730 ti.domNode.tabIndex = 0; 731 ti.domNode.focus(); 732 } 733 else { 734 ti.domNode.tabIndex = -1; 735 } 736 } 737 738 }; 739 740 TreeLinks.prototype.setFocusToNextItem = function (currentItem) { 741 742 var nextItem = false; 743 744 for (var i = (this.treeitems.length - 1); i >= 0; i--) { 745 var ti = this.treeitems[i]; 746 if (ti === currentItem) { 747 break; 748 } 749 if (ti.isVisible) { 750 nextItem = ti; 751 } 752 } 753 754 if (nextItem) { 755 this.setFocusToItem(nextItem); 756 } 757 758 }; 759 760 TreeLinks.prototype.setFocusToPreviousItem = function (currentItem) { 761 762 var prevItem = false; 763 764 for (var i = 0; i < this.treeitems.length; i++) { 765 var ti = this.treeitems[i]; 766 if (ti === currentItem) { 767 break; 768 } 769 if (ti.isVisible) { 770 prevItem = ti; 771 } 772 } 773 774 if (prevItem) { 775 this.setFocusToItem(prevItem); 776 } 777 }; 778 779 TreeLinks.prototype.setFocusToParentItem = function (currentItem) { 780 781 if (currentItem.groupTreeitem) { 782 this.setFocusToItem(currentItem.groupTreeitem); 783 } 784 }; 785 786 TreeLinks.prototype.setFocusToFirstItem = function () { 787 this.setFocusToItem(this.firstTreeitem); 788 }; 789 790 TreeLinks.prototype.setFocusToLastItem = function () { 791 this.setFocusToItem(this.lastTreeitem); 792 }; 793 794 TreeLinks.prototype.expandTreeitem = function (currentItem) { 795 796 if (currentItem.isExpandable) { 797 currentItem.domNode.setAttribute('aria-expanded', true); 798 this.updateVisibleTreeitems(); 799 } 800 801 }; 802 803 TreeLinks.prototype.expandAllSiblingItems = function (currentItem) { 804 for (var i = 0; i < this.treeitems.length; i++) { 805 var ti = this.treeitems[i]; 806 807 if ((ti.groupTreeitem === currentItem.groupTreeitem) && ti.isExpandable) { 808 this.expandTreeitem(ti); 809 } 810 } 811 812 }; 813 814 TreeLinks.prototype.collapseTreeitem = function (currentItem) { 815 816 var groupTreeitem = false; 817 818 if (currentItem.isExpanded()) { 819 groupTreeitem = currentItem; 820 } 821 else { 822 groupTreeitem = currentItem.groupTreeitem; 823 } 824 825 if (groupTreeitem) { 826 groupTreeitem.domNode.setAttribute('aria-expanded', false); 827 this.updateVisibleTreeitems(); 828 this.setFocusToItem(groupTreeitem); 829 } 830 831 }; 832 833 TreeLinks.prototype.updateVisibleTreeitems = function () { 834 835 this.firstTreeitem = this.treeitems[0]; 836 837 for (var i = 0; i < this.treeitems.length; i++) { 838 var ti = this.treeitems[i]; 839 840 var parent = ti.domNode.parentNode; 841 842 ti.isVisible = true; 843 844 while (parent && (parent !== this.domNode)) { 845 846 if (parent.getAttribute('aria-expanded') == 'false') { 847 ti.isVisible = false; 848 } 849 parent = parent.parentNode; 850 } 851 852 if (ti.isVisible) { 853 this.lastTreeitem = ti; 854 } 855 } 856 857 }; 858 859 TreeLinks.prototype.setFocusByFirstCharacter = function (currentItem, char) { 860 var start, index, char = char.toLowerCase(); 861 862 // Get start index for search based on position of currentItem 863 start = this.treeitems.indexOf(currentItem) + 1; 864 if (start === this.treeitems.length) { 865 start = 0; 866 } 867 868 // Check remaining slots in the menu 869 index = this.getIndexFirstChars(start, char); 870 871 // If not found in remaining slots, check from beginning 872 if (index === -1) { 873 index = this.getIndexFirstChars(0, char); 874 } 875 876 // If match was found... 877 if (index > -1) { 878 this.setFocusToItem(this.treeitems[index]); 879 } 880 }; 881 882 TreeLinks.prototype.getIndexFirstChars = function (startIndex, char) { 883 for (var i = startIndex; i < this.firstChars.length; i++) { 884 if (this.treeitems[i].isVisible) { 885 if (char === this.firstChars[i]) { 886 return i; 887 } 888 } 889 } 890 return -1; 891 }; 892 893 return TreeLinks; 894 })(); 895 896 /** 897 * Initialization of the file browser's folder states. 898 * 899 * @since 4.9.0 900 * @returns {void} 901 */ 902 component.initFileBrowser = function initFileBrowser() { 903 // Collapse all folders. 904 $('#templateside [role="group"]').parent().attr('aria-expanded', false); 905 906 // Expand ancestors to the current file. 907 $('#templateside .notice').parents('[aria-expanded]').attr('aria-expanded', true); 908 909 // Find Tree elements and enhance them. 910 var trees = document.querySelectorAll('[role="tree"]'); 911 912 for (var i = 0; i < trees.length; i++) { 913 var t = new TreeLinks(trees[i]); 914 t.init(); 915 } 916 } 917 353 918 return component; 354 919 })( jQuery ); -
src/wp-admin/plugin-editor.php
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(); … … 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
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']; … … 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 } 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> 241 </div> 246 242 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 <?php260 endforeach;261 ?>262 </ul>263 <?php endif; ?>264 </div>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 : ?>