first
This commit is contained in:
94
wp-admin/js/accordion.js
Normal file
94
wp-admin/js/accordion.js
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Accordion-folding functionality.
|
||||
*
|
||||
* Markup with the appropriate classes will be automatically hidden,
|
||||
* with one section opening at a time when its title is clicked.
|
||||
* Use the following markup structure for accordion behavior:
|
||||
*
|
||||
* <div class="accordion-container">
|
||||
* <div class="accordion-section open">
|
||||
* <h3 class="accordion-section-title"></h3>
|
||||
* <div class="accordion-section-content">
|
||||
* </div>
|
||||
* </div>
|
||||
* <div class="accordion-section">
|
||||
* <h3 class="accordion-section-title"></h3>
|
||||
* <div class="accordion-section-content">
|
||||
* </div>
|
||||
* </div>
|
||||
* <div class="accordion-section">
|
||||
* <h3 class="accordion-section-title"></h3>
|
||||
* <div class="accordion-section-content">
|
||||
* </div>
|
||||
* </div>
|
||||
* </div>
|
||||
*
|
||||
* Note that any appropriate tags may be used, as long as the above classes are present.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @output wp-admin/js/accordion.js
|
||||
*/
|
||||
|
||||
( function( $ ){
|
||||
|
||||
$( function () {
|
||||
|
||||
// Expand/Collapse accordion sections on click.
|
||||
$( '.accordion-container' ).on( 'click keydown', '.accordion-section-title', function( e ) {
|
||||
if ( e.type === 'keydown' && 13 !== e.which ) { // "Return" key.
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault(); // Keep this AFTER the key filter above.
|
||||
|
||||
accordionSwitch( $( this ) );
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Close the current accordion section and open a new one.
|
||||
*
|
||||
* @param {Object} el Title element of the accordion section to toggle.
|
||||
* @since 3.6.0
|
||||
*/
|
||||
function accordionSwitch ( el ) {
|
||||
var section = el.closest( '.accordion-section' ),
|
||||
sectionToggleControl = section.find( '[aria-expanded]' ).first(),
|
||||
container = section.closest( '.accordion-container' ),
|
||||
siblings = container.find( '.open' ),
|
||||
siblingsToggleControl = siblings.find( '[aria-expanded]' ).first(),
|
||||
content = section.find( '.accordion-section-content' );
|
||||
|
||||
// This section has no content and cannot be expanded.
|
||||
if ( section.hasClass( 'cannot-expand' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a class to the container to let us know something is happening inside.
|
||||
// This helps in cases such as hiding a scrollbar while animations are executing.
|
||||
container.addClass( 'opening' );
|
||||
|
||||
if ( section.hasClass( 'open' ) ) {
|
||||
section.toggleClass( 'open' );
|
||||
content.toggle( true ).slideToggle( 150 );
|
||||
} else {
|
||||
siblingsToggleControl.attr( 'aria-expanded', 'false' );
|
||||
siblings.removeClass( 'open' );
|
||||
siblings.find( '.accordion-section-content' ).show().slideUp( 150 );
|
||||
content.toggle( false ).slideToggle( 150 );
|
||||
section.toggleClass( 'open' );
|
||||
}
|
||||
|
||||
// We have to wait for the animations to finish.
|
||||
setTimeout(function(){
|
||||
container.removeClass( 'opening' );
|
||||
}, 150);
|
||||
|
||||
// If there's an element with an aria-expanded attribute, assume it's a toggle control and toggle the aria-expanded value.
|
||||
if ( sectionToggleControl ) {
|
||||
sectionToggleControl.attr( 'aria-expanded', String( sectionToggleControl.attr( 'aria-expanded' ) === 'false' ) );
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery);
|
2
wp-admin/js/accordion.min.js
vendored
Normal file
2
wp-admin/js/accordion.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(s){s(function(){s(".accordion-container").on("click keydown",".accordion-section-title",function(e){var n,o,a,i,t;"keydown"===e.type&&13!==e.which||(e.preventDefault(),e=(e=s(this)).closest(".accordion-section"),n=e.find("[aria-expanded]").first(),o=e.closest(".accordion-container"),a=o.find(".open"),i=a.find("[aria-expanded]").first(),t=e.find(".accordion-section-content"),e.hasClass("cannot-expand"))||(o.addClass("opening"),e.hasClass("open")?(e.toggleClass("open"),t.toggle(!0).slideToggle(150)):(i.attr("aria-expanded","false"),a.removeClass("open"),a.find(".accordion-section-content").show().slideUp(150),t.toggle(!1).slideToggle(150),e.toggleClass("open")),setTimeout(function(){o.removeClass("opening")},150),n&&n.attr("aria-expanded",String("false"===n.attr("aria-expanded"))))})})}(jQuery);
|
219
wp-admin/js/application-passwords.js
Normal file
219
wp-admin/js/application-passwords.js
Normal file
@ -0,0 +1,219 @@
|
||||
/**
|
||||
* @output wp-admin/js/application-passwords.js
|
||||
*/
|
||||
|
||||
( function( $ ) {
|
||||
var $appPassSection = $( '#application-passwords-section' ),
|
||||
$newAppPassForm = $appPassSection.find( '.create-application-password' ),
|
||||
$newAppPassField = $newAppPassForm.find( '.input' ),
|
||||
$newAppPassButton = $newAppPassForm.find( '.button' ),
|
||||
$appPassTwrapper = $appPassSection.find( '.application-passwords-list-table-wrapper' ),
|
||||
$appPassTbody = $appPassSection.find( 'tbody' ),
|
||||
$appPassTrNoItems = $appPassTbody.find( '.no-items' ),
|
||||
$removeAllBtn = $( '#revoke-all-application-passwords' ),
|
||||
tmplNewAppPass = wp.template( 'new-application-password' ),
|
||||
tmplAppPassRow = wp.template( 'application-password-row' ),
|
||||
userId = $( '#user_id' ).val();
|
||||
|
||||
$newAppPassButton.on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
if ( $newAppPassButton.prop( 'aria-disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = $newAppPassField.val();
|
||||
|
||||
if ( 0 === name.length ) {
|
||||
$newAppPassField.trigger( 'focus' );
|
||||
return;
|
||||
}
|
||||
|
||||
clearNotices();
|
||||
$newAppPassButton.prop( 'aria-disabled', true ).addClass( 'disabled' );
|
||||
|
||||
var request = {
|
||||
name: name
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters the request data used to create a new Application Password.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {Object} request The request data.
|
||||
* @param {number} userId The id of the user the password is added for.
|
||||
*/
|
||||
request = wp.hooks.applyFilters( 'wp_application_passwords_new_password_request', request, userId );
|
||||
|
||||
wp.apiRequest( {
|
||||
path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user',
|
||||
method: 'POST',
|
||||
data: request
|
||||
} ).always( function() {
|
||||
$newAppPassButton.removeProp( 'aria-disabled' ).removeClass( 'disabled' );
|
||||
} ).done( function( response ) {
|
||||
$newAppPassField.val( '' );
|
||||
$newAppPassButton.prop( 'disabled', false );
|
||||
|
||||
$newAppPassForm.after( tmplNewAppPass( {
|
||||
name: response.name,
|
||||
password: response.password
|
||||
} ) );
|
||||
$( '.new-application-password-notice' ).attr( 'tabindex', '-1' ).trigger( 'focus' );
|
||||
|
||||
$appPassTbody.prepend( tmplAppPassRow( response ) );
|
||||
|
||||
$appPassTwrapper.show();
|
||||
$appPassTrNoItems.remove();
|
||||
|
||||
/**
|
||||
* Fires after an application password has been successfully created.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {Object} response The response data from the REST API.
|
||||
* @param {Object} request The request data used to create the password.
|
||||
*/
|
||||
wp.hooks.doAction( 'wp_application_passwords_created_password', response, request );
|
||||
} ).fail( handleErrorResponse );
|
||||
} );
|
||||
|
||||
$appPassTbody.on( 'click', '.delete', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
if ( ! window.confirm( wp.i18n.__( 'Are you sure you want to revoke this password? This action cannot be undone.' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $submitButton = $( this ),
|
||||
$tr = $submitButton.closest( 'tr' ),
|
||||
uuid = $tr.data( 'uuid' );
|
||||
|
||||
clearNotices();
|
||||
$submitButton.prop( 'disabled', true );
|
||||
|
||||
wp.apiRequest( {
|
||||
path: '/wp/v2/users/' + userId + '/application-passwords/' + uuid + '?_locale=user',
|
||||
method: 'DELETE'
|
||||
} ).always( function() {
|
||||
$submitButton.prop( 'disabled', false );
|
||||
} ).done( function( response ) {
|
||||
if ( response.deleted ) {
|
||||
if ( 0 === $tr.siblings().length ) {
|
||||
$appPassTwrapper.hide();
|
||||
}
|
||||
$tr.remove();
|
||||
|
||||
addNotice( wp.i18n.__( 'Application password revoked.' ), 'success' ).trigger( 'focus' );
|
||||
}
|
||||
} ).fail( handleErrorResponse );
|
||||
} );
|
||||
|
||||
$removeAllBtn.on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
if ( ! window.confirm( wp.i18n.__( 'Are you sure you want to revoke all passwords? This action cannot be undone.' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $submitButton = $( this );
|
||||
|
||||
clearNotices();
|
||||
$submitButton.prop( 'disabled', true );
|
||||
|
||||
wp.apiRequest( {
|
||||
path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user',
|
||||
method: 'DELETE'
|
||||
} ).always( function() {
|
||||
$submitButton.prop( 'disabled', false );
|
||||
} ).done( function( response ) {
|
||||
if ( response.deleted ) {
|
||||
$appPassTbody.children().remove();
|
||||
$appPassSection.children( '.new-application-password' ).remove();
|
||||
$appPassTwrapper.hide();
|
||||
|
||||
addNotice( wp.i18n.__( 'All application passwords revoked.' ), 'success' ).trigger( 'focus' );
|
||||
}
|
||||
} ).fail( handleErrorResponse );
|
||||
} );
|
||||
|
||||
$appPassSection.on( 'click', '.notice-dismiss', function( e ) {
|
||||
e.preventDefault();
|
||||
var $el = $( this ).parent();
|
||||
$el.removeAttr( 'role' );
|
||||
$el.fadeTo( 100, 0, function () {
|
||||
$el.slideUp( 100, function () {
|
||||
$el.remove();
|
||||
$newAppPassField.trigger( 'focus' );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
$newAppPassField.on( 'keypress', function ( e ) {
|
||||
if ( 13 === e.which ) {
|
||||
e.preventDefault();
|
||||
$newAppPassButton.trigger( 'click' );
|
||||
}
|
||||
} );
|
||||
|
||||
// If there are no items, don't display the table yet. If there are, show it.
|
||||
if ( 0 === $appPassTbody.children( 'tr' ).not( $appPassTrNoItems ).length ) {
|
||||
$appPassTwrapper.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an error response from the REST API.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {jqXHR} xhr The XHR object from the ajax call.
|
||||
* @param {string} textStatus The string categorizing the ajax request's status.
|
||||
* @param {string} errorThrown The HTTP status error text.
|
||||
*/
|
||||
function handleErrorResponse( xhr, textStatus, errorThrown ) {
|
||||
var errorMessage = errorThrown;
|
||||
|
||||
if ( xhr.responseJSON && xhr.responseJSON.message ) {
|
||||
errorMessage = xhr.responseJSON.message;
|
||||
}
|
||||
|
||||
addNotice( errorMessage, 'error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a message in the Application Passwords section.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {string} message The message to display.
|
||||
* @param {string} type The notice type. Either 'success' or 'error'.
|
||||
* @returns {jQuery} The notice element.
|
||||
*/
|
||||
function addNotice( message, type ) {
|
||||
var $notice = $( '<div></div>' )
|
||||
.attr( 'role', 'alert' )
|
||||
.attr( 'tabindex', '-1' )
|
||||
.addClass( 'is-dismissible notice notice-' + type )
|
||||
.append( $( '<p></p>' ).text( message ) )
|
||||
.append(
|
||||
$( '<button></button>' )
|
||||
.attr( 'type', 'button' )
|
||||
.addClass( 'notice-dismiss' )
|
||||
.append( $( '<span></span>' ).addClass( 'screen-reader-text' ).text( wp.i18n.__( 'Dismiss this notice.' ) ) )
|
||||
);
|
||||
|
||||
$newAppPassForm.after( $notice );
|
||||
|
||||
return $notice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears notice messages from the Application Passwords section.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*/
|
||||
function clearNotices() {
|
||||
$( '.notice', $appPassSection ).remove();
|
||||
}
|
||||
}( jQuery ) );
|
2
wp-admin/js/application-passwords.min.js
vendored
Normal file
2
wp-admin/js/application-passwords.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(o){var a=o("#application-passwords-section"),i=a.find(".create-application-password"),t=i.find(".input"),n=i.find(".button"),p=a.find(".application-passwords-list-table-wrapper"),r=a.find("tbody"),d=r.find(".no-items"),e=o("#revoke-all-application-passwords"),l=wp.template("new-application-password"),c=wp.template("application-password-row"),u=o("#user_id").val();function w(e,s,a){f(a=e.responseJSON&&e.responseJSON.message?e.responseJSON.message:a,"error")}function f(e,s){s=o("<div></div>").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(o("<p></p>").text(e)).append(o("<button></button>").attr("type","button").addClass("notice-dismiss").append(o("<span></span>").addClass("screen-reader-text").text(wp.i18n.__("Dismiss this notice."))));return i.after(s),s}function v(){o(".notice",a).remove()}n.on("click",function(e){var s;e.preventDefault(),n.prop("aria-disabled")||(0===(e=t.val()).length?t.trigger("focus"):(v(),n.prop("aria-disabled",!0).addClass("disabled"),s={name:e},s=wp.hooks.applyFilters("wp_application_passwords_new_password_request",s,u),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"POST",data:s}).always(function(){n.removeProp("aria-disabled").removeClass("disabled")}).done(function(e){t.val(""),n.prop("disabled",!1),i.after(l({name:e.name,password:e.password})),o(".new-application-password-notice").attr("tabindex","-1").trigger("focus"),r.prepend(c(e)),p.show(),d.remove(),wp.hooks.doAction("wp_application_passwords_created_password",e,s)}).fail(w)))}),r.on("click",".delete",function(e){var s,a;e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke this password? This action cannot be undone."))&&(s=o(this),e=(a=s.closest("tr")).data("uuid"),v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords/"+e+"?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(0===a.siblings().length&&p.hide(),a.remove(),f(wp.i18n.__("Application password revoked."),"success").trigger("focus"))}).fail(w))}),e.on("click",function(e){var s;e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke all passwords? This action cannot be undone."))&&(s=o(this),v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(r.children().remove(),a.children(".new-application-password").remove(),p.hide(),f(wp.i18n.__("All application passwords revoked."),"success").trigger("focus"))}).fail(w))}),a.on("click",".notice-dismiss",function(e){e.preventDefault();var s=o(this).parent();s.removeAttr("role"),s.fadeTo(100,0,function(){s.slideUp(100,function(){s.remove(),t.trigger("focus")})})}),t.on("keypress",function(e){13===e.which&&(e.preventDefault(),n.trigger("click"))}),0===r.children("tr").not(d).length&&p.hide()}(jQuery);
|
165
wp-admin/js/auth-app.js
Normal file
165
wp-admin/js/auth-app.js
Normal file
@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @output wp-admin/js/auth-app.js
|
||||
*/
|
||||
|
||||
/* global authApp */
|
||||
|
||||
( function( $, authApp ) {
|
||||
var $appNameField = $( '#app_name' ),
|
||||
$approveBtn = $( '#approve' ),
|
||||
$rejectBtn = $( '#reject' ),
|
||||
$form = $appNameField.closest( 'form' ),
|
||||
context = {
|
||||
userLogin: authApp.user_login,
|
||||
successUrl: authApp.success,
|
||||
rejectUrl: authApp.reject
|
||||
};
|
||||
|
||||
$approveBtn.on( 'click', function( e ) {
|
||||
var name = $appNameField.val(),
|
||||
appId = $( 'input[name="app_id"]', $form ).val();
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if ( $approveBtn.prop( 'aria-disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 0 === name.length ) {
|
||||
$appNameField.trigger( 'focus' );
|
||||
return;
|
||||
}
|
||||
|
||||
$approveBtn.prop( 'aria-disabled', true ).addClass( 'disabled' );
|
||||
|
||||
var request = {
|
||||
name: name
|
||||
};
|
||||
|
||||
if ( appId.length > 0 ) {
|
||||
request.app_id = appId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the request data used to Authorize an Application Password request.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {Object} request The request data.
|
||||
* @param {Object} context Context about the Application Password request.
|
||||
* @param {string} context.userLogin The user's login username.
|
||||
* @param {string} context.successUrl The URL the user will be redirected to after approving the request.
|
||||
* @param {string} context.rejectUrl The URL the user will be redirected to after rejecting the request.
|
||||
*/
|
||||
request = wp.hooks.applyFilters( 'wp_application_passwords_approve_app_request', request, context );
|
||||
|
||||
wp.apiRequest( {
|
||||
path: '/wp/v2/users/me/application-passwords?_locale=user',
|
||||
method: 'POST',
|
||||
data: request
|
||||
} ).done( function( response, textStatus, jqXHR ) {
|
||||
|
||||
/**
|
||||
* Fires when an Authorize Application Password request has been successfully approved.
|
||||
*
|
||||
* In most cases, this should be used in combination with the {@see 'wp_authorize_application_password_form_approved_no_js'}
|
||||
* action to ensure that both the JS and no-JS variants are handled.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {Object} response The response from the REST API.
|
||||
* @param {string} response.password The newly created password.
|
||||
* @param {string} textStatus The status of the request.
|
||||
* @param {jqXHR} jqXHR The underlying jqXHR object that made the request.
|
||||
*/
|
||||
wp.hooks.doAction( 'wp_application_passwords_approve_app_request_success', response, textStatus, jqXHR );
|
||||
|
||||
var raw = authApp.success,
|
||||
url, message, $notice;
|
||||
|
||||
if ( raw ) {
|
||||
url = raw + ( -1 === raw.indexOf( '?' ) ? '?' : '&' ) +
|
||||
'site_url=' + encodeURIComponent( authApp.site_url ) +
|
||||
'&user_login=' + encodeURIComponent( authApp.user_login ) +
|
||||
'&password=' + encodeURIComponent( response.password );
|
||||
|
||||
window.location = url;
|
||||
} else {
|
||||
message = wp.i18n.sprintf(
|
||||
/* translators: %s: Application name. */
|
||||
'<label for="new-application-password-value">' + wp.i18n.__( 'Your new password for %s is:' ) + '</label>',
|
||||
'<strong></strong>'
|
||||
) + ' <input id="new-application-password-value" type="text" class="code" readonly="readonly" value="" />';
|
||||
$notice = $( '<div></div>' )
|
||||
.attr( 'role', 'alert' )
|
||||
.attr( 'tabindex', -1 )
|
||||
.addClass( 'notice notice-success notice-alt' )
|
||||
.append( $( '<p></p>' ).addClass( 'application-password-display' ).html( message ) )
|
||||
.append( '<p>' + wp.i18n.__( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ) + '</p>' );
|
||||
|
||||
// We're using .text() to write the variables to avoid any chance of XSS.
|
||||
$( 'strong', $notice ).text( response.name );
|
||||
$( 'input', $notice ).val( response.password );
|
||||
|
||||
$form.replaceWith( $notice );
|
||||
$notice.trigger( 'focus' );
|
||||
}
|
||||
} ).fail( function( jqXHR, textStatus, errorThrown ) {
|
||||
var errorMessage = errorThrown,
|
||||
error = null;
|
||||
|
||||
if ( jqXHR.responseJSON ) {
|
||||
error = jqXHR.responseJSON;
|
||||
|
||||
if ( error.message ) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
var $notice = $( '<div></div>' )
|
||||
.attr( 'role', 'alert' )
|
||||
.addClass( 'notice notice-error' )
|
||||
.append( $( '<p></p>' ).text( errorMessage ) );
|
||||
|
||||
$( 'h1' ).after( $notice );
|
||||
|
||||
$approveBtn.removeProp( 'aria-disabled', false ).removeClass( 'disabled' );
|
||||
|
||||
/**
|
||||
* Fires when an Authorize Application Password request encountered an error when trying to approve the request.
|
||||
*
|
||||
* @since 5.6.0
|
||||
* @since 5.6.1 Corrected action name and signature.
|
||||
*
|
||||
* @param {Object|null} error The error from the REST API. May be null if the server did not send proper JSON.
|
||||
* @param {string} textStatus The status of the request.
|
||||
* @param {string} errorThrown The error message associated with the response status code.
|
||||
* @param {jqXHR} jqXHR The underlying jqXHR object that made the request.
|
||||
*/
|
||||
wp.hooks.doAction( 'wp_application_passwords_approve_app_request_error', error, textStatus, errorThrown, jqXHR );
|
||||
} );
|
||||
} );
|
||||
|
||||
$rejectBtn.on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
/**
|
||||
* Fires when an Authorize Application Password request has been rejected by the user.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {Object} context Context about the Application Password request.
|
||||
* @param {string} context.userLogin The user's login username.
|
||||
* @param {string} context.successUrl The URL the user will be redirected to after approving the request.
|
||||
* @param {string} context.rejectUrl The URL the user will be redirected to after rejecting the request.
|
||||
*/
|
||||
wp.hooks.doAction( 'wp_application_passwords_reject_app', context );
|
||||
|
||||
// @todo: Make a better way to do this so it feels like less of a semi-open redirect.
|
||||
window.location = authApp.reject;
|
||||
} );
|
||||
|
||||
$form.on( 'submit', function( e ) {
|
||||
e.preventDefault();
|
||||
} );
|
||||
}( jQuery, authApp ) );
|
2
wp-admin/js/auth-app.min.js
vendored
Normal file
2
wp-admin/js/auth-app.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(t,s){var p=t("#app_name"),r=t("#approve"),e=t("#reject"),n=p.closest("form"),i={userLogin:s.user_login,successUrl:s.success,rejectUrl:s.reject};r.on("click",function(e){var a=p.val(),o=t('input[name="app_id"]',n).val();e.preventDefault(),r.prop("aria-disabled")||(0===a.length?p.trigger("focus"):(r.prop("aria-disabled",!0).addClass("disabled"),e={name:a},0<o.length&&(e.app_id=o),e=wp.hooks.applyFilters("wp_application_passwords_approve_app_request",e,i),wp.apiRequest({path:"/wp/v2/users/me/application-passwords?_locale=user",method:"POST",data:e}).done(function(e,a,o){wp.hooks.doAction("wp_application_passwords_approve_app_request_success",e,a,o);var a=s.success;a?(o=a+(-1===a.indexOf("?")?"?":"&")+"site_url="+encodeURIComponent(s.site_url)+"&user_login="+encodeURIComponent(s.user_login)+"&password="+encodeURIComponent(e.password),window.location=o):(a=wp.i18n.sprintf('<label for="new-application-password-value">'+wp.i18n.__("Your new password for %s is:")+"</label>","<strong></strong>")+' <input id="new-application-password-value" type="text" class="code" readonly="readonly" value="" />',o=t("<div></div>").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(t("<p></p>").addClass("application-password-display").html(a)).append("<p>"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"</p>"),t("strong",o).text(e.name),t("input",o).val(e.password),n.replaceWith(o),o.trigger("focus"))}).fail(function(e,a,o){var s=o,p=null,s=(e.responseJSON&&(p=e.responseJSON).message&&(s=p.message),t("<div></div>").attr("role","alert").addClass("notice notice-error").append(t("<p></p>").text(s)));t("h1").after(s),r.removeProp("aria-disabled",!1).removeClass("disabled"),wp.hooks.doAction("wp_application_passwords_approve_app_request_error",p,a,o,e)})))}),e.on("click",function(e){e.preventDefault(),wp.hooks.doAction("wp_application_passwords_reject_app",i),window.location=s.reject}),n.on("submit",function(e){e.preventDefault()})}(jQuery,authApp);
|
346
wp-admin/js/code-editor.js
Normal file
346
wp-admin/js/code-editor.js
Normal file
@ -0,0 +1,346 @@
|
||||
/**
|
||||
* @output wp-admin/js/code-editor.js
|
||||
*/
|
||||
|
||||
if ( 'undefined' === typeof window.wp ) {
|
||||
/**
|
||||
* @namespace wp
|
||||
*/
|
||||
window.wp = {};
|
||||
}
|
||||
if ( 'undefined' === typeof window.wp.codeEditor ) {
|
||||
/**
|
||||
* @namespace wp.codeEditor
|
||||
*/
|
||||
window.wp.codeEditor = {};
|
||||
}
|
||||
|
||||
( function( $, wp ) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Default settings for code editor.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @type {object}
|
||||
*/
|
||||
wp.codeEditor.defaultSettings = {
|
||||
codemirror: {},
|
||||
csslint: {},
|
||||
htmlhint: {},
|
||||
jshint: {},
|
||||
onTabNext: function() {},
|
||||
onTabPrevious: function() {},
|
||||
onChangeLintingErrors: function() {},
|
||||
onUpdateErrorNotice: function() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure linting.
|
||||
*
|
||||
* @param {CodeMirror} editor - Editor.
|
||||
* @param {Object} settings - Code editor settings.
|
||||
* @param {Object} settings.codeMirror - Settings for CodeMirror.
|
||||
* @param {Function} settings.onChangeLintingErrors - Callback for when there are changes to linting errors.
|
||||
* @param {Function} settings.onUpdateErrorNotice - Callback to update error notice.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function configureLinting( editor, settings ) { // eslint-disable-line complexity
|
||||
var currentErrorAnnotations = [], previouslyShownErrorAnnotations = [];
|
||||
|
||||
/**
|
||||
* Call the onUpdateErrorNotice if there are new errors to show.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function updateErrorNotice() {
|
||||
if ( settings.onUpdateErrorNotice && ! _.isEqual( currentErrorAnnotations, previouslyShownErrorAnnotations ) ) {
|
||||
settings.onUpdateErrorNotice( currentErrorAnnotations, editor );
|
||||
previouslyShownErrorAnnotations = currentErrorAnnotations;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lint options.
|
||||
*
|
||||
* @return {Object} Lint options.
|
||||
*/
|
||||
function getLintOptions() { // eslint-disable-line complexity
|
||||
var options = editor.getOption( 'lint' );
|
||||
|
||||
if ( ! options ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( true === options ) {
|
||||
options = {};
|
||||
} else if ( _.isObject( options ) ) {
|
||||
options = $.extend( {}, options );
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that rules must be sent in the "deprecated" lint.options property
|
||||
* to prevent linter from complaining about unrecognized options.
|
||||
* See <https://github.com/codemirror/CodeMirror/pull/4944>.
|
||||
*/
|
||||
if ( ! options.options ) {
|
||||
options.options = {};
|
||||
}
|
||||
|
||||
// Configure JSHint.
|
||||
if ( 'javascript' === settings.codemirror.mode && settings.jshint ) {
|
||||
$.extend( options.options, settings.jshint );
|
||||
}
|
||||
|
||||
// Configure CSSLint.
|
||||
if ( 'css' === settings.codemirror.mode && settings.csslint ) {
|
||||
$.extend( options.options, settings.csslint );
|
||||
}
|
||||
|
||||
// Configure HTMLHint.
|
||||
if ( 'htmlmixed' === settings.codemirror.mode && settings.htmlhint ) {
|
||||
options.options.rules = $.extend( {}, settings.htmlhint );
|
||||
|
||||
if ( settings.jshint ) {
|
||||
options.options.rules.jshint = settings.jshint;
|
||||
}
|
||||
if ( settings.csslint ) {
|
||||
options.options.rules.csslint = settings.csslint;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the onUpdateLinting CodeMirror event to route to onChangeLintingErrors and onUpdateErrorNotice.
|
||||
options.onUpdateLinting = (function( onUpdateLintingOverridden ) {
|
||||
return function( annotations, annotationsSorted, cm ) {
|
||||
var errorAnnotations = _.filter( annotations, function( annotation ) {
|
||||
return 'error' === annotation.severity;
|
||||
} );
|
||||
|
||||
if ( onUpdateLintingOverridden ) {
|
||||
onUpdateLintingOverridden.apply( annotations, annotationsSorted, cm );
|
||||
}
|
||||
|
||||
// Skip if there are no changes to the errors.
|
||||
if ( _.isEqual( errorAnnotations, currentErrorAnnotations ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentErrorAnnotations = errorAnnotations;
|
||||
|
||||
if ( settings.onChangeLintingErrors ) {
|
||||
settings.onChangeLintingErrors( errorAnnotations, annotations, annotationsSorted, cm );
|
||||
}
|
||||
|
||||
/*
|
||||
* Update notifications when the editor is not focused to prevent error message
|
||||
* from overwhelming the user during input, unless there are now no errors or there
|
||||
* were previously errors shown. In these cases, update immediately so they can know
|
||||
* that they fixed the errors.
|
||||
*/
|
||||
if ( ! editor.state.focused || 0 === currentErrorAnnotations.length || previouslyShownErrorAnnotations.length > 0 ) {
|
||||
updateErrorNotice();
|
||||
}
|
||||
};
|
||||
})( options.onUpdateLinting );
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
editor.setOption( 'lint', getLintOptions() );
|
||||
|
||||
// Keep lint options populated.
|
||||
editor.on( 'optionChange', function( cm, option ) {
|
||||
var options, gutters, gutterName = 'CodeMirror-lint-markers';
|
||||
if ( 'lint' !== option ) {
|
||||
return;
|
||||
}
|
||||
gutters = editor.getOption( 'gutters' ) || [];
|
||||
options = editor.getOption( 'lint' );
|
||||
if ( true === options ) {
|
||||
if ( ! _.contains( gutters, gutterName ) ) {
|
||||
editor.setOption( 'gutters', [ gutterName ].concat( gutters ) );
|
||||
}
|
||||
editor.setOption( 'lint', getLintOptions() ); // Expand to include linting options.
|
||||
} else if ( ! options ) {
|
||||
editor.setOption( 'gutters', _.without( gutters, gutterName ) );
|
||||
}
|
||||
|
||||
// Force update on error notice to show or hide.
|
||||
if ( editor.getOption( 'lint' ) ) {
|
||||
editor.performLint();
|
||||
} else {
|
||||
currentErrorAnnotations = [];
|
||||
updateErrorNotice();
|
||||
}
|
||||
} );
|
||||
|
||||
// Update error notice when leaving the editor.
|
||||
editor.on( 'blur', updateErrorNotice );
|
||||
|
||||
// Work around hint selection with mouse causing focus to leave editor.
|
||||
editor.on( 'startCompletion', function() {
|
||||
editor.off( 'blur', updateErrorNotice );
|
||||
} );
|
||||
editor.on( 'endCompletion', function() {
|
||||
var editorRefocusWait = 500;
|
||||
editor.on( 'blur', updateErrorNotice );
|
||||
|
||||
// Wait for editor to possibly get re-focused after selection.
|
||||
_.delay( function() {
|
||||
if ( ! editor.state.focused ) {
|
||||
updateErrorNotice();
|
||||
}
|
||||
}, editorRefocusWait );
|
||||
});
|
||||
|
||||
/*
|
||||
* Make sure setting validities are set if the user tries to click Publish
|
||||
* while an autocomplete dropdown is still open. The Customizer will block
|
||||
* saving when a setting has an error notifications on it. This is only
|
||||
* necessary for mouse interactions because keyboards will have already
|
||||
* blurred the field and cause onUpdateErrorNotice to have already been
|
||||
* called.
|
||||
*/
|
||||
$( document.body ).on( 'mousedown', function( event ) {
|
||||
if ( editor.state.focused && ! $.contains( editor.display.wrapper, event.target ) && ! $( event.target ).hasClass( 'CodeMirror-hint' ) ) {
|
||||
updateErrorNotice();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure tabbing.
|
||||
*
|
||||
* @param {CodeMirror} codemirror - Editor.
|
||||
* @param {Object} settings - Code editor settings.
|
||||
* @param {Object} settings.codeMirror - Settings for CodeMirror.
|
||||
* @param {Function} settings.onTabNext - Callback to handle tabbing to the next tabbable element.
|
||||
* @param {Function} settings.onTabPrevious - Callback to handle tabbing to the previous tabbable element.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function configureTabbing( codemirror, settings ) {
|
||||
var $textarea = $( codemirror.getTextArea() );
|
||||
|
||||
codemirror.on( 'blur', function() {
|
||||
$textarea.data( 'next-tab-blurs', false );
|
||||
});
|
||||
codemirror.on( 'keydown', function onKeydown( editor, event ) {
|
||||
var tabKeyCode = 9, escKeyCode = 27;
|
||||
|
||||
// Take note of the ESC keypress so that the next TAB can focus outside the editor.
|
||||
if ( escKeyCode === event.keyCode ) {
|
||||
$textarea.data( 'next-tab-blurs', true );
|
||||
return;
|
||||
}
|
||||
|
||||
// Short-circuit if tab key is not being pressed or the tab key press should move focus.
|
||||
if ( tabKeyCode !== event.keyCode || ! $textarea.data( 'next-tab-blurs' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus on previous or next focusable item.
|
||||
if ( event.shiftKey ) {
|
||||
settings.onTabPrevious( codemirror, event );
|
||||
} else {
|
||||
settings.onTabNext( codemirror, event );
|
||||
}
|
||||
|
||||
// Reset tab state.
|
||||
$textarea.data( 'next-tab-blurs', false );
|
||||
|
||||
// Prevent tab character from being added.
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} wp.codeEditor~CodeEditorInstance
|
||||
* @property {object} settings - The code editor settings.
|
||||
* @property {CodeMirror} codemirror - The CodeMirror instance.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize Code Editor (CodeMirror) for an existing textarea.
|
||||
*
|
||||
* @since 4.9.0
|
||||
*
|
||||
* @param {string|jQuery|Element} textarea - The HTML id, jQuery object, or DOM Element for the textarea that is used for the editor.
|
||||
* @param {Object} [settings] - Settings to override defaults.
|
||||
* @param {Function} [settings.onChangeLintingErrors] - Callback for when the linting errors have changed.
|
||||
* @param {Function} [settings.onUpdateErrorNotice] - Callback for when error notice should be displayed.
|
||||
* @param {Function} [settings.onTabPrevious] - Callback to handle tabbing to the previous tabbable element.
|
||||
* @param {Function} [settings.onTabNext] - Callback to handle tabbing to the next tabbable element.
|
||||
* @param {Object} [settings.codemirror] - Options for CodeMirror.
|
||||
* @param {Object} [settings.csslint] - Rules for CSSLint.
|
||||
* @param {Object} [settings.htmlhint] - Rules for HTMLHint.
|
||||
* @param {Object} [settings.jshint] - Rules for JSHint.
|
||||
*
|
||||
* @return {CodeEditorInstance} Instance.
|
||||
*/
|
||||
wp.codeEditor.initialize = function initialize( textarea, settings ) {
|
||||
var $textarea, codemirror, instanceSettings, instance;
|
||||
if ( 'string' === typeof textarea ) {
|
||||
$textarea = $( '#' + textarea );
|
||||
} else {
|
||||
$textarea = $( textarea );
|
||||
}
|
||||
|
||||
instanceSettings = $.extend( {}, wp.codeEditor.defaultSettings, settings );
|
||||
instanceSettings.codemirror = $.extend( {}, instanceSettings.codemirror );
|
||||
|
||||
codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror );
|
||||
|
||||
configureLinting( codemirror, instanceSettings );
|
||||
|
||||
instance = {
|
||||
settings: instanceSettings,
|
||||
codemirror: codemirror
|
||||
};
|
||||
|
||||
if ( codemirror.showHint ) {
|
||||
codemirror.on( 'keyup', function( editor, event ) { // eslint-disable-line complexity
|
||||
var shouldAutocomplete, isAlphaKey = /^[a-zA-Z]$/.test( event.key ), lineBeforeCursor, innerMode, token;
|
||||
if ( codemirror.state.completionActive && isAlphaKey ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent autocompletion in string literals or comments.
|
||||
token = codemirror.getTokenAt( codemirror.getCursor() );
|
||||
if ( 'string' === token.type || 'comment' === token.type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
innerMode = wp.CodeMirror.innerMode( codemirror.getMode(), token.state ).mode.name;
|
||||
lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).substr( 0, codemirror.doc.getCursor().ch );
|
||||
if ( 'html' === innerMode || 'xml' === innerMode ) {
|
||||
shouldAutocomplete =
|
||||
'<' === event.key ||
|
||||
'/' === event.key && 'tag' === token.type ||
|
||||
isAlphaKey && 'tag' === token.type ||
|
||||
isAlphaKey && 'attribute' === token.type ||
|
||||
'=' === token.string && token.state.htmlState && token.state.htmlState.tagName;
|
||||
} else if ( 'css' === innerMode ) {
|
||||
shouldAutocomplete =
|
||||
isAlphaKey ||
|
||||
':' === event.key ||
|
||||
' ' === event.key && /:\s+$/.test( lineBeforeCursor );
|
||||
} else if ( 'javascript' === innerMode ) {
|
||||
shouldAutocomplete = isAlphaKey || '.' === event.key;
|
||||
} else if ( 'clike' === innerMode && 'php' === codemirror.options.mode ) {
|
||||
shouldAutocomplete = 'keyword' === token.type || 'variable' === token.type;
|
||||
}
|
||||
if ( shouldAutocomplete ) {
|
||||
codemirror.showHint( { completeSingle: false } );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Facilitate tabbing out of the editor.
|
||||
configureTabbing( codemirror, settings );
|
||||
|
||||
return instance;
|
||||
};
|
||||
|
||||
})( window.jQuery, window.wp );
|
2
wp-admin/js/code-editor.min.js
vendored
Normal file
2
wp-admin/js/code-editor.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
void 0===window.wp&&(window.wp={}),void 0===window.wp.codeEditor&&(window.wp.codeEditor={}),function(u,d){"use strict";function s(r,s){var a=[],d=[];function c(){s.onUpdateErrorNotice&&!_.isEqual(a,d)&&(s.onUpdateErrorNotice(a,r),d=a)}function i(){var i,t=r.getOption("lint");return!!t&&(!0===t?t={}:_.isObject(t)&&(t=u.extend({},t)),t.options||(t.options={}),"javascript"===s.codemirror.mode&&s.jshint&&u.extend(t.options,s.jshint),"css"===s.codemirror.mode&&s.csslint&&u.extend(t.options,s.csslint),"htmlmixed"===s.codemirror.mode&&s.htmlhint&&(t.options.rules=u.extend({},s.htmlhint),s.jshint&&(t.options.rules.jshint=s.jshint),s.csslint)&&(t.options.rules.csslint=s.csslint),t.onUpdateLinting=(i=t.onUpdateLinting,function(t,e,n){var o=_.filter(t,function(t){return"error"===t.severity});i&&i.apply(t,e,n),!_.isEqual(o,a)&&(a=o,s.onChangeLintingErrors&&s.onChangeLintingErrors(o,t,e,n),!r.state.focused||0===a.length||0<d.length)&&c()}),t)}r.setOption("lint",i()),r.on("optionChange",function(t,e){var n,o="CodeMirror-lint-markers";"lint"===e&&(e=r.getOption("gutters")||[],!0===(n=r.getOption("lint"))?(_.contains(e,o)||r.setOption("gutters",[o].concat(e)),r.setOption("lint",i())):n||r.setOption("gutters",_.without(e,o)),r.getOption("lint")?r.performLint():(a=[],c()))}),r.on("blur",c),r.on("startCompletion",function(){r.off("blur",c)}),r.on("endCompletion",function(){r.on("blur",c),_.delay(function(){r.state.focused||c()},500)}),u(document.body).on("mousedown",function(t){!r.state.focused||u.contains(r.display.wrapper,t.target)||u(t.target).hasClass("CodeMirror-hint")||c()})}d.codeEditor.defaultSettings={codemirror:{},csslint:{},htmlhint:{},jshint:{},onTabNext:function(){},onTabPrevious:function(){},onChangeLintingErrors:function(){},onUpdateErrorNotice:function(){}},d.codeEditor.initialize=function(t,e){var a,n,o,i,t=u("string"==typeof t?"#"+t:t),r=u.extend({},d.codeEditor.defaultSettings,e);return r.codemirror=u.extend({},r.codemirror),s(a=d.CodeMirror.fromTextArea(t[0],r.codemirror),r),t={settings:r,codemirror:a},a.showHint&&a.on("keyup",function(t,e){var n,o,i,r,s=/^[a-zA-Z]$/.test(e.key);a.state.completionActive&&s||"string"!==(r=a.getTokenAt(a.getCursor())).type&&"comment"!==r.type&&(i=d.CodeMirror.innerMode(a.getMode(),r.state).mode.name,o=a.doc.getLine(a.doc.getCursor().line).substr(0,a.doc.getCursor().ch),"html"===i||"xml"===i?n="<"===e.key||"/"===e.key&&"tag"===r.type||s&&"tag"===r.type||s&&"attribute"===r.type||"="===r.string&&r.state.htmlState&&r.state.htmlState.tagName:"css"===i?n=s||":"===e.key||" "===e.key&&/:\s+$/.test(o):"javascript"===i?n=s||"."===e.key:"clike"===i&&"php"===a.options.mode&&(n="keyword"===r.type||"variable"===r.type),n)&&a.showHint({completeSingle:!1})}),o=e,i=u((n=a).getTextArea()),n.on("blur",function(){i.data("next-tab-blurs",!1)}),n.on("keydown",function(t,e){27===e.keyCode?i.data("next-tab-blurs",!0):9===e.keyCode&&i.data("next-tab-blurs")&&(e.shiftKey?o.onTabPrevious(n,e):o.onTabNext(n,e),i.data("next-tab-blurs",!1),e.preventDefault())}),t}}(window.jQuery,window.wp);
|
356
wp-admin/js/color-picker.js
Normal file
356
wp-admin/js/color-picker.js
Normal file
@ -0,0 +1,356 @@
|
||||
/**
|
||||
* @output wp-admin/js/color-picker.js
|
||||
*/
|
||||
|
||||
( function( $, undef ) {
|
||||
|
||||
var ColorPicker,
|
||||
_before = '<button type="button" class="button wp-color-result" aria-expanded="false"><span class="wp-color-result-text"></span></button>',
|
||||
_after = '<div class="wp-picker-holder" />',
|
||||
_wrap = '<div class="wp-picker-container" />',
|
||||
_button = '<input type="button" class="button button-small" />',
|
||||
_wrappingLabel = '<label></label>',
|
||||
_wrappingLabelText = '<span class="screen-reader-text"></span>',
|
||||
__ = wp.i18n.__;
|
||||
|
||||
/**
|
||||
* Creates a jQuery UI color picker that is used in the theme customizer.
|
||||
*
|
||||
* @class $.widget.wp.wpColorPicker
|
||||
*
|
||||
* @since 3.5.0
|
||||
*/
|
||||
ColorPicker = /** @lends $.widget.wp.wpColorPicker.prototype */{
|
||||
options: {
|
||||
defaultColor: false,
|
||||
change: false,
|
||||
clear: false,
|
||||
hide: true,
|
||||
palettes: true,
|
||||
width: 255,
|
||||
mode: 'hsv',
|
||||
type: 'full',
|
||||
slider: 'horizontal'
|
||||
},
|
||||
/**
|
||||
* Creates a color picker that only allows you to adjust the hue.
|
||||
*
|
||||
* @since 3.5.0
|
||||
* @access private
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
_createHueOnly: function() {
|
||||
var self = this,
|
||||
el = self.element,
|
||||
color;
|
||||
|
||||
el.hide();
|
||||
|
||||
// Set the saturation to the maximum level.
|
||||
color = 'hsl(' + el.val() + ', 100, 50)';
|
||||
|
||||
// Create an instance of the color picker, using the hsl mode.
|
||||
el.iris( {
|
||||
mode: 'hsl',
|
||||
type: 'hue',
|
||||
hide: false,
|
||||
color: color,
|
||||
/**
|
||||
* Handles the onChange event if one has been defined in the options.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @param {Event} event The event that's being called.
|
||||
* @param {HTMLElement} ui The HTMLElement containing the color picker.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
change: function( event, ui ) {
|
||||
if ( typeof self.options.change === 'function' ) {
|
||||
self.options.change.call( this, event, ui );
|
||||
}
|
||||
},
|
||||
width: self.options.width,
|
||||
slider: self.options.slider
|
||||
} );
|
||||
},
|
||||
/**
|
||||
* Creates the color picker, sets default values, css classes and wraps it all in HTML.
|
||||
*
|
||||
* @since 3.5.0
|
||||
* @access private
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
_create: function() {
|
||||
// Return early if Iris support is missing.
|
||||
if ( ! $.support.iris ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this,
|
||||
el = self.element;
|
||||
|
||||
// Override default options with options bound to the element.
|
||||
$.extend( self.options, el.data() );
|
||||
|
||||
// Create a color picker which only allows adjustments to the hue.
|
||||
if ( self.options.type === 'hue' ) {
|
||||
return self._createHueOnly();
|
||||
}
|
||||
|
||||
// Bind the close event.
|
||||
self.close = self.close.bind( self );
|
||||
|
||||
self.initialValue = el.val();
|
||||
|
||||
// Add a CSS class to the input field.
|
||||
el.addClass( 'wp-color-picker' );
|
||||
|
||||
/*
|
||||
* Check if there's already a wrapping label, e.g. in the Customizer.
|
||||
* If there's no label, add a default one to match the Customizer template.
|
||||
*/
|
||||
if ( ! el.parent( 'label' ).length ) {
|
||||
// Wrap the input field in the default label.
|
||||
el.wrap( _wrappingLabel );
|
||||
// Insert the default label text.
|
||||
self.wrappingLabelText = $( _wrappingLabelText )
|
||||
.insertBefore( el )
|
||||
.text( __( 'Color value' ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, either it's the standalone version or the Customizer
|
||||
* one, we have a wrapping label to use as hook in the DOM, let's store it.
|
||||
*/
|
||||
self.wrappingLabel = el.parent();
|
||||
|
||||
// Wrap the label in the main wrapper.
|
||||
self.wrappingLabel.wrap( _wrap );
|
||||
// Store a reference to the main wrapper.
|
||||
self.wrap = self.wrappingLabel.parent();
|
||||
// Set up the toggle button and insert it before the wrapping label.
|
||||
self.toggler = $( _before )
|
||||
.insertBefore( self.wrappingLabel )
|
||||
.css( { backgroundColor: self.initialValue } );
|
||||
// Set the toggle button span element text.
|
||||
self.toggler.find( '.wp-color-result-text' ).text( __( 'Select Color' ) );
|
||||
// Set up the Iris container and insert it after the wrapping label.
|
||||
self.pickerContainer = $( _after ).insertAfter( self.wrappingLabel );
|
||||
// Store a reference to the Clear/Default button.
|
||||
self.button = $( _button );
|
||||
|
||||
// Set up the Clear/Default button.
|
||||
if ( self.options.defaultColor ) {
|
||||
self.button
|
||||
.addClass( 'wp-picker-default' )
|
||||
.val( __( 'Default' ) )
|
||||
.attr( 'aria-label', __( 'Select default color' ) );
|
||||
} else {
|
||||
self.button
|
||||
.addClass( 'wp-picker-clear' )
|
||||
.val( __( 'Clear' ) )
|
||||
.attr( 'aria-label', __( 'Clear color' ) );
|
||||
}
|
||||
|
||||
// Wrap the wrapping label in its wrapper and append the Clear/Default button.
|
||||
self.wrappingLabel
|
||||
.wrap( '<span class="wp-picker-input-wrap hidden" />' )
|
||||
.after( self.button );
|
||||
|
||||
/*
|
||||
* The input wrapper now contains the label+input+Clear/Default button.
|
||||
* Store a reference to the input wrapper: we'll use this to toggle
|
||||
* the controls visibility.
|
||||
*/
|
||||
self.inputWrapper = el.closest( '.wp-picker-input-wrap' );
|
||||
|
||||
el.iris( {
|
||||
target: self.pickerContainer,
|
||||
hide: self.options.hide,
|
||||
width: self.options.width,
|
||||
mode: self.options.mode,
|
||||
palettes: self.options.palettes,
|
||||
/**
|
||||
* Handles the onChange event if one has been defined in the options and additionally
|
||||
* sets the background color for the toggler element.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @param {Event} event The event that's being called.
|
||||
* @param {HTMLElement} ui The HTMLElement containing the color picker.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
change: function( event, ui ) {
|
||||
self.toggler.css( { backgroundColor: ui.color.toString() } );
|
||||
|
||||
if ( typeof self.options.change === 'function' ) {
|
||||
self.options.change.call( this, event, ui );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
el.val( self.initialValue );
|
||||
self._addListeners();
|
||||
|
||||
// Force the color picker to always be closed on initial load.
|
||||
if ( ! self.options.hide ) {
|
||||
self.toggler.click();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Binds event listeners to the color picker.
|
||||
*
|
||||
* @since 3.5.0
|
||||
* @access private
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
_addListeners: function() {
|
||||
var self = this;
|
||||
|
||||
/**
|
||||
* Prevent any clicks inside this widget from leaking to the top and closing it.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param {Event} event The event that's being called.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
self.wrap.on( 'click.wpcolorpicker', function( event ) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
/**
|
||||
* Open or close the color picker depending on the class.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*/
|
||||
self.toggler.on( 'click', function(){
|
||||
if ( self.toggler.hasClass( 'wp-picker-open' ) ) {
|
||||
self.close();
|
||||
} else {
|
||||
self.open();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks if value is empty when changing the color in the color picker.
|
||||
* If so, the background color is cleared.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param {Event} event The event that's being called.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
self.element.on( 'change', function( event ) {
|
||||
var me = $( this ),
|
||||
val = me.val();
|
||||
|
||||
if ( val === '' || val === '#' ) {
|
||||
self.toggler.css( 'backgroundColor', '' );
|
||||
// Fire clear callback if we have one.
|
||||
if ( typeof self.options.clear === 'function' ) {
|
||||
self.options.clear.call( this, event );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Enables the user to either clear the color in the color picker or revert back to the default color.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param {Event} event The event that's being called.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
self.button.on( 'click', function( event ) {
|
||||
var me = $( this );
|
||||
if ( me.hasClass( 'wp-picker-clear' ) ) {
|
||||
self.element.val( '' );
|
||||
self.toggler.css( 'backgroundColor', '' );
|
||||
if ( typeof self.options.clear === 'function' ) {
|
||||
self.options.clear.call( this, event );
|
||||
}
|
||||
} else if ( me.hasClass( 'wp-picker-default' ) ) {
|
||||
self.element.val( self.options.defaultColor ).change();
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Opens the color picker dialog.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
open: function() {
|
||||
this.element.iris( 'toggle' );
|
||||
this.inputWrapper.removeClass( 'hidden' );
|
||||
this.wrap.addClass( 'wp-picker-active' );
|
||||
this.toggler
|
||||
.addClass( 'wp-picker-open' )
|
||||
.attr( 'aria-expanded', 'true' );
|
||||
$( 'body' ).trigger( 'click.wpcolorpicker' ).on( 'click.wpcolorpicker', this.close );
|
||||
},
|
||||
/**
|
||||
* Closes the color picker dialog.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
close: function() {
|
||||
this.element.iris( 'toggle' );
|
||||
this.inputWrapper.addClass( 'hidden' );
|
||||
this.wrap.removeClass( 'wp-picker-active' );
|
||||
this.toggler
|
||||
.removeClass( 'wp-picker-open' )
|
||||
.attr( 'aria-expanded', 'false' );
|
||||
$( 'body' ).off( 'click.wpcolorpicker', this.close );
|
||||
},
|
||||
/**
|
||||
* Returns the iris object if no new color is provided. If a new color is provided, it sets the new color.
|
||||
*
|
||||
* @param newColor {string|*} The new color to use. Can be undefined.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @return {string} The element's color.
|
||||
*/
|
||||
color: function( newColor ) {
|
||||
if ( newColor === undef ) {
|
||||
return this.element.iris( 'option', 'color' );
|
||||
}
|
||||
this.element.iris( 'option', 'color', newColor );
|
||||
},
|
||||
/**
|
||||
* Returns the iris object if no new default color is provided.
|
||||
* If a new default color is provided, it sets the new default color.
|
||||
*
|
||||
* @param newDefaultColor {string|*} The new default color to use. Can be undefined.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @return {boolean|string} The element's color.
|
||||
*/
|
||||
defaultColor: function( newDefaultColor ) {
|
||||
if ( newDefaultColor === undef ) {
|
||||
return this.options.defaultColor;
|
||||
}
|
||||
|
||||
this.options.defaultColor = newDefaultColor;
|
||||
}
|
||||
};
|
||||
|
||||
// Register the color picker as a widget.
|
||||
$.widget( 'wp.wpColorPicker', ColorPicker );
|
||||
}( jQuery ) );
|
2
wp-admin/js/color-picker.min.js
vendored
Normal file
2
wp-admin/js/color-picker.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(i,t){var a=wp.i18n.__;i.widget("wp.wpColorPicker",{options:{defaultColor:!1,change:!1,clear:!1,hide:!0,palettes:!0,width:255,mode:"hsv",type:"full",slider:"horizontal"},_createHueOnly:function(){var e,o=this,t=o.element;t.hide(),e="hsl("+t.val()+", 100, 50)",t.iris({mode:"hsl",type:"hue",hide:!1,color:e,change:function(e,t){"function"==typeof o.options.change&&o.options.change.call(this,e,t)},width:o.options.width,slider:o.options.slider})},_create:function(){if(i.support.iris){var o=this,e=o.element;if(i.extend(o.options,e.data()),"hue"===o.options.type)return o._createHueOnly();o.close=o.close.bind(o),o.initialValue=e.val(),e.addClass("wp-color-picker"),e.parent("label").length||(e.wrap("<label></label>"),o.wrappingLabelText=i('<span class="screen-reader-text"></span>').insertBefore(e).text(a("Color value"))),o.wrappingLabel=e.parent(),o.wrappingLabel.wrap('<div class="wp-picker-container" />'),o.wrap=o.wrappingLabel.parent(),o.toggler=i('<button type="button" class="button wp-color-result" aria-expanded="false"><span class="wp-color-result-text"></span></button>').insertBefore(o.wrappingLabel).css({backgroundColor:o.initialValue}),o.toggler.find(".wp-color-result-text").text(a("Select Color")),o.pickerContainer=i('<div class="wp-picker-holder" />').insertAfter(o.wrappingLabel),o.button=i('<input type="button" class="button button-small" />'),o.options.defaultColor?o.button.addClass("wp-picker-default").val(a("Default")).attr("aria-label",a("Select default color")):o.button.addClass("wp-picker-clear").val(a("Clear")).attr("aria-label",a("Clear color")),o.wrappingLabel.wrap('<span class="wp-picker-input-wrap hidden" />').after(o.button),o.inputWrapper=e.closest(".wp-picker-input-wrap"),e.iris({target:o.pickerContainer,hide:o.options.hide,width:o.options.width,mode:o.options.mode,palettes:o.options.palettes,change:function(e,t){o.toggler.css({backgroundColor:t.color.toString()}),"function"==typeof o.options.change&&o.options.change.call(this,e,t)}}),e.val(o.initialValue),o._addListeners(),o.options.hide||o.toggler.click()}},_addListeners:function(){var o=this;o.wrap.on("click.wpcolorpicker",function(e){e.stopPropagation()}),o.toggler.on("click",function(){o.toggler.hasClass("wp-picker-open")?o.close():o.open()}),o.element.on("change",function(e){var t=i(this).val();""!==t&&"#"!==t||(o.toggler.css("backgroundColor",""),"function"==typeof o.options.clear&&o.options.clear.call(this,e))}),o.button.on("click",function(e){var t=i(this);t.hasClass("wp-picker-clear")?(o.element.val(""),o.toggler.css("backgroundColor",""),"function"==typeof o.options.clear&&o.options.clear.call(this,e)):t.hasClass("wp-picker-default")&&o.element.val(o.options.defaultColor).change()})},open:function(){this.element.iris("toggle"),this.inputWrapper.removeClass("hidden"),this.wrap.addClass("wp-picker-active"),this.toggler.addClass("wp-picker-open").attr("aria-expanded","true"),i("body").trigger("click.wpcolorpicker").on("click.wpcolorpicker",this.close)},close:function(){this.element.iris("toggle"),this.inputWrapper.addClass("hidden"),this.wrap.removeClass("wp-picker-active"),this.toggler.removeClass("wp-picker-open").attr("aria-expanded","false"),i("body").off("click.wpcolorpicker",this.close)},color:function(e){if(e===t)return this.element.iris("option","color");this.element.iris("option","color",e)},defaultColor:function(e){if(e===t)return this.options.defaultColor;this.options.defaultColor=e}})}(jQuery);
|
102
wp-admin/js/comment.js
Normal file
102
wp-admin/js/comment.js
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @output wp-admin/js/comment.js
|
||||
*/
|
||||
|
||||
/* global postboxes */
|
||||
|
||||
/**
|
||||
* Binds to the document ready event.
|
||||
*
|
||||
* @since 2.5.0
|
||||
*
|
||||
* @param {jQuery} $ The jQuery object.
|
||||
*/
|
||||
jQuery( function($) {
|
||||
|
||||
postboxes.add_postbox_toggles('comment');
|
||||
|
||||
var $timestampdiv = $('#timestampdiv'),
|
||||
$timestamp = $( '#timestamp' ),
|
||||
stamp = $timestamp.html(),
|
||||
$timestampwrap = $timestampdiv.find( '.timestamp-wrap' ),
|
||||
$edittimestamp = $timestampdiv.siblings( 'a.edit-timestamp' );
|
||||
|
||||
/**
|
||||
* Adds event that opens the time stamp form if the form is hidden.
|
||||
*
|
||||
* @listens $edittimestamp:click
|
||||
*
|
||||
* @param {Event} event The event object.
|
||||
* @return {void}
|
||||
*/
|
||||
$edittimestamp.on( 'click', function( event ) {
|
||||
if ( $timestampdiv.is( ':hidden' ) ) {
|
||||
// Slide down the form and set focus on the first field.
|
||||
$timestampdiv.slideDown( 'fast', function() {
|
||||
$( 'input, select', $timestampwrap ).first().trigger( 'focus' );
|
||||
} );
|
||||
$(this).hide();
|
||||
}
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
/**
|
||||
* Resets the time stamp values when the cancel button is clicked.
|
||||
*
|
||||
* @listens .cancel-timestamp:click
|
||||
*
|
||||
* @param {Event} event The event object.
|
||||
* @return {void}
|
||||
*/
|
||||
|
||||
$timestampdiv.find('.cancel-timestamp').on( 'click', function( event ) {
|
||||
// Move focus back to the Edit link.
|
||||
$edittimestamp.show().trigger( 'focus' );
|
||||
$timestampdiv.slideUp( 'fast' );
|
||||
$('#mm').val($('#hidden_mm').val());
|
||||
$('#jj').val($('#hidden_jj').val());
|
||||
$('#aa').val($('#hidden_aa').val());
|
||||
$('#hh').val($('#hidden_hh').val());
|
||||
$('#mn').val($('#hidden_mn').val());
|
||||
$timestamp.html( stamp );
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets the time stamp values when the ok button is clicked.
|
||||
*
|
||||
* @listens .save-timestamp:click
|
||||
*
|
||||
* @param {Event} event The event object.
|
||||
* @return {void}
|
||||
*/
|
||||
$timestampdiv.find('.save-timestamp').on( 'click', function( event ) { // Crazyhorse branch - multiple OK cancels.
|
||||
var aa = $('#aa').val(), mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val(),
|
||||
newD = new Date( aa, mm - 1, jj, hh, mn );
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if ( newD.getFullYear() != aa || (1 + newD.getMonth()) != mm || newD.getDate() != jj || newD.getMinutes() != mn ) {
|
||||
$timestampwrap.addClass( 'form-invalid' );
|
||||
return;
|
||||
} else {
|
||||
$timestampwrap.removeClass( 'form-invalid' );
|
||||
}
|
||||
|
||||
$timestamp.html(
|
||||
wp.i18n.__( 'Submitted on:' ) + ' <b>' +
|
||||
/* translators: 1: Month, 2: Day, 3: Year, 4: Hour, 5: Minute. */
|
||||
wp.i18n.__( '%1$s %2$s, %3$s at %4$s:%5$s' )
|
||||
.replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) )
|
||||
.replace( '%2$s', parseInt( jj, 10 ) )
|
||||
.replace( '%3$s', aa )
|
||||
.replace( '%4$s', ( '00' + hh ).slice( -2 ) )
|
||||
.replace( '%5$s', ( '00' + mn ).slice( -2 ) ) +
|
||||
'</b> '
|
||||
);
|
||||
|
||||
// Move focus back to the Edit link.
|
||||
$edittimestamp.show().trigger( 'focus' );
|
||||
$timestampdiv.slideUp( 'fast' );
|
||||
});
|
||||
});
|
2
wp-admin/js/comment.min.js
vendored
Normal file
2
wp-admin/js/comment.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
jQuery(function(m){postboxes.add_postbox_toggles("comment");var d=m("#timestampdiv"),o=m("#timestamp"),a=o.html(),v=d.find(".timestamp-wrap"),c=d.siblings("a.edit-timestamp");c.on("click",function(e){d.is(":hidden")&&(d.slideDown("fast",function(){m("input, select",v).first().trigger("focus")}),m(this).hide()),e.preventDefault()}),d.find(".cancel-timestamp").on("click",function(e){c.show().trigger("focus"),d.slideUp("fast"),m("#mm").val(m("#hidden_mm").val()),m("#jj").val(m("#hidden_jj").val()),m("#aa").val(m("#hidden_aa").val()),m("#hh").val(m("#hidden_hh").val()),m("#mn").val(m("#hidden_mn").val()),o.html(a),e.preventDefault()}),d.find(".save-timestamp").on("click",function(e){var a=m("#aa").val(),t=m("#mm").val(),i=m("#jj").val(),s=m("#hh").val(),l=m("#mn").val(),n=new Date(a,t-1,i,s,l);e.preventDefault(),n.getFullYear()!=a||1+n.getMonth()!=t||n.getDate()!=i||n.getMinutes()!=l?v.addClass("form-invalid"):(v.removeClass("form-invalid"),o.html(wp.i18n.__("Submitted on:")+" <b>"+wp.i18n.__("%1$s %2$s, %3$s at %4$s:%5$s").replace("%1$s",m('option[value="'+t+'"]',"#mm").attr("data-text")).replace("%2$s",parseInt(i,10)).replace("%3$s",a).replace("%4$s",("00"+s).slice(-2)).replace("%5$s",("00"+l).slice(-2))+"</b> "),c.show().trigger("focus"),d.slideUp("fast"))})});
|
2262
wp-admin/js/common.js
Normal file
2262
wp-admin/js/common.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/common.min.js
vendored
Normal file
2
wp-admin/js/common.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
147
wp-admin/js/custom-background.js
Normal file
147
wp-admin/js/custom-background.js
Normal file
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @output wp-admin/js/custom-background.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl */
|
||||
|
||||
/**
|
||||
* Registers all events for customizing the background.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @requires jQuery
|
||||
*/
|
||||
(function($) {
|
||||
$( function() {
|
||||
var frame,
|
||||
bgImage = $( '#custom-background-image' );
|
||||
|
||||
/**
|
||||
* Instantiates the WordPress color picker and binds the change and clear events.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('#background-color').wpColorPicker({
|
||||
change: function( event, ui ) {
|
||||
bgImage.css('background-color', ui.color.toString());
|
||||
},
|
||||
clear: function() {
|
||||
bgImage.css('background-color', '');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Alters the background size CSS property whenever the background size input has changed.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( 'select[name="background-size"]' ).on( 'change', function() {
|
||||
bgImage.css( 'background-size', $( this ).val() );
|
||||
});
|
||||
|
||||
/**
|
||||
* Alters the background position CSS property whenever the background position input has changed.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( 'input[name="background-position"]' ).on( 'change', function() {
|
||||
bgImage.css( 'background-position', $( this ).val() );
|
||||
});
|
||||
|
||||
/**
|
||||
* Alters the background repeat CSS property whenever the background repeat input has changed.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( 'input[name="background-repeat"]' ).on( 'change', function() {
|
||||
bgImage.css( 'background-repeat', $( this ).is( ':checked' ) ? 'repeat' : 'no-repeat' );
|
||||
});
|
||||
|
||||
/**
|
||||
* Alters the background attachment CSS property whenever the background attachment input has changed.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( 'input[name="background-attachment"]' ).on( 'change', function() {
|
||||
bgImage.css( 'background-attachment', $( this ).is( ':checked' ) ? 'scroll' : 'fixed' );
|
||||
});
|
||||
|
||||
/**
|
||||
* Binds the event for opening the WP Media dialog.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('#choose-from-library-link').on( 'click', function( event ) {
|
||||
var $el = $(this);
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
// If the media frame already exists, reopen it.
|
||||
if ( frame ) {
|
||||
frame.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the media frame.
|
||||
frame = wp.media.frames.customBackground = wp.media({
|
||||
// Set the title of the modal.
|
||||
title: $el.data('choose'),
|
||||
|
||||
// Tell the modal to show only images.
|
||||
library: {
|
||||
type: 'image'
|
||||
},
|
||||
|
||||
// Customize the submit button.
|
||||
button: {
|
||||
// Set the text of the button.
|
||||
text: $el.data('update'),
|
||||
/*
|
||||
* Tell the button not to close the modal, since we're
|
||||
* going to refresh the page when the image is selected.
|
||||
*/
|
||||
close: false
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* When an image is selected, run a callback.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
frame.on( 'select', function() {
|
||||
// Grab the selected attachment.
|
||||
var attachment = frame.state().get('selection').first();
|
||||
var nonceValue = $( '#_wpnonce' ).val() || '';
|
||||
|
||||
// Run an Ajax request to set the background image.
|
||||
$.post( ajaxurl, {
|
||||
action: 'set-background-image',
|
||||
attachment_id: attachment.id,
|
||||
_ajax_nonce: nonceValue,
|
||||
size: 'full'
|
||||
}).done( function() {
|
||||
// When the request completes, reload the window.
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
|
||||
// Finally, open the modal.
|
||||
frame.open();
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
2
wp-admin/js/custom-background.min.js
vendored
Normal file
2
wp-admin/js/custom-background.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(e){e(function(){var c,a=e("#custom-background-image");e("#background-color").wpColorPicker({change:function(n,o){a.css("background-color",o.color.toString())},clear:function(){a.css("background-color","")}}),e('select[name="background-size"]').on("change",function(){a.css("background-size",e(this).val())}),e('input[name="background-position"]').on("change",function(){a.css("background-position",e(this).val())}),e('input[name="background-repeat"]').on("change",function(){a.css("background-repeat",e(this).is(":checked")?"repeat":"no-repeat")}),e('input[name="background-attachment"]').on("change",function(){a.css("background-attachment",e(this).is(":checked")?"scroll":"fixed")}),e("#choose-from-library-link").on("click",function(n){var o=e(this);n.preventDefault(),c||(c=wp.media.frames.customBackground=wp.media({title:o.data("choose"),library:{type:"image"},button:{text:o.data("update"),close:!1}})).on("select",function(){var n=c.state().get("selection").first(),o=e("#_wpnonce").val()||"";e.post(ajaxurl,{action:"set-background-image",attachment_id:n.id,_ajax_nonce:o,size:"full"}).done(function(){window.location.reload()})}),c.open()})})}(jQuery);
|
88
wp-admin/js/custom-header.js
Normal file
88
wp-admin/js/custom-header.js
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @output wp-admin/js/custom-header.js
|
||||
*/
|
||||
|
||||
/* global isRtl */
|
||||
|
||||
/**
|
||||
* Initializes the custom header selection page.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @deprecated 4.1.0 The page this is used on is never linked to from the UI.
|
||||
* Setting a custom header is completely handled by the Customizer.
|
||||
*/
|
||||
(function($) {
|
||||
var frame;
|
||||
|
||||
$( function() {
|
||||
// Fetch available headers.
|
||||
var $headers = $('.available-headers');
|
||||
|
||||
// Apply jQuery.masonry once the images have loaded.
|
||||
$headers.imagesLoaded( function() {
|
||||
$headers.masonry({
|
||||
itemSelector: '.default-header',
|
||||
isRTL: !! ( 'undefined' != typeof isRtl && isRtl )
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Opens the 'choose from library' frame and creates it if it doesn't exist.
|
||||
*
|
||||
* @since 3.5.0
|
||||
* @deprecated 4.1.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('#choose-from-library-link').on( 'click', function( event ) {
|
||||
var $el = $(this);
|
||||
event.preventDefault();
|
||||
|
||||
// If the media frame already exists, reopen it.
|
||||
if ( frame ) {
|
||||
frame.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the media frame.
|
||||
frame = wp.media.frames.customHeader = wp.media({
|
||||
// Set the title of the modal.
|
||||
title: $el.data('choose'),
|
||||
|
||||
// Tell the modal to show only images.
|
||||
library: {
|
||||
type: 'image'
|
||||
},
|
||||
|
||||
// Customize the submit button.
|
||||
button: {
|
||||
// Set the text of the button.
|
||||
text: $el.data('update'),
|
||||
// Tell the button not to close the modal, since we're
|
||||
// going to refresh the page when the image is selected.
|
||||
close: false
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the window location to include the selected attachment.
|
||||
*
|
||||
* @since 3.5.0
|
||||
* @deprecated 4.1.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
frame.on( 'select', function() {
|
||||
// Grab the selected attachment.
|
||||
var attachment = frame.state().get('selection').first(),
|
||||
link = $el.data('updateLink');
|
||||
|
||||
// Tell the browser to navigate to the crop step.
|
||||
window.location = link + '&file=' + attachment.id;
|
||||
});
|
||||
|
||||
frame.open();
|
||||
});
|
||||
});
|
||||
}(jQuery));
|
9353
wp-admin/js/customize-controls.js
Normal file
9353
wp-admin/js/customize-controls.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/customize-controls.min.js
vendored
Normal file
2
wp-admin/js/customize-controls.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3442
wp-admin/js/customize-nav-menus.js
Normal file
3442
wp-admin/js/customize-nav-menus.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/customize-nav-menus.min.js
vendored
Normal file
2
wp-admin/js/customize-nav-menus.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2372
wp-admin/js/customize-widgets.js
Normal file
2372
wp-admin/js/customize-widgets.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/customize-widgets.min.js
vendored
Normal file
2
wp-admin/js/customize-widgets.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
839
wp-admin/js/dashboard.js
Normal file
839
wp-admin/js/dashboard.js
Normal file
@ -0,0 +1,839 @@
|
||||
/**
|
||||
* @output wp-admin/js/dashboard.js
|
||||
*/
|
||||
|
||||
/* global pagenow, ajaxurl, postboxes, wpActiveEditor:true, ajaxWidgets */
|
||||
/* global ajaxPopulateWidgets, quickPressLoad, */
|
||||
window.wp = window.wp || {};
|
||||
window.communityEventsData = window.communityEventsData || {};
|
||||
|
||||
/**
|
||||
* Initializes the dashboard widget functionality.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
jQuery( function($) {
|
||||
var welcomePanel = $( '#welcome-panel' ),
|
||||
welcomePanelHide = $('#wp_welcome_panel-hide'),
|
||||
updateWelcomePanel;
|
||||
|
||||
/**
|
||||
* Saves the visibility of the welcome panel.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @param {boolean} visible Should it be visible or not.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
updateWelcomePanel = function( visible ) {
|
||||
$.post( ajaxurl, {
|
||||
action: 'update-welcome-panel',
|
||||
visible: visible,
|
||||
welcomepanelnonce: $( '#welcomepanelnonce' ).val()
|
||||
});
|
||||
};
|
||||
|
||||
// Unhide the welcome panel if the Welcome Option checkbox is checked.
|
||||
if ( welcomePanel.hasClass('hidden') && welcomePanelHide.prop('checked') ) {
|
||||
welcomePanel.removeClass('hidden');
|
||||
}
|
||||
|
||||
// Hide the welcome panel when the dismiss button or close button is clicked.
|
||||
$('.welcome-panel-close, .welcome-panel-dismiss a', welcomePanel).on( 'click', function(e) {
|
||||
e.preventDefault();
|
||||
welcomePanel.addClass('hidden');
|
||||
updateWelcomePanel( 0 );
|
||||
$('#wp_welcome_panel-hide').prop('checked', false);
|
||||
});
|
||||
|
||||
// Set welcome panel visibility based on Welcome Option checkbox value.
|
||||
welcomePanelHide.on( 'click', function() {
|
||||
welcomePanel.toggleClass('hidden', ! this.checked );
|
||||
updateWelcomePanel( this.checked ? 1 : 0 );
|
||||
});
|
||||
|
||||
/**
|
||||
* These widgets can be populated via ajax.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @type {string[]}
|
||||
*
|
||||
* @global
|
||||
*/
|
||||
window.ajaxWidgets = ['dashboard_primary'];
|
||||
|
||||
/**
|
||||
* Triggers widget updates via Ajax.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @param {string} el Optional. Widget to fetch or none to update all.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
window.ajaxPopulateWidgets = function(el) {
|
||||
/**
|
||||
* Fetch the latest representation of the widget via Ajax and show it.
|
||||
*
|
||||
* @param {number} i Number of half-seconds to use as the timeout.
|
||||
* @param {string} id ID of the element which is going to be checked for changes.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function show(i, id) {
|
||||
var p, e = $('#' + id + ' div.inside:visible').find('.widget-loading');
|
||||
// If the element is found in the dom, queue to load latest representation.
|
||||
if ( e.length ) {
|
||||
p = e.parent();
|
||||
setTimeout( function(){
|
||||
// Request the widget content.
|
||||
p.load( ajaxurl + '?action=dashboard-widgets&widget=' + id + '&pagenow=' + pagenow, '', function() {
|
||||
// Hide the parent and slide it out for visual fancyness.
|
||||
p.hide().slideDown('normal', function(){
|
||||
$(this).css('display', '');
|
||||
});
|
||||
});
|
||||
}, i * 500 );
|
||||
}
|
||||
}
|
||||
|
||||
// If we have received a specific element to fetch, check if it is valid.
|
||||
if ( el ) {
|
||||
el = el.toString();
|
||||
// If the element is available as Ajax widget, show it.
|
||||
if ( $.inArray(el, ajaxWidgets) !== -1 ) {
|
||||
// Show element without any delay.
|
||||
show(0, el);
|
||||
}
|
||||
} else {
|
||||
// Walk through all ajaxWidgets, loading them after each other.
|
||||
$.each( ajaxWidgets, show );
|
||||
}
|
||||
};
|
||||
|
||||
// Initially populate ajax widgets.
|
||||
ajaxPopulateWidgets();
|
||||
|
||||
// Register ajax widgets as postbox toggles.
|
||||
postboxes.add_postbox_toggles(pagenow, { pbshow: ajaxPopulateWidgets } );
|
||||
|
||||
/**
|
||||
* Control the Quick Press (Quick Draft) widget.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
window.quickPressLoad = function() {
|
||||
var act = $('#quickpost-action'), t;
|
||||
|
||||
// Enable the submit buttons.
|
||||
$( '#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]' ).prop( 'disabled' , false );
|
||||
|
||||
t = $('#quick-press').on( 'submit', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
// Show a spinner.
|
||||
$('#dashboard_quick_press #publishing-action .spinner').show();
|
||||
|
||||
// Disable the submit button to prevent duplicate submissions.
|
||||
$('#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]').prop('disabled', true);
|
||||
|
||||
// Post the entered data to save it.
|
||||
$.post( t.attr( 'action' ), t.serializeArray(), function( data ) {
|
||||
// Replace the form, and prepend the published post.
|
||||
$('#dashboard_quick_press .inside').html( data );
|
||||
$('#quick-press').removeClass('initial-form');
|
||||
quickPressLoad();
|
||||
highlightLatestPost();
|
||||
|
||||
// Focus the title to allow for quickly drafting another post.
|
||||
$('#title').trigger( 'focus' );
|
||||
});
|
||||
|
||||
/**
|
||||
* Highlights the latest post for one second.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function highlightLatestPost () {
|
||||
var latestPost = $('.drafts ul li').first();
|
||||
latestPost.css('background', '#fffbe5');
|
||||
setTimeout(function () {
|
||||
latestPost.css('background', 'none');
|
||||
}, 1000);
|
||||
}
|
||||
} );
|
||||
|
||||
// Change the QuickPost action to the publish value.
|
||||
$('#publish').on( 'click', function() { act.val( 'post-quickpress-publish' ); } );
|
||||
|
||||
$('#quick-press').on( 'click focusin', function() {
|
||||
wpActiveEditor = 'content';
|
||||
});
|
||||
|
||||
autoResizeTextarea();
|
||||
};
|
||||
window.quickPressLoad();
|
||||
|
||||
// Enable the dragging functionality of the widgets.
|
||||
$( '.meta-box-sortables' ).sortable( 'option', 'containment', '#wpwrap' );
|
||||
|
||||
/**
|
||||
* Adjust the height of the textarea based on the content.
|
||||
*
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function autoResizeTextarea() {
|
||||
// When IE8 or older is used to render this document, exit.
|
||||
if ( document.documentMode && document.documentMode < 9 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a hidden div. We'll copy over the text from the textarea to measure its height.
|
||||
$('body').append( '<div class="quick-draft-textarea-clone" style="display: none;"></div>' );
|
||||
|
||||
var clone = $('.quick-draft-textarea-clone'),
|
||||
editor = $('#content'),
|
||||
editorHeight = editor.height(),
|
||||
/*
|
||||
* 100px roughly accounts for browser chrome and allows the
|
||||
* save draft button to show on-screen at the same time.
|
||||
*/
|
||||
editorMaxHeight = $(window).height() - 100;
|
||||
|
||||
/*
|
||||
* Match up textarea and clone div as much as possible.
|
||||
* Padding cannot be reliably retrieved using shorthand in all browsers.
|
||||
*/
|
||||
clone.css({
|
||||
'font-family': editor.css('font-family'),
|
||||
'font-size': editor.css('font-size'),
|
||||
'line-height': editor.css('line-height'),
|
||||
'padding-bottom': editor.css('paddingBottom'),
|
||||
'padding-left': editor.css('paddingLeft'),
|
||||
'padding-right': editor.css('paddingRight'),
|
||||
'padding-top': editor.css('paddingTop'),
|
||||
'white-space': 'pre-wrap',
|
||||
'word-wrap': 'break-word',
|
||||
'display': 'none'
|
||||
});
|
||||
|
||||
// The 'propertychange' is used in IE < 9.
|
||||
editor.on('focus input propertychange', function() {
|
||||
var $this = $(this),
|
||||
// Add a non-breaking space to ensure that the height of a trailing newline is
|
||||
// included.
|
||||
textareaContent = $this.val() + ' ',
|
||||
// Add 2px to compensate for border-top & border-bottom.
|
||||
cloneHeight = clone.css('width', $this.css('width')).text(textareaContent).outerHeight() + 2;
|
||||
|
||||
// Default to show a vertical scrollbar, if needed.
|
||||
editor.css('overflow-y', 'auto');
|
||||
|
||||
// Only change the height if it has changed and both heights are below the max.
|
||||
if ( cloneHeight === editorHeight || ( cloneHeight >= editorMaxHeight && editorHeight >= editorMaxHeight ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't allow editor to exceed the height of the window.
|
||||
* This is also bound in CSS to a max-height of 1300px to be extra safe.
|
||||
*/
|
||||
if ( cloneHeight > editorMaxHeight ) {
|
||||
editorHeight = editorMaxHeight;
|
||||
} else {
|
||||
editorHeight = cloneHeight;
|
||||
}
|
||||
|
||||
// Disable scrollbars because we adjust the height to the content.
|
||||
editor.css('overflow', 'hidden');
|
||||
|
||||
$this.css('height', editorHeight + 'px');
|
||||
});
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
jQuery( function( $ ) {
|
||||
'use strict';
|
||||
|
||||
var communityEventsData = window.communityEventsData,
|
||||
dateI18n = wp.date.dateI18n,
|
||||
format = wp.date.format,
|
||||
sprintf = wp.i18n.sprintf,
|
||||
__ = wp.i18n.__,
|
||||
_x = wp.i18n._x,
|
||||
app;
|
||||
|
||||
/**
|
||||
* Global Community Events namespace.
|
||||
*
|
||||
* @since 4.8.0
|
||||
*
|
||||
* @memberOf wp
|
||||
* @namespace wp.communityEvents
|
||||
*/
|
||||
app = window.wp.communityEvents = /** @lends wp.communityEvents */{
|
||||
initialized: false,
|
||||
model: null,
|
||||
|
||||
/**
|
||||
* Initializes the wp.communityEvents object.
|
||||
*
|
||||
* @since 4.8.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
init: function() {
|
||||
if ( app.initialized ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $container = $( '#community-events' );
|
||||
|
||||
/*
|
||||
* When JavaScript is disabled, the errors container is shown, so
|
||||
* that "This widget requires JavaScript" message can be seen.
|
||||
*
|
||||
* When JS is enabled, the container is hidden at first, and then
|
||||
* revealed during the template rendering, if there actually are
|
||||
* errors to show.
|
||||
*
|
||||
* The display indicator switches from `hide-if-js` to `aria-hidden`
|
||||
* here in order to maintain consistency with all the other fields
|
||||
* that key off of `aria-hidden` to determine their visibility.
|
||||
* `aria-hidden` can't be used initially, because there would be no
|
||||
* way to set it to false when JavaScript is disabled, which would
|
||||
* prevent people from seeing the "This widget requires JavaScript"
|
||||
* message.
|
||||
*/
|
||||
$( '.community-events-errors' )
|
||||
.attr( 'aria-hidden', 'true' )
|
||||
.removeClass( 'hide-if-js' );
|
||||
|
||||
$container.on( 'click', '.community-events-toggle-location, .community-events-cancel', app.toggleLocationForm );
|
||||
|
||||
/**
|
||||
* Filters events based on entered location.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$container.on( 'submit', '.community-events-form', function( event ) {
|
||||
var location = $( '#community-events-location' ).val().trim();
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
/*
|
||||
* Don't trigger a search if the search field is empty or the
|
||||
* search term was made of only spaces before being trimmed.
|
||||
*/
|
||||
if ( ! location ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.getEvents({
|
||||
location: location
|
||||
});
|
||||
});
|
||||
|
||||
if ( communityEventsData && communityEventsData.cache && communityEventsData.cache.location && communityEventsData.cache.events ) {
|
||||
app.renderEventsTemplate( communityEventsData.cache, 'app' );
|
||||
} else {
|
||||
app.getEvents();
|
||||
}
|
||||
|
||||
app.initialized = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the visibility of the Edit Location form.
|
||||
*
|
||||
* @since 4.8.0
|
||||
*
|
||||
* @param {event|string} action 'show' or 'hide' to specify a state;
|
||||
* or an event object to flip between states.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
toggleLocationForm: function( action ) {
|
||||
var $toggleButton = $( '.community-events-toggle-location' ),
|
||||
$cancelButton = $( '.community-events-cancel' ),
|
||||
$form = $( '.community-events-form' ),
|
||||
$target = $();
|
||||
|
||||
if ( 'object' === typeof action ) {
|
||||
// The action is the event object: get the clicked element.
|
||||
$target = $( action.target );
|
||||
/*
|
||||
* Strict comparison doesn't work in this case because sometimes
|
||||
* we explicitly pass a string as value of aria-expanded and
|
||||
* sometimes a boolean as the result of an evaluation.
|
||||
*/
|
||||
action = 'true' == $toggleButton.attr( 'aria-expanded' ) ? 'hide' : 'show';
|
||||
}
|
||||
|
||||
if ( 'hide' === action ) {
|
||||
$toggleButton.attr( 'aria-expanded', 'false' );
|
||||
$cancelButton.attr( 'aria-expanded', 'false' );
|
||||
$form.attr( 'aria-hidden', 'true' );
|
||||
/*
|
||||
* If the Cancel button has been clicked, bring the focus back
|
||||
* to the toggle button so users relying on screen readers don't
|
||||
* lose their place.
|
||||
*/
|
||||
if ( $target.hasClass( 'community-events-cancel' ) ) {
|
||||
$toggleButton.trigger( 'focus' );
|
||||
}
|
||||
} else {
|
||||
$toggleButton.attr( 'aria-expanded', 'true' );
|
||||
$cancelButton.attr( 'aria-expanded', 'true' );
|
||||
$form.attr( 'aria-hidden', 'false' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends REST API requests to fetch events for the widget.
|
||||
*
|
||||
* @since 4.8.0
|
||||
*
|
||||
* @param {Object} requestParams REST API Request parameters object.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
getEvents: function( requestParams ) {
|
||||
var initiatedBy,
|
||||
app = this,
|
||||
$spinner = $( '.community-events-form' ).children( '.spinner' );
|
||||
|
||||
requestParams = requestParams || {};
|
||||
requestParams._wpnonce = communityEventsData.nonce;
|
||||
requestParams.timezone = window.Intl ? window.Intl.DateTimeFormat().resolvedOptions().timeZone : '';
|
||||
|
||||
initiatedBy = requestParams.location ? 'user' : 'app';
|
||||
|
||||
$spinner.addClass( 'is-active' );
|
||||
|
||||
wp.ajax.post( 'get-community-events', requestParams )
|
||||
.always( function() {
|
||||
$spinner.removeClass( 'is-active' );
|
||||
})
|
||||
|
||||
.done( function( response ) {
|
||||
if ( 'no_location_available' === response.error ) {
|
||||
if ( requestParams.location ) {
|
||||
response.unknownCity = requestParams.location;
|
||||
} else {
|
||||
/*
|
||||
* No location was passed, which means that this was an automatic query
|
||||
* based on IP, locale, and timezone. Since the user didn't initiate it,
|
||||
* it should fail silently. Otherwise, the error could confuse and/or
|
||||
* annoy them.
|
||||
*/
|
||||
delete response.error;
|
||||
}
|
||||
}
|
||||
app.renderEventsTemplate( response, initiatedBy );
|
||||
})
|
||||
|
||||
.fail( function() {
|
||||
app.renderEventsTemplate({
|
||||
'location' : false,
|
||||
'events' : [],
|
||||
'error' : true
|
||||
}, initiatedBy );
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the template for the Events section of the Events & News widget.
|
||||
*
|
||||
* @since 4.8.0
|
||||
*
|
||||
* @param {Object} templateParams The various parameters that will get passed to wp.template.
|
||||
* @param {string} initiatedBy 'user' to indicate that this was triggered manually by the user;
|
||||
* 'app' to indicate it was triggered automatically by the app itself.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
renderEventsTemplate: function( templateParams, initiatedBy ) {
|
||||
var template,
|
||||
elementVisibility,
|
||||
$toggleButton = $( '.community-events-toggle-location' ),
|
||||
$locationMessage = $( '#community-events-location-message' ),
|
||||
$results = $( '.community-events-results' );
|
||||
|
||||
templateParams.events = app.populateDynamicEventFields(
|
||||
templateParams.events,
|
||||
communityEventsData.time_format
|
||||
);
|
||||
|
||||
/*
|
||||
* Hide all toggleable elements by default, to keep the logic simple.
|
||||
* Otherwise, each block below would have to turn hide everything that
|
||||
* could have been shown at an earlier point.
|
||||
*
|
||||
* The exception to that is that the .community-events container is hidden
|
||||
* when the page is first loaded, because the content isn't ready yet,
|
||||
* but once we've reached this point, it should always be shown.
|
||||
*/
|
||||
elementVisibility = {
|
||||
'.community-events' : true,
|
||||
'.community-events-loading' : false,
|
||||
'.community-events-errors' : false,
|
||||
'.community-events-error-occurred' : false,
|
||||
'.community-events-could-not-locate' : false,
|
||||
'#community-events-location-message' : false,
|
||||
'.community-events-toggle-location' : false,
|
||||
'.community-events-results' : false
|
||||
};
|
||||
|
||||
/*
|
||||
* Determine which templates should be rendered and which elements
|
||||
* should be displayed.
|
||||
*/
|
||||
if ( templateParams.location.ip ) {
|
||||
/*
|
||||
* If the API determined the location by geolocating an IP, it will
|
||||
* provide events, but not a specific location.
|
||||
*/
|
||||
$locationMessage.text( __( 'Attend an upcoming event near you.' ) );
|
||||
|
||||
if ( templateParams.events.length ) {
|
||||
template = wp.template( 'community-events-event-list' );
|
||||
$results.html( template( templateParams ) );
|
||||
} else {
|
||||
template = wp.template( 'community-events-no-upcoming-events' );
|
||||
$results.html( template( templateParams ) );
|
||||
}
|
||||
|
||||
elementVisibility['#community-events-location-message'] = true;
|
||||
elementVisibility['.community-events-toggle-location'] = true;
|
||||
elementVisibility['.community-events-results'] = true;
|
||||
|
||||
} else if ( templateParams.location.description ) {
|
||||
template = wp.template( 'community-events-attend-event-near' );
|
||||
$locationMessage.html( template( templateParams ) );
|
||||
|
||||
if ( templateParams.events.length ) {
|
||||
template = wp.template( 'community-events-event-list' );
|
||||
$results.html( template( templateParams ) );
|
||||
} else {
|
||||
template = wp.template( 'community-events-no-upcoming-events' );
|
||||
$results.html( template( templateParams ) );
|
||||
}
|
||||
|
||||
if ( 'user' === initiatedBy ) {
|
||||
wp.a11y.speak(
|
||||
sprintf(
|
||||
/* translators: %s: The name of a city. */
|
||||
__( 'City updated. Listing events near %s.' ),
|
||||
templateParams.location.description
|
||||
),
|
||||
'assertive'
|
||||
);
|
||||
}
|
||||
|
||||
elementVisibility['#community-events-location-message'] = true;
|
||||
elementVisibility['.community-events-toggle-location'] = true;
|
||||
elementVisibility['.community-events-results'] = true;
|
||||
|
||||
} else if ( templateParams.unknownCity ) {
|
||||
template = wp.template( 'community-events-could-not-locate' );
|
||||
$( '.community-events-could-not-locate' ).html( template( templateParams ) );
|
||||
wp.a11y.speak(
|
||||
sprintf(
|
||||
/*
|
||||
* These specific examples were chosen to highlight the fact that a
|
||||
* state is not needed, even for cities whose name is not unique.
|
||||
* It would be too cumbersome to include that in the instructions
|
||||
* to the user, so it's left as an implication.
|
||||
*/
|
||||
/*
|
||||
* translators: %s is the name of the city we couldn't locate.
|
||||
* Replace the examples with cities related to your locale. Test that
|
||||
* they match the expected location and have upcoming events before
|
||||
* including them. If no cities related to your locale have events,
|
||||
* then use cities related to your locale that would be recognizable
|
||||
* to most users. Use only the city name itself, without any region
|
||||
* or country. Use the endonym (native locale name) instead of the
|
||||
* English name if possible.
|
||||
*/
|
||||
__( 'We couldn’t locate %s. Please try another nearby city. For example: Kansas City; Springfield; Portland.' ),
|
||||
templateParams.unknownCity
|
||||
)
|
||||
);
|
||||
|
||||
elementVisibility['.community-events-errors'] = true;
|
||||
elementVisibility['.community-events-could-not-locate'] = true;
|
||||
|
||||
} else if ( templateParams.error && 'user' === initiatedBy ) {
|
||||
/*
|
||||
* Errors messages are only shown for requests that were initiated
|
||||
* by the user, not for ones that were initiated by the app itself.
|
||||
* Showing error messages for an event that user isn't aware of
|
||||
* could be confusing or unnecessarily distracting.
|
||||
*/
|
||||
wp.a11y.speak( __( 'An error occurred. Please try again.' ) );
|
||||
|
||||
elementVisibility['.community-events-errors'] = true;
|
||||
elementVisibility['.community-events-error-occurred'] = true;
|
||||
} else {
|
||||
$locationMessage.text( __( 'Enter your closest city to find nearby events.' ) );
|
||||
|
||||
elementVisibility['#community-events-location-message'] = true;
|
||||
elementVisibility['.community-events-toggle-location'] = true;
|
||||
}
|
||||
|
||||
// Set the visibility of toggleable elements.
|
||||
_.each( elementVisibility, function( isVisible, element ) {
|
||||
$( element ).attr( 'aria-hidden', ! isVisible );
|
||||
});
|
||||
|
||||
$toggleButton.attr( 'aria-expanded', elementVisibility['.community-events-toggle-location'] );
|
||||
|
||||
if ( templateParams.location && ( templateParams.location.ip || templateParams.location.latitude ) ) {
|
||||
// Hide the form when there's a valid location.
|
||||
app.toggleLocationForm( 'hide' );
|
||||
|
||||
if ( 'user' === initiatedBy ) {
|
||||
/*
|
||||
* When the form is programmatically hidden after a user search,
|
||||
* bring the focus back to the toggle button so users relying
|
||||
* on screen readers don't lose their place.
|
||||
*/
|
||||
$toggleButton.trigger( 'focus' );
|
||||
}
|
||||
} else {
|
||||
app.toggleLocationForm( 'show' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Populate event fields that have to be calculated on the fly.
|
||||
*
|
||||
* These can't be stored in the database, because they're dependent on
|
||||
* the user's current time zone, locale, etc.
|
||||
*
|
||||
* @since 5.5.2
|
||||
*
|
||||
* @param {Array} rawEvents The events that should have dynamic fields added to them.
|
||||
* @param {string} timeFormat A time format acceptable by `wp.date.dateI18n()`.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
populateDynamicEventFields: function( rawEvents, timeFormat ) {
|
||||
// Clone the parameter to avoid mutating it, so that this can remain a pure function.
|
||||
var populatedEvents = JSON.parse( JSON.stringify( rawEvents ) );
|
||||
|
||||
$.each( populatedEvents, function( index, event ) {
|
||||
var timeZone = app.getTimeZone( event.start_unix_timestamp * 1000 );
|
||||
|
||||
event.user_formatted_date = app.getFormattedDate(
|
||||
event.start_unix_timestamp * 1000,
|
||||
event.end_unix_timestamp * 1000,
|
||||
timeZone
|
||||
);
|
||||
|
||||
event.user_formatted_time = dateI18n(
|
||||
timeFormat,
|
||||
event.start_unix_timestamp * 1000,
|
||||
timeZone
|
||||
);
|
||||
|
||||
event.timeZoneAbbreviation = app.getTimeZoneAbbreviation( event.start_unix_timestamp * 1000 );
|
||||
} );
|
||||
|
||||
return populatedEvents;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the user's local/browser time zone, in a form suitable for `wp.date.i18n()`.
|
||||
*
|
||||
* @since 5.5.2
|
||||
*
|
||||
* @param startTimestamp
|
||||
*
|
||||
* @returns {string|number}
|
||||
*/
|
||||
getTimeZone: function( startTimestamp ) {
|
||||
/*
|
||||
* Prefer a name like `Europe/Helsinki`, since that automatically tracks daylight savings. This
|
||||
* doesn't need to take `startTimestamp` into account for that reason.
|
||||
*/
|
||||
var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
/*
|
||||
* Fall back to an offset for IE11, which declares the property but doesn't assign a value.
|
||||
*/
|
||||
if ( 'undefined' === typeof timeZone ) {
|
||||
/*
|
||||
* It's important to use the _event_ time, not the _current_
|
||||
* time, so that daylight savings time is accounted for.
|
||||
*/
|
||||
timeZone = app.getFlippedTimeZoneOffset( startTimestamp );
|
||||
}
|
||||
|
||||
return timeZone;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get intuitive time zone offset.
|
||||
*
|
||||
* `Data.prototype.getTimezoneOffset()` returns a positive value for time zones
|
||||
* that are _behind_ UTC, and a _negative_ value for ones that are ahead.
|
||||
*
|
||||
* See https://stackoverflow.com/questions/21102435/why-does-javascript-date-gettimezoneoffset-consider-0500-as-a-positive-off.
|
||||
*
|
||||
* @since 5.5.2
|
||||
*
|
||||
* @param {number} startTimestamp
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getFlippedTimeZoneOffset: function( startTimestamp ) {
|
||||
return new Date( startTimestamp ).getTimezoneOffset() * -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a short time zone name, like `PST`.
|
||||
*
|
||||
* @since 5.5.2
|
||||
*
|
||||
* @param {number} startTimestamp
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getTimeZoneAbbreviation: function( startTimestamp ) {
|
||||
var timeZoneAbbreviation,
|
||||
eventDateTime = new Date( startTimestamp );
|
||||
|
||||
/*
|
||||
* Leaving the `locales` argument undefined is important, so that the browser
|
||||
* displays the abbreviation that's most appropriate for the current locale. For
|
||||
* some that will be `UTC{+|-}{n}`, and for others it will be a code like `PST`.
|
||||
*
|
||||
* This doesn't need to take `startTimestamp` into account, because a name like
|
||||
* `America/Chicago` automatically tracks daylight savings.
|
||||
*/
|
||||
var shortTimeStringParts = eventDateTime.toLocaleTimeString( undefined, { timeZoneName : 'short' } ).split( ' ' );
|
||||
|
||||
if ( 3 === shortTimeStringParts.length ) {
|
||||
timeZoneAbbreviation = shortTimeStringParts[2];
|
||||
}
|
||||
|
||||
if ( 'undefined' === typeof timeZoneAbbreviation ) {
|
||||
/*
|
||||
* It's important to use the _event_ time, not the _current_
|
||||
* time, so that daylight savings time is accounted for.
|
||||
*/
|
||||
var timeZoneOffset = app.getFlippedTimeZoneOffset( startTimestamp ),
|
||||
sign = -1 === Math.sign( timeZoneOffset ) ? '' : '+';
|
||||
|
||||
// translators: Used as part of a string like `GMT+5` in the Events Widget.
|
||||
timeZoneAbbreviation = _x( 'GMT', 'Events widget offset prefix' ) + sign + ( timeZoneOffset / 60 );
|
||||
}
|
||||
|
||||
return timeZoneAbbreviation;
|
||||
},
|
||||
|
||||
/**
|
||||
* Format a start/end date in the user's local time zone and locale.
|
||||
*
|
||||
* @since 5.5.2
|
||||
*
|
||||
* @param {int} startDate The Unix timestamp in milliseconds when the the event starts.
|
||||
* @param {int} endDate The Unix timestamp in milliseconds when the the event ends.
|
||||
* @param {string} timeZone A time zone string or offset which is parsable by `wp.date.i18n()`.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getFormattedDate: function( startDate, endDate, timeZone ) {
|
||||
var formattedDate;
|
||||
|
||||
/*
|
||||
* The `date_format` option is not used because it's important
|
||||
* in this context to keep the day of the week in the displayed date,
|
||||
* so that users can tell at a glance if the event is on a day they
|
||||
* are available, without having to open the link.
|
||||
*
|
||||
* The case of crossing a year boundary is intentionally not handled.
|
||||
* It's so rare in practice that it's not worth the complexity
|
||||
* tradeoff. The _ending_ year should be passed to
|
||||
* `multiple_month_event`, though, just in case.
|
||||
*/
|
||||
/* translators: Date format for upcoming events on the dashboard. Include the day of the week. See https://www.php.net/manual/datetime.format.php */
|
||||
var singleDayEvent = __( 'l, M j, Y' ),
|
||||
/* translators: Date string for upcoming events. 1: Month, 2: Starting day, 3: Ending day, 4: Year. */
|
||||
multipleDayEvent = __( '%1$s %2$d–%3$d, %4$d' ),
|
||||
/* translators: Date string for upcoming events. 1: Starting month, 2: Starting day, 3: Ending month, 4: Ending day, 5: Ending year. */
|
||||
multipleMonthEvent = __( '%1$s %2$d – %3$s %4$d, %5$d' );
|
||||
|
||||
// Detect single-day events.
|
||||
if ( ! endDate || format( 'Y-m-d', startDate ) === format( 'Y-m-d', endDate ) ) {
|
||||
formattedDate = dateI18n( singleDayEvent, startDate, timeZone );
|
||||
|
||||
// Multiple day events.
|
||||
} else if ( format( 'Y-m', startDate ) === format( 'Y-m', endDate ) ) {
|
||||
formattedDate = sprintf(
|
||||
multipleDayEvent,
|
||||
dateI18n( _x( 'F', 'upcoming events month format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), endDate, timeZone ),
|
||||
dateI18n( _x( 'Y', 'upcoming events year format' ), endDate, timeZone )
|
||||
);
|
||||
|
||||
// Multi-day events that cross a month boundary.
|
||||
} else {
|
||||
formattedDate = sprintf(
|
||||
multipleMonthEvent,
|
||||
dateI18n( _x( 'F', 'upcoming events month format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'F', 'upcoming events month format' ), endDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), endDate, timeZone ),
|
||||
dateI18n( _x( 'Y', 'upcoming events year format' ), endDate, timeZone )
|
||||
);
|
||||
}
|
||||
|
||||
return formattedDate;
|
||||
}
|
||||
};
|
||||
|
||||
if ( $( '#dashboard_primary' ).is( ':visible' ) ) {
|
||||
app.init();
|
||||
} else {
|
||||
$( document ).on( 'postbox-toggled', function( event, postbox ) {
|
||||
var $postbox = $( postbox );
|
||||
|
||||
if ( 'dashboard_primary' === $postbox.attr( 'id' ) && $postbox.is( ':visible' ) ) {
|
||||
app.init();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Removed in 5.6.0, needed for back-compatibility.
|
||||
*
|
||||
* @since 4.8.0
|
||||
* @deprecated 5.6.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
window.communityEventsData.l10n = window.communityEventsData.l10n || {
|
||||
enter_closest_city: '',
|
||||
error_occurred_please_try_again: '',
|
||||
attend_event_near_generic: '',
|
||||
could_not_locate_city: '',
|
||||
city_updated: ''
|
||||
};
|
||||
|
||||
window.communityEventsData.l10n = window.wp.deprecateL10nObject( 'communityEventsData.l10n', window.communityEventsData.l10n, '5.6.0' );
|
2
wp-admin/js/dashboard.min.js
vendored
Normal file
2
wp-admin/js/dashboard.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1356
wp-admin/js/edit-comments.js
Normal file
1356
wp-admin/js/edit-comments.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/edit-comments.min.js
vendored
Normal file
2
wp-admin/js/edit-comments.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1617
wp-admin/js/editor-expand.js
Normal file
1617
wp-admin/js/editor-expand.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/editor-expand.min.js
vendored
Normal file
2
wp-admin/js/editor-expand.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1416
wp-admin/js/editor.js
Normal file
1416
wp-admin/js/editor.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/editor.min.js
vendored
Normal file
2
wp-admin/js/editor.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
282
wp-admin/js/farbtastic.js
Normal file
282
wp-admin/js/farbtastic.js
Normal file
@ -0,0 +1,282 @@
|
||||
/*!
|
||||
* Farbtastic: jQuery color picker plug-in v1.3u
|
||||
* https://github.com/mattfarina/farbtastic
|
||||
*
|
||||
* Licensed under the GPL license:
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
/**
|
||||
* Modified for WordPress: replaced deprecated jQuery methods.
|
||||
* See https://core.trac.wordpress.org/ticket/57946.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.fn.farbtastic = function (options) {
|
||||
$.farbtastic(this, options);
|
||||
return this;
|
||||
};
|
||||
|
||||
$.farbtastic = function (container, callback) {
|
||||
var container = $(container).get(0);
|
||||
return container.farbtastic || (container.farbtastic = new $._farbtastic(container, callback));
|
||||
};
|
||||
|
||||
$._farbtastic = function (container, callback) {
|
||||
// Store farbtastic object
|
||||
var fb = this;
|
||||
|
||||
// Insert markup
|
||||
$(container).html('<div class="farbtastic"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>');
|
||||
var e = $('.farbtastic', container);
|
||||
fb.wheel = $('.wheel', container).get(0);
|
||||
// Dimensions
|
||||
fb.radius = 84;
|
||||
fb.square = 100;
|
||||
fb.width = 194;
|
||||
|
||||
// Fix background PNGs in IE6
|
||||
if (navigator.appVersion.match(/MSIE [0-6]\./)) {
|
||||
$('*', e).each(function () {
|
||||
if (this.currentStyle.backgroundImage != 'none') {
|
||||
var image = this.currentStyle.backgroundImage;
|
||||
image = this.currentStyle.backgroundImage.substring(5, image.length - 2);
|
||||
$(this).css({
|
||||
'backgroundImage': 'none',
|
||||
'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to the given element(s) or callback.
|
||||
*/
|
||||
fb.linkTo = function (callback) {
|
||||
// Unbind previous nodes
|
||||
if (typeof fb.callback == 'object') {
|
||||
$(fb.callback).off('keyup', fb.updateValue);
|
||||
}
|
||||
|
||||
// Reset color
|
||||
fb.color = null;
|
||||
|
||||
// Bind callback or elements
|
||||
if (typeof callback == 'function') {
|
||||
fb.callback = callback;
|
||||
}
|
||||
else if (typeof callback == 'object' || typeof callback == 'string') {
|
||||
fb.callback = $(callback);
|
||||
fb.callback.on('keyup', fb.updateValue);
|
||||
if (fb.callback.get(0).value) {
|
||||
fb.setColor(fb.callback.get(0).value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
fb.updateValue = function (event) {
|
||||
if (this.value && this.value != fb.color) {
|
||||
fb.setColor(this.value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Change color with HTML syntax #123456
|
||||
*/
|
||||
fb.setColor = function (color) {
|
||||
var unpack = fb.unpack(color);
|
||||
if (fb.color != color && unpack) {
|
||||
fb.color = color;
|
||||
fb.rgb = unpack;
|
||||
fb.hsl = fb.RGBToHSL(fb.rgb);
|
||||
fb.updateDisplay();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Change color with HSL triplet [0..1, 0..1, 0..1]
|
||||
*/
|
||||
fb.setHSL = function (hsl) {
|
||||
fb.hsl = hsl;
|
||||
fb.rgb = fb.HSLToRGB(hsl);
|
||||
fb.color = fb.pack(fb.rgb);
|
||||
fb.updateDisplay();
|
||||
return this;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Retrieve the coordinates of the given event relative to the center
|
||||
* of the widget.
|
||||
*/
|
||||
fb.widgetCoords = function (event) {
|
||||
var offset = $(fb.wheel).offset();
|
||||
return { x: (event.pageX - offset.left) - fb.width / 2, y: (event.pageY - offset.top) - fb.width / 2 };
|
||||
};
|
||||
|
||||
/**
|
||||
* Mousedown handler
|
||||
*/
|
||||
fb.mousedown = function (event) {
|
||||
// Capture mouse
|
||||
if (!document.dragging) {
|
||||
$(document).on('mousemove', fb.mousemove).on('mouseup', fb.mouseup);
|
||||
document.dragging = true;
|
||||
}
|
||||
|
||||
// Check which area is being dragged
|
||||
var pos = fb.widgetCoords(event);
|
||||
fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;
|
||||
|
||||
// Process
|
||||
fb.mousemove(event);
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mousemove handler
|
||||
*/
|
||||
fb.mousemove = function (event) {
|
||||
// Get coordinates relative to color picker center
|
||||
var pos = fb.widgetCoords(event);
|
||||
|
||||
// Set new HSL parameters
|
||||
if (fb.circleDrag) {
|
||||
var hue = Math.atan2(pos.x, -pos.y) / 6.28;
|
||||
if (hue < 0) hue += 1;
|
||||
fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);
|
||||
}
|
||||
else {
|
||||
var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));
|
||||
var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));
|
||||
fb.setHSL([fb.hsl[0], sat, lum]);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mouseup handler
|
||||
*/
|
||||
fb.mouseup = function () {
|
||||
// Uncapture mouse
|
||||
$(document).off('mousemove', fb.mousemove);
|
||||
$(document).off('mouseup', fb.mouseup);
|
||||
document.dragging = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the markers and styles
|
||||
*/
|
||||
fb.updateDisplay = function () {
|
||||
// Markers
|
||||
var angle = fb.hsl[0] * 6.28;
|
||||
$('.h-marker', e).css({
|
||||
left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',
|
||||
top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'
|
||||
});
|
||||
|
||||
$('.sl-marker', e).css({
|
||||
left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',
|
||||
top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'
|
||||
});
|
||||
|
||||
// Saturation/Luminance gradient
|
||||
$('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));
|
||||
|
||||
// Linked elements or callback
|
||||
if (typeof fb.callback == 'object') {
|
||||
// Set background/foreground color
|
||||
$(fb.callback).css({
|
||||
backgroundColor: fb.color,
|
||||
color: fb.hsl[2] > 0.5 ? '#000' : '#fff'
|
||||
});
|
||||
|
||||
// Change linked value
|
||||
$(fb.callback).each(function() {
|
||||
if (this.value && this.value != fb.color) {
|
||||
this.value = fb.color;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (typeof fb.callback == 'function') {
|
||||
fb.callback.call(fb, fb.color);
|
||||
}
|
||||
};
|
||||
|
||||
/* Various color utility functions */
|
||||
fb.pack = function (rgb) {
|
||||
var r = Math.round(rgb[0] * 255);
|
||||
var g = Math.round(rgb[1] * 255);
|
||||
var b = Math.round(rgb[2] * 255);
|
||||
return '#' + (r < 16 ? '0' : '') + r.toString(16) +
|
||||
(g < 16 ? '0' : '') + g.toString(16) +
|
||||
(b < 16 ? '0' : '') + b.toString(16);
|
||||
};
|
||||
|
||||
fb.unpack = function (color) {
|
||||
if (color.length == 7) {
|
||||
return [parseInt('0x' + color.substring(1, 3)) / 255,
|
||||
parseInt('0x' + color.substring(3, 5)) / 255,
|
||||
parseInt('0x' + color.substring(5, 7)) / 255];
|
||||
}
|
||||
else if (color.length == 4) {
|
||||
return [parseInt('0x' + color.substring(1, 2)) / 15,
|
||||
parseInt('0x' + color.substring(2, 3)) / 15,
|
||||
parseInt('0x' + color.substring(3, 4)) / 15];
|
||||
}
|
||||
};
|
||||
|
||||
fb.HSLToRGB = function (hsl) {
|
||||
var m1, m2, r, g, b;
|
||||
var h = hsl[0], s = hsl[1], l = hsl[2];
|
||||
m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
|
||||
m1 = l * 2 - m2;
|
||||
return [this.hueToRGB(m1, m2, h+0.33333),
|
||||
this.hueToRGB(m1, m2, h),
|
||||
this.hueToRGB(m1, m2, h-0.33333)];
|
||||
};
|
||||
|
||||
fb.hueToRGB = function (m1, m2, h) {
|
||||
h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
|
||||
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
|
||||
if (h * 2 < 1) return m2;
|
||||
if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
|
||||
return m1;
|
||||
};
|
||||
|
||||
fb.RGBToHSL = function (rgb) {
|
||||
var min, max, delta, h, s, l;
|
||||
var r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
min = Math.min(r, Math.min(g, b));
|
||||
max = Math.max(r, Math.max(g, b));
|
||||
delta = max - min;
|
||||
l = (min + max) / 2;
|
||||
s = 0;
|
||||
if (l > 0 && l < 1) {
|
||||
s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
|
||||
}
|
||||
h = 0;
|
||||
if (delta > 0) {
|
||||
if (max == r && max != g) h += (g - b) / delta;
|
||||
if (max == g && max != b) h += (2 + (b - r) / delta);
|
||||
if (max == b && max != r) h += (4 + (r - g) / delta);
|
||||
h /= 6;
|
||||
}
|
||||
return [h, s, l];
|
||||
};
|
||||
|
||||
// Install mousedown handler (the others are set on the document on-demand)
|
||||
$('*', e).on('mousedown', fb.mousedown);
|
||||
|
||||
// Init color
|
||||
fb.setColor('#000000');
|
||||
|
||||
// Set linked elements/callback
|
||||
if (callback) {
|
||||
fb.linkTo(callback);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
239
wp-admin/js/gallery.js
Normal file
239
wp-admin/js/gallery.js
Normal file
@ -0,0 +1,239 @@
|
||||
/**
|
||||
* @output wp-admin/js/gallery.js
|
||||
*/
|
||||
|
||||
/* global unescape, getUserSetting, setUserSetting, wpgallery, tinymce */
|
||||
|
||||
jQuery( function($) {
|
||||
var gallerySortable, gallerySortableInit, sortIt, clearAll, w, desc = false;
|
||||
|
||||
gallerySortableInit = function() {
|
||||
gallerySortable = $('#media-items').sortable( {
|
||||
items: 'div.media-item',
|
||||
placeholder: 'sorthelper',
|
||||
axis: 'y',
|
||||
distance: 2,
|
||||
handle: 'div.filename',
|
||||
stop: function() {
|
||||
// When an update has occurred, adjust the order for each item.
|
||||
var all = $('#media-items').sortable('toArray'), len = all.length;
|
||||
$.each(all, function(i, id) {
|
||||
var order = desc ? (len - i) : (1 + i);
|
||||
$('#' + id + ' .menu_order input').val(order);
|
||||
});
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
sortIt = function() {
|
||||
var all = $('.menu_order_input'), len = all.length;
|
||||
all.each(function(i){
|
||||
var order = desc ? (len - i) : (1 + i);
|
||||
$(this).val(order);
|
||||
});
|
||||
};
|
||||
|
||||
clearAll = function(c) {
|
||||
c = c || 0;
|
||||
$('.menu_order_input').each( function() {
|
||||
if ( this.value === '0' || c ) {
|
||||
this.value = '';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#asc').on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
desc = false;
|
||||
sortIt();
|
||||
});
|
||||
$('#desc').on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
desc = true;
|
||||
sortIt();
|
||||
});
|
||||
$('#clear').on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
clearAll(1);
|
||||
});
|
||||
$('#showall').on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
$('#sort-buttons span a').toggle();
|
||||
$('a.describe-toggle-on').hide();
|
||||
$('a.describe-toggle-off, table.slidetoggle').show();
|
||||
$('img.pinkynail').toggle(false);
|
||||
});
|
||||
$('#hideall').on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
$('#sort-buttons span a').toggle();
|
||||
$('a.describe-toggle-on').show();
|
||||
$('a.describe-toggle-off, table.slidetoggle').hide();
|
||||
$('img.pinkynail').toggle(true);
|
||||
});
|
||||
|
||||
// Initialize sortable.
|
||||
gallerySortableInit();
|
||||
clearAll();
|
||||
|
||||
if ( $('#media-items>*').length > 1 ) {
|
||||
w = wpgallery.getWin();
|
||||
|
||||
$('#save-all, #gallery-settings').show();
|
||||
if ( typeof w.tinyMCE !== 'undefined' && w.tinyMCE.activeEditor && ! w.tinyMCE.activeEditor.isHidden() ) {
|
||||
wpgallery.mcemode = true;
|
||||
wpgallery.init();
|
||||
} else {
|
||||
$('#insert-gallery').show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* gallery settings */
|
||||
window.tinymce = null;
|
||||
|
||||
window.wpgallery = {
|
||||
mcemode : false,
|
||||
editor : {},
|
||||
dom : {},
|
||||
is_update : false,
|
||||
el : {},
|
||||
|
||||
I : function(e) {
|
||||
return document.getElementById(e);
|
||||
},
|
||||
|
||||
init: function() {
|
||||
var t = this, li, q, i, it, w = t.getWin();
|
||||
|
||||
if ( ! t.mcemode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
li = ('' + document.location.search).replace(/^\?/, '').split('&');
|
||||
q = {};
|
||||
for (i=0; i<li.length; i++) {
|
||||
it = li[i].split('=');
|
||||
q[unescape(it[0])] = unescape(it[1]);
|
||||
}
|
||||
|
||||
if ( q.mce_rdomain ) {
|
||||
document.domain = q.mce_rdomain;
|
||||
}
|
||||
|
||||
// Find window & API.
|
||||
window.tinymce = w.tinymce;
|
||||
window.tinyMCE = w.tinyMCE;
|
||||
t.editor = tinymce.EditorManager.activeEditor;
|
||||
|
||||
t.setup();
|
||||
},
|
||||
|
||||
getWin : function() {
|
||||
return window.dialogArguments || opener || parent || top;
|
||||
},
|
||||
|
||||
setup : function() {
|
||||
var t = this, a, ed = t.editor, g, columns, link, order, orderby;
|
||||
if ( ! t.mcemode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
t.el = ed.selection.getNode();
|
||||
|
||||
if ( t.el.nodeName !== 'IMG' || ! ed.dom.hasClass(t.el, 'wpGallery') ) {
|
||||
if ( ( g = ed.dom.select('img.wpGallery') ) && g[0] ) {
|
||||
t.el = g[0];
|
||||
} else {
|
||||
if ( getUserSetting('galfile') === '1' ) {
|
||||
t.I('linkto-file').checked = 'checked';
|
||||
}
|
||||
if ( getUserSetting('galdesc') === '1' ) {
|
||||
t.I('order-desc').checked = 'checked';
|
||||
}
|
||||
if ( getUserSetting('galcols') ) {
|
||||
t.I('columns').value = getUserSetting('galcols');
|
||||
}
|
||||
if ( getUserSetting('galord') ) {
|
||||
t.I('orderby').value = getUserSetting('galord');
|
||||
}
|
||||
jQuery('#insert-gallery').show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
a = ed.dom.getAttrib(t.el, 'title');
|
||||
a = ed.dom.decode(a);
|
||||
|
||||
if ( a ) {
|
||||
jQuery('#update-gallery').show();
|
||||
t.is_update = true;
|
||||
|
||||
columns = a.match(/columns=['"]([0-9]+)['"]/);
|
||||
link = a.match(/link=['"]([^'"]+)['"]/i);
|
||||
order = a.match(/order=['"]([^'"]+)['"]/i);
|
||||
orderby = a.match(/orderby=['"]([^'"]+)['"]/i);
|
||||
|
||||
if ( link && link[1] ) {
|
||||
t.I('linkto-file').checked = 'checked';
|
||||
}
|
||||
if ( order && order[1] ) {
|
||||
t.I('order-desc').checked = 'checked';
|
||||
}
|
||||
if ( columns && columns[1] ) {
|
||||
t.I('columns').value = '' + columns[1];
|
||||
}
|
||||
if ( orderby && orderby[1] ) {
|
||||
t.I('orderby').value = orderby[1];
|
||||
}
|
||||
} else {
|
||||
jQuery('#insert-gallery').show();
|
||||
}
|
||||
},
|
||||
|
||||
update : function() {
|
||||
var t = this, ed = t.editor, all = '', s;
|
||||
|
||||
if ( ! t.mcemode || ! t.is_update ) {
|
||||
s = '[gallery' + t.getSettings() + ']';
|
||||
t.getWin().send_to_editor(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( t.el.nodeName !== 'IMG' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
all = ed.dom.decode( ed.dom.getAttrib( t.el, 'title' ) );
|
||||
all = all.replace(/\s*(order|link|columns|orderby)=['"]([^'"]+)['"]/gi, '');
|
||||
all += t.getSettings();
|
||||
|
||||
ed.dom.setAttrib(t.el, 'title', all);
|
||||
t.getWin().tb_remove();
|
||||
},
|
||||
|
||||
getSettings : function() {
|
||||
var I = this.I, s = '';
|
||||
|
||||
if ( I('linkto-file').checked ) {
|
||||
s += ' link="file"';
|
||||
setUserSetting('galfile', '1');
|
||||
}
|
||||
|
||||
if ( I('order-desc').checked ) {
|
||||
s += ' order="DESC"';
|
||||
setUserSetting('galdesc', '1');
|
||||
}
|
||||
|
||||
if ( I('columns').value !== 3 ) {
|
||||
s += ' columns="' + I('columns').value + '"';
|
||||
setUserSetting('galcols', I('columns').value);
|
||||
}
|
||||
|
||||
if ( I('orderby').value !== 'menu_order' ) {
|
||||
s += ' orderby="' + I('orderby').value + '"';
|
||||
setUserSetting('galord', I('orderby').value);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
};
|
2
wp-admin/js/gallery.min.js
vendored
Normal file
2
wp-admin/js/gallery.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
jQuery(function(n){var o=!1,e=function(){n("#media-items").sortable({items:"div.media-item",placeholder:"sorthelper",axis:"y",distance:2,handle:"div.filename",stop:function(){var e=n("#media-items").sortable("toArray"),i=e.length;n.each(e,function(e,t){e=o?i-e:1+e;n("#"+t+" .menu_order input").val(e)})}})},t=function(){var e=n(".menu_order_input"),t=e.length;e.each(function(e){e=o?t-e:1+e;n(this).val(e)})},i=function(e){e=e||0,n(".menu_order_input").each(function(){"0"!==this.value&&!e||(this.value="")})};n("#asc").on("click",function(e){e.preventDefault(),o=!1,t()}),n("#desc").on("click",function(e){e.preventDefault(),o=!0,t()}),n("#clear").on("click",function(e){e.preventDefault(),i(1)}),n("#showall").on("click",function(e){e.preventDefault(),n("#sort-buttons span a").toggle(),n("a.describe-toggle-on").hide(),n("a.describe-toggle-off, table.slidetoggle").show(),n("img.pinkynail").toggle(!1)}),n("#hideall").on("click",function(e){e.preventDefault(),n("#sort-buttons span a").toggle(),n("a.describe-toggle-on").show(),n("a.describe-toggle-off, table.slidetoggle").hide(),n("img.pinkynail").toggle(!0)}),e(),i(),1<n("#media-items>*").length&&(e=wpgallery.getWin(),n("#save-all, #gallery-settings").show(),void 0!==e.tinyMCE&&e.tinyMCE.activeEditor&&!e.tinyMCE.activeEditor.isHidden()?(wpgallery.mcemode=!0,wpgallery.init()):n("#insert-gallery").show())}),window.tinymce=null,window.wpgallery={mcemode:!1,editor:{},dom:{},is_update:!1,el:{},I:function(e){return document.getElementById(e)},init:function(){var e,t,i,n,o=this,l=o.getWin();if(o.mcemode){for(e=(""+document.location.search).replace(/^\?/,"").split("&"),t={},i=0;i<e.length;i++)n=e[i].split("="),t[unescape(n[0])]=unescape(n[1]);t.mce_rdomain&&(document.domain=t.mce_rdomain),window.tinymce=l.tinymce,window.tinyMCE=l.tinyMCE,o.editor=tinymce.EditorManager.activeEditor,o.setup()}},getWin:function(){return window.dialogArguments||opener||parent||top},setup:function(){var e,t,i,n=this,o=n.editor;if(n.mcemode){if(n.el=o.selection.getNode(),"IMG"!==n.el.nodeName||!o.dom.hasClass(n.el,"wpGallery")){if(!(i=o.dom.select("img.wpGallery"))||!i[0])return"1"===getUserSetting("galfile")&&(n.I("linkto-file").checked="checked"),"1"===getUserSetting("galdesc")&&(n.I("order-desc").checked="checked"),getUserSetting("galcols")&&(n.I("columns").value=getUserSetting("galcols")),getUserSetting("galord")&&(n.I("orderby").value=getUserSetting("galord")),void jQuery("#insert-gallery").show();n.el=i[0]}i=o.dom.getAttrib(n.el,"title"),(i=o.dom.decode(i))?(jQuery("#update-gallery").show(),n.is_update=!0,o=i.match(/columns=['"]([0-9]+)['"]/),e=i.match(/link=['"]([^'"]+)['"]/i),t=i.match(/order=['"]([^'"]+)['"]/i),i=i.match(/orderby=['"]([^'"]+)['"]/i),e&&e[1]&&(n.I("linkto-file").checked="checked"),t&&t[1]&&(n.I("order-desc").checked="checked"),o&&o[1]&&(n.I("columns").value=""+o[1]),i&&i[1]&&(n.I("orderby").value=i[1])):jQuery("#insert-gallery").show()}},update:function(){var e=this,t=e.editor,i="";e.mcemode&&e.is_update?"IMG"===e.el.nodeName&&(i=(i=t.dom.decode(t.dom.getAttrib(e.el,"title"))).replace(/\s*(order|link|columns|orderby)=['"]([^'"]+)['"]/gi,""),i+=e.getSettings(),t.dom.setAttrib(e.el,"title",i),e.getWin().tb_remove()):(t="[gallery"+e.getSettings()+"]",e.getWin().send_to_editor(t))},getSettings:function(){var e=this.I,t="";return e("linkto-file").checked&&(t+=' link="file"',setUserSetting("galfile","1")),e("order-desc").checked&&(t+=' order="DESC"',setUserSetting("galdesc","1")),3!==e("columns").value&&(t+=' columns="'+e("columns").value+'"',setUserSetting("galcols",e("columns").value)),"menu_order"!==e("orderby").value&&(t+=' orderby="'+e("orderby").value+'"',setUserSetting("galord",e("orderby").value)),t}};
|
1462
wp-admin/js/image-edit.js
Normal file
1462
wp-admin/js/image-edit.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/image-edit.min.js
vendored
Normal file
2
wp-admin/js/image-edit.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
645
wp-admin/js/inline-edit-post.js
Normal file
645
wp-admin/js/inline-edit-post.js
Normal file
@ -0,0 +1,645 @@
|
||||
/**
|
||||
* This file contains the functions needed for the inline editing of posts.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @output wp-admin/js/inline-edit-post.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, typenow, inlineEditPost */
|
||||
|
||||
window.wp = window.wp || {};
|
||||
|
||||
/**
|
||||
* Manages the quick edit and bulk edit windows for editing posts or pages.
|
||||
*
|
||||
* @namespace inlineEditPost
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @type {Object}
|
||||
*
|
||||
* @property {string} type The type of inline editor.
|
||||
* @property {string} what The prefix before the post ID.
|
||||
*
|
||||
*/
|
||||
( function( $, wp ) {
|
||||
|
||||
window.inlineEditPost = {
|
||||
|
||||
/**
|
||||
* Initializes the inline and bulk post editor.
|
||||
*
|
||||
* Binds event handlers to the Escape key to close the inline editor
|
||||
* and to the save and close buttons. Changes DOM to be ready for inline
|
||||
* editing. Adds event handler to bulk edit.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditPost
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
init : function(){
|
||||
var t = this, qeRow = $('#inline-edit'), bulkRow = $('#bulk-edit');
|
||||
|
||||
t.type = $('table.widefat').hasClass('pages') ? 'page' : 'post';
|
||||
// Post ID prefix.
|
||||
t.what = '#post-';
|
||||
|
||||
/**
|
||||
* Binds the Escape key to revert the changes and close the quick editor.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
qeRow.on( 'keyup', function(e){
|
||||
// Revert changes if Escape key is pressed.
|
||||
if ( e.which === 27 ) {
|
||||
return inlineEditPost.revert();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Binds the Escape key to revert the changes and close the bulk editor.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
bulkRow.on( 'keyup', function(e){
|
||||
// Revert changes if Escape key is pressed.
|
||||
if ( e.which === 27 ) {
|
||||
return inlineEditPost.revert();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Reverts changes and close the quick editor if the cancel button is clicked.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
$( '.cancel', qeRow ).on( 'click', function() {
|
||||
return inlineEditPost.revert();
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves changes in the quick editor if the save(named: update) button is clicked.
|
||||
*
|
||||
* @return {boolean} The result of save.
|
||||
*/
|
||||
$( '.save', qeRow ).on( 'click', function() {
|
||||
return inlineEditPost.save(this);
|
||||
});
|
||||
|
||||
/**
|
||||
* If Enter is pressed, and the target is not the cancel button, save the post.
|
||||
*
|
||||
* @return {boolean} The result of save.
|
||||
*/
|
||||
$('td', qeRow).on( 'keydown', function(e){
|
||||
if ( e.which === 13 && ! $( e.target ).hasClass( 'cancel' ) ) {
|
||||
return inlineEditPost.save(this);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Reverts changes and close the bulk editor if the cancel button is clicked.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
$( '.cancel', bulkRow ).on( 'click', function() {
|
||||
return inlineEditPost.revert();
|
||||
});
|
||||
|
||||
/**
|
||||
* Disables the password input field when the private post checkbox is checked.
|
||||
*/
|
||||
$('#inline-edit .inline-edit-private input[value="private"]').on( 'click', function(){
|
||||
var pw = $('input.inline-edit-password-input');
|
||||
if ( $(this).prop('checked') ) {
|
||||
pw.val('').prop('disabled', true);
|
||||
} else {
|
||||
pw.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Binds click event to the .editinline button which opens the quick editor.
|
||||
*/
|
||||
$( '#the-list' ).on( 'click', '.editinline', function() {
|
||||
$( this ).attr( 'aria-expanded', 'true' );
|
||||
inlineEditPost.edit( this );
|
||||
});
|
||||
|
||||
$('#bulk-edit').find('fieldset:first').after(
|
||||
$('#inline-edit fieldset.inline-edit-categories').clone()
|
||||
).siblings( 'fieldset:last' ).prepend(
|
||||
$( '#inline-edit .inline-edit-tags-wrap' ).clone()
|
||||
);
|
||||
|
||||
$('select[name="_status"] option[value="future"]', bulkRow).remove();
|
||||
|
||||
/**
|
||||
* Adds onclick events to the apply buttons.
|
||||
*/
|
||||
$('#doaction').on( 'click', function(e){
|
||||
var n;
|
||||
|
||||
t.whichBulkButtonId = $( this ).attr( 'id' );
|
||||
n = t.whichBulkButtonId.substr( 2 );
|
||||
|
||||
if ( 'edit' === $( 'select[name="' + n + '"]' ).val() ) {
|
||||
e.preventDefault();
|
||||
t.setBulk();
|
||||
} else if ( $('form#posts-filter tr.inline-editor').length > 0 ) {
|
||||
t.revert();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the quick edit window, hiding it when it's active and showing it when
|
||||
* inactive.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditPost
|
||||
*
|
||||
* @param {Object} el Element within a post table row.
|
||||
*/
|
||||
toggle : function(el){
|
||||
var t = this;
|
||||
$( t.what + t.getId( el ) ).css( 'display' ) === 'none' ? t.revert() : t.edit( el );
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the bulk editor row to edit multiple posts at once.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditPost
|
||||
*/
|
||||
setBulk : function(){
|
||||
var te = '', type = this.type, c = true;
|
||||
var checkedPosts = $( 'tbody th.check-column input[type="checkbox"]:checked' );
|
||||
var categories = {};
|
||||
this.revert();
|
||||
|
||||
$( '#bulk-edit td' ).attr( 'colspan', $( 'th:visible, td:visible', '.widefat:first thead' ).length );
|
||||
|
||||
// Insert the editor at the top of the table with an empty row above to maintain zebra striping.
|
||||
$('table.widefat tbody').prepend( $('#bulk-edit') ).prepend('<tr class="hidden"></tr>');
|
||||
$('#bulk-edit').addClass('inline-editor').show();
|
||||
|
||||
/**
|
||||
* Create a HTML div with the title and a link(delete-icon) for each selected
|
||||
* post.
|
||||
*
|
||||
* Get the selected posts based on the checked checkboxes in the post table.
|
||||
*/
|
||||
$( 'tbody th.check-column input[type="checkbox"]' ).each( function() {
|
||||
|
||||
// If the checkbox for a post is selected, add the post to the edit list.
|
||||
if ( $(this).prop('checked') ) {
|
||||
c = false;
|
||||
var id = $( this ).val(),
|
||||
theTitle = $( '#inline_' + id + ' .post_title' ).html() || wp.i18n.__( '(no title)' ),
|
||||
buttonVisuallyHiddenText = wp.i18n.sprintf(
|
||||
/* translators: %s: Post title. */
|
||||
wp.i18n.__( 'Remove “%s” from Bulk Edit' ),
|
||||
theTitle
|
||||
);
|
||||
|
||||
te += '<li class="ntdelitem"><button type="button" id="_' + id + '" class="button-link ntdelbutton"><span class="screen-reader-text">' + buttonVisuallyHiddenText + '</span></button><span class="ntdeltitle" aria-hidden="true">' + theTitle + '</span></li>';
|
||||
}
|
||||
});
|
||||
|
||||
// If no checkboxes where checked, just hide the quick/bulk edit rows.
|
||||
if ( c ) {
|
||||
return this.revert();
|
||||
}
|
||||
|
||||
// Populate the list of items to bulk edit.
|
||||
$( '#bulk-titles' ).html( '<ul id="bulk-titles-list" role="list">' + te + '</ul>' );
|
||||
|
||||
// Gather up some statistics on which of these checked posts are in which categories.
|
||||
checkedPosts.each( function() {
|
||||
var id = $( this ).val();
|
||||
var checked = $( '#category_' + id ).text().split( ',' );
|
||||
|
||||
checked.map( function( cid ) {
|
||||
categories[ cid ] || ( categories[ cid ] = 0 );
|
||||
// Just record that this category is checked.
|
||||
categories[ cid ]++;
|
||||
} );
|
||||
} );
|
||||
|
||||
// Compute initial states.
|
||||
$( '.inline-edit-categories input[name="post_category[]"]' ).each( function() {
|
||||
if ( categories[ $( this ).val() ] == checkedPosts.length ) {
|
||||
// If the number of checked categories matches the number of selected posts, then all posts are in this category.
|
||||
$( this ).prop( 'checked', true );
|
||||
} else if ( categories[ $( this ).val() ] > 0 ) {
|
||||
// If the number is less than the number of selected posts, then it's indeterminate.
|
||||
$( this ).prop( 'indeterminate', true );
|
||||
if ( ! $( this ).parent().find( 'input[name="indeterminate_post_category[]"]' ).length ) {
|
||||
// Get the term label text.
|
||||
var label = $( this ).parent().text();
|
||||
// Set indeterminate states for the backend. Add accessible text for indeterminate inputs.
|
||||
$( this ).after( '<input type="hidden" name="indeterminate_post_category[]" value="' + $( this ).val() + '">' ).attr( 'aria-label', label.trim() + ': ' + wp.i18n.__( 'Some selected posts have this category' ) );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
$( '.inline-edit-categories input[name="post_category[]"]:indeterminate' ).on( 'change', function() {
|
||||
// Remove accessible label text. Remove the indeterminate flags as there was a specific state change.
|
||||
$( this ).removeAttr( 'aria-label' ).parent().find( 'input[name="indeterminate_post_category[]"]' ).remove();
|
||||
} );
|
||||
|
||||
$( '.inline-edit-save button' ).on( 'click', function() {
|
||||
$( '.inline-edit-categories input[name="post_category[]"]' ).prop( 'indeterminate', false );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Binds on click events to handle the list of items to bulk edit.
|
||||
*
|
||||
* @listens click
|
||||
*/
|
||||
$( '#bulk-titles .ntdelbutton' ).click( function() {
|
||||
var $this = $( this ),
|
||||
id = $this.attr( 'id' ).substr( 1 ),
|
||||
$prev = $this.parent().prev().children( '.ntdelbutton' ),
|
||||
$next = $this.parent().next().children( '.ntdelbutton' );
|
||||
|
||||
$( 'input#cb-select-all-1, input#cb-select-all-2' ).prop( 'checked', false );
|
||||
$( 'table.widefat input[value="' + id + '"]' ).prop( 'checked', false );
|
||||
$( '#_' + id ).parent().remove();
|
||||
wp.a11y.speak( wp.i18n.__( 'Item removed.' ), 'assertive' );
|
||||
|
||||
// Move focus to a proper place when items are removed.
|
||||
if ( $next.length ) {
|
||||
$next.focus();
|
||||
} else if ( $prev.length ) {
|
||||
$prev.focus();
|
||||
} else {
|
||||
$( '#bulk-titles-list' ).remove();
|
||||
inlineEditPost.revert();
|
||||
wp.a11y.speak( wp.i18n.__( 'All selected items have been removed. Select new items to use Bulk Actions.' ) );
|
||||
}
|
||||
});
|
||||
|
||||
// Enable auto-complete for tags when editing posts.
|
||||
if ( 'post' === type ) {
|
||||
$( 'tr.inline-editor textarea[data-wp-taxonomy]' ).each( function ( i, element ) {
|
||||
/*
|
||||
* While Quick Edit clones the form each time, Bulk Edit always re-uses
|
||||
* the same form. Let's check if an autocomplete instance already exists.
|
||||
*/
|
||||
if ( $( element ).autocomplete( 'instance' ) ) {
|
||||
// jQuery equivalent of `continue` within an `each()` loop.
|
||||
return;
|
||||
}
|
||||
|
||||
$( element ).wpTagsSuggest();
|
||||
} );
|
||||
}
|
||||
|
||||
// Set initial focus on the Bulk Edit region.
|
||||
$( '#bulk-edit .inline-edit-wrapper' ).attr( 'tabindex', '-1' ).focus();
|
||||
// Scrolls to the top of the table where the editor is rendered.
|
||||
$('html, body').animate( { scrollTop: 0 }, 'fast' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a quick edit window for the post that has been clicked.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditPost
|
||||
*
|
||||
* @param {number|Object} id The ID of the clicked post or an element within a post
|
||||
* table row.
|
||||
* @return {boolean} Always returns false at the end of execution.
|
||||
*/
|
||||
edit : function(id) {
|
||||
var t = this, fields, editRow, rowData, status, pageOpt, pageLevel, nextPage, pageLoop = true, nextLevel, f, val, pw;
|
||||
t.revert();
|
||||
|
||||
if ( typeof(id) === 'object' ) {
|
||||
id = t.getId(id);
|
||||
}
|
||||
|
||||
fields = ['post_title', 'post_name', 'post_author', '_status', 'jj', 'mm', 'aa', 'hh', 'mn', 'ss', 'post_password', 'post_format', 'menu_order', 'page_template'];
|
||||
if ( t.type === 'page' ) {
|
||||
fields.push('post_parent');
|
||||
}
|
||||
|
||||
// Add the new edit row with an extra blank row underneath to maintain zebra striping.
|
||||
editRow = $('#inline-edit').clone(true);
|
||||
$( 'td', editRow ).attr( 'colspan', $( 'th:visible, td:visible', '.widefat:first thead' ).length );
|
||||
|
||||
// Remove the ID from the copied row and let the `for` attribute reference the hidden ID.
|
||||
$( 'td', editRow ).find('#quick-edit-legend').removeAttr('id');
|
||||
$( 'td', editRow ).find('p[id^="quick-edit-"]').removeAttr('id');
|
||||
|
||||
$(t.what+id).removeClass('is-expanded').hide().after(editRow).after('<tr class="hidden"></tr>');
|
||||
|
||||
// Populate fields in the quick edit window.
|
||||
rowData = $('#inline_'+id);
|
||||
if ( !$(':input[name="post_author"] option[value="' + $('.post_author', rowData).text() + '"]', editRow).val() ) {
|
||||
|
||||
// The post author no longer has edit capabilities, so we need to add them to the list of authors.
|
||||
$(':input[name="post_author"]', editRow).prepend('<option value="' + $('.post_author', rowData).text() + '">' + $('#post-' + id + ' .author').text() + '</option>');
|
||||
}
|
||||
if ( $( ':input[name="post_author"] option', editRow ).length === 1 ) {
|
||||
$('label.inline-edit-author', editRow).hide();
|
||||
}
|
||||
|
||||
for ( f = 0; f < fields.length; f++ ) {
|
||||
val = $('.'+fields[f], rowData);
|
||||
|
||||
/**
|
||||
* Replaces the image for a Twemoji(Twitter emoji) with it's alternate text.
|
||||
*
|
||||
* @return {string} Alternate text from the image.
|
||||
*/
|
||||
val.find( 'img' ).replaceWith( function() { return this.alt; } );
|
||||
val = val.text();
|
||||
$(':input[name="' + fields[f] + '"]', editRow).val( val );
|
||||
}
|
||||
|
||||
if ( $( '.comment_status', rowData ).text() === 'open' ) {
|
||||
$( 'input[name="comment_status"]', editRow ).prop( 'checked', true );
|
||||
}
|
||||
if ( $( '.ping_status', rowData ).text() === 'open' ) {
|
||||
$( 'input[name="ping_status"]', editRow ).prop( 'checked', true );
|
||||
}
|
||||
if ( $( '.sticky', rowData ).text() === 'sticky' ) {
|
||||
$( 'input[name="sticky"]', editRow ).prop( 'checked', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the select boxes for the categories.
|
||||
*/
|
||||
$('.post_category', rowData).each(function(){
|
||||
var taxname,
|
||||
term_ids = $(this).text();
|
||||
|
||||
if ( term_ids ) {
|
||||
taxname = $(this).attr('id').replace('_'+id, '');
|
||||
$('ul.'+taxname+'-checklist :checkbox', editRow).val(term_ids.split(','));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets all the taxonomies for live auto-fill suggestions when typing the name
|
||||
* of a tag.
|
||||
*/
|
||||
$('.tags_input', rowData).each(function(){
|
||||
var terms = $(this),
|
||||
taxname = $(this).attr('id').replace('_' + id, ''),
|
||||
textarea = $('textarea.tax_input_' + taxname, editRow),
|
||||
comma = wp.i18n._x( ',', 'tag delimiter' ).trim();
|
||||
|
||||
// Ensure the textarea exists.
|
||||
if ( ! textarea.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
terms.find( 'img' ).replaceWith( function() { return this.alt; } );
|
||||
terms = terms.text();
|
||||
|
||||
if ( terms ) {
|
||||
if ( ',' !== comma ) {
|
||||
terms = terms.replace(/,/g, comma);
|
||||
}
|
||||
textarea.val(terms);
|
||||
}
|
||||
|
||||
textarea.wpTagsSuggest();
|
||||
});
|
||||
|
||||
// Handle the post status.
|
||||
var post_date_string = $(':input[name="aa"]').val() + '-' + $(':input[name="mm"]').val() + '-' + $(':input[name="jj"]').val();
|
||||
post_date_string += ' ' + $(':input[name="hh"]').val() + ':' + $(':input[name="mn"]').val() + ':' + $(':input[name="ss"]').val();
|
||||
var post_date = new Date( post_date_string );
|
||||
status = $('._status', rowData).text();
|
||||
if ( 'future' !== status && Date.now() > post_date ) {
|
||||
$('select[name="_status"] option[value="future"]', editRow).remove();
|
||||
} else {
|
||||
$('select[name="_status"] option[value="publish"]', editRow).remove();
|
||||
}
|
||||
|
||||
pw = $( '.inline-edit-password-input' ).prop( 'disabled', false );
|
||||
if ( 'private' === status ) {
|
||||
$('input[name="keep_private"]', editRow).prop('checked', true);
|
||||
pw.val( '' ).prop( 'disabled', true );
|
||||
}
|
||||
|
||||
// Remove the current page and children from the parent dropdown.
|
||||
pageOpt = $('select[name="post_parent"] option[value="' + id + '"]', editRow);
|
||||
if ( pageOpt.length > 0 ) {
|
||||
pageLevel = pageOpt[0].className.split('-')[1];
|
||||
nextPage = pageOpt;
|
||||
while ( pageLoop ) {
|
||||
nextPage = nextPage.next('option');
|
||||
if ( nextPage.length === 0 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
nextLevel = nextPage[0].className.split('-')[1];
|
||||
|
||||
if ( nextLevel <= pageLevel ) {
|
||||
pageLoop = false;
|
||||
} else {
|
||||
nextPage.remove();
|
||||
nextPage = pageOpt;
|
||||
}
|
||||
}
|
||||
pageOpt.remove();
|
||||
}
|
||||
|
||||
$(editRow).attr('id', 'edit-'+id).addClass('inline-editor').show();
|
||||
$('.ptitle', editRow).trigger( 'focus' );
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the changes made in the quick edit window to the post.
|
||||
* Ajax saving is only for Quick Edit and not for bulk edit.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @param {number} id The ID for the post that has been changed.
|
||||
* @return {boolean} False, so the form does not submit when pressing
|
||||
* Enter on a focused field.
|
||||
*/
|
||||
save : function(id) {
|
||||
var params, fields, page = $('.post_status_page').val() || '';
|
||||
|
||||
if ( typeof(id) === 'object' ) {
|
||||
id = this.getId(id);
|
||||
}
|
||||
|
||||
$( 'table.widefat .spinner' ).addClass( 'is-active' );
|
||||
|
||||
params = {
|
||||
action: 'inline-save',
|
||||
post_type: typenow,
|
||||
post_ID: id,
|
||||
edit_date: 'true',
|
||||
post_status: page
|
||||
};
|
||||
|
||||
fields = $('#edit-'+id).find(':input').serialize();
|
||||
params = fields + '&' + $.param(params);
|
||||
|
||||
// Make Ajax request.
|
||||
$.post( ajaxurl, params,
|
||||
function(r) {
|
||||
var $errorNotice = $( '#edit-' + id + ' .inline-edit-save .notice-error' ),
|
||||
$error = $errorNotice.find( '.error' );
|
||||
|
||||
$( 'table.widefat .spinner' ).removeClass( 'is-active' );
|
||||
|
||||
if (r) {
|
||||
if ( -1 !== r.indexOf( '<tr' ) ) {
|
||||
$(inlineEditPost.what+id).siblings('tr.hidden').addBack().remove();
|
||||
$('#edit-'+id).before(r).remove();
|
||||
$( inlineEditPost.what + id ).hide().fadeIn( 400, function() {
|
||||
// Move focus back to the Quick Edit button. $( this ) is the row being animated.
|
||||
$( this ).find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
wp.a11y.speak( wp.i18n.__( 'Changes saved.' ) );
|
||||
});
|
||||
} else {
|
||||
r = r.replace( /<.[^<>]*?>/g, '' );
|
||||
$errorNotice.removeClass( 'hidden' );
|
||||
$error.html( r );
|
||||
wp.a11y.speak( $error.text() );
|
||||
}
|
||||
} else {
|
||||
$errorNotice.removeClass( 'hidden' );
|
||||
$error.text( wp.i18n.__( 'Error while saving the changes.' ) );
|
||||
wp.a11y.speak( wp.i18n.__( 'Error while saving the changes.' ) );
|
||||
}
|
||||
},
|
||||
'html');
|
||||
|
||||
// Prevent submitting the form when pressing Enter on a focused field.
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides and empties the Quick Edit and/or Bulk Edit windows.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditPost
|
||||
*
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
revert : function(){
|
||||
var $tableWideFat = $( '.widefat' ),
|
||||
id = $( '.inline-editor', $tableWideFat ).attr( 'id' );
|
||||
|
||||
if ( id ) {
|
||||
$( '.spinner', $tableWideFat ).removeClass( 'is-active' );
|
||||
|
||||
if ( 'bulk-edit' === id ) {
|
||||
|
||||
// Hide the bulk editor.
|
||||
$( '#bulk-edit', $tableWideFat ).removeClass( 'inline-editor' ).hide().siblings( '.hidden' ).remove();
|
||||
$('#bulk-titles').empty();
|
||||
|
||||
// Store the empty bulk editor in a hidden element.
|
||||
$('#inlineedit').append( $('#bulk-edit') );
|
||||
|
||||
// Move focus back to the Bulk Action button that was activated.
|
||||
$( '#' + inlineEditPost.whichBulkButtonId ).trigger( 'focus' );
|
||||
} else {
|
||||
|
||||
// Remove both the inline-editor and its hidden tr siblings.
|
||||
$('#'+id).siblings('tr.hidden').addBack().remove();
|
||||
id = id.substr( id.lastIndexOf('-') + 1 );
|
||||
|
||||
// Show the post row and move focus back to the Quick Edit button.
|
||||
$( this.what + id ).show().find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the ID for a the post that you want to quick edit from the row in the quick
|
||||
* edit table.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditPost
|
||||
*
|
||||
* @param {Object} o DOM row object to get the ID for.
|
||||
* @return {string} The post ID extracted from the table row in the object.
|
||||
*/
|
||||
getId : function(o) {
|
||||
var id = $(o).closest('tr').attr('id'),
|
||||
parts = id.split('-');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
};
|
||||
|
||||
$( function() { inlineEditPost.init(); } );
|
||||
|
||||
// Show/hide locks on posts.
|
||||
$( function() {
|
||||
|
||||
// Set the heartbeat interval to 15 seconds.
|
||||
if ( typeof wp !== 'undefined' && wp.heartbeat ) {
|
||||
wp.heartbeat.interval( 15 );
|
||||
}
|
||||
}).on( 'heartbeat-tick.wp-check-locked-posts', function( e, data ) {
|
||||
var locked = data['wp-check-locked-posts'] || {};
|
||||
|
||||
$('#the-list tr').each( function(i, el) {
|
||||
var key = el.id, row = $(el), lock_data, avatar;
|
||||
|
||||
if ( locked.hasOwnProperty( key ) ) {
|
||||
if ( ! row.hasClass('wp-locked') ) {
|
||||
lock_data = locked[key];
|
||||
row.find('.column-title .locked-text').text( lock_data.text );
|
||||
row.find('.check-column checkbox').prop('checked', false);
|
||||
|
||||
if ( lock_data.avatar_src ) {
|
||||
avatar = $( '<img />', {
|
||||
'class': 'avatar avatar-18 photo',
|
||||
width: 18,
|
||||
height: 18,
|
||||
alt: '',
|
||||
src: lock_data.avatar_src,
|
||||
srcset: lock_data.avatar_src_2x ? lock_data.avatar_src_2x + ' 2x' : undefined
|
||||
} );
|
||||
row.find('.column-title .locked-avatar').empty().append( avatar );
|
||||
}
|
||||
row.addClass('wp-locked');
|
||||
}
|
||||
} else if ( row.hasClass('wp-locked') ) {
|
||||
row.removeClass( 'wp-locked' ).find( '.locked-info span' ).empty();
|
||||
}
|
||||
});
|
||||
}).on( 'heartbeat-send.wp-check-locked-posts', function( e, data ) {
|
||||
var check = [];
|
||||
|
||||
$('#the-list tr').each( function(i, el) {
|
||||
if ( el.id ) {
|
||||
check.push( el.id );
|
||||
}
|
||||
});
|
||||
|
||||
if ( check.length ) {
|
||||
data['wp-check-locked-posts'] = check;
|
||||
}
|
||||
});
|
||||
|
||||
})( jQuery, window.wp );
|
2
wp-admin/js/inline-edit-post.min.js
vendored
Normal file
2
wp-admin/js/inline-edit-post.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
294
wp-admin/js/inline-edit-tax.js
Normal file
294
wp-admin/js/inline-edit-tax.js
Normal file
@ -0,0 +1,294 @@
|
||||
/**
|
||||
* This file is used on the term overview page to power quick-editing terms.
|
||||
*
|
||||
* @output wp-admin/js/inline-edit-tax.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, inlineEditTax */
|
||||
|
||||
window.wp = window.wp || {};
|
||||
|
||||
/**
|
||||
* Consists of functions relevant to the inline taxonomy editor.
|
||||
*
|
||||
* @namespace inlineEditTax
|
||||
*
|
||||
* @property {string} type The type of inline edit we are currently on.
|
||||
* @property {string} what The type property with a hash prefixed and a dash
|
||||
* suffixed.
|
||||
*/
|
||||
( function( $, wp ) {
|
||||
|
||||
window.inlineEditTax = {
|
||||
|
||||
/**
|
||||
* Initializes the inline taxonomy editor by adding event handlers to be able to
|
||||
* quick edit.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @this inlineEditTax
|
||||
* @memberof inlineEditTax
|
||||
* @return {void}
|
||||
*/
|
||||
init : function() {
|
||||
var t = this, row = $('#inline-edit');
|
||||
|
||||
t.type = $('#the-list').attr('data-wp-lists').substr(5);
|
||||
t.what = '#'+t.type+'-';
|
||||
|
||||
$( '#the-list' ).on( 'click', '.editinline', function() {
|
||||
$( this ).attr( 'aria-expanded', 'true' );
|
||||
inlineEditTax.edit( this );
|
||||
});
|
||||
|
||||
/**
|
||||
* Cancels inline editing when pressing Escape inside the inline editor.
|
||||
*
|
||||
* @param {Object} e The keyup event that has been triggered.
|
||||
*/
|
||||
row.on( 'keyup', function( e ) {
|
||||
// 27 = [Escape].
|
||||
if ( e.which === 27 ) {
|
||||
return inlineEditTax.revert();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Cancels inline editing when clicking the cancel button.
|
||||
*/
|
||||
$( '.cancel', row ).on( 'click', function() {
|
||||
return inlineEditTax.revert();
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves the inline edits when clicking the save button.
|
||||
*/
|
||||
$( '.save', row ).on( 'click', function() {
|
||||
return inlineEditTax.save(this);
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves the inline edits when pressing Enter inside the inline editor.
|
||||
*/
|
||||
$( 'input, select', row ).on( 'keydown', function( e ) {
|
||||
// 13 = [Enter].
|
||||
if ( e.which === 13 ) {
|
||||
return inlineEditTax.save( this );
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves the inline edits on submitting the inline edit form.
|
||||
*/
|
||||
$( '#posts-filter input[type="submit"]' ).on( 'mousedown', function() {
|
||||
t.revert();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the quick edit based on if it is currently shown or hidden.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @this inlineEditTax
|
||||
* @memberof inlineEditTax
|
||||
*
|
||||
* @param {HTMLElement} el An element within the table row or the table row
|
||||
* itself that we want to quick edit.
|
||||
* @return {void}
|
||||
*/
|
||||
toggle : function(el) {
|
||||
var t = this;
|
||||
|
||||
$(t.what+t.getId(el)).css('display') === 'none' ? t.revert() : t.edit(el);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the quick editor
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @this inlineEditTax
|
||||
* @memberof inlineEditTax
|
||||
*
|
||||
* @param {string|HTMLElement} id The ID of the term we want to quick edit or an
|
||||
* element within the table row or the
|
||||
* table row itself.
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
edit : function(id) {
|
||||
var editRow, rowData, val,
|
||||
t = this;
|
||||
t.revert();
|
||||
|
||||
// Makes sure we can pass an HTMLElement as the ID.
|
||||
if ( typeof(id) === 'object' ) {
|
||||
id = t.getId(id);
|
||||
}
|
||||
|
||||
editRow = $('#inline-edit').clone(true), rowData = $('#inline_'+id);
|
||||
$( 'td', editRow ).attr( 'colspan', $( 'th:visible, td:visible', '.wp-list-table.widefat:first thead' ).length );
|
||||
|
||||
$(t.what+id).hide().after(editRow).after('<tr class="hidden"></tr>');
|
||||
|
||||
val = $('.name', rowData);
|
||||
val.find( 'img' ).replaceWith( function() { return this.alt; } );
|
||||
val = val.text();
|
||||
$(':input[name="name"]', editRow).val( val );
|
||||
|
||||
val = $('.slug', rowData);
|
||||
val.find( 'img' ).replaceWith( function() { return this.alt; } );
|
||||
val = val.text();
|
||||
$(':input[name="slug"]', editRow).val( val );
|
||||
|
||||
$(editRow).attr('id', 'edit-'+id).addClass('inline-editor').show();
|
||||
$('.ptitle', editRow).eq(0).trigger( 'focus' );
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the quick edit data.
|
||||
*
|
||||
* Saves the quick edit data to the server and replaces the table row with the
|
||||
* HTML retrieved from the server.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @this inlineEditTax
|
||||
* @memberof inlineEditTax
|
||||
*
|
||||
* @param {string|HTMLElement} id The ID of the term we want to quick edit or an
|
||||
* element within the table row or the
|
||||
* table row itself.
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
save : function(id) {
|
||||
var params, fields, tax = $('input[name="taxonomy"]').val() || '';
|
||||
|
||||
// Makes sure we can pass an HTMLElement as the ID.
|
||||
if( typeof(id) === 'object' ) {
|
||||
id = this.getId(id);
|
||||
}
|
||||
|
||||
$( 'table.widefat .spinner' ).addClass( 'is-active' );
|
||||
|
||||
params = {
|
||||
action: 'inline-save-tax',
|
||||
tax_type: this.type,
|
||||
tax_ID: id,
|
||||
taxonomy: tax
|
||||
};
|
||||
|
||||
fields = $('#edit-'+id).find(':input').serialize();
|
||||
params = fields + '&' + $.param(params);
|
||||
|
||||
// Do the Ajax request to save the data to the server.
|
||||
$.post( ajaxurl, params,
|
||||
/**
|
||||
* Handles the response from the server
|
||||
*
|
||||
* Handles the response from the server, replaces the table row with the response
|
||||
* from the server.
|
||||
*
|
||||
* @param {string} r The string with which to replace the table row.
|
||||
*/
|
||||
function(r) {
|
||||
var row, new_id, option_value,
|
||||
$errorNotice = $( '#edit-' + id + ' .inline-edit-save .notice-error' ),
|
||||
$error = $errorNotice.find( '.error' );
|
||||
|
||||
$( 'table.widefat .spinner' ).removeClass( 'is-active' );
|
||||
|
||||
if (r) {
|
||||
if ( -1 !== r.indexOf( '<tr' ) ) {
|
||||
$(inlineEditTax.what+id).siblings('tr.hidden').addBack().remove();
|
||||
new_id = $(r).attr('id');
|
||||
|
||||
$('#edit-'+id).before(r).remove();
|
||||
|
||||
if ( new_id ) {
|
||||
option_value = new_id.replace( inlineEditTax.type + '-', '' );
|
||||
row = $( '#' + new_id );
|
||||
} else {
|
||||
option_value = id;
|
||||
row = $( inlineEditTax.what + id );
|
||||
}
|
||||
|
||||
// Update the value in the Parent dropdown.
|
||||
$( '#parent' ).find( 'option[value=' + option_value + ']' ).text( row.find( '.row-title' ).text() );
|
||||
|
||||
row.hide().fadeIn( 400, function() {
|
||||
// Move focus back to the Quick Edit button.
|
||||
row.find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
wp.a11y.speak( wp.i18n.__( 'Changes saved.' ) );
|
||||
});
|
||||
|
||||
} else {
|
||||
$errorNotice.removeClass( 'hidden' );
|
||||
$error.html( r );
|
||||
/*
|
||||
* Some error strings may contain HTML entities (e.g. `“`), let's use
|
||||
* the HTML element's text.
|
||||
*/
|
||||
wp.a11y.speak( $error.text() );
|
||||
}
|
||||
} else {
|
||||
$errorNotice.removeClass( 'hidden' );
|
||||
$error.text( wp.i18n.__( 'Error while saving the changes.' ) );
|
||||
wp.a11y.speak( wp.i18n.__( 'Error while saving the changes.' ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Prevent submitting the form when pressing Enter on a focused field.
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the quick edit form.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @this inlineEditTax
|
||||
* @memberof inlineEditTax
|
||||
* @return {void}
|
||||
*/
|
||||
revert : function() {
|
||||
var id = $('table.widefat tr.inline-editor').attr('id');
|
||||
|
||||
if ( id ) {
|
||||
$( 'table.widefat .spinner' ).removeClass( 'is-active' );
|
||||
$('#'+id).siblings('tr.hidden').addBack().remove();
|
||||
id = id.substr( id.lastIndexOf('-') + 1 );
|
||||
|
||||
// Show the taxonomy row and move focus back to the Quick Edit button.
|
||||
$( this.what + id ).show().find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the ID of the term of the element inside the table row.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTax
|
||||
*
|
||||
* @param {HTMLElement} o An element within the table row or the table row itself.
|
||||
* @return {string} The ID of the term based on the element.
|
||||
*/
|
||||
getId : function(o) {
|
||||
var id = o.tagName === 'TR' ? o.id : $(o).parents('tr').attr('id'), parts = id.split('-');
|
||||
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
};
|
||||
|
||||
$( function() { inlineEditTax.init(); } );
|
||||
|
||||
})( jQuery, window.wp );
|
2
wp-admin/js/inline-edit-tax.min.js
vendored
Normal file
2
wp-admin/js/inline-edit-tax.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
window.wp=window.wp||{},function(s,l){window.inlineEditTax={init:function(){var t=this,i=s("#inline-edit");t.type=s("#the-list").attr("data-wp-lists").substr(5),t.what="#"+t.type+"-",s("#the-list").on("click",".editinline",function(){s(this).attr("aria-expanded","true"),inlineEditTax.edit(this)}),i.on("keyup",function(t){if(27===t.which)return inlineEditTax.revert()}),s(".cancel",i).on("click",function(){return inlineEditTax.revert()}),s(".save",i).on("click",function(){return inlineEditTax.save(this)}),s("input, select",i).on("keydown",function(t){if(13===t.which)return inlineEditTax.save(this)}),s('#posts-filter input[type="submit"]').on("mousedown",function(){t.revert()})},toggle:function(t){var i=this;"none"===s(i.what+i.getId(t)).css("display")?i.revert():i.edit(t)},edit:function(t){var i,e,n=this;return n.revert(),"object"==typeof t&&(t=n.getId(t)),i=s("#inline-edit").clone(!0),e=s("#inline_"+t),s("td",i).attr("colspan",s("th:visible, td:visible",".wp-list-table.widefat:first thead").length),s(n.what+t).hide().after(i).after('<tr class="hidden"></tr>'),(n=s(".name",e)).find("img").replaceWith(function(){return this.alt}),n=n.text(),s(':input[name="name"]',i).val(n),(n=s(".slug",e)).find("img").replaceWith(function(){return this.alt}),n=n.text(),s(':input[name="slug"]',i).val(n),s(i).attr("id","edit-"+t).addClass("inline-editor").show(),s(".ptitle",i).eq(0).trigger("focus"),!1},save:function(d){var t=s('input[name="taxonomy"]').val()||"";return"object"==typeof d&&(d=this.getId(d)),s("table.widefat .spinner").addClass("is-active"),t={action:"inline-save-tax",tax_type:this.type,tax_ID:d,taxonomy:t},t=s("#edit-"+d).find(":input").serialize()+"&"+s.param(t),s.post(ajaxurl,t,function(t){var i,e,n,a=s("#edit-"+d+" .inline-edit-save .notice-error"),r=a.find(".error");s("table.widefat .spinner").removeClass("is-active"),t?-1!==t.indexOf("<tr")?(s(inlineEditTax.what+d).siblings("tr.hidden").addBack().remove(),e=s(t).attr("id"),s("#edit-"+d).before(t).remove(),i=e?(n=e.replace(inlineEditTax.type+"-",""),s("#"+e)):(n=d,s(inlineEditTax.what+d)),s("#parent").find("option[value="+n+"]").text(i.find(".row-title").text()),i.hide().fadeIn(400,function(){i.find(".editinline").attr("aria-expanded","false").trigger("focus"),l.a11y.speak(l.i18n.__("Changes saved."))})):(a.removeClass("hidden"),r.html(t),l.a11y.speak(r.text())):(a.removeClass("hidden"),r.text(l.i18n.__("Error while saving the changes.")),l.a11y.speak(l.i18n.__("Error while saving the changes.")))}),!1},revert:function(){var t=s("table.widefat tr.inline-editor").attr("id");t&&(s("table.widefat .spinner").removeClass("is-active"),s("#"+t).siblings("tr.hidden").addBack().remove(),t=t.substr(t.lastIndexOf("-")+1),s(this.what+t).show().find(".editinline").attr("aria-expanded","false").trigger("focus"))},getId:function(t){t=("TR"===t.tagName?t.id:s(t).parents("tr").attr("id")).split("-");return t[t.length-1]}},s(function(){inlineEditTax.init()})}(jQuery,window.wp);
|
5
wp-admin/js/iris.min.js
vendored
Normal file
5
wp-admin/js/iris.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
36
wp-admin/js/language-chooser.js
Normal file
36
wp-admin/js/language-chooser.js
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @output wp-admin/js/language-chooser.js
|
||||
*/
|
||||
|
||||
jQuery( function($) {
|
||||
/*
|
||||
* Set the correct translation to the continue button and show a spinner
|
||||
* when downloading a language.
|
||||
*/
|
||||
var select = $( '#language' ),
|
||||
submit = $( '#language-continue' );
|
||||
|
||||
if ( ! $( 'body' ).hasClass( 'language-chooser' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
select.trigger( 'focus' ).on( 'change', function() {
|
||||
/*
|
||||
* When a language is selected, set matching translation to continue button
|
||||
* and attach the language attribute.
|
||||
*/
|
||||
var option = select.children( 'option:selected' );
|
||||
submit.attr({
|
||||
value: option.data( 'continue' ),
|
||||
lang: option.attr( 'lang' )
|
||||
});
|
||||
});
|
||||
|
||||
$( 'form' ).on( 'submit', function() {
|
||||
// Show spinner for languages that need to be downloaded.
|
||||
if ( ! select.children( 'option:selected' ).data( 'installed' ) ) {
|
||||
$( this ).find( '.step .spinner' ).css( 'visibility', 'visible' );
|
||||
}
|
||||
});
|
||||
|
||||
});
|
2
wp-admin/js/language-chooser.min.js
vendored
Normal file
2
wp-admin/js/language-chooser.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
jQuery(function(n){var e=n("#language"),a=n("#language-continue");n("body").hasClass("language-chooser")&&(e.trigger("focus").on("change",function(){var n=e.children("option:selected");a.attr({value:n.data("continue"),lang:n.attr("lang")})}),n("form").on("submit",function(){e.children("option:selected").data("installed")||n(this).find(".step .spinner").css("visibility","visible")}))});
|
140
wp-admin/js/link.js
Normal file
140
wp-admin/js/link.js
Normal file
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @output wp-admin/js/link.js
|
||||
*/
|
||||
|
||||
/* global postboxes, deleteUserSetting, setUserSetting, getUserSetting */
|
||||
|
||||
jQuery( function($) {
|
||||
|
||||
var newCat, noSyncChecks = false, syncChecks, catAddAfter;
|
||||
|
||||
$('#link_name').trigger( 'focus' );
|
||||
// Postboxes.
|
||||
postboxes.add_postbox_toggles('link');
|
||||
|
||||
/**
|
||||
* Adds event that opens a particular category tab.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @return {boolean} Always returns false to prevent the default behavior.
|
||||
*/
|
||||
$('#category-tabs a').on( 'click', function(){
|
||||
var t = $(this).attr('href');
|
||||
$(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
|
||||
$('.tabs-panel').hide();
|
||||
$(t).show();
|
||||
if ( '#categories-all' == t )
|
||||
deleteUserSetting('cats');
|
||||
else
|
||||
setUserSetting('cats','pop');
|
||||
return false;
|
||||
});
|
||||
if ( getUserSetting('cats') )
|
||||
$('#category-tabs a[href="#categories-pop"]').trigger( 'click' );
|
||||
|
||||
// Ajax Cat.
|
||||
newCat = $('#newcat').one( 'focus', function() { $(this).val( '' ).removeClass( 'form-input-tip' ); } );
|
||||
|
||||
/**
|
||||
* After adding a new category, focus on the category add input field.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('#link-category-add-submit').on( 'click', function() { newCat.focus(); } );
|
||||
|
||||
/**
|
||||
* Synchronize category checkboxes.
|
||||
*
|
||||
* This function makes sure that the checkboxes are synced between the all
|
||||
* categories tab and the most used categories tab.
|
||||
*
|
||||
* @since 2.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
syncChecks = function() {
|
||||
if ( noSyncChecks )
|
||||
return;
|
||||
noSyncChecks = true;
|
||||
var th = $(this), c = th.is(':checked'), id = th.val().toString();
|
||||
$('#in-link-category-' + id + ', #in-popular-link_category-' + id).prop( 'checked', c );
|
||||
noSyncChecks = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds event listeners to an added category.
|
||||
*
|
||||
* This is run on the addAfter event to make sure the correct event listeners
|
||||
* are bound to the DOM elements.
|
||||
*
|
||||
* @since 2.5.0
|
||||
*
|
||||
* @param {string} r Raw XML response returned from the server after adding a
|
||||
* category.
|
||||
* @param {Object} s List manager configuration object; settings for the Ajax
|
||||
* request.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
catAddAfter = function( r, s ) {
|
||||
$(s.what + ' response_data', r).each( function() {
|
||||
var t = $($(this).text());
|
||||
t.find( 'label' ).each( function() {
|
||||
var th = $(this),
|
||||
val = th.find('input').val(),
|
||||
id = th.find('input')[0].id,
|
||||
name = th.text().trim(),
|
||||
o;
|
||||
$('#' + id).on( 'change', syncChecks );
|
||||
o = $( '<option value="' + parseInt( val, 10 ) + '"></option>' ).text( name );
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiates the list manager.
|
||||
*
|
||||
* @see js/_enqueues/lib/lists.js
|
||||
*/
|
||||
$('#categorychecklist').wpList( {
|
||||
// CSS class name for alternate styling.
|
||||
alt: '',
|
||||
|
||||
// The type of list.
|
||||
what: 'link-category',
|
||||
|
||||
// ID of the element the parsed Ajax response will be stored in.
|
||||
response: 'category-ajax-response',
|
||||
|
||||
// Callback that's run after an item got added to the list.
|
||||
addAfter: catAddAfter
|
||||
} );
|
||||
|
||||
// All categories is the default tab, so we delete the user setting.
|
||||
$('a[href="#categories-all"]').on( 'click', function(){deleteUserSetting('cats');});
|
||||
|
||||
// Set a preference for the popular categories to cookies.
|
||||
$('a[href="#categories-pop"]').on( 'click', function(){setUserSetting('cats','pop');});
|
||||
|
||||
if ( 'pop' == getUserSetting('cats') )
|
||||
$('a[href="#categories-pop"]').trigger( 'click' );
|
||||
|
||||
/**
|
||||
* Adds event handler that shows the interface controls to add a new category.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @param {Event} event The event object.
|
||||
* @return {boolean} Always returns false to prevent regular link
|
||||
* functionality.
|
||||
*/
|
||||
$('#category-add-toggle').on( 'click', function() {
|
||||
$(this).parents('div:first').toggleClass( 'wp-hidden-children' );
|
||||
$('#category-tabs a[href="#categories-all"]').trigger( 'click' );
|
||||
$('#newcategory').trigger( 'focus' );
|
||||
return false;
|
||||
} );
|
||||
|
||||
$('.categorychecklist :checkbox').on( 'change', syncChecks ).filter( ':checked' ).trigger( 'change' );
|
||||
});
|
2
wp-admin/js/link.min.js
vendored
Normal file
2
wp-admin/js/link.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
jQuery(function(a){var t,c,e,i=!1;a("#link_name").trigger("focus"),postboxes.add_postbox_toggles("link"),a("#category-tabs a").on("click",function(){var t=a(this).attr("href");return a(this).parent().addClass("tabs").siblings("li").removeClass("tabs"),a(".tabs-panel").hide(),a(t).show(),"#categories-all"==t?deleteUserSetting("cats"):setUserSetting("cats","pop"),!1}),getUserSetting("cats")&&a('#category-tabs a[href="#categories-pop"]').trigger("click"),t=a("#newcat").one("focus",function(){a(this).val("").removeClass("form-input-tip")}),a("#link-category-add-submit").on("click",function(){t.focus()}),c=function(){var t,e;i||(i=!0,t=(e=a(this)).is(":checked"),e=e.val().toString(),a("#in-link-category-"+e+", #in-popular-link_category-"+e).prop("checked",t),i=!1)},e=function(t,e){a(e.what+" response_data",t).each(function(){a(a(this).text()).find("label").each(function(){var t=a(this),e=t.find("input").val(),i=t.find("input")[0].id,t=t.text().trim();a("#"+i).on("change",c),a('<option value="'+parseInt(e,10)+'"></option>').text(t)})})},a("#categorychecklist").wpList({alt:"",what:"link-category",response:"category-ajax-response",addAfter:e}),a('a[href="#categories-all"]').on("click",function(){deleteUserSetting("cats")}),a('a[href="#categories-pop"]').on("click",function(){setUserSetting("cats","pop")}),"pop"==getUserSetting("cats")&&a('a[href="#categories-pop"]').trigger("click"),a("#category-add-toggle").on("click",function(){return a(this).parents("div:first").toggleClass("wp-hidden-children"),a('#category-tabs a[href="#categories-all"]').trigger("click"),a("#newcategory").trigger("focus"),!1}),a(".categorychecklist :checkbox").on("change",c).filter(":checked").trigger("change")});
|
43
wp-admin/js/media-gallery.js
Normal file
43
wp-admin/js/media-gallery.js
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* This file is used on media-upload.php which has been replaced by media-new.php and upload.php
|
||||
*
|
||||
* @deprecated 3.5.0
|
||||
* @output wp-admin/js/media-gallery.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl */
|
||||
jQuery(function($) {
|
||||
/**
|
||||
* Adds a click event handler to the element with a 'wp-gallery' class.
|
||||
*/
|
||||
$( 'body' ).on( 'click.wp-gallery', function(e) {
|
||||
var target = $( e.target ), id, img_size, nonceValue;
|
||||
|
||||
if ( target.hasClass( 'wp-set-header' ) ) {
|
||||
// Opens the image to preview it full size.
|
||||
( window.dialogArguments || opener || parent || top ).location.href = target.data( 'location' );
|
||||
e.preventDefault();
|
||||
} else if ( target.hasClass( 'wp-set-background' ) ) {
|
||||
// Sets the image as background of the theme.
|
||||
id = target.data( 'attachment-id' );
|
||||
img_size = $( 'input[name="attachments[' + id + '][image-size]"]:checked').val();
|
||||
nonceValue = $( '#_wpnonce' ).val() && '';
|
||||
|
||||
/**
|
||||
* This Ajax action has been deprecated since 3.5.0, see custom-background.php
|
||||
*/
|
||||
jQuery.post(ajaxurl, {
|
||||
action: 'set-background-image',
|
||||
attachment_id: id,
|
||||
_ajax_nonce: nonceValue,
|
||||
size: img_size
|
||||
}, function() {
|
||||
var win = window.dialogArguments || opener || parent || top;
|
||||
win.tb_remove();
|
||||
win.location.reload();
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
2
wp-admin/js/media-gallery.min.js
vendored
Normal file
2
wp-admin/js/media-gallery.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
jQuery(function(o){o("body").on("click.wp-gallery",function(a){var e,t,n=o(a.target);n.hasClass("wp-set-header")?((window.dialogArguments||opener||parent||top).location.href=n.data("location"),a.preventDefault()):n.hasClass("wp-set-background")&&(n=n.data("attachment-id"),e=o('input[name="attachments['+n+'][image-size]"]:checked').val(),t=o("#_wpnonce").val()&&"",jQuery.post(ajaxurl,{action:"set-background-image",attachment_id:n,_ajax_nonce:t,size:e},function(){var a=window.dialogArguments||opener||parent||top;a.tb_remove(),a.location.reload()}),a.preventDefault())})});
|
113
wp-admin/js/media-upload.js
Normal file
113
wp-admin/js/media-upload.js
Normal file
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Contains global functions for the media upload within the post edit screen.
|
||||
*
|
||||
* Updates the ThickBox anchor href and the ThickBox's own properties in order
|
||||
* to set the size and position on every resize event. Also adds a function to
|
||||
* send HTML or text to the currently active editor.
|
||||
*
|
||||
* @file
|
||||
* @since 2.5.0
|
||||
* @output wp-admin/js/media-upload.js
|
||||
*
|
||||
* @requires jQuery
|
||||
*/
|
||||
|
||||
/* global tinymce, QTags, wpActiveEditor, tb_position */
|
||||
|
||||
/**
|
||||
* Sends the HTML passed in the parameters to TinyMCE.
|
||||
*
|
||||
* @since 2.5.0
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @param {string} html The HTML to be sent to the editor.
|
||||
* @return {void|boolean} Returns false when both TinyMCE and QTags instances
|
||||
* are unavailable. This means that the HTML was not
|
||||
* sent to the editor.
|
||||
*/
|
||||
window.send_to_editor = function( html ) {
|
||||
var editor,
|
||||
hasTinymce = typeof tinymce !== 'undefined',
|
||||
hasQuicktags = typeof QTags !== 'undefined';
|
||||
|
||||
// If no active editor is set, try to set it.
|
||||
if ( ! wpActiveEditor ) {
|
||||
if ( hasTinymce && tinymce.activeEditor ) {
|
||||
editor = tinymce.activeEditor;
|
||||
window.wpActiveEditor = editor.id;
|
||||
} else if ( ! hasQuicktags ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( hasTinymce ) {
|
||||
editor = tinymce.get( wpActiveEditor );
|
||||
}
|
||||
|
||||
// If the editor is set and not hidden,
|
||||
// insert the HTML into the content of the editor.
|
||||
if ( editor && ! editor.isHidden() ) {
|
||||
editor.execCommand( 'mceInsertContent', false, html );
|
||||
} else if ( hasQuicktags ) {
|
||||
// If quick tags are available, insert the HTML into its content.
|
||||
QTags.insertContent( html );
|
||||
} else {
|
||||
// If neither the TinyMCE editor and the quick tags are available,
|
||||
// add the HTML to the current active editor.
|
||||
document.getElementById( wpActiveEditor ).value += html;
|
||||
}
|
||||
|
||||
// If the old thickbox remove function exists, call it.
|
||||
if ( window.tb_remove ) {
|
||||
try { window.tb_remove(); } catch( e ) {}
|
||||
}
|
||||
};
|
||||
|
||||
(function($) {
|
||||
/**
|
||||
* Recalculates and applies the new ThickBox position based on the current
|
||||
* window size.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @return {Object[]} Array containing jQuery objects for all the found
|
||||
* ThickBox anchors.
|
||||
*/
|
||||
window.tb_position = function() {
|
||||
var tbWindow = $('#TB_window'),
|
||||
width = $(window).width(),
|
||||
H = $(window).height(),
|
||||
W = ( 833 < width ) ? 833 : width,
|
||||
adminbar_height = 0;
|
||||
|
||||
if ( $('#wpadminbar').length ) {
|
||||
adminbar_height = parseInt( $('#wpadminbar').css('height'), 10 );
|
||||
}
|
||||
|
||||
if ( tbWindow.length ) {
|
||||
tbWindow.width( W - 50 ).height( H - 45 - adminbar_height );
|
||||
$('#TB_iframeContent').width( W - 50 ).height( H - 75 - adminbar_height );
|
||||
tbWindow.css({'margin-left': '-' + parseInt( ( ( W - 50 ) / 2 ), 10 ) + 'px'});
|
||||
if ( typeof document.body.style.maxWidth !== 'undefined' )
|
||||
tbWindow.css({'top': 20 + adminbar_height + 'px', 'margin-top': '0'});
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculates the new height and width for all links with a ThickBox class.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
return $('a.thickbox').each( function() {
|
||||
var href = $(this).attr('href');
|
||||
if ( ! href ) return;
|
||||
href = href.replace(/&width=[0-9]+/g, '');
|
||||
href = href.replace(/&height=[0-9]+/g, '');
|
||||
$(this).attr( 'href', href + '&width=' + ( W - 80 ) + '&height=' + ( H - 85 - adminbar_height ) );
|
||||
});
|
||||
};
|
||||
|
||||
// Add handler to recalculates the ThickBox position when the window is resized.
|
||||
$(window).on( 'resize', function(){ tb_position(); });
|
||||
|
||||
})(jQuery);
|
2
wp-admin/js/media-upload.min.js
vendored
Normal file
2
wp-admin/js/media-upload.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
window.send_to_editor=function(t){var e,i="undefined"!=typeof tinymce,n="undefined"!=typeof QTags;if(wpActiveEditor)i&&(e=tinymce.get(wpActiveEditor));else if(i&&tinymce.activeEditor)e=tinymce.activeEditor,window.wpActiveEditor=e.id;else if(!n)return!1;if(e&&!e.isHidden()?e.execCommand("mceInsertContent",!1,t):n?QTags.insertContent(t):document.getElementById(wpActiveEditor).value+=t,window.tb_remove)try{window.tb_remove()}catch(t){}},function(d){window.tb_position=function(){var t=d("#TB_window"),e=d(window).width(),i=d(window).height(),n=833<e?833:e,o=0;return d("#wpadminbar").length&&(o=parseInt(d("#wpadminbar").css("height"),10)),t.length&&(t.width(n-50).height(i-45-o),d("#TB_iframeContent").width(n-50).height(i-75-o),t.css({"margin-left":"-"+parseInt((n-50)/2,10)+"px"}),void 0!==document.body.style.maxWidth)&&t.css({top:20+o+"px","margin-top":"0"}),d("a.thickbox").each(function(){var t=d(this).attr("href");t&&(t=(t=t.replace(/&width=[0-9]+/g,"")).replace(/&height=[0-9]+/g,""),d(this).attr("href",t+"&width="+(n-80)+"&height="+(i-85-o)))})},d(window).on("resize",function(){tb_position()})}(jQuery);
|
240
wp-admin/js/media.js
Normal file
240
wp-admin/js/media.js
Normal file
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Creates a dialog containing posts that can have a particular media attached
|
||||
* to it.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @output wp-admin/js/media.js
|
||||
*
|
||||
* @namespace findPosts
|
||||
*
|
||||
* @requires jQuery
|
||||
*/
|
||||
|
||||
/* global ajaxurl, _wpMediaGridSettings, showNotice, findPosts, ClipboardJS */
|
||||
|
||||
( function( $ ){
|
||||
window.findPosts = {
|
||||
/**
|
||||
* Opens a dialog to attach media to a post.
|
||||
*
|
||||
* Adds an overlay prior to retrieving a list of posts to attach the media to.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberOf findPosts
|
||||
*
|
||||
* @param {string} af_name The name of the affected element.
|
||||
* @param {string} af_val The value of the affected post element.
|
||||
*
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
open: function( af_name, af_val ) {
|
||||
var overlay = $( '.ui-find-overlay' );
|
||||
|
||||
if ( overlay.length === 0 ) {
|
||||
$( 'body' ).append( '<div class="ui-find-overlay"></div>' );
|
||||
findPosts.overlay();
|
||||
}
|
||||
|
||||
overlay.show();
|
||||
|
||||
if ( af_name && af_val ) {
|
||||
// #affected is a hidden input field in the dialog that keeps track of which media should be attached.
|
||||
$( '#affected' ).attr( 'name', af_name ).val( af_val );
|
||||
}
|
||||
|
||||
$( '#find-posts' ).show();
|
||||
|
||||
// Close the dialog when the escape key is pressed.
|
||||
$('#find-posts-input').trigger( 'focus' ).on( 'keyup', function( event ){
|
||||
if ( event.which == 27 ) {
|
||||
findPosts.close();
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieves a list of applicable posts for media attachment and shows them.
|
||||
findPosts.send();
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the found posts lists before hiding the attach media dialog.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberOf findPosts
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
close: function() {
|
||||
$('#find-posts-response').empty();
|
||||
$('#find-posts').hide();
|
||||
$( '.ui-find-overlay' ).hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Binds a click event listener to the overlay which closes the attach media
|
||||
* dialog.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @memberOf findPosts
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
overlay: function() {
|
||||
$( '.ui-find-overlay' ).on( 'click', function () {
|
||||
findPosts.close();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves and displays posts based on the search term.
|
||||
*
|
||||
* Sends a post request to the admin_ajax.php, requesting posts based on the
|
||||
* search term provided by the user. Defaults to all posts if no search term is
|
||||
* provided.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberOf findPosts
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
send: function() {
|
||||
var post = {
|
||||
ps: $( '#find-posts-input' ).val(),
|
||||
action: 'find_posts',
|
||||
_ajax_nonce: $('#_ajax_nonce').val()
|
||||
},
|
||||
spinner = $( '.find-box-search .spinner' );
|
||||
|
||||
spinner.addClass( 'is-active' );
|
||||
|
||||
/**
|
||||
* Send a POST request to admin_ajax.php, hide the spinner and replace the list
|
||||
* of posts with the response data. If an error occurs, display it.
|
||||
*/
|
||||
$.ajax( ajaxurl, {
|
||||
type: 'POST',
|
||||
data: post,
|
||||
dataType: 'json'
|
||||
}).always( function() {
|
||||
spinner.removeClass( 'is-active' );
|
||||
}).done( function( x ) {
|
||||
if ( ! x.success ) {
|
||||
$( '#find-posts-response' ).text( wp.i18n.__( 'An error has occurred. Please reload the page and try again.' ) );
|
||||
}
|
||||
|
||||
$( '#find-posts-response' ).html( x.data );
|
||||
}).fail( function() {
|
||||
$( '#find-posts-response' ).text( wp.i18n.__( 'An error has occurred. Please reload the page and try again.' ) );
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the file once the DOM is fully loaded and attaches events to the
|
||||
* various form elements.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( function() {
|
||||
var settings,
|
||||
$mediaGridWrap = $( '#wp-media-grid' ),
|
||||
copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.media-library' ),
|
||||
copyAttachmentURLSuccessTimeout;
|
||||
|
||||
// Opens a manage media frame into the grid.
|
||||
if ( $mediaGridWrap.length && window.wp && window.wp.media ) {
|
||||
settings = _wpMediaGridSettings;
|
||||
|
||||
var frame = window.wp.media({
|
||||
frame: 'manage',
|
||||
container: $mediaGridWrap,
|
||||
library: settings.queryVars
|
||||
}).open();
|
||||
|
||||
// Fire a global ready event.
|
||||
$mediaGridWrap.trigger( 'wp-media-grid-ready', frame );
|
||||
}
|
||||
|
||||
// Prevents form submission if no post has been selected.
|
||||
$( '#find-posts-submit' ).on( 'click', function( event ) {
|
||||
if ( ! $( '#find-posts-response input[type="radio"]:checked' ).length )
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Submits the search query when hitting the enter key in the search input.
|
||||
$( '#find-posts .find-box-search :input' ).on( 'keypress', function( event ) {
|
||||
if ( 13 == event.which ) {
|
||||
findPosts.send();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Binds the click event to the search button.
|
||||
$( '#find-posts-search' ).on( 'click', findPosts.send );
|
||||
|
||||
// Binds the close dialog click event.
|
||||
$( '#find-posts-close' ).on( 'click', findPosts.close );
|
||||
|
||||
// Binds the bulk action events to the submit buttons.
|
||||
$( '#doaction' ).on( 'click', function( event ) {
|
||||
|
||||
/*
|
||||
* Handle the bulk action based on its value.
|
||||
*/
|
||||
$( 'select[name="action"]' ).each( function() {
|
||||
var optionValue = $( this ).val();
|
||||
|
||||
if ( 'attach' === optionValue ) {
|
||||
event.preventDefault();
|
||||
findPosts.open();
|
||||
} else if ( 'delete' === optionValue ) {
|
||||
if ( ! showNotice.warn() ) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Enables clicking on the entire table row.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( '.find-box-inside' ).on( 'click', 'tr', function() {
|
||||
$( this ).find( '.found-radio input' ).prop( 'checked', true );
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles media list copy media URL button.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param {MouseEvent} event A click event.
|
||||
* @return {void}
|
||||
*/
|
||||
copyAttachmentURLClipboard.on( 'success', function( event ) {
|
||||
var triggerElement = $( event.trigger ),
|
||||
successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
|
||||
|
||||
// Clear the selection and move focus back to the trigger.
|
||||
event.clearSelection();
|
||||
|
||||
// Show success visual feedback.
|
||||
clearTimeout( copyAttachmentURLSuccessTimeout );
|
||||
successElement.removeClass( 'hidden' );
|
||||
|
||||
// Hide success visual feedback after 3 seconds since last success and unfocus the trigger.
|
||||
copyAttachmentURLSuccessTimeout = setTimeout( function() {
|
||||
successElement.addClass( 'hidden' );
|
||||
}, 3000 );
|
||||
|
||||
// Handle success audible feedback.
|
||||
wp.a11y.speak( wp.i18n.__( 'The file URL has been copied to your clipboard' ) );
|
||||
} );
|
||||
});
|
||||
})( jQuery );
|
2
wp-admin/js/media.min.js
vendored
Normal file
2
wp-admin/js/media.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(s){window.findPosts={open:function(n,e){var i=s(".ui-find-overlay");return 0===i.length&&(s("body").append('<div class="ui-find-overlay"></div>'),findPosts.overlay()),i.show(),n&&e&&s("#affected").attr("name",n).val(e),s("#find-posts").show(),s("#find-posts-input").trigger("focus").on("keyup",function(n){27==n.which&&findPosts.close()}),findPosts.send(),!1},close:function(){s("#find-posts-response").empty(),s("#find-posts").hide(),s(".ui-find-overlay").hide()},overlay:function(){s(".ui-find-overlay").on("click",function(){findPosts.close()})},send:function(){var n={ps:s("#find-posts-input").val(),action:"find_posts",_ajax_nonce:s("#_ajax_nonce").val()},e=s(".find-box-search .spinner");e.addClass("is-active"),s.ajax(ajaxurl,{type:"POST",data:n,dataType:"json"}).always(function(){e.removeClass("is-active")}).done(function(n){n.success||s("#find-posts-response").text(wp.i18n.__("An error has occurred. Please reload the page and try again.")),s("#find-posts-response").html(n.data)}).fail(function(){s("#find-posts-response").text(wp.i18n.__("An error has occurred. Please reload the page and try again."))})}},s(function(){var o,n,e=s("#wp-media-grid"),i=new ClipboardJS(".copy-attachment-url.media-library");e.length&&window.wp&&window.wp.media&&(n=_wpMediaGridSettings,n=window.wp.media({frame:"manage",container:e,library:n.queryVars}).open(),e.trigger("wp-media-grid-ready",n)),s("#find-posts-submit").on("click",function(n){s('#find-posts-response input[type="radio"]:checked').length||n.preventDefault()}),s("#find-posts .find-box-search :input").on("keypress",function(n){if(13==n.which)return findPosts.send(),!1}),s("#find-posts-search").on("click",findPosts.send),s("#find-posts-close").on("click",findPosts.close),s("#doaction").on("click",function(e){s('select[name="action"]').each(function(){var n=s(this).val();"attach"===n?(e.preventDefault(),findPosts.open()):"delete"!==n||showNotice.warn()||e.preventDefault()})}),s(".find-box-inside").on("click","tr",function(){s(this).find(".found-radio input").prop("checked",!0)}),i.on("success",function(n){var e=s(n.trigger),i=s(".success",e.closest(".copy-to-clipboard-container"));n.clearSelection(),clearTimeout(o),i.removeClass("hidden"),o=setTimeout(function(){i.addClass("hidden")},3e3),wp.a11y.speak(wp.i18n.__("The file URL has been copied to your clipboard"))})})}(jQuery);
|
1575
wp-admin/js/nav-menu.js
Normal file
1575
wp-admin/js/nav-menu.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/nav-menu.min.js
vendored
Normal file
2
wp-admin/js/nav-menu.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
149
wp-admin/js/password-strength-meter.js
Normal file
149
wp-admin/js/password-strength-meter.js
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @output wp-admin/js/password-strength-meter.js
|
||||
*/
|
||||
|
||||
/* global zxcvbn */
|
||||
window.wp = window.wp || {};
|
||||
|
||||
(function($){
|
||||
var __ = wp.i18n.__,
|
||||
sprintf = wp.i18n.sprintf;
|
||||
|
||||
/**
|
||||
* Contains functions to determine the password strength.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
wp.passwordStrength = {
|
||||
/**
|
||||
* Determines the strength of a given password.
|
||||
*
|
||||
* Compares first password to the password confirmation.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @param {string} password1 The subject password.
|
||||
* @param {Array} disallowedList An array of words that will lower the entropy of
|
||||
* the password.
|
||||
* @param {string} password2 The password confirmation.
|
||||
*
|
||||
* @return {number} The password strength score.
|
||||
*/
|
||||
meter : function( password1, disallowedList, password2 ) {
|
||||
if ( ! Array.isArray( disallowedList ) )
|
||||
disallowedList = [ disallowedList.toString() ];
|
||||
|
||||
if (password1 != password2 && password2 && password2.length > 0)
|
||||
return 5;
|
||||
|
||||
if ( 'undefined' === typeof window.zxcvbn ) {
|
||||
// Password strength unknown.
|
||||
return -1;
|
||||
}
|
||||
|
||||
var result = zxcvbn( password1, disallowedList );
|
||||
return result.score;
|
||||
},
|
||||
|
||||
/**
|
||||
* Builds an array of words that should be penalized.
|
||||
*
|
||||
* Certain words need to be penalized because it would lower the entropy of a
|
||||
* password if they were used. The disallowedList is based on user input fields such
|
||||
* as username, first name, email etc.
|
||||
*
|
||||
* @since 3.7.0
|
||||
* @deprecated 5.5.0 Use {@see 'userInputDisallowedList()'} instead.
|
||||
*
|
||||
* @return {string[]} The array of words to be disallowed.
|
||||
*/
|
||||
userInputBlacklist : function() {
|
||||
window.console.log(
|
||||
sprintf(
|
||||
/* translators: 1: Deprecated function name, 2: Version number, 3: Alternative function name. */
|
||||
__( '%1$s is deprecated since version %2$s! Use %3$s instead. Please consider writing more inclusive code.' ),
|
||||
'wp.passwordStrength.userInputBlacklist()',
|
||||
'5.5.0',
|
||||
'wp.passwordStrength.userInputDisallowedList()'
|
||||
)
|
||||
);
|
||||
|
||||
return wp.passwordStrength.userInputDisallowedList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Builds an array of words that should be penalized.
|
||||
*
|
||||
* Certain words need to be penalized because it would lower the entropy of a
|
||||
* password if they were used. The disallowed list is based on user input fields such
|
||||
* as username, first name, email etc.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @return {string[]} The array of words to be disallowed.
|
||||
*/
|
||||
userInputDisallowedList : function() {
|
||||
var i, userInputFieldsLength, rawValuesLength, currentField,
|
||||
rawValues = [],
|
||||
disallowedList = [],
|
||||
userInputFields = [ 'user_login', 'first_name', 'last_name', 'nickname', 'display_name', 'email', 'url', 'description', 'weblog_title', 'admin_email' ];
|
||||
|
||||
// Collect all the strings we want to disallow.
|
||||
rawValues.push( document.title );
|
||||
rawValues.push( document.URL );
|
||||
|
||||
userInputFieldsLength = userInputFields.length;
|
||||
for ( i = 0; i < userInputFieldsLength; i++ ) {
|
||||
currentField = $( '#' + userInputFields[ i ] );
|
||||
|
||||
if ( 0 === currentField.length ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rawValues.push( currentField[0].defaultValue );
|
||||
rawValues.push( currentField.val() );
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip out non-alphanumeric characters and convert each word to an
|
||||
* individual entry.
|
||||
*/
|
||||
rawValuesLength = rawValues.length;
|
||||
for ( i = 0; i < rawValuesLength; i++ ) {
|
||||
if ( rawValues[ i ] ) {
|
||||
disallowedList = disallowedList.concat( rawValues[ i ].replace( /\W/g, ' ' ).split( ' ' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove empty values, short words and duplicates. Short words are likely to
|
||||
* cause many false positives.
|
||||
*/
|
||||
disallowedList = $.grep( disallowedList, function( value, key ) {
|
||||
if ( '' === value || 4 > value.length ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $.inArray( value, disallowedList ) === key;
|
||||
});
|
||||
|
||||
return disallowedList;
|
||||
}
|
||||
};
|
||||
|
||||
// Backward compatibility.
|
||||
|
||||
/**
|
||||
* Password strength meter function.
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @deprecated 3.7.0 Use wp.passwordStrength.meter instead.
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @type {wp.passwordStrength.meter}
|
||||
*/
|
||||
window.passwordStrength = wp.passwordStrength.meter;
|
||||
})(jQuery);
|
2
wp-admin/js/password-strength-meter.min.js
vendored
Normal file
2
wp-admin/js/password-strength-meter.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
window.wp=window.wp||{},function(a){var e=wp.i18n.__,n=wp.i18n.sprintf;wp.passwordStrength={meter:function(e,n,t){return Array.isArray(n)||(n=[n.toString()]),e!=t&&t&&0<t.length?5:void 0===window.zxcvbn?-1:zxcvbn(e,n).score},userInputBlacklist:function(){return window.console.log(n(e("%1$s is deprecated since version %2$s! Use %3$s instead. Please consider writing more inclusive code."),"wp.passwordStrength.userInputBlacklist()","5.5.0","wp.passwordStrength.userInputDisallowedList()")),wp.passwordStrength.userInputDisallowedList()},userInputDisallowedList:function(){var e,n,t,r,s=[],i=[],o=["user_login","first_name","last_name","nickname","display_name","email","url","description","weblog_title","admin_email"];for(s.push(document.title),s.push(document.URL),n=o.length,e=0;e<n;e++)0!==(r=a("#"+o[e])).length&&(s.push(r[0].defaultValue),s.push(r.val()));for(t=s.length,e=0;e<t;e++)s[e]&&(i=i.concat(s[e].replace(/\W/g," ").split(" ")));return i=a.grep(i,function(e,n){return!(""===e||e.length<4)&&a.inArray(e,i)===n})}},window.passwordStrength=wp.passwordStrength.meter}(jQuery);
|
40
wp-admin/js/password-toggle.js
Normal file
40
wp-admin/js/password-toggle.js
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Adds functionality for password visibility buttons to toggle between text and password input types.
|
||||
*
|
||||
* @since 6.3.0
|
||||
* @output wp-admin/js/password-toggle.js
|
||||
*/
|
||||
|
||||
( function () {
|
||||
var toggleElements, status, input, icon, label, __ = wp.i18n.__;
|
||||
|
||||
toggleElements = document.querySelectorAll( '.pwd-toggle' );
|
||||
|
||||
toggleElements.forEach( function (toggle) {
|
||||
toggle.classList.remove( 'hide-if-no-js' );
|
||||
toggle.addEventListener( 'click', togglePassword );
|
||||
} );
|
||||
|
||||
function togglePassword() {
|
||||
status = this.getAttribute( 'data-toggle' );
|
||||
input = this.parentElement.children.namedItem( 'pwd' );
|
||||
icon = this.getElementsByClassName( 'dashicons' )[ 0 ];
|
||||
label = this.getElementsByClassName( 'text' )[ 0 ];
|
||||
|
||||
if ( 0 === parseInt( status, 10 ) ) {
|
||||
this.setAttribute( 'data-toggle', 1 );
|
||||
this.setAttribute( 'aria-label', __( 'Hide password' ) );
|
||||
input.setAttribute( 'type', 'text' );
|
||||
label.innerHTML = __( 'Hide' );
|
||||
icon.classList.remove( 'dashicons-visibility' );
|
||||
icon.classList.add( 'dashicons-hidden' );
|
||||
} else {
|
||||
this.setAttribute( 'data-toggle', 0 );
|
||||
this.setAttribute( 'aria-label', __( 'Show password' ) );
|
||||
input.setAttribute( 'type', 'password' );
|
||||
label.innerHTML = __( 'Show' );
|
||||
icon.classList.remove( 'dashicons-hidden' );
|
||||
icon.classList.add( 'dashicons-visibility' );
|
||||
}
|
||||
}
|
||||
} )();
|
2
wp-admin/js/password-toggle.min.js
vendored
Normal file
2
wp-admin/js/password-toggle.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(){var t,e,s,i,a=wp.i18n.__;function d(){t=this.getAttribute("data-toggle"),e=this.parentElement.children.namedItem("pwd"),s=this.getElementsByClassName("dashicons")[0],i=this.getElementsByClassName("text")[0],0===parseInt(t,10)?(this.setAttribute("data-toggle",1),this.setAttribute("aria-label",a("Hide password")),e.setAttribute("type","text"),i.innerHTML=a("Hide"),s.classList.remove("dashicons-visibility"),s.classList.add("dashicons-hidden")):(this.setAttribute("data-toggle",0),this.setAttribute("aria-label",a("Show password")),e.setAttribute("type","password"),i.innerHTML=a("Show"),s.classList.remove("dashicons-hidden"),s.classList.add("dashicons-visibility"))}document.querySelectorAll(".pwd-toggle").forEach(function(t){t.classList.remove("hide-if-no-js"),t.addEventListener("click",d)})}();
|
229
wp-admin/js/plugin-install.js
Normal file
229
wp-admin/js/plugin-install.js
Normal file
@ -0,0 +1,229 @@
|
||||
/**
|
||||
* @file Functionality for the plugin install screens.
|
||||
*
|
||||
* @output wp-admin/js/plugin-install.js
|
||||
*/
|
||||
|
||||
/* global tb_click, tb_remove, tb_position */
|
||||
|
||||
jQuery( function( $ ) {
|
||||
|
||||
var tbWindow,
|
||||
$iframeBody,
|
||||
$tabbables,
|
||||
$firstTabbable,
|
||||
$lastTabbable,
|
||||
$focusedBefore = $(),
|
||||
$uploadViewToggle = $( '.upload-view-toggle' ),
|
||||
$wrap = $ ( '.wrap' ),
|
||||
$body = $( document.body );
|
||||
|
||||
window.tb_position = function() {
|
||||
var width = $( window ).width(),
|
||||
H = $( window ).height() - ( ( 792 < width ) ? 60 : 20 ),
|
||||
W = ( 792 < width ) ? 772 : width - 20;
|
||||
|
||||
tbWindow = $( '#TB_window' );
|
||||
|
||||
if ( tbWindow.length ) {
|
||||
tbWindow.width( W ).height( H );
|
||||
$( '#TB_iframeContent' ).width( W ).height( H );
|
||||
tbWindow.css({
|
||||
'margin-left': '-' + parseInt( ( W / 2 ), 10 ) + 'px'
|
||||
});
|
||||
if ( typeof document.body.style.maxWidth !== 'undefined' ) {
|
||||
tbWindow.css({
|
||||
'top': '30px',
|
||||
'margin-top': '0'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return $( 'a.thickbox' ).each( function() {
|
||||
var href = $( this ).attr( 'href' );
|
||||
if ( ! href ) {
|
||||
return;
|
||||
}
|
||||
href = href.replace( /&width=[0-9]+/g, '' );
|
||||
href = href.replace( /&height=[0-9]+/g, '' );
|
||||
$(this).attr( 'href', href + '&width=' + W + '&height=' + ( H ) );
|
||||
});
|
||||
};
|
||||
|
||||
$( window ).on( 'resize', function() {
|
||||
tb_position();
|
||||
});
|
||||
|
||||
/*
|
||||
* Custom events: when a Thickbox iframe has loaded and when the Thickbox
|
||||
* modal gets removed from the DOM.
|
||||
*/
|
||||
$body
|
||||
.on( 'thickbox:iframe:loaded', tbWindow, function() {
|
||||
/*
|
||||
* Return if it's not the modal with the plugin details iframe. Other
|
||||
* thickbox instances might want to load an iframe with content from
|
||||
* an external domain. Avoid to access the iframe contents when we're
|
||||
* not sure the iframe loads from the same domain.
|
||||
*/
|
||||
if ( ! tbWindow.hasClass( 'plugin-details-modal' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
iframeLoaded();
|
||||
})
|
||||
.on( 'thickbox:removed', function() {
|
||||
// Set focus back to the element that opened the modal dialog.
|
||||
// Note: IE 8 would need this wrapped in a fake setTimeout `0`.
|
||||
$focusedBefore.trigger( 'focus' );
|
||||
});
|
||||
|
||||
function iframeLoaded() {
|
||||
var $iframe = tbWindow.find( '#TB_iframeContent' );
|
||||
|
||||
// Get the iframe body.
|
||||
$iframeBody = $iframe.contents().find( 'body' );
|
||||
|
||||
// Get the tabbable elements and handle the keydown event on first load.
|
||||
handleTabbables();
|
||||
|
||||
// Set initial focus on the "Close" button.
|
||||
$firstTabbable.trigger( 'focus' );
|
||||
|
||||
/*
|
||||
* When the "Install" button is disabled (e.g. the Plugin is already installed)
|
||||
* then we can't predict where the last focusable element is. We need to get
|
||||
* the tabbable elements and handle the keydown event again and again,
|
||||
* each time the active tab panel changes.
|
||||
*/
|
||||
$( '#plugin-information-tabs a', $iframeBody ).on( 'click', function() {
|
||||
handleTabbables();
|
||||
});
|
||||
|
||||
// Close the modal when pressing Escape.
|
||||
$iframeBody.on( 'keydown', function( event ) {
|
||||
if ( 27 !== event.which ) {
|
||||
return;
|
||||
}
|
||||
tb_remove();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the tabbable elements and detach/attach the keydown event.
|
||||
* Called after the iframe has fully loaded so we have all the elements we need.
|
||||
* Called again each time a Tab gets clicked.
|
||||
* @todo Consider to implement a WordPress general utility for this and don't use jQuery UI.
|
||||
*/
|
||||
function handleTabbables() {
|
||||
var $firstAndLast;
|
||||
// Get all the tabbable elements.
|
||||
$tabbables = $( ':tabbable', $iframeBody );
|
||||
// Our first tabbable element is always the "Close" button.
|
||||
$firstTabbable = tbWindow.find( '#TB_closeWindowButton' );
|
||||
// Get the last tabbable element.
|
||||
$lastTabbable = $tabbables.last();
|
||||
// Make a jQuery collection.
|
||||
$firstAndLast = $firstTabbable.add( $lastTabbable );
|
||||
// Detach any previously attached keydown event.
|
||||
$firstAndLast.off( 'keydown.wp-plugin-details' );
|
||||
// Attach again the keydown event on the first and last focusable elements.
|
||||
$firstAndLast.on( 'keydown.wp-plugin-details', function( event ) {
|
||||
constrainTabbing( event );
|
||||
});
|
||||
}
|
||||
|
||||
// Constrain tabbing within the plugin modal dialog.
|
||||
function constrainTabbing( event ) {
|
||||
if ( 9 !== event.which ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $lastTabbable[0] === event.target && ! event.shiftKey ) {
|
||||
event.preventDefault();
|
||||
$firstTabbable.trigger( 'focus' );
|
||||
} else if ( $firstTabbable[0] === event.target && event.shiftKey ) {
|
||||
event.preventDefault();
|
||||
$lastTabbable.trigger( 'focus' );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the Plugin details modal. The event is delegated to get also the links
|
||||
* in the plugins search tab, after the Ajax search rebuilds the HTML. It's
|
||||
* delegated on the closest ancestor and not on the body to avoid conflicts
|
||||
* with other handlers, see Trac ticket #43082.
|
||||
*/
|
||||
$( '.wrap' ).on( 'click', '.thickbox.open-plugin-details-modal', function( e ) {
|
||||
// The `data-title` attribute is used only in the Plugin screens.
|
||||
var title = $( this ).data( 'title' ) ?
|
||||
wp.i18n.sprintf(
|
||||
// translators: %s: Plugin name.
|
||||
wp.i18n.__( 'Plugin: %s' ),
|
||||
$( this ).data( 'title' )
|
||||
) :
|
||||
wp.i18n.__( 'Plugin details' );
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Store the element that has focus before opening the modal dialog, i.e. the control which opens it.
|
||||
$focusedBefore = $( this );
|
||||
|
||||
tb_click.call(this);
|
||||
|
||||
// Set ARIA role, ARIA label, and add a CSS class.
|
||||
tbWindow
|
||||
.attr({
|
||||
'role': 'dialog',
|
||||
'aria-label': wp.i18n.__( 'Plugin details' )
|
||||
})
|
||||
.addClass( 'plugin-details-modal' );
|
||||
|
||||
// Set title attribute on the iframe.
|
||||
tbWindow.find( '#TB_iframeContent' ).attr( 'title', title );
|
||||
});
|
||||
|
||||
/* Plugin install related JS */
|
||||
$( '#plugin-information-tabs a' ).on( 'click', function( event ) {
|
||||
var tab = $( this ).attr( 'name' );
|
||||
event.preventDefault();
|
||||
|
||||
// Flip the tab.
|
||||
$( '#plugin-information-tabs a.current' ).removeClass( 'current' );
|
||||
$( this ).addClass( 'current' );
|
||||
|
||||
// Only show the fyi box in the description section, on smaller screen,
|
||||
// where it's otherwise always displayed at the top.
|
||||
if ( 'description' !== tab && $( window ).width() < 772 ) {
|
||||
$( '#plugin-information-content' ).find( '.fyi' ).hide();
|
||||
} else {
|
||||
$( '#plugin-information-content' ).find( '.fyi' ).show();
|
||||
}
|
||||
|
||||
// Flip the content.
|
||||
$( '#section-holder div.section' ).hide(); // Hide 'em all.
|
||||
$( '#section-' + tab ).show();
|
||||
});
|
||||
|
||||
/*
|
||||
* When a user presses the "Upload Plugin" button, show the upload form in place
|
||||
* rather than sending them to the devoted upload plugin page.
|
||||
* The `?tab=upload` page still exists for no-js support and for plugins that
|
||||
* might access it directly. When we're in this page, let the link behave
|
||||
* like a link. Otherwise we're in the normal plugin installer pages and the
|
||||
* link should behave like a toggle button.
|
||||
*/
|
||||
if ( ! $wrap.hasClass( 'plugin-install-tab-upload' ) ) {
|
||||
$uploadViewToggle
|
||||
.attr({
|
||||
role: 'button',
|
||||
'aria-expanded': 'false'
|
||||
})
|
||||
.on( 'click', function( event ) {
|
||||
event.preventDefault();
|
||||
$body.toggleClass( 'show-upload-view' );
|
||||
$uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
|
||||
});
|
||||
}
|
||||
});
|
2
wp-admin/js/plugin-install.min.js
vendored
Normal file
2
wp-admin/js/plugin-install.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
jQuery(function(e){var o,i,n,a,l,r=e(),s=e(".upload-view-toggle"),t=e(".wrap"),d=e(document.body);function c(){var t;n=e(":tabbable",i),a=o.find("#TB_closeWindowButton"),l=n.last(),(t=a.add(l)).off("keydown.wp-plugin-details"),t.on("keydown.wp-plugin-details",function(t){9===(t=t).which&&(l[0]!==t.target||t.shiftKey?a[0]===t.target&&t.shiftKey&&(t.preventDefault(),l.trigger("focus")):(t.preventDefault(),a.trigger("focus")))})}window.tb_position=function(){var t=e(window).width(),i=e(window).height()-(792<t?60:20),n=792<t?772:t-20;return(o=e("#TB_window")).length&&(o.width(n).height(i),e("#TB_iframeContent").width(n).height(i),o.css({"margin-left":"-"+parseInt(n/2,10)+"px"}),void 0!==document.body.style.maxWidth)&&o.css({top:"30px","margin-top":"0"}),e("a.thickbox").each(function(){var t=e(this).attr("href");t&&(t=(t=t.replace(/&width=[0-9]+/g,"")).replace(/&height=[0-9]+/g,""),e(this).attr("href",t+"&width="+n+"&height="+i))})},e(window).on("resize",function(){tb_position()}),d.on("thickbox:iframe:loaded",o,function(){var t;o.hasClass("plugin-details-modal")&&(t=o.find("#TB_iframeContent"),i=t.contents().find("body"),c(),a.trigger("focus"),e("#plugin-information-tabs a",i).on("click",function(){c()}),i.on("keydown",function(t){27===t.which&&tb_remove()}))}).on("thickbox:removed",function(){r.trigger("focus")}),e(".wrap").on("click",".thickbox.open-plugin-details-modal",function(t){var i=e(this).data("title")?wp.i18n.sprintf(wp.i18n.__("Plugin: %s"),e(this).data("title")):wp.i18n.__("Plugin details");t.preventDefault(),t.stopPropagation(),r=e(this),tb_click.call(this),o.attr({role:"dialog","aria-label":wp.i18n.__("Plugin details")}).addClass("plugin-details-modal"),o.find("#TB_iframeContent").attr("title",i)}),e("#plugin-information-tabs a").on("click",function(t){var i=e(this).attr("name");t.preventDefault(),e("#plugin-information-tabs a.current").removeClass("current"),e(this).addClass("current"),"description"!==i&&e(window).width()<772?e("#plugin-information-content").find(".fyi").hide():e("#plugin-information-content").find(".fyi").show(),e("#section-holder div.section").hide(),e("#section-"+i).show()}),t.hasClass("plugin-install-tab-upload")||s.attr({role:"button","aria-expanded":"false"}).on("click",function(t){t.preventDefault(),d.toggleClass("show-upload-view"),s.attr("aria-expanded",d.hasClass("show-upload-view"))})});
|
1373
wp-admin/js/post.js
Normal file
1373
wp-admin/js/post.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/post.min.js
vendored
Normal file
2
wp-admin/js/post.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
654
wp-admin/js/postbox.js
Normal file
654
wp-admin/js/postbox.js
Normal file
@ -0,0 +1,654 @@
|
||||
/**
|
||||
* Contains the postboxes logic, opening and closing postboxes, reordering and saving
|
||||
* the state and ordering to the database.
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @requires jQuery
|
||||
* @output wp-admin/js/postbox.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, postboxes */
|
||||
|
||||
(function($) {
|
||||
var $document = $( document ),
|
||||
__ = wp.i18n.__;
|
||||
|
||||
/**
|
||||
* This object contains all function to handle the behavior of the post boxes. The post boxes are the boxes you see
|
||||
* around the content on the edit page.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @namespace postboxes
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
window.postboxes = {
|
||||
|
||||
/**
|
||||
* Handles a click on either the postbox heading or the postbox open/close icon.
|
||||
*
|
||||
* Opens or closes the postbox. Expects `this` to equal the clicked element.
|
||||
* Calls postboxes.pbshow if the postbox has been opened, calls postboxes.pbhide
|
||||
* if the postbox has been closed.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @fires postboxes#postbox-toggled
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handle_click : function () {
|
||||
var $el = $( this ),
|
||||
p = $el.closest( '.postbox' ),
|
||||
id = p.attr( 'id' ),
|
||||
ariaExpandedValue;
|
||||
|
||||
if ( 'dashboard_browser_nag' === id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
p.toggleClass( 'closed' );
|
||||
ariaExpandedValue = ! p.hasClass( 'closed' );
|
||||
|
||||
if ( $el.hasClass( 'handlediv' ) ) {
|
||||
// The handle button was clicked.
|
||||
$el.attr( 'aria-expanded', ariaExpandedValue );
|
||||
} else {
|
||||
// The handle heading was clicked.
|
||||
$el.closest( '.postbox' ).find( 'button.handlediv' )
|
||||
.attr( 'aria-expanded', ariaExpandedValue );
|
||||
}
|
||||
|
||||
if ( postboxes.page !== 'press-this' ) {
|
||||
postboxes.save_state( postboxes.page );
|
||||
}
|
||||
|
||||
if ( id ) {
|
||||
if ( !p.hasClass('closed') && typeof postboxes.pbshow === 'function' ) {
|
||||
postboxes.pbshow( id );
|
||||
} else if ( p.hasClass('closed') && typeof postboxes.pbhide === 'function' ) {
|
||||
postboxes.pbhide( id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when a postbox has been opened or closed.
|
||||
*
|
||||
* Contains a jQuery object with the relevant postbox element.
|
||||
*
|
||||
* @since 4.0.0
|
||||
* @ignore
|
||||
*
|
||||
* @event postboxes#postbox-toggled
|
||||
* @type {Object}
|
||||
*/
|
||||
$document.trigger( 'postbox-toggled', p );
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles clicks on the move up/down buttons.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleOrder: function() {
|
||||
var button = $( this ),
|
||||
postbox = button.closest( '.postbox' ),
|
||||
postboxId = postbox.attr( 'id' ),
|
||||
postboxesWithinSortables = postbox.closest( '.meta-box-sortables' ).find( '.postbox:visible' ),
|
||||
postboxesWithinSortablesCount = postboxesWithinSortables.length,
|
||||
postboxWithinSortablesIndex = postboxesWithinSortables.index( postbox ),
|
||||
firstOrLastPositionMessage;
|
||||
|
||||
if ( 'dashboard_browser_nag' === postboxId ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If on the first or last position, do nothing and send an audible message to screen reader users.
|
||||
if ( 'true' === button.attr( 'aria-disabled' ) ) {
|
||||
firstOrLastPositionMessage = button.hasClass( 'handle-order-higher' ) ?
|
||||
__( 'The box is on the first position' ) :
|
||||
__( 'The box is on the last position' );
|
||||
|
||||
wp.a11y.speak( firstOrLastPositionMessage );
|
||||
return;
|
||||
}
|
||||
|
||||
// Move a postbox up.
|
||||
if ( button.hasClass( 'handle-order-higher' ) ) {
|
||||
// If the box is first within a sortable area, move it to the previous sortable area.
|
||||
if ( 0 === postboxWithinSortablesIndex ) {
|
||||
postboxes.handleOrderBetweenSortables( 'previous', button, postbox );
|
||||
return;
|
||||
}
|
||||
|
||||
postbox.prevAll( '.postbox:visible' ).eq( 0 ).before( postbox );
|
||||
button.trigger( 'focus' );
|
||||
postboxes.updateOrderButtonsProperties();
|
||||
postboxes.save_order( postboxes.page );
|
||||
}
|
||||
|
||||
// Move a postbox down.
|
||||
if ( button.hasClass( 'handle-order-lower' ) ) {
|
||||
// If the box is last within a sortable area, move it to the next sortable area.
|
||||
if ( postboxWithinSortablesIndex + 1 === postboxesWithinSortablesCount ) {
|
||||
postboxes.handleOrderBetweenSortables( 'next', button, postbox );
|
||||
return;
|
||||
}
|
||||
|
||||
postbox.nextAll( '.postbox:visible' ).eq( 0 ).after( postbox );
|
||||
button.trigger( 'focus' );
|
||||
postboxes.updateOrderButtonsProperties();
|
||||
postboxes.save_order( postboxes.page );
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves postboxes between the sortables areas.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param {string} position The "previous" or "next" sortables area.
|
||||
* @param {Object} button The jQuery object representing the button that was clicked.
|
||||
* @param {Object} postbox The jQuery object representing the postbox to be moved.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleOrderBetweenSortables: function( position, button, postbox ) {
|
||||
var closestSortablesId = button.closest( '.meta-box-sortables' ).attr( 'id' ),
|
||||
sortablesIds = [],
|
||||
sortablesIndex,
|
||||
detachedPostbox;
|
||||
|
||||
// Get the list of sortables within the page.
|
||||
$( '.meta-box-sortables:visible' ).each( function() {
|
||||
sortablesIds.push( $( this ).attr( 'id' ) );
|
||||
});
|
||||
|
||||
// Return if there's only one visible sortables area, e.g. in the block editor page.
|
||||
if ( 1 === sortablesIds.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the index of the current sortables area within all the sortable areas.
|
||||
sortablesIndex = $.inArray( closestSortablesId, sortablesIds );
|
||||
// Detach the postbox to be moved.
|
||||
detachedPostbox = postbox.detach();
|
||||
|
||||
// Move the detached postbox to its new position.
|
||||
if ( 'previous' === position ) {
|
||||
$( detachedPostbox ).appendTo( '#' + sortablesIds[ sortablesIndex - 1 ] );
|
||||
}
|
||||
|
||||
if ( 'next' === position ) {
|
||||
$( detachedPostbox ).prependTo( '#' + sortablesIds[ sortablesIndex + 1 ] );
|
||||
}
|
||||
|
||||
postboxes._mark_area();
|
||||
button.focus();
|
||||
postboxes.updateOrderButtonsProperties();
|
||||
postboxes.save_order( postboxes.page );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the move buttons properties depending on the postbox position.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
updateOrderButtonsProperties: function() {
|
||||
var firstSortablesId = $( '.meta-box-sortables:visible:first' ).attr( 'id' ),
|
||||
lastSortablesId = $( '.meta-box-sortables:visible:last' ).attr( 'id' ),
|
||||
firstPostbox = $( '.postbox:visible:first' ),
|
||||
lastPostbox = $( '.postbox:visible:last' ),
|
||||
firstPostboxId = firstPostbox.attr( 'id' ),
|
||||
lastPostboxId = lastPostbox.attr( 'id' ),
|
||||
firstPostboxSortablesId = firstPostbox.closest( '.meta-box-sortables' ).attr( 'id' ),
|
||||
lastPostboxSortablesId = lastPostbox.closest( '.meta-box-sortables' ).attr( 'id' ),
|
||||
moveUpButtons = $( '.handle-order-higher' ),
|
||||
moveDownButtons = $( '.handle-order-lower' );
|
||||
|
||||
// Enable all buttons as a reset first.
|
||||
moveUpButtons
|
||||
.attr( 'aria-disabled', 'false' )
|
||||
.removeClass( 'hidden' );
|
||||
moveDownButtons
|
||||
.attr( 'aria-disabled', 'false' )
|
||||
.removeClass( 'hidden' );
|
||||
|
||||
// When there's only one "sortables" area (e.g. in the block editor) and only one visible postbox, hide the buttons.
|
||||
if ( firstSortablesId === lastSortablesId && firstPostboxId === lastPostboxId ) {
|
||||
moveUpButtons.addClass( 'hidden' );
|
||||
moveDownButtons.addClass( 'hidden' );
|
||||
}
|
||||
|
||||
// Set an aria-disabled=true attribute on the first visible "move" buttons.
|
||||
if ( firstSortablesId === firstPostboxSortablesId ) {
|
||||
$( firstPostbox ).find( '.handle-order-higher' ).attr( 'aria-disabled', 'true' );
|
||||
}
|
||||
|
||||
// Set an aria-disabled=true attribute on the last visible "move" buttons.
|
||||
if ( lastSortablesId === lastPostboxSortablesId ) {
|
||||
$( '.postbox:visible .handle-order-lower' ).last().attr( 'aria-disabled', 'true' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds event handlers to all postboxes and screen option on the current page.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @param {string} page The page we are currently on.
|
||||
* @param {Object} [args]
|
||||
* @param {Function} args.pbshow A callback that is called when a postbox opens.
|
||||
* @param {Function} args.pbhide A callback that is called when a postbox closes.
|
||||
* @return {void}
|
||||
*/
|
||||
add_postbox_toggles : function (page, args) {
|
||||
var $handles = $( '.postbox .hndle, .postbox .handlediv' ),
|
||||
$orderButtons = $( '.postbox .handle-order-higher, .postbox .handle-order-lower' );
|
||||
|
||||
this.page = page;
|
||||
this.init( page, args );
|
||||
|
||||
$handles.on( 'click.postboxes', this.handle_click );
|
||||
|
||||
// Handle the order of the postboxes.
|
||||
$orderButtons.on( 'click.postboxes', this.handleOrder );
|
||||
|
||||
/**
|
||||
* @since 2.7.0
|
||||
*/
|
||||
$('.postbox .hndle a').on( 'click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
/**
|
||||
* Hides a postbox.
|
||||
*
|
||||
* Event handler for the postbox dismiss button. After clicking the button
|
||||
* the postbox will be hidden.
|
||||
*
|
||||
* As of WordPress 5.5, this is only used for the browser update nag.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( '.postbox a.dismiss' ).on( 'click.postboxes', function( e ) {
|
||||
var hide_id = $(this).parents('.postbox').attr('id') + '-hide';
|
||||
e.preventDefault();
|
||||
$( '#' + hide_id ).prop('checked', false).triggerHandler('click');
|
||||
});
|
||||
|
||||
/**
|
||||
* Hides the postbox element
|
||||
*
|
||||
* Event handler for the screen options checkboxes. When a checkbox is
|
||||
* clicked this function will hide or show the relevant postboxes.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @ignore
|
||||
*
|
||||
* @fires postboxes#postbox-toggled
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('.hide-postbox-tog').on('click.postboxes', function() {
|
||||
var $el = $(this),
|
||||
boxId = $el.val(),
|
||||
$postbox = $( '#' + boxId );
|
||||
|
||||
if ( $el.prop( 'checked' ) ) {
|
||||
$postbox.show();
|
||||
if ( typeof postboxes.pbshow === 'function' ) {
|
||||
postboxes.pbshow( boxId );
|
||||
}
|
||||
} else {
|
||||
$postbox.hide();
|
||||
if ( typeof postboxes.pbhide === 'function' ) {
|
||||
postboxes.pbhide( boxId );
|
||||
}
|
||||
}
|
||||
|
||||
postboxes.save_state( page );
|
||||
postboxes._mark_area();
|
||||
|
||||
/**
|
||||
* @since 4.0.0
|
||||
* @see postboxes.handle_click
|
||||
*/
|
||||
$document.trigger( 'postbox-toggled', $postbox );
|
||||
});
|
||||
|
||||
/**
|
||||
* Changes the amount of columns based on the layout preferences.
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('.columns-prefs input[type="radio"]').on('click.postboxes', function(){
|
||||
var n = parseInt($(this).val(), 10);
|
||||
|
||||
if ( n ) {
|
||||
postboxes._pb_edit(n);
|
||||
postboxes.save_order( page );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes all the postboxes, mainly their sortable behavior.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @param {string} page The page we are currently on.
|
||||
* @param {Object} [args={}] The arguments for the postbox initializer.
|
||||
* @param {Function} args.pbshow A callback that is called when a postbox opens.
|
||||
* @param {Function} args.pbhide A callback that is called when a postbox
|
||||
* closes.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
init : function(page, args) {
|
||||
var isMobile = $( document.body ).hasClass( 'mobile' ),
|
||||
$handleButtons = $( '.postbox .handlediv' );
|
||||
|
||||
$.extend( this, args || {} );
|
||||
$('.meta-box-sortables').sortable({
|
||||
placeholder: 'sortable-placeholder',
|
||||
connectWith: '.meta-box-sortables',
|
||||
items: '.postbox',
|
||||
handle: '.hndle',
|
||||
cursor: 'move',
|
||||
delay: ( isMobile ? 200 : 0 ),
|
||||
distance: 2,
|
||||
tolerance: 'pointer',
|
||||
forcePlaceholderSize: true,
|
||||
helper: function( event, element ) {
|
||||
/* `helper: 'clone'` is equivalent to `return element.clone();`
|
||||
* Cloning a checked radio and then inserting that clone next to the original
|
||||
* radio unchecks the original radio (since only one of the two can be checked).
|
||||
* We get around this by renaming the helper's inputs' name attributes so that,
|
||||
* when the helper is inserted into the DOM for the sortable, no radios are
|
||||
* duplicated, and no original radio gets unchecked.
|
||||
*/
|
||||
return element.clone()
|
||||
.find( ':input' )
|
||||
.attr( 'name', function( i, currentName ) {
|
||||
return 'sort_' + parseInt( Math.random() * 100000, 10 ).toString() + '_' + currentName;
|
||||
} )
|
||||
.end();
|
||||
},
|
||||
opacity: 0.65,
|
||||
start: function() {
|
||||
$( 'body' ).addClass( 'is-dragging-metaboxes' );
|
||||
// Refresh the cached positions of all the sortable items so that the min-height set while dragging works.
|
||||
$( '.meta-box-sortables' ).sortable( 'refreshPositions' );
|
||||
},
|
||||
stop: function() {
|
||||
var $el = $( this );
|
||||
|
||||
$( 'body' ).removeClass( 'is-dragging-metaboxes' );
|
||||
|
||||
if ( $el.find( '#dashboard_browser_nag' ).is( ':visible' ) && 'dashboard_browser_nag' != this.firstChild.id ) {
|
||||
$el.sortable('cancel');
|
||||
return;
|
||||
}
|
||||
|
||||
postboxes.updateOrderButtonsProperties();
|
||||
postboxes.save_order(page);
|
||||
},
|
||||
receive: function(e,ui) {
|
||||
if ( 'dashboard_browser_nag' == ui.item[0].id )
|
||||
$(ui.sender).sortable('cancel');
|
||||
|
||||
postboxes._mark_area();
|
||||
$document.trigger( 'postbox-moved', ui.item );
|
||||
}
|
||||
});
|
||||
|
||||
if ( isMobile ) {
|
||||
$(document.body).on('orientationchange.postboxes', function(){ postboxes._pb_change(); });
|
||||
this._pb_change();
|
||||
}
|
||||
|
||||
this._mark_area();
|
||||
|
||||
// Update the "move" buttons properties.
|
||||
this.updateOrderButtonsProperties();
|
||||
$document.on( 'postbox-toggled', this.updateOrderButtonsProperties );
|
||||
|
||||
// Set the handle buttons `aria-expanded` attribute initial value on page load.
|
||||
$handleButtons.each( function () {
|
||||
var $el = $( this );
|
||||
$el.attr( 'aria-expanded', ! $el.closest( '.postbox' ).hasClass( 'closed' ) );
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the state of the postboxes to the server.
|
||||
*
|
||||
* It sends two lists, one with all the closed postboxes, one with all the
|
||||
* hidden postboxes.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @param {string} page The page we are currently on.
|
||||
* @return {void}
|
||||
*/
|
||||
save_state : function(page) {
|
||||
var closed, hidden;
|
||||
|
||||
// Return on the nav-menus.php screen, see #35112.
|
||||
if ( 'nav-menus' === page ) {
|
||||
return;
|
||||
}
|
||||
|
||||
closed = $( '.postbox' ).filter( '.closed' ).map( function() { return this.id; } ).get().join( ',' );
|
||||
hidden = $( '.postbox' ).filter( ':hidden' ).map( function() { return this.id; } ).get().join( ',' );
|
||||
|
||||
$.post(ajaxurl, {
|
||||
action: 'closed-postboxes',
|
||||
closed: closed,
|
||||
hidden: hidden,
|
||||
closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
|
||||
page: page
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the order of the postboxes to the server.
|
||||
*
|
||||
* Sends a list of all postboxes inside a sortable area to the server.
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @param {string} page The page we are currently on.
|
||||
* @return {void}
|
||||
*/
|
||||
save_order : function(page) {
|
||||
var postVars, page_columns = $('.columns-prefs input:checked').val() || 0;
|
||||
|
||||
postVars = {
|
||||
action: 'meta-box-order',
|
||||
_ajax_nonce: $('#meta-box-order-nonce').val(),
|
||||
page_columns: page_columns,
|
||||
page: page
|
||||
};
|
||||
|
||||
$('.meta-box-sortables').each( function() {
|
||||
postVars[ 'order[' + this.id.split( '-' )[0] + ']' ] = $( this ).sortable( 'toArray' ).join( ',' );
|
||||
} );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
postVars,
|
||||
function( response ) {
|
||||
if ( response.success ) {
|
||||
wp.a11y.speak( __( 'The boxes order has been saved.' ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Marks empty postbox areas.
|
||||
*
|
||||
* Adds a message to empty sortable areas on the dashboard page. Also adds a
|
||||
* border around the side area on the post edit screen if there are no postboxes
|
||||
* present.
|
||||
*
|
||||
* @since 3.3.0
|
||||
* @access private
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
_mark_area : function() {
|
||||
var visible = $( 'div.postbox:visible' ).length,
|
||||
visibleSortables = $( '#dashboard-widgets .meta-box-sortables:visible, #post-body .meta-box-sortables:visible' ),
|
||||
areAllVisibleSortablesEmpty = true;
|
||||
|
||||
visibleSortables.each( function() {
|
||||
var t = $(this);
|
||||
|
||||
if ( visible == 1 || t.children( '.postbox:visible' ).length ) {
|
||||
t.removeClass('empty-container');
|
||||
areAllVisibleSortablesEmpty = false;
|
||||
}
|
||||
else {
|
||||
t.addClass('empty-container');
|
||||
}
|
||||
});
|
||||
|
||||
postboxes.updateEmptySortablesText( visibleSortables, areAllVisibleSortablesEmpty );
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the text for the empty sortable areas on the Dashboard.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param {Object} visibleSortables The jQuery object representing the visible sortable areas.
|
||||
* @param {boolean} areAllVisibleSortablesEmpty Whether all the visible sortable areas are "empty".
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
updateEmptySortablesText: function( visibleSortables, areAllVisibleSortablesEmpty ) {
|
||||
var isDashboard = $( '#dashboard-widgets' ).length,
|
||||
emptySortableText = areAllVisibleSortablesEmpty ? __( 'Add boxes from the Screen Options menu' ) : __( 'Drag boxes here' );
|
||||
|
||||
if ( ! isDashboard ) {
|
||||
return;
|
||||
}
|
||||
|
||||
visibleSortables.each( function() {
|
||||
if ( $( this ).hasClass( 'empty-container' ) ) {
|
||||
$( this ).attr( 'data-emptyString', emptySortableText );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the amount of columns on the post edit page.
|
||||
*
|
||||
* @since 3.3.0
|
||||
* @access private
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @fires postboxes#postboxes-columnchange
|
||||
*
|
||||
* @param {number} n The amount of columns to divide the post edit page in.
|
||||
* @return {void}
|
||||
*/
|
||||
_pb_edit : function(n) {
|
||||
var el = $('.metabox-holder').get(0);
|
||||
|
||||
if ( el ) {
|
||||
el.className = el.className.replace(/columns-\d+/, 'columns-' + n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when the amount of columns on the post edit page has been changed.
|
||||
*
|
||||
* @since 4.0.0
|
||||
* @ignore
|
||||
*
|
||||
* @event postboxes#postboxes-columnchange
|
||||
*/
|
||||
$( document ).trigger( 'postboxes-columnchange' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the amount of columns the postboxes are in based on the current
|
||||
* orientation of the browser.
|
||||
*
|
||||
* @since 3.3.0
|
||||
* @access private
|
||||
*
|
||||
* @memberof postboxes
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
_pb_change : function() {
|
||||
var check = $( 'label.columns-prefs-1 input[type="radio"]' );
|
||||
|
||||
switch ( window.orientation ) {
|
||||
case 90:
|
||||
case -90:
|
||||
if ( !check.length || !check.is(':checked') )
|
||||
this._pb_edit(2);
|
||||
break;
|
||||
case 0:
|
||||
case 180:
|
||||
if ( $( '#poststuff' ).length ) {
|
||||
this._pb_edit(1);
|
||||
} else {
|
||||
if ( !check.length || !check.is(':checked') )
|
||||
this._pb_edit(2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
/**
|
||||
* @since 2.7.0
|
||||
* @access public
|
||||
*
|
||||
* @property {Function|boolean} pbshow A callback that is called when a postbox
|
||||
* is opened.
|
||||
* @memberof postboxes
|
||||
*/
|
||||
pbshow : false,
|
||||
|
||||
/**
|
||||
* @since 2.7.0
|
||||
* @access public
|
||||
* @property {Function|boolean} pbhide A callback that is called when a postbox
|
||||
* is closed.
|
||||
* @memberof postboxes
|
||||
*/
|
||||
pbhide : false
|
||||
};
|
||||
|
||||
}(jQuery));
|
2
wp-admin/js/postbox.min.js
vendored
Normal file
2
wp-admin/js/postbox.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
346
wp-admin/js/privacy-tools.js
Normal file
346
wp-admin/js/privacy-tools.js
Normal file
@ -0,0 +1,346 @@
|
||||
/**
|
||||
* Interactions used by the User Privacy tools in WordPress.
|
||||
*
|
||||
* @output wp-admin/js/privacy-tools.js
|
||||
*/
|
||||
|
||||
// Privacy request action handling.
|
||||
jQuery( function( $ ) {
|
||||
var __ = wp.i18n.__,
|
||||
copiedNoticeTimeout;
|
||||
|
||||
function setActionState( $action, state ) {
|
||||
$action.children().addClass( 'hidden' );
|
||||
$action.children( '.' + state ).removeClass( 'hidden' );
|
||||
}
|
||||
|
||||
function clearResultsAfterRow( $requestRow ) {
|
||||
$requestRow.removeClass( 'has-request-results' );
|
||||
|
||||
if ( $requestRow.next().hasClass( 'request-results' ) ) {
|
||||
$requestRow.next().remove();
|
||||
}
|
||||
}
|
||||
|
||||
function appendResultsAfterRow( $requestRow, classes, summaryMessage, additionalMessages ) {
|
||||
var itemList = '',
|
||||
resultRowClasses = 'request-results';
|
||||
|
||||
clearResultsAfterRow( $requestRow );
|
||||
|
||||
if ( additionalMessages.length ) {
|
||||
$.each( additionalMessages, function( index, value ) {
|
||||
itemList = itemList + '<li>' + value + '</li>';
|
||||
});
|
||||
itemList = '<ul>' + itemList + '</ul>';
|
||||
}
|
||||
|
||||
$requestRow.addClass( 'has-request-results' );
|
||||
|
||||
if ( $requestRow.hasClass( 'status-request-confirmed' ) ) {
|
||||
resultRowClasses = resultRowClasses + ' status-request-confirmed';
|
||||
}
|
||||
|
||||
if ( $requestRow.hasClass( 'status-request-failed' ) ) {
|
||||
resultRowClasses = resultRowClasses + ' status-request-failed';
|
||||
}
|
||||
|
||||
$requestRow.after( function() {
|
||||
return '<tr class="' + resultRowClasses + '"><th colspan="5">' +
|
||||
'<div class="notice inline notice-alt ' + classes + '">' +
|
||||
'<p>' + summaryMessage + '</p>' +
|
||||
itemList +
|
||||
'</div>' +
|
||||
'</td>' +
|
||||
'</tr>';
|
||||
});
|
||||
}
|
||||
|
||||
$( '.export-personal-data-handle' ).on( 'click', function( event ) {
|
||||
var $this = $( this ),
|
||||
$action = $this.parents( '.export-personal-data' ),
|
||||
$requestRow = $this.parents( 'tr' ),
|
||||
$progress = $requestRow.find( '.export-progress' ),
|
||||
$rowActions = $this.parents( '.row-actions' ),
|
||||
requestID = $action.data( 'request-id' ),
|
||||
nonce = $action.data( 'nonce' ),
|
||||
exportersCount = $action.data( 'exporters-count' ),
|
||||
sendAsEmail = $action.data( 'send-as-email' ) ? true : false;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
$rowActions.addClass( 'processing' );
|
||||
|
||||
$action.trigger( 'blur' );
|
||||
clearResultsAfterRow( $requestRow );
|
||||
setExportProgress( 0 );
|
||||
|
||||
function onExportDoneSuccess( zipUrl ) {
|
||||
var summaryMessage = __( 'This user’s personal data export link was sent.' );
|
||||
|
||||
if ( 'undefined' !== typeof zipUrl ) {
|
||||
summaryMessage = __( 'This user’s personal data export file was downloaded.' );
|
||||
}
|
||||
|
||||
setActionState( $action, 'export-personal-data-success' );
|
||||
|
||||
appendResultsAfterRow( $requestRow, 'notice-success', summaryMessage, [] );
|
||||
|
||||
if ( 'undefined' !== typeof zipUrl ) {
|
||||
window.location = zipUrl;
|
||||
} else if ( ! sendAsEmail ) {
|
||||
onExportFailure( __( 'No personal data export file was generated.' ) );
|
||||
}
|
||||
|
||||
setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
|
||||
}
|
||||
|
||||
function onExportFailure( errorMessage ) {
|
||||
var summaryMessage = __( 'An error occurred while attempting to export personal data.' );
|
||||
|
||||
setActionState( $action, 'export-personal-data-failed' );
|
||||
|
||||
if ( errorMessage ) {
|
||||
appendResultsAfterRow( $requestRow, 'notice-error', summaryMessage, [ errorMessage ] );
|
||||
}
|
||||
|
||||
setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
|
||||
}
|
||||
|
||||
function setExportProgress( exporterIndex ) {
|
||||
var progress = ( exportersCount > 0 ? exporterIndex / exportersCount : 0 ),
|
||||
progressString = Math.round( progress * 100 ).toString() + '%';
|
||||
|
||||
$progress.html( progressString );
|
||||
}
|
||||
|
||||
function doNextExport( exporterIndex, pageIndex ) {
|
||||
$.ajax(
|
||||
{
|
||||
url: window.ajaxurl,
|
||||
data: {
|
||||
action: 'wp-privacy-export-personal-data',
|
||||
exporter: exporterIndex,
|
||||
id: requestID,
|
||||
page: pageIndex,
|
||||
security: nonce,
|
||||
sendAsEmail: sendAsEmail
|
||||
},
|
||||
method: 'post'
|
||||
}
|
||||
).done( function( response ) {
|
||||
var responseData = response.data;
|
||||
|
||||
if ( ! response.success ) {
|
||||
// e.g. invalid request ID.
|
||||
setTimeout( function() { onExportFailure( response.data ); }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! responseData.done ) {
|
||||
setTimeout( doNextExport( exporterIndex, pageIndex + 1 ) );
|
||||
} else {
|
||||
setExportProgress( exporterIndex );
|
||||
if ( exporterIndex < exportersCount ) {
|
||||
setTimeout( doNextExport( exporterIndex + 1, 1 ) );
|
||||
} else {
|
||||
setTimeout( function() { onExportDoneSuccess( responseData.url ); }, 500 );
|
||||
}
|
||||
}
|
||||
}).fail( function( jqxhr, textStatus, error ) {
|
||||
// e.g. Nonce failure.
|
||||
setTimeout( function() { onExportFailure( error ); }, 500 );
|
||||
});
|
||||
}
|
||||
|
||||
// And now, let's begin.
|
||||
setActionState( $action, 'export-personal-data-processing' );
|
||||
doNextExport( 1, 1 );
|
||||
});
|
||||
|
||||
$( '.remove-personal-data-handle' ).on( 'click', function( event ) {
|
||||
var $this = $( this ),
|
||||
$action = $this.parents( '.remove-personal-data' ),
|
||||
$requestRow = $this.parents( 'tr' ),
|
||||
$progress = $requestRow.find( '.erasure-progress' ),
|
||||
$rowActions = $this.parents( '.row-actions' ),
|
||||
requestID = $action.data( 'request-id' ),
|
||||
nonce = $action.data( 'nonce' ),
|
||||
erasersCount = $action.data( 'erasers-count' ),
|
||||
hasRemoved = false,
|
||||
hasRetained = false,
|
||||
messages = [];
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
$rowActions.addClass( 'processing' );
|
||||
|
||||
$action.trigger( 'blur' );
|
||||
clearResultsAfterRow( $requestRow );
|
||||
setErasureProgress( 0 );
|
||||
|
||||
function onErasureDoneSuccess() {
|
||||
var summaryMessage = __( 'No personal data was found for this user.' ),
|
||||
classes = 'notice-success';
|
||||
|
||||
setActionState( $action, 'remove-personal-data-success' );
|
||||
|
||||
if ( false === hasRemoved ) {
|
||||
if ( false === hasRetained ) {
|
||||
summaryMessage = __( 'No personal data was found for this user.' );
|
||||
} else {
|
||||
summaryMessage = __( 'Personal data was found for this user but was not erased.' );
|
||||
classes = 'notice-warning';
|
||||
}
|
||||
} else {
|
||||
if ( false === hasRetained ) {
|
||||
summaryMessage = __( 'All of the personal data found for this user was erased.' );
|
||||
} else {
|
||||
summaryMessage = __( 'Personal data was found for this user but some of the personal data found was not erased.' );
|
||||
classes = 'notice-warning';
|
||||
}
|
||||
}
|
||||
appendResultsAfterRow( $requestRow, classes, summaryMessage, messages );
|
||||
|
||||
setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
|
||||
}
|
||||
|
||||
function onErasureFailure() {
|
||||
var summaryMessage = __( 'An error occurred while attempting to find and erase personal data.' );
|
||||
|
||||
setActionState( $action, 'remove-personal-data-failed' );
|
||||
|
||||
appendResultsAfterRow( $requestRow, 'notice-error', summaryMessage, [] );
|
||||
|
||||
setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
|
||||
}
|
||||
|
||||
function setErasureProgress( eraserIndex ) {
|
||||
var progress = ( erasersCount > 0 ? eraserIndex / erasersCount : 0 ),
|
||||
progressString = Math.round( progress * 100 ).toString() + '%';
|
||||
|
||||
$progress.html( progressString );
|
||||
}
|
||||
|
||||
function doNextErasure( eraserIndex, pageIndex ) {
|
||||
$.ajax({
|
||||
url: window.ajaxurl,
|
||||
data: {
|
||||
action: 'wp-privacy-erase-personal-data',
|
||||
eraser: eraserIndex,
|
||||
id: requestID,
|
||||
page: pageIndex,
|
||||
security: nonce
|
||||
},
|
||||
method: 'post'
|
||||
}).done( function( response ) {
|
||||
var responseData = response.data;
|
||||
|
||||
if ( ! response.success ) {
|
||||
setTimeout( function() { onErasureFailure(); }, 500 );
|
||||
return;
|
||||
}
|
||||
if ( responseData.items_removed ) {
|
||||
hasRemoved = hasRemoved || responseData.items_removed;
|
||||
}
|
||||
if ( responseData.items_retained ) {
|
||||
hasRetained = hasRetained || responseData.items_retained;
|
||||
}
|
||||
if ( responseData.messages ) {
|
||||
messages = messages.concat( responseData.messages );
|
||||
}
|
||||
if ( ! responseData.done ) {
|
||||
setTimeout( doNextErasure( eraserIndex, pageIndex + 1 ) );
|
||||
} else {
|
||||
setErasureProgress( eraserIndex );
|
||||
if ( eraserIndex < erasersCount ) {
|
||||
setTimeout( doNextErasure( eraserIndex + 1, 1 ) );
|
||||
} else {
|
||||
setTimeout( function() { onErasureDoneSuccess(); }, 500 );
|
||||
}
|
||||
}
|
||||
}).fail( function() {
|
||||
setTimeout( function() { onErasureFailure(); }, 500 );
|
||||
});
|
||||
}
|
||||
|
||||
// And now, let's begin.
|
||||
setActionState( $action, 'remove-personal-data-processing' );
|
||||
|
||||
doNextErasure( 1, 1 );
|
||||
});
|
||||
|
||||
// Privacy Policy page, copy action.
|
||||
$( document ).on( 'click', function( event ) {
|
||||
var $parent,
|
||||
range,
|
||||
$target = $( event.target ),
|
||||
copiedNotice = $target.siblings( '.success' );
|
||||
|
||||
clearTimeout( copiedNoticeTimeout );
|
||||
|
||||
if ( $target.is( 'button.privacy-text-copy' ) ) {
|
||||
$parent = $target.closest( '.privacy-settings-accordion-panel' );
|
||||
|
||||
if ( $parent.length ) {
|
||||
try {
|
||||
var documentPosition = document.documentElement.scrollTop,
|
||||
bodyPosition = document.body.scrollTop;
|
||||
|
||||
// Setup copy.
|
||||
window.getSelection().removeAllRanges();
|
||||
|
||||
// Hide tutorial content to remove from copied content.
|
||||
range = document.createRange();
|
||||
$parent.addClass( 'hide-privacy-policy-tutorial' );
|
||||
|
||||
// Copy action.
|
||||
range.selectNodeContents( $parent[0] );
|
||||
window.getSelection().addRange( range );
|
||||
document.execCommand( 'copy' );
|
||||
|
||||
// Reset section.
|
||||
$parent.removeClass( 'hide-privacy-policy-tutorial' );
|
||||
window.getSelection().removeAllRanges();
|
||||
|
||||
// Return scroll position - see #49540.
|
||||
if ( documentPosition > 0 && documentPosition !== document.documentElement.scrollTop ) {
|
||||
document.documentElement.scrollTop = documentPosition;
|
||||
} else if ( bodyPosition > 0 && bodyPosition !== document.body.scrollTop ) {
|
||||
document.body.scrollTop = bodyPosition;
|
||||
}
|
||||
|
||||
// Display and speak notice to indicate action complete.
|
||||
copiedNotice.addClass( 'visible' );
|
||||
wp.a11y.speak( __( 'The suggested policy text has been copied to your clipboard.' ) );
|
||||
|
||||
// Delay notice dismissal.
|
||||
copiedNoticeTimeout = setTimeout( function() {
|
||||
copiedNotice.removeClass( 'visible' );
|
||||
}, 3000 );
|
||||
} catch ( er ) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Label handling to focus the create page button on Privacy settings page.
|
||||
$( 'body.options-privacy-php label[for=create-page]' ).on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
$( 'input#create-page' ).trigger( 'focus' );
|
||||
} );
|
||||
|
||||
// Accordion handling in various new Privacy settings pages.
|
||||
$( '.privacy-settings-accordion' ).on( 'click', '.privacy-settings-accordion-trigger', function() {
|
||||
var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
|
||||
|
||||
if ( isExpanded ) {
|
||||
$( this ).attr( 'aria-expanded', 'false' );
|
||||
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
|
||||
} else {
|
||||
$( this ).attr( 'aria-expanded', 'true' );
|
||||
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
|
||||
}
|
||||
} );
|
||||
});
|
2
wp-admin/js/privacy-tools.min.js
vendored
Normal file
2
wp-admin/js/privacy-tools.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1175
wp-admin/js/revisions.js
Normal file
1175
wp-admin/js/revisions.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/revisions.min.js
vendored
Normal file
2
wp-admin/js/revisions.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
28
wp-admin/js/set-post-thumbnail.js
Normal file
28
wp-admin/js/set-post-thumbnail.js
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @output wp-admin/js/set-post-thumbnail.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, post_id, alert */
|
||||
/* exported WPSetAsThumbnail */
|
||||
|
||||
window.WPSetAsThumbnail = function( id, nonce ) {
|
||||
var $link = jQuery('a#wp-post-thumbnail-' + id);
|
||||
|
||||
$link.text( wp.i18n.__( 'Saving…' ) );
|
||||
jQuery.post(ajaxurl, {
|
||||
action: 'set-post-thumbnail', post_id: post_id, thumbnail_id: id, _ajax_nonce: nonce, cookie: encodeURIComponent( document.cookie )
|
||||
}, function(str){
|
||||
var win = window.dialogArguments || opener || parent || top;
|
||||
$link.text( wp.i18n.__( 'Use as featured image' ) );
|
||||
if ( str == '0' ) {
|
||||
alert( wp.i18n.__( 'Could not set that as the thumbnail image. Try a different attachment.' ) );
|
||||
} else {
|
||||
jQuery('a.wp-post-thumbnail').show();
|
||||
$link.text( wp.i18n.__( 'Done' ) );
|
||||
$link.fadeOut( 2000 );
|
||||
win.WPSetThumbnailID(id);
|
||||
win.WPSetThumbnailHTML(str);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
2
wp-admin/js/set-post-thumbnail.min.js
vendored
Normal file
2
wp-admin/js/set-post-thumbnail.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
window.WPSetAsThumbnail=function(n,t){var a=jQuery("a#wp-post-thumbnail-"+n);a.text(wp.i18n.__("Saving\u2026")),jQuery.post(ajaxurl,{action:"set-post-thumbnail",post_id:post_id,thumbnail_id:n,_ajax_nonce:t,cookie:encodeURIComponent(document.cookie)},function(t){var e=window.dialogArguments||opener||parent||top;a.text(wp.i18n.__("Use as featured image")),"0"==t?alert(wp.i18n.__("Could not set that as the thumbnail image. Try a different attachment.")):(jQuery("a.wp-post-thumbnail").show(),a.text(wp.i18n.__("Done")),a.fadeOut(2e3),e.WPSetThumbnailID(n),e.WPSetThumbnailHTML(t))})};
|
482
wp-admin/js/site-health.js
Normal file
482
wp-admin/js/site-health.js
Normal file
@ -0,0 +1,482 @@
|
||||
/**
|
||||
* Interactions used by the Site Health modules in WordPress.
|
||||
*
|
||||
* @output wp-admin/js/site-health.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, ClipboardJS, SiteHealth, wp */
|
||||
|
||||
jQuery( function( $ ) {
|
||||
|
||||
var __ = wp.i18n.__,
|
||||
_n = wp.i18n._n,
|
||||
sprintf = wp.i18n.sprintf,
|
||||
clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' ),
|
||||
isStatusTab = $( '.health-check-body.health-check-status-tab' ).length,
|
||||
isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length,
|
||||
pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' ),
|
||||
menuCounterWrapper = $( '#adminmenu .site-health-counter' ),
|
||||
menuCounter = $( '#adminmenu .site-health-counter .count' ),
|
||||
successTimeout;
|
||||
|
||||
// Debug information copy section.
|
||||
clipboard.on( 'success', function( e ) {
|
||||
var triggerElement = $( e.trigger ),
|
||||
successElement = $( '.success', triggerElement.closest( 'div' ) );
|
||||
|
||||
// Clear the selection and move focus back to the trigger.
|
||||
e.clearSelection();
|
||||
|
||||
// Show success visual feedback.
|
||||
clearTimeout( successTimeout );
|
||||
successElement.removeClass( 'hidden' );
|
||||
|
||||
// Hide success visual feedback after 3 seconds since last success.
|
||||
successTimeout = setTimeout( function() {
|
||||
successElement.addClass( 'hidden' );
|
||||
}, 3000 );
|
||||
|
||||
// Handle success audible feedback.
|
||||
wp.a11y.speak( __( 'Site information has been copied to your clipboard.' ) );
|
||||
} );
|
||||
|
||||
// Accordion handling in various areas.
|
||||
$( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
|
||||
var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
|
||||
|
||||
if ( isExpanded ) {
|
||||
$( this ).attr( 'aria-expanded', 'false' );
|
||||
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
|
||||
} else {
|
||||
$( this ).attr( 'aria-expanded', 'true' );
|
||||
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
|
||||
}
|
||||
} );
|
||||
|
||||
// Site Health test handling.
|
||||
|
||||
$( '.site-health-view-passed' ).on( 'click', function() {
|
||||
var goodIssuesWrapper = $( '#health-check-issues-good' );
|
||||
|
||||
goodIssuesWrapper.toggleClass( 'hidden' );
|
||||
$( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Validates the Site Health test result format.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {Object} issue
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function validateIssueData( issue ) {
|
||||
// Expected minimum format of a valid SiteHealth test response.
|
||||
var minimumExpected = {
|
||||
test: 'string',
|
||||
label: 'string',
|
||||
description: 'string'
|
||||
},
|
||||
passed = true,
|
||||
key, value, subKey, subValue;
|
||||
|
||||
// If the issue passed is not an object, return a `false` state early.
|
||||
if ( 'object' !== typeof( issue ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loop over expected data and match the data types.
|
||||
for ( key in minimumExpected ) {
|
||||
value = minimumExpected[ key ];
|
||||
|
||||
if ( 'object' === typeof( value ) ) {
|
||||
for ( subKey in value ) {
|
||||
subValue = value[ subKey ];
|
||||
|
||||
if ( 'undefined' === typeof( issue[ key ] ) ||
|
||||
'undefined' === typeof( issue[ key ][ subKey ] ) ||
|
||||
subValue !== typeof( issue[ key ][ subKey ] )
|
||||
) {
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( 'undefined' === typeof( issue[ key ] ) ||
|
||||
value !== typeof( issue[ key ] )
|
||||
) {
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a new issue to the issue list.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @param {Object} issue The issue data.
|
||||
*/
|
||||
function appendIssue( issue ) {
|
||||
var template = wp.template( 'health-check-issue' ),
|
||||
issueWrapper = $( '#health-check-issues-' + issue.status ),
|
||||
heading,
|
||||
count;
|
||||
|
||||
/*
|
||||
* Validate the issue data format before using it.
|
||||
* If the output is invalid, discard it.
|
||||
*/
|
||||
if ( ! validateIssueData( issue ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SiteHealth.site_status.issues[ issue.status ]++;
|
||||
|
||||
count = SiteHealth.site_status.issues[ issue.status ];
|
||||
|
||||
// If no test name is supplied, append a placeholder for markup references.
|
||||
if ( typeof issue.test === 'undefined' ) {
|
||||
issue.test = issue.status + count;
|
||||
}
|
||||
|
||||
if ( 'critical' === issue.status ) {
|
||||
heading = sprintf(
|
||||
_n( '%s critical issue', '%s critical issues', count ),
|
||||
'<span class="issue-count">' + count + '</span>'
|
||||
);
|
||||
} else if ( 'recommended' === issue.status ) {
|
||||
heading = sprintf(
|
||||
_n( '%s recommended improvement', '%s recommended improvements', count ),
|
||||
'<span class="issue-count">' + count + '</span>'
|
||||
);
|
||||
} else if ( 'good' === issue.status ) {
|
||||
heading = sprintf(
|
||||
_n( '%s item with no issues detected', '%s items with no issues detected', count ),
|
||||
'<span class="issue-count">' + count + '</span>'
|
||||
);
|
||||
}
|
||||
|
||||
if ( heading ) {
|
||||
$( '.site-health-issue-count-title', issueWrapper ).html( heading );
|
||||
}
|
||||
|
||||
menuCounter.text( SiteHealth.site_status.issues.critical );
|
||||
|
||||
if ( 0 < parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
|
||||
$( '#health-check-issues-critical' ).removeClass( 'hidden' );
|
||||
|
||||
menuCounterWrapper.removeClass( 'count-0' );
|
||||
} else {
|
||||
menuCounterWrapper.addClass( 'count-0' );
|
||||
}
|
||||
if ( 0 < parseInt( SiteHealth.site_status.issues.recommended, 0 ) ) {
|
||||
$( '#health-check-issues-recommended' ).removeClass( 'hidden' );
|
||||
}
|
||||
|
||||
$( '.issues', '#health-check-issues-' + issue.status ).append( template( issue ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates site health status indicator as asynchronous tests are run and returned.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*/
|
||||
function recalculateProgression() {
|
||||
var r, c, pct;
|
||||
var $progress = $( '.site-health-progress' );
|
||||
var $wrapper = $progress.closest( '.site-health-progress-wrapper' );
|
||||
var $progressLabel = $( '.site-health-progress-label', $wrapper );
|
||||
var $circle = $( '.site-health-progress svg #bar' );
|
||||
var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) +
|
||||
parseInt( SiteHealth.site_status.issues.recommended, 0 ) +
|
||||
( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
|
||||
var failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) +
|
||||
( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
|
||||
var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
|
||||
|
||||
if ( 0 === totalTests ) {
|
||||
$progress.addClass( 'hidden' );
|
||||
return;
|
||||
}
|
||||
|
||||
$wrapper.removeClass( 'loading' );
|
||||
|
||||
r = $circle.attr( 'r' );
|
||||
c = Math.PI * ( r * 2 );
|
||||
|
||||
if ( 0 > val ) {
|
||||
val = 0;
|
||||
}
|
||||
if ( 100 < val ) {
|
||||
val = 100;
|
||||
}
|
||||
|
||||
pct = ( ( 100 - val ) / 100 ) * c + 'px';
|
||||
|
||||
$circle.css( { strokeDashoffset: pct } );
|
||||
|
||||
if ( 80 <= val && 0 === parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
|
||||
$wrapper.addClass( 'green' ).removeClass( 'orange' );
|
||||
|
||||
$progressLabel.text( __( 'Good' ) );
|
||||
announceTestsProgression( 'good' );
|
||||
} else {
|
||||
$wrapper.addClass( 'orange' ).removeClass( 'green' );
|
||||
|
||||
$progressLabel.text( __( 'Should be improved' ) );
|
||||
announceTestsProgression( 'improvable' );
|
||||
}
|
||||
|
||||
if ( isStatusTab ) {
|
||||
$.post(
|
||||
ajaxurl,
|
||||
{
|
||||
'action': 'health-check-site-status-result',
|
||||
'_wpnonce': SiteHealth.nonce.site_status_result,
|
||||
'counts': SiteHealth.site_status.issues
|
||||
}
|
||||
);
|
||||
|
||||
if ( 100 === val ) {
|
||||
$( '.site-status-all-clear' ).removeClass( 'hide' );
|
||||
$( '.site-status-has-issues' ).addClass( 'hide' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues the next asynchronous test when we're ready to run it.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*/
|
||||
function maybeRunNextAsyncTest() {
|
||||
var doCalculation = true;
|
||||
|
||||
if ( 1 <= SiteHealth.site_status.async.length ) {
|
||||
$.each( SiteHealth.site_status.async, function() {
|
||||
var data = {
|
||||
'action': 'health-check-' + this.test.replace( '_', '-' ),
|
||||
'_wpnonce': SiteHealth.nonce.site_status
|
||||
};
|
||||
|
||||
if ( this.completed ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
doCalculation = false;
|
||||
|
||||
this.completed = true;
|
||||
|
||||
if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) {
|
||||
wp.apiRequest( {
|
||||
url: wp.url.addQueryArgs( this.test, { _locale: 'user' } ),
|
||||
headers: this.headers
|
||||
} )
|
||||
.done( function( response ) {
|
||||
/** This filter is documented in wp-admin/includes/class-wp-site-health.php */
|
||||
appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response ) );
|
||||
} )
|
||||
.fail( function( response ) {
|
||||
var description;
|
||||
|
||||
if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
|
||||
description = response.responseJSON.message;
|
||||
} else {
|
||||
description = __( 'No details available' );
|
||||
}
|
||||
|
||||
addFailedSiteHealthCheckNotice( this.url, description );
|
||||
} )
|
||||
.always( function() {
|
||||
maybeRunNextAsyncTest();
|
||||
} );
|
||||
} else {
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data
|
||||
).done( function( response ) {
|
||||
/** This filter is documented in wp-admin/includes/class-wp-site-health.php */
|
||||
appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) );
|
||||
} ).fail( function( response ) {
|
||||
var description;
|
||||
|
||||
if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
|
||||
description = response.responseJSON.message;
|
||||
} else {
|
||||
description = __( 'No details available' );
|
||||
}
|
||||
|
||||
addFailedSiteHealthCheckNotice( this.url, description );
|
||||
} ).always( function() {
|
||||
maybeRunNextAsyncTest();
|
||||
} );
|
||||
}
|
||||
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
|
||||
if ( doCalculation ) {
|
||||
recalculateProgression();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the details of a failed asynchronous test to the list of test results.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*/
|
||||
function addFailedSiteHealthCheckNotice( url, description ) {
|
||||
var issue;
|
||||
|
||||
issue = {
|
||||
'status': 'recommended',
|
||||
'label': __( 'A test is unavailable' ),
|
||||
'badge': {
|
||||
'color': 'red',
|
||||
'label': __( 'Unavailable' )
|
||||
},
|
||||
'description': '<p>' + url + '</p><p>' + description + '</p>',
|
||||
'actions': ''
|
||||
};
|
||||
|
||||
/** This filter is documented in wp-admin/includes/class-wp-site-health.php */
|
||||
appendIssue( wp.hooks.applyFilters( 'site_status_test_result', issue ) );
|
||||
}
|
||||
|
||||
if ( 'undefined' !== typeof SiteHealth ) {
|
||||
if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) {
|
||||
recalculateProgression();
|
||||
} else {
|
||||
SiteHealth.site_status.issues = {
|
||||
'good': 0,
|
||||
'recommended': 0,
|
||||
'critical': 0
|
||||
};
|
||||
}
|
||||
|
||||
if ( 0 < SiteHealth.site_status.direct.length ) {
|
||||
$.each( SiteHealth.site_status.direct, function() {
|
||||
appendIssue( this );
|
||||
} );
|
||||
}
|
||||
|
||||
if ( 0 < SiteHealth.site_status.async.length ) {
|
||||
maybeRunNextAsyncTest();
|
||||
} else {
|
||||
recalculateProgression();
|
||||
}
|
||||
}
|
||||
|
||||
function getDirectorySizes() {
|
||||
var timestamp = ( new Date().getTime() );
|
||||
|
||||
// After 3 seconds announce that we're still waiting for directory sizes.
|
||||
var timeout = window.setTimeout( function() {
|
||||
announceTestsProgression( 'waiting-for-directory-sizes' );
|
||||
}, 3000 );
|
||||
|
||||
wp.apiRequest( {
|
||||
path: '/wp-site-health/v1/directory-sizes'
|
||||
} ).done( function( response ) {
|
||||
updateDirSizes( response || {} );
|
||||
} ).always( function() {
|
||||
var delay = ( new Date().getTime() ) - timestamp;
|
||||
|
||||
$( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
|
||||
|
||||
if ( delay > 3000 ) {
|
||||
/*
|
||||
* We have announced that we're waiting.
|
||||
* Announce that we're ready after giving at least 3 seconds
|
||||
* for the first announcement to be read out, or the two may collide.
|
||||
*/
|
||||
if ( delay > 6000 ) {
|
||||
delay = 0;
|
||||
} else {
|
||||
delay = 6500 - delay;
|
||||
}
|
||||
|
||||
window.setTimeout( function() {
|
||||
recalculateProgression();
|
||||
}, delay );
|
||||
} else {
|
||||
// Cancel the announcement.
|
||||
window.clearTimeout( timeout );
|
||||
}
|
||||
|
||||
$( document ).trigger( 'site-health-info-dirsizes-done' );
|
||||
} );
|
||||
}
|
||||
|
||||
function updateDirSizes( data ) {
|
||||
var copyButton = $( 'button.button.copy-button' );
|
||||
var clipboardText = copyButton.attr( 'data-clipboard-text' );
|
||||
|
||||
$.each( data, function( name, value ) {
|
||||
var text = value.debug || value.size;
|
||||
|
||||
if ( typeof text !== 'undefined' ) {
|
||||
clipboardText = clipboardText.replace( name + ': loading...', name + ': ' + text );
|
||||
}
|
||||
} );
|
||||
|
||||
copyButton.attr( 'data-clipboard-text', clipboardText );
|
||||
|
||||
pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
|
||||
var td = $( element );
|
||||
var name = td.attr( 'class' );
|
||||
|
||||
if ( data.hasOwnProperty( name ) && data[ name ].size ) {
|
||||
td.text( data[ name ].size );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
if ( isDebugTab ) {
|
||||
if ( pathsSizesSection.length ) {
|
||||
getDirectorySizes();
|
||||
} else {
|
||||
recalculateProgression();
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger a class toggle when the extended menu button is clicked.
|
||||
$( '.health-check-offscreen-nav-wrapper' ).on( 'click', function() {
|
||||
$( this ).toggleClass( 'visible' );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Announces to assistive technologies the tests progression status.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param {string} type The type of message to be announced.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function announceTestsProgression( type ) {
|
||||
// Only announce the messages in the Site Health pages.
|
||||
if ( 'site-health' !== SiteHealth.screen ) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( type ) {
|
||||
case 'good':
|
||||
wp.a11y.speak( __( 'All site health tests have finished running. Your site is looking good.' ) );
|
||||
break;
|
||||
case 'improvable':
|
||||
wp.a11y.speak( __( 'All site health tests have finished running. There are items that should be addressed.' ) );
|
||||
break;
|
||||
case 'waiting-for-directory-sizes':
|
||||
wp.a11y.speak( __( 'Running additional tests... please wait.' ) );
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
} );
|
2
wp-admin/js/site-health.min.js
vendored
Normal file
2
wp-admin/js/site-health.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
236
wp-admin/js/site-icon.js
Normal file
236
wp-admin/js/site-icon.js
Normal file
@ -0,0 +1,236 @@
|
||||
/**
|
||||
* Handle the site icon setting in options-general.php.
|
||||
*
|
||||
* @since 6.5.0
|
||||
* @output wp-admin/js/site-icon.js
|
||||
*/
|
||||
|
||||
/* global jQuery, wp */
|
||||
|
||||
( function ( $ ) {
|
||||
var $chooseButton = $( '#choose-from-library-button' ),
|
||||
$iconPreview = $( '#site-icon-preview' ),
|
||||
$browserIconPreview = $( '#browser-icon-preview' ),
|
||||
$appIconPreview = $( '#app-icon-preview' ),
|
||||
$hiddenDataField = $( '#site_icon_hidden_field' ),
|
||||
$removeButton = $( '#js-remove-site-icon' ),
|
||||
frame;
|
||||
|
||||
/**
|
||||
* Calculate image selection options based on the attachment dimensions.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param {Object} attachment The attachment object representing the image.
|
||||
* @return {Object} The image selection options.
|
||||
*/
|
||||
function calculateImageSelectOptions( attachment ) {
|
||||
var realWidth = attachment.get( 'width' ),
|
||||
realHeight = attachment.get( 'height' ),
|
||||
xInit = 512,
|
||||
yInit = 512,
|
||||
ratio = xInit / yInit,
|
||||
xImg = xInit,
|
||||
yImg = yInit,
|
||||
x1,
|
||||
y1,
|
||||
imgSelectOptions;
|
||||
|
||||
if ( realWidth / realHeight > ratio ) {
|
||||
yInit = realHeight;
|
||||
xInit = yInit * ratio;
|
||||
} else {
|
||||
xInit = realWidth;
|
||||
yInit = xInit / ratio;
|
||||
}
|
||||
|
||||
x1 = ( realWidth - xInit ) / 2;
|
||||
y1 = ( realHeight - yInit ) / 2;
|
||||
|
||||
imgSelectOptions = {
|
||||
aspectRatio: xInit + ':' + yInit,
|
||||
handles: true,
|
||||
keys: true,
|
||||
instance: true,
|
||||
persistent: true,
|
||||
imageWidth: realWidth,
|
||||
imageHeight: realHeight,
|
||||
minWidth: xImg > xInit ? xInit : xImg,
|
||||
minHeight: yImg > yInit ? yInit : yImg,
|
||||
x1: x1,
|
||||
y1: y1,
|
||||
x2: xInit + x1,
|
||||
y2: yInit + y1,
|
||||
};
|
||||
|
||||
return imgSelectOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the media frame for selecting or cropping an image.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*/
|
||||
$chooseButton.on( 'click', function () {
|
||||
var $el = $( this );
|
||||
|
||||
// Create the media frame.
|
||||
frame = wp.media( {
|
||||
button: {
|
||||
// Set the text of the button.
|
||||
text: $el.data( 'update' ),
|
||||
|
||||
// Don't close, we might need to crop.
|
||||
close: false,
|
||||
},
|
||||
states: [
|
||||
new wp.media.controller.Library( {
|
||||
title: $el.data( 'choose-text' ),
|
||||
library: wp.media.query( { type: 'image' } ),
|
||||
date: false,
|
||||
suggestedWidth: $el.data( 'size' ),
|
||||
suggestedHeight: $el.data( 'size' ),
|
||||
} ),
|
||||
new wp.media.controller.SiteIconCropper( {
|
||||
control: {
|
||||
params: {
|
||||
width: $el.data( 'size' ),
|
||||
height: $el.data( 'size' ),
|
||||
},
|
||||
},
|
||||
imgSelectOptions: calculateImageSelectOptions,
|
||||
} ),
|
||||
],
|
||||
} );
|
||||
|
||||
frame.on( 'cropped', function ( attachment ) {
|
||||
$hiddenDataField.val( attachment.id );
|
||||
switchToUpdate( attachment );
|
||||
frame.close();
|
||||
|
||||
// Start over with a frame that is so fresh and so clean clean.
|
||||
frame = null;
|
||||
} );
|
||||
|
||||
// When an image is selected, run a callback.
|
||||
frame.on( 'select', function () {
|
||||
// Grab the selected attachment.
|
||||
var attachment = frame.state().get( 'selection' ).first();
|
||||
|
||||
if (
|
||||
attachment.attributes.height === $el.data( 'size' ) &&
|
||||
$el.data( 'size' ) === attachment.attributes.width
|
||||
) {
|
||||
switchToUpdate( attachment.attributes );
|
||||
frame.close();
|
||||
|
||||
// Set the value of the hidden input to the attachment id.
|
||||
$hiddenDataField.val( attachment.id );
|
||||
} else {
|
||||
frame.setState( 'cropper' );
|
||||
}
|
||||
} );
|
||||
|
||||
frame.open();
|
||||
} );
|
||||
|
||||
/**
|
||||
* Update the UI when a site icon is selected.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param {array} attributes The attributes for the attachment.
|
||||
*/
|
||||
function switchToUpdate( attributes ) {
|
||||
var i18nAppAlternativeString, i18nBrowserAlternativeString;
|
||||
|
||||
if ( attributes.alt ) {
|
||||
i18nAppAlternativeString = wp.i18n.sprintf(
|
||||
/* translators: %s: The selected image alt text. */
|
||||
wp.i18n.__( 'App icon preview: Current image: %s' ),
|
||||
attributes.alt
|
||||
);
|
||||
i18nBrowserAlternativeString = wp.i18n.sprintf(
|
||||
/* translators: %s: The selected image alt text. */
|
||||
wp.i18n.__( 'Browser icon preview: Current image: %s' ),
|
||||
attributes.alt
|
||||
);
|
||||
} else {
|
||||
i18nAppAlternativeString = wp.i18n.sprintf(
|
||||
/* translators: %s: The selected image filename. */
|
||||
wp.i18n.__(
|
||||
'App icon preview: The current image has no alternative text. The file name is: %s'
|
||||
),
|
||||
attributes.filename
|
||||
);
|
||||
i18nBrowserAlternativeString = wp.i18n.sprintf(
|
||||
/* translators: %s: The selected image filename. */
|
||||
wp.i18n.__(
|
||||
'Browser icon preview: The current image has no alternative text. The file name is: %s'
|
||||
),
|
||||
attributes.filename
|
||||
);
|
||||
}
|
||||
|
||||
// Set site-icon-img src and alternative text to app icon preview.
|
||||
$appIconPreview.attr( {
|
||||
src: attributes.url,
|
||||
alt: i18nAppAlternativeString,
|
||||
} );
|
||||
|
||||
// Set site-icon-img src and alternative text to browser preview.
|
||||
$browserIconPreview.attr( {
|
||||
src: attributes.url,
|
||||
alt: i18nBrowserAlternativeString,
|
||||
} );
|
||||
|
||||
// Remove hidden class from icon preview div and remove button.
|
||||
$iconPreview.removeClass( 'hidden' );
|
||||
$removeButton.removeClass( 'hidden' );
|
||||
|
||||
// If the choose button is not in the update state, swap the classes.
|
||||
if ( $chooseButton.attr( 'data-state' ) !== '1' ) {
|
||||
$chooseButton.attr( {
|
||||
class: $chooseButton.attr( 'data-alt-classes' ),
|
||||
'data-alt-classes': $chooseButton.attr( 'class' ),
|
||||
'data-state': '1',
|
||||
} );
|
||||
}
|
||||
|
||||
// Swap the text of the choose button.
|
||||
$chooseButton.text( $chooseButton.attr( 'data-update-text' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click event of the remove button.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*/
|
||||
$removeButton.on( 'click', function () {
|
||||
$hiddenDataField.val( 'false' );
|
||||
$( this ).toggleClass( 'hidden' );
|
||||
$iconPreview.toggleClass( 'hidden' );
|
||||
$browserIconPreview.attr( {
|
||||
src: '',
|
||||
alt: '',
|
||||
} );
|
||||
$appIconPreview.attr( {
|
||||
src: '',
|
||||
alt: '',
|
||||
} );
|
||||
|
||||
/**
|
||||
* Resets state to the button, for correct visual style and state.
|
||||
* Updates the text of the button.
|
||||
* Sets focus state to the button.
|
||||
*/
|
||||
$chooseButton
|
||||
.attr( {
|
||||
class: $chooseButton.attr( 'data-alt-classes' ),
|
||||
'data-alt-classes': $chooseButton.attr( 'class' ),
|
||||
'data-state': '',
|
||||
} )
|
||||
.text( $chooseButton.attr( 'data-choose-text' ) )
|
||||
.trigger( 'focus' );
|
||||
} );
|
||||
} )( jQuery );
|
2
wp-admin/js/site-icon.min.js
vendored
Normal file
2
wp-admin/js/site-icon.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(t){var a,i=t("#choose-from-library-button"),s=t("#site-icon-preview"),r=t("#browser-icon-preview"),n=t("#app-icon-preview"),l=t("#site_icon_hidden_field"),o=t("#js-remove-site-icon");function c(t){var e=t.get("width"),t=t.get("height"),a=512,i=512,s=a/i,r=a,n=i;return s<e/t?a=(i=t)*s:i=(a=e)/s,{aspectRatio:a+":"+i,handles:!0,keys:!0,instance:!0,persistent:!0,imageWidth:e,imageHeight:t,minWidth:a<r?a:r,minHeight:i<n?i:n,x1:s=(e-a)/2,y1:r=(t-i)/2,x2:a+s,y2:i+r}}function d(t){var e,a=t.alt?(e=wp.i18n.sprintf(wp.i18n.__("App icon preview: Current image: %s"),t.alt),wp.i18n.sprintf(wp.i18n.__("Browser icon preview: Current image: %s"),t.alt)):(e=wp.i18n.sprintf(wp.i18n.__("App icon preview: The current image has no alternative text. The file name is: %s"),t.filename),wp.i18n.sprintf(wp.i18n.__("Browser icon preview: The current image has no alternative text. The file name is: %s"),t.filename));n.attr({src:t.url,alt:e}),r.attr({src:t.url,alt:a}),s.removeClass("hidden"),o.removeClass("hidden"),"1"!==i.attr("data-state")&&i.attr({class:i.attr("data-alt-classes"),"data-alt-classes":i.attr("class"),"data-state":"1"}),i.text(i.attr("data-update-text"))}i.on("click",function(){var e=t(this);(a=wp.media({button:{text:e.data("update"),close:!1},states:[new wp.media.controller.Library({title:e.data("choose-text"),library:wp.media.query({type:"image"}),date:!1,suggestedWidth:e.data("size"),suggestedHeight:e.data("size")}),new wp.media.controller.SiteIconCropper({control:{params:{width:e.data("size"),height:e.data("size")}},imgSelectOptions:c})]})).on("cropped",function(t){l.val(t.id),d(t),a.close(),a=null}),a.on("select",function(){var t=a.state().get("selection").first();t.attributes.height===e.data("size")&&e.data("size")===t.attributes.width?(d(t.attributes),a.close(),l.val(t.id)):a.setState("cropper")}),a.open()}),o.on("click",function(){l.val("false"),t(this).toggleClass("hidden"),s.toggleClass("hidden"),r.attr({src:"",alt:""}),n.attr({src:"",alt:""}),i.attr({class:i.attr("data-alt-classes"),"data-alt-classes":i.attr("class"),"data-state":""}).text(i.attr("data-choose-text")).trigger("focus")})}(jQuery);
|
238
wp-admin/js/svg-painter.js
Normal file
238
wp-admin/js/svg-painter.js
Normal file
@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Attempt to re-color SVG icons used in the admin menu or the toolbar
|
||||
*
|
||||
* @output wp-admin/js/svg-painter.js
|
||||
*/
|
||||
|
||||
window.wp = window.wp || {};
|
||||
|
||||
wp.svgPainter = ( function( $, window, document, undefined ) {
|
||||
'use strict';
|
||||
var selector, base64, painter,
|
||||
colorscheme = {},
|
||||
elements = [];
|
||||
|
||||
$( function() {
|
||||
// Detection for browser SVG capability.
|
||||
if ( document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' ) ) {
|
||||
$( document.body ).removeClass( 'no-svg' ).addClass( 'svg' );
|
||||
wp.svgPainter.init();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Needed only for IE9
|
||||
*
|
||||
* Based on jquery.base64.js 0.0.3 - https://github.com/yckart/jquery.base64.js
|
||||
*
|
||||
* Based on: https://gist.github.com/Yaffle/1284012
|
||||
*
|
||||
* Copyright (c) 2012 Yannick Albert (http://yckart.com)
|
||||
* Licensed under the MIT license
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
base64 = ( function() {
|
||||
var c,
|
||||
b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
|
||||
a256 = '',
|
||||
r64 = [256],
|
||||
r256 = [256],
|
||||
i = 0;
|
||||
|
||||
function init() {
|
||||
while( i < 256 ) {
|
||||
c = String.fromCharCode(i);
|
||||
a256 += c;
|
||||
r256[i] = i;
|
||||
r64[i] = b64.indexOf(c);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
function code( s, discard, alpha, beta, w1, w2 ) {
|
||||
var tmp, length,
|
||||
buffer = 0,
|
||||
i = 0,
|
||||
result = '',
|
||||
bitsInBuffer = 0;
|
||||
|
||||
s = String(s);
|
||||
length = s.length;
|
||||
|
||||
while( i < length ) {
|
||||
c = s.charCodeAt(i);
|
||||
c = c < 256 ? alpha[c] : -1;
|
||||
|
||||
buffer = ( buffer << w1 ) + c;
|
||||
bitsInBuffer += w1;
|
||||
|
||||
while( bitsInBuffer >= w2 ) {
|
||||
bitsInBuffer -= w2;
|
||||
tmp = buffer >> bitsInBuffer;
|
||||
result += beta.charAt(tmp);
|
||||
buffer ^= tmp << bitsInBuffer;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if ( ! discard && bitsInBuffer > 0 ) {
|
||||
result += beta.charAt( buffer << ( w2 - bitsInBuffer ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function btoa( plain ) {
|
||||
if ( ! c ) {
|
||||
init();
|
||||
}
|
||||
|
||||
plain = code( plain, false, r256, b64, 8, 6 );
|
||||
return plain + '===='.slice( ( plain.length % 4 ) || 4 );
|
||||
}
|
||||
|
||||
function atob( coded ) {
|
||||
var i;
|
||||
|
||||
if ( ! c ) {
|
||||
init();
|
||||
}
|
||||
|
||||
coded = coded.replace( /[^A-Za-z0-9\+\/\=]/g, '' );
|
||||
coded = String(coded).split('=');
|
||||
i = coded.length;
|
||||
|
||||
do {
|
||||
--i;
|
||||
coded[i] = code( coded[i], true, r64, a256, 6, 8 );
|
||||
} while ( i > 0 );
|
||||
|
||||
coded = coded.join('');
|
||||
return coded;
|
||||
}
|
||||
|
||||
return {
|
||||
atob: atob,
|
||||
btoa: btoa
|
||||
};
|
||||
})();
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
painter = this;
|
||||
selector = $( '#adminmenu .wp-menu-image, #wpadminbar .ab-item' );
|
||||
|
||||
this.setColors();
|
||||
this.findElements();
|
||||
this.paint();
|
||||
},
|
||||
|
||||
setColors: function( colors ) {
|
||||
if ( typeof colors === 'undefined' && typeof window._wpColorScheme !== 'undefined' ) {
|
||||
colors = window._wpColorScheme;
|
||||
}
|
||||
|
||||
if ( colors && colors.icons && colors.icons.base && colors.icons.current && colors.icons.focus ) {
|
||||
colorscheme = colors.icons;
|
||||
}
|
||||
},
|
||||
|
||||
findElements: function() {
|
||||
selector.each( function() {
|
||||
var $this = $(this), bgImage = $this.css( 'background-image' );
|
||||
|
||||
if ( bgImage && bgImage.indexOf( 'data:image/svg+xml;base64' ) != -1 ) {
|
||||
elements.push( $this );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
paint: function() {
|
||||
// Loop through all elements.
|
||||
$.each( elements, function( index, $element ) {
|
||||
var $menuitem = $element.parent().parent();
|
||||
|
||||
if ( $menuitem.hasClass( 'current' ) || $menuitem.hasClass( 'wp-has-current-submenu' ) ) {
|
||||
// Paint icon in 'current' color.
|
||||
painter.paintElement( $element, 'current' );
|
||||
} else {
|
||||
// Paint icon in base color.
|
||||
painter.paintElement( $element, 'base' );
|
||||
|
||||
// Set hover callbacks.
|
||||
$menuitem.on( 'mouseenter', function() {
|
||||
painter.paintElement( $element, 'focus' );
|
||||
} ).on( 'mouseleave', function() {
|
||||
// Match the delay from hoverIntent.
|
||||
window.setTimeout( function() {
|
||||
painter.paintElement( $element, 'base' );
|
||||
}, 100 );
|
||||
} );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
paintElement: function( $element, colorType ) {
|
||||
var xml, encoded, color;
|
||||
|
||||
if ( ! colorType || ! colorscheme.hasOwnProperty( colorType ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
color = colorscheme[ colorType ];
|
||||
|
||||
// Only accept hex colors: #101 or #101010.
|
||||
if ( ! color.match( /^(#[0-9a-f]{3}|#[0-9a-f]{6})$/i ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
xml = $element.data( 'wp-ui-svg-' + color );
|
||||
|
||||
if ( xml === 'none' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! xml ) {
|
||||
encoded = $element.css( 'background-image' ).match( /.+data:image\/svg\+xml;base64,([A-Za-z0-9\+\/\=]+)/ );
|
||||
|
||||
if ( ! encoded || ! encoded[1] ) {
|
||||
$element.data( 'wp-ui-svg-' + color, 'none' );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( 'atob' in window ) {
|
||||
xml = window.atob( encoded[1] );
|
||||
} else {
|
||||
xml = base64.atob( encoded[1] );
|
||||
}
|
||||
} catch ( error ) {}
|
||||
|
||||
if ( xml ) {
|
||||
// Replace `fill` attributes.
|
||||
xml = xml.replace( /fill="(.+?)"/g, 'fill="' + color + '"');
|
||||
|
||||
// Replace `style` attributes.
|
||||
xml = xml.replace( /style="(.+?)"/g, 'style="fill:' + color + '"');
|
||||
|
||||
// Replace `fill` properties in `<style>` tags.
|
||||
xml = xml.replace( /fill:.*?;/g, 'fill: ' + color + ';');
|
||||
|
||||
if ( 'btoa' in window ) {
|
||||
xml = window.btoa( xml );
|
||||
} else {
|
||||
xml = base64.btoa( xml );
|
||||
}
|
||||
|
||||
$element.data( 'wp-ui-svg-' + color, xml );
|
||||
} else {
|
||||
$element.data( 'wp-ui-svg-' + color, 'none' );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$element.attr( 'style', 'background-image: url("data:image/svg+xml;base64,' + xml + '") !important;' );
|
||||
}
|
||||
};
|
||||
|
||||
})( jQuery, window, document );
|
2
wp-admin/js/svg-painter.min.js
vendored
Normal file
2
wp-admin/js/svg-painter.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
window.wp=window.wp||{},wp.svgPainter=function(e,i,n){"use strict";var t,o,a,m,r,s,c,u,l,f={},g=[];function p(){for(;l<256;)m=String.fromCharCode(l),s+=m,u[l]=l,c[l]=r.indexOf(m),++l}function d(n,t,e,a,i,o){for(var r,s=0,c=0,u="",l=0,f=(n=String(n)).length;c<f;){for(s=(s<<i)+(m=(m=n.charCodeAt(c))<256?e[m]:-1),l+=i;o<=l;)l-=o,u+=a.charAt(r=s>>l),s^=r<<l;++c}return!t&&0<l&&(u+=a.charAt(s<<o-l)),u}return e(function(){n.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")&&(e(n.body).removeClass("no-svg").addClass("svg"),wp.svgPainter.init())}),r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s="",c=[256],u=[256],l=0,o={atob:function(n){var t;for(m||p(),n=n.replace(/[^A-Za-z0-9\+\/\=]/g,""),t=(n=String(n).split("=")).length;n[--t]=d(n[t],!0,c,s,6,8),0<t;);return n=n.join("")},btoa:function(n){return m||p(),(n=d(n,!1,u,r,8,6))+"====".slice(n.length%4||4)}},{init:function(){a=this,t=e("#adminmenu .wp-menu-image, #wpadminbar .ab-item"),this.setColors(),this.findElements(),this.paint()},setColors:function(n){(n=void 0===n&&void 0!==i._wpColorScheme?i._wpColorScheme:n)&&n.icons&&n.icons.base&&n.icons.current&&n.icons.focus&&(f=n.icons)},findElements:function(){t.each(function(){var n=e(this),t=n.css("background-image");t&&-1!=t.indexOf("data:image/svg+xml;base64")&&g.push(n)})},paint:function(){e.each(g,function(n,t){var e=t.parent().parent();e.hasClass("current")||e.hasClass("wp-has-current-submenu")?a.paintElement(t,"current"):(a.paintElement(t,"base"),e.on("mouseenter",function(){a.paintElement(t,"focus")}).on("mouseleave",function(){i.setTimeout(function(){a.paintElement(t,"base")},100)}))})},paintElement:function(n,t){var e,a;if(t&&f.hasOwnProperty(t)&&(t=f[t]).match(/^(#[0-9a-f]{3}|#[0-9a-f]{6})$/i)&&"none"!==(e=n.data("wp-ui-svg-"+t))){if(!e){if(!(a=n.css("background-image").match(/.+data:image\/svg\+xml;base64,([A-Za-z0-9\+\/\=]+)/))||!a[1])return void n.data("wp-ui-svg-"+t,"none");try{e=("atob"in i?i:o).atob(a[1])}catch(n){}if(!e)return void n.data("wp-ui-svg-"+t,"none");e=(e=(e=e.replace(/fill="(.+?)"/g,'fill="'+t+'"')).replace(/style="(.+?)"/g,'style="fill:'+t+'"')).replace(/fill:.*?;/g,"fill: "+t+";"),e=("btoa"in i?i:o).btoa(e),n.data("wp-ui-svg-"+t,e)}n.attr("style",'background-image: url("data:image/svg+xml;base64,'+e+'") !important;')}}}}(jQuery,window,document);
|
440
wp-admin/js/tags-box.js
Normal file
440
wp-admin/js/tags-box.js
Normal file
@ -0,0 +1,440 @@
|
||||
/**
|
||||
* @output wp-admin/js/tags-box.js
|
||||
*/
|
||||
|
||||
/* jshint curly: false, eqeqeq: false */
|
||||
/* global ajaxurl, tagBox, array_unique_noempty */
|
||||
|
||||
( function( $ ) {
|
||||
var tagDelimiter = wp.i18n._x( ',', 'tag delimiter' ) || ',';
|
||||
|
||||
/**
|
||||
* Filters unique items and returns a new array.
|
||||
*
|
||||
* Filters all items from an array into a new array containing only the unique
|
||||
* items. This also excludes whitespace or empty values.
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @param {Array} array The array to filter through.
|
||||
*
|
||||
* @return {Array} A new array containing only the unique items.
|
||||
*/
|
||||
window.array_unique_noempty = function( array ) {
|
||||
var out = [];
|
||||
|
||||
// Trim the values and ensure they are unique.
|
||||
$.each( array, function( key, val ) {
|
||||
val = val || '';
|
||||
val = val.trim();
|
||||
|
||||
if ( val && $.inArray( val, out ) === -1 ) {
|
||||
out.push( val );
|
||||
}
|
||||
} );
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
/**
|
||||
* The TagBox object.
|
||||
*
|
||||
* Contains functions to create and manage tags that can be associated with a
|
||||
* post.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @global
|
||||
*/
|
||||
window.tagBox = {
|
||||
/**
|
||||
* Cleans up tags by removing redundant characters.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @memberOf tagBox
|
||||
*
|
||||
* @param {string} tags Comma separated tags that need to be cleaned up.
|
||||
*
|
||||
* @return {string} The cleaned up tags.
|
||||
*/
|
||||
clean : function( tags ) {
|
||||
if ( ',' !== tagDelimiter ) {
|
||||
tags = tags.replace( new RegExp( tagDelimiter, 'g' ), ',' );
|
||||
}
|
||||
|
||||
tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, '');
|
||||
|
||||
if ( ',' !== tagDelimiter ) {
|
||||
tags = tags.replace( /,/g, tagDelimiter );
|
||||
}
|
||||
|
||||
return tags;
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses tags and makes them editable.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @memberOf tagBox
|
||||
*
|
||||
* @param {Object} el The tag element to retrieve the ID from.
|
||||
*
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
parseTags : function(el) {
|
||||
var id = el.id,
|
||||
num = id.split('-check-num-')[1],
|
||||
taxbox = $(el).closest('.tagsdiv'),
|
||||
thetags = taxbox.find('.the-tags'),
|
||||
current_tags = thetags.val().split( tagDelimiter ),
|
||||
new_tags = [];
|
||||
|
||||
delete current_tags[num];
|
||||
|
||||
// Sanitize the current tags and push them as if they're new tags.
|
||||
$.each( current_tags, function( key, val ) {
|
||||
val = val || '';
|
||||
val = val.trim();
|
||||
if ( val ) {
|
||||
new_tags.push( val );
|
||||
}
|
||||
});
|
||||
|
||||
thetags.val( this.clean( new_tags.join( tagDelimiter ) ) );
|
||||
|
||||
this.quickClicks( taxbox );
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates clickable links, buttons and fields for adding or editing tags.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @memberOf tagBox
|
||||
*
|
||||
* @param {Object} el The container HTML element.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
quickClicks : function( el ) {
|
||||
var thetags = $('.the-tags', el),
|
||||
tagchecklist = $('.tagchecklist', el),
|
||||
id = $(el).attr('id'),
|
||||
current_tags, disabled;
|
||||
|
||||
if ( ! thetags.length )
|
||||
return;
|
||||
|
||||
disabled = thetags.prop('disabled');
|
||||
|
||||
current_tags = thetags.val().split( tagDelimiter );
|
||||
tagchecklist.empty();
|
||||
|
||||
/**
|
||||
* Creates a delete button if tag editing is enabled, before adding it to the tag list.
|
||||
*
|
||||
* @since 2.5.0
|
||||
*
|
||||
* @memberOf tagBox
|
||||
*
|
||||
* @param {string} key The index of the current tag.
|
||||
* @param {string} val The value of the current tag.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$.each( current_tags, function( key, val ) {
|
||||
var listItem, xbutton;
|
||||
|
||||
val = val || '';
|
||||
val = val.trim();
|
||||
|
||||
if ( ! val )
|
||||
return;
|
||||
|
||||
// Create a new list item, and ensure the text is properly escaped.
|
||||
listItem = $( '<li />' ).text( val );
|
||||
|
||||
// If tags editing isn't disabled, create the X button.
|
||||
if ( ! disabled ) {
|
||||
/*
|
||||
* Build the X buttons, hide the X icon with aria-hidden and
|
||||
* use visually hidden text for screen readers.
|
||||
*/
|
||||
xbutton = $( '<button type="button" id="' + id + '-check-num-' + key + '" class="ntdelbutton">' +
|
||||
'<span class="remove-tag-icon" aria-hidden="true"></span>' +
|
||||
'<span class="screen-reader-text">' + wp.i18n.__( 'Remove term:' ) + ' ' + listItem.html() + '</span>' +
|
||||
'</button>' );
|
||||
|
||||
/**
|
||||
* Handles the click and keypress event of the tag remove button.
|
||||
*
|
||||
* Makes sure the focus ends up in the tag input field when using
|
||||
* the keyboard to delete the tag.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param {Event} e The click or keypress event to handle.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
xbutton.on( 'click keypress', function( e ) {
|
||||
// On click or when using the Enter/Spacebar keys.
|
||||
if ( 'click' === e.type || 13 === e.keyCode || 32 === e.keyCode ) {
|
||||
/*
|
||||
* When using the keyboard, move focus back to the
|
||||
* add new tag field. Note: when releasing the pressed
|
||||
* key this will fire the `keyup` event on the input.
|
||||
*/
|
||||
if ( 13 === e.keyCode || 32 === e.keyCode ) {
|
||||
$( this ).closest( '.tagsdiv' ).find( 'input.newtag' ).trigger( 'focus' );
|
||||
}
|
||||
|
||||
tagBox.userAction = 'remove';
|
||||
tagBox.parseTags( this );
|
||||
}
|
||||
});
|
||||
|
||||
listItem.prepend( ' ' ).prepend( xbutton );
|
||||
}
|
||||
|
||||
// Append the list item to the tag list.
|
||||
tagchecklist.append( listItem );
|
||||
});
|
||||
|
||||
// The buttons list is built now, give feedback to screen reader users.
|
||||
tagBox.screenReadersMessage();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new tag.
|
||||
*
|
||||
* Also ensures that the quick links are properly generated.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @memberOf tagBox
|
||||
*
|
||||
* @param {Object} el The container HTML element.
|
||||
* @param {Object|boolean} a When this is an HTML element the text of that
|
||||
* element will be used for the new tag.
|
||||
* @param {number|boolean} f If this value is not passed then the tag input
|
||||
* field is focused.
|
||||
*
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
flushTags : function( el, a, f ) {
|
||||
var tagsval, newtags, text,
|
||||
tags = $( '.the-tags', el ),
|
||||
newtag = $( 'input.newtag', el );
|
||||
|
||||
a = a || false;
|
||||
|
||||
text = a ? $(a).text() : newtag.val();
|
||||
|
||||
/*
|
||||
* Return if there's no new tag or if the input field is empty.
|
||||
* Note: when using the keyboard to add tags, focus is moved back to
|
||||
* the input field and the `keyup` event attached on this field will
|
||||
* fire when releasing the pressed key. Checking also for the field
|
||||
* emptiness avoids to set the tags and call quickClicks() again.
|
||||
*/
|
||||
if ( 'undefined' == typeof( text ) || '' === text ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tagsval = tags.val();
|
||||
newtags = tagsval ? tagsval + tagDelimiter + text : text;
|
||||
|
||||
newtags = this.clean( newtags );
|
||||
newtags = array_unique_noempty( newtags.split( tagDelimiter ) ).join( tagDelimiter );
|
||||
tags.val( newtags );
|
||||
this.quickClicks( el );
|
||||
|
||||
if ( ! a )
|
||||
newtag.val('');
|
||||
if ( 'undefined' == typeof( f ) )
|
||||
newtag.trigger( 'focus' );
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the available tags and creates a tagcloud.
|
||||
*
|
||||
* Retrieves the available tags from the database and creates an interactive
|
||||
* tagcloud. Clicking a tag will add it.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @memberOf tagBox
|
||||
*
|
||||
* @param {string} id The ID to extract the taxonomy from.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
get : function( id ) {
|
||||
var tax = id.substr( id.indexOf('-') + 1 );
|
||||
|
||||
/**
|
||||
* Puts a received tag cloud into a DOM element.
|
||||
*
|
||||
* The tag cloud HTML is generated on the server.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param {number|string} r The response message from the Ajax call.
|
||||
* @param {string} stat The status of the Ajax request.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$.post( ajaxurl, { 'action': 'get-tagcloud', 'tax': tax }, function( r, stat ) {
|
||||
if ( 0 === r || 'success' != stat ) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = $( '<div id="tagcloud-' + tax + '" class="the-tagcloud">' + r + '</div>' );
|
||||
|
||||
/**
|
||||
* Adds a new tag when a tag in the tagcloud is clicked.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return {boolean} Returns false to prevent the default action.
|
||||
*/
|
||||
$( 'a', r ).on( 'click', function() {
|
||||
tagBox.userAction = 'add';
|
||||
tagBox.flushTags( $( '#' + tax ), this );
|
||||
return false;
|
||||
});
|
||||
|
||||
$( '#' + id ).after( r );
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Track the user's last action.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*/
|
||||
userAction: '',
|
||||
|
||||
/**
|
||||
* Dispatches an audible message to screen readers.
|
||||
*
|
||||
* This will inform the user when a tag has been added or removed.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
screenReadersMessage: function() {
|
||||
var message;
|
||||
|
||||
switch ( this.userAction ) {
|
||||
case 'remove':
|
||||
message = wp.i18n.__( 'Term removed.' );
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
message = wp.i18n.__( 'Term added.' );
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
window.wp.a11y.speak( message, 'assertive' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the tags box by setting up the links, buttons. Sets up event
|
||||
* handling.
|
||||
*
|
||||
* This includes handling of pressing the enter key in the input field and the
|
||||
* retrieval of tag suggestions.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @memberOf tagBox
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
init : function() {
|
||||
var ajaxtag = $('div.ajaxtag');
|
||||
|
||||
$('.tagsdiv').each( function() {
|
||||
tagBox.quickClicks( this );
|
||||
});
|
||||
|
||||
$( '.tagadd', ajaxtag ).on( 'click', function() {
|
||||
tagBox.userAction = 'add';
|
||||
tagBox.flushTags( $( this ).closest( '.tagsdiv' ) );
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles pressing enter on the new tag input field.
|
||||
*
|
||||
* Prevents submitting the post edit form. Uses `keypress` to take
|
||||
* into account Input Method Editor (IME) converters.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param {Event} event The keypress event that occurred.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( 'input.newtag', ajaxtag ).on( 'keypress', function( event ) {
|
||||
if ( 13 == event.which ) {
|
||||
tagBox.userAction = 'add';
|
||||
tagBox.flushTags( $( this ).closest( '.tagsdiv' ) );
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}).each( function( i, element ) {
|
||||
$( element ).wpTagsSuggest();
|
||||
});
|
||||
|
||||
/**
|
||||
* Before a post is saved the value currently in the new tag input field will be
|
||||
* added as a tag.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('#post').on( 'submit', function(){
|
||||
$('div.tagsdiv').each( function() {
|
||||
tagBox.flushTags(this, false, 1);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles clicking on the tag cloud link.
|
||||
*
|
||||
* Makes sure the ARIA attributes are set correctly.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$('.tagcloud-link').on( 'click', function(){
|
||||
// On the first click, fetch the tag cloud and insert it in the DOM.
|
||||
tagBox.get( $( this ).attr( 'id' ) );
|
||||
// Update button state, remove previous click event and attach a new one to toggle the cloud.
|
||||
$( this )
|
||||
.attr( 'aria-expanded', 'true' )
|
||||
.off()
|
||||
.on( 'click', function() {
|
||||
$( this )
|
||||
.attr( 'aria-expanded', 'false' === $( this ).attr( 'aria-expanded' ) ? 'true' : 'false' )
|
||||
.siblings( '.the-tagcloud' ).toggle();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}( jQuery ));
|
2
wp-admin/js/tags-box.min.js
vendored
Normal file
2
wp-admin/js/tags-box.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(o){var r=wp.i18n._x(",","tag delimiter")||",";window.array_unique_noempty=function(t){var a=[];return o.each(t,function(t,e){(e=(e=e||"").trim())&&-1===o.inArray(e,a)&&a.push(e)}),a},window.tagBox={clean:function(t){return t=(t=","!==r?t.replace(new RegExp(r,"g"),","):t).replace(/\s*,\s*/g,",").replace(/,+/g,",").replace(/[,\s]+$/,"").replace(/^[,\s]+/,""),t=","!==r?t.replace(/,/g,r):t},parseTags:function(t){var e=t.id.split("-check-num-")[1],t=o(t).closest(".tagsdiv"),a=t.find(".the-tags"),i=a.val().split(r),n=[];return delete i[e],o.each(i,function(t,e){(e=(e=e||"").trim())&&n.push(e)}),a.val(this.clean(n.join(r))),this.quickClicks(t),!1},quickClicks:function(t){var a,e=o(".the-tags",t),i=o(".tagchecklist",t),n=o(t).attr("id");e.length&&(a=e.prop("disabled"),t=e.val().split(r),i.empty(),o.each(t,function(t,e){(e=(e=e||"").trim())&&(e=o("<li />").text(e),a||((t=o('<button type="button" id="'+n+"-check-num-"+t+'" class="ntdelbutton"><span class="remove-tag-icon" aria-hidden="true"></span><span class="screen-reader-text">'+wp.i18n.__("Remove term:")+" "+e.html()+"</span></button>")).on("click keypress",function(t){"click"!==t.type&&13!==t.keyCode&&32!==t.keyCode||(13!==t.keyCode&&32!==t.keyCode||o(this).closest(".tagsdiv").find("input.newtag").trigger("focus"),tagBox.userAction="remove",tagBox.parseTags(this))}),e.prepend(" ").prepend(t)),i.append(e))}),tagBox.screenReadersMessage())},flushTags:function(t,e,a){var i,n,s=o(".the-tags",t),c=o("input.newtag",t);return void 0!==(n=(e=e||!1)?o(e).text():c.val())&&""!==n&&(i=s.val(),i=this.clean(i=i?i+r+n:n),i=array_unique_noempty(i.split(r)).join(r),s.val(i),this.quickClicks(t),e||c.val(""),void 0===a)&&c.trigger("focus"),!1},get:function(a){var i=a.substr(a.indexOf("-")+1);o.post(ajaxurl,{action:"get-tagcloud",tax:i},function(t,e){0!==t&&"success"==e&&(t=o('<div id="tagcloud-'+i+'" class="the-tagcloud">'+t+"</div>"),o("a",t).on("click",function(){return tagBox.userAction="add",tagBox.flushTags(o("#"+i),this),!1}),o("#"+a).after(t))})},userAction:"",screenReadersMessage:function(){var t;switch(this.userAction){case"remove":t=wp.i18n.__("Term removed.");break;case"add":t=wp.i18n.__("Term added.");break;default:return}window.wp.a11y.speak(t,"assertive")},init:function(){var t=o("div.ajaxtag");o(".tagsdiv").each(function(){tagBox.quickClicks(this)}),o(".tagadd",t).on("click",function(){tagBox.userAction="add",tagBox.flushTags(o(this).closest(".tagsdiv"))}),o("input.newtag",t).on("keypress",function(t){13==t.which&&(tagBox.userAction="add",tagBox.flushTags(o(this).closest(".tagsdiv")),t.preventDefault(),t.stopPropagation())}).each(function(t,e){o(e).wpTagsSuggest()}),o("#post").on("submit",function(){o("div.tagsdiv").each(function(){tagBox.flushTags(this,!1,1)})}),o(".tagcloud-link").on("click",function(){tagBox.get(o(this).attr("id")),o(this).attr("aria-expanded","true").off().on("click",function(){o(this).attr("aria-expanded","false"===o(this).attr("aria-expanded")?"true":"false").siblings(".the-tagcloud").toggle()})})}}}(jQuery);
|
212
wp-admin/js/tags-suggest.js
Normal file
212
wp-admin/js/tags-suggest.js
Normal file
@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Default settings for jQuery UI Autocomplete for use with non-hierarchical taxonomies.
|
||||
*
|
||||
* @output wp-admin/js/tags-suggest.js
|
||||
*/
|
||||
( function( $ ) {
|
||||
var tempID = 0;
|
||||
var separator = wp.i18n._x( ',', 'tag delimiter' ) || ',';
|
||||
var __ = wp.i18n.__,
|
||||
_n = wp.i18n._n,
|
||||
sprintf = wp.i18n.sprintf;
|
||||
|
||||
function split( val ) {
|
||||
return val.split( new RegExp( separator + '\\s*' ) );
|
||||
}
|
||||
|
||||
function getLast( term ) {
|
||||
return split( term ).pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add UI Autocomplete to an input or textarea element with presets for use
|
||||
* with non-hierarchical taxonomies.
|
||||
*
|
||||
* Example: `$( element ).wpTagsSuggest( options )`.
|
||||
*
|
||||
* The taxonomy can be passed in a `data-wp-taxonomy` attribute on the element or
|
||||
* can be in `options.taxonomy`.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param {Object} options Options that are passed to UI Autocomplete. Can be used to override the default settings.
|
||||
* @return {Object} jQuery instance.
|
||||
*/
|
||||
$.fn.wpTagsSuggest = function( options ) {
|
||||
var cache;
|
||||
var last;
|
||||
var $element = $( this );
|
||||
|
||||
// Do not initialize if the element doesn't exist.
|
||||
if ( ! $element.length ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
var taxonomy = options.taxonomy || $element.attr( 'data-wp-taxonomy' ) || 'post_tag';
|
||||
|
||||
delete( options.taxonomy );
|
||||
|
||||
options = $.extend( {
|
||||
source: function( request, response ) {
|
||||
var term;
|
||||
|
||||
if ( last === request.term ) {
|
||||
response( cache );
|
||||
return;
|
||||
}
|
||||
|
||||
term = getLast( request.term );
|
||||
|
||||
$.get( window.ajaxurl, {
|
||||
action: 'ajax-tag-search',
|
||||
tax: taxonomy,
|
||||
q: term,
|
||||
number: 20
|
||||
} ).always( function() {
|
||||
$element.removeClass( 'ui-autocomplete-loading' ); // UI fails to remove this sometimes?
|
||||
} ).done( function( data ) {
|
||||
var tagName;
|
||||
var tags = [];
|
||||
|
||||
if ( data ) {
|
||||
data = data.split( '\n' );
|
||||
|
||||
for ( tagName in data ) {
|
||||
var id = ++tempID;
|
||||
|
||||
tags.push({
|
||||
id: id,
|
||||
name: data[tagName]
|
||||
});
|
||||
}
|
||||
|
||||
cache = tags;
|
||||
response( tags );
|
||||
} else {
|
||||
response( tags );
|
||||
}
|
||||
} );
|
||||
|
||||
last = request.term;
|
||||
},
|
||||
focus: function( event, ui ) {
|
||||
$element.attr( 'aria-activedescendant', 'wp-tags-autocomplete-' + ui.item.id );
|
||||
|
||||
// Don't empty the input field when using the arrow keys
|
||||
// to highlight items. See api.jqueryui.com/autocomplete/#event-focus
|
||||
event.preventDefault();
|
||||
},
|
||||
select: function( event, ui ) {
|
||||
var tags = split( $element.val() );
|
||||
// Remove the last user input.
|
||||
tags.pop();
|
||||
// Append the new tag and an empty element to get one more separator at the end.
|
||||
tags.push( ui.item.name, '' );
|
||||
|
||||
$element.val( tags.join( separator + ' ' ) );
|
||||
|
||||
if ( $.ui.keyCode.TAB === event.keyCode ) {
|
||||
// Audible confirmation message when a tag has been selected.
|
||||
window.wp.a11y.speak( wp.i18n.__( 'Term selected.' ), 'assertive' );
|
||||
event.preventDefault();
|
||||
} else if ( $.ui.keyCode.ENTER === event.keyCode ) {
|
||||
// If we're in the edit post Tags meta box, add the tag.
|
||||
if ( window.tagBox ) {
|
||||
window.tagBox.userAction = 'add';
|
||||
window.tagBox.flushTags( $( this ).closest( '.tagsdiv' ) );
|
||||
}
|
||||
|
||||
// Do not close Quick Edit / Bulk Edit.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
open: function() {
|
||||
$element.attr( 'aria-expanded', 'true' );
|
||||
},
|
||||
close: function() {
|
||||
$element.attr( 'aria-expanded', 'false' );
|
||||
},
|
||||
minLength: 2,
|
||||
position: {
|
||||
my: 'left top+2',
|
||||
at: 'left bottom',
|
||||
collision: 'none'
|
||||
},
|
||||
messages: {
|
||||
noResults: __( 'No results found.' ),
|
||||
results: function( number ) {
|
||||
return sprintf(
|
||||
/* translators: %d: Number of search results found. */
|
||||
_n(
|
||||
'%d result found. Use up and down arrow keys to navigate.',
|
||||
'%d results found. Use up and down arrow keys to navigate.',
|
||||
number
|
||||
),
|
||||
number
|
||||
);
|
||||
}
|
||||
}
|
||||
}, options );
|
||||
|
||||
$element.on( 'keydown', function() {
|
||||
$element.removeAttr( 'aria-activedescendant' );
|
||||
} );
|
||||
|
||||
$element.autocomplete( options );
|
||||
|
||||
// Ensure the autocomplete instance exists.
|
||||
if ( ! $element.autocomplete( 'instance' ) ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
$element.autocomplete( 'instance' )._renderItem = function( ul, item ) {
|
||||
return $( '<li role="option" id="wp-tags-autocomplete-' + item.id + '">' )
|
||||
.text( item.name )
|
||||
.appendTo( ul );
|
||||
};
|
||||
|
||||
$element.attr( {
|
||||
'role': 'combobox',
|
||||
'aria-autocomplete': 'list',
|
||||
'aria-expanded': 'false',
|
||||
'aria-owns': $element.autocomplete( 'widget' ).attr( 'id' )
|
||||
} )
|
||||
.on( 'focus', function() {
|
||||
var inputValue = split( $element.val() ).pop();
|
||||
|
||||
// Don't trigger a search if the field is empty.
|
||||
// Also, avoids screen readers announce `No search results`.
|
||||
if ( inputValue ) {
|
||||
$element.autocomplete( 'search' );
|
||||
}
|
||||
} );
|
||||
|
||||
// Returns a jQuery object containing the menu element.
|
||||
$element.autocomplete( 'widget' )
|
||||
.addClass( 'wp-tags-autocomplete' )
|
||||
.attr( 'role', 'listbox' )
|
||||
.removeAttr( 'tabindex' ) // Remove the `tabindex=0` attribute added by jQuery UI.
|
||||
|
||||
/*
|
||||
* Looks like Safari and VoiceOver need an `aria-selected` attribute. See ticket #33301.
|
||||
* The `menufocus` and `menublur` events are the same events used to add and remove
|
||||
* the `ui-state-focus` CSS class on the menu items. See jQuery UI Menu Widget.
|
||||
*/
|
||||
.on( 'menufocus', function( event, ui ) {
|
||||
ui.item.attr( 'aria-selected', 'true' );
|
||||
})
|
||||
.on( 'menublur', function() {
|
||||
// The `menublur` event returns an object where the item is `null`,
|
||||
// so we need to find the active item with other means.
|
||||
$( this ).find( '[aria-selected="true"]' ).removeAttr( 'aria-selected' );
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
}( jQuery ) );
|
2
wp-admin/js/tags-suggest.min.js
vendored
Normal file
2
wp-admin/js/tags-suggest.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(s){var u=0,n=wp.i18n._x(",","tag delimiter")||",",t=wp.i18n.__,d=wp.i18n._n,l=wp.i18n.sprintf;function p(e){return e.split(new RegExp(n+"\\s*"))}s.fn.wpTagsSuggest=function(e){var i,o,a,r=s(this);return r.length&&(a=(e=e||{}).taxonomy||r.attr("data-wp-taxonomy")||"post_tag",delete e.taxonomy,e=s.extend({source:function(e,n){var t;o===e.term?n(i):(t=p(e.term).pop(),s.get(window.ajaxurl,{action:"ajax-tag-search",tax:a,q:t,number:20}).always(function(){r.removeClass("ui-autocomplete-loading")}).done(function(e){var t,o=[];if(e){for(t in e=e.split("\n")){var a=++u;o.push({id:a,name:e[t]})}n(i=o)}else n(o)}),o=e.term)},focus:function(e,t){r.attr("aria-activedescendant","wp-tags-autocomplete-"+t.item.id),e.preventDefault()},select:function(e,t){var o=p(r.val());return o.pop(),o.push(t.item.name,""),r.val(o.join(n+" ")),s.ui.keyCode.TAB===e.keyCode?(window.wp.a11y.speak(wp.i18n.__("Term selected."),"assertive"),e.preventDefault()):s.ui.keyCode.ENTER===e.keyCode&&(window.tagBox&&(window.tagBox.userAction="add",window.tagBox.flushTags(s(this).closest(".tagsdiv"))),e.preventDefault(),e.stopPropagation()),!1},open:function(){r.attr("aria-expanded","true")},close:function(){r.attr("aria-expanded","false")},minLength:2,position:{my:"left top+2",at:"left bottom",collision:"none"},messages:{noResults:t("No results found."),results:function(e){return l(d("%d result found. Use up and down arrow keys to navigate.","%d results found. Use up and down arrow keys to navigate.",e),e)}}},e),r.on("keydown",function(){r.removeAttr("aria-activedescendant")}),r.autocomplete(e),r.autocomplete("instance"))&&(r.autocomplete("instance")._renderItem=function(e,t){return s('<li role="option" id="wp-tags-autocomplete-'+t.id+'">').text(t.name).appendTo(e)},r.attr({role:"combobox","aria-autocomplete":"list","aria-expanded":"false","aria-owns":r.autocomplete("widget").attr("id")}).on("focus",function(){p(r.val()).pop()&&r.autocomplete("search")}),r.autocomplete("widget").addClass("wp-tags-autocomplete").attr("role","listbox").removeAttr("tabindex").on("menufocus",function(e,t){t.item.attr("aria-selected","true")}).on("menublur",function(){s(this).find('[aria-selected="true"]').removeAttr("aria-selected")})),this}}(jQuery);
|
167
wp-admin/js/tags.js
Normal file
167
wp-admin/js/tags.js
Normal file
@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Contains logic for deleting and adding tags.
|
||||
*
|
||||
* For deleting tags it makes a request to the server to delete the tag.
|
||||
* For adding tags it makes a request to the server to add the tag.
|
||||
*
|
||||
* @output wp-admin/js/tags.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, wpAjax, showNotice, validateForm */
|
||||
|
||||
jQuery( function($) {
|
||||
|
||||
var addingTerm = false;
|
||||
|
||||
/**
|
||||
* Adds an event handler to the delete term link on the term overview page.
|
||||
*
|
||||
* Cancels default event handling and event bubbling.
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @return {boolean} Always returns false to cancel the default event handling.
|
||||
*/
|
||||
$( '#the-list' ).on( 'click', '.delete-tag', function() {
|
||||
var t = $(this), tr = t.parents('tr'), r = true, data;
|
||||
|
||||
if ( 'undefined' != showNotice )
|
||||
r = showNotice.warn();
|
||||
|
||||
if ( r ) {
|
||||
data = t.attr('href').replace(/[^?]*\?/, '').replace(/action=delete/, 'action=delete-tag');
|
||||
|
||||
/**
|
||||
* Makes a request to the server to delete the term that corresponds to the
|
||||
* delete term button.
|
||||
*
|
||||
* @param {string} r The response from the server.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$.post(ajaxurl, data, function(r){
|
||||
if ( '1' == r ) {
|
||||
$('#ajax-response').empty();
|
||||
tr.fadeOut('normal', function(){ tr.remove(); });
|
||||
|
||||
/**
|
||||
* Removes the term from the parent box and the tag cloud.
|
||||
*
|
||||
* `data.match(/tag_ID=(\d+)/)[1]` matches the term ID from the data variable.
|
||||
* This term ID is then used to select the relevant HTML elements:
|
||||
* The parent box and the tag cloud.
|
||||
*/
|
||||
$('select#parent option[value="' + data.match(/tag_ID=(\d+)/)[1] + '"]').remove();
|
||||
$('a.tag-link-' + data.match(/tag_ID=(\d+)/)[1]).remove();
|
||||
|
||||
} else if ( '-1' == r ) {
|
||||
$('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Sorry, you are not allowed to do that.' ) + '</p></div>');
|
||||
tr.children().css('backgroundColor', '');
|
||||
|
||||
} else {
|
||||
$('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Something went wrong.' ) + '</p></div>');
|
||||
tr.children().css('backgroundColor', '');
|
||||
}
|
||||
});
|
||||
|
||||
tr.children().css('backgroundColor', '#f33');
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds a deletion confirmation when removing a tag.
|
||||
*
|
||||
* @since 4.8.0
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$( '#edittag' ).on( 'click', '.delete', function( e ) {
|
||||
if ( 'undefined' === typeof showNotice ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Confirms the deletion, a negative response means the deletion must not be executed.
|
||||
var response = showNotice.warn();
|
||||
if ( ! response ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds an event handler to the form submit on the term overview page.
|
||||
*
|
||||
* Cancels default event handling and event bubbling.
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @return {boolean} Always returns false to cancel the default event handling.
|
||||
*/
|
||||
$('#submit').on( 'click', function(){
|
||||
var form = $(this).parents('form');
|
||||
|
||||
if ( addingTerm ) {
|
||||
// If we're adding a term, noop the button to avoid duplicate requests.
|
||||
return false;
|
||||
}
|
||||
|
||||
addingTerm = true;
|
||||
form.find( '.submit .spinner' ).addClass( 'is-active' );
|
||||
|
||||
/**
|
||||
* Does a request to the server to add a new term to the database
|
||||
*
|
||||
* @param {string} r The response from the server.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
$.post(ajaxurl, $('#addtag').serialize(), function(r){
|
||||
var res, parent, term, indent, i;
|
||||
|
||||
addingTerm = false;
|
||||
form.find( '.submit .spinner' ).removeClass( 'is-active' );
|
||||
|
||||
$('#ajax-response').empty();
|
||||
res = wpAjax.parseAjaxResponse( r, 'ajax-response' );
|
||||
|
||||
if ( res.errors && res.responses[0].errors[0].code === 'empty_term_name' ) {
|
||||
validateForm( form );
|
||||
}
|
||||
|
||||
if ( ! res || res.errors ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent = form.find( 'select#parent' ).val();
|
||||
|
||||
// If the parent exists on this page, insert it below. Else insert it at the top of the list.
|
||||
if ( parent > 0 && $('#tag-' + parent ).length > 0 ) {
|
||||
// As the parent exists, insert the version with - - - prefixed.
|
||||
$( '.tags #tag-' + parent ).after( res.responses[0].supplemental.noparents );
|
||||
} else {
|
||||
// As the parent is not visible, insert the version with Parent - Child - ThisTerm.
|
||||
$( '.tags' ).prepend( res.responses[0].supplemental.parents );
|
||||
}
|
||||
|
||||
$('.tags .no-items').remove();
|
||||
|
||||
if ( form.find('select#parent') ) {
|
||||
// Parents field exists, Add new term to the list.
|
||||
term = res.responses[1].supplemental;
|
||||
|
||||
// Create an indent for the Parent field.
|
||||
indent = '';
|
||||
for ( i = 0; i < res.responses[1].position; i++ )
|
||||
indent += ' ';
|
||||
|
||||
form.find( 'select#parent option:selected' ).after( '<option value="' + term.term_id + '">' + indent + term.name + '</option>' );
|
||||
}
|
||||
|
||||
$('input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):visible, textarea:visible', form).val('');
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
2
wp-admin/js/tags.min.js
vendored
Normal file
2
wp-admin/js/tags.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
jQuery(function(s){var o=!1;s("#the-list").on("click",".delete-tag",function(){var t,e=s(this),n=e.parents("tr"),a=!0;return(a="undefined"!=showNotice?showNotice.warn():a)&&(t=e.attr("href").replace(/[^?]*\?/,"").replace(/action=delete/,"action=delete-tag"),s.post(ajaxurl,t,function(e){"1"==e?(s("#ajax-response").empty(),n.fadeOut("normal",function(){n.remove()}),s('select#parent option[value="'+t.match(/tag_ID=(\d+)/)[1]+'"]').remove(),s("a.tag-link-"+t.match(/tag_ID=(\d+)/)[1]).remove()):("-1"==e?s("#ajax-response").empty().append('<div class="error"><p>'+wp.i18n.__("Sorry, you are not allowed to do that.")+"</p></div>"):s("#ajax-response").empty().append('<div class="error"><p>'+wp.i18n.__("Something went wrong.")+"</p></div>"),n.children().css("backgroundColor",""))}),n.children().css("backgroundColor","#f33")),!1}),s("#edittag").on("click",".delete",function(e){if("undefined"==typeof showNotice)return!0;showNotice.warn()||e.preventDefault()}),s("#submit").on("click",function(){var r=s(this).parents("form");return o||(o=!0,r.find(".submit .spinner").addClass("is-active"),s.post(ajaxurl,s("#addtag").serialize(),function(e){var t,n,a;if(o=!1,r.find(".submit .spinner").removeClass("is-active"),s("#ajax-response").empty(),(t=wpAjax.parseAjaxResponse(e,"ajax-response")).errors&&"empty_term_name"===t.responses[0].errors[0].code&&validateForm(r),t&&!t.errors){if(0<(e=r.find("select#parent").val())&&0<s("#tag-"+e).length?s(".tags #tag-"+e).after(t.responses[0].supplemental.noparents):s(".tags").prepend(t.responses[0].supplemental.parents),s(".tags .no-items").remove(),r.find("select#parent")){for(e=t.responses[1].supplemental,n="",a=0;a<t.responses[1].position;a++)n+=" ";r.find("select#parent option:selected").after('<option value="'+e.term_id+'">'+n+e.name+"</option>")}s('input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):visible, textarea:visible',r).val("")}})),!1})});
|
1026
wp-admin/js/theme-plugin-editor.js
Normal file
1026
wp-admin/js/theme-plugin-editor.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/theme-plugin-editor.min.js
vendored
Normal file
2
wp-admin/js/theme-plugin-editor.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2120
wp-admin/js/theme.js
Normal file
2120
wp-admin/js/theme.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/theme.min.js
vendored
Normal file
2
wp-admin/js/theme.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3511
wp-admin/js/updates.js
Normal file
3511
wp-admin/js/updates.js
Normal file
File diff suppressed because it is too large
Load Diff
2
wp-admin/js/updates.min.js
vendored
Normal file
2
wp-admin/js/updates.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
497
wp-admin/js/user-profile.js
Normal file
497
wp-admin/js/user-profile.js
Normal file
@ -0,0 +1,497 @@
|
||||
/**
|
||||
* @output wp-admin/js/user-profile.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, pwsL10n, userProfileL10n */
|
||||
(function($) {
|
||||
var updateLock = false,
|
||||
__ = wp.i18n.__,
|
||||
$pass1Row,
|
||||
$pass1,
|
||||
$pass2,
|
||||
$weakRow,
|
||||
$weakCheckbox,
|
||||
$toggleButton,
|
||||
$submitButtons,
|
||||
$submitButton,
|
||||
currentPass,
|
||||
$passwordWrapper;
|
||||
|
||||
function generatePassword() {
|
||||
if ( typeof zxcvbn !== 'function' ) {
|
||||
setTimeout( generatePassword, 50 );
|
||||
return;
|
||||
} else if ( ! $pass1.val() || $passwordWrapper.hasClass( 'is-open' ) ) {
|
||||
// zxcvbn loaded before user entered password, or generating new password.
|
||||
$pass1.val( $pass1.data( 'pw' ) );
|
||||
$pass1.trigger( 'pwupdate' );
|
||||
showOrHideWeakPasswordCheckbox();
|
||||
} else {
|
||||
// zxcvbn loaded after the user entered password, check strength.
|
||||
check_pass_strength();
|
||||
showOrHideWeakPasswordCheckbox();
|
||||
}
|
||||
|
||||
/*
|
||||
* This works around a race condition when zxcvbn loads quickly and
|
||||
* causes `generatePassword()` to run prior to the toggle button being
|
||||
* bound.
|
||||
*/
|
||||
bindToggleButton();
|
||||
|
||||
// Install screen.
|
||||
if ( 1 !== parseInt( $toggleButton.data( 'start-masked' ), 10 ) ) {
|
||||
// Show the password not masked if admin_password hasn't been posted yet.
|
||||
$pass1.attr( 'type', 'text' );
|
||||
} else {
|
||||
// Otherwise, mask the password.
|
||||
$toggleButton.trigger( 'click' );
|
||||
}
|
||||
|
||||
// Once zxcvbn loads, passwords strength is known.
|
||||
$( '#pw-weak-text-label' ).text( __( 'Confirm use of weak password' ) );
|
||||
|
||||
// Focus the password field.
|
||||
if ( 'mailserver_pass' !== $pass1.prop('id' ) ) {
|
||||
$( $pass1 ).trigger( 'focus' );
|
||||
}
|
||||
}
|
||||
|
||||
function bindPass1() {
|
||||
currentPass = $pass1.val();
|
||||
|
||||
if ( 1 === parseInt( $pass1.data( 'reveal' ), 10 ) ) {
|
||||
generatePassword();
|
||||
}
|
||||
|
||||
$pass1.on( 'input' + ' pwupdate', function () {
|
||||
if ( $pass1.val() === currentPass ) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentPass = $pass1.val();
|
||||
|
||||
// Refresh password strength area.
|
||||
$pass1.removeClass( 'short bad good strong' );
|
||||
showOrHideWeakPasswordCheckbox();
|
||||
} );
|
||||
}
|
||||
|
||||
function resetToggle( show ) {
|
||||
$toggleButton
|
||||
.attr({
|
||||
'aria-label': show ? __( 'Show password' ) : __( 'Hide password' )
|
||||
})
|
||||
.find( '.text' )
|
||||
.text( show ? __( 'Show' ) : __( 'Hide' ) )
|
||||
.end()
|
||||
.find( '.dashicons' )
|
||||
.removeClass( show ? 'dashicons-hidden' : 'dashicons-visibility' )
|
||||
.addClass( show ? 'dashicons-visibility' : 'dashicons-hidden' );
|
||||
}
|
||||
|
||||
function bindToggleButton() {
|
||||
if ( !! $toggleButton ) {
|
||||
// Do not rebind.
|
||||
return;
|
||||
}
|
||||
$toggleButton = $pass1Row.find('.wp-hide-pw');
|
||||
$toggleButton.show().on( 'click', function () {
|
||||
if ( 'password' === $pass1.attr( 'type' ) ) {
|
||||
$pass1.attr( 'type', 'text' );
|
||||
resetToggle( false );
|
||||
} else {
|
||||
$pass1.attr( 'type', 'password' );
|
||||
resetToggle( true );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the password reset button. Sets up an ajax callback to trigger sending
|
||||
* a password reset email.
|
||||
*/
|
||||
function bindPasswordResetLink() {
|
||||
$( '#generate-reset-link' ).on( 'click', function() {
|
||||
var $this = $(this),
|
||||
data = {
|
||||
'user_id': userProfileL10n.user_id, // The user to send a reset to.
|
||||
'nonce': userProfileL10n.nonce // Nonce to validate the action.
|
||||
};
|
||||
|
||||
// Remove any previous error messages.
|
||||
$this.parent().find( '.notice-error' ).remove();
|
||||
|
||||
// Send the reset request.
|
||||
var resetAction = wp.ajax.post( 'send-password-reset', data );
|
||||
|
||||
// Handle reset success.
|
||||
resetAction.done( function( response ) {
|
||||
addInlineNotice( $this, true, response );
|
||||
} );
|
||||
|
||||
// Handle reset failure.
|
||||
resetAction.fail( function( response ) {
|
||||
addInlineNotice( $this, false, response );
|
||||
} );
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to insert an inline notice of success or failure.
|
||||
*
|
||||
* @param {jQuery Object} $this The button element: the message will be inserted
|
||||
* above this button
|
||||
* @param {bool} success Whether the message is a success message.
|
||||
* @param {string} message The message to insert.
|
||||
*/
|
||||
function addInlineNotice( $this, success, message ) {
|
||||
var resultDiv = $( '<div />' );
|
||||
|
||||
// Set up the notice div.
|
||||
resultDiv.addClass( 'notice inline' );
|
||||
|
||||
// Add a class indicating success or failure.
|
||||
resultDiv.addClass( 'notice-' + ( success ? 'success' : 'error' ) );
|
||||
|
||||
// Add the message, wrapping in a p tag, with a fadein to highlight each message.
|
||||
resultDiv.text( $( $.parseHTML( message ) ).text() ).wrapInner( '<p />');
|
||||
|
||||
// Disable the button when the callback has succeeded.
|
||||
$this.prop( 'disabled', success );
|
||||
|
||||
// Remove any previous notices.
|
||||
$this.siblings( '.notice' ).remove();
|
||||
|
||||
// Insert the notice.
|
||||
$this.before( resultDiv );
|
||||
}
|
||||
|
||||
function bindPasswordForm() {
|
||||
var $generateButton,
|
||||
$cancelButton;
|
||||
|
||||
$pass1Row = $( '.user-pass1-wrap, .user-pass-wrap, .mailserver-pass-wrap, .reset-pass-submit' );
|
||||
|
||||
// Hide the confirm password field when JavaScript support is enabled.
|
||||
$('.user-pass2-wrap').hide();
|
||||
|
||||
$submitButton = $( '#submit, #wp-submit' ).on( 'click', function () {
|
||||
updateLock = false;
|
||||
});
|
||||
|
||||
$submitButtons = $submitButton.add( ' #createusersub' );
|
||||
|
||||
$weakRow = $( '.pw-weak' );
|
||||
$weakCheckbox = $weakRow.find( '.pw-checkbox' );
|
||||
$weakCheckbox.on( 'change', function() {
|
||||
$submitButtons.prop( 'disabled', ! $weakCheckbox.prop( 'checked' ) );
|
||||
} );
|
||||
|
||||
$pass1 = $('#pass1, #mailserver_pass');
|
||||
if ( $pass1.length ) {
|
||||
bindPass1();
|
||||
} else {
|
||||
// Password field for the login form.
|
||||
$pass1 = $( '#user_pass' );
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix a LastPass mismatch issue, LastPass only changes pass2.
|
||||
*
|
||||
* This fixes the issue by copying any changes from the hidden
|
||||
* pass2 field to the pass1 field, then running check_pass_strength.
|
||||
*/
|
||||
$pass2 = $( '#pass2' ).on( 'input', function () {
|
||||
if ( $pass2.val().length > 0 ) {
|
||||
$pass1.val( $pass2.val() );
|
||||
$pass2.val('');
|
||||
currentPass = '';
|
||||
$pass1.trigger( 'pwupdate' );
|
||||
}
|
||||
} );
|
||||
|
||||
// Disable hidden inputs to prevent autofill and submission.
|
||||
if ( $pass1.is( ':hidden' ) ) {
|
||||
$pass1.prop( 'disabled', true );
|
||||
$pass2.prop( 'disabled', true );
|
||||
}
|
||||
|
||||
$passwordWrapper = $pass1Row.find( '.wp-pwd' );
|
||||
$generateButton = $pass1Row.find( 'button.wp-generate-pw' );
|
||||
|
||||
bindToggleButton();
|
||||
|
||||
$generateButton.show();
|
||||
$generateButton.on( 'click', function () {
|
||||
updateLock = true;
|
||||
|
||||
// Make sure the password fields are shown.
|
||||
$generateButton.not( '.skip-aria-expanded' ).attr( 'aria-expanded', 'true' );
|
||||
$passwordWrapper
|
||||
.show()
|
||||
.addClass( 'is-open' );
|
||||
|
||||
// Enable the inputs when showing.
|
||||
$pass1.attr( 'disabled', false );
|
||||
$pass2.attr( 'disabled', false );
|
||||
|
||||
// Set the password to the generated value.
|
||||
generatePassword();
|
||||
|
||||
// Show generated password in plaintext by default.
|
||||
resetToggle ( false );
|
||||
|
||||
// Generate the next password and cache.
|
||||
wp.ajax.post( 'generate-password' )
|
||||
.done( function( data ) {
|
||||
$pass1.data( 'pw', data );
|
||||
} );
|
||||
} );
|
||||
|
||||
$cancelButton = $pass1Row.find( 'button.wp-cancel-pw' );
|
||||
$cancelButton.on( 'click', function () {
|
||||
updateLock = false;
|
||||
|
||||
// Disable the inputs when hiding to prevent autofill and submission.
|
||||
$pass1.prop( 'disabled', true );
|
||||
$pass2.prop( 'disabled', true );
|
||||
|
||||
// Clear password field and update the UI.
|
||||
$pass1.val( '' ).trigger( 'pwupdate' );
|
||||
resetToggle( false );
|
||||
|
||||
// Hide password controls.
|
||||
$passwordWrapper
|
||||
.hide()
|
||||
.removeClass( 'is-open' );
|
||||
|
||||
// Stop an empty password from being submitted as a change.
|
||||
$submitButtons.prop( 'disabled', false );
|
||||
|
||||
$generateButton.attr( 'aria-expanded', 'false' );
|
||||
} );
|
||||
|
||||
$pass1Row.closest( 'form' ).on( 'submit', function () {
|
||||
updateLock = false;
|
||||
|
||||
$pass1.prop( 'disabled', false );
|
||||
$pass2.prop( 'disabled', false );
|
||||
$pass2.val( $pass1.val() );
|
||||
});
|
||||
}
|
||||
|
||||
function check_pass_strength() {
|
||||
var pass1 = $('#pass1').val(), strength;
|
||||
|
||||
$('#pass-strength-result').removeClass('short bad good strong empty');
|
||||
if ( ! pass1 || '' === pass1.trim() ) {
|
||||
$( '#pass-strength-result' ).addClass( 'empty' ).html( ' ' );
|
||||
return;
|
||||
}
|
||||
|
||||
strength = wp.passwordStrength.meter( pass1, wp.passwordStrength.userInputDisallowedList(), pass1 );
|
||||
|
||||
switch ( strength ) {
|
||||
case -1:
|
||||
$( '#pass-strength-result' ).addClass( 'bad' ).html( pwsL10n.unknown );
|
||||
break;
|
||||
case 2:
|
||||
$('#pass-strength-result').addClass('bad').html( pwsL10n.bad );
|
||||
break;
|
||||
case 3:
|
||||
$('#pass-strength-result').addClass('good').html( pwsL10n.good );
|
||||
break;
|
||||
case 4:
|
||||
$('#pass-strength-result').addClass('strong').html( pwsL10n.strong );
|
||||
break;
|
||||
case 5:
|
||||
$('#pass-strength-result').addClass('short').html( pwsL10n.mismatch );
|
||||
break;
|
||||
default:
|
||||
$('#pass-strength-result').addClass('short').html( pwsL10n.short );
|
||||
}
|
||||
}
|
||||
|
||||
function showOrHideWeakPasswordCheckbox() {
|
||||
var passStrengthResult = $('#pass-strength-result');
|
||||
|
||||
if ( passStrengthResult.length ) {
|
||||
var passStrength = passStrengthResult[0];
|
||||
|
||||
if ( passStrength.className ) {
|
||||
$pass1.addClass( passStrength.className );
|
||||
if ( $( passStrength ).is( '.short, .bad' ) ) {
|
||||
if ( ! $weakCheckbox.prop( 'checked' ) ) {
|
||||
$submitButtons.prop( 'disabled', true );
|
||||
}
|
||||
$weakRow.show();
|
||||
} else {
|
||||
if ( $( passStrength ).is( '.empty' ) ) {
|
||||
$submitButtons.prop( 'disabled', true );
|
||||
$weakCheckbox.prop( 'checked', false );
|
||||
} else {
|
||||
$submitButtons.prop( 'disabled', false );
|
||||
}
|
||||
$weakRow.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$( function() {
|
||||
var $colorpicker, $stylesheet, user_id, current_user_id,
|
||||
select = $( '#display_name' ),
|
||||
current_name = select.val(),
|
||||
greeting = $( '#wp-admin-bar-my-account' ).find( '.display-name' );
|
||||
|
||||
$( '#pass1' ).val( '' ).on( 'input' + ' pwupdate', check_pass_strength );
|
||||
$('#pass-strength-result').show();
|
||||
$('.color-palette').on( 'click', function() {
|
||||
$(this).siblings('input[name="admin_color"]').prop('checked', true);
|
||||
});
|
||||
|
||||
if ( select.length ) {
|
||||
$('#first_name, #last_name, #nickname').on( 'blur.user_profile', function() {
|
||||
var dub = [],
|
||||
inputs = {
|
||||
display_nickname : $('#nickname').val() || '',
|
||||
display_username : $('#user_login').val() || '',
|
||||
display_firstname : $('#first_name').val() || '',
|
||||
display_lastname : $('#last_name').val() || ''
|
||||
};
|
||||
|
||||
if ( inputs.display_firstname && inputs.display_lastname ) {
|
||||
inputs.display_firstlast = inputs.display_firstname + ' ' + inputs.display_lastname;
|
||||
inputs.display_lastfirst = inputs.display_lastname + ' ' + inputs.display_firstname;
|
||||
}
|
||||
|
||||
$.each( $('option', select), function( i, el ){
|
||||
dub.push( el.value );
|
||||
});
|
||||
|
||||
$.each(inputs, function( id, value ) {
|
||||
if ( ! value ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var val = value.replace(/<\/?[a-z][^>]*>/gi, '');
|
||||
|
||||
if ( inputs[id].length && $.inArray( val, dub ) === -1 ) {
|
||||
dub.push(val);
|
||||
$('<option />', {
|
||||
'text': val
|
||||
}).appendTo( select );
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Replaces "Howdy, *" in the admin toolbar whenever the display name dropdown is updated for one's own profile.
|
||||
*/
|
||||
select.on( 'change', function() {
|
||||
if ( user_id !== current_user_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var display_name = this.value.trim() || current_name;
|
||||
|
||||
greeting.text( display_name );
|
||||
} );
|
||||
}
|
||||
|
||||
$colorpicker = $( '#color-picker' );
|
||||
$stylesheet = $( '#colors-css' );
|
||||
user_id = $( 'input#user_id' ).val();
|
||||
current_user_id = $( 'input[name="checkuser_id"]' ).val();
|
||||
|
||||
$colorpicker.on( 'click.colorpicker', '.color-option', function() {
|
||||
var colors,
|
||||
$this = $(this);
|
||||
|
||||
if ( $this.hasClass( 'selected' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this.siblings( '.selected' ).removeClass( 'selected' );
|
||||
$this.addClass( 'selected' ).find( 'input[type="radio"]' ).prop( 'checked', true );
|
||||
|
||||
// Set color scheme.
|
||||
if ( user_id === current_user_id ) {
|
||||
// Load the colors stylesheet.
|
||||
// The default color scheme won't have one, so we'll need to create an element.
|
||||
if ( 0 === $stylesheet.length ) {
|
||||
$stylesheet = $( '<link rel="stylesheet" />' ).appendTo( 'head' );
|
||||
}
|
||||
$stylesheet.attr( 'href', $this.children( '.css_url' ).val() );
|
||||
|
||||
// Repaint icons.
|
||||
if ( typeof wp !== 'undefined' && wp.svgPainter ) {
|
||||
try {
|
||||
colors = JSON.parse( $this.children( '.icon_colors' ).val() );
|
||||
} catch ( error ) {}
|
||||
|
||||
if ( colors ) {
|
||||
wp.svgPainter.setColors( colors );
|
||||
wp.svgPainter.paint();
|
||||
}
|
||||
}
|
||||
|
||||
// Update user option.
|
||||
$.post( ajaxurl, {
|
||||
action: 'save-user-color-scheme',
|
||||
color_scheme: $this.children( 'input[name="admin_color"]' ).val(),
|
||||
nonce: $('#color-nonce').val()
|
||||
}).done( function( response ) {
|
||||
if ( response.success ) {
|
||||
$( 'body' ).removeClass( response.data.previousScheme ).addClass( response.data.currentScheme );
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
bindPasswordForm();
|
||||
bindPasswordResetLink();
|
||||
});
|
||||
|
||||
$( '#destroy-sessions' ).on( 'click', function( e ) {
|
||||
var $this = $(this);
|
||||
|
||||
wp.ajax.post( 'destroy-sessions', {
|
||||
nonce: $( '#_wpnonce' ).val(),
|
||||
user_id: $( '#user_id' ).val()
|
||||
}).done( function( response ) {
|
||||
$this.prop( 'disabled', true );
|
||||
$this.siblings( '.notice' ).remove();
|
||||
$this.before( '<div class="notice notice-success inline"><p>' + response.message + '</p></div>' );
|
||||
}).fail( function( response ) {
|
||||
$this.siblings( '.notice' ).remove();
|
||||
$this.before( '<div class="notice notice-error inline"><p>' + response.message + '</p></div>' );
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
window.generatePassword = generatePassword;
|
||||
|
||||
// Warn the user if password was generated but not saved.
|
||||
$( window ).on( 'beforeunload', function () {
|
||||
if ( true === updateLock ) {
|
||||
return __( 'Your new password has not been saved.' );
|
||||
}
|
||||
} );
|
||||
|
||||
/*
|
||||
* We need to generate a password as soon as the Reset Password page is loaded,
|
||||
* to avoid double clicking the button to retrieve the first generated password.
|
||||
* See ticket #39638.
|
||||
*/
|
||||
$( function() {
|
||||
if ( $( '.reset-pass-submit' ).length ) {
|
||||
$( '.reset-pass-submit button.wp-generate-pw' ).trigger( 'click' );
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
2
wp-admin/js/user-profile.min.js
vendored
Normal file
2
wp-admin/js/user-profile.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
64
wp-admin/js/user-suggest.js
Normal file
64
wp-admin/js/user-suggest.js
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Suggests users in a multisite environment.
|
||||
*
|
||||
* For input fields where the admin can select a user based on email or
|
||||
* username, this script shows an autocompletion menu for these inputs. Should
|
||||
* only be used in a multisite environment. Only users in the currently active
|
||||
* site are shown.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @output wp-admin/js/user-suggest.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, current_site_id, isRtl */
|
||||
|
||||
(function( $ ) {
|
||||
var id = ( typeof current_site_id !== 'undefined' ) ? '&site_id=' + current_site_id : '';
|
||||
$( function() {
|
||||
var position = { offset: '0, -1' };
|
||||
if ( typeof isRtl !== 'undefined' && isRtl ) {
|
||||
position.my = 'right top';
|
||||
position.at = 'right bottom';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an autocomplete function to input fields marked with the class
|
||||
* 'wp-suggest-user'.
|
||||
*
|
||||
* A minimum of two characters is required to trigger the suggestions. The
|
||||
* autocompletion menu is shown at the left bottom of the input field. On
|
||||
* RTL installations, it is shown at the right top. Adds the class 'open' to
|
||||
* the input field when the autocompletion menu is shown.
|
||||
*
|
||||
* Does a backend call to retrieve the users.
|
||||
*
|
||||
* Optional data-attributes:
|
||||
* - data-autocomplete-type (add, search)
|
||||
* The action that is going to be performed: search for existing users
|
||||
* or add a new one. Default: add
|
||||
* - data-autocomplete-field (user_login, user_email)
|
||||
* The field that is returned as the value for the suggestion.
|
||||
* Default: user_login
|
||||
*
|
||||
* @see wp-admin/includes/admin-actions.php:wp_ajax_autocomplete_user()
|
||||
*/
|
||||
$( '.wp-suggest-user' ).each( function(){
|
||||
var $this = $( this ),
|
||||
autocompleteType = ( typeof $this.data( 'autocompleteType' ) !== 'undefined' ) ? $this.data( 'autocompleteType' ) : 'add',
|
||||
autocompleteField = ( typeof $this.data( 'autocompleteField' ) !== 'undefined' ) ? $this.data( 'autocompleteField' ) : 'user_login';
|
||||
|
||||
$this.autocomplete({
|
||||
source: ajaxurl + '?action=autocomplete-user&autocomplete_type=' + autocompleteType + '&autocomplete_field=' + autocompleteField + id,
|
||||
delay: 500,
|
||||
minLength: 2,
|
||||
position: position,
|
||||
open: function() {
|
||||
$( this ).addClass( 'open' );
|
||||
},
|
||||
close: function() {
|
||||
$( this ).removeClass( 'open' );
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
})( jQuery );
|
2
wp-admin/js/user-suggest.min.js
vendored
Normal file
2
wp-admin/js/user-suggest.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(a){var n="undefined"!=typeof current_site_id?"&site_id="+current_site_id:"";a(function(){var i={offset:"0, -1"};"undefined"!=typeof isRtl&&isRtl&&(i.my="right top",i.at="right bottom"),a(".wp-suggest-user").each(function(){var e=a(this),t=void 0!==e.data("autocompleteType")?e.data("autocompleteType"):"add",o=void 0!==e.data("autocompleteField")?e.data("autocompleteField"):"user_login";e.autocomplete({source:ajaxurl+"?action=autocomplete-user&autocomplete_type="+t+"&autocomplete_field="+o+n,delay:500,minLength:2,position:i,open:function(){a(this).addClass("open")},close:function(){a(this).removeClass("open")}})})})}(jQuery);
|
763
wp-admin/js/widgets.js
Normal file
763
wp-admin/js/widgets.js
Normal file
@ -0,0 +1,763 @@
|
||||
/**
|
||||
* @output wp-admin/js/widgets.js
|
||||
*/
|
||||
|
||||
/* global ajaxurl, isRtl, wpWidgets */
|
||||
|
||||
(function($) {
|
||||
var $document = $( document );
|
||||
|
||||
window.wpWidgets = {
|
||||
/**
|
||||
* A closed Sidebar that gets a Widget dragged over it.
|
||||
*
|
||||
* @var {element|null}
|
||||
*/
|
||||
hoveredSidebar: null,
|
||||
|
||||
/**
|
||||
* Lookup of which widgets have had change events triggered.
|
||||
*
|
||||
* @var {object}
|
||||
*/
|
||||
dirtyWidgets: {},
|
||||
|
||||
init : function() {
|
||||
var rem, the_id,
|
||||
self = this,
|
||||
chooser = $('.widgets-chooser'),
|
||||
selectSidebar = chooser.find('.widgets-chooser-sidebars'),
|
||||
sidebars = $('div.widgets-sortables'),
|
||||
isRTL = !! ( 'undefined' !== typeof isRtl && isRtl );
|
||||
|
||||
// Handle the widgets containers in the right column.
|
||||
$( '#widgets-right .sidebar-name' )
|
||||
/*
|
||||
* Toggle the widgets containers when clicked and update the toggle
|
||||
* button `aria-expanded` attribute value.
|
||||
*/
|
||||
.on( 'click', function() {
|
||||
var $this = $( this ),
|
||||
$wrap = $this.closest( '.widgets-holder-wrap '),
|
||||
$toggle = $this.find( '.handlediv' );
|
||||
|
||||
if ( $wrap.hasClass( 'closed' ) ) {
|
||||
$wrap.removeClass( 'closed' );
|
||||
$toggle.attr( 'aria-expanded', 'true' );
|
||||
// Refresh the jQuery UI sortable items.
|
||||
$this.parent().sortable( 'refresh' );
|
||||
} else {
|
||||
$wrap.addClass( 'closed' );
|
||||
$toggle.attr( 'aria-expanded', 'false' );
|
||||
}
|
||||
|
||||
// Update the admin menu "sticky" state.
|
||||
$document.triggerHandler( 'wp-pin-menu' );
|
||||
})
|
||||
/*
|
||||
* Set the initial `aria-expanded` attribute value on the widgets
|
||||
* containers toggle button. The first one is expanded by default.
|
||||
*/
|
||||
.find( '.handlediv' ).each( function( index ) {
|
||||
if ( 0 === index ) {
|
||||
// jQuery equivalent of `continue` within an `each()` loop.
|
||||
return;
|
||||
}
|
||||
|
||||
$( this ).attr( 'aria-expanded', 'false' );
|
||||
});
|
||||
|
||||
// Show AYS dialog when there are unsaved widget changes.
|
||||
$( window ).on( 'beforeunload.widgets', function( event ) {
|
||||
var dirtyWidgetIds = [], unsavedWidgetsElements;
|
||||
$.each( self.dirtyWidgets, function( widgetId, dirty ) {
|
||||
if ( dirty ) {
|
||||
dirtyWidgetIds.push( widgetId );
|
||||
}
|
||||
});
|
||||
if ( 0 !== dirtyWidgetIds.length ) {
|
||||
unsavedWidgetsElements = $( '#widgets-right' ).find( '.widget' ).filter( function() {
|
||||
return -1 !== dirtyWidgetIds.indexOf( $( this ).prop( 'id' ).replace( /^widget-\d+_/, '' ) );
|
||||
});
|
||||
unsavedWidgetsElements.each( function() {
|
||||
if ( ! $( this ).hasClass( 'open' ) ) {
|
||||
$( this ).find( '.widget-title-action:first' ).trigger( 'click' );
|
||||
}
|
||||
});
|
||||
|
||||
// Bring the first unsaved widget into view and focus on the first tabbable field.
|
||||
unsavedWidgetsElements.first().each( function() {
|
||||
if ( this.scrollIntoViewIfNeeded ) {
|
||||
this.scrollIntoViewIfNeeded();
|
||||
} else {
|
||||
this.scrollIntoView();
|
||||
}
|
||||
$( this ).find( '.widget-inside :tabbable:first' ).trigger( 'focus' );
|
||||
} );
|
||||
|
||||
event.returnValue = wp.i18n.__( 'The changes you made will be lost if you navigate away from this page.' );
|
||||
return event.returnValue;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle the widgets containers in the left column.
|
||||
$( '#widgets-left .sidebar-name' ).on( 'click', function() {
|
||||
var $wrap = $( this ).closest( '.widgets-holder-wrap' );
|
||||
|
||||
$wrap
|
||||
.toggleClass( 'closed' )
|
||||
.find( '.handlediv' ).attr( 'aria-expanded', ! $wrap.hasClass( 'closed' ) );
|
||||
|
||||
// Update the admin menu "sticky" state.
|
||||
$document.triggerHandler( 'wp-pin-menu' );
|
||||
});
|
||||
|
||||
$(document.body).on('click.widgets-toggle', function(e) {
|
||||
var target = $(e.target), css = {},
|
||||
widget, inside, targetWidth, widgetWidth, margin, saveButton, widgetId,
|
||||
toggleBtn = target.closest( '.widget' ).find( '.widget-top button.widget-action' );
|
||||
|
||||
if ( target.parents('.widget-top').length && ! target.parents('#available-widgets').length ) {
|
||||
widget = target.closest('div.widget');
|
||||
inside = widget.children('.widget-inside');
|
||||
targetWidth = parseInt( widget.find('input.widget-width').val(), 10 );
|
||||
widgetWidth = widget.parent().width();
|
||||
widgetId = inside.find( '.widget-id' ).val();
|
||||
|
||||
// Save button is initially disabled, but is enabled when a field is changed.
|
||||
if ( ! widget.data( 'dirty-state-initialized' ) ) {
|
||||
saveButton = inside.find( '.widget-control-save' );
|
||||
saveButton.prop( 'disabled', true ).val( wp.i18n.__( 'Saved' ) );
|
||||
inside.on( 'input change', function() {
|
||||
self.dirtyWidgets[ widgetId ] = true;
|
||||
widget.addClass( 'widget-dirty' );
|
||||
saveButton.prop( 'disabled', false ).val( wp.i18n.__( 'Save' ) );
|
||||
});
|
||||
widget.data( 'dirty-state-initialized', true );
|
||||
}
|
||||
|
||||
if ( inside.is(':hidden') ) {
|
||||
if ( targetWidth > 250 && ( targetWidth + 30 > widgetWidth ) && widget.closest('div.widgets-sortables').length ) {
|
||||
if ( widget.closest('div.widget-liquid-right').length ) {
|
||||
margin = isRTL ? 'margin-right' : 'margin-left';
|
||||
} else {
|
||||
margin = isRTL ? 'margin-left' : 'margin-right';
|
||||
}
|
||||
|
||||
css[ margin ] = widgetWidth - ( targetWidth + 30 ) + 'px';
|
||||
widget.css( css );
|
||||
}
|
||||
/*
|
||||
* Don't change the order of attributes changes and animation:
|
||||
* it's important for screen readers, see ticket #31476.
|
||||
*/
|
||||
toggleBtn.attr( 'aria-expanded', 'true' );
|
||||
inside.slideDown( 'fast', function() {
|
||||
widget.addClass( 'open' );
|
||||
});
|
||||
} else {
|
||||
/*
|
||||
* Don't change the order of attributes changes and animation:
|
||||
* it's important for screen readers, see ticket #31476.
|
||||
*/
|
||||
toggleBtn.attr( 'aria-expanded', 'false' );
|
||||
inside.slideUp( 'fast', function() {
|
||||
widget.attr( 'style', '' );
|
||||
widget.removeClass( 'open' );
|
||||
});
|
||||
}
|
||||
} else if ( target.hasClass('widget-control-save') ) {
|
||||
wpWidgets.save( target.closest('div.widget'), 0, 1, 0 );
|
||||
e.preventDefault();
|
||||
} else if ( target.hasClass('widget-control-remove') ) {
|
||||
wpWidgets.save( target.closest('div.widget'), 1, 1, 0 );
|
||||
} else if ( target.hasClass('widget-control-close') ) {
|
||||
widget = target.closest('div.widget');
|
||||
widget.removeClass( 'open' );
|
||||
toggleBtn.attr( 'aria-expanded', 'false' );
|
||||
wpWidgets.close( widget );
|
||||
} else if ( target.attr( 'id' ) === 'inactive-widgets-control-remove' ) {
|
||||
wpWidgets.removeInactiveWidgets();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
sidebars.children('.widget').each( function() {
|
||||
var $this = $(this);
|
||||
|
||||
wpWidgets.appendTitle( this );
|
||||
|
||||
if ( $this.find( 'p.widget-error' ).length ) {
|
||||
$this.find( '.widget-action' ).trigger( 'click' ).attr( 'aria-expanded', 'true' );
|
||||
}
|
||||
});
|
||||
|
||||
$('#widget-list').children('.widget').draggable({
|
||||
connectToSortable: 'div.widgets-sortables',
|
||||
handle: '> .widget-top > .widget-title',
|
||||
distance: 2,
|
||||
helper: 'clone',
|
||||
zIndex: 101,
|
||||
containment: '#wpwrap',
|
||||
refreshPositions: true,
|
||||
start: function( event, ui ) {
|
||||
var chooser = $(this).find('.widgets-chooser');
|
||||
|
||||
ui.helper.find('div.widget-description').hide();
|
||||
the_id = this.id;
|
||||
|
||||
if ( chooser.length ) {
|
||||
// Hide the chooser and move it out of the widget.
|
||||
$( '#wpbody-content' ).append( chooser.hide() );
|
||||
// Delete the cloned chooser from the drag helper.
|
||||
ui.helper.find('.widgets-chooser').remove();
|
||||
self.clearWidgetSelection();
|
||||
}
|
||||
},
|
||||
stop: function() {
|
||||
if ( rem ) {
|
||||
$(rem).hide();
|
||||
}
|
||||
|
||||
rem = '';
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Opens and closes previously closed Sidebars when Widgets are dragged over/out of them.
|
||||
*/
|
||||
sidebars.droppable( {
|
||||
tolerance: 'intersect',
|
||||
|
||||
/**
|
||||
* Open Sidebar when a Widget gets dragged over it.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @param {Object} event jQuery event object.
|
||||
*/
|
||||
over: function( event ) {
|
||||
var $wrap = $( event.target ).parent();
|
||||
|
||||
if ( wpWidgets.hoveredSidebar && ! $wrap.is( wpWidgets.hoveredSidebar ) ) {
|
||||
// Close the previous Sidebar as the Widget has been dragged onto another Sidebar.
|
||||
wpWidgets.closeSidebar( event );
|
||||
}
|
||||
|
||||
if ( $wrap.hasClass( 'closed' ) ) {
|
||||
wpWidgets.hoveredSidebar = $wrap;
|
||||
$wrap
|
||||
.removeClass( 'closed' )
|
||||
.find( '.handlediv' ).attr( 'aria-expanded', 'true' );
|
||||
}
|
||||
|
||||
$( this ).sortable( 'refresh' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Close Sidebar when the Widget gets dragged out of it.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @param {Object} event jQuery event object.
|
||||
*/
|
||||
out: function( event ) {
|
||||
if ( wpWidgets.hoveredSidebar ) {
|
||||
wpWidgets.closeSidebar( event );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
sidebars.sortable({
|
||||
placeholder: 'widget-placeholder',
|
||||
items: '> .widget',
|
||||
handle: '> .widget-top > .widget-title',
|
||||
cursor: 'move',
|
||||
distance: 2,
|
||||
containment: '#wpwrap',
|
||||
tolerance: 'pointer',
|
||||
refreshPositions: true,
|
||||
start: function( event, ui ) {
|
||||
var height, $this = $(this),
|
||||
$wrap = $this.parent(),
|
||||
inside = ui.item.children('.widget-inside');
|
||||
|
||||
if ( inside.css('display') === 'block' ) {
|
||||
ui.item.removeClass('open');
|
||||
ui.item.find( '.widget-top button.widget-action' ).attr( 'aria-expanded', 'false' );
|
||||
inside.hide();
|
||||
$(this).sortable('refreshPositions');
|
||||
}
|
||||
|
||||
if ( ! $wrap.hasClass('closed') ) {
|
||||
// Lock all open sidebars min-height when starting to drag.
|
||||
// Prevents jumping when dragging a widget from an open sidebar to a closed sidebar below.
|
||||
height = ui.item.hasClass('ui-draggable') ? $this.height() : 1 + $this.height();
|
||||
$this.css( 'min-height', height + 'px' );
|
||||
}
|
||||
},
|
||||
|
||||
stop: function( event, ui ) {
|
||||
var addNew, widgetNumber, $sidebar, $children, child, item,
|
||||
$widget = ui.item,
|
||||
id = the_id;
|
||||
|
||||
// Reset the var to hold a previously closed sidebar.
|
||||
wpWidgets.hoveredSidebar = null;
|
||||
|
||||
if ( $widget.hasClass('deleting') ) {
|
||||
wpWidgets.save( $widget, 1, 0, 1 ); // Delete widget.
|
||||
$widget.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
addNew = $widget.find('input.add_new').val();
|
||||
widgetNumber = $widget.find('input.multi_number').val();
|
||||
|
||||
$widget.attr( 'style', '' ).removeClass('ui-draggable');
|
||||
the_id = '';
|
||||
|
||||
if ( addNew ) {
|
||||
if ( 'multi' === addNew ) {
|
||||
$widget.html(
|
||||
$widget.html().replace( /<[^<>]+>/g, function( tag ) {
|
||||
return tag.replace( /__i__|%i%/g, widgetNumber );
|
||||
})
|
||||
);
|
||||
|
||||
$widget.attr( 'id', id.replace( '__i__', widgetNumber ) );
|
||||
widgetNumber++;
|
||||
|
||||
$( 'div#' + id ).find( 'input.multi_number' ).val( widgetNumber );
|
||||
} else if ( 'single' === addNew ) {
|
||||
$widget.attr( 'id', 'new-' + id );
|
||||
rem = 'div#' + id;
|
||||
}
|
||||
|
||||
wpWidgets.save( $widget, 0, 0, 1 );
|
||||
$widget.find('input.add_new').val('');
|
||||
$document.trigger( 'widget-added', [ $widget ] );
|
||||
}
|
||||
|
||||
$sidebar = $widget.parent();
|
||||
|
||||
if ( $sidebar.parent().hasClass('closed') ) {
|
||||
$sidebar.parent()
|
||||
.removeClass( 'closed' )
|
||||
.find( '.handlediv' ).attr( 'aria-expanded', 'true' );
|
||||
|
||||
$children = $sidebar.children('.widget');
|
||||
|
||||
// Make sure the dropped widget is at the top.
|
||||
if ( $children.length > 1 ) {
|
||||
child = $children.get(0);
|
||||
item = $widget.get(0);
|
||||
|
||||
if ( child.id && item.id && child.id !== item.id ) {
|
||||
$( child ).before( $widget );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( addNew ) {
|
||||
$widget.find( '.widget-action' ).trigger( 'click' );
|
||||
} else {
|
||||
wpWidgets.saveOrder( $sidebar.attr('id') );
|
||||
}
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
$(this).parent().addClass( 'widget-hover' );
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
// Remove all min-height added on "start".
|
||||
$(this).css( 'min-height', '' ).parent().removeClass( 'widget-hover' );
|
||||
},
|
||||
|
||||
receive: function( event, ui ) {
|
||||
var $sender = $( ui.sender );
|
||||
|
||||
// Don't add more widgets to orphaned sidebars.
|
||||
if ( this.id.indexOf('orphaned_widgets') > -1 ) {
|
||||
$sender.sortable('cancel');
|
||||
return;
|
||||
}
|
||||
|
||||
// If the last widget was moved out of an orphaned sidebar, close and remove it.
|
||||
if ( $sender.attr('id').indexOf('orphaned_widgets') > -1 && ! $sender.children('.widget').length ) {
|
||||
$sender.parents('.orphan-sidebar').slideUp( 400, function(){ $(this).remove(); } );
|
||||
}
|
||||
}
|
||||
}).sortable( 'option', 'connectWith', 'div.widgets-sortables' );
|
||||
|
||||
$('#available-widgets').droppable({
|
||||
tolerance: 'pointer',
|
||||
accept: function(o){
|
||||
return $(o).parent().attr('id') !== 'widget-list';
|
||||
},
|
||||
drop: function(e,ui) {
|
||||
ui.draggable.addClass('deleting');
|
||||
$('#removing-widget').hide().children('span').empty();
|
||||
},
|
||||
over: function(e,ui) {
|
||||
ui.draggable.addClass('deleting');
|
||||
$('div.widget-placeholder').hide();
|
||||
|
||||
if ( ui.draggable.hasClass('ui-sortable-helper') ) {
|
||||
$('#removing-widget').show().children('span')
|
||||
.html( ui.draggable.find( 'div.widget-title' ).children( 'h3' ).html() );
|
||||
}
|
||||
},
|
||||
out: function(e,ui) {
|
||||
ui.draggable.removeClass('deleting');
|
||||
$('div.widget-placeholder').show();
|
||||
$('#removing-widget').hide().children('span').empty();
|
||||
}
|
||||
});
|
||||
|
||||
// Area Chooser.
|
||||
$( '#widgets-right .widgets-holder-wrap' ).each( function( index, element ) {
|
||||
var $element = $( element ),
|
||||
name = $element.find( '.sidebar-name h2' ).text() || '',
|
||||
ariaLabel = $element.find( '.sidebar-name' ).data( 'add-to' ),
|
||||
id = $element.find( '.widgets-sortables' ).attr( 'id' ),
|
||||
li = $( '<li>' ),
|
||||
button = $( '<button>', {
|
||||
type: 'button',
|
||||
'aria-pressed': 'false',
|
||||
'class': 'widgets-chooser-button',
|
||||
'aria-label': ariaLabel
|
||||
} ).text( name.toString().trim() );
|
||||
|
||||
li.append( button );
|
||||
|
||||
if ( index === 0 ) {
|
||||
li.addClass( 'widgets-chooser-selected' );
|
||||
button.attr( 'aria-pressed', 'true' );
|
||||
}
|
||||
|
||||
selectSidebar.append( li );
|
||||
li.data( 'sidebarId', id );
|
||||
});
|
||||
|
||||
$( '#available-widgets .widget .widget-top' ).on( 'click.widgets-chooser', function() {
|
||||
var $widget = $( this ).closest( '.widget' ),
|
||||
toggleButton = $( this ).find( '.widget-action' ),
|
||||
chooserButtons = selectSidebar.find( '.widgets-chooser-button' );
|
||||
|
||||
if ( $widget.hasClass( 'widget-in-question' ) || $( '#widgets-left' ).hasClass( 'chooser' ) ) {
|
||||
toggleButton.attr( 'aria-expanded', 'false' );
|
||||
self.closeChooser();
|
||||
} else {
|
||||
// Open the chooser.
|
||||
self.clearWidgetSelection();
|
||||
$( '#widgets-left' ).addClass( 'chooser' );
|
||||
// Add CSS class and insert the chooser after the widget description.
|
||||
$widget.addClass( 'widget-in-question' ).children( '.widget-description' ).after( chooser );
|
||||
// Open the chooser with a slide down animation.
|
||||
chooser.slideDown( 300, function() {
|
||||
// Update the toggle button aria-expanded attribute after previous DOM manipulations.
|
||||
toggleButton.attr( 'aria-expanded', 'true' );
|
||||
});
|
||||
|
||||
chooserButtons.on( 'click.widgets-chooser', function() {
|
||||
selectSidebar.find( '.widgets-chooser-selected' ).removeClass( 'widgets-chooser-selected' );
|
||||
chooserButtons.attr( 'aria-pressed', 'false' );
|
||||
$( this )
|
||||
.attr( 'aria-pressed', 'true' )
|
||||
.closest( 'li' ).addClass( 'widgets-chooser-selected' );
|
||||
} );
|
||||
}
|
||||
});
|
||||
|
||||
// Add event handlers.
|
||||
chooser.on( 'click.widgets-chooser', function( event ) {
|
||||
var $target = $( event.target );
|
||||
|
||||
if ( $target.hasClass('button-primary') ) {
|
||||
self.addWidget( chooser );
|
||||
self.closeChooser();
|
||||
} else if ( $target.hasClass( 'widgets-chooser-cancel' ) ) {
|
||||
self.closeChooser();
|
||||
}
|
||||
}).on( 'keyup.widgets-chooser', function( event ) {
|
||||
if ( event.which === $.ui.keyCode.ESCAPE ) {
|
||||
self.closeChooser();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
saveOrder : function( sidebarId ) {
|
||||
var data = {
|
||||
action: 'widgets-order',
|
||||
savewidgets: $('#_wpnonce_widgets').val(),
|
||||
sidebars: []
|
||||
};
|
||||
|
||||
if ( sidebarId ) {
|
||||
$( '#' + sidebarId ).find( '.spinner:first' ).addClass( 'is-active' );
|
||||
}
|
||||
|
||||
$('div.widgets-sortables').each( function() {
|
||||
if ( $(this).sortable ) {
|
||||
data['sidebars[' + $(this).attr('id') + ']'] = $(this).sortable('toArray').join(',');
|
||||
}
|
||||
});
|
||||
|
||||
$.post( ajaxurl, data, function() {
|
||||
$( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
|
||||
$( '.spinner' ).removeClass( 'is-active' );
|
||||
});
|
||||
},
|
||||
|
||||
save : function( widget, del, animate, order ) {
|
||||
var self = this, data, a,
|
||||
sidebarId = widget.closest( 'div.widgets-sortables' ).attr( 'id' ),
|
||||
form = widget.find( 'form' ),
|
||||
isAdd = widget.find( 'input.add_new' ).val();
|
||||
|
||||
if ( ! del && ! isAdd && form.prop( 'checkValidity' ) && ! form[0].checkValidity() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
data = form.serialize();
|
||||
|
||||
widget = $(widget);
|
||||
$( '.spinner', widget ).addClass( 'is-active' );
|
||||
|
||||
a = {
|
||||
action: 'save-widget',
|
||||
savewidgets: $('#_wpnonce_widgets').val(),
|
||||
sidebar: sidebarId
|
||||
};
|
||||
|
||||
if ( del ) {
|
||||
a.delete_widget = 1;
|
||||
}
|
||||
|
||||
data += '&' + $.param(a);
|
||||
|
||||
$.post( ajaxurl, data, function(r) {
|
||||
var id = $('input.widget-id', widget).val();
|
||||
|
||||
if ( del ) {
|
||||
if ( ! $('input.widget_number', widget).val() ) {
|
||||
$('#available-widgets').find('input.widget-id').each(function(){
|
||||
if ( $(this).val() === id ) {
|
||||
$(this).closest('div.widget').show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ( animate ) {
|
||||
order = 0;
|
||||
widget.slideUp( 'fast', function() {
|
||||
$( this ).remove();
|
||||
wpWidgets.saveOrder();
|
||||
delete self.dirtyWidgets[ id ];
|
||||
});
|
||||
} else {
|
||||
widget.remove();
|
||||
delete self.dirtyWidgets[ id ];
|
||||
|
||||
if ( sidebarId === 'wp_inactive_widgets' ) {
|
||||
$( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$( '.spinner' ).removeClass( 'is-active' );
|
||||
if ( r && r.length > 2 ) {
|
||||
$( 'div.widget-content', widget ).html( r );
|
||||
wpWidgets.appendTitle( widget );
|
||||
|
||||
// Re-disable the save button.
|
||||
widget.find( '.widget-control-save' ).prop( 'disabled', true ).val( wp.i18n.__( 'Saved' ) );
|
||||
|
||||
widget.removeClass( 'widget-dirty' );
|
||||
|
||||
// Clear the dirty flag from the widget.
|
||||
delete self.dirtyWidgets[ id ];
|
||||
|
||||
$document.trigger( 'widget-updated', [ widget ] );
|
||||
|
||||
if ( sidebarId === 'wp_inactive_widgets' ) {
|
||||
$( '#inactive-widgets-control-remove' ).prop( 'disabled' , ! $( '#wp_inactive_widgets .widget' ).length );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( order ) {
|
||||
wpWidgets.saveOrder();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeInactiveWidgets : function() {
|
||||
var $element = $( '.remove-inactive-widgets' ), self = this, a, data;
|
||||
|
||||
$( '.spinner', $element ).addClass( 'is-active' );
|
||||
|
||||
a = {
|
||||
action : 'delete-inactive-widgets',
|
||||
removeinactivewidgets : $( '#_wpnonce_remove_inactive_widgets' ).val()
|
||||
};
|
||||
|
||||
data = $.param( a );
|
||||
|
||||
$.post( ajaxurl, data, function() {
|
||||
$( '#wp_inactive_widgets .widget' ).each(function() {
|
||||
var $widget = $( this );
|
||||
delete self.dirtyWidgets[ $widget.find( 'input.widget-id' ).val() ];
|
||||
$widget.remove();
|
||||
});
|
||||
$( '#inactive-widgets-control-remove' ).prop( 'disabled', true );
|
||||
$( '.spinner', $element ).removeClass( 'is-active' );
|
||||
} );
|
||||
},
|
||||
|
||||
appendTitle : function(widget) {
|
||||
var title = $('input[id*="-title"]', widget).val() || '';
|
||||
|
||||
if ( title ) {
|
||||
title = ': ' + title.replace(/<[^<>]+>/g, '').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
$(widget).children('.widget-top').children('.widget-title').children()
|
||||
.children('.in-widget-title').html(title);
|
||||
|
||||
},
|
||||
|
||||
close : function(widget) {
|
||||
widget.children('.widget-inside').slideUp('fast', function() {
|
||||
widget.attr( 'style', '' )
|
||||
.find( '.widget-top button.widget-action' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.focus();
|
||||
});
|
||||
},
|
||||
|
||||
addWidget: function( chooser ) {
|
||||
var widget, widgetId, add, n, viewportTop, viewportBottom, sidebarBounds,
|
||||
sidebarId = chooser.find( '.widgets-chooser-selected' ).data('sidebarId'),
|
||||
sidebar = $( '#' + sidebarId );
|
||||
|
||||
widget = $('#available-widgets').find('.widget-in-question').clone();
|
||||
widgetId = widget.attr('id');
|
||||
add = widget.find( 'input.add_new' ).val();
|
||||
n = widget.find( 'input.multi_number' ).val();
|
||||
|
||||
// Remove the cloned chooser from the widget.
|
||||
widget.find('.widgets-chooser').remove();
|
||||
|
||||
if ( 'multi' === add ) {
|
||||
widget.html(
|
||||
widget.html().replace( /<[^<>]+>/g, function(m) {
|
||||
return m.replace( /__i__|%i%/g, n );
|
||||
})
|
||||
);
|
||||
|
||||
widget.attr( 'id', widgetId.replace( '__i__', n ) );
|
||||
n++;
|
||||
$( '#' + widgetId ).find('input.multi_number').val(n);
|
||||
} else if ( 'single' === add ) {
|
||||
widget.attr( 'id', 'new-' + widgetId );
|
||||
$( '#' + widgetId ).hide();
|
||||
}
|
||||
|
||||
// Open the widgets container.
|
||||
sidebar.closest( '.widgets-holder-wrap' )
|
||||
.removeClass( 'closed' )
|
||||
.find( '.handlediv' ).attr( 'aria-expanded', 'true' );
|
||||
|
||||
sidebar.append( widget );
|
||||
sidebar.sortable('refresh');
|
||||
|
||||
wpWidgets.save( widget, 0, 0, 1 );
|
||||
// No longer "new" widget.
|
||||
widget.find( 'input.add_new' ).val('');
|
||||
|
||||
$document.trigger( 'widget-added', [ widget ] );
|
||||
|
||||
/*
|
||||
* Check if any part of the sidebar is visible in the viewport. If it is, don't scroll.
|
||||
* Otherwise, scroll up to so the sidebar is in view.
|
||||
*
|
||||
* We do this by comparing the top and bottom, of the sidebar so see if they are within
|
||||
* the bounds of the viewport.
|
||||
*/
|
||||
viewportTop = $(window).scrollTop();
|
||||
viewportBottom = viewportTop + $(window).height();
|
||||
sidebarBounds = sidebar.offset();
|
||||
|
||||
sidebarBounds.bottom = sidebarBounds.top + sidebar.outerHeight();
|
||||
|
||||
if ( viewportTop > sidebarBounds.bottom || viewportBottom < sidebarBounds.top ) {
|
||||
$( 'html, body' ).animate({
|
||||
scrollTop: sidebarBounds.top - 130
|
||||
}, 200 );
|
||||
}
|
||||
|
||||
window.setTimeout( function() {
|
||||
// Cannot use a callback in the animation above as it fires twice,
|
||||
// have to queue this "by hand".
|
||||
widget.find( '.widget-title' ).trigger('click');
|
||||
// At the end of the animation, announce the widget has been added.
|
||||
window.wp.a11y.speak( wp.i18n.__( 'Widget has been added to the selected sidebar' ), 'assertive' );
|
||||
}, 250 );
|
||||
},
|
||||
|
||||
closeChooser: function() {
|
||||
var self = this,
|
||||
widgetInQuestion = $( '#available-widgets .widget-in-question' );
|
||||
|
||||
$( '.widgets-chooser' ).slideUp( 200, function() {
|
||||
$( '#wpbody-content' ).append( this );
|
||||
self.clearWidgetSelection();
|
||||
// Move focus back to the toggle button.
|
||||
widgetInQuestion.find( '.widget-action' ).attr( 'aria-expanded', 'false' ).focus();
|
||||
});
|
||||
},
|
||||
|
||||
clearWidgetSelection: function() {
|
||||
$( '#widgets-left' ).removeClass( 'chooser' );
|
||||
$( '.widget-in-question' ).removeClass( 'widget-in-question' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes a Sidebar that was previously closed, but opened by dragging a Widget over it.
|
||||
*
|
||||
* Used when a Widget gets dragged in/out of the Sidebar and never dropped.
|
||||
*
|
||||
* @param {Object} event jQuery event object.
|
||||
*/
|
||||
closeSidebar: function( event ) {
|
||||
this.hoveredSidebar
|
||||
.addClass( 'closed' )
|
||||
.find( '.handlediv' ).attr( 'aria-expanded', 'false' );
|
||||
|
||||
$( event.target ).css( 'min-height', '' );
|
||||
this.hoveredSidebar = null;
|
||||
}
|
||||
};
|
||||
|
||||
$( function(){ wpWidgets.init(); } );
|
||||
|
||||
})(jQuery);
|
||||
|
||||
/**
|
||||
* Removed in 5.5.0, needed for back-compatibility.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @deprecated 5.5.0
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
wpWidgets.l10n = wpWidgets.l10n || {
|
||||
save: '',
|
||||
saved: '',
|
||||
saveAlert: '',
|
||||
widgetAdded: ''
|
||||
};
|
||||
|
||||
wpWidgets.l10n = window.wp.deprecateL10nObject( 'wpWidgets.l10n', wpWidgets.l10n, '5.5.0' );
|
2
wp-admin/js/widgets.min.js
vendored
Normal file
2
wp-admin/js/widgets.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
462
wp-admin/js/widgets/custom-html-widgets.js
Normal file
462
wp-admin/js/widgets/custom-html-widgets.js
Normal file
@ -0,0 +1,462 @@
|
||||
/**
|
||||
* @output wp-admin/js/widgets/custom-html-widgets.js
|
||||
*/
|
||||
|
||||
/* global wp */
|
||||
/* eslint consistent-this: [ "error", "control" ] */
|
||||
/* eslint no-magic-numbers: ["error", { "ignore": [0,1,-1] }] */
|
||||
|
||||
/**
|
||||
* @namespace wp.customHtmlWidget
|
||||
* @memberOf wp
|
||||
*/
|
||||
wp.customHtmlWidgets = ( function( $ ) {
|
||||
'use strict';
|
||||
|
||||
var component = {
|
||||
idBases: [ 'custom_html' ],
|
||||
codeEditorSettings: {},
|
||||
l10n: {
|
||||
errorNotice: {
|
||||
singular: '',
|
||||
plural: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
component.CustomHtmlWidgetControl = Backbone.View.extend(/** @lends wp.customHtmlWidgets.CustomHtmlWidgetControl.prototype */{
|
||||
|
||||
/**
|
||||
* View events.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
events: {},
|
||||
|
||||
/**
|
||||
* Text widget control.
|
||||
*
|
||||
* @constructs wp.customHtmlWidgets.CustomHtmlWidgetControl
|
||||
* @augments Backbone.View
|
||||
* @abstract
|
||||
*
|
||||
* @param {Object} options - Options.
|
||||
* @param {jQuery} options.el - Control field container element.
|
||||
* @param {jQuery} options.syncContainer - Container element where fields are synced for the server.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
initialize: function initialize( options ) {
|
||||
var control = this;
|
||||
|
||||
if ( ! options.el ) {
|
||||
throw new Error( 'Missing options.el' );
|
||||
}
|
||||
if ( ! options.syncContainer ) {
|
||||
throw new Error( 'Missing options.syncContainer' );
|
||||
}
|
||||
|
||||
Backbone.View.prototype.initialize.call( control, options );
|
||||
control.syncContainer = options.syncContainer;
|
||||
control.widgetIdBase = control.syncContainer.parent().find( '.id_base' ).val();
|
||||
control.widgetNumber = control.syncContainer.parent().find( '.widget_number' ).val();
|
||||
control.customizeSettingId = 'widget_' + control.widgetIdBase + '[' + String( control.widgetNumber ) + ']';
|
||||
|
||||
control.$el.addClass( 'custom-html-widget-fields' );
|
||||
control.$el.html( wp.template( 'widget-custom-html-control-fields' )( { codeEditorDisabled: component.codeEditorSettings.disabled } ) );
|
||||
|
||||
control.errorNoticeContainer = control.$el.find( '.code-editor-error-container' );
|
||||
control.currentErrorAnnotations = [];
|
||||
control.saveButton = control.syncContainer.add( control.syncContainer.parent().find( '.widget-control-actions' ) ).find( '.widget-control-save, #savewidget' );
|
||||
control.saveButton.addClass( 'custom-html-widget-save-button' ); // To facilitate style targeting.
|
||||
|
||||
control.fields = {
|
||||
title: control.$el.find( '.title' ),
|
||||
content: control.$el.find( '.content' )
|
||||
};
|
||||
|
||||
// Sync input fields to hidden sync fields which actually get sent to the server.
|
||||
_.each( control.fields, function( fieldInput, fieldName ) {
|
||||
fieldInput.on( 'input change', function updateSyncField() {
|
||||
var syncInput = control.syncContainer.find( '.sync-input.' + fieldName );
|
||||
if ( syncInput.val() !== fieldInput.val() ) {
|
||||
syncInput.val( fieldInput.val() );
|
||||
syncInput.trigger( 'change' );
|
||||
}
|
||||
});
|
||||
|
||||
// Note that syncInput cannot be re-used because it will be destroyed with each widget-updated event.
|
||||
fieldInput.val( control.syncContainer.find( '.sync-input.' + fieldName ).val() );
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Update input fields from the sync fields.
|
||||
*
|
||||
* This function is called at the widget-updated and widget-synced events.
|
||||
* A field will only be updated if it is not currently focused, to avoid
|
||||
* overwriting content that the user is entering.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
updateFields: function updateFields() {
|
||||
var control = this, syncInput;
|
||||
|
||||
if ( ! control.fields.title.is( document.activeElement ) ) {
|
||||
syncInput = control.syncContainer.find( '.sync-input.title' );
|
||||
control.fields.title.val( syncInput.val() );
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent updating content when the editor is focused or if there are current error annotations,
|
||||
* to prevent the editor's contents from getting sanitized as soon as a user removes focus from
|
||||
* the editor. This is particularly important for users who cannot unfiltered_html.
|
||||
*/
|
||||
control.contentUpdateBypassed = control.fields.content.is( document.activeElement ) || control.editor && control.editor.codemirror.state.focused || 0 !== control.currentErrorAnnotations.length;
|
||||
if ( ! control.contentUpdateBypassed ) {
|
||||
syncInput = control.syncContainer.find( '.sync-input.content' );
|
||||
control.fields.content.val( syncInput.val() );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show linting error notice.
|
||||
*
|
||||
* @param {Array} errorAnnotations - Error annotations.
|
||||
* @return {void}
|
||||
*/
|
||||
updateErrorNotice: function( errorAnnotations ) {
|
||||
var control = this, errorNotice, message = '', customizeSetting;
|
||||
|
||||
if ( 1 === errorAnnotations.length ) {
|
||||
message = component.l10n.errorNotice.singular.replace( '%d', '1' );
|
||||
} else if ( errorAnnotations.length > 1 ) {
|
||||
message = component.l10n.errorNotice.plural.replace( '%d', String( errorAnnotations.length ) );
|
||||
}
|
||||
|
||||
if ( control.fields.content[0].setCustomValidity ) {
|
||||
control.fields.content[0].setCustomValidity( message );
|
||||
}
|
||||
|
||||
if ( wp.customize && wp.customize.has( control.customizeSettingId ) ) {
|
||||
customizeSetting = wp.customize( control.customizeSettingId );
|
||||
customizeSetting.notifications.remove( 'htmlhint_error' );
|
||||
if ( 0 !== errorAnnotations.length ) {
|
||||
customizeSetting.notifications.add( 'htmlhint_error', new wp.customize.Notification( 'htmlhint_error', {
|
||||
message: message,
|
||||
type: 'error'
|
||||
} ) );
|
||||
}
|
||||
} else if ( 0 !== errorAnnotations.length ) {
|
||||
errorNotice = $( '<div class="inline notice notice-error notice-alt"></div>' );
|
||||
errorNotice.append( $( '<p></p>', {
|
||||
text: message
|
||||
} ) );
|
||||
control.errorNoticeContainer.empty();
|
||||
control.errorNoticeContainer.append( errorNotice );
|
||||
control.errorNoticeContainer.slideDown( 'fast' );
|
||||
wp.a11y.speak( message );
|
||||
} else {
|
||||
control.errorNoticeContainer.slideUp( 'fast' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize editor.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
initializeEditor: function initializeEditor() {
|
||||
var control = this, settings;
|
||||
|
||||
if ( component.codeEditorSettings.disabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings = _.extend( {}, component.codeEditorSettings, {
|
||||
|
||||
/**
|
||||
* Handle tabbing to the field before the editor.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
onTabPrevious: function onTabPrevious() {
|
||||
control.fields.title.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle tabbing to the field after the editor.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
onTabNext: function onTabNext() {
|
||||
var tabbables = control.syncContainer.add( control.syncContainer.parent().find( '.widget-position, .widget-control-actions' ) ).find( ':tabbable' );
|
||||
tabbables.first().focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable save button and store linting errors for use in updateFields.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @param {Array} errorAnnotations - Error notifications.
|
||||
* @return {void}
|
||||
*/
|
||||
onChangeLintingErrors: function onChangeLintingErrors( errorAnnotations ) {
|
||||
control.currentErrorAnnotations = errorAnnotations;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update error notice.
|
||||
*
|
||||
* @ignore
|
||||
*
|
||||
* @param {Array} errorAnnotations - Error annotations.
|
||||
* @return {void}
|
||||
*/
|
||||
onUpdateErrorNotice: function onUpdateErrorNotice( errorAnnotations ) {
|
||||
control.saveButton.toggleClass( 'validation-blocked disabled', errorAnnotations.length > 0 );
|
||||
control.updateErrorNotice( errorAnnotations );
|
||||
}
|
||||
});
|
||||
|
||||
control.editor = wp.codeEditor.initialize( control.fields.content, settings );
|
||||
|
||||
// Improve the editor accessibility.
|
||||
$( control.editor.codemirror.display.lineDiv )
|
||||
.attr({
|
||||
role: 'textbox',
|
||||
'aria-multiline': 'true',
|
||||
'aria-labelledby': control.fields.content[0].id + '-label',
|
||||
'aria-describedby': 'editor-keyboard-trap-help-1 editor-keyboard-trap-help-2 editor-keyboard-trap-help-3 editor-keyboard-trap-help-4'
|
||||
});
|
||||
|
||||
// Focus the editor when clicking on its label.
|
||||
$( '#' + control.fields.content[0].id + '-label' ).on( 'click', function() {
|
||||
control.editor.codemirror.focus();
|
||||
});
|
||||
|
||||
control.fields.content.on( 'change', function() {
|
||||
if ( this.value !== control.editor.codemirror.getValue() ) {
|
||||
control.editor.codemirror.setValue( this.value );
|
||||
}
|
||||
});
|
||||
control.editor.codemirror.on( 'change', function() {
|
||||
var value = control.editor.codemirror.getValue();
|
||||
if ( value !== control.fields.content.val() ) {
|
||||
control.fields.content.val( value ).trigger( 'change' );
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure the editor gets updated if the content was updated on the server (sanitization) but not updated in the editor since it was focused.
|
||||
control.editor.codemirror.on( 'blur', function() {
|
||||
if ( control.contentUpdateBypassed ) {
|
||||
control.syncContainer.find( '.sync-input.content' ).trigger( 'change' );
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent hitting Esc from collapsing the widget control.
|
||||
if ( wp.customize ) {
|
||||
control.editor.codemirror.on( 'keydown', function onKeydown( codemirror, event ) {
|
||||
var escKeyCode = 27;
|
||||
if ( escKeyCode === event.keyCode ) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Mapping of widget ID to instances of CustomHtmlWidgetControl subclasses.
|
||||
*
|
||||
* @alias wp.customHtmlWidgets.widgetControls
|
||||
*
|
||||
* @type {Object.<string, wp.textWidgets.CustomHtmlWidgetControl>}
|
||||
*/
|
||||
component.widgetControls = {};
|
||||
|
||||
/**
|
||||
* Handle widget being added or initialized for the first time at the widget-added event.
|
||||
*
|
||||
* @alias wp.customHtmlWidgets.handleWidgetAdded
|
||||
*
|
||||
* @param {jQuery.Event} event - Event.
|
||||
* @param {jQuery} widgetContainer - Widget container element.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
component.handleWidgetAdded = function handleWidgetAdded( event, widgetContainer ) {
|
||||
var widgetForm, idBase, widgetControl, widgetId, animatedCheckDelay = 50, renderWhenAnimationDone, fieldContainer, syncContainer;
|
||||
widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); // Note: '.form' appears in the customizer, whereas 'form' on the widgets admin screen.
|
||||
|
||||
idBase = widgetForm.find( '> .id_base' ).val();
|
||||
if ( -1 === component.idBases.indexOf( idBase ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent initializing already-added widgets.
|
||||
widgetId = widgetForm.find( '.widget-id' ).val();
|
||||
if ( component.widgetControls[ widgetId ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a container element for the widget control fields.
|
||||
* This is inserted into the DOM immediately before the the .widget-content
|
||||
* element because the contents of this element are essentially "managed"
|
||||
* by PHP, where each widget update cause the entire element to be emptied
|
||||
* and replaced with the rendered output of WP_Widget::form() which is
|
||||
* sent back in Ajax request made to save/update the widget instance.
|
||||
* To prevent a "flash of replaced DOM elements and re-initialized JS
|
||||
* components", the JS template is rendered outside of the normal form
|
||||
* container.
|
||||
*/
|
||||
fieldContainer = $( '<div></div>' );
|
||||
syncContainer = widgetContainer.find( '.widget-content:first' );
|
||||
syncContainer.before( fieldContainer );
|
||||
|
||||
widgetControl = new component.CustomHtmlWidgetControl({
|
||||
el: fieldContainer,
|
||||
syncContainer: syncContainer
|
||||
});
|
||||
|
||||
component.widgetControls[ widgetId ] = widgetControl;
|
||||
|
||||
/*
|
||||
* Render the widget once the widget parent's container finishes animating,
|
||||
* as the widget-added event fires with a slideDown of the container.
|
||||
* This ensures that the textarea is visible and the editor can be initialized.
|
||||
*/
|
||||
renderWhenAnimationDone = function() {
|
||||
if ( ! ( wp.customize ? widgetContainer.parent().hasClass( 'expanded' ) : widgetContainer.hasClass( 'open' ) ) ) { // Core merge: The wp.customize condition can be eliminated with this change being in core: https://github.com/xwp/wordpress-develop/pull/247/commits/5322387d
|
||||
setTimeout( renderWhenAnimationDone, animatedCheckDelay );
|
||||
} else {
|
||||
widgetControl.initializeEditor();
|
||||
}
|
||||
};
|
||||
renderWhenAnimationDone();
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup widget in accessibility mode.
|
||||
*
|
||||
* @alias wp.customHtmlWidgets.setupAccessibleMode
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
component.setupAccessibleMode = function setupAccessibleMode() {
|
||||
var widgetForm, idBase, widgetControl, fieldContainer, syncContainer;
|
||||
widgetForm = $( '.editwidget > form' );
|
||||
if ( 0 === widgetForm.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
idBase = widgetForm.find( '.id_base' ).val();
|
||||
if ( -1 === component.idBases.indexOf( idBase ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
fieldContainer = $( '<div></div>' );
|
||||
syncContainer = widgetForm.find( '> .widget-inside' );
|
||||
syncContainer.before( fieldContainer );
|
||||
|
||||
widgetControl = new component.CustomHtmlWidgetControl({
|
||||
el: fieldContainer,
|
||||
syncContainer: syncContainer
|
||||
});
|
||||
|
||||
widgetControl.initializeEditor();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sync widget instance data sanitized from server back onto widget model.
|
||||
*
|
||||
* This gets called via the 'widget-updated' event when saving a widget from
|
||||
* the widgets admin screen and also via the 'widget-synced' event when making
|
||||
* a change to a widget in the customizer.
|
||||
*
|
||||
* @alias wp.customHtmlWidgets.handleWidgetUpdated
|
||||
*
|
||||
* @param {jQuery.Event} event - Event.
|
||||
* @param {jQuery} widgetContainer - Widget container element.
|
||||
* @return {void}
|
||||
*/
|
||||
component.handleWidgetUpdated = function handleWidgetUpdated( event, widgetContainer ) {
|
||||
var widgetForm, widgetId, widgetControl, idBase;
|
||||
widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' );
|
||||
|
||||
idBase = widgetForm.find( '> .id_base' ).val();
|
||||
if ( -1 === component.idBases.indexOf( idBase ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
widgetId = widgetForm.find( '> .widget-id' ).val();
|
||||
widgetControl = component.widgetControls[ widgetId ];
|
||||
if ( ! widgetControl ) {
|
||||
return;
|
||||
}
|
||||
|
||||
widgetControl.updateFields();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize functionality.
|
||||
*
|
||||
* This function exists to prevent the JS file from having to boot itself.
|
||||
* When WordPress enqueues this script, it should have an inline script
|
||||
* attached which calls wp.textWidgets.init().
|
||||
*
|
||||
* @alias wp.customHtmlWidgets.init
|
||||
*
|
||||
* @param {Object} settings - Options for code editor, exported from PHP.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
component.init = function init( settings ) {
|
||||
var $document = $( document );
|
||||
_.extend( component.codeEditorSettings, settings );
|
||||
|
||||
$document.on( 'widget-added', component.handleWidgetAdded );
|
||||
$document.on( 'widget-synced widget-updated', component.handleWidgetUpdated );
|
||||
|
||||
/*
|
||||
* Manually trigger widget-added events for media widgets on the admin
|
||||
* screen once they are expanded. The widget-added event is not triggered
|
||||
* for each pre-existing widget on the widgets admin screen like it is
|
||||
* on the customizer. Likewise, the customizer only triggers widget-added
|
||||
* when the widget is expanded to just-in-time construct the widget form
|
||||
* when it is actually going to be displayed. So the following implements
|
||||
* the same for the widgets admin screen, to invoke the widget-added
|
||||
* handler when a pre-existing media widget is expanded.
|
||||
*/
|
||||
$( function initializeExistingWidgetContainers() {
|
||||
var widgetContainers;
|
||||
if ( 'widgets' !== window.pagenow ) {
|
||||
return;
|
||||
}
|
||||
widgetContainers = $( '.widgets-holder-wrap:not(#available-widgets)' ).find( 'div.widget' );
|
||||
widgetContainers.one( 'click.toggle-widget-expanded', function toggleWidgetExpanded() {
|
||||
var widgetContainer = $( this );
|
||||
component.handleWidgetAdded( new jQuery.Event( 'widget-added' ), widgetContainer );
|
||||
});
|
||||
|
||||
// Accessibility mode.
|
||||
if ( document.readyState === 'complete' ) {
|
||||
// Page is fully loaded.
|
||||
component.setupAccessibleMode();
|
||||
} else {
|
||||
// Page is still loading.
|
||||
$( window ).on( 'load', function() {
|
||||
component.setupAccessibleMode();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return component;
|
||||
})( jQuery );
|
2
wp-admin/js/widgets/custom-html-widgets.min.js
vendored
Normal file
2
wp-admin/js/widgets/custom-html-widgets.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
154
wp-admin/js/widgets/media-audio-widget.js
Normal file
154
wp-admin/js/widgets/media-audio-widget.js
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @output wp-admin/js/widgets/media-audio-widget.js
|
||||
*/
|
||||
|
||||
/* eslint consistent-this: [ "error", "control" ] */
|
||||
(function( component ) {
|
||||
'use strict';
|
||||
|
||||
var AudioWidgetModel, AudioWidgetControl, AudioDetailsMediaFrame;
|
||||
|
||||
/**
|
||||
* Custom audio details frame that removes the replace-audio state.
|
||||
*
|
||||
* @class wp.mediaWidgets.controlConstructors~AudioDetailsMediaFrame
|
||||
* @augments wp.media.view.MediaFrame.AudioDetails
|
||||
*/
|
||||
AudioDetailsMediaFrame = wp.media.view.MediaFrame.AudioDetails.extend(/** @lends wp.mediaWidgets.controlConstructors~AudioDetailsMediaFrame.prototype */{
|
||||
|
||||
/**
|
||||
* Create the default states.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
createStates: function createStates() {
|
||||
this.states.add([
|
||||
new wp.media.controller.AudioDetails({
|
||||
media: this.media
|
||||
}),
|
||||
|
||||
new wp.media.controller.MediaLibrary({
|
||||
type: 'audio',
|
||||
id: 'add-audio-source',
|
||||
title: wp.media.view.l10n.audioAddSourceTitle,
|
||||
toolbar: 'add-audio-source',
|
||||
media: this.media,
|
||||
menu: false
|
||||
})
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Audio widget model.
|
||||
*
|
||||
* See WP_Widget_Audio::enqueue_admin_scripts() for amending prototype from PHP exports.
|
||||
*
|
||||
* @class wp.mediaWidgets.modelConstructors.media_audio
|
||||
* @augments wp.mediaWidgets.MediaWidgetModel
|
||||
*/
|
||||
AudioWidgetModel = component.MediaWidgetModel.extend({});
|
||||
|
||||
/**
|
||||
* Audio widget control.
|
||||
*
|
||||
* See WP_Widget_Audio::enqueue_admin_scripts() for amending prototype from PHP exports.
|
||||
*
|
||||
* @class wp.mediaWidgets.controlConstructors.media_audio
|
||||
* @augments wp.mediaWidgets.MediaWidgetControl
|
||||
*/
|
||||
AudioWidgetControl = component.MediaWidgetControl.extend(/** @lends wp.mediaWidgets.controlConstructors.media_audio.prototype */{
|
||||
|
||||
/**
|
||||
* Show display settings.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
showDisplaySettings: false,
|
||||
|
||||
/**
|
||||
* Map model props to media frame props.
|
||||
*
|
||||
* @param {Object} modelProps - Model props.
|
||||
* @return {Object} Media frame props.
|
||||
*/
|
||||
mapModelToMediaFrameProps: function mapModelToMediaFrameProps( modelProps ) {
|
||||
var control = this, mediaFrameProps;
|
||||
mediaFrameProps = component.MediaWidgetControl.prototype.mapModelToMediaFrameProps.call( control, modelProps );
|
||||
mediaFrameProps.link = 'embed';
|
||||
return mediaFrameProps;
|
||||
},
|
||||
|
||||
/**
|
||||
* Render preview.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
renderPreview: function renderPreview() {
|
||||
var control = this, previewContainer, previewTemplate, attachmentId, attachmentUrl;
|
||||
attachmentId = control.model.get( 'attachment_id' );
|
||||
attachmentUrl = control.model.get( 'url' );
|
||||
|
||||
if ( ! attachmentId && ! attachmentUrl ) {
|
||||
return;
|
||||
}
|
||||
|
||||
previewContainer = control.$el.find( '.media-widget-preview' );
|
||||
previewTemplate = wp.template( 'wp-media-widget-audio-preview' );
|
||||
|
||||
previewContainer.html( previewTemplate({
|
||||
model: {
|
||||
attachment_id: control.model.get( 'attachment_id' ),
|
||||
src: attachmentUrl
|
||||
},
|
||||
error: control.model.get( 'error' )
|
||||
}));
|
||||
wp.mediaelement.initialize();
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the media audio-edit frame to modify the selected item.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
editMedia: function editMedia() {
|
||||
var control = this, mediaFrame, metadata, updateCallback;
|
||||
|
||||
metadata = control.mapModelToMediaFrameProps( control.model.toJSON() );
|
||||
|
||||
// Set up the media frame.
|
||||
mediaFrame = new AudioDetailsMediaFrame({
|
||||
frame: 'audio',
|
||||
state: 'audio-details',
|
||||
metadata: metadata
|
||||
});
|
||||
wp.media.frame = mediaFrame;
|
||||
mediaFrame.$el.addClass( 'media-widget' );
|
||||
|
||||
updateCallback = function( mediaFrameProps ) {
|
||||
|
||||
// Update cached attachment object to avoid having to re-fetch. This also triggers re-rendering of preview.
|
||||
control.selectedAttachment.set( mediaFrameProps );
|
||||
|
||||
control.model.set( _.extend(
|
||||
control.model.defaults(),
|
||||
control.mapMediaToModelProps( mediaFrameProps ),
|
||||
{ error: false }
|
||||
) );
|
||||
};
|
||||
|
||||
mediaFrame.state( 'audio-details' ).on( 'update', updateCallback );
|
||||
mediaFrame.state( 'replace-audio' ).on( 'replace', updateCallback );
|
||||
mediaFrame.on( 'close', function() {
|
||||
mediaFrame.detach();
|
||||
});
|
||||
|
||||
mediaFrame.open();
|
||||
}
|
||||
});
|
||||
|
||||
// Exports.
|
||||
component.controlConstructors.media_audio = AudioWidgetControl;
|
||||
component.modelConstructors.media_audio = AudioWidgetModel;
|
||||
|
||||
})( wp.mediaWidgets );
|
2
wp-admin/js/widgets/media-audio-widget.min.js
vendored
Normal file
2
wp-admin/js/widgets/media-audio-widget.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(t){"use strict";var a=wp.media.view.MediaFrame.AudioDetails.extend({createStates:function(){this.states.add([new wp.media.controller.AudioDetails({media:this.media}),new wp.media.controller.MediaLibrary({type:"audio",id:"add-audio-source",title:wp.media.view.l10n.audioAddSourceTitle,toolbar:"add-audio-source",media:this.media,menu:!1})])}}),e=t.MediaWidgetModel.extend({}),d=t.MediaWidgetControl.extend({showDisplaySettings:!1,mapModelToMediaFrameProps:function(e){e=t.MediaWidgetControl.prototype.mapModelToMediaFrameProps.call(this,e);return e.link="embed",e},renderPreview:function(){var e,t=this,d=t.model.get("attachment_id"),a=t.model.get("url");(d||a)&&(d=t.$el.find(".media-widget-preview"),e=wp.template("wp-media-widget-audio-preview"),d.html(e({model:{attachment_id:t.model.get("attachment_id"),src:a},error:t.model.get("error")})),wp.mediaelement.initialize())},editMedia:function(){var t=this,e=t.mapModelToMediaFrameProps(t.model.toJSON()),d=new a({frame:"audio",state:"audio-details",metadata:e});(wp.media.frame=d).$el.addClass("media-widget"),e=function(e){t.selectedAttachment.set(e),t.model.set(_.extend(t.model.defaults(),t.mapMediaToModelProps(e),{error:!1}))},d.state("audio-details").on("update",e),d.state("replace-audio").on("replace",e),d.on("close",function(){d.detach()}),d.open()}});t.controlConstructors.media_audio=d,t.modelConstructors.media_audio=e}(wp.mediaWidgets);
|
341
wp-admin/js/widgets/media-gallery-widget.js
Normal file
341
wp-admin/js/widgets/media-gallery-widget.js
Normal file
@ -0,0 +1,341 @@
|
||||
/**
|
||||
* @output wp-admin/js/widgets/media-gallery-widget.js
|
||||
*/
|
||||
|
||||
/* eslint consistent-this: [ "error", "control" ] */
|
||||
(function( component ) {
|
||||
'use strict';
|
||||
|
||||
var GalleryWidgetModel, GalleryWidgetControl, GalleryDetailsMediaFrame;
|
||||
|
||||
/**
|
||||
* Custom gallery details frame.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @class wp.mediaWidgets~GalleryDetailsMediaFrame
|
||||
* @augments wp.media.view.MediaFrame.Post
|
||||
*/
|
||||
GalleryDetailsMediaFrame = wp.media.view.MediaFrame.Post.extend(/** @lends wp.mediaWidgets~GalleryDetailsMediaFrame.prototype */{
|
||||
|
||||
/**
|
||||
* Create the default states.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @return {void}
|
||||
*/
|
||||
createStates: function createStates() {
|
||||
this.states.add([
|
||||
new wp.media.controller.Library({
|
||||
id: 'gallery',
|
||||
title: wp.media.view.l10n.createGalleryTitle,
|
||||
priority: 40,
|
||||
toolbar: 'main-gallery',
|
||||
filterable: 'uploaded',
|
||||
multiple: 'add',
|
||||
editable: true,
|
||||
|
||||
library: wp.media.query( _.defaults({
|
||||
type: 'image'
|
||||
}, this.options.library ) )
|
||||
}),
|
||||
|
||||
// Gallery states.
|
||||
new wp.media.controller.GalleryEdit({
|
||||
library: this.options.selection,
|
||||
editing: this.options.editing,
|
||||
menu: 'gallery'
|
||||
}),
|
||||
|
||||
new wp.media.controller.GalleryAdd()
|
||||
]);
|
||||
}
|
||||
} );
|
||||
|
||||
/**
|
||||
* Gallery widget model.
|
||||
*
|
||||
* See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
|
||||
*
|
||||
* @since 4.9.0
|
||||
*
|
||||
* @class wp.mediaWidgets.modelConstructors.media_gallery
|
||||
* @augments wp.mediaWidgets.MediaWidgetModel
|
||||
*/
|
||||
GalleryWidgetModel = component.MediaWidgetModel.extend(/** @lends wp.mediaWidgets.modelConstructors.media_gallery.prototype */{} );
|
||||
|
||||
GalleryWidgetControl = component.MediaWidgetControl.extend(/** @lends wp.mediaWidgets.controlConstructors.media_gallery.prototype */{
|
||||
|
||||
/**
|
||||
* View events.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @type {object}
|
||||
*/
|
||||
events: _.extend( {}, component.MediaWidgetControl.prototype.events, {
|
||||
'click .media-widget-gallery-preview': 'editMedia'
|
||||
} ),
|
||||
|
||||
/**
|
||||
* Gallery widget control.
|
||||
*
|
||||
* See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
|
||||
*
|
||||
* @constructs wp.mediaWidgets.controlConstructors.media_gallery
|
||||
* @augments wp.mediaWidgets.MediaWidgetControl
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @param {Object} options - Options.
|
||||
* @param {Backbone.Model} options.model - Model.
|
||||
* @param {jQuery} options.el - Control field container element.
|
||||
* @param {jQuery} options.syncContainer - Container element where fields are synced for the server.
|
||||
* @return {void}
|
||||
*/
|
||||
initialize: function initialize( options ) {
|
||||
var control = this;
|
||||
|
||||
component.MediaWidgetControl.prototype.initialize.call( control, options );
|
||||
|
||||
_.bindAll( control, 'updateSelectedAttachments', 'handleAttachmentDestroy' );
|
||||
control.selectedAttachments = new wp.media.model.Attachments();
|
||||
control.model.on( 'change:ids', control.updateSelectedAttachments );
|
||||
control.selectedAttachments.on( 'change', control.renderPreview );
|
||||
control.selectedAttachments.on( 'reset', control.renderPreview );
|
||||
control.updateSelectedAttachments();
|
||||
|
||||
/*
|
||||
* Refresh a Gallery widget partial when the user modifies one of the selected attachments.
|
||||
* This ensures that when an attachment's caption is updated in the media modal the Gallery
|
||||
* widget in the preview will then be refreshed to show the change. Normally doing this
|
||||
* would not be necessary because all of the state should be contained inside the changeset,
|
||||
* as everything done in the Customizer should not make a change to the site unless the
|
||||
* changeset itself is published. Attachments are a current exception to this rule.
|
||||
* For a proposal to include attachments in the customized state, see #37887.
|
||||
*/
|
||||
if ( wp.customize && wp.customize.previewer ) {
|
||||
control.selectedAttachments.on( 'change', function() {
|
||||
wp.customize.previewer.send( 'refresh-widget-partial', control.model.get( 'widget_id' ) );
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the selected attachments if necessary.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @return {void}
|
||||
*/
|
||||
updateSelectedAttachments: function updateSelectedAttachments() {
|
||||
var control = this, newIds, oldIds, removedIds, addedIds, addedQuery;
|
||||
|
||||
newIds = control.model.get( 'ids' );
|
||||
oldIds = _.pluck( control.selectedAttachments.models, 'id' );
|
||||
|
||||
removedIds = _.difference( oldIds, newIds );
|
||||
_.each( removedIds, function( removedId ) {
|
||||
control.selectedAttachments.remove( control.selectedAttachments.get( removedId ) );
|
||||
});
|
||||
|
||||
addedIds = _.difference( newIds, oldIds );
|
||||
if ( addedIds.length ) {
|
||||
addedQuery = wp.media.query({
|
||||
order: 'ASC',
|
||||
orderby: 'post__in',
|
||||
perPage: -1,
|
||||
post__in: newIds,
|
||||
query: true,
|
||||
type: 'image'
|
||||
});
|
||||
addedQuery.more().done( function() {
|
||||
control.selectedAttachments.reset( addedQuery.models );
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Render preview.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @return {void}
|
||||
*/
|
||||
renderPreview: function renderPreview() {
|
||||
var control = this, previewContainer, previewTemplate, data;
|
||||
|
||||
previewContainer = control.$el.find( '.media-widget-preview' );
|
||||
previewTemplate = wp.template( 'wp-media-widget-gallery-preview' );
|
||||
|
||||
data = control.previewTemplateProps.toJSON();
|
||||
data.attachments = {};
|
||||
control.selectedAttachments.each( function( attachment ) {
|
||||
data.attachments[ attachment.id ] = attachment.toJSON();
|
||||
} );
|
||||
|
||||
previewContainer.html( previewTemplate( data ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether there are selected attachments.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @return {boolean} Selected.
|
||||
*/
|
||||
isSelected: function isSelected() {
|
||||
var control = this;
|
||||
|
||||
if ( control.model.get( 'error' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return control.model.get( 'ids' ).length > 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the media select frame to edit images.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @return {void}
|
||||
*/
|
||||
editMedia: function editMedia() {
|
||||
var control = this, selection, mediaFrame, mediaFrameProps;
|
||||
|
||||
selection = new wp.media.model.Selection( control.selectedAttachments.models, {
|
||||
multiple: true
|
||||
});
|
||||
|
||||
mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() );
|
||||
selection.gallery = new Backbone.Model( mediaFrameProps );
|
||||
if ( mediaFrameProps.size ) {
|
||||
control.displaySettings.set( 'size', mediaFrameProps.size );
|
||||
}
|
||||
mediaFrame = new GalleryDetailsMediaFrame({
|
||||
frame: 'manage',
|
||||
text: control.l10n.add_to_widget,
|
||||
selection: selection,
|
||||
mimeType: control.mime_type,
|
||||
selectedDisplaySettings: control.displaySettings,
|
||||
showDisplaySettings: control.showDisplaySettings,
|
||||
metadata: mediaFrameProps,
|
||||
editing: true,
|
||||
multiple: true,
|
||||
state: 'gallery-edit'
|
||||
});
|
||||
wp.media.frame = mediaFrame; // See wp.media().
|
||||
|
||||
// Handle selection of a media item.
|
||||
mediaFrame.on( 'update', function onUpdate( newSelection ) {
|
||||
var state = mediaFrame.state(), resultSelection;
|
||||
|
||||
resultSelection = newSelection || state.get( 'selection' );
|
||||
if ( ! resultSelection ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy orderby_random from gallery state.
|
||||
if ( resultSelection.gallery ) {
|
||||
control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) );
|
||||
}
|
||||
|
||||
// Directly update selectedAttachments to prevent needing to do additional request.
|
||||
control.selectedAttachments.reset( resultSelection.models );
|
||||
|
||||
// Update models in the widget instance.
|
||||
control.model.set( {
|
||||
ids: _.pluck( resultSelection.models, 'id' )
|
||||
} );
|
||||
} );
|
||||
|
||||
mediaFrame.$el.addClass( 'media-widget' );
|
||||
mediaFrame.open();
|
||||
|
||||
if ( selection ) {
|
||||
selection.on( 'destroy', control.handleAttachmentDestroy );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the media select frame to chose an item.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @return {void}
|
||||
*/
|
||||
selectMedia: function selectMedia() {
|
||||
var control = this, selection, mediaFrame, mediaFrameProps;
|
||||
selection = new wp.media.model.Selection( control.selectedAttachments.models, {
|
||||
multiple: true
|
||||
});
|
||||
|
||||
mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() );
|
||||
if ( mediaFrameProps.size ) {
|
||||
control.displaySettings.set( 'size', mediaFrameProps.size );
|
||||
}
|
||||
mediaFrame = new GalleryDetailsMediaFrame({
|
||||
frame: 'select',
|
||||
text: control.l10n.add_to_widget,
|
||||
selection: selection,
|
||||
mimeType: control.mime_type,
|
||||
selectedDisplaySettings: control.displaySettings,
|
||||
showDisplaySettings: control.showDisplaySettings,
|
||||
metadata: mediaFrameProps,
|
||||
state: 'gallery'
|
||||
});
|
||||
wp.media.frame = mediaFrame; // See wp.media().
|
||||
|
||||
// Handle selection of a media item.
|
||||
mediaFrame.on( 'update', function onUpdate( newSelection ) {
|
||||
var state = mediaFrame.state(), resultSelection;
|
||||
|
||||
resultSelection = newSelection || state.get( 'selection' );
|
||||
if ( ! resultSelection ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy orderby_random from gallery state.
|
||||
if ( resultSelection.gallery ) {
|
||||
control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) );
|
||||
}
|
||||
|
||||
// Directly update selectedAttachments to prevent needing to do additional request.
|
||||
control.selectedAttachments.reset( resultSelection.models );
|
||||
|
||||
// Update widget instance.
|
||||
control.model.set( {
|
||||
ids: _.pluck( resultSelection.models, 'id' )
|
||||
} );
|
||||
} );
|
||||
|
||||
mediaFrame.$el.addClass( 'media-widget' );
|
||||
mediaFrame.open();
|
||||
|
||||
if ( selection ) {
|
||||
selection.on( 'destroy', control.handleAttachmentDestroy );
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure focus is set inside of modal so that hitting Esc will close
|
||||
* the modal and not inadvertently cause the widget to collapse in the customizer.
|
||||
*/
|
||||
mediaFrame.$el.find( ':focusable:first' ).focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the selected attachment when it is deleted in the media select frame.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @param {wp.media.models.Attachment} attachment - Attachment.
|
||||
* @return {void}
|
||||
*/
|
||||
handleAttachmentDestroy: function handleAttachmentDestroy( attachment ) {
|
||||
var control = this;
|
||||
control.model.set( {
|
||||
ids: _.difference(
|
||||
control.model.get( 'ids' ),
|
||||
[ attachment.id ]
|
||||
)
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
||||
// Exports.
|
||||
component.controlConstructors.media_gallery = GalleryWidgetControl;
|
||||
component.modelConstructors.media_gallery = GalleryWidgetModel;
|
||||
|
||||
})( wp.mediaWidgets );
|
2
wp-admin/js/widgets/media-gallery-widget.min.js
vendored
Normal file
2
wp-admin/js/widgets/media-gallery-widget.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! This file is auto-generated */
|
||||
!function(i){"use strict";var a=wp.media.view.MediaFrame.Post.extend({createStates:function(){this.states.add([new wp.media.controller.Library({id:"gallery",title:wp.media.view.l10n.createGalleryTitle,priority:40,toolbar:"main-gallery",filterable:"uploaded",multiple:"add",editable:!0,library:wp.media.query(_.defaults({type:"image"},this.options.library))}),new wp.media.controller.GalleryEdit({library:this.options.selection,editing:this.options.editing,menu:"gallery"}),new wp.media.controller.GalleryAdd])}}),e=i.MediaWidgetModel.extend({}),t=i.MediaWidgetControl.extend({events:_.extend({},i.MediaWidgetControl.prototype.events,{"click .media-widget-gallery-preview":"editMedia"}),initialize:function(e){var t=this;i.MediaWidgetControl.prototype.initialize.call(t,e),_.bindAll(t,"updateSelectedAttachments","handleAttachmentDestroy"),t.selectedAttachments=new wp.media.model.Attachments,t.model.on("change:ids",t.updateSelectedAttachments),t.selectedAttachments.on("change",t.renderPreview),t.selectedAttachments.on("reset",t.renderPreview),t.updateSelectedAttachments(),wp.customize&&wp.customize.previewer&&t.selectedAttachments.on("change",function(){wp.customize.previewer.send("refresh-widget-partial",t.model.get("widget_id"))})},updateSelectedAttachments:function(){var e,t=this,i=t.model.get("ids"),d=_.pluck(t.selectedAttachments.models,"id"),a=_.difference(d,i);_.each(a,function(e){t.selectedAttachments.remove(t.selectedAttachments.get(e))}),_.difference(i,d).length&&(e=wp.media.query({order:"ASC",orderby:"post__in",perPage:-1,post__in:i,query:!0,type:"image"})).more().done(function(){t.selectedAttachments.reset(e.models)})},renderPreview:function(){var e=this,t=e.$el.find(".media-widget-preview"),i=wp.template("wp-media-widget-gallery-preview"),d=e.previewTemplateProps.toJSON();d.attachments={},e.selectedAttachments.each(function(e){d.attachments[e.id]=e.toJSON()}),t.html(i(d))},isSelected:function(){return!this.model.get("error")&&0<this.model.get("ids").length},editMedia:function(){var i,d=this,e=new wp.media.model.Selection(d.selectedAttachments.models,{multiple:!0}),t=d.mapModelToMediaFrameProps(d.model.toJSON());e.gallery=new Backbone.Model(t),t.size&&d.displaySettings.set("size",t.size),i=new a({frame:"manage",text:d.l10n.add_to_widget,selection:e,mimeType:d.mime_type,selectedDisplaySettings:d.displaySettings,showDisplaySettings:d.showDisplaySettings,metadata:t,editing:!0,multiple:!0,state:"gallery-edit"}),(wp.media.frame=i).on("update",function(e){var t=i.state(),e=e||t.get("selection");e&&(e.gallery&&d.model.set(d.mapMediaToModelProps(e.gallery.toJSON())),d.selectedAttachments.reset(e.models),d.model.set({ids:_.pluck(e.models,"id")}))}),i.$el.addClass("media-widget"),i.open(),e&&e.on("destroy",d.handleAttachmentDestroy)},selectMedia:function(){var i,d=this,e=new wp.media.model.Selection(d.selectedAttachments.models,{multiple:!0}),t=d.mapModelToMediaFrameProps(d.model.toJSON());t.size&&d.displaySettings.set("size",t.size),i=new a({frame:"select",text:d.l10n.add_to_widget,selection:e,mimeType:d.mime_type,selectedDisplaySettings:d.displaySettings,showDisplaySettings:d.showDisplaySettings,metadata:t,state:"gallery"}),(wp.media.frame=i).on("update",function(e){var t=i.state(),e=e||t.get("selection");e&&(e.gallery&&d.model.set(d.mapMediaToModelProps(e.gallery.toJSON())),d.selectedAttachments.reset(e.models),d.model.set({ids:_.pluck(e.models,"id")}))}),i.$el.addClass("media-widget"),i.open(),e&&e.on("destroy",d.handleAttachmentDestroy),i.$el.find(":focusable:first").focus()},handleAttachmentDestroy:function(e){this.model.set({ids:_.difference(this.model.get("ids"),[e.id])})}});i.controlConstructors.media_gallery=t,i.modelConstructors.media_gallery=e}(wp.mediaWidgets);
|
170
wp-admin/js/widgets/media-image-widget.js
Normal file
170
wp-admin/js/widgets/media-image-widget.js
Normal file
@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @output wp-admin/js/widgets/media-image-widget.js
|
||||
*/
|
||||
|
||||
/* eslint consistent-this: [ "error", "control" ] */
|
||||
(function( component, $ ) {
|
||||
'use strict';
|
||||
|
||||
var ImageWidgetModel, ImageWidgetControl;
|
||||
|
||||
/**
|
||||
* Image widget model.
|
||||
*
|
||||
* See WP_Widget_Media_Image::enqueue_admin_scripts() for amending prototype from PHP exports.
|
||||
*
|
||||
* @class wp.mediaWidgets.modelConstructors.media_image
|
||||
* @augments wp.mediaWidgets.MediaWidgetModel
|
||||
*/
|
||||
ImageWidgetModel = component.MediaWidgetModel.extend({});
|
||||
|
||||
/**
|
||||
* Image widget control.
|
||||
*
|
||||
* See WP_Widget_Media_Image::enqueue_admin_scripts() for amending prototype from PHP exports.
|
||||
*
|
||||
* @class wp.mediaWidgets.controlConstructors.media_audio
|
||||
* @augments wp.mediaWidgets.MediaWidgetControl
|
||||
*/
|
||||
ImageWidgetControl = component.MediaWidgetControl.extend(/** @lends wp.mediaWidgets.controlConstructors.media_image.prototype */{
|
||||
|
||||
/**
|
||||
* View events.
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
events: _.extend( {}, component.MediaWidgetControl.prototype.events, {
|
||||
'click .media-widget-preview.populated': 'editMedia'
|
||||
} ),
|
||||
|
||||
/**
|
||||
* Render preview.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
renderPreview: function renderPreview() {
|
||||
var control = this, previewContainer, previewTemplate, fieldsContainer, fieldsTemplate, linkInput;
|
||||
if ( ! control.model.get( 'attachment_id' ) && ! control.model.get( 'url' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
previewContainer = control.$el.find( '.media-widget-preview' );
|
||||
previewTemplate = wp.template( 'wp-media-widget-image-preview' );
|
||||
previewContainer.html( previewTemplate( control.previewTemplateProps.toJSON() ) );
|
||||
previewContainer.addClass( 'populated' );
|
||||
|
||||
linkInput = control.$el.find( '.link' );
|
||||
if ( ! linkInput.is( document.activeElement ) ) {
|
||||
fieldsContainer = control.$el.find( '.media-widget-fields' );
|
||||
fieldsTemplate = wp.template( 'wp-media-widget-image-fields' );
|
||||
fieldsContainer.html( fieldsTemplate( control.previewTemplateProps.toJSON() ) );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the media image-edit frame to modify the selected item.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
editMedia: function editMedia() {
|
||||
var control = this, mediaFrame, updateCallback, defaultSync, metadata;
|
||||
|
||||
metadata = control.mapModelToMediaFrameProps( control.model.toJSON() );
|
||||
|
||||
// Needed or else none will not be selected if linkUrl is not also empty.
|
||||
if ( 'none' === metadata.link ) {
|
||||
metadata.linkUrl = '';
|
||||
}
|
||||
|
||||
// Set up the media frame.
|
||||
mediaFrame = wp.media({
|
||||
frame: 'image',
|
||||
state: 'image-details',
|
||||
metadata: metadata
|
||||
});
|
||||
mediaFrame.$el.addClass( 'media-widget' );
|
||||
|
||||
updateCallback = function() {
|
||||
var mediaProps, linkType;
|
||||
|
||||
// Update cached attachment object to avoid having to re-fetch. This also triggers re-rendering of preview.
|
||||
mediaProps = mediaFrame.state().attributes.image.toJSON();
|
||||
linkType = mediaProps.link;
|
||||
mediaProps.link = mediaProps.linkUrl;
|
||||
control.selectedAttachment.set( mediaProps );
|
||||
control.displaySettings.set( 'link', linkType );
|
||||
|
||||
control.model.set( _.extend(
|
||||
control.mapMediaToModelProps( mediaProps ),
|
||||
{ error: false }
|
||||
) );
|
||||
};
|
||||
|
||||
mediaFrame.state( 'image-details' ).on( 'update', updateCallback );
|
||||
mediaFrame.state( 'replace-image' ).on( 'replace', updateCallback );
|
||||
|
||||
// Disable syncing of attachment changes back to server. See <https://core.trac.wordpress.org/ticket/40403>.
|
||||
defaultSync = wp.media.model.Attachment.prototype.sync;
|
||||
wp.media.model.Attachment.prototype.sync = function rejectedSync() {
|
||||
return $.Deferred().rejectWith( this ).promise();
|
||||
};
|
||||
mediaFrame.on( 'close', function onClose() {
|
||||
mediaFrame.detach();
|
||||
wp.media.model.Attachment.prototype.sync = defaultSync;
|
||||
});
|
||||
|
||||
mediaFrame.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get props which are merged on top of the model when an embed is chosen (as opposed to an attachment).
|
||||
*
|
||||
* @return {Object} Reset/override props.
|
||||
*/
|
||||
getEmbedResetProps: function getEmbedResetProps() {
|
||||
return _.extend(
|
||||
component.MediaWidgetControl.prototype.getEmbedResetProps.call( this ),
|
||||
{
|
||||
size: 'full',
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the instance props from the media selection frame.
|
||||
*
|
||||
* Prevent the image_title attribute from being initially set when adding an image from the media library.
|
||||
*
|
||||
* @param {wp.media.view.MediaFrame.Select} mediaFrame - Select frame.
|
||||
* @return {Object} Props.
|
||||
*/
|
||||
getModelPropsFromMediaFrame: function getModelPropsFromMediaFrame( mediaFrame ) {
|
||||
var control = this;
|
||||
return _.omit(
|
||||
component.MediaWidgetControl.prototype.getModelPropsFromMediaFrame.call( control, mediaFrame ),
|
||||
'image_title'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Map model props to preview template props.
|
||||
*
|
||||
* @return {Object} Preview template props.
|
||||
*/
|
||||
mapModelToPreviewTemplateProps: function mapModelToPreviewTemplateProps() {
|
||||
var control = this, previewTemplateProps, url;
|
||||
url = control.model.get( 'url' );
|
||||
previewTemplateProps = component.MediaWidgetControl.prototype.mapModelToPreviewTemplateProps.call( control );
|
||||
previewTemplateProps.currentFilename = url ? url.replace( /\?.*$/, '' ).replace( /^.+\//, '' ) : '';
|
||||
previewTemplateProps.link_url = control.model.get( 'link_url' );
|
||||
return previewTemplateProps;
|
||||
}
|
||||
});
|
||||
|
||||
// Exports.
|
||||
component.controlConstructors.media_image = ImageWidgetControl;
|
||||
component.modelConstructors.media_image = ImageWidgetModel;
|
||||
|
||||
})( wp.mediaWidgets, jQuery );
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user