diff --git a/wp-admin/css/customize-nav-menus-rtl.css b/wp-admin/css/customize-nav-menus-rtl.css new file mode 100644 index 0000000000..be793e52d9 --- /dev/null +++ b/wp-admin/css/customize-nav-menus-rtl.css @@ -0,0 +1,964 @@ +#accordion-section-menu_locations { + position: relative; + margin-bottom: 15px; +} + +.menu-in-location, +.menu-in-locations { + display: block; + color: #999; + font-weight: 600; + font-size: 10px; +} + +#customize-controls .control-section .accordion-section-title:focus .menu-in-location, +#customize-controls .control-section .accordion-section-title:hover .menu-in-location, +#customize-controls .control-section .accordion-section-title:focus .menu-in-locations, +#customize-controls .control-section .accordion-section-title:hover .menu-in-locations { + color: #fff; +} + +.wp-customizer .menu-item-bar .menu-item-handle, +.wp-customizer .menu-item-settings, +.wp-customizer .menu-item-settings .description-thin { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.wp-customizer .menu-item-bar { + margin: 0; +} + +.wp-customizer .menu-item-bar .menu-item-handle { + max-width: 100%; + background: #fff; +} + +.wp-customizer .menu-item-handle .item-title { + margin-left: 0; +} + +.wp-customizer .menu-item-handle .item-type { + padding: 1px 5px 0 15px; + float: left; + text-align: left; +} + +.wp-customizer .menu-item-settings { + max-width: 100%; + overflow: hidden; + padding: 10px; + background: #eee; + border: 1px solid #999; + border-top: none; +} + +.wp-customizer .menu-item-settings .description-thin { + width: 100%; + height: auto; + margin: 0 0 8px 0; +} + +.wp-customizer .menu-item-settings input[type="text"] { + width: 100%; +} + +.wp-customizer .menu-item-settings .submitbox { + margin: 0; + padding: 0; +} + +.wp-customizer .menu-item-settings .link-to-original { + padding: 5px 0; + border: none; + font-style: normal; + margin: 0; + width: 100%; +} + +.wp-customizer .menu-item .submitbox .submitdelete { + display: block; + float: right; + margin: 6px 0 0; + padding: 0; + cursor: pointer; +} + +.wp-customizer .menu-item .submitbox .submitdelete:focus { + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +/* Menu-item reordering nav. */ +#customize-theme-controls button.reorder-toggle { + padding: 5px 8px; +} + +.menu-item-reorder-nav { + display: none; + background-color: #fff; + position: absolute; + top: 0; + left: 0; +} + +#customize-theme-controls .reordering .add-new-menu-item { + opacity: 0.2; + pointer-events: none; + cursor: not-allowed; +} + +.menu-item-reorder-nav button { + position: relative; + overflow: hidden; + float: right; + display: block; + width: 30px; + height: 40px; + color: #82878c; + text-indent: -9999px; + cursor: pointer; + background: transparent; + border: none; + -webkit-box-shadow: none; + box-shadow: none; + outline: none; +} + +.menu-item-reorder-nav button:before { + display: inline-block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + font: normal 20px/40px dashicons; + text-align: center; + text-indent: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.menu-item-reorder-nav button:hover, +.menu-item-reorder-nav button:focus { + color: #191e23; + background: #eee; +} + +.menus-move-down:before { + content: '\f347'; +} + +.menus-move-up:before { + content: '\f343'; +} + +.menus-move-left:before { + content: '\f341'; +} + +.menus-move-right:before { + content: '\f345'; +} + +.move-up-disabled .menus-move-up, +.move-down-disabled .menus-move-down, +.move-right-disabled .menus-move-right, +.move-left-disabled .menus-move-left, +.menu-item-depth-0 .menus-move-left, +.menu-item-depth-10 .menus-move-right { + color: #d5d5d5 !important; + background-color: #fff !important; + cursor: default; + pointer-events: none; +} + +.menu-item-reorder-nav:before { + content: ""; + display: block; + position: absolute; + right: -10px; + width: 10px; + height: 40px; + background: -webkit-linear-gradient(right, rgba(250,250,250,0) 0%,rgba(250,250,250,1) 100%); + background: -webkit-gradient(linear, right top, left top, from(rgba(250,250,250,0)), to(rgba(250,250,250,1))); + background: -webkit-linear-gradient(right, rgba(250,250,250,0) 0%, rgba(250,250,250,1) 100%); + background: linear-gradient(to left, rgba(250,250,250,0) 0%,rgba(250,250,250,1) 100%); +} + +.reordering .menu-item .item-controls, +.reordering .menu-item .item-type { + display: none; +} + +.reordering .menu-item-reorder-nav { + display: block; +} + +.customize-control input.menu-name-field { + width: 100%; /* Override the 98% default for customizer inputs, to align with the size of menu items. */ + margin: 12px 0; +} + +.wp-customizer .menu-item .item-edit { + position: absolute; + left: -19px; + top: 2px; + display: block; + width: 30px; + height: 38px; + margin-left: 0 !important; + text-indent: 100%; + outline: none; + overflow: hidden; + white-space: nowrap; + cursor: pointer; +} + +.customize-control-nav_menu_item .item-edit:focus { + color: #0073aa; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +/* Duplicates `.nav-menus-php .item-edit:before {}` in common.css:2220. */ +.wp-customizer .menu-item .item-edit:before { + top: -1px; + left: 0; + content: '\f140'; + border: none; + background: none; + font: normal 20px/1 dashicons; + speak: none; + display: block; + padding: 0; + text-indent: 0; + text-align: center; + position: relative; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-decoration: none !important; +} + +.wp-customizer .menu-item.menu-item-edit-active .item-edit:before { + content: '\f142'; +} + +.wp-customizer .menu-item .item-edit:before { + line-height: 2; +} + +/* Duplicates `.nav-menus-php .menu-item-edit-active .item-edit:before {}` in common.css:2271. */ +.wp-customizer .menu-item .menu-item-edit-active .item-edit:before { + content: '\f142'; +} + +.wp-customizer .menu-item-settings p.description { + font-style: normal; +} + +.wp-customizer .menu-settings dl { + margin: 12px 0 0 0; + padding: 0; +} + +.wp-customizer .menu-settings .checkbox-input { + margin-top: 8px; +} + +.wp-customizer .menu-settings .menu-theme-locations { + border-top: 1px solid #ccc; +} + +.wp-customizer .menu-settings { + margin-top: 36px; + border-top: none; +} + +.menu-settings .customize-control-checkbox label { + line-height: 1; +} + +/* @todo update selector or potentially remove */ +.menu-settings .customize-control.customize-control-checkbox { + margin-bottom: 8px; /* Override collapsing at smaller viewports. */ +} + +.customize-control-menu { + margin-top: 4px; +} + +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle { + color: #555; +} + +/* Screen Options */ +.customize-screen-options-toggle { + background: none; + border: none; + color: #555; + cursor: pointer; + padding: 20px; + position: absolute; + left: 31px; + top: 4px; +} + +#customize-controls .customize-info .customize-help-toggle { + padding: 20px; +} + +#customize-controls .customize-info .customize-help-toggle:before { + padding: 5px; +} + +.customize-screen-options-toggle:hover, +.customize-screen-options-toggle:active, +.customize-screen-options-toggle:focus, +.active-menu-screen-options .customize-screen-options-toggle, +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:hover, +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:active, +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:focus { + color: #0073aa; +} + +.customize-screen-options-toggle:focus, +#customize-controls .customize-info .customize-help-toggle:focus { + outline: none; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +.customize-screen-options-toggle:before { + -moz-osx-font-smoothing: grayscale; + border: none; + content: "\f111"; + display: block; + font: 20px/1 "dashicons"; + padding: 5px; + text-align: center; + text-decoration: none !important; + text-indent: 0; + right: 5px; + position: absolute; + top: 5px; +} + +.wp-customizer #screen-options-wrap { + display: none; + background: #fff; + border-top: 1px solid #ddd; + padding: 4px 15px 0; +} + +.wp-customizer .metabox-prefs label { + display: block; + padding-left: 0; + line-height: 30px; +} + +#accordion-panel-menus .field-link-target, +#accordion-panel-menus .field-attr-title, +#accordion-panel-menus .field-css-classes, +#accordion-panel-menus .field-xfn, +#accordion-panel-menus .field-description { + display: none; +} + +#accordion-panel-menus.field-link-target-active .field-link-target, +#accordion-panel-menus.field-attr-title-active .field-attr-title, +#accordion-panel-menus.field-css-classes-active .field-css-classes, +#accordion-panel-menus.field-xfn-active .field-xfn, +#accordion-panel-menus.field-description-active .field-description { + display: block; +} + + +/* Not exactly sure what broke this, or why it works without these styles in core. */ +.wp-customizer .wp-full-overlay a.collapse-sidebar { + position: fixed; + right: 0; +} + +/* WARNING: The 20px factor is hard-coded in JS. */ +.menu-item-depth-0 { margin-right: 0; } +.menu-item-depth-1 { margin-right: 20px; } +.menu-item-depth-2 { margin-right: 40px; } +.menu-item-depth-3 { margin-right: 60px; } +.menu-item-depth-4 { margin-right: 80px; } +.menu-item-depth-5 { margin-right: 100px; } +.menu-item-depth-6 { margin-right: 120px; } +.menu-item-depth-7 { margin-right: 140px; } +.menu-item-depth-8 { margin-right: 160px; } /* Not likely to be used or useful beyond this depth */ +.menu-item-depth-9 { margin-right: 180px; } +.menu-item-depth-10 { margin-right: 200px; } +.menu-item-depth-11 { margin-right: 220px; } + +/* @todo handle .menu-item-settings width */ +.menu-item-depth-0 > .menu-item-bar { margin-left: 0; } +.menu-item-depth-1 > .menu-item-bar { margin-left: 20px; } +.menu-item-depth-2 > .menu-item-bar { margin-left: 40px; } +.menu-item-depth-3 > .menu-item-bar { margin-left: 60px; } +.menu-item-depth-4 > .menu-item-bar { margin-left: 80px; } +.menu-item-depth-5 > .menu-item-bar { margin-left: 100px; } +.menu-item-depth-6 > .menu-item-bar { margin-left: 120px; } +.menu-item-depth-7 > .menu-item-bar { margin-left: 140px; } +.menu-item-depth-8 > .menu-item-bar { margin-left: 160px; } +.menu-item-depth-9 > .menu-item-bar { margin-left: 180px; } +.menu-item-depth-10 > .menu-item-bar { margin-left: 200px; } +.menu-item-depth-11 > .menu-item-bar { margin-left: 220px; } + +/* Submenu left margin. */ +/* @todo menu-item-transport seems entirely unused. */ +.menu-item-depth-0 .menu-item-transport { margin-right: 0; } +.menu-item-depth-1 .menu-item-transport { margin-right: -20px; } +.menu-item-depth-3 .menu-item-transport { margin-right: -60px; } +.menu-item-depth-4 .menu-item-transport { margin-right: -80px; } +.menu-item-depth-2 .menu-item-transport { margin-right: -40px; } +.menu-item-depth-5 .menu-item-transport { margin-right: -100px; } +.menu-item-depth-6 .menu-item-transport { margin-right: -120px; } +.menu-item-depth-7 .menu-item-transport { margin-right: -140px; } +.menu-item-depth-8 .menu-item-transport { margin-right: -160px; } +.menu-item-depth-9 .menu-item-transport { margin-right: -180px; } +.menu-item-depth-10 .menu-item-transport { margin-right: -200px; } +.menu-item-depth-11 .menu-item-transport { margin-right: -220px; } + +/* WARNING: The 20px factor is hard-coded in JS. */ +.reordering .menu-item-depth-0 { margin-right: 0; } +.reordering .menu-item-depth-1 { margin-right: 15px; } +.reordering .menu-item-depth-2 { margin-right: 30px; } +.reordering .menu-item-depth-3 { margin-right: 45px; } +.reordering .menu-item-depth-4 { margin-right: 60px; } +.reordering .menu-item-depth-5 { margin-right: 75px; } +.reordering .menu-item-depth-6 { margin-right: 90px; } +.reordering .menu-item-depth-7 { margin-right: 105px; } +.reordering .menu-item-depth-8 { margin-right: 120px; } /* Not likely to be used or useful beyond this depth */ +.reordering .menu-item-depth-9 { margin-right: 135px; } +.reordering .menu-item-depth-10 { margin-right: 150px; } +.reordering .menu-item-depth-11 { margin-right: 165px; } + +.reordering .menu-item-depth-0 > .menu-item-bar { margin-left: 0; } +.reordering .menu-item-depth-1 > .menu-item-bar { margin-left: 15px; } +.reordering .menu-item-depth-2 > .menu-item-bar { margin-left: 30px; } +.reordering .menu-item-depth-3 > .menu-item-bar { margin-left: 45px; } +.reordering .menu-item-depth-4 > .menu-item-bar { margin-left: 60px; } +.reordering .menu-item-depth-5 > .menu-item-bar { margin-left: 75px; } +.reordering .menu-item-depth-6 > .menu-item-bar { margin-left: 90px; } +.reordering .menu-item-depth-7 > .menu-item-bar { margin-left: 105px; } +.reordering .menu-item-depth-8 > .menu-item-bar { margin-left: 120px; } +.reordering .menu-item-depth-9 > .menu-item-bar { margin-left: 135px; } +.reordering .menu-item-depth-10 > .menu-item-bar { margin-left: 150px; } +.reordering .menu-item-depth-11 > .menu-item-bar { margin-left: 165px; } + +.control-section-nav_menu .menu .menu-item-edit-active { + margin-right: 0; +} + +.control-section-nav_menu .menu .menu-item-edit-active .menu-item-bar { + margin-left: 0; +} + +.control-section-nav_menu .menu .sortable-placeholder { + margin-top: 0; + margin-bottom: 1px; + max-width: -webkit-calc(100% - 2px); + max-width: calc(100% - 2px); + float: right; + display: list-item; + border-color: #a0a5aa; +} + +.control-section-nav_menu .menu ul.menu-item-transport dl { + margin-top: 0; +} + +/* + * Add-menu-items mode. + */ +.wp-full-overlay-main { + left: auto; /* This overrides a right: 0; which causes the preview to resize rather than slide off screen at the normal size. */ + width: 100%; +} + +.adding-menu-items .control-section { + opacity: .4; +} + +.adding-menu-items .control-panel.control-section, +.adding-menu-items .control-section.open { + opacity: 1; +} + +/* Add-new button. */ +#customize-theme-controls .add-new-menu-item { + cursor: pointer; + float: left; + margin-right: 10px; + -webkit-transition: all 0.2s; + transition: all 0.2s; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + outline: none; +} + +.add-new-menu-item:before { + content: "\f132"; + display: inline-block; + position: relative; + right: -2px; + top: -1px; + font: normal 20px/1 'dashicons'; + vertical-align: middle; + -webkit-transition: all 0.2s; + transition: all 0.2s; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.adding-menu-items .add-new-menu-item, +.adding-menu-items .add-new-menu-item:hover, +.add-menu-toggle.open, +.add-menu-toggle.open:hover { + background: #eee; + border-color: #929793; + color: #32373c; + -webkit-box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); + box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); +} + +.adding-menu-items .add-new-menu-item:before, +#accordion-section-add_menu .add-new-menu-item.open:before { + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.menu-item-bar .item-delete { + color: #a00; + position: absolute; + top: 2px; + left: -19px; + width: 30px; + height: 38px; + cursor: pointer; + display: none; +} + +.menu-item-bar .item-delete:before { + content: "\f335"; + font: normal 20px/1 dashicons; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + position: absolute; + top: 9px; + right: 5px; +} + +.menu-item-bar .item-delete:hover, +.menu-item-bar .item-delete:focus { + color: #f00; +} + +.adding-menu-items .menu-item-bar .item-edit { + display: none; +} + +.adding-menu-items .menu-item-bar .item-delete { + display: block; +} + +#available-menu-items .item { + position: static; +} + +#available-menu-items { + position: absolute; + overflow: hidden; + top: 0; + bottom: 0; + right: -301px; + width: 300px; + margin: 0; + z-index: 4; + background: #eee; + -webkit-transition: all 0.2s; + transition: all 0.2s; + border-left: 1px solid #ddd; +} + +#available-menu-items.allow-scroll { + overflow-y: auto; +} + +#available-menu-items .accordion-section-title { + border-right: none; + border-left: none; + background: #fff; +} + +#available-menu-items .open .accordion-section-title { + background: #eee; +} + +#available-menu-items .open .accordion-section-title:after { + content: '\f142'; +} + +#available-menu-items .accordion-section-content { + overflow-y: auto; + max-height: 200px; /* This gets set in JS to fit the screen size, and based on # of sections. */ + background: transparent; +} + +button.not-a-button { + background: transparent; + border: none; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 0; + border-radius: 0; + outline: 0; + padding: 0; + margin: 0; +} + +#available-menu-items .accordion-section-title button:focus:before { + display: block; + content: ""; + width: 28px; + height: 32px; + position: absolute; + left: 5px; + top: 5px; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +#available-menu-items .accordion-section-content { + padding: 1px 15px 15px 15px; + min-height: 120px; + max-height: 290px; +} + +#custom-menu-item-name.invalid, +#custom-menu-item-url.invalid { + border: 1px solid #f00; +} + +#available-menu-items .item-tpl { + position: relative; + padding: 20px 60px 20px 15px; + border-bottom: 1px solid #e4e4e4; + cursor: pointer; + display: none; +} + +#available-menu-items .item-tpl:hover, +#available-menu-items .item-tpl.selected { + background: #eee; +} + +#available-menu-items .menu-item-handle .item-type { + padding-left: 0; +} + +#available-menu-items .menu-item-handle .item-title { + padding-right: 20px; +} + +#available-menu-items .menu-item-handle { + cursor: pointer; +} + +#available-menu-items .item-top, +#available-menu-items .item-top:hover { + border: none; + background: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} + +#available-menu-items .menu-item-handle { + -webkit-box-shadow: none; + box-shadow: none; + margin-top: -1px; +} + +#available-menu-items .menu-item-handle:hover { + z-index: 1; +} + +#available-menu-items .item-title h4 { + padding: 0 0 5px; + font-size: 14px; +} + +#available-menu-items .item-add { + position: absolute; + top: 1px; + right: 1px; + color: #82878c; + width: 30px; + height: 38px; + cursor: pointer; +} + +#available-menu-items .menu-item-handle .item-add:focus { + color: #23282d; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +#available-menu-items .item-add:before { + content: "\f132"; + font: normal 20px/1 dashicons; + position: relative; + right: 2px; + top: 4px; +} + +#available-menu-items .menu-item-handle.item-added .item-type, +#available-menu-items .menu-item-handle.item-added .item-title, +#available-menu-items .menu-item-handle.item-added:hover .item-add, +#available-menu-items .menu-item-handle.item-added .item-add:focus { + color: #82878c; +} + +#available-menu-items .menu-item-handle.item-added .item-add:before { + content: "\f147"; +} + +#available-menu-items .accordion-section-title.loading .spinner, +#available-menu-items-search.loading .accordion-section-title .spinner { + visibility: visible; + margin: 0 20px; +} + +#available-menu-items-search .spinner { + position: absolute; + top: 18px; + margin: 0 !important; + left: 20px; +} + +#available-menu-items-search input { + padding: 6px 10px; + width: 100%; +} + +#available-menu-items-search .accordion-section-title { + padding: 12px 15px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +#available-menu-items-search .accordion-section-title:after { + display: none; +} + +#available-menu-items-search .accordion-section-content:empty { + min-height: 0; + padding: 0; +} + +#available-menu-items-search.loading .accordion-section-content div { + opacity: .5; +} + +#available-menu-items-search.loading.loading-more .accordion-section-content div { + opacity: 1; +} + +#customize-preview { + -webkit-transition: all 0.2s; + transition: all 0.2s; +} + +body.adding-menu-items #available-menu-items { + right: 0; +} + +body.adding-menu-items .wp-full-overlay-main { + right: 300px; +} + +body.adding-menu-items #customize-preview { + opacity: 0.4; +} + +.menu-item-handle .spinner { + display: none; + float: right; + margin: 0 0 0 8px; +} + +.nav-menu-inserted-item-loading .spinner { + display: block; +} + +.nav-menu-inserted-item-loading .menu-item-handle .item-type { + padding: 0 8px 0 0; +} + +.nav-menu-inserted-item-loading .menu-item-handle, +.added-menu-item .menu-item-handle.loading { + padding: 10px 8px 10px 15px; + cursor: default; + opacity: .5; + background: #fff; + color: #727773; +} + +.added-menu-item .menu-item-handle { + -webkit-transition-property: opacity, background, color; + transition-property: opacity, background, color; + -webkit-transition-duration: 1.25s; + transition-duration: 1.25s; + -webkit-transition-timing-function: cubic-bezier( .25, -2.5, .75, 8 ); + transition-timing-function: cubic-bezier( .25, -2.5, .75, 8 ); /* Replacement for .hide().fadeIn('slow') in JS to add emphasis when it's loaded. */ +} + +/* Add/delete Menus */ + +/* @todo update selector */ +#accordion-section-add_menu { + margin: 15px 12px; +} + +.new-menu-section-content { + display: none; + padding: 15px 0 0 0; + overflow: hidden; + clear: both; +} + +/* @todo update selector */ +#accordion-section-add_menu .accordion-section-title { + padding-right: 45px; +} + +/* @todo update selector */ +#accordion-section-add_menu .accordion-section-title:before { + font: normal 20px/1 dashicons; + position: absolute; + top: 12px; + right: 14px; + content: "\f132"; +} + +#create-new-menu-submit { + float: left; + margin: 0 0 12px 0; +} + +.menu-delete-item { + display: block; + float: right; + padding: 1em 0; + width: 100%; +} + +li.assigned-to-menu-location .menu-delete-item { + display: none; +} + +li.assigned-to-menu-location .add-new-menu-item { + margin-bottom: 1em; +} + +.menu-delete { + color: #a00; + cursor: pointer; + text-decoration: underline; +} + +.menu-delete:hover, +.menu-delete:focus { + color: #f00; + text-decoration: none; +} + +.menu-delete:focus { + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +.menu-item-handle { + margin-top: -1px; +} +.ui-sortable-disabled .menu-item-handle { + cursor: default; +} + +.menu-item-handle:hover { + position: relative; + z-index: 10; + color: #0073aa; +} + +.menu-item-handle:hover .item-type, +.menu-item-handle:hover .item-edit, +#available-menu-items .menu-item-handle:hover .item-add { + color: #0073aa; +} + +.menu-item-edit-active .menu-item-handle { + border-color: #999; + border-bottom: none; +} + +.customize-control-nav_menu_item { + margin-bottom: 0; +} + +.customize-control-nav_menu { + margin-top: 12px; +} + +#available-menu-items .customize-section-title { + display: none; +} + +@media screen and ( max-width: 640px ) { + body.adding-menu-items div#available-menu-items { + top: 46px; + right: 0; + z-index: 10; + width: 100%; + } + + #available-menu-items .customize-section-title { + display: block; + margin: 0; + } + + #available-menu-items .customize-section-back { + height: 69px; + } + + #available-menu-items .customize-section-title h3 { + font-size: 20px; + font-weight: 200; + padding: 9px 14px 12px 10px; + margin: 0; + line-height: 24px; + color: #555; + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + #available-menu-items .customize-section-title .customize-action { + font-size: 13px; + display: block; + font-weight: 400; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } +} diff --git a/wp-admin/css/customize-nav-menus-rtl.min.css b/wp-admin/css/customize-nav-menus-rtl.min.css new file mode 100644 index 0000000000..376efffaaa --- /dev/null +++ b/wp-admin/css/customize-nav-menus-rtl.min.css @@ -0,0 +1 @@ +#accordion-section-menu_locations{position:relative;margin-bottom:15px}.menu-in-location,.menu-in-locations{display:block;color:#999;font-weight:600;font-size:10px}#customize-controls .control-section .accordion-section-title:focus .menu-in-location,#customize-controls .control-section .accordion-section-title:focus .menu-in-locations,#customize-controls .control-section .accordion-section-title:hover .menu-in-location,#customize-controls .control-section .accordion-section-title:hover .menu-in-locations{color:#fff}.wp-customizer .menu-item-bar .menu-item-handle,.wp-customizer .menu-item-settings,.wp-customizer .menu-item-settings .description-thin{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.wp-customizer .menu-item-bar{margin:0}.wp-customizer .menu-item-bar .menu-item-handle{max-width:100%;background:#fff}.wp-customizer .menu-item-handle .item-title{margin-left:0}.wp-customizer .menu-item-handle .item-type{padding:1px 5px 0 15px;float:left;text-align:left}.wp-customizer .menu-item-settings{max-width:100%;overflow:hidden;padding:10px;background:#eee;border:1px solid #999;border-top:none}.wp-customizer .menu-item-settings .description-thin{width:100%;height:auto;margin:0 0 8px}.wp-customizer .menu-item-settings input[type=text]{width:100%}.wp-customizer .menu-item-settings .submitbox{margin:0;padding:0}.wp-customizer .menu-item-settings .link-to-original{padding:5px 0;border:none;font-style:normal;margin:0;width:100%}.wp-customizer .menu-item .submitbox .submitdelete{display:block;float:right;margin:6px 0 0;padding:0;cursor:pointer}.wp-customizer .menu-item .submitbox .submitdelete:focus{-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}#customize-theme-controls button.reorder-toggle{padding:5px 8px}.menu-item-reorder-nav{display:none;background-color:#fff;position:absolute;top:0;left:0}#customize-theme-controls .reordering .add-new-menu-item{opacity:.2;pointer-events:none;cursor:not-allowed}.menu-item-reorder-nav button{position:relative;overflow:hidden;float:right;display:block;width:30px;height:40px;color:#82878c;text-indent:-9999px;cursor:pointer;background:0 0;border:none;-webkit-box-shadow:none;box-shadow:none;outline:0}.menu-item-reorder-nav button:before{display:inline-block;position:absolute;top:0;left:0;width:100%;height:100%;font:400 20px/40px dashicons;text-align:center;text-indent:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.menu-item-reorder-nav button:focus,.menu-item-reorder-nav button:hover{color:#191e23;background:#eee}.menus-move-down:before{content:'\f347'}.menus-move-up:before{content:'\f343'}.menus-move-left:before{content:'\f341'}.menus-move-right:before{content:'\f345'}.menu-item-depth-0 .menus-move-left,.menu-item-depth-10 .menus-move-right,.move-down-disabled .menus-move-down,.move-left-disabled .menus-move-left,.move-right-disabled .menus-move-right,.move-up-disabled .menus-move-up{color:#d5d5d5!important;background-color:#fff!important;cursor:default;pointer-events:none}.menu-item-reorder-nav:before{content:"";display:block;position:absolute;right:-10px;width:10px;height:40px;background:-webkit-gradient(linear,right top,left top,from(rgba(250,250,250,0)),to(rgba(250,250,250,1)));background:-webkit-linear-gradient(right,rgba(250,250,250,0) 0,rgba(250,250,250,1) 100%);background:linear-gradient(to left,rgba(250,250,250,0) 0,rgba(250,250,250,1) 100%)}.reordering .menu-item .item-controls,.reordering .menu-item .item-type{display:none}.reordering .menu-item-reorder-nav{display:block}.customize-control input.menu-name-field{width:100%;margin:12px 0}.wp-customizer .menu-item .item-edit{position:absolute;left:-19px;top:2px;display:block;width:30px;height:38px;margin-left:0!important;text-indent:100%;outline:0;overflow:hidden;white-space:nowrap;cursor:pointer}.customize-control-nav_menu_item .item-edit:focus{color:#0073aa;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}.wp-customizer .menu-item .item-edit:before{top:-1px;left:0;content:'\f140';border:none;background:0 0;font:400 20px/1 dashicons;speak:none;display:block;padding:0;text-indent:0;text-align:center;position:relative;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none!important}.wp-customizer .menu-item.menu-item-edit-active .item-edit:before{content:'\f142'}.wp-customizer .menu-item .item-edit:before{line-height:2}.wp-customizer .menu-item .menu-item-edit-active .item-edit:before{content:'\f142'}.wp-customizer .menu-item-settings p.description{font-style:normal}.wp-customizer .menu-settings dl{margin:12px 0 0;padding:0}.wp-customizer .menu-settings .checkbox-input{margin-top:8px}.wp-customizer .menu-settings .menu-theme-locations{border-top:1px solid #ccc}.wp-customizer .menu-settings{margin-top:36px;border-top:none}.menu-settings .customize-control-checkbox label{line-height:1}.menu-settings .customize-control.customize-control-checkbox{margin-bottom:8px}.customize-control-menu{margin-top:4px}#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle{color:#555}.customize-screen-options-toggle{background:0 0;border:none;color:#555;cursor:pointer;padding:20px;position:absolute;left:31px;top:4px}#customize-controls .customize-info .customize-help-toggle{padding:20px}#customize-controls .customize-info .customize-help-toggle:before{padding:5px}#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:active,#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:focus,#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:hover,.active-menu-screen-options .customize-screen-options-toggle,.customize-screen-options-toggle:active,.customize-screen-options-toggle:focus,.customize-screen-options-toggle:hover{color:#0073aa}#customize-controls .customize-info .customize-help-toggle:focus,.customize-screen-options-toggle:focus{outline:0;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}.customize-screen-options-toggle:before{-moz-osx-font-smoothing:grayscale;border:none;content:"\f111";display:block;font:20px/1 dashicons;padding:5px;text-align:center;text-decoration:none!important;text-indent:0;right:5px;position:absolute;top:5px}.wp-customizer #screen-options-wrap{display:none;background:#fff;border-top:1px solid #ddd;padding:4px 15px 0}.wp-customizer .metabox-prefs label{display:block;padding-left:0;line-height:30px}#accordion-panel-menus .field-attr-title,#accordion-panel-menus .field-css-classes,#accordion-panel-menus .field-description,#accordion-panel-menus .field-link-target,#accordion-panel-menus .field-xfn{display:none}#accordion-panel-menus.field-attr-title-active .field-attr-title,#accordion-panel-menus.field-css-classes-active .field-css-classes,#accordion-panel-menus.field-description-active .field-description,#accordion-panel-menus.field-link-target-active .field-link-target,#accordion-panel-menus.field-xfn-active .field-xfn{display:block}.wp-customizer .wp-full-overlay a.collapse-sidebar{position:fixed;right:0}.menu-item-depth-0{margin-right:0}.menu-item-depth-1{margin-right:20px}.menu-item-depth-2{margin-right:40px}.menu-item-depth-3{margin-right:60px}.menu-item-depth-4{margin-right:80px}.menu-item-depth-5{margin-right:100px}.menu-item-depth-6{margin-right:120px}.menu-item-depth-7{margin-right:140px}.menu-item-depth-8{margin-right:160px}.menu-item-depth-9{margin-right:180px}.menu-item-depth-10{margin-right:200px}.menu-item-depth-11{margin-right:220px}.menu-item-depth-0>.menu-item-bar{margin-left:0}.menu-item-depth-1>.menu-item-bar{margin-left:20px}.menu-item-depth-2>.menu-item-bar{margin-left:40px}.menu-item-depth-3>.menu-item-bar{margin-left:60px}.menu-item-depth-4>.menu-item-bar{margin-left:80px}.menu-item-depth-5>.menu-item-bar{margin-left:100px}.menu-item-depth-6>.menu-item-bar{margin-left:120px}.menu-item-depth-7>.menu-item-bar{margin-left:140px}.menu-item-depth-8>.menu-item-bar{margin-left:160px}.menu-item-depth-9>.menu-item-bar{margin-left:180px}.menu-item-depth-10>.menu-item-bar{margin-left:200px}.menu-item-depth-11>.menu-item-bar{margin-left:220px}.menu-item-depth-0 .menu-item-transport{margin-right:0}.menu-item-depth-1 .menu-item-transport{margin-right:-20px}.menu-item-depth-3 .menu-item-transport{margin-right:-60px}.menu-item-depth-4 .menu-item-transport{margin-right:-80px}.menu-item-depth-2 .menu-item-transport{margin-right:-40px}.menu-item-depth-5 .menu-item-transport{margin-right:-100px}.menu-item-depth-6 .menu-item-transport{margin-right:-120px}.menu-item-depth-7 .menu-item-transport{margin-right:-140px}.menu-item-depth-8 .menu-item-transport{margin-right:-160px}.menu-item-depth-9 .menu-item-transport{margin-right:-180px}.menu-item-depth-10 .menu-item-transport{margin-right:-200px}.menu-item-depth-11 .menu-item-transport{margin-right:-220px}.reordering .menu-item-depth-0{margin-right:0}.reordering .menu-item-depth-1{margin-right:15px}.reordering .menu-item-depth-2{margin-right:30px}.reordering .menu-item-depth-3{margin-right:45px}.reordering .menu-item-depth-4{margin-right:60px}.reordering .menu-item-depth-5{margin-right:75px}.reordering .menu-item-depth-6{margin-right:90px}.reordering .menu-item-depth-7{margin-right:105px}.reordering .menu-item-depth-8{margin-right:120px}.reordering .menu-item-depth-9{margin-right:135px}.reordering .menu-item-depth-10{margin-right:150px}.reordering .menu-item-depth-11{margin-right:165px}.reordering .menu-item-depth-0>.menu-item-bar{margin-left:0}.reordering .menu-item-depth-1>.menu-item-bar{margin-left:15px}.reordering .menu-item-depth-2>.menu-item-bar{margin-left:30px}.reordering .menu-item-depth-3>.menu-item-bar{margin-left:45px}.reordering .menu-item-depth-4>.menu-item-bar{margin-left:60px}.reordering .menu-item-depth-5>.menu-item-bar{margin-left:75px}.reordering .menu-item-depth-6>.menu-item-bar{margin-left:90px}.reordering .menu-item-depth-7>.menu-item-bar{margin-left:105px}.reordering .menu-item-depth-8>.menu-item-bar{margin-left:120px}.reordering .menu-item-depth-9>.menu-item-bar{margin-left:135px}.reordering .menu-item-depth-10>.menu-item-bar{margin-left:150px}.reordering .menu-item-depth-11>.menu-item-bar{margin-left:165px}.control-section-nav_menu .menu .menu-item-edit-active{margin-right:0}.control-section-nav_menu .menu .menu-item-edit-active .menu-item-bar{margin-left:0}.control-section-nav_menu .menu .sortable-placeholder{margin-top:0;margin-bottom:1px;max-width:-webkit-calc(100% - 2px);max-width:calc(100% - 2px);float:right;display:list-item;border-color:#a0a5aa}.control-section-nav_menu .menu ul.menu-item-transport dl{margin-top:0}.wp-full-overlay-main{left:auto;width:100%}.adding-menu-items .control-section{opacity:.4}.adding-menu-items .control-panel.control-section,.adding-menu-items .control-section.open{opacity:1}#customize-theme-controls .add-new-menu-item{cursor:pointer;float:left;margin-right:10px;-webkit-transition:all .2s;transition:all .2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:0}.add-new-menu-item:before{content:"\f132";display:inline-block;position:relative;right:-2px;top:-1px;font:400 20px/1 dashicons;vertical-align:middle;-webkit-transition:all .2s;transition:all .2s;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.add-menu-toggle.open,.add-menu-toggle.open:hover,.adding-menu-items .add-new-menu-item,.adding-menu-items .add-new-menu-item:hover{background:#eee;border-color:#929793;color:#32373c;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}#accordion-section-add_menu .add-new-menu-item.open:before,.adding-menu-items .add-new-menu-item:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.menu-item-bar .item-delete{color:#a00;position:absolute;top:2px;left:-19px;width:30px;height:38px;cursor:pointer;display:none}.menu-item-bar .item-delete:before{content:"\f335";font:400 20px/1 dashicons;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;position:absolute;top:9px;right:5px}.menu-item-bar .item-delete:focus,.menu-item-bar .item-delete:hover{color:red}.adding-menu-items .menu-item-bar .item-edit{display:none}.adding-menu-items .menu-item-bar .item-delete{display:block}#available-menu-items .item{position:static}#available-menu-items{position:absolute;overflow:hidden;top:0;bottom:0;right:-301px;width:300px;margin:0;z-index:4;background:#eee;-webkit-transition:all .2s;transition:all .2s;border-left:1px solid #ddd}#available-menu-items.allow-scroll{overflow-y:auto}#available-menu-items .accordion-section-title{border-right:none;border-left:none;background:#fff}#available-menu-items .open .accordion-section-title{background:#eee}#available-menu-items .open .accordion-section-title:after{content:'\f142'}#available-menu-items .accordion-section-content{overflow-y:auto;background:0 0}button.not-a-button{background:0 0;border:none;-webkit-box-shadow:none;box-shadow:none;-webkit-border-radius:0;border-radius:0;outline:0;padding:0;margin:0}#available-menu-items .accordion-section-title button:focus:before{display:block;content:"";width:28px;height:32px;position:absolute;left:5px;top:5px;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}#available-menu-items .accordion-section-content{padding:1px 15px 15px;min-height:120px;max-height:290px}#custom-menu-item-name.invalid,#custom-menu-item-url.invalid{border:1px solid red}#available-menu-items .item-tpl{position:relative;padding:20px 60px 20px 15px;border-bottom:1px solid #e4e4e4;cursor:pointer;display:none}#available-menu-items .item-tpl.selected,#available-menu-items .item-tpl:hover{background:#eee}#available-menu-items .menu-item-handle .item-type{padding-left:0}#available-menu-items .menu-item-handle .item-title{padding-right:20px}#available-menu-items .menu-item-handle{cursor:pointer}#available-menu-items .item-top,#available-menu-items .item-top:hover{border:none;background:0 0;-webkit-box-shadow:none;box-shadow:none}#available-menu-items .menu-item-handle{-webkit-box-shadow:none;box-shadow:none;margin-top:-1px}#available-menu-items .menu-item-handle:hover{z-index:1}#available-menu-items .item-title h4{padding:0 0 5px;font-size:14px}#available-menu-items .item-add{position:absolute;top:1px;right:1px;color:#82878c;width:30px;height:38px;cursor:pointer}#available-menu-items .menu-item-handle .item-add:focus{color:#23282d;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}#available-menu-items .item-add:before{content:"\f132";font:400 20px/1 dashicons;position:relative;right:2px;top:4px}#available-menu-items .menu-item-handle.item-added .item-add:focus,#available-menu-items .menu-item-handle.item-added .item-title,#available-menu-items .menu-item-handle.item-added .item-type,#available-menu-items .menu-item-handle.item-added:hover .item-add{color:#82878c}#available-menu-items .menu-item-handle.item-added .item-add:before{content:"\f147"}#available-menu-items .accordion-section-title.loading .spinner,#available-menu-items-search.loading .accordion-section-title .spinner{visibility:visible;margin:0 20px}#available-menu-items-search .spinner{position:absolute;top:18px;margin:0!important;left:20px}#available-menu-items-search input{padding:6px 10px;width:100%}#available-menu-items-search .accordion-section-title{padding:12px 15px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#available-menu-items-search .accordion-section-title:after{display:none}#available-menu-items-search .accordion-section-content:empty{min-height:0;padding:0}#available-menu-items-search.loading .accordion-section-content div{opacity:.5}#available-menu-items-search.loading.loading-more .accordion-section-content div{opacity:1}#customize-preview{-webkit-transition:all .2s;transition:all .2s}body.adding-menu-items #available-menu-items{right:0}body.adding-menu-items .wp-full-overlay-main{right:300px}body.adding-menu-items #customize-preview{opacity:.4}.menu-item-handle .spinner{display:none;float:right;margin:0 0 0 8px}.nav-menu-inserted-item-loading .spinner{display:block}.nav-menu-inserted-item-loading .menu-item-handle .item-type{padding:0 8px 0 0}.added-menu-item .menu-item-handle.loading,.nav-menu-inserted-item-loading .menu-item-handle{padding:10px 8px 10px 15px;cursor:default;opacity:.5;background:#fff;color:#727773}.added-menu-item .menu-item-handle{-webkit-transition-property:opacity,background,color;transition-property:opacity,background,color;-webkit-transition-duration:1.25s;transition-duration:1.25s;-webkit-transition-timing-function:cubic-bezier(.25,-2.5,.75,8);transition-timing-function:cubic-bezier(.25,-2.5,.75,8)}#accordion-section-add_menu{margin:15px 12px}.new-menu-section-content{display:none;padding:15px 0 0;overflow:hidden;clear:both}#accordion-section-add_menu .accordion-section-title{padding-right:45px}#accordion-section-add_menu .accordion-section-title:before{font:400 20px/1 dashicons;position:absolute;top:12px;right:14px;content:"\f132"}#create-new-menu-submit{float:left;margin:0 0 12px}.menu-delete-item{display:block;float:right;padding:1em 0;width:100%}li.assigned-to-menu-location .menu-delete-item{display:none}li.assigned-to-menu-location .add-new-menu-item{margin-bottom:1em}.menu-delete{color:#a00;cursor:pointer;text-decoration:underline}.menu-delete:focus,.menu-delete:hover{color:red;text-decoration:none}.menu-delete:focus{-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}.menu-item-handle{margin-top:-1px}.ui-sortable-disabled .menu-item-handle{cursor:default}.menu-item-handle:hover{position:relative;z-index:10;color:#0073aa}#available-menu-items .menu-item-handle:hover .item-add,.menu-item-handle:hover .item-edit,.menu-item-handle:hover .item-type{color:#0073aa}.menu-item-edit-active .menu-item-handle{border-color:#999;border-bottom:none}.customize-control-nav_menu_item{margin-bottom:0}.customize-control-nav_menu{margin-top:12px}#available-menu-items .customize-section-title{display:none}@media screen and (max-width:640px){body.adding-menu-items div#available-menu-items{top:46px;right:0;z-index:10;width:100%}#available-menu-items .customize-section-title{display:block;margin:0}#available-menu-items .customize-section-back{height:69px}#available-menu-items .customize-section-title h3{font-size:20px;font-weight:200;padding:9px 14px 12px 10px;margin:0;line-height:24px;color:#555;display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}#available-menu-items .customize-section-title .customize-action{font-size:13px;display:block;font-weight:400;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}} \ No newline at end of file diff --git a/wp-admin/css/customize-nav-menus.css b/wp-admin/css/customize-nav-menus.css new file mode 100644 index 0000000000..9c4fd1366e --- /dev/null +++ b/wp-admin/css/customize-nav-menus.css @@ -0,0 +1,964 @@ +#accordion-section-menu_locations { + position: relative; + margin-bottom: 15px; +} + +.menu-in-location, +.menu-in-locations { + display: block; + color: #999; + font-weight: 600; + font-size: 10px; +} + +#customize-controls .control-section .accordion-section-title:focus .menu-in-location, +#customize-controls .control-section .accordion-section-title:hover .menu-in-location, +#customize-controls .control-section .accordion-section-title:focus .menu-in-locations, +#customize-controls .control-section .accordion-section-title:hover .menu-in-locations { + color: #fff; +} + +.wp-customizer .menu-item-bar .menu-item-handle, +.wp-customizer .menu-item-settings, +.wp-customizer .menu-item-settings .description-thin { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.wp-customizer .menu-item-bar { + margin: 0; +} + +.wp-customizer .menu-item-bar .menu-item-handle { + max-width: 100%; + background: #fff; +} + +.wp-customizer .menu-item-handle .item-title { + margin-right: 0; +} + +.wp-customizer .menu-item-handle .item-type { + padding: 1px 15px 0 5px; + float: right; + text-align: right; +} + +.wp-customizer .menu-item-settings { + max-width: 100%; + overflow: hidden; + padding: 10px; + background: #eee; + border: 1px solid #999; + border-top: none; +} + +.wp-customizer .menu-item-settings .description-thin { + width: 100%; + height: auto; + margin: 0 0 8px 0; +} + +.wp-customizer .menu-item-settings input[type="text"] { + width: 100%; +} + +.wp-customizer .menu-item-settings .submitbox { + margin: 0; + padding: 0; +} + +.wp-customizer .menu-item-settings .link-to-original { + padding: 5px 0; + border: none; + font-style: normal; + margin: 0; + width: 100%; +} + +.wp-customizer .menu-item .submitbox .submitdelete { + display: block; + float: left; + margin: 6px 0 0; + padding: 0; + cursor: pointer; +} + +.wp-customizer .menu-item .submitbox .submitdelete:focus { + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +/* Menu-item reordering nav. */ +#customize-theme-controls button.reorder-toggle { + padding: 5px 8px; +} + +.menu-item-reorder-nav { + display: none; + background-color: #fff; + position: absolute; + top: 0; + right: 0; +} + +#customize-theme-controls .reordering .add-new-menu-item { + opacity: 0.2; + pointer-events: none; + cursor: not-allowed; +} + +.menu-item-reorder-nav button { + position: relative; + overflow: hidden; + float: left; + display: block; + width: 30px; + height: 40px; + color: #82878c; + text-indent: -9999px; + cursor: pointer; + background: transparent; + border: none; + -webkit-box-shadow: none; + box-shadow: none; + outline: none; +} + +.menu-item-reorder-nav button:before { + display: inline-block; + position: absolute; + top: 0; + right: 0; + width: 100%; + height: 100%; + font: normal 20px/40px dashicons; + text-align: center; + text-indent: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.menu-item-reorder-nav button:hover, +.menu-item-reorder-nav button:focus { + color: #191e23; + background: #eee; +} + +.menus-move-down:before { + content: '\f347'; +} + +.menus-move-up:before { + content: '\f343'; +} + +.menus-move-left:before { + content: '\f341'; +} + +.menus-move-right:before { + content: '\f345'; +} + +.move-up-disabled .menus-move-up, +.move-down-disabled .menus-move-down, +.move-right-disabled .menus-move-right, +.move-left-disabled .menus-move-left, +.menu-item-depth-0 .menus-move-left, +.menu-item-depth-10 .menus-move-right { + color: #d5d5d5 !important; + background-color: #fff !important; + cursor: default; + pointer-events: none; +} + +.menu-item-reorder-nav:before { + content: ""; + display: block; + position: absolute; + left: -10px; + width: 10px; + height: 40px; + background: -webkit-linear-gradient(left, rgba(250,250,250,0) 0%,rgba(250,250,250,1) 100%); + background: -webkit-gradient(linear, left top, right top, from(rgba(250,250,250,0)), to(rgba(250,250,250,1))); + background: -webkit-linear-gradient(left, rgba(250,250,250,0) 0%, rgba(250,250,250,1) 100%); + background: linear-gradient(to right, rgba(250,250,250,0) 0%,rgba(250,250,250,1) 100%); +} + +.reordering .menu-item .item-controls, +.reordering .menu-item .item-type { + display: none; +} + +.reordering .menu-item-reorder-nav { + display: block; +} + +.customize-control input.menu-name-field { + width: 100%; /* Override the 98% default for customizer inputs, to align with the size of menu items. */ + margin: 12px 0; +} + +.wp-customizer .menu-item .item-edit { + position: absolute; + right: -19px; + top: 2px; + display: block; + width: 30px; + height: 38px; + margin-right: 0 !important; + text-indent: 100%; + outline: none; + overflow: hidden; + white-space: nowrap; + cursor: pointer; +} + +.customize-control-nav_menu_item .item-edit:focus { + color: #0073aa; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +/* Duplicates `.nav-menus-php .item-edit:before {}` in common.css:2220. */ +.wp-customizer .menu-item .item-edit:before { + top: -1px; + right: 0; + content: '\f140'; + border: none; + background: none; + font: normal 20px/1 dashicons; + speak: none; + display: block; + padding: 0; + text-indent: 0; + text-align: center; + position: relative; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-decoration: none !important; +} + +.wp-customizer .menu-item.menu-item-edit-active .item-edit:before { + content: '\f142'; +} + +.wp-customizer .menu-item .item-edit:before { + line-height: 2; +} + +/* Duplicates `.nav-menus-php .menu-item-edit-active .item-edit:before {}` in common.css:2271. */ +.wp-customizer .menu-item .menu-item-edit-active .item-edit:before { + content: '\f142'; +} + +.wp-customizer .menu-item-settings p.description { + font-style: normal; +} + +.wp-customizer .menu-settings dl { + margin: 12px 0 0 0; + padding: 0; +} + +.wp-customizer .menu-settings .checkbox-input { + margin-top: 8px; +} + +.wp-customizer .menu-settings .menu-theme-locations { + border-top: 1px solid #ccc; +} + +.wp-customizer .menu-settings { + margin-top: 36px; + border-top: none; +} + +.menu-settings .customize-control-checkbox label { + line-height: 1; +} + +/* @todo update selector or potentially remove */ +.menu-settings .customize-control.customize-control-checkbox { + margin-bottom: 8px; /* Override collapsing at smaller viewports. */ +} + +.customize-control-menu { + margin-top: 4px; +} + +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle { + color: #555; +} + +/* Screen Options */ +.customize-screen-options-toggle { + background: none; + border: none; + color: #555; + cursor: pointer; + padding: 20px; + position: absolute; + right: 31px; + top: 4px; +} + +#customize-controls .customize-info .customize-help-toggle { + padding: 20px; +} + +#customize-controls .customize-info .customize-help-toggle:before { + padding: 5px; +} + +.customize-screen-options-toggle:hover, +.customize-screen-options-toggle:active, +.customize-screen-options-toggle:focus, +.active-menu-screen-options .customize-screen-options-toggle, +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:hover, +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:active, +#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:focus { + color: #0073aa; +} + +.customize-screen-options-toggle:focus, +#customize-controls .customize-info .customize-help-toggle:focus { + outline: none; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +.customize-screen-options-toggle:before { + -moz-osx-font-smoothing: grayscale; + border: none; + content: "\f111"; + display: block; + font: 20px/1 "dashicons"; + padding: 5px; + text-align: center; + text-decoration: none !important; + text-indent: 0; + left: 5px; + position: absolute; + top: 5px; +} + +.wp-customizer #screen-options-wrap { + display: none; + background: #fff; + border-top: 1px solid #ddd; + padding: 4px 15px 0; +} + +.wp-customizer .metabox-prefs label { + display: block; + padding-right: 0; + line-height: 30px; +} + +#accordion-panel-menus .field-link-target, +#accordion-panel-menus .field-attr-title, +#accordion-panel-menus .field-css-classes, +#accordion-panel-menus .field-xfn, +#accordion-panel-menus .field-description { + display: none; +} + +#accordion-panel-menus.field-link-target-active .field-link-target, +#accordion-panel-menus.field-attr-title-active .field-attr-title, +#accordion-panel-menus.field-css-classes-active .field-css-classes, +#accordion-panel-menus.field-xfn-active .field-xfn, +#accordion-panel-menus.field-description-active .field-description { + display: block; +} + + +/* Not exactly sure what broke this, or why it works without these styles in core. */ +.wp-customizer .wp-full-overlay a.collapse-sidebar { + position: fixed; + left: 0; +} + +/* WARNING: The 20px factor is hard-coded in JS. */ +.menu-item-depth-0 { margin-left: 0; } +.menu-item-depth-1 { margin-left: 20px; } +.menu-item-depth-2 { margin-left: 40px; } +.menu-item-depth-3 { margin-left: 60px; } +.menu-item-depth-4 { margin-left: 80px; } +.menu-item-depth-5 { margin-left: 100px; } +.menu-item-depth-6 { margin-left: 120px; } +.menu-item-depth-7 { margin-left: 140px; } +.menu-item-depth-8 { margin-left: 160px; } /* Not likely to be used or useful beyond this depth */ +.menu-item-depth-9 { margin-left: 180px; } +.menu-item-depth-10 { margin-left: 200px; } +.menu-item-depth-11 { margin-left: 220px; } + +/* @todo handle .menu-item-settings width */ +.menu-item-depth-0 > .menu-item-bar { margin-right: 0; } +.menu-item-depth-1 > .menu-item-bar { margin-right: 20px; } +.menu-item-depth-2 > .menu-item-bar { margin-right: 40px; } +.menu-item-depth-3 > .menu-item-bar { margin-right: 60px; } +.menu-item-depth-4 > .menu-item-bar { margin-right: 80px; } +.menu-item-depth-5 > .menu-item-bar { margin-right: 100px; } +.menu-item-depth-6 > .menu-item-bar { margin-right: 120px; } +.menu-item-depth-7 > .menu-item-bar { margin-right: 140px; } +.menu-item-depth-8 > .menu-item-bar { margin-right: 160px; } +.menu-item-depth-9 > .menu-item-bar { margin-right: 180px; } +.menu-item-depth-10 > .menu-item-bar { margin-right: 200px; } +.menu-item-depth-11 > .menu-item-bar { margin-right: 220px; } + +/* Submenu left margin. */ +/* @todo menu-item-transport seems entirely unused. */ +.menu-item-depth-0 .menu-item-transport { margin-left: 0; } +.menu-item-depth-1 .menu-item-transport { margin-left: -20px; } +.menu-item-depth-3 .menu-item-transport { margin-left: -60px; } +.menu-item-depth-4 .menu-item-transport { margin-left: -80px; } +.menu-item-depth-2 .menu-item-transport { margin-left: -40px; } +.menu-item-depth-5 .menu-item-transport { margin-left: -100px; } +.menu-item-depth-6 .menu-item-transport { margin-left: -120px; } +.menu-item-depth-7 .menu-item-transport { margin-left: -140px; } +.menu-item-depth-8 .menu-item-transport { margin-left: -160px; } +.menu-item-depth-9 .menu-item-transport { margin-left: -180px; } +.menu-item-depth-10 .menu-item-transport { margin-left: -200px; } +.menu-item-depth-11 .menu-item-transport { margin-left: -220px; } + +/* WARNING: The 20px factor is hard-coded in JS. */ +.reordering .menu-item-depth-0 { margin-left: 0; } +.reordering .menu-item-depth-1 { margin-left: 15px; } +.reordering .menu-item-depth-2 { margin-left: 30px; } +.reordering .menu-item-depth-3 { margin-left: 45px; } +.reordering .menu-item-depth-4 { margin-left: 60px; } +.reordering .menu-item-depth-5 { margin-left: 75px; } +.reordering .menu-item-depth-6 { margin-left: 90px; } +.reordering .menu-item-depth-7 { margin-left: 105px; } +.reordering .menu-item-depth-8 { margin-left: 120px; } /* Not likely to be used or useful beyond this depth */ +.reordering .menu-item-depth-9 { margin-left: 135px; } +.reordering .menu-item-depth-10 { margin-left: 150px; } +.reordering .menu-item-depth-11 { margin-left: 165px; } + +.reordering .menu-item-depth-0 > .menu-item-bar { margin-right: 0; } +.reordering .menu-item-depth-1 > .menu-item-bar { margin-right: 15px; } +.reordering .menu-item-depth-2 > .menu-item-bar { margin-right: 30px; } +.reordering .menu-item-depth-3 > .menu-item-bar { margin-right: 45px; } +.reordering .menu-item-depth-4 > .menu-item-bar { margin-right: 60px; } +.reordering .menu-item-depth-5 > .menu-item-bar { margin-right: 75px; } +.reordering .menu-item-depth-6 > .menu-item-bar { margin-right: 90px; } +.reordering .menu-item-depth-7 > .menu-item-bar { margin-right: 105px; } +.reordering .menu-item-depth-8 > .menu-item-bar { margin-right: 120px; } +.reordering .menu-item-depth-9 > .menu-item-bar { margin-right: 135px; } +.reordering .menu-item-depth-10 > .menu-item-bar { margin-right: 150px; } +.reordering .menu-item-depth-11 > .menu-item-bar { margin-right: 165px; } + +.control-section-nav_menu .menu .menu-item-edit-active { + margin-left: 0; +} + +.control-section-nav_menu .menu .menu-item-edit-active .menu-item-bar { + margin-right: 0; +} + +.control-section-nav_menu .menu .sortable-placeholder { + margin-top: 0; + margin-bottom: 1px; + max-width: -webkit-calc(100% - 2px); + max-width: calc(100% - 2px); + float: left; + display: list-item; + border-color: #a0a5aa; +} + +.control-section-nav_menu .menu ul.menu-item-transport dl { + margin-top: 0; +} + +/* + * Add-menu-items mode. + */ +.wp-full-overlay-main { + right: auto; /* This overrides a right: 0; which causes the preview to resize rather than slide off screen at the normal size. */ + width: 100%; +} + +.adding-menu-items .control-section { + opacity: .4; +} + +.adding-menu-items .control-panel.control-section, +.adding-menu-items .control-section.open { + opacity: 1; +} + +/* Add-new button. */ +#customize-theme-controls .add-new-menu-item { + cursor: pointer; + float: right; + margin-left: 10px; + -webkit-transition: all 0.2s; + transition: all 0.2s; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + outline: none; +} + +.add-new-menu-item:before { + content: "\f132"; + display: inline-block; + position: relative; + left: -2px; + top: -1px; + font: normal 20px/1 'dashicons'; + vertical-align: middle; + -webkit-transition: all 0.2s; + transition: all 0.2s; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.adding-menu-items .add-new-menu-item, +.adding-menu-items .add-new-menu-item:hover, +.add-menu-toggle.open, +.add-menu-toggle.open:hover { + background: #eee; + border-color: #929793; + color: #32373c; + -webkit-box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); + box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); +} + +.adding-menu-items .add-new-menu-item:before, +#accordion-section-add_menu .add-new-menu-item.open:before { + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.menu-item-bar .item-delete { + color: #a00; + position: absolute; + top: 2px; + right: -19px; + width: 30px; + height: 38px; + cursor: pointer; + display: none; +} + +.menu-item-bar .item-delete:before { + content: "\f335"; + font: normal 20px/1 dashicons; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + position: absolute; + top: 9px; + left: 5px; +} + +.menu-item-bar .item-delete:hover, +.menu-item-bar .item-delete:focus { + color: #f00; +} + +.adding-menu-items .menu-item-bar .item-edit { + display: none; +} + +.adding-menu-items .menu-item-bar .item-delete { + display: block; +} + +#available-menu-items .item { + position: static; +} + +#available-menu-items { + position: absolute; + overflow: hidden; + top: 0; + bottom: 0; + left: -301px; + width: 300px; + margin: 0; + z-index: 4; + background: #eee; + -webkit-transition: all 0.2s; + transition: all 0.2s; + border-right: 1px solid #ddd; +} + +#available-menu-items.allow-scroll { + overflow-y: auto; +} + +#available-menu-items .accordion-section-title { + border-left: none; + border-right: none; + background: #fff; +} + +#available-menu-items .open .accordion-section-title { + background: #eee; +} + +#available-menu-items .open .accordion-section-title:after { + content: '\f142'; +} + +#available-menu-items .accordion-section-content { + overflow-y: auto; + max-height: 200px; /* This gets set in JS to fit the screen size, and based on # of sections. */ + background: transparent; +} + +button.not-a-button { + background: transparent; + border: none; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 0; + border-radius: 0; + outline: 0; + padding: 0; + margin: 0; +} + +#available-menu-items .accordion-section-title button:focus:before { + display: block; + content: ""; + width: 28px; + height: 32px; + position: absolute; + right: 5px; + top: 5px; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +#available-menu-items .accordion-section-content { + padding: 1px 15px 15px 15px; + min-height: 120px; + max-height: 290px; +} + +#custom-menu-item-name.invalid, +#custom-menu-item-url.invalid { + border: 1px solid #f00; +} + +#available-menu-items .item-tpl { + position: relative; + padding: 20px 15px 20px 60px; + border-bottom: 1px solid #e4e4e4; + cursor: pointer; + display: none; +} + +#available-menu-items .item-tpl:hover, +#available-menu-items .item-tpl.selected { + background: #eee; +} + +#available-menu-items .menu-item-handle .item-type { + padding-right: 0; +} + +#available-menu-items .menu-item-handle .item-title { + padding-left: 20px; +} + +#available-menu-items .menu-item-handle { + cursor: pointer; +} + +#available-menu-items .item-top, +#available-menu-items .item-top:hover { + border: none; + background: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} + +#available-menu-items .menu-item-handle { + -webkit-box-shadow: none; + box-shadow: none; + margin-top: -1px; +} + +#available-menu-items .menu-item-handle:hover { + z-index: 1; +} + +#available-menu-items .item-title h4 { + padding: 0 0 5px; + font-size: 14px; +} + +#available-menu-items .item-add { + position: absolute; + top: 1px; + left: 1px; + color: #82878c; + width: 30px; + height: 38px; + cursor: pointer; +} + +#available-menu-items .menu-item-handle .item-add:focus { + color: #23282d; + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +#available-menu-items .item-add:before { + content: "\f132"; + font: normal 20px/1 dashicons; + position: relative; + left: 2px; + top: 4px; +} + +#available-menu-items .menu-item-handle.item-added .item-type, +#available-menu-items .menu-item-handle.item-added .item-title, +#available-menu-items .menu-item-handle.item-added:hover .item-add, +#available-menu-items .menu-item-handle.item-added .item-add:focus { + color: #82878c; +} + +#available-menu-items .menu-item-handle.item-added .item-add:before { + content: "\f147"; +} + +#available-menu-items .accordion-section-title.loading .spinner, +#available-menu-items-search.loading .accordion-section-title .spinner { + visibility: visible; + margin: 0 20px; +} + +#available-menu-items-search .spinner { + position: absolute; + top: 18px; + margin: 0 !important; + right: 20px; +} + +#available-menu-items-search input { + padding: 6px 10px; + width: 100%; +} + +#available-menu-items-search .accordion-section-title { + padding: 12px 15px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +#available-menu-items-search .accordion-section-title:after { + display: none; +} + +#available-menu-items-search .accordion-section-content:empty { + min-height: 0; + padding: 0; +} + +#available-menu-items-search.loading .accordion-section-content div { + opacity: .5; +} + +#available-menu-items-search.loading.loading-more .accordion-section-content div { + opacity: 1; +} + +#customize-preview { + -webkit-transition: all 0.2s; + transition: all 0.2s; +} + +body.adding-menu-items #available-menu-items { + left: 0; +} + +body.adding-menu-items .wp-full-overlay-main { + left: 300px; +} + +body.adding-menu-items #customize-preview { + opacity: 0.4; +} + +.menu-item-handle .spinner { + display: none; + float: left; + margin: 0 8px 0 0; +} + +.nav-menu-inserted-item-loading .spinner { + display: block; +} + +.nav-menu-inserted-item-loading .menu-item-handle .item-type { + padding: 0 0 0 8px; +} + +.nav-menu-inserted-item-loading .menu-item-handle, +.added-menu-item .menu-item-handle.loading { + padding: 10px 15px 10px 8px; + cursor: default; + opacity: .5; + background: #fff; + color: #727773; +} + +.added-menu-item .menu-item-handle { + -webkit-transition-property: opacity, background, color; + transition-property: opacity, background, color; + -webkit-transition-duration: 1.25s; + transition-duration: 1.25s; + -webkit-transition-timing-function: cubic-bezier( .25, -2.5, .75, 8 ); + transition-timing-function: cubic-bezier( .25, -2.5, .75, 8 ); /* Replacement for .hide().fadeIn('slow') in JS to add emphasis when it's loaded. */ +} + +/* Add/delete Menus */ + +/* @todo update selector */ +#accordion-section-add_menu { + margin: 15px 12px; +} + +.new-menu-section-content { + display: none; + padding: 15px 0 0 0; + overflow: hidden; + clear: both; +} + +/* @todo update selector */ +#accordion-section-add_menu .accordion-section-title { + padding-left: 45px; +} + +/* @todo update selector */ +#accordion-section-add_menu .accordion-section-title:before { + font: normal 20px/1 dashicons; + position: absolute; + top: 12px; + left: 14px; + content: "\f132"; +} + +#create-new-menu-submit { + float: right; + margin: 0 0 12px 0; +} + +.menu-delete-item { + display: block; + float: left; + padding: 1em 0; + width: 100%; +} + +li.assigned-to-menu-location .menu-delete-item { + display: none; +} + +li.assigned-to-menu-location .add-new-menu-item { + margin-bottom: 1em; +} + +.menu-delete { + color: #a00; + cursor: pointer; + text-decoration: underline; +} + +.menu-delete:hover, +.menu-delete:focus { + color: #f00; + text-decoration: none; +} + +.menu-delete:focus { + -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); +} + +.menu-item-handle { + margin-top: -1px; +} +.ui-sortable-disabled .menu-item-handle { + cursor: default; +} + +.menu-item-handle:hover { + position: relative; + z-index: 10; + color: #0073aa; +} + +.menu-item-handle:hover .item-type, +.menu-item-handle:hover .item-edit, +#available-menu-items .menu-item-handle:hover .item-add { + color: #0073aa; +} + +.menu-item-edit-active .menu-item-handle { + border-color: #999; + border-bottom: none; +} + +.customize-control-nav_menu_item { + margin-bottom: 0; +} + +.customize-control-nav_menu { + margin-top: 12px; +} + +#available-menu-items .customize-section-title { + display: none; +} + +@media screen and ( max-width: 640px ) { + body.adding-menu-items div#available-menu-items { + top: 46px; + left: 0; + z-index: 10; + width: 100%; + } + + #available-menu-items .customize-section-title { + display: block; + margin: 0; + } + + #available-menu-items .customize-section-back { + height: 69px; + } + + #available-menu-items .customize-section-title h3 { + font-size: 20px; + font-weight: 200; + padding: 9px 10px 12px 14px; + margin: 0; + line-height: 24px; + color: #555; + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + #available-menu-items .customize-section-title .customize-action { + font-size: 13px; + display: block; + font-weight: 400; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } +} diff --git a/wp-admin/css/customize-nav-menus.min.css b/wp-admin/css/customize-nav-menus.min.css new file mode 100644 index 0000000000..70fc05884a --- /dev/null +++ b/wp-admin/css/customize-nav-menus.min.css @@ -0,0 +1 @@ +#accordion-section-menu_locations{position:relative;margin-bottom:15px}.menu-in-location,.menu-in-locations{display:block;color:#999;font-weight:600;font-size:10px}#customize-controls .control-section .accordion-section-title:focus .menu-in-location,#customize-controls .control-section .accordion-section-title:focus .menu-in-locations,#customize-controls .control-section .accordion-section-title:hover .menu-in-location,#customize-controls .control-section .accordion-section-title:hover .menu-in-locations{color:#fff}.wp-customizer .menu-item-bar .menu-item-handle,.wp-customizer .menu-item-settings,.wp-customizer .menu-item-settings .description-thin{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.wp-customizer .menu-item-bar{margin:0}.wp-customizer .menu-item-bar .menu-item-handle{max-width:100%;background:#fff}.wp-customizer .menu-item-handle .item-title{margin-right:0}.wp-customizer .menu-item-handle .item-type{padding:1px 15px 0 5px;float:right;text-align:right}.wp-customizer .menu-item-settings{max-width:100%;overflow:hidden;padding:10px;background:#eee;border:1px solid #999;border-top:none}.wp-customizer .menu-item-settings .description-thin{width:100%;height:auto;margin:0 0 8px}.wp-customizer .menu-item-settings input[type=text]{width:100%}.wp-customizer .menu-item-settings .submitbox{margin:0;padding:0}.wp-customizer .menu-item-settings .link-to-original{padding:5px 0;border:none;font-style:normal;margin:0;width:100%}.wp-customizer .menu-item .submitbox .submitdelete{display:block;float:left;margin:6px 0 0;padding:0;cursor:pointer}.wp-customizer .menu-item .submitbox .submitdelete:focus{-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}#customize-theme-controls button.reorder-toggle{padding:5px 8px}.menu-item-reorder-nav{display:none;background-color:#fff;position:absolute;top:0;right:0}#customize-theme-controls .reordering .add-new-menu-item{opacity:.2;pointer-events:none;cursor:not-allowed}.menu-item-reorder-nav button{position:relative;overflow:hidden;float:left;display:block;width:30px;height:40px;color:#82878c;text-indent:-9999px;cursor:pointer;background:0 0;border:none;-webkit-box-shadow:none;box-shadow:none;outline:0}.menu-item-reorder-nav button:before{display:inline-block;position:absolute;top:0;right:0;width:100%;height:100%;font:400 20px/40px dashicons;text-align:center;text-indent:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.menu-item-reorder-nav button:focus,.menu-item-reorder-nav button:hover{color:#191e23;background:#eee}.menus-move-down:before{content:'\f347'}.menus-move-up:before{content:'\f343'}.menus-move-left:before{content:'\f341'}.menus-move-right:before{content:'\f345'}.menu-item-depth-0 .menus-move-left,.menu-item-depth-10 .menus-move-right,.move-down-disabled .menus-move-down,.move-left-disabled .menus-move-left,.move-right-disabled .menus-move-right,.move-up-disabled .menus-move-up{color:#d5d5d5!important;background-color:#fff!important;cursor:default;pointer-events:none}.menu-item-reorder-nav:before{content:"";display:block;position:absolute;left:-10px;width:10px;height:40px;background:-webkit-gradient(linear,left top,right top,from(rgba(250,250,250,0)),to(rgba(250,250,250,1)));background:-webkit-linear-gradient(left,rgba(250,250,250,0) 0,rgba(250,250,250,1) 100%);background:linear-gradient(to right,rgba(250,250,250,0) 0,rgba(250,250,250,1) 100%)}.reordering .menu-item .item-controls,.reordering .menu-item .item-type{display:none}.reordering .menu-item-reorder-nav{display:block}.customize-control input.menu-name-field{width:100%;margin:12px 0}.wp-customizer .menu-item .item-edit{position:absolute;right:-19px;top:2px;display:block;width:30px;height:38px;margin-right:0!important;text-indent:100%;outline:0;overflow:hidden;white-space:nowrap;cursor:pointer}.customize-control-nav_menu_item .item-edit:focus{color:#0073aa;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}.wp-customizer .menu-item .item-edit:before{top:-1px;right:0;content:'\f140';border:none;background:0 0;font:400 20px/1 dashicons;speak:none;display:block;padding:0;text-indent:0;text-align:center;position:relative;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none!important}.wp-customizer .menu-item.menu-item-edit-active .item-edit:before{content:'\f142'}.wp-customizer .menu-item .item-edit:before{line-height:2}.wp-customizer .menu-item .menu-item-edit-active .item-edit:before{content:'\f142'}.wp-customizer .menu-item-settings p.description{font-style:normal}.wp-customizer .menu-settings dl{margin:12px 0 0;padding:0}.wp-customizer .menu-settings .checkbox-input{margin-top:8px}.wp-customizer .menu-settings .menu-theme-locations{border-top:1px solid #ccc}.wp-customizer .menu-settings{margin-top:36px;border-top:none}.menu-settings .customize-control-checkbox label{line-height:1}.menu-settings .customize-control.customize-control-checkbox{margin-bottom:8px}.customize-control-menu{margin-top:4px}#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle{color:#555}.customize-screen-options-toggle{background:0 0;border:none;color:#555;cursor:pointer;padding:20px;position:absolute;right:31px;top:4px}#customize-controls .customize-info .customize-help-toggle{padding:20px}#customize-controls .customize-info .customize-help-toggle:before{padding:5px}#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:active,#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:focus,#customize-controls .customize-info.open.active-menu-screen-options .customize-help-toggle:hover,.active-menu-screen-options .customize-screen-options-toggle,.customize-screen-options-toggle:active,.customize-screen-options-toggle:focus,.customize-screen-options-toggle:hover{color:#0073aa}#customize-controls .customize-info .customize-help-toggle:focus,.customize-screen-options-toggle:focus{outline:0;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}.customize-screen-options-toggle:before{-moz-osx-font-smoothing:grayscale;border:none;content:"\f111";display:block;font:20px/1 dashicons;padding:5px;text-align:center;text-decoration:none!important;text-indent:0;left:5px;position:absolute;top:5px}.wp-customizer #screen-options-wrap{display:none;background:#fff;border-top:1px solid #ddd;padding:4px 15px 0}.wp-customizer .metabox-prefs label{display:block;padding-right:0;line-height:30px}#accordion-panel-menus .field-attr-title,#accordion-panel-menus .field-css-classes,#accordion-panel-menus .field-description,#accordion-panel-menus .field-link-target,#accordion-panel-menus .field-xfn{display:none}#accordion-panel-menus.field-attr-title-active .field-attr-title,#accordion-panel-menus.field-css-classes-active .field-css-classes,#accordion-panel-menus.field-description-active .field-description,#accordion-panel-menus.field-link-target-active .field-link-target,#accordion-panel-menus.field-xfn-active .field-xfn{display:block}.wp-customizer .wp-full-overlay a.collapse-sidebar{position:fixed;left:0}.menu-item-depth-0{margin-left:0}.menu-item-depth-1{margin-left:20px}.menu-item-depth-2{margin-left:40px}.menu-item-depth-3{margin-left:60px}.menu-item-depth-4{margin-left:80px}.menu-item-depth-5{margin-left:100px}.menu-item-depth-6{margin-left:120px}.menu-item-depth-7{margin-left:140px}.menu-item-depth-8{margin-left:160px}.menu-item-depth-9{margin-left:180px}.menu-item-depth-10{margin-left:200px}.menu-item-depth-11{margin-left:220px}.menu-item-depth-0>.menu-item-bar{margin-right:0}.menu-item-depth-1>.menu-item-bar{margin-right:20px}.menu-item-depth-2>.menu-item-bar{margin-right:40px}.menu-item-depth-3>.menu-item-bar{margin-right:60px}.menu-item-depth-4>.menu-item-bar{margin-right:80px}.menu-item-depth-5>.menu-item-bar{margin-right:100px}.menu-item-depth-6>.menu-item-bar{margin-right:120px}.menu-item-depth-7>.menu-item-bar{margin-right:140px}.menu-item-depth-8>.menu-item-bar{margin-right:160px}.menu-item-depth-9>.menu-item-bar{margin-right:180px}.menu-item-depth-10>.menu-item-bar{margin-right:200px}.menu-item-depth-11>.menu-item-bar{margin-right:220px}.menu-item-depth-0 .menu-item-transport{margin-left:0}.menu-item-depth-1 .menu-item-transport{margin-left:-20px}.menu-item-depth-3 .menu-item-transport{margin-left:-60px}.menu-item-depth-4 .menu-item-transport{margin-left:-80px}.menu-item-depth-2 .menu-item-transport{margin-left:-40px}.menu-item-depth-5 .menu-item-transport{margin-left:-100px}.menu-item-depth-6 .menu-item-transport{margin-left:-120px}.menu-item-depth-7 .menu-item-transport{margin-left:-140px}.menu-item-depth-8 .menu-item-transport{margin-left:-160px}.menu-item-depth-9 .menu-item-transport{margin-left:-180px}.menu-item-depth-10 .menu-item-transport{margin-left:-200px}.menu-item-depth-11 .menu-item-transport{margin-left:-220px}.reordering .menu-item-depth-0{margin-left:0}.reordering .menu-item-depth-1{margin-left:15px}.reordering .menu-item-depth-2{margin-left:30px}.reordering .menu-item-depth-3{margin-left:45px}.reordering .menu-item-depth-4{margin-left:60px}.reordering .menu-item-depth-5{margin-left:75px}.reordering .menu-item-depth-6{margin-left:90px}.reordering .menu-item-depth-7{margin-left:105px}.reordering .menu-item-depth-8{margin-left:120px}.reordering .menu-item-depth-9{margin-left:135px}.reordering .menu-item-depth-10{margin-left:150px}.reordering .menu-item-depth-11{margin-left:165px}.reordering .menu-item-depth-0>.menu-item-bar{margin-right:0}.reordering .menu-item-depth-1>.menu-item-bar{margin-right:15px}.reordering .menu-item-depth-2>.menu-item-bar{margin-right:30px}.reordering .menu-item-depth-3>.menu-item-bar{margin-right:45px}.reordering .menu-item-depth-4>.menu-item-bar{margin-right:60px}.reordering .menu-item-depth-5>.menu-item-bar{margin-right:75px}.reordering .menu-item-depth-6>.menu-item-bar{margin-right:90px}.reordering .menu-item-depth-7>.menu-item-bar{margin-right:105px}.reordering .menu-item-depth-8>.menu-item-bar{margin-right:120px}.reordering .menu-item-depth-9>.menu-item-bar{margin-right:135px}.reordering .menu-item-depth-10>.menu-item-bar{margin-right:150px}.reordering .menu-item-depth-11>.menu-item-bar{margin-right:165px}.control-section-nav_menu .menu .menu-item-edit-active{margin-left:0}.control-section-nav_menu .menu .menu-item-edit-active .menu-item-bar{margin-right:0}.control-section-nav_menu .menu .sortable-placeholder{margin-top:0;margin-bottom:1px;max-width:-webkit-calc(100% - 2px);max-width:calc(100% - 2px);float:left;display:list-item;border-color:#a0a5aa}.control-section-nav_menu .menu ul.menu-item-transport dl{margin-top:0}.wp-full-overlay-main{right:auto;width:100%}.adding-menu-items .control-section{opacity:.4}.adding-menu-items .control-panel.control-section,.adding-menu-items .control-section.open{opacity:1}#customize-theme-controls .add-new-menu-item{cursor:pointer;float:right;margin-left:10px;-webkit-transition:all .2s;transition:all .2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:0}.add-new-menu-item:before{content:"\f132";display:inline-block;position:relative;left:-2px;top:-1px;font:400 20px/1 dashicons;vertical-align:middle;-webkit-transition:all .2s;transition:all .2s;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.add-menu-toggle.open,.add-menu-toggle.open:hover,.adding-menu-items .add-new-menu-item,.adding-menu-items .add-new-menu-item:hover{background:#eee;border-color:#929793;color:#32373c;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}#accordion-section-add_menu .add-new-menu-item.open:before,.adding-menu-items .add-new-menu-item:before{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.menu-item-bar .item-delete{color:#a00;position:absolute;top:2px;right:-19px;width:30px;height:38px;cursor:pointer;display:none}.menu-item-bar .item-delete:before{content:"\f335";font:400 20px/1 dashicons;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;position:absolute;top:9px;left:5px}.menu-item-bar .item-delete:focus,.menu-item-bar .item-delete:hover{color:red}.adding-menu-items .menu-item-bar .item-edit{display:none}.adding-menu-items .menu-item-bar .item-delete{display:block}#available-menu-items .item{position:static}#available-menu-items{position:absolute;overflow:hidden;top:0;bottom:0;left:-301px;width:300px;margin:0;z-index:4;background:#eee;-webkit-transition:all .2s;transition:all .2s;border-right:1px solid #ddd}#available-menu-items.allow-scroll{overflow-y:auto}#available-menu-items .accordion-section-title{border-left:none;border-right:none;background:#fff}#available-menu-items .open .accordion-section-title{background:#eee}#available-menu-items .open .accordion-section-title:after{content:'\f142'}#available-menu-items .accordion-section-content{overflow-y:auto;background:0 0}button.not-a-button{background:0 0;border:none;-webkit-box-shadow:none;box-shadow:none;-webkit-border-radius:0;border-radius:0;outline:0;padding:0;margin:0}#available-menu-items .accordion-section-title button:focus:before{display:block;content:"";width:28px;height:32px;position:absolute;right:5px;top:5px;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}#available-menu-items .accordion-section-content{padding:1px 15px 15px;min-height:120px;max-height:290px}#custom-menu-item-name.invalid,#custom-menu-item-url.invalid{border:1px solid red}#available-menu-items .item-tpl{position:relative;padding:20px 15px 20px 60px;border-bottom:1px solid #e4e4e4;cursor:pointer;display:none}#available-menu-items .item-tpl.selected,#available-menu-items .item-tpl:hover{background:#eee}#available-menu-items .menu-item-handle .item-type{padding-right:0}#available-menu-items .menu-item-handle .item-title{padding-left:20px}#available-menu-items .menu-item-handle{cursor:pointer}#available-menu-items .item-top,#available-menu-items .item-top:hover{border:none;background:0 0;-webkit-box-shadow:none;box-shadow:none}#available-menu-items .menu-item-handle{-webkit-box-shadow:none;box-shadow:none;margin-top:-1px}#available-menu-items .menu-item-handle:hover{z-index:1}#available-menu-items .item-title h4{padding:0 0 5px;font-size:14px}#available-menu-items .item-add{position:absolute;top:1px;left:1px;color:#82878c;width:30px;height:38px;cursor:pointer}#available-menu-items .menu-item-handle .item-add:focus{color:#23282d;-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}#available-menu-items .item-add:before{content:"\f132";font:400 20px/1 dashicons;position:relative;left:2px;top:4px}#available-menu-items .menu-item-handle.item-added .item-add:focus,#available-menu-items .menu-item-handle.item-added .item-title,#available-menu-items .menu-item-handle.item-added .item-type,#available-menu-items .menu-item-handle.item-added:hover .item-add{color:#82878c}#available-menu-items .menu-item-handle.item-added .item-add:before{content:"\f147"}#available-menu-items .accordion-section-title.loading .spinner,#available-menu-items-search.loading .accordion-section-title .spinner{visibility:visible;margin:0 20px}#available-menu-items-search .spinner{position:absolute;top:18px;margin:0!important;right:20px}#available-menu-items-search input{padding:6px 10px;width:100%}#available-menu-items-search .accordion-section-title{padding:12px 15px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#available-menu-items-search .accordion-section-title:after{display:none}#available-menu-items-search .accordion-section-content:empty{min-height:0;padding:0}#available-menu-items-search.loading .accordion-section-content div{opacity:.5}#available-menu-items-search.loading.loading-more .accordion-section-content div{opacity:1}#customize-preview{-webkit-transition:all .2s;transition:all .2s}body.adding-menu-items #available-menu-items{left:0}body.adding-menu-items .wp-full-overlay-main{left:300px}body.adding-menu-items #customize-preview{opacity:.4}.menu-item-handle .spinner{display:none;float:left;margin:0 8px 0 0}.nav-menu-inserted-item-loading .spinner{display:block}.nav-menu-inserted-item-loading .menu-item-handle .item-type{padding:0 0 0 8px}.added-menu-item .menu-item-handle.loading,.nav-menu-inserted-item-loading .menu-item-handle{padding:10px 15px 10px 8px;cursor:default;opacity:.5;background:#fff;color:#727773}.added-menu-item .menu-item-handle{-webkit-transition-property:opacity,background,color;transition-property:opacity,background,color;-webkit-transition-duration:1.25s;transition-duration:1.25s;-webkit-transition-timing-function:cubic-bezier(.25,-2.5,.75,8);transition-timing-function:cubic-bezier(.25,-2.5,.75,8)}#accordion-section-add_menu{margin:15px 12px}.new-menu-section-content{display:none;padding:15px 0 0;overflow:hidden;clear:both}#accordion-section-add_menu .accordion-section-title{padding-left:45px}#accordion-section-add_menu .accordion-section-title:before{font:400 20px/1 dashicons;position:absolute;top:12px;left:14px;content:"\f132"}#create-new-menu-submit{float:right;margin:0 0 12px}.menu-delete-item{display:block;float:left;padding:1em 0;width:100%}li.assigned-to-menu-location .menu-delete-item{display:none}li.assigned-to-menu-location .add-new-menu-item{margin-bottom:1em}.menu-delete{color:#a00;cursor:pointer;text-decoration:underline}.menu-delete:focus,.menu-delete:hover{color:red;text-decoration:none}.menu-delete:focus{-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}.menu-item-handle{margin-top:-1px}.ui-sortable-disabled .menu-item-handle{cursor:default}.menu-item-handle:hover{position:relative;z-index:10;color:#0073aa}#available-menu-items .menu-item-handle:hover .item-add,.menu-item-handle:hover .item-edit,.menu-item-handle:hover .item-type{color:#0073aa}.menu-item-edit-active .menu-item-handle{border-color:#999;border-bottom:none}.customize-control-nav_menu_item{margin-bottom:0}.customize-control-nav_menu{margin-top:12px}#available-menu-items .customize-section-title{display:none}@media screen and (max-width:640px){body.adding-menu-items div#available-menu-items{top:46px;left:0;z-index:10;width:100%}#available-menu-items .customize-section-title{display:block;margin:0}#available-menu-items .customize-section-back{height:69px}#available-menu-items .customize-section-title h3{font-size:20px;font-weight:200;padding:9px 10px 12px 14px;margin:0;line-height:24px;color:#555;display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}#available-menu-items .customize-section-title .customize-action{font-size:13px;display:block;font-weight:400;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}} \ No newline at end of file diff --git a/wp-admin/js/customize-nav-menus.js b/wp-admin/js/customize-nav-menus.js new file mode 100644 index 0000000000..21f8fcd6b0 --- /dev/null +++ b/wp-admin/js/customize-nav-menus.js @@ -0,0 +1,2513 @@ +/* global _wpCustomizeNavMenusSettings, wpNavMenu, console */ +( function( api, wp, $ ) { + 'use strict'; + + /** + * Set up wpNavMenu for drag and drop. + */ + wpNavMenu.originalInit = wpNavMenu.init; + wpNavMenu.options.menuItemDepthPerLevel = 20; + wpNavMenu.options.sortableItems = '.customize-control-nav_menu_item'; + wpNavMenu.init = function() { + this.jQueryExtensions(); + }; + + api.Menus = api.Menus || {}; + + // Link settings. + api.Menus.data = { + nonce: '', + itemTypes: { + taxonomies: {}, + postTypes: {} + }, + l10n: {}, + menuItemTransport: 'postMessage', + phpIntMax: 0, + defaultSettingValues: { + nav_menu: {}, + nav_menu_item: {} + } + }; + if ( 'undefined' !== typeof _wpCustomizeNavMenusSettings ) { + $.extend( api.Menus.data, _wpCustomizeNavMenusSettings ); + } + + /** + * Newly-created Nav Menus and Nav Menu Items have negative integer IDs which + * serve as placeholders until Save & Publish happens. + * + * @return {number} + */ + api.Menus.generatePlaceholderAutoIncrementId = function() { + return -Math.ceil( api.Menus.data.phpIntMax * Math.random() ); + }; + + /** + * wp.customize.Menus.AvailableItemModel + * + * A single available menu item model. See PHP's WP_Customize_Nav_Menu_Item_Setting class. + * + * @constructor + * @augments Backbone.Model + */ + api.Menus.AvailableItemModel = Backbone.Model.extend( $.extend( + { + id: null // This is only used by Backbone. + }, + api.Menus.data.defaultSettingValues.nav_menu_item + ) ); + + /** + * wp.customize.Menus.AvailableItemCollection + * + * Collection for available menu item models. + * + * @constructor + * @augments Backbone.Model + */ + api.Menus.AvailableItemCollection = Backbone.Collection.extend({ + model: api.Menus.AvailableItemModel, + + sort_key: 'order', + + comparator: function( item ) { + return -item.get( this.sort_key ); + }, + + sortByField: function( fieldName ) { + this.sort_key = fieldName; + this.sort(); + } + }); + api.Menus.availableMenuItems = new api.Menus.AvailableItemCollection( api.Menus.data.availableMenuItems ); + + /** + * wp.customize.Menus.AvailableMenuItemsPanelView + * + * View class for the available menu items panel. + * + * @constructor + * @augments wp.Backbone.View + * @augments Backbone.View + */ + api.Menus.AvailableMenuItemsPanelView = wp.Backbone.View.extend({ + + el: '#available-menu-items', + + events: { + 'input #menu-items-search': 'debounceSearch', + 'change #menu-items-search': 'debounceSearch', + 'click #menu-items-search': 'debounceSearch', + 'focus .menu-item-tpl': 'focus', + 'click .menu-item-tpl': '_submit', + 'keypress .menu-item-tpl': '_submit', + 'click #custom-menu-item-submit': '_submitLink', + 'keypress #custom-menu-item-name': '_submitLink', + 'keydown': 'keyboardAccessible' + }, + + // Cache current selected menu item. + selected: null, + + // Cache menu control that opened the panel. + currentMenuControl: null, + debounceSearch: null, + $search: null, + searchTerm: '', + rendered: false, + pages: {}, + sectionContent: '', + loading: false, + + initialize: function() { + var self = this; + + this.$search = $( '#menu-items-search' ); + this.sectionContent = this.$el.find( '.accordion-section-content' ); + + this.debounceSearch = _.debounce( self.search, 250 ); + + _.bindAll( this, 'close' ); + + // If the available menu items panel is open and the customize controls are + // interacted with (other than an item being deleted), then close the + // available menu items panel. Also close on back button click. + $( '#customize-controls, .customize-section-back' ).on( 'click keydown', function( e ) { + var isDeleteBtn = $( e.target ).is( '.item-delete, .item-delete *' ), + isAddNewBtn = $( e.target ).is( '.add-new-menu-item, .add-new-menu-item *' ); + if ( $( 'body' ).hasClass( 'adding-menu-items' ) && ! isDeleteBtn && ! isAddNewBtn ) { + self.close(); + } + } ); + + this.$el.on( 'input', '#custom-menu-item-name.invalid, #custom-menu-item-url.invalid', function() { + $( this ).removeClass( 'invalid' ); + }); + + // Load available items if it looks like we'll need them. + api.panel( 'nav_menus' ).container.bind( 'expanded', function() { + if ( ! self.rendered ) { + self.initList(); + self.rendered = true; + } + }); + + // Load more items. + this.sectionContent.scroll( function() { + var totalHeight = self.$el.find( '.accordion-section.open .accordion-section-content' ).prop( 'scrollHeight' ), + visibleHeight = self.$el.find( '.accordion-section.open' ).height(); + if ( ! self.loading && $( this ).scrollTop() > 3 / 4 * totalHeight - visibleHeight ) { + var type = $( this ).data( 'type' ), + obj_type = $( this ).data( 'obj_type' ); + if ( 'search' === type ) { + if ( self.searchTerm ) { + self.doSearch( self.pages.search ); + } + } else { + self.loadItems( type, obj_type ); + } + } + }); + + // Close the panel if the URL in the preview changes + api.previewer.bind( 'url', this.close ); + }, + + // Search input change handler. + search: function( event ) { + if ( ! event ) { + return; + } + // Manual accordion-opening behavior. + if ( this.searchTerm && ! $( '#available-menu-items-search' ).hasClass( 'open' ) ) { + $( '#available-menu-items .accordion-section-content' ).slideUp( 'fast' ); + $( '#available-menu-items-search .accordion-section-content' ).slideDown( 'fast' ); + $( '#available-menu-items .accordion-section.open' ).removeClass( 'open' ); + $( '#available-menu-items-search' ).addClass( 'open' ); + } + if ( '' === event.target.value ) { + $( '#available-menu-items-search' ).removeClass( 'open' ); + } + if ( this.searchTerm === event.target.value ) { + return; + } + this.searchTerm = event.target.value; + this.pages.search = 1; + this.doSearch( 1 ); + }, + + // Get search results. + doSearch: function( page ) { + var self = this, params, + $section = $( '#available-menu-items-search' ), + $content = $section.find( '.accordion-section-content' ), + itemTemplate = wp.template( 'available-menu-item' ); + + if ( self.currentRequest ) { + self.currentRequest.abort(); + } + + if ( page < 0 ) { + return; + } else if ( page > 1 ) { + $section.addClass( 'loading-more' ); + } else if ( '' === self.searchTerm ) { + $content.html( '' ); + return; + } + + $section.addClass( 'loading' ); + self.loading = true; + params = { + 'customize-menus-nonce': api.Menus.data.nonce, + 'wp_customize': 'on', + 'search': self.searchTerm, + 'page': page + }; + + self.currentRequest = wp.ajax.post( 'search-available-menu-items-customizer', params ); + + self.currentRequest.done(function( data ) { + var items; + if ( 1 === page ) { + // Clear previous results as it's a new search. + $content.empty(); + } + $section.removeClass( 'loading loading-more' ); + $section.addClass( 'open' ); + self.loading = false; + items = new api.Menus.AvailableItemCollection( data.items ); + self.collection.add( items.models ); + items.each( function( menuItem ) { + $content.append( itemTemplate( menuItem.attributes ) ); + } ); + if ( 20 > items.length ) { + self.pages.search = -1; // Up to 20 posts and 20 terms in results, if <20, no more results for either. + } else { + self.pages.search = self.pages.search + 1; + } + }); + + self.currentRequest.fail(function( data ) { + $content.empty().append( $( '

