PK 2>\ku u accordion.jsnu [ /**
* 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:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* 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', '.accordion-section-title button', function() {
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' ),
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 ( el ) {
el.attr( 'aria-expanded', String( el.attr( 'aria-expanded' ) === 'false' ) );
}
}
})(jQuery);
PK 2>\a accordion.min.jsnu [ /*! This file is auto-generated */
!function(s){s(function(){s(".accordion-container").on("click",".accordion-section-title button",function(){var n,o,e,a,t,i;n=s(this),o=n.closest(".accordion-section"),e=o.closest(".accordion-container"),a=e.find(".open"),t=a.find("[aria-expanded]").first(),i=o.find(".accordion-section-content"),o.hasClass("cannot-expand")||(e.addClass("opening"),o.hasClass("open")?(o.toggleClass("open"),i.toggle(!0).slideToggle(150)):(t.attr("aria-expanded","false"),a.removeClass("open"),a.find(".accordion-section-content").show().slideUp(150),i.toggle(!1).slideToggle(150),o.toggleClass("open")),setTimeout(function(){e.removeClass("opening")},150),n&&n.attr("aria-expanded",String("false"===n.attr("aria-expanded"))))})})}(jQuery);PK 2>\A^[_ application-passwords.jsnu [ /**
* @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 = $( '' )
.attr( 'role', 'alert' )
.attr( 'tabindex', '-1' )
.addClass( 'is-dismissible notice notice-' + type )
.append( $( '' ).text( message ) )
.append(
$( '' )
.attr( 'type', 'button' )
.addClass( 'notice-dismiss' )
.append( $( '' ).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 ) );
PK 2>\ġNr application-passwords.min.jsnu [ /*! 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("").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(o("").text(e)).append(o("").attr("type","button").addClass("notice-dismiss").append(o("").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);PK 2>\{X auth-app.jsnu [ /**
* @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. */
'',
''
) + ' ';
$notice = $( '' )
.attr( 'role', 'alert' )
.attr( 'tabindex', -1 )
.addClass( 'notice notice-success notice-alt' )
.append( $( '' ).addClass( 'application-password-display' ).html( message ) )
.append( '
' + wp.i18n.__( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ) + '
' );
// 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 = $( '' )
.attr( 'role', 'alert' )
.addClass( 'notice notice-error' )
.append( $( '' ).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 ) );
PK 2>\ry$ $ auth-app.min.jsnu [ /*! 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'+wp.i18n.__("Your new password for %s is:")+"","")+' ',o=t("").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(t("").addClass("application-password-display").html(a)).append("
"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"
"),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("").attr("role","alert").addClass("notice notice-error").append(t("").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);PK 2>\2S+F +F code-editor.jsnu ȯ /**
* @output wp-admin/js/code-editor.js
*/
/* global console */
/* eslint-env es2020 */
if ( 'undefined' === typeof window.wp ) {
/**
* @namespace wp
*/
window.wp = {};
}
if ( 'undefined' === typeof window.wp.codeEditor ) {
/**
* @namespace wp.codeEditor
*/
window.wp.codeEditor = {};
}
/**
* @typedef {object} CodeMirrorState
* @property {boolean} [completionActive] - Whether completion is active.
* @property {boolean} [focused] - Whether the editor is focused.
*/
/**
* @typedef {import('codemirror').EditorFromTextArea & {
* options: import('codemirror').EditorConfiguration,
* performLint?: () => void,
* showHint?: (options: import('codemirror').ShowHintOptions) => void,
* state: CodeMirrorState
* }} CodeMirrorEditor
*/
/**
* @typedef {object} LintAnnotation
* @property {string} message - Message.
* @property {'error'|'warning'} severity - Severity.
* @property {import('codemirror').Position} from - From position.
* @property {import('codemirror').Position} to - To position.
*/
/**
* @typedef {object} CodeMirrorTokenState
* @property {object} [htmlState] - HTML state.
* @property {string} [htmlState.tagName] - Tag name.
* @property {CodeMirrorTokenState} [curState] - Current state.
*/
/**
* @typedef {import('codemirror').EditorConfiguration & {
* lint?: boolean | CombinedLintOptions,
* autoCloseBrackets?: boolean,
* matchBrackets?: boolean,
* continueComments?: boolean,
* styleActiveLine?: boolean
* }} CodeMirrorSettings
*/
/**
* @typedef {object} CSSLintRules
* @property {boolean} [errors] - Errors.
* @property {boolean} [box-model] - Box model rules.
* @property {boolean} [display-property-grouping] - Display property grouping rules.
* @property {boolean} [duplicate-properties] - Duplicate properties rules.
* @property {boolean} [known-properties] - Known properties rules.
* @property {boolean} [outline-none] - Outline none rules.
*/
/**
* @typedef {object} JSHintRules
* @property {number} [esversion] - ECMAScript version.
* @property {boolean} [module] - Whether to use modules.
* @property {boolean} [boss] - Whether to allow assignments in control expressions.
* @property {boolean} [curly] - Whether to require curly braces.
* @property {boolean} [eqeqeq] - Whether to require === and !==.
* @property {boolean} [eqnull] - Whether to allow == null.
* @property {boolean} [expr] - Whether to allow expressions.
* @property {boolean} [immed] - Whether to require immediate function invocation.
* @property {boolean} [noarg] - Whether to prohibit arguments.caller/callee.
* @property {boolean} [nonbsp] - Whether to prohibit non-breaking spaces.
* @property {string} [quotmark] - Quote mark preference.
* @property {boolean} [undef] - Whether to prohibit undefined variables.
* @property {boolean} [unused] - Whether to prohibit unused variables.
* @property {boolean} [browser] - Whether to enable browser globals.
* @property {Record} [globals] - Global variables.
*/
/**
* @typedef {object} HTMLHintRules
* @property {boolean} [tagname-lowercase] - Tag name lowercase rules.
* @property {boolean} [attr-lowercase] - Attribute lowercase rules.
* @property {boolean} [attr-value-double-quotes] - Attribute value double quotes rules.
* @property {boolean} [doctype-first] - Doctype first rules.
* @property {boolean} [tag-pair] - Tag pair rules.
* @property {boolean} [spec-char-escape] - Spec char escape rules.
* @property {boolean} [id-unique] - ID unique rules.
* @property {boolean} [src-not-empty] - Src not empty rules.
* @property {boolean} [attr-no-duplication] - Attribute no duplication rules.
* @property {boolean} [alt-require] - Alt require rules.
* @property {string} [space-tab-mixed-disabled] - Space tab mixed disabled rules.
* @property {boolean} [attr-unsafe-chars] - Attribute unsafe chars rules.
* @property {JSHintRules} [jshint] - JSHint rules.
* @property {CSSLintRules} [csslint] - CSSLint rules.
*/
/**
* Settings for the code editor.
*
* @typedef {object} CodeEditorSettings
*
* @property {CodeMirrorSettings} [codemirror] - CodeMirror settings.
* @property {CSSLintRules} [csslint] - CSSLint rules.
* @property {JSHintRules} [jshint] - JSHint rules.
* @property {HTMLHintRules} [htmlhint] - HTMLHint rules.
*
* @property {(codemirror: CodeMirrorEditor, event: KeyboardEvent|JQuery.KeyDownEvent) => void} [onTabNext] - Callback to handle tabbing to the next tabbable element.
* @property {(codemirror: CodeMirrorEditor, event: KeyboardEvent|JQuery.KeyDownEvent) => void} [onTabPrevious] - Callback to handle tabbing to the previous tabbable element.
* @property {(errorAnnotations: LintAnnotation[], annotations: LintAnnotation[], annotationsSorted: LintAnnotation[], cm: CodeMirrorEditor) => void} [onChangeLintingErrors] - Callback for when the linting errors have changed.
* @property {(errorAnnotations: LintAnnotation[], editor: CodeMirrorEditor) => void} [onUpdateErrorNotice] - Callback for when error notice should be displayed.
*/
/**
* @typedef {import('codemirror/addon/lint/lint').LintStateOptions> & JSHintRules & CSSLintRules & { rules?: HTMLHintRules }} CombinedLintOptions
*/
/**
* @typedef {object} CodeEditorInstance
* @property {CodeEditorSettings} settings - The code editor settings.
* @property {CodeMirrorEditor} codemirror - The CodeMirror instance.
* @property {() => void} updateErrorNotice - Force update the error notice.
*/
/**
* @typedef {object} WpCodeEditor
* @property {CodeEditorSettings} defaultSettings - Default settings.
* @property {(textarea: string|JQuery|Element, settings?: CodeEditorSettings) => CodeEditorInstance} initialize - Initialize.
*/
/**
* @param {JQueryStatic} $ - jQuery.
* @param {Object & {
* codeEditor: WpCodeEditor,
* CodeMirror: typeof import('codemirror'),
* }} wp - WordPress namespace.
*/
( function( $, wp ) {
'use strict';
/**
* Default settings for code editor.
*
* @since 4.9.0
* @type {CodeEditorSettings}
*/
wp.codeEditor.defaultSettings = {
codemirror: {},
csslint: {},
htmlhint: {},
jshint: {},
onTabNext: function() {},
onTabPrevious: function() {},
onChangeLintingErrors: function() {},
onUpdateErrorNotice: function() {},
};
/**
* Configure linting.
*
* @param {CodeEditorSettings} settings - Code editor settings.
*
* @return {LintingController} Linting controller.
*/
function configureLinting( settings ) { // eslint-disable-line complexity
/** @type {LintAnnotation[]} */
let currentErrorAnnotations = [];
/** @type {LintAnnotation[]} */
let previouslyShownErrorAnnotations = [];
/**
* Call the onUpdateErrorNotice if there are new errors to show.
*
* @param {import('codemirror').Editor} editor - Editor.
* @return {void}
*/
function updateErrorNotice( editor ) {
if ( settings.onUpdateErrorNotice && ! _.isEqual( currentErrorAnnotations, previouslyShownErrorAnnotations ) ) {
settings.onUpdateErrorNotice( currentErrorAnnotations, /** @type {CodeMirrorEditor} */ ( editor ) );
previouslyShownErrorAnnotations = currentErrorAnnotations;
}
}
/**
* Get lint options.
*
* @return {CombinedLintOptions|false} Lint options.
*/
function getLintOptions() { // eslint-disable-line complexity
/** @type {CombinedLintOptions | boolean} */
let options = settings.codemirror?.lint ?? false;
if ( ! options ) {
return false;
}
if ( true === options ) {
options = {};
} else if ( _.isObject( options ) ) {
options = $.extend( {}, options );
}
const linterOptions = /** @type {CombinedLintOptions} */ ( options );
// Configure JSHint.
if ( 'javascript' === settings.codemirror?.mode && settings.jshint ) {
$.extend( linterOptions, settings.jshint );
}
// Configure CSSLint.
if ( 'css' === settings.codemirror?.mode && settings.csslint ) {
$.extend( linterOptions, settings.csslint );
}
// Configure HTMLHint.
if ( 'htmlmixed' === settings.codemirror?.mode && settings.htmlhint ) {
linterOptions.rules = $.extend( {}, settings.htmlhint );
if ( settings.jshint && linterOptions.rules ) {
linterOptions.rules.jshint = settings.jshint;
}
if ( settings.csslint && linterOptions.rules ) {
linterOptions.rules.csslint = settings.csslint;
}
}
// Wrap the onUpdateLinting CodeMirror event to route to onChangeLintingErrors and onUpdateErrorNotice.
linterOptions.onUpdateLinting = (function( onUpdateLintingOverridden ) {
/**
* @param {LintAnnotation[]} annotations - Annotations.
* @param {LintAnnotation[]} annotationsSorted - Sorted annotations.
* @param {CodeMirrorEditor} cm - Editor.
*/
return function( annotations, annotationsSorted, cm ) {
const errorAnnotations = annotations.filter( function( annotation ) {
return 'error' === annotation.severity;
} );
if ( onUpdateLintingOverridden ) {
onUpdateLintingOverridden( 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 ( ! cm.state.focused || 0 === currentErrorAnnotations.length || previouslyShownErrorAnnotations.length > 0 ) {
updateErrorNotice( cm );
}
};
})( linterOptions.onUpdateLinting );
return linterOptions;
}
return {
getLintOptions,
/**
* @param {CodeMirrorEditor} editor - Editor instance.
* @return {void}
*/
init: function( editor ) {
// Keep lint options populated.
editor.on( 'optionChange', function( _cm, option ) {
const gutterName = 'CodeMirror-lint-markers';
if ( 'lint' !== ( /** @type {string} */ ( option ) ) ) {
return;
}
const gutters = ( /** @type {string[]} */ ( editor.getOption( 'gutters' ) ) ) || [];
const 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 ) {
editor.performLint();
} else {
currentErrorAnnotations = [];
updateErrorNotice( editor );
}
} );
// 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() {
const editorRefocusWait = 500;
editor.on( 'blur', updateErrorNotice );
// Wait for editor to possibly get re-focused after selection.
_.delay( function() {
if ( ! editor.state.focused ) {
updateErrorNotice( editor );
}
}, 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( /** @type {JQuery.MouseDownEvent} */ event ) {
if (
editor.state.focused &&
! editor.getWrapperElement().contains( event.target ) &&
! event.target.classList.contains( 'CodeMirror-hint' )
) {
updateErrorNotice( editor );
}
} );
},
/**
* @param {CodeMirrorEditor} editor - Editor instance.
* @return {void}
*/
updateErrorNotice,
};
}
/**
* Configure tabbing.
*
* @param {CodeMirrorEditor} codemirror - Editor.
* @param {CodeEditorSettings} settings - Code editor settings.
*
* @return {void}
*/
function configureTabbing( codemirror, settings ) {
const $textarea = $( codemirror.getTextArea() );
codemirror.on( 'blur', function() {
$textarea.data( 'next-tab-blurs', false );
});
codemirror.on( 'keydown', function onKeydown( _editor, event ) {
// Take note of the ESC keypress so that the next TAB can focus outside the editor.
if ( 'Escape' === event.key ) {
$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 ( 'Tab' !== event.key || ! $textarea.data( 'next-tab-blurs' ) ) {
return;
}
// Focus on previous or next focusable item.
if ( event.shiftKey && settings.onTabPrevious ) {
settings.onTabPrevious( codemirror, event );
} else if ( ! event.shiftKey && settings.onTabNext ) {
settings.onTabNext( codemirror, event );
}
// Reset tab state.
$textarea.data( 'next-tab-blurs', false );
// Prevent tab character from being added.
event.preventDefault();
});
}
/**
* @typedef {object} LintingController
* @property {() => CombinedLintOptions|false} getLintOptions - Get lint options.
* @property {(editor: CodeMirrorEditor) => void} init - Initialize.
* @property {(editor: import('codemirror').Editor) => void} updateErrorNotice - Update error notice.
*/
/**
* Initialize Code Editor (CodeMirror) for an existing textarea.
*
* @since 4.9.0
*
* @param {string|JQuery|HTMLElement} textarea - The HTML id, jQuery object, or DOM Element for the textarea that is used for the editor.
* @param {CodeEditorSettings} [settings] - Settings to override defaults.
*
* @return {CodeEditorInstance} Instance.
*/
wp.codeEditor.initialize = function initialize( textarea, settings ) {
if ( document.readyState === 'loading' ) {
console.warn( 'wp.codeEditor.initialize() ran too early. Invoke this function in a `DOMContentLoaded` event listener.' );
}
let $textarea;
if ( 'string' === typeof textarea ) {
$textarea = $( '#' + textarea );
} else {
$textarea = $( textarea );
}
/** @type {CodeEditorSettings} */
const instanceSettings = $.extend( true, {}, wp.codeEditor.defaultSettings, settings );
const lintingController = configureLinting( instanceSettings );
if ( instanceSettings.codemirror ) {
instanceSettings.codemirror.lint = lintingController.getLintOptions();
}
const codemirror = /** @type {CodeMirrorEditor} */ ( wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror ) );
lintingController.init( codemirror );
/** @type {CodeEditorInstance} */
const instance = {
settings: instanceSettings,
codemirror,
updateErrorNotice: function() {
lintingController.updateErrorNotice( codemirror );
},
};
if ( codemirror.showHint ) {
codemirror.on( 'inputRead', function( _editor, change ) {
// Only trigger autocompletion for typed input or IME composition.
if ( ! change.origin || ( '+input' !== change.origin && ! change.origin.startsWith( '*compose' ) ) ) {
return;
}
// Only trigger autocompletion for single-character inputs.
// The text property is an array of strings, one for each line.
// We check that there is only one line and that line has only one character.
if ( 1 !== change.text.length || 1 !== change.text[0].length ) {
return;
}
const char = change.text[0];
const isAlphaKey = /^[a-zA-Z]$/.test( char );
if ( codemirror.state.completionActive && isAlphaKey ) {
return;
}
// Prevent autocompletion in string literals or comments.
const token = /** @type {import('codemirror').Token & { state: CodeMirrorTokenState }} */ ( codemirror.getTokenAt( codemirror.getCursor() ) );
if ( 'string' === token.type || 'comment' === token.type ) {
return;
}
const innerMode = wp.CodeMirror.innerMode( codemirror.getMode(), token.state ).mode.name;
const doc = codemirror.getDoc();
const lineBeforeCursor = doc.getLine( doc.getCursor().line ).slice( 0, doc.getCursor().ch );
let shouldAutocomplete = false;
if ( 'html' === innerMode || 'xml' === innerMode ) {
shouldAutocomplete = (
'<' === char ||
( '/' === char && 'tag' === token.type ) ||
( isAlphaKey && 'tag' === token.type ) ||
( isAlphaKey && 'attribute' === token.type ) ||
( '=' === char && !! (
token.state.htmlState?.tagName ||
token.state.curState?.htmlState?.tagName
) )
);
} else if ( 'css' === innerMode ) {
shouldAutocomplete =
isAlphaKey ||
':' === char ||
( ' ' === char && /:\s+$/.test( lineBeforeCursor ) );
} else if ( 'javascript' === innerMode ) {
shouldAutocomplete = isAlphaKey || '.' === char;
} else if ( 'clike' === innerMode && 'php' === codemirror.options.mode ) {
shouldAutocomplete = isAlphaKey && ( 'keyword' === token.type || 'variable' === token.type );
}
if ( shouldAutocomplete ) {
codemirror.showHint( { completeSingle: false } );
}
} );
}
// Facilitate tabbing out of the editor.
configureTabbing( codemirror, instanceSettings );
return instance;
};
})( jQuery, window.wp );
PK 2>\DY
code-editor.min.jsnu ȯ /*! This file is auto-generated */
void 0===window.wp&&(window.wp={}),void 0===window.wp.codeEditor&&(window.wp.codeEditor={}),function(u,c){"use strict";function d(r){let s=[],a=[];function c(t){r.onUpdateErrorNotice&&!_.isEqual(s,a)&&(r.onUpdateErrorNotice(s,t),a=s)}function d(){let t=r.codemirror?.lint??!1;if(!t)return!1;!0===t?t={}:_.isObject(t)&&(t=u.extend({},t));var i,e=t;return"javascript"===r.codemirror?.mode&&r.jshint&&u.extend(e,r.jshint),"css"===r.codemirror?.mode&&r.csslint&&u.extend(e,r.csslint),"htmlmixed"===r.codemirror?.mode&&r.htmlhint&&(e.rules=u.extend({},r.htmlhint),r.jshint&&e.rules&&(e.rules.jshint=r.jshint),r.csslint)&&e.rules&&(e.rules.csslint=r.csslint),e.onUpdateLinting=(i=e.onUpdateLinting,function(t,e,n){var o=t.filter(function(t){return"error"===t.severity});i&&i(t,e,n),!_.isEqual(o,s)&&(s=o,r.onChangeLintingErrors&&r.onChangeLintingErrors(o,t,e,n),!n.state.focused||0===s.length||0