' ).text( data.message ) ); + wp.a11y.speak( data.message ); + self.pages.search = -1; + }); + + self.currentRequest.always(function() { + $section.removeClass( 'loading loading-more' ); + self.loading = false; + self.currentRequest = null; + }); + }, + + // Render the individual items. + initList: function() { + var self = this; + + // Render the template for each item by type. + _.each( api.Menus.data.itemTypes, function( typeObjects, type ) { + _.each( typeObjects, function( typeObject, slug ) { + if ( 'postTypes' === type ) { + type = 'post_type'; + } else if ( 'taxonomies' === type ) { + type = 'taxonomy'; + } + self.pages[ slug ] = 0; // @todo should prefix with type + self.loadItems( slug, type ); + } ); + } ); + }, + + // Load available menu items. + loadItems: function( type, obj_type ) { + var self = this, params, request, itemTemplate; + itemTemplate = wp.template( 'available-menu-item' ); + + if ( 0 > self.pages[type] ) { + return; + } + $( '#available-menu-items-' + type + ' .accordion-section-title' ).addClass( 'loading' ); + self.loading = true; + params = { + 'customize-menus-nonce': api.Menus.data.nonce, + 'wp_customize': 'on', + 'type': type, + 'obj_type': obj_type, + 'page': self.pages[ type ] + }; + request = wp.ajax.post( 'load-available-menu-items-customizer', params ); + + request.done(function( data ) { + var items, typeInner; + items = data.items; + if ( 0 === items.length ) { + self.pages[ type ] = -1; + return; + } + items = new api.Menus.AvailableItemCollection( items ); // @todo Why is this collection created and then thrown away? + self.collection.add( items.models ); + typeInner = $( '#available-menu-items-' + type + ' .accordion-section-content' ); + items.each(function( menu_item ) { + typeInner.append( itemTemplate( menu_item.attributes ) ); + }); + self.pages[ type ] = self.pages[ type ] + 1; + }); + request.fail(function( data ) { + if ( typeof console !== 'undefined' && console.error ) { + console.error( data ); + } + }); + request.always(function() { + $( '#available-menu-items-' + type + ' .accordion-section-title' ).removeClass( 'loading' ); + self.loading = false; + }); + }, + + // Adjust the height of each section of items to fit the screen. + itemSectionHeight: function() { + var sections, totalHeight, accordionHeight, diff; + totalHeight = window.innerHeight; + sections = this.$el.find( '.accordion-section-content' ); + accordionHeight = 46 * ( 1 + sections.length ) - 16; // Magic numbers. + diff = totalHeight - accordionHeight; + if ( 120 < diff && 290 > diff ) { + sections.css( 'max-height', diff ); + } else if ( 120 >= diff ) { + this.$el.addClass( 'allow-scroll' ); + } + }, + + // Highlights a menu item. + select: function( menuitemTpl ) { + this.selected = $( menuitemTpl ); + this.selected.siblings( '.menu-item-tpl' ).removeClass( 'selected' ); + this.selected.addClass( 'selected' ); + }, + + // Highlights a menu item on focus. + focus: function( event ) { + this.select( $( event.currentTarget ) ); + }, + + // Submit handler for keypress and click on menu item. + _submit: function( event ) { + // Only proceed with keypress if it is Enter or Spacebar + if ( 'keypress' === event.type && ( 13 !== event.which && 32 !== event.which ) ) { + return; + } + + this.submit( $( event.currentTarget ) ); + }, + + // Adds a selected menu item to the menu. + submit: function( menuitemTpl ) { + var menuitemId, menu_item; + + if ( ! menuitemTpl ) { + menuitemTpl = this.selected; + } + + if ( ! menuitemTpl || ! this.currentMenuControl ) { + return; + } + + this.select( menuitemTpl ); + + menuitemId = $( this.selected ).data( 'menu-item-id' ); + menu_item = this.collection.findWhere( { id: menuitemId } ); + if ( ! menu_item ) { + return; + } + + this.currentMenuControl.addItemToMenu( menu_item.attributes ); + + $( menuitemTpl ).find( '.menu-item-handle' ).addClass( 'item-added' ); + }, + + // Submit handler for keypress and click on custom menu item. + _submitLink: function( event ) { + // Only proceed with keypress if it is Enter. + if ( 'keypress' === event.type && 13 !== event.which ) { + return; + } + + this.submitLink(); + }, + + // Adds the custom menu item to the menu. + submitLink: function() { + var menuItem, + itemName = $( '#custom-menu-item-name' ), + itemUrl = $( '#custom-menu-item-url' ); + + if ( ! this.currentMenuControl ) { + return; + } + + if ( '' === itemName.val() ) { + itemName.addClass( 'invalid' ); + return; + } else if ( '' === itemUrl.val() || 'http://' === itemUrl.val() ) { + itemUrl.addClass( 'invalid' ); + return; + } + + menuItem = { + 'title': itemName.val(), + 'url': itemUrl.val(), + 'type': 'custom', + 'type_label': api.Menus.data.l10n.custom_label, + 'object': '' + }; + + this.currentMenuControl.addItemToMenu( menuItem ); + + // Reset the custom link form. + itemUrl.val( 'http://' ); + itemName.val( '' ); + }, + + // Opens the panel. + open: function( menuControl ) { + this.currentMenuControl = menuControl; + + this.itemSectionHeight(); + + $( 'body' ).addClass( 'adding-menu-items' ); + + // Collapse all controls. + _( this.currentMenuControl.getMenuItemControls() ).each( function( control ) { + control.collapseForm(); + } ); + + this.$el.find( '.selected' ).removeClass( 'selected' ); + + this.$search.focus(); + }, + + // Closes the panel + close: function( options ) { + options = options || {}; + + if ( options.returnFocus && this.currentMenuControl ) { + this.currentMenuControl.container.find( '.add-new-menu-item' ).focus(); + } + + this.currentMenuControl = null; + this.selected = null; + + $( 'body' ).removeClass( 'adding-menu-items' ); + $( '#available-menu-items .menu-item-handle.item-added' ).removeClass( 'item-added' ); + + this.$search.val( '' ); + }, + + // Add keyboard accessiblity to the panel + keyboardAccessible: function( event ) { + var isEnter = ( 13 === event.which ), + isEsc = ( 27 === event.which ), + isDown = ( 40 === event.which ), + isUp = ( 38 === event.which ), + isBackTab = ( 9 === event.which && event.shiftKey ), + selected = null, + firstVisible = this.$el.find( '> .menu-item-tpl:visible:first' ), + lastVisible = this.$el.find( '> .menu-item-tpl:visible:last' ), + isSearchFocused = $( event.target ).is( this.$search ); + + if ( isDown || isUp ) { + if ( isDown ) { + if ( isSearchFocused ) { + selected = firstVisible; + } else if ( this.selected && 0 !== this.selected.nextAll( '.menu-item-tpl:visible' ).length ) { + selected = this.selected.nextAll( '.menu-item-tpl:visible:first' ); + } + } else if ( isUp ) { + if ( isSearchFocused ) { + selected = lastVisible; + } else if ( this.selected && 0 !== this.selected.prevAll( '.menu-item-tpl:visible' ).length ) { + selected = this.selected.prevAll( '.menu-item-tpl:visible:first' ); + } + } + + this.select( selected ); + + if ( selected ) { + selected.focus(); + } else { + this.$search.focus(); + } + + return; + } + + // If enter pressed but nothing entered, don't do anything + if ( isEnter && ! this.$search.val() ) { + return; + } + + if ( isSearchFocused && isBackTab ) { + this.currentMenuControl.container.find( '.add-new-menu-item' ).focus(); + event.preventDefault(); // Avoid additional back-tab. + } else if ( isEsc ) { + this.close( { returnFocus: true } ); + } + } + }); + + /** + * wp.customize.Menus.MenusPanel + * + * Customizer panel for menus. This is used only for screen options management. + * Note that 'menus' must match the WP_Customize_Menu_Panel::$type. + * + * @constructor + * @augments wp.customize.Panel + */ + api.Menus.MenusPanel = api.Panel.extend({ + + attachEvents: function() { + api.Panel.prototype.attachEvents.call( this ); + + var panel = this, + panelMeta = panel.container.find( '.panel-meta' ), + help = panelMeta.find( '.customize-help-toggle' ), + content = panelMeta.find( '.customize-panel-description' ), + options = $( '#screen-options-wrap' ), + button = panelMeta.find( '.customize-screen-options-toggle' ); + button.on( 'click', function() { + // Hide description + if ( content.not( ':hidden' ) ) { + content.slideUp( 'fast' ); + help.attr( 'aria-expanded', 'false' ); + } + + if ( 'true' === button.attr( 'aria-expanded' ) ) { + button.attr( 'aria-expanded', 'false' ); + panelMeta.removeClass( 'open' ); + panelMeta.removeClass( 'active-menu-screen-options' ); + options.slideUp( 'fast' ); + } else { + button.attr( 'aria-expanded', 'true' ); + panelMeta.addClass( 'open' ); + panelMeta.addClass( 'active-menu-screen-options' ); + options.slideDown( 'fast' ); + } + + return false; + } ); + + // Help toggle + help.on( 'click', function() { + if ( 'true' === button.attr( 'aria-expanded' ) ) { + button.attr( 'aria-expanded', 'false' ); + help.attr( 'aria-expanded', 'true' ); + panelMeta.addClass( 'open' ); + panelMeta.removeClass( 'active-menu-screen-options' ); + options.slideUp( 'fast' ); + content.slideDown( 'fast' ); + } + } ); + }, + + /** + * Show/hide/save screen options (columns). From common.js. + */ + ready: function() { + var panel = this; + this.container.find( '.hide-column-tog' ).click( function() { + var $t = $( this ), column = $t.val(); + if ( $t.prop( 'checked' ) ) { + panel.checked( column ); + } else { + panel.unchecked( column ); + } + + panel.saveManageColumnsState(); + }); + this.container.find( '.hide-column-tog' ).each( function() { + var $t = $( this ), column = $t.val(); + if ( $t.prop( 'checked' ) ) { + panel.checked( column ); + } else { + panel.unchecked( column ); + } + }); + }, + + saveManageColumnsState: function() { + var hidden = this.hidden(); + $.post( wp.ajax.settings.url, { + action: 'hidden-columns', + hidden: hidden, + screenoptionnonce: $( '#screenoptionnonce' ).val(), + page: 'nav-menus' + }); + }, + + checked: function( column ) { + this.container.addClass( 'field-' + column + '-active' ); + }, + + unchecked: function( column ) { + this.container.removeClass( 'field-' + column + '-active' ); + }, + + hidden: function() { + this.hidden = function() { + return $( '.hide-column-tog' ).not( ':checked' ).map( function() { + var id = this.id; + return id.substring( id, id.length - 5 ); + }).get().join( ',' ); + }; + } + } ); + + /** + * wp.customize.Menus.MenuSection + * + * Customizer section for menus. This is used only for lazy-loading child controls. + * Note that 'nav_menu' must match the WP_Customize_Menu_Section::$type. + * + * @constructor + * @augments wp.customize.Section + */ + api.Menus.MenuSection = api.Section.extend({ + + /** + * @since Menu Customizer 0.3 + * + * @param {String} id + * @param {Object} options + */ + initialize: function( id, options ) { + var section = this; + api.Section.prototype.initialize.call( section, id, options ); + section.deferred.initSortables = $.Deferred(); + }, + + /** + * + */ + ready: function() { + var section = this; + + if ( 'undefined' === typeof section.params.menu_id ) { + throw new Error( 'params.menu_id was not defined' ); + } + + /* + * Since newly created sections won't be registered in PHP, we need to prevent the + * preview's sending of the activeSections to result in this control + * being deactivated when the preview refreshes. So we can hook onto + * the setting that has the same ID and its presence can dictate + * whether the section is active. + */ + section.active.validate = function() { + if ( ! api.has( section.id ) ) { + return false; + } + return !! api( section.id ).get(); + }; + + section.populateControls(); + + section.navMenuLocationSettings = {}; + section.assignedLocations = new api.Value( [] ); + + api.each(function( setting, id ) { + var matches = id.match( /^nav_menu_locations\[(.+?)]/ ); + if ( matches ) { + section.navMenuLocationSettings[ matches[1] ] = setting; + setting.bind( function() { + section.refreshAssignedLocations(); + }); + } + }); + + section.assignedLocations.bind(function( to ) { + section.updateAssignedLocationsInSectionTitle( to ); + }); + + section.refreshAssignedLocations(); + }, + + populateControls: function() { + var section = this, menuNameControlId, menuControl, menuNameControl; + + // Add the control for managing the menu name. + menuNameControlId = section.id + '[name]'; + menuNameControl = api.control( menuNameControlId ); + if ( ! menuNameControl ) { + menuNameControl = new api.controlConstructor.nav_menu_name( menuNameControlId, { + params: { + type: 'nav_menu_name', + content: '
  • ', // @todo core should do this for us + label: '', + active: true, + section: section.id, + priority: 0, + settings: { + 'default': section.id + } + } + } ); + api.control.add( menuNameControl.id, menuNameControl ); + menuNameControl.active.set( true ); + } + + // Add the menu control. + menuControl = api.control( section.id ); + if ( ! menuControl ) { + menuControl = new api.controlConstructor.nav_menu( section.id, { + params: { + type: 'nav_menu', + content: '
  • ', // @todo core should do this for us + section: section.id, + priority: 999, + active: true, + settings: { + 'default': section.id + }, + menu_id: section.params.menu_id + } + } ); + api.control.add( menuControl.id, menuControl ); + menuControl.active.set( true ); + } + + }, + + /** + * + */ + refreshAssignedLocations: function() { + var section = this, + menuTermId = section.params.menu_id, + currentAssignedLocations = []; + _.each( section.navMenuLocationSettings, function( setting, themeLocation ) { + if ( setting() === menuTermId ) { + currentAssignedLocations.push( themeLocation ); + } + }); + section.assignedLocations.set( currentAssignedLocations ); + }, + + /** + * @param {array} themeLocations + */ + updateAssignedLocationsInSectionTitle: function( themeLocations ) { + var section = this, + $title; + + $title = section.container.find( '.accordion-section-title:first' ); + $title.find( '.menu-in-location' ).remove(); + _.each( themeLocations, function( themeLocation ) { + var $label = $( '' ); + $label.text( api.Menus.data.l10n.menuLocation.replace( '%s', themeLocation ) ); + $title.append( $label ); + }); + + section.container.toggleClass( 'assigned-to-menu-location', 0 !== themeLocations.length ); + + }, + + onChangeExpanded: function( expanded, args ) { + var section = this; + + if ( expanded ) { + wpNavMenu.menuList = section.container.find( '.accordion-section-content:first' ); + wpNavMenu.targetList = wpNavMenu.menuList; + + // Add attributes needed by wpNavMenu + $( '#menu-to-edit' ).removeAttr( 'id' ); + wpNavMenu.menuList.attr( 'id', 'menu-to-edit' ).addClass( 'menu' ); + + _.each( api.section( section.id ).controls(), function( control ) { + if ( 'nav_menu_item' === control.params.type ) { + control.actuallyEmbed(); + } + } ); + + if ( 'resolved' !== section.deferred.initSortables.state() ) { + wpNavMenu.initSortables(); // Depends on menu-to-edit ID being set above. + section.deferred.initSortables.resolve( wpNavMenu.menuList ); // Now MenuControl can extend the sortable. + + // @todo Note that wp.customize.reflowPaneContents() is debounced, so this immediate change will show a slight flicker while priorities get updated. + api.control( 'nav_menu[' + String( section.params.menu_id ) + ']' ).reflowMenuItems(); + } + } + api.Section.prototype.onChangeExpanded.call( section, expanded, args ); + } + }); + + /** + * wp.customize.Menus.NewMenuSection + * + * Customizer section for new menus. + * Note that 'new_menu' must match the WP_Customize_New_Menu_Section::$type. + * + * @constructor + * @augments wp.customize.Section + */ + api.Menus.NewMenuSection = api.Section.extend({ + + /** + * Add behaviors for the accordion section. + * + * @since Menu Customizer 0.3 + */ + attachEvents: function() { + var section = this; + this.container.on( 'click', '.add-menu-toggle', function() { + if ( section.expanded() ) { + section.collapse(); + } else { + section.expand(); + } + }); + }, + + /** + * Update UI to reflect expanded state. + * + * @since 4.1.0 + * + * @param {Boolean} expanded + */ + onChangeExpanded: function( expanded ) { + var section = this, + button = section.container.find( '.add-menu-toggle' ), + content = section.container.find( '.new-menu-section-content' ), + customizer = section.container.closest( '.wp-full-overlay-sidebar-content' ); + if ( expanded ) { + button.addClass( 'open' ); + content.slideDown( 'fast', function() { + customizer.scrollTop( customizer.height() ); + }); + } else { + button.removeClass( 'open' ); + content.slideUp( 'fast' ); + } + } + }); + + /** + * wp.customize.Menus.MenuLocationControl + * + * Customizer control for menu locations (rendered as a ', + 'link-target' => __( 'Link Target' ), + 'attr-title' => __( 'Title Attribute' ), + 'css-classes' => __( 'CSS Classes' ), + 'xfn' => __( 'Link Relationship (XFN)' ), + 'description' => __( 'Description' ), + ); + } + + /** + * An Underscore (JS) template for this panel's content (but not its container). + * + * Class variables for this panel class are available in the `data` JS object; + * export custom variables by overriding {@see WP_Customize_Panel::json()}. + * + * @since 4.3.0 + * + * @see WP_Customize_Panel::print_template() + * + * @since 4.3.0 + */ + protected function content_template() { + ?> +
  • + +
    + + {{ data.title }}' ); + ?> + + + +
    + <# if ( data.description ) { #> +
    {{{ data.description }}}
    + <# } #> + render_screen_options(); ?> +
  • + + + + + + + + + + +

    + +

    + setting->term_id; + + return $exported; + } +} + +/** + * Customize control to represent the name field for a given menu. + * + * @since 4.3.0 + */ +class WP_Customize_Nav_Menu_Item_Control extends WP_Customize_Control { + + /** + * Control type. + * + * @since 4.3.0 + * + * @access public + * @var string + */ + public $type = 'nav_menu_item'; + + /** + * The nav menu item setting. + * + * @since 4.3.0 + * + * @var WP_Customize_Nav_Menu_Item_Setting + */ + public $setting; + + /** + * Constructor. + * + * @since 4.3.0 + * + * @uses WP_Customize_Control::__construct() + * + * @param WP_Customize_Manager $manager An instance of the WP_Customize_Manager class. + * @param string $id The control ID. + * @param array $args Optional. Overrides class property defaults. + */ + public function __construct( $manager, $id, $args = array() ) { + parent::__construct( $manager, $id, $args ); + } + + /** + * Don't render the control's content - it's rendered with a JS template. + * + * @since 4.3.0 + */ + public function render_content() {} + + /** + * JS/Underscore template for the control UI. + * + * @since 4.3.0 + */ + public function content_template() { + ?> + + + + + setting->post_id; + + return $exported; + } +} + +/** + * Customize Menu Location Control Class + * + * This custom control is only needed for JS. + * + * @since 4.3.0 + */ +class WP_Customize_Nav_Menu_Location_Control extends WP_Customize_Control { + + /** + * Control type. + * + * @since 4.3.0 + * + * @access public + * @var string + */ + public $type = 'nav_menu_location'; + + /** + * Location ID. + * + * @since 4.3.0 + * + * @access public + * @var string + */ + public $location_id = ''; + + /** + * Refresh the parameters passed to JavaScript via JSON. + * + * @since 4.3.0 + * + * @uses WP_Customize_Control::to_json() + */ + public function to_json() { + parent::to_json(); + $this->json['locationId'] = $this->location_id; + } + + /** + * Render content just like a normal select control. + * + * @since 4.3.0 + */ + public function render_content() { + if ( empty( $this->choices ) ) { + return; + } + ?> + + + + + + + widgets = new WP_Customize_Widgets( $this ); + $this->nav_menus = new WP_Customize_Nav_Menus( $this ); add_filter( 'wp_die_handler', array( $this, 'wp_die_handler' ) ); @@ -1484,48 +1493,6 @@ final class WP_Customize_Manager { } } - /* Nav Menus */ - - $locations = get_registered_nav_menus(); - $menus = wp_get_nav_menus(); - $num_locations = count( array_keys( $locations ) ); - - if ( 1 == $num_locations ) { - $description = __( 'Your theme supports one menu. Select which menu you would like to use.' ); - } else { - $description = sprintf( _n( 'Your theme supports %s menu. Select which menu appears in each location.', 'Your theme supports %s menus. Select which menu appears in each location.', $num_locations ), number_format_i18n( $num_locations ) ); - } - - $this->add_section( 'nav', array( - 'title' => __( 'Navigation' ), - 'theme_supports' => 'menus', - 'priority' => 100, - 'description' => $description . "\n\n" . __( 'You can edit your menu content on the Menus screen in the Appearance section.' ), - ) ); - - if ( $menus ) { - $choices = array( '' => __( '— Select —' ) ); - foreach ( $menus as $menu ) { - $choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '…' ); - } - - foreach ( $locations as $location => $description ) { - $menu_setting_id = "nav_menu_locations[{$location}]"; - - $this->add_setting( $menu_setting_id, array( - 'sanitize_callback' => 'absint', - 'theme_supports' => 'menus', - ) ); - - $this->add_control( $menu_setting_id, array( - 'label' => $description, - 'section' => 'nav', - 'type' => 'select', - 'choices' => $choices, - ) ); - } - } - /* Static Front Page */ // #WP19627 diff --git a/wp-includes/class-wp-customize-nav-menus.php b/wp-includes/class-wp-customize-nav-menus.php new file mode 100644 index 0000000000..eb4de49c24 --- /dev/null +++ b/wp-includes/class-wp-customize-nav-menus.php @@ -0,0 +1,882 @@ +previewed_menus = array(); + $this->manager = $manager; + + add_action( 'wp_ajax_load-available-menu-items-customizer', array( $this, 'ajax_load_available_items' ) ); + add_action( 'wp_ajax_search-available-menu-items-customizer', array( $this, 'ajax_search_available_items' ) ); + add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); + add_action( 'customize_register', array( $this, 'customize_register' ), 11 ); // Needs to run after core Navigation section is set up. + add_filter( 'customize_dynamic_setting_args', array( $this, 'filter_dynamic_setting_args' ), 10, 2 ); + add_filter( 'customize_dynamic_setting_class', array( $this, 'filter_dynamic_setting_class' ), 10, 3 ); + add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_templates' ) ); + add_action( 'customize_controls_print_footer_scripts', array( $this, 'available_items_template' ) ); + add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ) ); + } + + /** + * Ajax handler for loading available menu items. + * + * @since 4.3.0 + */ + public function ajax_load_available_items() { + check_ajax_referer( 'customize-menus', 'customize-menus-nonce' ); + + if ( ! current_user_can( 'edit_theme_options' ) ) { + wp_send_json_error( array( 'message' => __( 'Error: invalid user capabilities.' ) ) ); + } + if ( empty( $_POST['obj_type'] ) || empty( $_POST['type'] ) ) { + wp_send_json_error( array( 'message' => __( 'Missing obj_type or type param.' ) ) ); + } + + $obj_type = sanitize_key( $_POST['obj_type'] ); + if ( ! in_array( $obj_type, array( 'post_type', 'taxonomy' ) ) ) { + wp_send_json_error( array( 'message' => __( 'Invalid obj_type param: ' . $obj_type ) ) ); + } + $taxonomy_or_post_type = sanitize_key( $_POST['type'] ); + $page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 0; + $items = array(); + + if ( 'post_type' === $obj_type ) { + if ( ! get_post_type_object( $taxonomy_or_post_type ) ) { + wp_send_json_error( array( 'message' => __( 'Unknown post type.' ) ) ); + } + + if ( 0 === $page && 'page' === $taxonomy_or_post_type ) { + // Add "Home" link. Treat as a page, but switch to custom on add. + $items[] = array( + 'id' => 'home', + 'title' => _x( 'Home', 'nav menu home label' ), + 'type' => 'custom', + 'type_label' => __( 'Custom Link' ), + 'object' => '', + 'url' => home_url(), + ); + } + + $posts = get_posts( array( + 'numberposts' => 10, + 'offset' => 10 * $page, + 'orderby' => 'date', + 'order' => 'DESC', + 'post_type' => $taxonomy_or_post_type, + ) ); + foreach ( $posts as $post ) { + $items[] = array( + 'id' => "post-{$post->ID}", + 'title' => html_entity_decode( get_the_title( $post ) ), + 'type' => 'post_type', + 'type_label' => get_post_type_object( $post->post_type )->labels->singular_name, + 'object' => $post->post_type, + 'object_id' => (int) $post->ID, + ); + } + } else if ( 'taxonomy' === $obj_type ) { + $terms = get_terms( $taxonomy_or_post_type, array( + 'child_of' => 0, + 'exclude' => '', + 'hide_empty' => false, + 'hierarchical' => 1, + 'include' => '', + 'number' => 10, + 'offset' => 10 * $page, + 'order' => 'DESC', + 'orderby' => 'count', + 'pad_counts' => false, + ) ); + if ( is_wp_error( $terms ) ) { + wp_send_json_error( array( 'message' => wp_strip_all_tags( $terms->get_error_message(), true ) ) ); + } + + foreach ( $terms as $term ) { + $items[] = array( + 'id' => "term-{$term->term_id}", + 'title' => html_entity_decode( $term->name ), + 'type' => 'taxonomy', + 'type_label' => get_taxonomy( $term->taxonomy )->labels->singular_name, + 'object' => $term->taxonomy, + 'object_id' => $term->term_id, + ); + } + } + + wp_send_json_success( array( 'items' => $items ) ); + } + + /** + * Ajax handler for searching available menu items. + * + * @since 4.3.0 + */ + public function ajax_search_available_items() { + check_ajax_referer( 'customize-menus', 'customize-menus-nonce' ); + + if ( ! current_user_can( 'edit_theme_options' ) ) { + wp_send_json_error( array( 'message' => __( 'Error: invalid user capabilities.' ) ) ); + } + if ( empty( $_POST['search'] ) ) { + wp_send_json_error( array( 'message' => __( 'Error: missing search parameter.' ) ) ); + } + + $p = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 0; + if ( $p < 1 ) { + $p = 1; + } + + $s = sanitize_text_field( wp_unslash( $_POST['search'] ) ); + $results = $this->search_available_items_query( array( 'pagenum' => $p, 's' => $s ) ); + + if ( empty( $results ) ) { + wp_send_json_error( array( 'message' => __( 'No results found.' ) ) ); + } else { + wp_send_json_success( array( 'items' => $results ) ); + } + } + + /** + * Performs post queries for available-item searching. + * + * Based on WP_Editor::wp_link_query(). + * + * @since 4.3.0 + * + * @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments. + * @return array Results. + */ + public function search_available_items_query( $args = array() ) { + $results = array(); + + $post_type_objects = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' ); + $query = array( + 'post_type' => array_keys( $post_type_objects ), + 'suppress_filters' => true, + 'update_post_term_cache' => false, + 'update_post_meta_cache' => false, + 'post_status' => 'publish', + 'posts_per_page' => 20, + ); + + $args['pagenum'] = isset( $args['pagenum'] ) ? absint( $args['pagenum'] ) : 1; + $query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0; + + if ( isset( $args['s'] ) ) { + $query['s'] = $args['s']; + } + + // Query posts. + $get_posts = new WP_Query( $query ); + + // Check if any posts were found. + if ( $get_posts->post_count ) { + foreach ( $get_posts->posts as $post ) { + $results[] = array( + 'id' => 'post-' . $post->ID, + 'type' => 'post_type', + 'type_label' => $post_type_objects[ $post->post_type ]->labels->singular_name, + 'object' => $post->post_type, + 'object_id' => intval( $post->ID ), + 'title' => html_entity_decode( get_the_title( $post ) ), + ); + } + } + + // Query taxonomy terms. + $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'names' ); + $terms = get_terms( $taxonomies, array( + 'name__like' => $args['s'], + 'number' => 20, + 'offset' => 20 * ($args['pagenum'] - 1), + ) ); + + // Check if any taxonomies were found. + if ( ! empty( $terms ) ) { + foreach ( $terms as $term ) { + $results[] = array( + 'id' => 'term-' . $term->term_id, + 'type' => 'taxonomy', + 'type_label' => get_taxonomy( $term->taxonomy )->labels->singular_name, + 'object' => $term->taxonomy, + 'object_id' => intval( $term->term_id ), + 'title' => html_entity_decode( $term->name ), + ); + } + } + + return $results; + } + + /** + * Enqueue scripts and styles for Customizer pane. + * + * @since 4.3.0 + */ + public function enqueue_scripts() { + wp_enqueue_style( 'customize-nav-menus' ); + wp_enqueue_script( 'customize-nav-menus' ); + + $temp_nav_menu_setting = new WP_Customize_Nav_Menu_Setting( $this->manager, 'nav_menu[-1]' ); + $temp_nav_menu_item_setting = new WP_Customize_Nav_Menu_Item_Setting( $this->manager, 'nav_menu_item[-1]' ); + + // Pass data to JS. + $settings = array( + 'nonce' => wp_create_nonce( 'customize-menus' ), + 'allMenus' => wp_get_nav_menus(), + 'itemTypes' => $this->available_item_types(), + 'l10n' => array( + 'untitled' => _x( '(no label)', 'Missing menu item navigation label.' ), + 'custom_label' => _x( 'Custom', 'Custom menu item type label.' ), + 'menuLocation' => _x( '(Currently set to: %s)', 'Current menu location.' ), + 'deleteWarn' => __( 'You are about to permanently delete this menu. "Cancel" to stop, "OK" to delete.' ), + 'itemAdded' => __( 'Menu item added' ), + 'itemDeleted' => __( 'Menu item deleted' ), + 'menuAdded' => __( 'Menu created' ), + 'menuDeleted' => __( 'Menu deleted' ), + 'movedUp' => __( 'Menu item moved up' ), + 'movedDown' => __( 'Menu item moved down' ), + 'movedLeft' => __( 'Menu item moved out of submenu' ), + 'movedRight' => __( 'Menu item is now a sub-item' ), + 'customizingMenus' => _x( 'Customizing ▸ Menus', '▸ is the unicode right-pointing triangle' ), + 'invalidTitleTpl' => __( '%s (Invalid)' ), + 'pendingTitleTpl' => __( '%s (Pending)' ), + 'taxonomyTermLabel' => __( 'Taxonomy' ), + 'postTypeLabel' => __( 'Post Type' ), + ), + 'menuItemTransport' => 'postMessage', + 'phpIntMax' => PHP_INT_MAX, + 'defaultSettingValues' => array( + 'nav_menu' => $temp_nav_menu_setting->default, + 'nav_menu_item' => $temp_nav_menu_item_setting->default, + ), + ); + + $data = sprintf( 'var _wpCustomizeNavMenusSettings = %s;', wp_json_encode( $settings ) ); + wp_scripts()->add_data( 'customize-nav-menus', 'data', $data ); + + // This is copied from nav-menus.php, and it has an unfortunate object name of `menus`. + $nav_menus_l10n = array( + 'oneThemeLocationNoMenus' => null, + 'moveUp' => __( 'Move up one' ), + 'moveDown' => __( 'Move down one' ), + 'moveToTop' => __( 'Move to the top' ), + /* translators: %s: previous item name */ + 'moveUnder' => __( 'Move under %s' ), + /* translators: %s: previous item name */ + 'moveOutFrom' => __( 'Move out from under %s' ), + /* translators: %s: previous item name */ + 'under' => __( 'Under %s' ), + /* translators: %s: previous item name */ + 'outFrom' => __( 'Out from under %s' ), + /* translators: 1: item name, 2: item position, 3: total number of items */ + 'menuFocus' => __( '%1$s. Menu item %2$d of %3$d.' ), + /* translators: 1: item name, 2: item position, 3: parent item name */ + 'subMenuFocus' => __( '%1$s. Sub item number %2$d under %3$s.' ), + ); + wp_localize_script( 'nav-menu', 'menus', $nav_menus_l10n ); + } + + /** + * Filter a dynamic setting's constructor args. + * + * For a dynamic setting to be registered, this filter must be employed + * to override the default false value with an array of args to pass to + * the WP_Customize_Setting constructor. + * + * @since 4.3.0 + * + * @param false|array $setting_args The arguments to the WP_Customize_Setting constructor. + * @param string $setting_id ID for dynamic setting, usually coming from `$_POST['customized']`. + * @return array|false + */ + public function filter_dynamic_setting_args( $setting_args, $setting_id ) { + if ( preg_match( WP_Customize_Nav_Menu_Setting::ID_PATTERN, $setting_id ) ) { + $setting_args = array( + 'type' => WP_Customize_Nav_Menu_Setting::TYPE, + ); + } else if ( preg_match( WP_Customize_Nav_Menu_Item_Setting::ID_PATTERN, $setting_id ) ) { + $setting_args = array( + 'type' => WP_Customize_Nav_Menu_Item_Setting::TYPE, + ); + } + return $setting_args; + } + + /** + * Allow non-statically created settings to be constructed with custom WP_Customize_Setting subclass. + * + * @since 4.3.0 + * + * @param string $setting_class WP_Customize_Setting or a subclass. + * @param string $setting_id ID for dynamic setting, usually coming from `$_POST['customized']`. + * @param array $setting_args WP_Customize_Setting or a subclass. + * @return string + */ + public function filter_dynamic_setting_class( $setting_class, $setting_id, $setting_args ) { + unset( $setting_id ); + + if ( ! empty( $setting_args['type'] ) && WP_Customize_Nav_Menu_Setting::TYPE === $setting_args['type'] ) { + $setting_class = 'WP_Customize_Nav_Menu_Setting'; + } else if ( ! empty( $setting_args['type'] ) && WP_Customize_Nav_Menu_Item_Setting::TYPE === $setting_args['type'] ) { + $setting_class = 'WP_Customize_Nav_Menu_Item_Setting'; + } + return $setting_class; + } + + /** + * Add the customizer settings and controls. + * + * @since 4.3.0 + */ + public function customize_register() { + + // Require JS-rendered control types. + $this->manager->register_panel_type( 'WP_Customize_Nav_Menus_Panel' ); + $this->manager->register_control_type( 'WP_Customize_Nav_Menu_Control' ); + $this->manager->register_control_type( 'WP_Customize_Nav_Menu_Name_Control' ); + $this->manager->register_control_type( 'WP_Customize_Nav_Menu_Item_Control' ); + + // Create a panel for Menus. + $this->manager->add_panel( new WP_Customize_Nav_Menus_Panel( $this->manager, 'nav_menus', array( + 'title' => __( 'Menus' ), + 'description' => '

    ' . __( 'This panel is used for managing navigation menus for content you have already published on your site. You can create menus and add items for existing content such as pages, posts, categories, tags, formats, or custom links.' ) . '

    ' . __( 'Menus can be displayed in locations defined by your theme or in widget areas by adding a "Custom Menu" widget.' ) . '

    ', + 'priority' => 100, + // 'theme_supports' => 'menus|widgets', @todo allow multiple theme supports + ) ) ); + $menus = wp_get_nav_menus(); + + // Menu loactions. + $locations = get_registered_nav_menus(); + $num_locations = count( array_keys( $locations ) ); + $description = '

    ' . sprintf( _n( 'Your theme contains %s menu location. Select which menu you would like to use.', 'Your theme contains %s menu locations. Select which menu appears in each location.', $num_locations ), number_format_i18n( $num_locations ) ); + $description .= '

    ' . __( 'You can also place menus in widget areas with the Custom Menu widget.' ) . '

    '; + + $this->manager->add_section( 'menu_locations', array( + 'title' => __( 'Menu Locations' ), + 'panel' => 'nav_menus', + 'priority' => 5, + 'description' => $description, + ) ); + + // @todo if ( ! $menus ) : make a "default" menu + if ( $menus ) { + $choices = array( '0' => __( '— Select —' ) ); + foreach ( $menus as $menu ) { + $choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '…' ); + } + + foreach ( $locations as $location => $description ) { + $setting_id = "nav_menu_locations[{$location}]"; + + $setting = $this->manager->get_setting( $setting_id ); + if ( $setting ) { + $setting->transport = 'postMessage'; + remove_filter( "customize_sanitize_{$setting_id}", 'absint' ); + add_filter( "customize_sanitize_{$setting_id}", array( $this, 'intval_base10' ) ); + } else { + $this->manager->add_setting( $setting_id, array( + 'sanitize_callback' => array( $this, 'intval_base10' ), + 'theme_supports' => 'menus', + 'type' => 'theme_mod', + 'transport' => 'postMessage', + ) ); + } + + $this->manager->add_control( new WP_Customize_Nav_Menu_Location_Control( $this->manager, $setting_id, array( + 'label' => $description, + 'location_id' => $location, + 'section' => 'menu_locations', + 'choices' => $choices, + ) ) ); + } + } + + // Register each menu as a Customizer section, and add each menu item to each menu. + foreach ( $menus as $menu ) { + $menu_id = $menu->term_id; + + // Create a section for each menu. + $section_id = 'nav_menu[' . $menu_id . ']'; + $this->manager->add_section( new WP_Customize_Nav_Menu_Section( $this->manager, $section_id, array( + 'title' => html_entity_decode( $menu->name ), + 'priority' => 10, + 'panel' => 'nav_menus', + ) ) ); + + $nav_menu_setting_id = 'nav_menu[' . $menu_id . ']'; + $this->manager->add_setting( new WP_Customize_Nav_Menu_Setting( $this->manager, $nav_menu_setting_id ) ); + + // Add the menu contents. + $menu_items = (array) wp_get_nav_menu_items( $menu_id ); + + foreach ( array_values( $menu_items ) as $i => $item ) { + + // Create a setting for each menu item (which doesn't actually manage data, currently). + $menu_item_setting_id = 'nav_menu_item[' . $item->ID . ']'; + $this->manager->add_setting( new WP_Customize_Nav_Menu_Item_Setting( $this->manager, $menu_item_setting_id ) ); + + // Create a control for each menu item. + $this->manager->add_control( new WP_Customize_Nav_Menu_Item_Control( $this->manager, $menu_item_setting_id, array( + 'label' => $item->title, + 'section' => $section_id, + 'priority' => 10 + $i, + ) ) ); + } + + // Note: other controls inside of this section get added dynamically in JS via the MenuSection.ready() function. + } + + // Add the add-new-menu section and controls. + $this->manager->add_section( new WP_Customize_New_Menu_Section( $this->manager, 'add_menu', array( + 'title' => __( 'Add a Menu' ), + 'panel' => 'nav_menus', + 'priority' => 999, + ) ) ); + + $this->manager->add_setting( 'new_menu_name', array( + 'type' => 'new_menu', + 'default' => '', + 'transport' => 'postMessage', + ) ); + + $this->manager->add_control( 'new_menu_name', array( + 'label' => '', + 'section' => 'add_menu', + 'type' => 'text', + 'input_attrs' => array( + 'class' => 'menu-name-field', + 'placeholder' => __( 'New menu name' ), + ), + ) ); + + $this->manager->add_setting( 'create_new_menu', array( + 'type' => 'new_menu', + ) ); + + $this->manager->add_control( new WP_New_Menu_Customize_Control( $this->manager, 'create_new_menu', array( + 'section' => 'add_menu', + ) ) ); + } + + /** + * Get the base10 intval. + * + * This is used as a setting's sanitize_callback; we can't use just plain + * intval because the second argument is not what intval() expects. + * + * @since 4.3.0 + * + * @param mixed $value Number to convert. + * + * @return int + */ + function intval_base10( $value ) { + return intval( $value, 10 ); + } + + /** + * Return an array of all the available item types. + * + * @since 4.3.0 + */ + public function available_item_types() { + $items = array( + 'postTypes' => array(), + 'taxonomies' => array(), + ); + + $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' ); + foreach ( $post_types as $slug => $post_type ) { + $items['postTypes'][ $slug ] = array( + 'label' => $post_type->labels->singular_name, + ); + } + + $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'objects' ); + foreach ( $taxonomies as $slug => $taxonomy ) { + if ( 'post_format' === $taxonomy && ! current_theme_supports( 'post-formats' ) ) { + continue; + } + $items['taxonomies'][ $slug ] = array( + 'label' => $taxonomy->labels->singular_name, + ); + } + return $items; + } + + /** + * Print the JavaScript templates used to render Menu Customizer components. + * + * Templates are imported into the JS use wp.template. + * + * @since 4.3.0 + */ + public function print_templates() { + ?> + + + + + + +
    +
    + +

    + + manager->get_panel( 'nav_menus' )->title ) ); + ?> + + +

    +
    + +
    +

    +
    + + + +

    + + + + +

    +
    +
    + true ), 'object' ); + if ( $post_types ) : + foreach ( $post_types as $type ) : + ?> +
    +

    label ); ?>

    +
    +
    + true ), 'object' ); + if ( $taxonomies ) : + foreach ( $taxonomies as $tax ) : + ?> +
    +

    label ); ?>

    +
    +
    + +
    + preview_nav_menu_instance_number += 1; + $args['instance_number'] = $this->preview_nav_menu_instance_number; + + $can_partial_refresh = ( + $args['echo'] + && + is_string( $args['fallback_cb'] ) + && + is_string( $args['walker'] ) + ); + $args['can_partial_refresh'] = $can_partial_refresh; + + if ( ! $can_partial_refresh ) { + unset( $args['fallback_cb'] ); + unset( $args['walker'] ); + } + + ksort( $args ); + $args['args_hash'] = $this->hash_nav_menu_args( $args ); + + $this->preview_nav_menu_instance_args[ $this->preview_nav_menu_instance_number ] = $args; + return $args; + } + + /** + * Prepare wp_nav_menu() calls for partial refresh. Wraps output in container for refreshing. + * + * @since 4.3.0 + * + * @see wp_nav_menu() + * + * @param string $nav_menu_content The HTML content for the navigation menu. + * @param object $args An object containing wp_nav_menu() arguments. + * @return null + */ + function filter_wp_nav_menu( $nav_menu_content, $args ) { + if ( ! empty( $args->can_partial_refresh ) && ! empty( $args->instance_number ) ) { + $nav_menu_content = sprintf( + '
    %2$s
    ', + $args->instance_number, + $nav_menu_content + ); + } + return $nav_menu_content; + } + + /** + * Hash (hmac) the arguments with the nonce and secret auth key to ensure they + * are not tampered with when submitted in the Ajax request. + * + * @since 4.3.0 + * + * @param array $args The arguments to hash. + * @return string + */ + function hash_nav_menu_args( $args ) { + return wp_hash( wp_create_nonce( self::RENDER_AJAX_ACTION ) . serialize( $args ) ); + } + + /** + * Enqueue scripts for the Customizer preview. + * + * @since 4.3.0 + */ + function customize_preview_enqueue_deps() { + wp_enqueue_script( 'customize-preview-nav-menus' ); + wp_enqueue_style( 'customize-preview' ); + + add_action( 'wp_print_footer_scripts', array( $this, 'export_preview_data' ) ); + } + + /** + * Export data from PHP to JS. + * + * @since 4.3.0 + */ + function export_preview_data() { + + // Why not wp_localize_script? Because we're not localizing, and it forces values into strings. + $exports = array( + 'renderQueryVar' => self::RENDER_QUERY_VAR, + 'renderNonceValue' => wp_create_nonce( self::RENDER_AJAX_ACTION ), + 'renderNoncePostKey' => self::RENDER_NONCE_POST_KEY, + 'requestUri' => '/', + 'theme' => array( + 'stylesheet' => $this->manager->get_stylesheet(), + 'active' => $this->manager->is_theme_active(), + ), + 'previewCustomizeNonce' => wp_create_nonce( 'preview-customize_' . $this->manager->get_stylesheet() ), + 'navMenuInstanceArgs' => $this->preview_nav_menu_instance_args, + ); + + if ( ! empty( $_SERVER['REQUEST_URI'] ) ) { + $exports['requestUri'] = esc_url_raw( home_url( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ); + } + + printf( '', wp_json_encode( $exports ) ); + } + + /** + * Render a specific menu via wp_nav_menu() using the supplied arguments. + * + * @since 4.3.0 + * + * @see wp_nav_menu() + */ + function render_menu() { + if ( empty( $_POST[ self::RENDER_QUERY_VAR ] ) ) { + return; + } + + $this->manager->remove_preview_signature(); + + if ( empty( $_POST[ self::RENDER_NONCE_POST_KEY ] ) ) { + wp_send_json_error( 'missing_nonce_param' ); + } + + if ( ! is_customize_preview() ) { + wp_send_json_error( 'expected_customize_preview' ); + } + + if ( ! check_ajax_referer( self::RENDER_AJAX_ACTION, self::RENDER_NONCE_POST_KEY, false ) ) { + wp_send_json_error( 'nonce_check_fail' ); + } + + if ( ! current_user_can( 'edit_theme_options' ) ) { + wp_send_json_error( 'unauthorized' ); + } + + if ( ! isset( $_POST['wp_nav_menu_args'] ) ) { + wp_send_json_error( 'missing_param' ); + } + + if ( ! isset( $_POST['wp_nav_menu_args_hash'] ) ) { + wp_send_json_error( 'missing_param' ); + } + + $wp_nav_menu_args = json_decode( wp_unslash( $_POST['wp_nav_menu_args'] ), true ); + if ( ! is_array( $wp_nav_menu_args ) ) { + wp_send_json_error( 'wp_nav_menu_args_not_array' ); + } + + $wp_nav_menu_args_hash = sanitize_text_field( wp_unslash( $_POST['wp_nav_menu_args_hash'] ) ); + if ( ! hash_equals( $this->hash_nav_menu_args( $wp_nav_menu_args ), $wp_nav_menu_args_hash ) ) { + wp_send_json_error( 'wp_nav_menu_args_hash_mismatch' ); + } + + $wp_nav_menu_args['echo'] = false; + wp_send_json_success( wp_nav_menu( $wp_nav_menu_args ) ); + } +} diff --git a/wp-includes/class-wp-customize-section.php b/wp-includes/class-wp-customize-section.php index a48f0dfacc..8bc6bf60c4 100644 --- a/wp-includes/class-wp-customize-section.php +++ b/wp-includes/class-wp-customize-section.php @@ -501,3 +501,74 @@ class WP_Customize_Sidebar_Section extends WP_Customize_Section { return $this->manager->widgets->is_sidebar_rendered( $this->sidebar_id ); } } + +/** + * Customize Menu Section Class + * + * Custom section only needed in JS. + * + * @since 4.3.0 + */ +class WP_Customize_Nav_Menu_Section extends WP_Customize_Section { + + /** + * Control type. + * + * @since 4.3.0 + * + * @access public + * @var string + */ + public $type = 'nav_menu'; + + /** + * Get section params for JS. + * + * @since 4.3.0 + * + * @return array + */ + function json() { + $exported = parent::json(); + $exported['menu_id'] = intval( preg_replace( '/^nav_menu\[(\d+)\]/', '$1', $this->id ) ); + + return $exported; + } +} + +/** + * Customize Menu Section Class + * + * Implements the new-menu-ui toggle button instead of a regular section. + * + * @since 4.3.0 + */ +class WP_Customize_New_Menu_Section extends WP_Customize_Section { + + /** + * Control type. + * + * @since 4.3.0 + * + * @access public + * @var string + */ + public $type = 'new_menu'; + + /** + * Render the section, and the controls that have been added to it. + * + * @since 4.3.0 + */ + protected function render() { + ?> +
  • + + +
  • + -?\d+)\]$/'; + + const POST_TYPE = 'nav_menu_item'; + + const TYPE = 'nav_menu_item'; + + /** + * Setting type. + * + * @since 4.3.0 + * + * @var string + */ + public $type = self::TYPE; + + /** + * Default setting value. + * + * @since 4.3.0 + * + * @see wp_setup_nav_menu_item() + * @var array + */ + public $default = array( + // The $menu_item_data for wp_update_nav_menu_item(). + 'object_id' => 0, + 'object' => '', // Taxonomy name. + 'menu_item_parent' => 0, // A.K.A. menu-item-parent-id; note that post_parent is different, and not included. + 'position' => 0, // A.K.A. menu_order. + 'type' => 'custom', // Note that type_label is not included here. + 'title' => '', + 'url' => '', + 'target' => '', + 'attr_title' => '', + 'description' => '', + 'classes' => '', + 'xfn' => '', + 'status' => 'publish', + 'original_title' => '', + 'nav_menu_term_id' => 0, // This will be supplied as the $menu_id arg for wp_update_nav_menu_item(). + // @todo also expose invalid? + ); + + /** + * Default transport. + * + * @since 4.3.0 + * + * @var string + */ + public $transport = 'postMessage'; + + /** + * The post ID represented by this setting instance. This is the db_id. + * + * A negative value represents a placeholder ID for a new menu not yet saved. + * + * @todo Should this be $db_id, and also use this for WP_Customize_Nav_Menu_Setting::$term_id + * + * @since 4.3.0 + * + * @var int + */ + public $post_id; + + /** + * Previous (placeholder) post ID used before creating a new menu item. + * + * This value will be exported to JS via the customize_save_response filter + * so that JavaScript can update the settings to refer to the newly-assigned + * post ID. This value is always negative to indicate it does not refer to + * a real post. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Item_Setting::update() + * @see WP_Customize_Nav_Menu_Item_Setting::amend_customize_save_response() + * + * @var int + */ + public $previous_post_id; + + /** + * When previewing or updating a menu item, this stores the previous nav_menu_term_id + * which ensures that we can apply the proper filters. + * + * @since 4.3.0 + * + * @var int + */ + public $original_nav_menu_term_id; + + /** + * Whether or not preview() was called. + * + * @since 4.3.0 + * + * @var bool + */ + protected $is_previewed = false; + + /** + * Whether or not update() was called. + * + * @since 4.3.0 + * + * @var bool + */ + protected $is_updated = false; + + /** + * Status for calling the update method, used in customize_save_response filter. + * + * When status is inserted, the placeholder post ID is stored in $previous_post_id. + * When status is error, the error is stored in $update_error. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Item_Setting::update() + * @see WP_Customize_Nav_Menu_Item_Setting::amend_customize_save_response() + * + * @var string updated|inserted|deleted|error + */ + public $update_status; + + /** + * Any error object returned by wp_update_nav_menu_item() when setting is updated. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Item_Setting::update() + * @see WP_Customize_Nav_Menu_Item_Setting::amend_customize_save_response() + * + * @var WP_Error + */ + public $update_error; + + /** + * Constructor. + * + * Any supplied $args override class property defaults. + * + * @since 4.3.0 + * + * @param WP_Customize_Manager $manager Manager instance. + * @param string $id An specific ID of the setting. Can be a + * theme mod or option name. + * @param array $args Optional. Setting arguments. + * @throws Exception If $id is not valid for this setting type. + */ + public function __construct( WP_Customize_Manager $manager, $id, array $args = array() ) { + if ( empty( $manager->nav_menus ) ) { + throw new Exception( 'Expected WP_Customize_Manager::$nav_menus to be set.' ); + } + + if ( ! preg_match( self::ID_PATTERN, $id, $matches ) ) { + throw new Exception( "Illegal widget setting ID: $id" ); + } + + $this->post_id = intval( $matches['id'] ); + + $menu = $this->value(); + $this->original_nav_menu_term_id = $menu['nav_menu_term_id']; + + parent::__construct( $manager, $id, $args ); + } + + /** + * Get the instance data for a given widget setting. + * + * @since 4.3.0 + * + * @see wp_setup_nav_menu_item() + * + * @return array + */ + public function value() { + if ( $this->is_previewed && $this->_previewed_blog_id === get_current_blog_id() ) { + $undefined = new stdClass(); // Symbol. + $post_value = $this->post_value( $undefined ); + + if ( $undefined === $post_value ) { + $value = $this->_original_value; + } else { + $value = $post_value; + } + } else { + $value = false; + + // Note that a ID of less than one indicates a nav_menu not yet inserted. + if ( $this->post_id > 0 ) { + $post = get_post( $this->post_id ); + if ( $post && self::POST_TYPE === $post->post_type ) { + $item = wp_setup_nav_menu_item( $post ); + $value = wp_array_slice_assoc( + (array) $item, + array_keys( $this->default ) + ); + $value['position'] = $item->menu_order; + $value['status'] = $item->post_status; + $value['original_title'] = ''; + + $menus = wp_get_post_terms( $post->ID, WP_Customize_Nav_Menu_Setting::TAXONOMY, array( + 'fields' => 'ids', + ) ); + + if ( ! empty( $menus ) ) { + $value['nav_menu_term_id'] = array_shift( $menus ); + } else { + $value['nav_menu_term_id'] = 0; + } + + if ( 'post_type' === $value['type'] ) { + $original_title = get_the_title( $value['object_id'] ); + } else if ( 'taxonomy' === $value['type'] ) { + $original_title = get_term_field( 'name', $value['object_id'], $value['object'], 'raw' ); + if ( is_wp_error( $original_title ) ) { + $original_title = ''; + } + } + + if ( ! empty( $original_title ) ) { + $value['original_title'] = $original_title; + } + } + } + + if ( ! is_array( $value ) ) { + $value = $this->default; + } + } + + if ( is_array( $value ) ) { + foreach ( array( 'object_id', 'menu_item_parent', 'nav_menu_term_id' ) as $key ) { + $value[ $key ] = intval( $value[ $key ] ); + } + } + + return $value; + } + + /** + * Handle previewing the setting. + * + * @since 4.3.0 + * + * @see WP_Customize_Manager::post_value() + */ + public function preview() { + if ( $this->is_previewed ) { + return; + } + + $this->is_previewed = true; + $this->_original_value = $this->value(); + $this->original_nav_menu_term_id = $this->_original_value['nav_menu_term_id']; + $this->_previewed_blog_id = get_current_blog_id(); + + add_filter( 'wp_get_nav_menu_items', array( $this, 'filter_wp_get_nav_menu_items' ), 10, 3 ); + + $sort_callback = array( __CLASS__, 'sort_wp_get_nav_menu_items' ); + if ( ! has_filter( 'wp_get_nav_menu_items', $sort_callback ) ) { + add_filter( 'wp_get_nav_menu_items', array( __CLASS__, 'sort_wp_get_nav_menu_items' ), 1000, 3 ); + } + + // @todo Add get_post_metadata filters for plugins to add their data. + } + + /** + * Filter the wp_get_nav_menu_items() result to supply the previewed menu items. + * + * @since 4.3.0 + * + * @see wp_get_nav_menu_items() + * + * @param array $items An array of menu item post objects. + * @param object $menu The menu object. + * @param array $args An array of arguments used to retrieve menu item objects. + * @return array Array of menu items, + */ + function filter_wp_get_nav_menu_items( $items, $menu, $args ) { + $this_item = $this->value(); + $current_nav_menu_term_id = $this_item['nav_menu_term_id']; + unset( $this_item['nav_menu_term_id'] ); + + $should_filter = ( + $menu->term_id === $this->original_nav_menu_term_id + || + $menu->term_id === $current_nav_menu_term_id + ); + if ( ! $should_filter ) { + return $items; + } + + // Handle deleted menu item, or menu item moved to another menu. + $should_remove = ( + false === $this_item + || + ( + $this->original_nav_menu_term_id === $menu->term_id + && + $current_nav_menu_term_id !== $this->original_nav_menu_term_id + ) + ); + if ( $should_remove ) { + $filtered_items = array(); + foreach ( $items as $item ) { + if ( $item->db_id !== $this->post_id ) { + $filtered_items[] = $item; + } + } + return $filtered_items; + } + + $mutated = false; + $should_update = ( + is_array( $this_item ) + && + $current_nav_menu_term_id === $menu->term_id + ); + if ( $should_update ) { + foreach ( $items as $item ) { + if ( $item->db_id === $this->post_id ) { + foreach ( get_object_vars( $this->value_as_wp_post_nav_menu_item() ) as $key => $value ) { + $item->$key = $value; + } + $mutated = true; + } + } + + // Not found so we have to append it.. + if ( ! $mutated ) { + $items[] = $this->value_as_wp_post_nav_menu_item(); + } + } + + return $items; + } + + /** + * Re-apply the tail logic also applied on $items by wp_get_nav_menu_items(). + * + * @since 4.3.0 + * + * @see wp_get_nav_menu_items() + * + * @param array $items An array of menu item post objects. + * @param object $menu The menu object. + * @param array $args An array of arguments used to retrieve menu item objects. + * @return array Array of menu items, + */ + static function sort_wp_get_nav_menu_items( $items, $menu, $args ) { + // @todo We should probably re-apply some constraints imposed by $args. + unset( $args['include'] ); + + // Remove invalid items only in frontend. + if ( ! is_admin() ) { + $items = array_filter( $items, '_is_valid_nav_menu_item' ); + } + + if ( ARRAY_A === $args['output'] ) { + $GLOBALS['_menu_item_sort_prop'] = $args['output_key']; + usort( $items, '_sort_nav_menu_items' ); + $i = 1; + + foreach ( $items as $k => $item ) { + $items[ $k ]->$args['output_key'] = $i++; + } + } + + return $items; + } + + /** + * Get the value emulated into a WP_Post and set up as a nav_menu_item. + * + * @since 4.3.0 + * + * @return WP_Post With {@see wp_setup_nav_menu_item()} applied. + */ + public function value_as_wp_post_nav_menu_item() { + $item = (object) $this->value(); + unset( $item->nav_menu_term_id ); + + $item->post_status = $item->status; + unset( $item->status ); + + $item->post_type = 'nav_menu_item'; + $item->menu_order = $item->position; + unset( $item->position ); + + $item->post_author = get_current_user_id(); + + if ( $item->title ) { + $item->post_title = $item->title; + } + + $item->ID = $this->post_id; + $post = new WP_Post( (object) $item ); + $post = wp_setup_nav_menu_item( $post ); + + return $post; + } + + /** + * Sanitize an input. + * + * Note that parent::sanitize() erroneously does wp_unslash() on $value, but + * we remove that in this override. + * + * @since 4.3.0 + * + * @param array $menu_item_value The value to sanitize. + * @return array|false|null Null if an input isn't valid. False if it is marked for deletion. Otherwise the sanitized value. + */ + public function sanitize( $menu_item_value ) { + // Menu is marked for deletion. + if ( false === $menu_item_value ) { + return $menu_item_value; + } + + // Invalid. + if ( ! is_array( $menu_item_value ) ) { + return null; + } + + $default = array( + 'object_id' => 0, + 'object' => '', + 'menu_item_parent' => 0, + 'position' => 0, + 'type' => 'custom', + 'title' => '', + 'url' => '', + 'target' => '', + 'attr_title' => '', + 'description' => '', + 'classes' => '', + 'xfn' => '', + 'status' => 'publish', + 'original_title' => '', + 'nav_menu_term_id' => 0, + ); + $menu_item_value = array_merge( $default, $menu_item_value ); + $menu_item_value = wp_array_slice_assoc( $menu_item_value, array_keys( $default ) ); + $menu_item_value['position'] = max( 0, intval( $menu_item_value['position'] ) ); + + foreach ( array( 'object_id', 'menu_item_parent', 'nav_menu_term_id' ) as $key ) { + // Note we need to allow negative-integer IDs for previewed objects not inserted yet. + $menu_item_value[ $key ] = intval( $menu_item_value[ $key ] ); + } + + foreach ( array( 'type', 'object', 'target' ) as $key ) { + $menu_item_value[ $key ] = sanitize_key( $menu_item_value[ $key ] ); + } + + foreach ( array( 'xfn', 'classes' ) as $key ) { + $value = $menu_item_value[ $key ]; + if ( ! is_array( $value ) ) { + $value = explode( ' ', $value ); + } + $menu_item_value[ $key ] = implode( ' ', array_map( 'sanitize_html_class', $value ) ); + } + + foreach ( array( 'title', 'attr_title', 'description', 'original_title' ) as $key ) { + // @todo Should esc_attr() the attr_title as well? + $menu_item_value[ $key ] = sanitize_text_field( $menu_item_value[ $key ] ); + } + + $menu_item_value['url'] = esc_url_raw( $menu_item_value['url'] ); + if ( ! get_post_status_object( $menu_item_value['status'] ) ) { + $menu_item_value['status'] = 'publish'; + } + + /** This filter is documented in wp-includes/class-wp-customize-setting.php */ + return apply_filters( "customize_sanitize_{$this->id}", $menu_item_value, $this ); + } + + /** + * Create/update the nav_menu_item post for this setting. + * + * Any created menu items will have their assigned post IDs exported to the client + * via the customize_save_response filter. Likewise, any errors will be exported + * to the client via the customize_save_response() filter. + * + * To delete a menu, the client can send false as the value. + * + * @since 4.3.0 + * + * @see wp_update_nav_menu_item() + * + * @param array|false $value The menu item array to update. If false, then the menu item will be deleted entirely. + * See {@see WP_Customize_Nav_Menu_Item_Setting::$default} for what the value should + * consist of. + * @return void + */ + protected function update( $value ) { + if ( $this->is_updated ) { + return; + } + + $this->is_updated = true; + $is_placeholder = ( $this->post_id < 0 ); + $is_delete = ( false === $value ); + + add_filter( 'customize_save_response', array( $this, 'amend_customize_save_response' ) ); + + if ( $is_delete ) { + // If the current setting post is a placeholder, a delete request is a no-op. + if ( $is_placeholder ) { + $this->update_status = 'deleted'; + } else { + $r = wp_delete_post( $this->post_id, true ); + + if ( false === $r ) { + $this->update_error = new WP_Error( 'delete_failure' ); + $this->update_status = 'error'; + } else { + $this->update_status = 'deleted'; + } + // @todo send back the IDs for all associated nav menu items deleted, so these settings (and controls) can be removed from Customizer? + } + } else { + + // Handle saving menu items for menus that are being newly-created. + if ( $value['nav_menu_term_id'] < 0 ) { + $nav_menu_setting_id = sprintf( 'nav_menu[%s]', $value['nav_menu_term_id'] ); + $nav_menu_setting = $this->manager->get_setting( $nav_menu_setting_id ); + + if ( ! $nav_menu_setting || ! ( $nav_menu_setting instanceof WP_Customize_Nav_Menu_Setting ) ) { + $this->update_status = 'error'; + $this->update_error = new WP_Error( 'unexpected_nav_menu_setting' ); + return; + } + + if ( false === $nav_menu_setting->save() ) { + $this->update_status = 'error'; + $this->update_error = new WP_Error( 'nav_menu_setting_failure' ); + } + + if ( $nav_menu_setting->previous_term_id !== intval( $value['nav_menu_term_id'] ) ) { + $this->update_status = 'error'; + $this->update_error = new WP_Error( 'unexpected_previous_term_id' ); + return; + } + + $value['nav_menu_term_id'] = $nav_menu_setting->term_id; + } + + // Handle saving a nav menu item that is a child of a nav menu item being newly-created. + if ( $value['menu_item_parent'] < 0 ) { + $parent_nav_menu_item_setting_id = sprintf( 'nav_menu_item[%s]', $value['menu_item_parent'] ); + $parent_nav_menu_item_setting = $this->manager->get_setting( $parent_nav_menu_item_setting_id ); + + if ( ! $parent_nav_menu_item_setting || ! ( $parent_nav_menu_item_setting instanceof WP_Customize_Nav_Menu_Item_Setting ) ) { + $this->update_status = 'error'; + $this->update_error = new WP_Error( 'unexpected_nav_menu_item_setting' ); + return; + } + + if ( false === $parent_nav_menu_item_setting->save() ) { + $this->update_status = 'error'; + $this->update_error = new WP_Error( 'nav_menu_item_setting_failure' ); + } + + if ( $parent_nav_menu_item_setting->previous_post_id !== intval( $value['menu_item_parent'] ) ) { + $this->update_status = 'error'; + $this->update_error = new WP_Error( 'unexpected_previous_post_id' ); + return; + } + + $value['menu_item_parent'] = $parent_nav_menu_item_setting->post_id; + } + + // Insert or update menu. + $menu_item_data = array( + 'menu-item-object-id' => $value['object_id'], + 'menu-item-object' => $value['object'], + 'menu-item-parent-id' => $value['menu_item_parent'], + 'menu-item-position' => $value['position'], + 'menu-item-type' => $value['type'], + 'menu-item-title' => $value['title'], + 'menu-item-url' => $value['url'], + 'menu-item-description' => $value['description'], + 'menu-item-attr-title' => $value['attr_title'], + 'menu-item-target' => $value['target'], + 'menu-item-classes' => $value['classes'], + 'menu-item-xfn' => $value['xfn'], + 'menu-item-status' => $value['status'], + ); + + $r = wp_update_nav_menu_item( + $value['nav_menu_term_id'], + $is_placeholder ? 0 : $this->post_id, + $menu_item_data + ); + + if ( is_wp_error( $r ) ) { + $this->update_status = 'error'; + $this->update_error = $r; + } else { + if ( $is_placeholder ) { + $this->previous_post_id = $this->post_id; + $this->post_id = $r; + $this->update_status = 'inserted'; + } else { + $this->update_status = 'updated'; + } + } + } + + } + + /** + * Export data for the JS client. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Item_Setting::update() + * + * @param array $data Additional information passed back to the 'saved' event on `wp.customize`. + * @return array + */ + function amend_customize_save_response( $data ) { + if ( ! isset( $data['nav_menu_item_updates'] ) ) { + $data['nav_menu_item_updates'] = array(); + } + + $data['nav_menu_item_updates'][] = array( + 'post_id' => $this->post_id, + 'previous_post_id' => $this->previous_post_id, + 'error' => $this->update_error ? $this->update_error->get_error_code() : null, + 'status' => $this->update_status, + ); + + return $data; + } +} + +/** + * Customize Setting to represent a nav_menu. + * + * Subclass of WP_Customize_Setting to represent a nav_menu taxonomy term, and + * the IDs for the nav_menu_items associated with the nav menu. + * + * @since 4.3.0 + * + * @see wp_get_nav_menu_object() + * @see WP_Customize_Setting + */ +class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { + + const ID_PATTERN = '/^nav_menu\[(?P-?\d+)\]$/'; + + const TAXONOMY = 'nav_menu'; + + const TYPE = 'nav_menu'; + + /** + * Setting type. + * + * @since 4.3.0 + * + * @var string + */ + public $type = self::TYPE; + + /** + * Default setting value. + * + * @since 4.3.0 + * + * @see wp_get_nav_menu_object() + * + * @var array + */ + public $default = array( + 'name' => '', + 'description' => '', + 'parent' => 0, + 'auto_add' => false, + ); + + /** + * Default transport. + * + * @since 4.3.0 + * + * @var string + */ + public $transport = 'postMessage'; + + /** + * The term ID represented by this setting instance. + * + * A negative value represents a placeholder ID for a new menu not yet saved. + * + * @since 4.3.0 + * + * @var int + */ + public $term_id; + + /** + * Previous (placeholder) term ID used before creating a new menu. + * + * This value will be exported to JS via the customize_save_response filter + * so that JavaScript can update the settings to refer to the newly-assigned + * term ID. This value is always negative to indicate it does not refer to + * a real term. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Setting::update() + * @see WP_Customize_Nav_Menu_Setting::amend_customize_save_response() + * + * @var int + */ + public $previous_term_id; + + /** + * Whether or not preview() was called. + * + * @since 4.3.0 + * + * @var bool + */ + protected $is_previewed = false; + + /** + * Whether or not update() was called. + * + * @since 4.3.0 + * + * @var bool + */ + protected $is_updated = false; + + /** + * Status for calling the update method, used in customize_save_response filter. + * + * When status is inserted, the placeholder term ID is stored in $previous_term_id. + * When status is error, the error is stored in $update_error. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Setting::update() + * @see WP_Customize_Nav_Menu_Setting::amend_customize_save_response() + * + * @var string updated|inserted|deleted|error + */ + public $update_status; + + /** + * Any error object returned by wp_update_nav_menu_object() when setting is updated. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Setting::update() + * @see WP_Customize_Nav_Menu_Setting::amend_customize_save_response() + * + * @var WP_Error + */ + public $update_error; + + /** + * Constructor. + * + * Any supplied $args override class property defaults. + * + * @since 4.3.0 + * + * @param WP_Customize_Manager $manager Manager instance. + * @param string $id An specific ID of the setting. Can be a + * theme mod or option name. + * @param array $args Optional. Setting arguments. + * @throws Exception If $id is not valid for this setting type. + */ + public function __construct( WP_Customize_Manager $manager, $id, array $args = array() ) { + if ( empty( $manager->nav_menus ) ) { + throw new Exception( 'Expected WP_Customize_Manager::$nav_menus to be set.' ); + } + + if ( ! preg_match( self::ID_PATTERN, $id, $matches ) ) { + throw new Exception( "Illegal widget setting ID: $id" ); + } + + $this->term_id = intval( $matches['id'] ); + + parent::__construct( $manager, $id, $args ); + } + + /** + * Get the instance data for a given widget setting. + * + * @since 4.3.0 + * + * @see wp_get_nav_menu_object() + * + * @return array + */ + public function value() { + if ( $this->is_previewed && $this->_previewed_blog_id === get_current_blog_id() ) { + $undefined = new stdClass(); // Symbol. + $post_value = $this->post_value( $undefined ); + + if ( $undefined === $post_value ) { + $value = $this->_original_value; + } else { + $value = $post_value; + } + } else { + $value = false; + + // Note that a term_id of less than one indicates a nav_menu not yet inserted. + if ( $this->term_id > 0 ) { + $term = wp_get_nav_menu_object( $this->term_id ); + + if ( $term ) { + $value = wp_array_slice_assoc( (array) $term, array_keys( $this->default ) ); + + $nav_menu_options = (array) get_option( 'nav_menu_options', array() ); + $value['auto_add'] = false; + + if ( isset( $nav_menu_options['auto_add'] ) && is_array( $nav_menu_options['auto_add'] ) ) { + $value['auto_add'] = in_array( $term->term_id, $nav_menu_options['auto_add'] ); + } + } + } + + if ( ! is_array( $value ) ) { + $value = $this->default; + } + } + return $value; + } + + /** + * Handle previewing the setting. + * + * @since 4.3.0 + * + * @see WP_Customize_Manager::post_value() + */ + public function preview() { + if ( $this->is_previewed ) { + return; + } + + $this->is_previewed = true; + $this->_original_value = $this->value(); + $this->_previewed_blog_id = get_current_blog_id(); + + add_filter( 'wp_get_nav_menu_object', array( $this, 'filter_wp_get_nav_menu_object' ), 10, 2 ); + add_filter( 'default_option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); + add_filter( 'option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); + } + + /** + * Filter the wp_get_nav_menu_object() result to supply the previewed menu object. + * + * Requesting a nav_menu object by anything but ID is not supported. + * + * @since 4.3.0 + * + * @see wp_get_nav_menu_object() + * + * @param object|null $menu_obj Object returned by wp_get_nav_menu_object(). + * @param string $menu_id ID of the nav_menu term. Requests by slug or name will be ignored. + * @return object|null + */ + function filter_wp_get_nav_menu_object( $menu_obj, $menu_id ) { + $ok = ( + get_current_blog_id() === $this->_previewed_blog_id + && + is_int( $menu_id ) + && + $menu_id === $this->term_id + ); + if ( ! $ok ) { + return $menu_obj; + } + + $setting_value = $this->value(); + + // Handle deleted menus. + if ( false === $setting_value ) { + return false; + } + + // Handle sanitization failure by preventing short-circuiting. + if ( null === $setting_value ) { + return $menu_obj; + } + + $menu_obj = (object) array_merge( array( + 'term_id' => $this->term_id, + 'term_taxonomy_id' => $this->term_id, + 'slug' => sanitize_title( $setting_value['name'] ), + 'count' => 0, + 'term_group' => 0, + 'taxonomy' => self::TAXONOMY, + 'filter' => 'raw', + ), $setting_value ); + + return $menu_obj; + } + + /** + * Filter the nav_menu_options option to include this menu's auto_add preference. + * + * @since 4.3.0 + * + * @param array $nav_menu_options Nav menu options including auto_add. + * @return array + */ + function filter_nav_menu_options( $nav_menu_options ) { + if ( $this->_previewed_blog_id !== get_current_blog_id() ) { + return $nav_menu_options; + } + + $menu = $this->value(); + $nav_menu_options = $this->filter_nav_menu_options_value( + $nav_menu_options, + $this->term_id, + false === $menu ? false : $menu['auto_add'] + ); + + return $nav_menu_options; + } + + /** + * Sanitize an input. + * + * Note that parent::sanitize() erroneously does wp_unslash() on $value, but + * we remove that in this override. + * + * @since 4.3.0 + * + * @param array $value The value to sanitize. + * @return array|false|null Null if an input isn't valid. False if it is marked for deletion. Otherwise the sanitized value. + */ + public function sanitize( $value ) { + // Menu is marked for deletion. + if ( false === $value ) { + return $value; + } + + // Invalid. + if ( ! is_array( $value ) ) { + return null; + } + + $default = array( + 'name' => '', + 'description' => '', + 'parent' => 0, + 'auto_add' => false, + ); + $value = array_merge( $default, $value ); + $value = wp_array_slice_assoc( $value, array_keys( $default ) ); + + $value['name'] = trim( esc_html( $value['name'] ) ); // This sanitization code is used in wp-admin/nav-menus.php. + $value['description'] = sanitize_text_field( $value['description'] ); + $value['parent'] = max( 0, intval( $value['parent'] ) ); + $value['auto_add'] = ! empty( $value['auto_add'] ); + + /** This filter is documented in wp-includes/class-wp-customize-setting.php */ + return apply_filters( "customize_sanitize_{$this->id}", $value, $this ); + } + + /** + * Create/update the nav_menu term for this setting. + * + * Any created menus will have their assigned term IDs exported to the client + * via the customize_save_response filter. Likewise, any errors will be exported + * to the client via the customize_save_response() filter. + * + * To delete a menu, the client can send false as the value. + * + * @since 4.3.0 + * + * @see wp_update_nav_menu_object() + * + * @param array|false $value { + * The value to update. Note that slug cannot be updated via wp_update_nav_menu_object(). + * If false, then the menu will be deleted entirely. + * + * @type string $name The name of the menu to save. + * @type string $description The term description. Default empty string. + * @type int $parent The id of the parent term. Default 0. + * @type bool $auto_add Whether pages will auto_add to this menu. Default false. + * } + * @return void + */ + protected function update( $value ) { + if ( $this->is_updated ) { + return; + } + + $this->is_updated = true; + $is_placeholder = ( $this->term_id < 0 ); + $is_delete = ( false === $value ); + + add_filter( 'customize_save_response', array( $this, 'amend_customize_save_response' ) ); + + $auto_add = null; + if ( $is_delete ) { + // If the current setting term is a placeholder, a delete request is a no-op. + if ( $is_placeholder ) { + $this->update_status = 'deleted'; + } else { + $r = wp_delete_nav_menu( $this->term_id ); + + if ( is_wp_error( $r ) ) { + $this->update_status = 'error'; + $this->update_error = $r; + } else { + $this->update_status = 'deleted'; + $auto_add = false; + } + } + } else { + // Insert or update menu. + $menu_data = wp_array_slice_assoc( $value, array( 'description', 'parent' ) ); + if ( isset( $value['name'] ) ) { + $menu_data['menu-name'] = $value['name']; + } + + $r = wp_update_nav_menu_object( $is_placeholder ? 0 : $this->term_id, $menu_data ); + if ( is_wp_error( $r ) ) { + $this->update_status = 'error'; + $this->update_error = $r; + } else { + if ( $is_placeholder ) { + $this->previous_term_id = $this->term_id; + $this->term_id = $r; + $this->update_status = 'inserted'; + } else { + $this->update_status = 'updated'; + } + + $auto_add = $value['auto_add']; + } + } + + if ( null !== $auto_add ) { + $nav_menu_options = $this->filter_nav_menu_options_value( + (array) get_option( 'nav_menu_options', array() ), + $this->term_id, + $auto_add + ); + update_option( 'nav_menu_options', $nav_menu_options ); + } + + // Make sure that new menus assigned to nav menu locations use their new IDs. + if ( 'inserted' === $this->update_status ) { + foreach ( $this->manager->settings() as $setting ) { + if ( ! preg_match( '/^nav_menu_locations\[/', $setting->id ) ) { + continue; + } + + $post_value = $setting->post_value( null ); + if ( ! is_null( $post_value ) && $this->previous_term_id === intval( $post_value ) ) { + $this->manager->set_post_value( $setting->id, $this->term_id ); + $setting->save(); + } + } + } + } + + /** + * Update a nav_menu_options array. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Setting::filter_nav_menu_options() + * @see WP_Customize_Nav_Menu_Setting::update() + * + * @param array $nav_menu_options Array as returned by get_option( 'nav_menu_options' ). + * @param int $menu_id The term ID for the given menu. + * @param bool $auto_add Whether to auto-add or not. + * @return array + */ + protected function filter_nav_menu_options_value( $nav_menu_options, $menu_id, $auto_add ) { + $nav_menu_options = (array) $nav_menu_options; + if ( ! isset( $nav_menu_options['auto_add'] ) ) { + $nav_menu_options['auto_add'] = array(); + } + + $i = array_search( $menu_id, $nav_menu_options['auto_add'] ); + if ( $auto_add && false === $i ) { + array_push( $nav_menu_options['auto_add'], $this->term_id ); + } else if ( ! $auto_add && false !== $i ) { + array_splice( $nav_menu_options['auto_add'], $i, 1 ); + } + + return $nav_menu_options; + } + + /** + * Export data for the JS client. + * + * @since 4.3.0 + * + * @see WP_Customize_Nav_Menu_Setting::update() + * + * @param array $data Additional information passed back to the 'saved' event on `wp.customize`. + * @return array + */ + function amend_customize_save_response( $data ) { + if ( ! isset( $data['nav_menu_updates'] ) ) { + $data['nav_menu_updates'] = array(); + } + + $data['nav_menu_updates'][] = array( + 'term_id' => $this->term_id, + 'previous_term_id' => $this->previous_term_id, + 'error' => $this->update_error ? $this->update_error->get_error_code() : null, + 'status' => $this->update_status, + ); + + return $data; + } +} diff --git a/wp-includes/css/customize-preview.css b/wp-includes/css/customize-preview.css new file mode 100644 index 0000000000..bc4a6fe903 --- /dev/null +++ b/wp-includes/css/customize-preview.css @@ -0,0 +1,6 @@ +.customize-partial-refreshing { + opacity: 0.25; + -webkit-transition: opacity 0.25s; + transition: opacity 0.25s; + cursor: progress; +} diff --git a/wp-includes/css/customize-preview.min.css b/wp-includes/css/customize-preview.min.css new file mode 100644 index 0000000000..dadf3f5216 --- /dev/null +++ b/wp-includes/css/customize-preview.min.css @@ -0,0 +1 @@ +.customize-partial-refreshing{opacity:.25;-webkit-transition:opacity .25s;transition:opacity .25s;cursor:progress} \ No newline at end of file diff --git a/wp-includes/js/customize-preview-nav-menus.js b/wp-includes/js/customize-preview-nav-menus.js new file mode 100644 index 0000000000..2b6c9949fe --- /dev/null +++ b/wp-includes/js/customize-preview-nav-menus.js @@ -0,0 +1,242 @@ +/*global jQuery, JSON, _wpCustomizePreviewNavMenusExports, _ */ + +wp.customize.menusPreview = ( function( $, api ) { + 'use strict'; + var self; + + self = { + renderQueryVar: null, + renderNonceValue: null, + renderNoncePostKey: null, + previewCustomizeNonce: null, + previewReady: $.Deferred(), + requestUri: '/', + theme: { + active: false, + stylesheet: '' + }, + navMenuInstanceArgs: {}, + refreshDebounceDelay: 200 + }; + + api.bind( 'preview-ready', function() { + self.previewReady.resolve(); + } ); + self.previewReady.done( function() { + self.init(); + } ); + + /** + * Bootstrap functionality. + */ + self.init = function() { + var self = this; + + if ( 'undefined' !== typeof _wpCustomizePreviewNavMenusExports ) { + $.extend( self, _wpCustomizePreviewNavMenusExports ); + } + + self.previewReady.done( function() { + api.each( function( setting, id ) { + setting.id = id; + self.bindListener( setting ); + } ); + + api.preview.bind( 'setting', function( args ) { + var id, value, setting; + args = args.slice(); + id = args.shift(); + value = args.shift(); + if ( ! api.has( id ) ) { + // Currently customize-preview.js is not creating settings for dynamically-created settings in the pane; so we have to do it + setting = api.create( id, value ); // @todo This should be in core + setting.id = id; + if ( self.bindListener( setting ) ) { + setting.callbacks.fireWith( setting, [ setting(), setting() ] ); + } + } + } ); + } ); + }; + + /** + * + * @param {wp.customize.Value} setting + * @returns {boolean} Whether the setting was bound. + */ + self.bindListener = function( setting ) { + var matches, themeLocation; + + matches = setting.id.match( /^nav_menu\[(-?\d+)]$/ ); + if ( matches ) { + setting.navMenuId = parseInt( matches[1], 10 ); + setting.bind( self.onChangeNavMenuSetting ); + return true; + } + + matches = setting.id.match( /^nav_menu_item\[(-?\d+)]$/ ); + if ( matches ) { + setting.navMenuItemId = parseInt( matches[1], 10 ); + setting.bind( self.onChangeNavMenuItemSetting ); + return true; + } + + matches = setting.id.match( /^nav_menu_locations\[(.+?)]/ ); + if ( matches ) { + themeLocation = matches[1]; + setting.bind( function() { + self.refreshMenuLocation( themeLocation ); + } ); + return true; + } + + return false; + }; + + /** + * Handle changing of a nav_menu setting. + * + * @this {wp.customize.Setting} + */ + self.onChangeNavMenuSetting = function() { + var setting = this; + if ( ! setting.navMenuId ) { + throw new Error( 'Expected navMenuId property to be set.' ); + } + self.refreshMenu( setting.navMenuId ); + }; + + /** + * Handle changing of a nav_menu_item setting. + * + * @this {wp.customize.Setting} + * @param {object} to + * @param {object} from + */ + self.onChangeNavMenuItemSetting = function( to, from ) { + if ( from && from.nav_menu_term_id && ( ! to || from.nav_menu_term_id !== to.nav_menu_term_id ) ) { + self.refreshMenu( from.nav_menu_term_id ); + } + if ( to && to.nav_menu_term_id ) { + self.refreshMenu( to.nav_menu_term_id ); + } + }; + + /** + * Update a given menu rendered in the preview. + * + * @param {int} menuId + */ + self.refreshMenu = function( menuId ) { + var self = this, assignedLocations = []; + + api.each(function( setting, id ) { + var matches = id.match( /^nav_menu_locations\[(.+?)]/ ); + if ( matches && menuId === setting() ) { + assignedLocations.push( matches[1] ); + } + }); + + _.each( self.navMenuInstanceArgs, function( navMenuArgs, instanceNumber ) { + if ( menuId === navMenuArgs.menu || -1 !== _.indexOf( assignedLocations, navMenuArgs.theme_location ) ) { + self.refreshMenuInstanceDebounced( instanceNumber ); + } + } ); + }; + + self.refreshMenuLocation = function( location ) { + var foundInstance = false; + _.each( self.navMenuInstanceArgs, function( navMenuArgs, instanceNumber ) { + if ( location === navMenuArgs.theme_location ) { + self.refreshMenuInstanceDebounced( instanceNumber ); + foundInstance = true; + } + } ); + if ( ! foundInstance ) { + api.preview.send( 'refresh' ); + } + }; + + /** + * Update a specific instance of a given menu on the page. + * + * @param {int} instanceNumber + */ + self.refreshMenuInstance = function( instanceNumber ) { + var self = this, data, customized, container, request, wpNavArgs, instance; + + if ( ! self.navMenuInstanceArgs[ instanceNumber ] ) { + throw new Error( 'unknown_instance_number' ); + } + instance = self.navMenuInstanceArgs[ instanceNumber ]; + + container = $( '#partial-refresh-menu-container-' + String( instanceNumber ) ); + + if ( ! instance.can_partial_refresh || 0 === container.length ) { + api.preview.send( 'refresh' ); + return; + } + + data = { + nonce: self.previewCustomizeNonce, // for Customize Preview + wp_customize: 'on' + }; + if ( ! self.theme.active ) { + data.theme = self.theme.stylesheet; + } + data[ self.renderQueryVar ] = '1'; + customized = {}; + api.each( function( setting, id ) { + // @todo We need to limit this to just the menu items that are associated with this menu/location. + if ( /^(nav_menu|nav_menu_locations)/.test( id ) ) { + customized[ id ] = setting.get(); + } + } ); + data.customized = JSON.stringify( customized ); + data[ self.renderNoncePostKey ] = self.renderNonceValue; + + wpNavArgs = $.extend( {}, instance ); + data.wp_nav_menu_args_hash = wpNavArgs.args_hash; + delete wpNavArgs.args_hash; + data.wp_nav_menu_args = JSON.stringify( wpNavArgs ); + + container.addClass( 'customize-partial-refreshing' ); + + request = wp.ajax.send( null, { + data: data, + url: self.requestUri + } ); + request.done( function( data ) { + var eventParam; + container.empty().append( $( data ) ); + eventParam = { + instanceNumber: instanceNumber, + wpNavArgs: wpNavArgs + }; + $( document ).trigger( 'customize-preview-menu-refreshed', [ eventParam ] ); + } ); + request.fail( function() { + // @todo provide some indication for why + } ); + request.always( function() { + container.removeClass( 'customize-partial-refreshing' ); + } ); + }; + + self.currentRefreshMenuInstanceDebouncedCalls = {}; + + self.refreshMenuInstanceDebounced = function( instanceNumber ) { + if ( self.currentRefreshMenuInstanceDebouncedCalls[ instanceNumber ] ) { + clearTimeout( self.currentRefreshMenuInstanceDebouncedCalls[ instanceNumber ] ); + } + self.currentRefreshMenuInstanceDebouncedCalls[ instanceNumber ] = setTimeout( + function() { + self.refreshMenuInstance( instanceNumber ); + }, + self.refreshDebounceDelay + ); + }; + + return self; + +}( jQuery, wp.customize ) ); diff --git a/wp-includes/js/customize-preview-nav-menus.min.js b/wp-includes/js/customize-preview-nav-menus.min.js new file mode 100644 index 0000000000..ad9382beb2 --- /dev/null +++ b/wp-includes/js/customize-preview-nav-menus.min.js @@ -0,0 +1 @@ +wp.customize.menusPreview=function(a,b){"use strict";var c;return c={renderQueryVar:null,renderNonceValue:null,renderNoncePostKey:null,previewCustomizeNonce:null,previewReady:a.Deferred(),requestUri:"/",theme:{active:!1,stylesheet:""},navMenuInstanceArgs:{},refreshDebounceDelay:200},b.bind("preview-ready",function(){c.previewReady.resolve()}),c.previewReady.done(function(){c.init()}),c.init=function(){var c=this;"undefined"!=typeof _wpCustomizePreviewNavMenusExports&&a.extend(c,_wpCustomizePreviewNavMenusExports),c.previewReady.done(function(){b.each(function(a,b){a.id=b,c.bindListener(a)}),b.preview.bind("setting",function(a){var d,e,f;a=a.slice(),d=a.shift(),e=a.shift(),b.has(d)||(f=b.create(d,e),f.id=d,c.bindListener(f)&&f.callbacks.fireWith(f,[f(),f()]))})})},c.bindListener=function(a){var b,d;return(b=a.id.match(/^nav_menu\[(-?\d+)]$/))?(a.navMenuId=parseInt(b[1],10),a.bind(c.onChangeNavMenuSetting),!0):(b=a.id.match(/^nav_menu_item\[(-?\d+)]$/))?(a.navMenuItemId=parseInt(b[1],10),a.bind(c.onChangeNavMenuItemSetting),!0):(b=a.id.match(/^nav_menu_locations\[(.+?)]/),b?(d=b[1],a.bind(function(){c.refreshMenuLocation(d)}),!0):!1)},c.onChangeNavMenuSetting=function(){var a=this;if(!a.navMenuId)throw new Error("Expected navMenuId property to be set.");c.refreshMenu(a.navMenuId)},c.onChangeNavMenuItemSetting=function(a,b){!b||!b.nav_menu_term_id||a&&b.nav_menu_term_id===a.nav_menu_term_id||c.refreshMenu(b.nav_menu_term_id),a&&a.nav_menu_term_id&&c.refreshMenu(a.nav_menu_term_id)},c.refreshMenu=function(a){var c=this,d=[];b.each(function(b,c){var e=c.match(/^nav_menu_locations\[(.+?)]/);e&&a===b()&&d.push(e[1])}),_.each(c.navMenuInstanceArgs,function(b,e){(a===b.menu||-1!==_.indexOf(d,b.theme_location))&&c.refreshMenuInstanceDebounced(e)})},c.refreshMenuLocation=function(a){var d=!1;_.each(c.navMenuInstanceArgs,function(b,e){a===b.theme_location&&(c.refreshMenuInstanceDebounced(e),d=!0)}),d||b.preview.send("refresh")},c.refreshMenuInstance=function(c){var d,e,f,g,h,i,j=this;if(!j.navMenuInstanceArgs[c])throw new Error("unknown_instance_number");return i=j.navMenuInstanceArgs[c],f=a("#partial-refresh-menu-container-"+String(c)),i.can_partial_refresh&&0!==f.length?(d={nonce:j.previewCustomizeNonce,wp_customize:"on"},j.theme.active||(d.theme=j.theme.stylesheet),d[j.renderQueryVar]="1",e={},b.each(function(a,b){/^(nav_menu|nav_menu_locations)/.test(b)&&(e[b]=a.get())}),d.customized=JSON.stringify(e),d[j.renderNoncePostKey]=j.renderNonceValue,h=a.extend({},i),d.wp_nav_menu_args_hash=h.args_hash,delete h.args_hash,d.wp_nav_menu_args=JSON.stringify(h),f.addClass("customize-partial-refreshing"),g=wp.ajax.send(null,{data:d,url:j.requestUri}),g.done(function(b){var d;f.empty().append(a(b)),d={instanceNumber:c,wpNavArgs:h},a(document).trigger("customize-preview-menu-refreshed",[d])}),g.fail(function(){}),void g.always(function(){f.removeClass("customize-partial-refreshing")})):void b.preview.send("refresh")},c.currentRefreshMenuInstanceDebouncedCalls={},c.refreshMenuInstanceDebounced=function(a){c.currentRefreshMenuInstanceDebouncedCalls[a]&&clearTimeout(c.currentRefreshMenuInstanceDebouncedCalls[a]),c.currentRefreshMenuInstanceDebouncedCalls[a]=setTimeout(function(){c.refreshMenuInstance(a)},c.refreshDebounceDelay)},c}(jQuery,wp.customize); \ No newline at end of file diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index c2ae253ac2..1da93a4734 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -406,6 +406,9 @@ function wp_default_scripts( &$scripts ) { $scripts->add( 'customize-widgets', "/wp-admin/js/customize-widgets$suffix.js", array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-droppable', 'wp-backbone', 'customize-controls' ), false, 1 ); $scripts->add( 'customize-preview-widgets', "/wp-includes/js/customize-preview-widgets$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 ); + $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu', 'wp-a11y' ), false, 1 ); + $scripts->add( 'customize-preview-nav-menus', "/wp-includes/js/customize-preview-nav-menus$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 ); + $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 ); $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 ); @@ -656,15 +659,16 @@ function wp_default_styles( &$styles ) { $suffix = SCRIPT_DEBUG ? '' : '.min'; // Admin CSS - $styles->add( 'wp-admin', "/wp-admin/css/wp-admin$suffix.css", array( 'open-sans', 'dashicons' ) ); - $styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'buttons', 'open-sans', 'dashicons' ) ); - $styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'buttons', 'open-sans' ) ); - $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" ); - $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie', 'imgareaselect' ) ); - $styles->add( 'customize-widgets', "/wp-admin/css/customize-widgets$suffix.css", array( 'wp-admin', 'colors' ) ); - $styles->add( 'press-this', "/wp-admin/css/press-this$suffix.css", array( 'open-sans', 'buttons' ) ); + $styles->add( 'wp-admin', "/wp-admin/css/wp-admin$suffix.css", array( 'open-sans', 'dashicons' ) ); + $styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'buttons', 'open-sans', 'dashicons' ) ); + $styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'buttons', 'open-sans' ) ); + $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" ); + $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie', 'imgareaselect' ) ); + $styles->add( 'customize-widgets', "/wp-admin/css/customize-widgets$suffix.css", array( 'wp-admin', 'colors' ) ); + $styles->add( 'customize-nav-menus', "/wp-admin/css/customize-nav-menus$suffix.css", array( 'wp-admin', 'colors' ) ); + $styles->add( 'press-this', "/wp-admin/css/press-this$suffix.css", array( 'open-sans', 'buttons' ) ); - $styles->add( 'ie', "/wp-admin/css/ie$suffix.css" ); + $styles->add( 'ie', "/wp-admin/css/ie$suffix.css" ); $styles->add_data( 'ie', 'conditional', 'lte IE 7' ); // Common dependencies @@ -673,11 +677,12 @@ function wp_default_styles( &$styles ) { $styles->add( 'open-sans', $open_sans_font_url ); // Includes CSS - $styles->add( 'admin-bar', "/wp-includes/css/admin-bar$suffix.css", array( 'open-sans', 'dashicons' ) ); - $styles->add( 'wp-auth-check', "/wp-includes/css/wp-auth-check$suffix.css", array( 'dashicons' ) ); - $styles->add( 'editor-buttons', "/wp-includes/css/editor$suffix.css", array( 'dashicons' ) ); - $styles->add( 'media-views', "/wp-includes/css/media-views$suffix.css", array( 'buttons', 'dashicons', 'wp-mediaelement' ) ); - $styles->add( 'wp-pointer', "/wp-includes/css/wp-pointer$suffix.css", array( 'dashicons' ) ); + $styles->add( 'admin-bar', "/wp-includes/css/admin-bar$suffix.css", array( 'open-sans', 'dashicons' ) ); + $styles->add( 'wp-auth-check', "/wp-includes/css/wp-auth-check$suffix.css", array( 'dashicons' ) ); + $styles->add( 'editor-buttons', "/wp-includes/css/editor$suffix.css", array( 'dashicons' ) ); + $styles->add( 'media-views', "/wp-includes/css/media-views$suffix.css", array( 'buttons', 'dashicons', 'wp-mediaelement' ) ); + $styles->add( 'wp-pointer', "/wp-includes/css/wp-pointer$suffix.css", array( 'dashicons' ) ); + $styles->add( 'customize-preview', "/wp-includes/css/customize-preview$suffix.css" ); // External libraries and friends $styles->add( 'imgareaselect', '/wp-includes/js/imgareaselect/imgareaselect.css', array(), '0.9.8' ); @@ -695,7 +700,7 @@ function wp_default_styles( &$styles ) { // RTL CSS $rtl_styles = array( // wp-admin - 'wp-admin', 'install', 'wp-color-picker', 'customize-controls', 'customize-widgets', 'ie', 'login', 'press-this', + 'wp-admin', 'install', 'wp-color-picker', 'customize-controls', 'customize-widgets', 'customize-nav-menus', 'ie', 'login', 'press-this', // wp-includes 'buttons', 'admin-bar', 'wp-auth-check', 'editor-buttons', 'media-views', 'wp-pointer', 'wp-jquery-ui-dialog', diff --git a/wp-includes/version.php b/wp-includes/version.php index 63aa600cb7..2b81aa1fa6 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.3-alpha-32805'; +$wp_version = '4.3-alpha-32806'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.