|
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417 |
- /**
- * Functions for ajaxified updates, deletions and installs inside the WordPress admin.
- *
- * @version 4.2.0
- *
- * @package WordPress
- * @subpackage Administration
- */
-
- /* global pagenow */
-
- /**
- * @param {jQuery} $ jQuery object.
- * @param {object} wp WP object.
- * @param {object} settings WP Updates settings.
- * @param {string} settings.ajax_nonce AJAX nonce.
- * @param {object} settings.l10n Translation strings.
- * @param {object=} settings.plugins Base names of plugins in their different states.
- * @param {Array} settings.plugins.all Base names of all plugins.
- * @param {Array} settings.plugins.active Base names of active plugins.
- * @param {Array} settings.plugins.inactive Base names of inactive plugins.
- * @param {Array} settings.plugins.upgrade Base names of plugins with updates available.
- * @param {Array} settings.plugins.recently_activated Base names of recently activated plugins.
- * @param {object=} settings.themes Plugin/theme status information or null.
- * @param {number} settings.themes.all Amount of all themes.
- * @param {number} settings.themes.upgrade Amount of themes with updates available.
- * @param {number} settings.themes.disabled Amount of disabled themes.
- * @param {object=} settings.totals Combined information for available update counts.
- * @param {number} settings.totals.count Holds the amount of available updates.
- */
- (function( $, wp, settings ) {
- var $document = $( document );
-
- wp = wp || {};
-
- /**
- * The WP Updates object.
- *
- * @since 4.2.0
- *
- * @type {object}
- */
- wp.updates = {};
-
- /**
- * User nonce for ajax calls.
- *
- * @since 4.2.0
- *
- * @type {string}
- */
- wp.updates.ajaxNonce = settings.ajax_nonce;
-
- /**
- * Localized strings.
- *
- * @since 4.2.0
- *
- * @type {object}
- */
- wp.updates.l10n = settings.l10n;
-
- /**
- * Current search term.
- *
- * @since 4.6.0
- *
- * @type {string}
- */
- wp.updates.searchTerm = '';
-
- /**
- * Whether filesystem credentials need to be requested from the user.
- *
- * @since 4.2.0
- *
- * @type {bool}
- */
- wp.updates.shouldRequestFilesystemCredentials = false;
-
- /**
- * Filesystem credentials to be packaged along with the request.
- *
- * @since 4.2.0
- * @since 4.6.0 Added `available` property to indicate whether credentials have been provided.
- *
- * @type {object} filesystemCredentials Holds filesystem credentials.
- * @type {object} filesystemCredentials.ftp Holds FTP credentials.
- * @type {string} filesystemCredentials.ftp.host FTP host. Default empty string.
- * @type {string} filesystemCredentials.ftp.username FTP user name. Default empty string.
- * @type {string} filesystemCredentials.ftp.password FTP password. Default empty string.
- * @type {string} filesystemCredentials.ftp.connectionType Type of FTP connection. 'ssh', 'ftp', or 'ftps'.
- * Default empty string.
- * @type {object} filesystemCredentials.ssh Holds SSH credentials.
- * @type {string} filesystemCredentials.ssh.publicKey The public key. Default empty string.
- * @type {string} filesystemCredentials.ssh.privateKey The private key. Default empty string.
- * @type {bool} filesystemCredentials.available Whether filesystem credentials have been provided.
- * Default 'false'.
- */
- wp.updates.filesystemCredentials = {
- ftp: {
- host: '',
- username: '',
- password: '',
- connectionType: ''
- },
- ssh: {
- publicKey: '',
- privateKey: ''
- },
- available: false
- };
-
- /**
- * Whether we're waiting for an Ajax request to complete.
- *
- * @since 4.2.0
- * @since 4.6.0 More accurately named `ajaxLocked`.
- *
- * @type {bool}
- */
- wp.updates.ajaxLocked = false;
-
- /**
- * Admin notice template.
- *
- * @since 4.6.0
- *
- * @type {function} A function that lazily-compiles the template requested.
- */
- wp.updates.adminNotice = wp.template( 'wp-updates-admin-notice' );
-
- /**
- * Update queue.
- *
- * If the user tries to update a plugin while an update is
- * already happening, it can be placed in this queue to perform later.
- *
- * @since 4.2.0
- * @since 4.6.0 More accurately named `queue`.
- *
- * @type {Array.object}
- */
- wp.updates.queue = [];
-
- /**
- * Holds a jQuery reference to return focus to when exiting the request credentials modal.
- *
- * @since 4.2.0
- *
- * @type {jQuery}
- */
- wp.updates.$elToReturnFocusToFromCredentialsModal = undefined;
-
- /**
- * Adds or updates an admin notice.
- *
- * @since 4.6.0
- *
- * @param {object} data
- * @param {*=} data.selector Optional. Selector of an element to be replaced with the admin notice.
- * @param {string=} data.id Optional. Unique id that will be used as the notice's id attribute.
- * @param {string=} data.className Optional. Class names that will be used in the admin notice.
- * @param {string=} data.message Optional. The message displayed in the notice.
- * @param {number=} data.successes Optional. The amount of successful operations.
- * @param {number=} data.errors Optional. The amount of failed operations.
- * @param {Array=} data.errorMessages Optional. Error messages of failed operations.
- *
- */
- wp.updates.addAdminNotice = function( data ) {
- var $notice = $( data.selector ), $adminNotice;
-
- delete data.selector;
- $adminNotice = wp.updates.adminNotice( data );
-
- // Check if this admin notice already exists.
- if ( ! $notice.length ) {
- $notice = $( '#' + data.id );
- }
-
- if ( $notice.length ) {
- $notice.replaceWith( $adminNotice );
- } else {
- $( '.wrap' ).find( '> h1' ).after( $adminNotice );
- }
-
- $document.trigger( 'wp-updates-notice-added' );
- };
-
- /**
- * Handles Ajax requests to WordPress.
- *
- * @since 4.6.0
- *
- * @param {string} action The type of Ajax request ('update-plugin', 'install-theme', etc).
- * @param {object} data Data that needs to be passed to the ajax callback.
- * @return {$.promise} A jQuery promise that represents the request,
- * decorated with an abort() method.
- */
- wp.updates.ajax = function( action, data ) {
- var options = {};
-
- if ( wp.updates.ajaxLocked ) {
- wp.updates.queue.push( {
- action: action,
- data: data
- } );
-
- // Return a Deferred object so callbacks can always be registered.
- return $.Deferred();
- }
-
- wp.updates.ajaxLocked = true;
-
- if ( data.success ) {
- options.success = data.success;
- delete data.success;
- }
-
- if ( data.error ) {
- options.error = data.error;
- delete data.error;
- }
-
- options.data = _.extend( data, {
- action: action,
- _ajax_nonce: wp.updates.ajaxNonce,
- username: wp.updates.filesystemCredentials.ftp.username,
- password: wp.updates.filesystemCredentials.ftp.password,
- hostname: wp.updates.filesystemCredentials.ftp.hostname,
- connection_type: wp.updates.filesystemCredentials.ftp.connectionType,
- public_key: wp.updates.filesystemCredentials.ssh.publicKey,
- private_key: wp.updates.filesystemCredentials.ssh.privateKey
- } );
-
- return wp.ajax.send( options ).always( wp.updates.ajaxAlways );
- };
-
- /**
- * Actions performed after every Ajax request.
- *
- * @since 4.6.0
- *
- * @param {object} response
- * @param {array=} response.debug Optional. Debug information.
- * @param {string=} response.errorCode Optional. Error code for an error that occurred.
- */
- wp.updates.ajaxAlways = function( response ) {
- if ( ! response.errorCode || 'unable_to_connect_to_filesystem' !== response.errorCode ) {
- wp.updates.ajaxLocked = false;
- wp.updates.queueChecker();
- }
-
- if ( 'undefined' !== typeof response.debug && window.console && window.console.log ) {
- _.map( response.debug, function( message ) {
- window.console.log( $( '<p />' ).html( message ).text() );
- } );
- }
- };
-
- /**
- * Refreshes update counts everywhere on the screen.
- *
- * @since 4.7.0
- */
- wp.updates.refreshCount = function() {
- var $adminBarUpdates = $( '#wp-admin-bar-updates' ),
- $dashboardNavMenuUpdateCount = $( 'a[href="update-core.php"] .update-plugins' ),
- $pluginsNavMenuUpdateCount = $( 'a[href="plugins.php"] .update-plugins' ),
- $appearanceNavMenuUpdateCount = $( 'a[href="themes.php"] .update-plugins' ),
- itemCount;
-
- $adminBarUpdates.find( '.ab-item' ).removeAttr( 'title' );
- $adminBarUpdates.find( '.ab-label' ).text( settings.totals.counts.total );
-
- // Remove the update count from the toolbar if it's zero.
- if ( 0 === settings.totals.counts.total ) {
- $adminBarUpdates.find( '.ab-label' ).parents( 'li' ).remove();
- }
-
- // Update the "Updates" menu item.
- $dashboardNavMenuUpdateCount.each( function( index, element ) {
- element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.total );
- } );
- if ( settings.totals.counts.total > 0 ) {
- $dashboardNavMenuUpdateCount.find( '.update-count' ).text( settings.totals.counts.total );
- } else {
- $dashboardNavMenuUpdateCount.remove();
- }
-
- // Update the "Plugins" menu item.
- $pluginsNavMenuUpdateCount.each( function( index, element ) {
- element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.plugins );
- } );
- if ( settings.totals.counts.total > 0 ) {
- $pluginsNavMenuUpdateCount.find( '.plugin-count' ).text( settings.totals.counts.plugins );
- } else {
- $pluginsNavMenuUpdateCount.remove();
- }
-
- // Update the "Appearance" menu item.
- $appearanceNavMenuUpdateCount.each( function( index, element ) {
- element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.themes );
- } );
- if ( settings.totals.counts.total > 0 ) {
- $appearanceNavMenuUpdateCount.find( '.theme-count' ).text( settings.totals.counts.themes );
- } else {
- $appearanceNavMenuUpdateCount.remove();
- }
-
- // Update list table filter navigation.
- if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
- itemCount = settings.totals.counts.plugins;
- } else if ( 'themes' === pagenow || 'themes-network' === pagenow ) {
- itemCount = settings.totals.counts.themes;
- }
-
- if ( itemCount > 0 ) {
- $( '.subsubsub .upgrade .count' ).text( '(' + itemCount + ')' );
- } else {
- $( '.subsubsub .upgrade' ).remove();
- }
- };
-
- /**
- * Decrements the update counts throughout the various menus.
- *
- * This includes the toolbar, the "Updates" menu item and the menu items
- * for plugins and themes.
- *
- * @since 3.9.0
- *
- * @param {string} type The type of item that was updated or deleted.
- * Can be 'plugin', 'theme'.
- */
- wp.updates.decrementCount = function( type ) {
- settings.totals.counts.total = Math.max( --settings.totals.counts.total, 0 );
-
- if ( 'plugin' === type ) {
- settings.totals.counts.plugins = Math.max( --settings.totals.counts.plugins, 0 );
- } else if ( 'theme' === type ) {
- settings.totals.counts.themes = Math.max( --settings.totals.counts.themes, 0 );
- }
-
- wp.updates.refreshCount( type );
- };
-
- /**
- * Sends an Ajax request to the server to update a plugin.
- *
- * @since 4.2.0
- * @since 4.6.0 More accurately named `updatePlugin`.
- *
- * @param {object} args Arguments.
- * @param {string} args.plugin Plugin basename.
- * @param {string} args.slug Plugin slug.
- * @param {updatePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.updatePluginSuccess
- * @param {updatePluginError=} args.error Optional. Error callback. Default: wp.updates.updatePluginError
- * @return {$.promise} A jQuery promise that represents the request,
- * decorated with an abort() method.
- */
- wp.updates.updatePlugin = function( args ) {
- var $updateRow, $card, $message, message;
-
- args = _.extend( {
- success: wp.updates.updatePluginSuccess,
- error: wp.updates.updatePluginError
- }, args );
-
- if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
- $updateRow = $( 'tr[data-plugin="' + args.plugin + '"]' );
- $message = $updateRow.find( '.update-message' ).removeClass( 'notice-error' ).addClass( 'updating-message notice-warning' ).find( 'p' );
- message = wp.updates.l10n.updatingLabel.replace( '%s', $updateRow.find( '.plugin-title strong' ).text() );
- } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
- $card = $( '.plugin-card-' + args.slug );
- $message = $card.find( '.update-now' ).addClass( 'updating-message' );
- message = wp.updates.l10n.updatingLabel.replace( '%s', $message.data( 'name' ) );
-
- // Remove previous error messages, if any.
- $card.removeClass( 'plugin-card-update-failed' ).find( '.notice.notice-error' ).remove();
- }
-
- if ( $message.html() !== wp.updates.l10n.updating ) {
- $message.data( 'originaltext', $message.html() );
- }
-
- $message
- .attr( 'aria-label', message )
- .text( wp.updates.l10n.updating );
-
- $document.trigger( 'wp-plugin-updating', args );
-
- return wp.updates.ajax( 'update-plugin', args );
- };
-
- /**
- * Updates the UI appropriately after a successful plugin update.
- *
- * @since 4.2.0
- * @since 4.6.0 More accurately named `updatePluginSuccess`.
- *
- * @typedef {object} updatePluginSuccess
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the plugin to be updated.
- * @param {string} response.plugin Basename of the plugin to be updated.
- * @param {string} response.pluginName Name of the plugin to be updated.
- * @param {string} response.oldVersion Old version of the plugin.
- * @param {string} response.newVersion New version of the plugin.
- */
- wp.updates.updatePluginSuccess = function( response ) {
- var $pluginRow, $updateMessage, newText;
-
- if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
- $pluginRow = $( 'tr[data-plugin="' + response.plugin + '"]' )
- .removeClass( 'update' )
- .addClass( 'updated' );
- $updateMessage = $pluginRow.find( '.update-message' )
- .removeClass( 'updating-message notice-warning' )
- .addClass( 'updated-message notice-success' ).find( 'p' );
-
- // Update the version number in the row.
- newText = $pluginRow.find( '.plugin-version-author-uri' ).html().replace( response.oldVersion, response.newVersion );
- $pluginRow.find( '.plugin-version-author-uri' ).html( newText );
- } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
- $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' )
- .removeClass( 'updating-message' )
- .addClass( 'button-disabled updated-message' );
- }
-
- $updateMessage
- .attr( 'aria-label', wp.updates.l10n.updatedLabel.replace( '%s', response.pluginName ) )
- .text( wp.updates.l10n.updated );
-
- wp.a11y.speak( wp.updates.l10n.updatedMsg, 'polite' );
-
- wp.updates.decrementCount( 'plugin' );
-
- $document.trigger( 'wp-plugin-update-success', response );
- };
-
- /**
- * Updates the UI appropriately after a failed plugin update.
- *
- * @since 4.2.0
- * @since 4.6.0 More accurately named `updatePluginError`.
- *
- * @typedef {object} updatePluginError
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the plugin to be updated.
- * @param {string} response.plugin Basename of the plugin to be updated.
- * @param {string=} response.pluginName Optional. Name of the plugin to be updated.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- */
- wp.updates.updatePluginError = function( response ) {
- var $card, $message, errorMessage;
-
- if ( ! wp.updates.isValidResponse( response, 'update' ) ) {
- return;
- }
-
- if ( wp.updates.maybeHandleCredentialError( response, 'update-plugin' ) ) {
- return;
- }
-
- errorMessage = wp.updates.l10n.updateFailed.replace( '%s', response.errorMessage );
-
- if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
- if ( response.plugin ) {
- $message = $( 'tr[data-plugin="' + response.plugin + '"]' ).find( '.update-message' );
- } else {
- $message = $( 'tr[data-slug="' + response.slug + '"]' ).find( '.update-message' );
- }
- $message.removeClass( 'updating-message notice-warning' ).addClass( 'notice-error' ).find( 'p' ).html( errorMessage );
-
- if ( response.pluginName ) {
- $message.find( 'p' )
- .attr( 'aria-label', wp.updates.l10n.updateFailedLabel.replace( '%s', response.pluginName ) );
- } else {
- $message.find( 'p' ).removeAttr( 'aria-label' );
- }
- } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
- $card = $( '.plugin-card-' + response.slug )
- .addClass( 'plugin-card-update-failed' )
- .append( wp.updates.adminNotice( {
- className: 'update-message notice-error notice-alt is-dismissible',
- message: errorMessage
- } ) );
-
- $card.find( '.update-now' )
- .text( wp.updates.l10n.updateFailedShort ).removeClass( 'updating-message' );
-
- if ( response.pluginName ) {
- $card.find( '.update-now' )
- .attr( 'aria-label', wp.updates.l10n.updateFailedLabel.replace( '%s', response.pluginName ) );
- } else {
- $card.find( '.update-now' ).removeAttr( 'aria-label' );
- }
-
- $card.on( 'click', '.notice.is-dismissible .notice-dismiss', function() {
-
- // Use same delay as the total duration of the notice fadeTo + slideUp animation.
- setTimeout( function() {
- $card
- .removeClass( 'plugin-card-update-failed' )
- .find( '.column-name a' ).focus();
-
- $card.find( '.update-now' )
- .attr( 'aria-label', false )
- .text( wp.updates.l10n.updateNow );
- }, 200 );
- } );
- }
-
- wp.a11y.speak( errorMessage, 'assertive' );
-
- $document.trigger( 'wp-plugin-update-error', response );
- };
-
- /**
- * Sends an Ajax request to the server to install a plugin.
- *
- * @since 4.6.0
- *
- * @param {object} args Arguments.
- * @param {string} args.slug Plugin identifier in the WordPress.org Plugin repository.
- * @param {installPluginSuccess=} args.success Optional. Success callback. Default: wp.updates.installPluginSuccess
- * @param {installPluginError=} args.error Optional. Error callback. Default: wp.updates.installPluginError
- * @return {$.promise} A jQuery promise that represents the request,
- * decorated with an abort() method.
- */
- wp.updates.installPlugin = function( args ) {
- var $card = $( '.plugin-card-' + args.slug ),
- $message = $card.find( '.install-now' );
-
- args = _.extend( {
- success: wp.updates.installPluginSuccess,
- error: wp.updates.installPluginError
- }, args );
-
- if ( 'import' === pagenow ) {
- $message = $( '[data-slug="' + args.slug + '"]' );
- }
-
- if ( $message.html() !== wp.updates.l10n.installing ) {
- $message.data( 'originaltext', $message.html() );
- }
-
- $message
- .addClass( 'updating-message' )
- .attr( 'aria-label', wp.updates.l10n.pluginInstallingLabel.replace( '%s', $message.data( 'name' ) ) )
- .text( wp.updates.l10n.installing );
-
- wp.a11y.speak( wp.updates.l10n.installingMsg, 'polite' );
-
- // Remove previous error messages, if any.
- $card.removeClass( 'plugin-card-install-failed' ).find( '.notice.notice-error' ).remove();
-
- $document.trigger( 'wp-plugin-installing', args );
-
- return wp.updates.ajax( 'install-plugin', args );
- };
-
- /**
- * Updates the UI appropriately after a successful plugin install.
- *
- * @since 4.6.0
- *
- * @typedef {object} installPluginSuccess
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the installed plugin.
- * @param {string} response.pluginName Name of the installed plugin.
- * @param {string} response.activateUrl URL to activate the just installed plugin.
- */
- wp.updates.installPluginSuccess = function( response ) {
- var $message = $( '.plugin-card-' + response.slug ).find( '.install-now' );
-
- $message
- .removeClass( 'updating-message' )
- .addClass( 'updated-message installed button-disabled' )
- .attr( 'aria-label', wp.updates.l10n.pluginInstalledLabel.replace( '%s', response.pluginName ) )
- .text( wp.updates.l10n.installed );
-
- wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' );
-
- $document.trigger( 'wp-plugin-install-success', response );
-
- if ( response.activateUrl ) {
- setTimeout( function() {
-
- // Transform the 'Install' button into an 'Activate' button.
- $message.removeClass( 'install-now installed button-disabled updated-message' ).addClass( 'activate-now button-primary' )
- .attr( 'href', response.activateUrl )
- .attr( 'aria-label', wp.updates.l10n.activatePluginLabel.replace( '%s', response.pluginName ) )
- .text( wp.updates.l10n.activatePlugin );
- }, 1000 );
- }
- };
-
- /**
- * Updates the UI appropriately after a failed plugin install.
- *
- * @since 4.6.0
- *
- * @typedef {object} installPluginError
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the plugin to be installed.
- * @param {string=} response.pluginName Optional. Name of the plugin to be installed.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- */
- wp.updates.installPluginError = function( response ) {
- var $card = $( '.plugin-card-' + response.slug ),
- $button = $card.find( '.install-now' ),
- errorMessage;
-
- if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
- return;
- }
-
- if ( wp.updates.maybeHandleCredentialError( response, 'install-plugin' ) ) {
- return;
- }
-
- errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage );
-
- $card
- .addClass( 'plugin-card-update-failed' )
- .append( '<div class="notice notice-error notice-alt is-dismissible"><p>' + errorMessage + '</p></div>' );
-
- $card.on( 'click', '.notice.is-dismissible .notice-dismiss', function() {
-
- // Use same delay as the total duration of the notice fadeTo + slideUp animation.
- setTimeout( function() {
- $card
- .removeClass( 'plugin-card-update-failed' )
- .find( '.column-name a' ).focus();
- }, 200 );
- } );
-
- $button
- .removeClass( 'updating-message' ).addClass( 'button-disabled' )
- .attr( 'aria-label', wp.updates.l10n.pluginInstallFailedLabel.replace( '%s', $button.data( 'name' ) ) )
- .text( wp.updates.l10n.installFailedShort );
-
- wp.a11y.speak( errorMessage, 'assertive' );
-
- $document.trigger( 'wp-plugin-install-error', response );
- };
-
- /**
- * Updates the UI appropriately after a successful importer install.
- *
- * @since 4.6.0
- *
- * @typedef {object} installImporterSuccess
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the installed plugin.
- * @param {string} response.pluginName Name of the installed plugin.
- * @param {string} response.activateUrl URL to activate the just installed plugin.
- */
- wp.updates.installImporterSuccess = function( response ) {
- wp.updates.addAdminNotice( {
- id: 'install-success',
- className: 'notice-success is-dismissible',
- message: wp.updates.l10n.importerInstalledMsg.replace( '%s', response.activateUrl + '&from=import' )
- } );
-
- $( '[data-slug="' + response.slug + '"]' )
- .removeClass( 'install-now updating-message' )
- .addClass( 'activate-now' )
- .attr({
- 'href': response.activateUrl + '&from=import',
- 'aria-label': wp.updates.l10n.activateImporterLabel.replace( '%s', response.pluginName )
- })
- .text( wp.updates.l10n.activateImporter );
-
- wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' );
-
- $document.trigger( 'wp-importer-install-success', response );
- };
-
- /**
- * Updates the UI appropriately after a failed importer install.
- *
- * @since 4.6.0
- *
- * @typedef {object} installImporterError
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the plugin to be installed.
- * @param {string=} response.pluginName Optional. Name of the plugin to be installed.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- */
- wp.updates.installImporterError = function( response ) {
- var errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ),
- $installLink = $( '[data-slug="' + response.slug + '"]' ),
- pluginName = $installLink.data( 'name' );
-
- if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
- return;
- }
-
- if ( wp.updates.maybeHandleCredentialError( response, 'install-plugin' ) ) {
- return;
- }
-
- wp.updates.addAdminNotice( {
- id: response.errorCode,
- className: 'notice-error is-dismissible',
- message: errorMessage
- } );
-
- $installLink
- .removeClass( 'updating-message' )
- .text( wp.updates.l10n.installNow )
- .attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', pluginName ) );
-
- wp.a11y.speak( errorMessage, 'assertive' );
-
- $document.trigger( 'wp-importer-install-error', response );
- };
-
- /**
- * Sends an Ajax request to the server to delete a plugin.
- *
- * @since 4.6.0
- *
- * @param {object} args Arguments.
- * @param {string} args.plugin Basename of the plugin to be deleted.
- * @param {string} args.slug Slug of the plugin to be deleted.
- * @param {deletePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.deletePluginSuccess
- * @param {deletePluginError=} args.error Optional. Error callback. Default: wp.updates.deletePluginError
- * @return {$.promise} A jQuery promise that represents the request,
- * decorated with an abort() method.
- */
- wp.updates.deletePlugin = function( args ) {
- var $link = $( '[data-plugin="' + args.plugin + '"]' ).find( '.row-actions a.delete' );
-
- args = _.extend( {
- success: wp.updates.deletePluginSuccess,
- error: wp.updates.deletePluginError
- }, args );
-
- if ( $link.html() !== wp.updates.l10n.deleting ) {
- $link
- .data( 'originaltext', $link.html() )
- .text( wp.updates.l10n.deleting );
- }
-
- wp.a11y.speak( wp.updates.l10n.deleting, 'polite' );
-
- $document.trigger( 'wp-plugin-deleting', args );
-
- return wp.updates.ajax( 'delete-plugin', args );
- };
-
- /**
- * Updates the UI appropriately after a successful plugin deletion.
- *
- * @since 4.6.0
- *
- * @typedef {object} deletePluginSuccess
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the plugin that was deleted.
- * @param {string} response.plugin Base name of the plugin that was deleted.
- * @param {string} response.pluginName Name of the plugin that was deleted.
- */
- wp.updates.deletePluginSuccess = function( response ) {
-
- // Removes the plugin and updates rows.
- $( '[data-plugin="' + response.plugin + '"]' ).css( { backgroundColor: '#faafaa' } ).fadeOut( 350, function() {
- var $form = $( '#bulk-action-form' ),
- $views = $( '.subsubsub' ),
- $pluginRow = $( this ),
- columnCount = $form.find( 'thead th:not(.hidden), thead td' ).length,
- pluginDeletedRow = wp.template( 'item-deleted-row' ),
- /** @type {object} plugins Base names of plugins in their different states. */
- plugins = settings.plugins;
-
- // Add a success message after deleting a plugin.
- if ( ! $pluginRow.hasClass( 'plugin-update-tr' ) ) {
- $pluginRow.after(
- pluginDeletedRow( {
- slug: response.slug,
- plugin: response.plugin,
- colspan: columnCount,
- name: response.pluginName
- } )
- );
- }
-
- $pluginRow.remove();
-
- // Remove plugin from update count.
- if ( -1 !== _.indexOf( plugins.upgrade, response.plugin ) ) {
- plugins.upgrade = _.without( plugins.upgrade, response.plugin );
- wp.updates.decrementCount( 'plugin' );
- }
-
- // Remove from views.
- if ( -1 !== _.indexOf( plugins.inactive, response.plugin ) ) {
- plugins.inactive = _.without( plugins.inactive, response.plugin );
- if ( plugins.inactive.length ) {
- $views.find( '.inactive .count' ).text( '(' + plugins.inactive.length + ')' );
- } else {
- $views.find( '.inactive' ).remove();
- }
- }
-
- if ( -1 !== _.indexOf( plugins.active, response.plugin ) ) {
- plugins.active = _.without( plugins.active, response.plugin );
- if ( plugins.active.length ) {
- $views.find( '.active .count' ).text( '(' + plugins.active.length + ')' );
- } else {
- $views.find( '.active' ).remove();
- }
- }
-
- if ( -1 !== _.indexOf( plugins.recently_activated, response.plugin ) ) {
- plugins.recently_activated = _.without( plugins.recently_activated, response.plugin );
- if ( plugins.recently_activated.length ) {
- $views.find( '.recently_activated .count' ).text( '(' + plugins.recently_activated.length + ')' );
- } else {
- $views.find( '.recently_activated' ).remove();
- }
- }
-
- plugins.all = _.without( plugins.all, response.plugin );
-
- if ( plugins.all.length ) {
- $views.find( '.all .count' ).text( '(' + plugins.all.length + ')' );
- } else {
- $form.find( '.tablenav' ).css( { visibility: 'hidden' } );
- $views.find( '.all' ).remove();
-
- if ( ! $form.find( 'tr.no-items' ).length ) {
- $form.find( '#the-list' ).append( '<tr class="no-items"><td class="colspanchange" colspan="' + columnCount + '">' + wp.updates.l10n.noPlugins + '</td></tr>' );
- }
- }
- } );
-
- wp.a11y.speak( wp.updates.l10n.deleted, 'polite' );
-
- $document.trigger( 'wp-plugin-delete-success', response );
- };
-
- /**
- * Updates the UI appropriately after a failed plugin deletion.
- *
- * @since 4.6.0
- *
- * @typedef {object} deletePluginError
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the plugin to be deleted.
- * @param {string} response.plugin Base name of the plugin to be deleted
- * @param {string=} response.pluginName Optional. Name of the plugin to be deleted.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- */
- wp.updates.deletePluginError = function( response ) {
- var $plugin, $pluginUpdateRow,
- pluginUpdateRow = wp.template( 'item-update-row' ),
- noticeContent = wp.updates.adminNotice( {
- className: 'update-message notice-error notice-alt',
- message: response.errorMessage
- } );
-
- if ( response.plugin ) {
- $plugin = $( 'tr.inactive[data-plugin="' + response.plugin + '"]' );
- $pluginUpdateRow = $plugin.siblings( '[data-plugin="' + response.plugin + '"]' );
- } else {
- $plugin = $( 'tr.inactive[data-slug="' + response.slug + '"]' );
- $pluginUpdateRow = $plugin.siblings( '[data-slug="' + response.slug + '"]' );
- }
-
- if ( ! wp.updates.isValidResponse( response, 'delete' ) ) {
- return;
- }
-
- if ( wp.updates.maybeHandleCredentialError( response, 'delete-plugin' ) ) {
- return;
- }
-
- // Add a plugin update row if it doesn't exist yet.
- if ( ! $pluginUpdateRow.length ) {
- $plugin.addClass( 'update' ).after(
- pluginUpdateRow( {
- slug: response.slug,
- plugin: response.plugin || response.slug,
- colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length,
- content: noticeContent
- } )
- );
- } else {
-
- // Remove previous error messages, if any.
- $pluginUpdateRow.find( '.notice-error' ).remove();
-
- $pluginUpdateRow.find( '.plugin-update' ).append( noticeContent );
- }
-
- $document.trigger( 'wp-plugin-delete-error', response );
- };
-
- /**
- * Sends an Ajax request to the server to update a theme.
- *
- * @since 4.6.0
- *
- * @param {object} args Arguments.
- * @param {string} args.slug Theme stylesheet.
- * @param {updateThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.updateThemeSuccess
- * @param {updateThemeError=} args.error Optional. Error callback. Default: wp.updates.updateThemeError
- * @return {$.promise} A jQuery promise that represents the request,
- * decorated with an abort() method.
- */
- wp.updates.updateTheme = function( args ) {
- var $notice;
-
- args = _.extend( {
- success: wp.updates.updateThemeSuccess,
- error: wp.updates.updateThemeError
- }, args );
-
- if ( 'themes-network' === pagenow ) {
- $notice = $( '[data-slug="' + args.slug + '"]' ).find( '.update-message' ).removeClass( 'notice-error' ).addClass( 'updating-message notice-warning' ).find( 'p' );
-
- } else {
- $notice = $( '#update-theme' ).closest( '.notice' ).removeClass( 'notice-large' );
-
- $notice.find( 'h3' ).remove();
-
- $notice = $notice.add( $( '[data-slug="' + args.slug + '"]' ).find( '.update-message' ) );
- $notice = $notice.addClass( 'updating-message' ).find( 'p' );
- }
-
- if ( $notice.html() !== wp.updates.l10n.updating ) {
- $notice.data( 'originaltext', $notice.html() );
- }
-
- wp.a11y.speak( wp.updates.l10n.updatingMsg, 'polite' );
- $notice.text( wp.updates.l10n.updating );
-
- $document.trigger( 'wp-theme-updating', args );
-
- return wp.updates.ajax( 'update-theme', args );
- };
-
- /**
- * Updates the UI appropriately after a successful theme update.
- *
- * @since 4.6.0
- *
- * @typedef {object} updateThemeSuccess
- * @param {object} response
- * @param {string} response.slug Slug of the theme to be updated.
- * @param {object} response.theme Updated theme.
- * @param {string} response.oldVersion Old version of the theme.
- * @param {string} response.newVersion New version of the theme.
- */
- wp.updates.updateThemeSuccess = function( response ) {
- var isModalOpen = $( 'body.modal-open' ).length,
- $theme = $( '[data-slug="' + response.slug + '"]' ),
- updatedMessage = {
- className: 'updated-message notice-success notice-alt',
- message: wp.updates.l10n.updated
- },
- $notice, newText;
-
- if ( 'themes-network' === pagenow ) {
- $notice = $theme.find( '.update-message' );
-
- // Update the version number in the row.
- newText = $theme.find( '.theme-version-author-uri' ).html().replace( response.oldVersion, response.newVersion );
- $theme.find( '.theme-version-author-uri' ).html( newText );
- } else {
- $notice = $( '.theme-info .notice' ).add( $theme.find( '.update-message' ) );
-
- // Focus on Customize button after updating.
- if ( isModalOpen ) {
- $( '.load-customize:visible' ).focus();
- } else {
- $theme.find( '.load-customize' ).focus();
- }
- }
-
- wp.updates.addAdminNotice( _.extend( { selector: $notice }, updatedMessage ) );
- wp.a11y.speak( wp.updates.l10n.updatedMsg, 'polite' );
-
- wp.updates.decrementCount( 'theme' );
-
- $document.trigger( 'wp-theme-update-success', response );
-
- // Show updated message after modal re-rendered.
- if ( isModalOpen ) {
- $( '.theme-info .theme-author' ).after( wp.updates.adminNotice( updatedMessage ) );
- }
- };
-
- /**
- * Updates the UI appropriately after a failed theme update.
- *
- * @since 4.6.0
- *
- * @typedef {object} updateThemeError
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the theme to be updated.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- */
- wp.updates.updateThemeError = function( response ) {
- var $theme = $( '[data-slug="' + response.slug + '"]' ),
- errorMessage = wp.updates.l10n.updateFailed.replace( '%s', response.errorMessage ),
- $notice;
-
- if ( ! wp.updates.isValidResponse( response, 'update' ) ) {
- return;
- }
-
- if ( wp.updates.maybeHandleCredentialError( response, 'update-theme' ) ) {
- return;
- }
-
- if ( 'themes-network' === pagenow ) {
- $notice = $theme.find( '.update-message ' );
- } else {
- $notice = $( '.theme-info .notice' ).add( $theme.find( '.notice' ) );
-
- $( 'body.modal-open' ).length ? $( '.load-customize:visible' ).focus() : $theme.find( '.load-customize' ).focus();
- }
-
- wp.updates.addAdminNotice( {
- selector: $notice,
- className: 'update-message notice-error notice-alt is-dismissible',
- message: errorMessage
- } );
-
- wp.a11y.speak( errorMessage, 'polite' );
-
- $document.trigger( 'wp-theme-update-error', response );
- };
-
- /**
- * Sends an Ajax request to the server to install a theme.
- *
- * @since 4.6.0
- *
- * @param {object} args
- * @param {string} args.slug Theme stylesheet.
- * @param {installThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.installThemeSuccess
- * @param {installThemeError=} args.error Optional. Error callback. Default: wp.updates.installThemeError
- * @return {$.promise} A jQuery promise that represents the request,
- * decorated with an abort() method.
- */
- wp.updates.installTheme = function( args ) {
- var $message = $( '.theme-install[data-slug="' + args.slug + '"]' );
-
- args = _.extend( {
- success: wp.updates.installThemeSuccess,
- error: wp.updates.installThemeError
- }, args );
-
- $message.addClass( 'updating-message' );
- $message.parents( '.theme' ).addClass( 'focus' );
- if ( $message.html() !== wp.updates.l10n.installing ) {
- $message.data( 'originaltext', $message.html() );
- }
-
- $message
- .text( wp.updates.l10n.installing )
- .attr( 'aria-label', wp.updates.l10n.themeInstallingLabel.replace( '%s', $message.data( 'name' ) ) );
- wp.a11y.speak( wp.updates.l10n.installingMsg, 'polite' );
-
- // Remove previous error messages, if any.
- $( '.install-theme-info, [data-slug="' + args.slug + '"]' ).removeClass( 'theme-install-failed' ).find( '.notice.notice-error' ).remove();
-
- $document.trigger( 'wp-theme-installing', args );
-
- return wp.updates.ajax( 'install-theme', args );
- };
-
- /**
- * Updates the UI appropriately after a successful theme install.
- *
- * @since 4.6.0
- *
- * @typedef {object} installThemeSuccess
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the theme to be installed.
- * @param {string} response.customizeUrl URL to the Customizer for the just installed theme.
- * @param {string} response.activateUrl URL to activate the just installed theme.
- */
- wp.updates.installThemeSuccess = function( response ) {
- var $card = $( '.wp-full-overlay-header, [data-slug=' + response.slug + ']' ),
- $message;
-
- $document.trigger( 'wp-theme-install-success', response );
-
- $message = $card.find( '.button-primary' )
- .removeClass( 'updating-message' )
- .addClass( 'updated-message disabled' )
- .attr( 'aria-label', wp.updates.l10n.themeInstalledLabel.replace( '%s', response.themeName ) )
- .text( wp.updates.l10n.installed );
-
- wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' );
-
- setTimeout( function() {
-
- if ( response.activateUrl ) {
-
- // Transform the 'Install' button into an 'Activate' button.
- $message
- .attr( 'href', response.activateUrl )
- .removeClass( 'theme-install updated-message disabled' )
- .addClass( 'activate' )
- .attr( 'aria-label', wp.updates.l10n.activateThemeLabel.replace( '%s', response.themeName ) )
- .text( wp.updates.l10n.activateTheme );
- }
-
- if ( response.customizeUrl ) {
-
- // Transform the 'Preview' button into a 'Live Preview' button.
- $message.siblings( '.preview' ).replaceWith( function () {
- return $( '<a>' )
- .attr( 'href', response.customizeUrl )
- .addClass( 'button load-customize' )
- .text( wp.updates.l10n.livePreview );
- } );
- }
- }, 1000 );
- };
-
- /**
- * Updates the UI appropriately after a failed theme install.
- *
- * @since 4.6.0
- *
- * @typedef {object} installThemeError
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the theme to be installed.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- */
- wp.updates.installThemeError = function( response ) {
- var $card, $button,
- errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ),
- $message = wp.updates.adminNotice( {
- className: 'update-message notice-error notice-alt',
- message: errorMessage
- } );
-
- if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
- return;
- }
-
- if ( wp.updates.maybeHandleCredentialError( response, 'install-theme' ) ) {
- return;
- }
-
- if ( $document.find( 'body' ).hasClass( 'full-overlay-active' ) ) {
- $button = $( '.theme-install[data-slug="' + response.slug + '"]' );
- $card = $( '.install-theme-info' ).prepend( $message );
- } else {
- $card = $( '[data-slug="' + response.slug + '"]' ).removeClass( 'focus' ).addClass( 'theme-install-failed' ).append( $message );
- $button = $card.find( '.theme-install' );
- }
-
- $button
- .removeClass( 'updating-message' )
- .attr( 'aria-label', wp.updates.l10n.themeInstallFailedLabel.replace( '%s', $button.data( 'name' ) ) )
- .text( wp.updates.l10n.installFailedShort );
-
- wp.a11y.speak( errorMessage, 'assertive' );
-
- $document.trigger( 'wp-theme-install-error', response );
- };
-
- /**
- * Sends an Ajax request to the server to install a theme.
- *
- * @since 4.6.0
- *
- * @param {object} args
- * @param {string} args.slug Theme stylesheet.
- * @param {deleteThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.deleteThemeSuccess
- * @param {deleteThemeError=} args.error Optional. Error callback. Default: wp.updates.deleteThemeError
- * @return {$.promise} A jQuery promise that represents the request,
- * decorated with an abort() method.
- */
- wp.updates.deleteTheme = function( args ) {
- var $button;
-
- if ( 'themes' === pagenow ) {
- $button = $( '.theme-actions .delete-theme' );
- } else if ( 'themes-network' === pagenow ) {
- $button = $( '[data-slug="' + args.slug + '"]' ).find( '.row-actions a.delete' );
- }
-
- args = _.extend( {
- success: wp.updates.deleteThemeSuccess,
- error: wp.updates.deleteThemeError
- }, args );
-
- if ( $button && $button.html() !== wp.updates.l10n.deleting ) {
- $button
- .data( 'originaltext', $button.html() )
- .text( wp.updates.l10n.deleting );
- }
-
- wp.a11y.speak( wp.updates.l10n.deleting, 'polite' );
-
- // Remove previous error messages, if any.
- $( '.theme-info .update-message' ).remove();
-
- $document.trigger( 'wp-theme-deleting', args );
-
- return wp.updates.ajax( 'delete-theme', args );
- };
-
- /**
- * Updates the UI appropriately after a successful theme deletion.
- *
- * @since 4.6.0
- *
- * @typedef {object} deleteThemeSuccess
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the theme that was deleted.
- */
- wp.updates.deleteThemeSuccess = function( response ) {
- var $themeRows = $( '[data-slug="' + response.slug + '"]' );
-
- if ( 'themes-network' === pagenow ) {
-
- // Removes the theme and updates rows.
- $themeRows.css( { backgroundColor: '#faafaa' } ).fadeOut( 350, function() {
- var $views = $( '.subsubsub' ),
- $themeRow = $( this ),
- totals = settings.themes,
- deletedRow = wp.template( 'item-deleted-row' );
-
- if ( ! $themeRow.hasClass( 'plugin-update-tr' ) ) {
- $themeRow.after(
- deletedRow( {
- slug: response.slug,
- colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length,
- name: $themeRow.find( '.theme-title strong' ).text()
- } )
- );
- }
-
- $themeRow.remove();
-
- // Remove theme from update count.
- if ( $themeRow.hasClass( 'update' ) ) {
- totals.upgrade--;
- wp.updates.decrementCount( 'theme' );
- }
-
- // Remove from views.
- if ( $themeRow.hasClass( 'inactive' ) ) {
- totals.disabled--;
- if ( totals.disabled ) {
- $views.find( '.disabled .count' ).text( '(' + totals.disabled + ')' );
- } else {
- $views.find( '.disabled' ).remove();
- }
- }
-
- // There is always at least one theme available.
- $views.find( '.all .count' ).text( '(' + --totals.all + ')' );
- } );
- }
-
- wp.a11y.speak( wp.updates.l10n.deleted, 'polite' );
-
- $document.trigger( 'wp-theme-delete-success', response );
- };
-
- /**
- * Updates the UI appropriately after a failed theme deletion.
- *
- * @since 4.6.0
- *
- * @typedef {object} deleteThemeError
- * @param {object} response Response from the server.
- * @param {string} response.slug Slug of the theme to be deleted.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- */
- wp.updates.deleteThemeError = function( response ) {
- var $themeRow = $( 'tr.inactive[data-slug="' + response.slug + '"]' ),
- $button = $( '.theme-actions .delete-theme' ),
- updateRow = wp.template( 'item-update-row' ),
- $updateRow = $themeRow.siblings( '#' + response.slug + '-update' ),
- errorMessage = wp.updates.l10n.deleteFailed.replace( '%s', response.errorMessage ),
- $message = wp.updates.adminNotice( {
- className: 'update-message notice-error notice-alt',
- message: errorMessage
- } );
-
- if ( wp.updates.maybeHandleCredentialError( response, 'delete-theme' ) ) {
- return;
- }
-
- if ( 'themes-network' === pagenow ) {
- if ( ! $updateRow.length ) {
- $themeRow.addClass( 'update' ).after(
- updateRow( {
- slug: response.slug,
- colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length,
- content: $message
- } )
- );
- } else {
- // Remove previous error messages, if any.
- $updateRow.find( '.notice-error' ).remove();
- $updateRow.find( '.plugin-update' ).append( $message );
- }
- } else {
- $( '.theme-info .theme-description' ).before( $message );
- }
-
- $button.html( $button.data( 'originaltext' ) );
-
- wp.a11y.speak( errorMessage, 'assertive' );
-
- $document.trigger( 'wp-theme-delete-error', response );
- };
-
- /**
- * Adds the appropriate callback based on the type of action and the current page.
- *
- * @since 4.6.0
- * @private
- *
- * @param {object} data AJAX payload.
- * @param {string} action The type of request to perform.
- * @return {object} The AJAX payload with the appropriate callbacks.
- */
- wp.updates._addCallbacks = function( data, action ) {
- if ( 'import' === pagenow && 'install-plugin' === action ) {
- data.success = wp.updates.installImporterSuccess;
- data.error = wp.updates.installImporterError;
- }
-
- return data;
- };
-
- /**
- * Pulls available jobs from the queue and runs them.
- *
- * @since 4.2.0
- * @since 4.6.0 Can handle multiple job types.
- */
- wp.updates.queueChecker = function() {
- var job;
-
- if ( wp.updates.ajaxLocked || ! wp.updates.queue.length ) {
- return;
- }
-
- job = wp.updates.queue.shift();
-
- // Handle a queue job.
- switch ( job.action ) {
- case 'install-plugin':
- wp.updates.installPlugin( job.data );
- break;
-
- case 'update-plugin':
- wp.updates.updatePlugin( job.data );
- break;
-
- case 'delete-plugin':
- wp.updates.deletePlugin( job.data );
- break;
-
- case 'install-theme':
- wp.updates.installTheme( job.data );
- break;
-
- case 'update-theme':
- wp.updates.updateTheme( job.data );
- break;
-
- case 'delete-theme':
- wp.updates.deleteTheme( job.data );
- break;
-
- default:
- break;
- }
- };
-
- /**
- * Requests the users filesystem credentials if they aren't already known.
- *
- * @since 4.2.0
- *
- * @param {Event=} event Optional. Event interface.
- */
- wp.updates.requestFilesystemCredentials = function( event ) {
- if ( false === wp.updates.filesystemCredentials.available ) {
- /*
- * After exiting the credentials request modal,
- * return the focus to the element triggering the request.
- */
- if ( event && ! wp.updates.$elToReturnFocusToFromCredentialsModal ) {
- wp.updates.$elToReturnFocusToFromCredentialsModal = $( event.target );
- }
-
- wp.updates.ajaxLocked = true;
- wp.updates.requestForCredentialsModalOpen();
- }
- };
-
- /**
- * Requests the users filesystem credentials if needed and there is no lock.
- *
- * @since 4.6.0
- *
- * @param {Event=} event Optional. Event interface.
- */
- wp.updates.maybeRequestFilesystemCredentials = function( event ) {
- if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) {
- wp.updates.requestFilesystemCredentials( event );
- }
- };
-
- /**
- * Keydown handler for the request for credentials modal.
- *
- * Closes the modal when the escape key is pressed and
- * constrains keyboard navigation to inside the modal.
- *
- * @since 4.2.0
- *
- * @param {Event} event Event interface.
- */
- wp.updates.keydown = function( event ) {
- if ( 27 === event.keyCode ) {
- wp.updates.requestForCredentialsModalCancel();
- } else if ( 9 === event.keyCode ) {
-
- // #upgrade button must always be the last focus-able element in the dialog.
- if ( 'upgrade' === event.target.id && ! event.shiftKey ) {
- $( '#hostname' ).focus();
-
- event.preventDefault();
- } else if ( 'hostname' === event.target.id && event.shiftKey ) {
- $( '#upgrade' ).focus();
-
- event.preventDefault();
- }
- }
- };
-
- /**
- * Opens the request for credentials modal.
- *
- * @since 4.2.0
- */
- wp.updates.requestForCredentialsModalOpen = function() {
- var $modal = $( '#request-filesystem-credentials-dialog' );
-
- $( 'body' ).addClass( 'modal-open' );
- $modal.show();
- $modal.find( 'input:enabled:first' ).focus();
- $modal.on( 'keydown', wp.updates.keydown );
- };
-
- /**
- * Closes the request for credentials modal.
- *
- * @since 4.2.0
- */
- wp.updates.requestForCredentialsModalClose = function() {
- $( '#request-filesystem-credentials-dialog' ).hide();
- $( 'body' ).removeClass( 'modal-open' );
-
- if ( wp.updates.$elToReturnFocusToFromCredentialsModal ) {
- wp.updates.$elToReturnFocusToFromCredentialsModal.focus();
- }
- };
-
- /**
- * Takes care of the steps that need to happen when the modal is canceled out.
- *
- * @since 4.2.0
- * @since 4.6.0 Triggers an event for callbacks to listen to and add their actions.
- */
- wp.updates.requestForCredentialsModalCancel = function() {
-
- // Not ajaxLocked and no queue means we already have cleared things up.
- if ( ! wp.updates.ajaxLocked && ! wp.updates.queue.length ) {
- return;
- }
-
- _.each( wp.updates.queue, function( job ) {
- $document.trigger( 'credential-modal-cancel', job );
- } );
-
- // Remove the lock, and clear the queue.
- wp.updates.ajaxLocked = false;
- wp.updates.queue = [];
-
- wp.updates.requestForCredentialsModalClose();
- };
-
- /**
- * Displays an error message in the request for credentials form.
- *
- * @since 4.2.0
- *
- * @param {string} message Error message.
- */
- wp.updates.showErrorInCredentialsForm = function( message ) {
- var $filesystemForm = $( '#request-filesystem-credentials-form' );
-
- // Remove any existing error.
- $filesystemForm.find( '.notice' ).remove();
- $filesystemForm.find( '#request-filesystem-credentials-title' ).after( '<div class="notice notice-alt notice-error"><p>' + message + '</p></div>' );
- };
-
- /**
- * Handles credential errors and runs events that need to happen in that case.
- *
- * @since 4.2.0
- *
- * @param {object} response Ajax response.
- * @param {string} action The type of request to perform.
- */
- wp.updates.credentialError = function( response, action ) {
-
- // Restore callbacks.
- response = wp.updates._addCallbacks( response, action );
-
- wp.updates.queue.unshift( {
- action: action,
-
- /*
- * Not cool that we're depending on response for this data.
- * This would feel more whole in a view all tied together.
- */
- data: response
- } );
-
- wp.updates.filesystemCredentials.available = false;
- wp.updates.showErrorInCredentialsForm( response.errorMessage );
- wp.updates.requestFilesystemCredentials();
- };
-
- /**
- * Handles credentials errors if it could not connect to the filesystem.
- *
- * @since 4.6.0
- *
- * @typedef {object} maybeHandleCredentialError
- * @param {object} response Response from the server.
- * @param {string} response.errorCode Error code for the error that occurred.
- * @param {string} response.errorMessage The error that occurred.
- * @param {string} action The type of request to perform.
- * @returns {boolean} Whether there is an error that needs to be handled or not.
- */
- wp.updates.maybeHandleCredentialError = function( response, action ) {
- if ( wp.updates.shouldRequestFilesystemCredentials && response.errorCode && 'unable_to_connect_to_filesystem' === response.errorCode ) {
- wp.updates.credentialError( response, action );
- return true;
- }
-
- return false;
- };
-
- /**
- * Validates an AJAX response to ensure it's a proper object.
- *
- * If the response deems to be invalid, an admin notice is being displayed.
- *
- * @param {(object|string)} response Response from the server.
- * @param {function=} response.always Optional. Callback for when the Deferred is resolved or rejected.
- * @param {string=} response.statusText Optional. Status message corresponding to the status code.
- * @param {string=} response.responseText Optional. Request response as text.
- * @param {string} action Type of action the response is referring to. Can be 'delete',
- * 'update' or 'install'.
- */
- wp.updates.isValidResponse = function( response, action ) {
- var error = wp.updates.l10n.unknownError,
- errorMessage;
-
- // Make sure the response is a valid data object and not a Promise object.
- if ( _.isObject( response ) && ! _.isFunction( response.always ) ) {
- return true;
- }
-
- if ( _.isString( response ) && '-1' === response ) {
- error = wp.updates.l10n.nonceError;
- } else if ( _.isString( response ) ) {
- error = response;
- } else if ( 'undefined' !== typeof response.readyState && 0 === response.readyState ) {
- error = wp.updates.l10n.connectionError;
- } else if ( _.isString( response.responseText ) && '' !== response.responseText ) {
- error = response.responseText;
- } else if ( _.isString( response.statusText ) ) {
- error = response.statusText;
- }
-
- switch ( action ) {
- case 'update':
- errorMessage = wp.updates.l10n.updateFailed;
- break;
-
- case 'install':
- errorMessage = wp.updates.l10n.installFailed;
- break;
-
- case 'delete':
- errorMessage = wp.updates.l10n.deleteFailed;
- break;
- }
-
- // Messages are escaped, remove HTML tags to make them more readable.
- error = error.replace( /<[\/a-z][^<>]*>/gi, '' );
- errorMessage = errorMessage.replace( '%s', error );
-
- // Add admin notice.
- wp.updates.addAdminNotice( {
- id: 'unknown_error',
- className: 'notice-error is-dismissible',
- message: _.escape( errorMessage )
- } );
-
- // Remove the lock, and clear the queue.
- wp.updates.ajaxLocked = false;
- wp.updates.queue = [];
-
- // Change buttons of all running updates.
- $( '.button.updating-message' )
- .removeClass( 'updating-message' )
- .removeAttr( 'aria-label' )
- .prop( 'disabled', true )
- .text( wp.updates.l10n.updateFailedShort );
-
- $( '.updating-message:not(.button):not(.thickbox)' )
- .removeClass( 'updating-message notice-warning' )
- .addClass( 'notice-error' )
- .find( 'p' )
- .removeAttr( 'aria-label' )
- .text( errorMessage );
-
- wp.a11y.speak( errorMessage, 'assertive' );
-
- return false;
- };
-
- /**
- * Potentially adds an AYS to a user attempting to leave the page.
- *
- * If an update is on-going and a user attempts to leave the page,
- * opens an "Are you sure?" alert.
- *
- * @since 4.2.0
- */
- wp.updates.beforeunload = function() {
- if ( wp.updates.ajaxLocked ) {
- return wp.updates.l10n.beforeunload;
- }
- };
-
- $( function() {
- var $pluginFilter = $( '#plugin-filter' ),
- $bulkActionForm = $( '#bulk-action-form' ),
- $filesystemForm = $( '#request-filesystem-credentials-form' ),
- $filesystemModal = $( '#request-filesystem-credentials-dialog' ),
- $pluginSearch = $( '.plugins-php .wp-filter-search' ),
- $pluginInstallSearch = $( '.plugin-install-php .wp-filter-search' );
-
- settings = _.extend( settings, window._wpUpdatesItemCounts || {} );
-
- if ( settings.totals ) {
- wp.updates.refreshCount();
- }
-
- /*
- * Whether a user needs to submit filesystem credentials.
- *
- * This is based on whether the form was output on the page server-side.
- *
- * @see {wp_print_request_filesystem_credentials_modal() in PHP}
- */
- wp.updates.shouldRequestFilesystemCredentials = $filesystemModal.length > 0;
-
- /**
- * File system credentials form submit noop-er / handler.
- *
- * @since 4.2.0
- */
- $filesystemModal.on( 'submit', 'form', function( event ) {
- event.preventDefault();
-
- // Persist the credentials input by the user for the duration of the page load.
- wp.updates.filesystemCredentials.ftp.hostname = $( '#hostname' ).val();
- wp.updates.filesystemCredentials.ftp.username = $( '#username' ).val();
- wp.updates.filesystemCredentials.ftp.password = $( '#password' ).val();
- wp.updates.filesystemCredentials.ftp.connectionType = $( 'input[name="connection_type"]:checked' ).val();
- wp.updates.filesystemCredentials.ssh.publicKey = $( '#public_key' ).val();
- wp.updates.filesystemCredentials.ssh.privateKey = $( '#private_key' ).val();
- wp.updates.filesystemCredentials.available = true;
-
- // Unlock and invoke the queue.
- wp.updates.ajaxLocked = false;
- wp.updates.queueChecker();
-
- wp.updates.requestForCredentialsModalClose();
- } );
-
- /**
- * Closes the request credentials modal when clicking the 'Cancel' button or outside of the modal.
- *
- * @since 4.2.0
- */
- $filesystemModal.on( 'click', '[data-js-action="close"], .notification-dialog-background', wp.updates.requestForCredentialsModalCancel );
-
- /**
- * Hide SSH fields when not selected.
- *
- * @since 4.2.0
- */
- $filesystemForm.on( 'change', 'input[name="connection_type"]', function() {
- $( '#ssh-keys' ).toggleClass( 'hidden', ( 'ssh' !== $( this ).val() ) );
- } ).change();
-
- /**
- * Handles events after the credential modal was closed.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- * @param {string} job The install/update.delete request.
- */
- $document.on( 'credential-modal-cancel', function( event, job ) {
- var $updatingMessage = $( '.updating-message' ),
- $message, originalText;
-
- if ( 'import' === pagenow ) {
- $updatingMessage.removeClass( 'updating-message' );
- } else if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
- if ( 'update-plugin' === job.action ) {
- $message = $( 'tr[data-plugin="' + job.data.plugin + '"]' ).find( '.update-message' );
- } else if ( 'delete-plugin' === job.action ) {
- $message = $( '[data-plugin="' + job.data.plugin + '"]' ).find( '.row-actions a.delete' );
- }
- } else if ( 'themes' === pagenow || 'themes-network' === pagenow ) {
- if ( 'update-theme' === job.action ) {
- $message = $( '[data-slug="' + job.data.slug + '"]' ).find( '.update-message' );
- } else if ( 'delete-theme' === job.action && 'themes-network' === pagenow ) {
- $message = $( '[data-slug="' + job.data.slug + '"]' ).find( '.row-actions a.delete' );
- } else if ( 'delete-theme' === job.action && 'themes' === pagenow ) {
- $message = $( '.theme-actions .delete-theme' );
- }
- } else {
- $message = $updatingMessage;
- }
-
- if ( $message && $message.hasClass( 'updating-message' ) ) {
- originalText = $message.data( 'originaltext' );
-
- if ( 'undefined' === typeof originalText ) {
- originalText = $( '<p>' ).html( $message.find( 'p' ).data( 'originaltext' ) );
- }
-
- $message
- .removeClass( 'updating-message' )
- .html( originalText );
-
- if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
- if ( 'update-plugin' === job.action ) {
- $message.attr( 'aria-label', wp.updates.l10n.updateNowLabel.replace( '%s', $message.data( 'name' ) ) );
- } else if ( 'install-plugin' === job.action ) {
- $message.attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', $message.data( 'name' ) ) );
- }
- }
- }
-
- wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' );
- } );
-
- /**
- * Click handler for plugin updates in List Table view.
- *
- * @since 4.2.0
- *
- * @param {Event} event Event interface.
- */
- $bulkActionForm.on( 'click', '[data-plugin] .update-link', function( event ) {
- var $message = $( event.target ),
- $pluginRow = $message.parents( 'tr' );
-
- event.preventDefault();
-
- if ( $message.hasClass( 'updating-message' ) || $message.hasClass( 'button-disabled' ) ) {
- return;
- }
-
- wp.updates.maybeRequestFilesystemCredentials( event );
-
- // Return the user to the input box of the plugin's table row after closing the modal.
- wp.updates.$elToReturnFocusToFromCredentialsModal = $pluginRow.find( '.check-column input' );
- wp.updates.updatePlugin( {
- plugin: $pluginRow.data( 'plugin' ),
- slug: $pluginRow.data( 'slug' )
- } );
- } );
-
- /**
- * Click handler for plugin updates in plugin install view.
- *
- * @since 4.2.0
- *
- * @param {Event} event Event interface.
- */
- $pluginFilter.on( 'click', '.update-now', function( event ) {
- var $button = $( event.target );
- event.preventDefault();
-
- if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
- return;
- }
-
- wp.updates.maybeRequestFilesystemCredentials( event );
-
- wp.updates.updatePlugin( {
- plugin: $button.data( 'plugin' ),
- slug: $button.data( 'slug' )
- } );
- } );
-
- /**
- * Click handler for plugin installs in plugin install view.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $pluginFilter.on( 'click', '.install-now', function( event ) {
- var $button = $( event.target );
- event.preventDefault();
-
- if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
- return;
- }
-
- if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) {
- wp.updates.requestFilesystemCredentials( event );
-
- $document.on( 'credential-modal-cancel', function() {
- var $message = $( '.install-now.updating-message' );
-
- $message
- .removeClass( 'updating-message' )
- .text( wp.updates.l10n.installNow );
-
- wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' );
- } );
- }
-
- wp.updates.installPlugin( {
- slug: $button.data( 'slug' )
- } );
- } );
-
- /**
- * Click handler for importer plugins installs in the Import screen.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $document.on( 'click', '.importer-item .install-now', function( event ) {
- var $button = $( event.target ),
- pluginName = $( this ).data( 'name' );
-
- event.preventDefault();
-
- if ( $button.hasClass( 'updating-message' ) ) {
- return;
- }
-
- if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) {
- wp.updates.requestFilesystemCredentials( event );
-
- $document.on( 'credential-modal-cancel', function() {
-
- $button
- .removeClass( 'updating-message' )
- .text( wp.updates.l10n.installNow )
- .attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', pluginName ) );
-
- wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' );
- } );
- }
-
- wp.updates.installPlugin( {
- slug: $button.data( 'slug' ),
- pagenow: pagenow,
- success: wp.updates.installImporterSuccess,
- error: wp.updates.installImporterError
- } );
- } );
-
- /**
- * Click handler for plugin deletions.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $bulkActionForm.on( 'click', '[data-plugin] a.delete', function( event ) {
- var $pluginRow = $( event.target ).parents( 'tr' );
-
- event.preventDefault();
-
- if ( ! window.confirm( wp.updates.l10n.aysDeleteUninstall.replace( '%s', $pluginRow.find( '.plugin-title strong' ).text() ) ) ) {
- return;
- }
-
- wp.updates.maybeRequestFilesystemCredentials( event );
-
- wp.updates.deletePlugin( {
- plugin: $pluginRow.data( 'plugin' ),
- slug: $pluginRow.data( 'slug' )
- } );
-
- } );
-
- /**
- * Click handler for theme updates.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $document.on( 'click', '.themes-php.network-admin .update-link', function( event ) {
- var $message = $( event.target ),
- $themeRow = $message.parents( 'tr' );
-
- event.preventDefault();
-
- if ( $message.hasClass( 'updating-message' ) || $message.hasClass( 'button-disabled' ) ) {
- return;
- }
-
- wp.updates.maybeRequestFilesystemCredentials( event );
-
- // Return the user to the input box of the theme's table row after closing the modal.
- wp.updates.$elToReturnFocusToFromCredentialsModal = $themeRow.find( '.check-column input' );
- wp.updates.updateTheme( {
- slug: $themeRow.data( 'slug' )
- } );
- } );
-
- /**
- * Click handler for theme deletions.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $document.on( 'click', '.themes-php.network-admin a.delete', function( event ) {
- var $themeRow = $( event.target ).parents( 'tr' );
-
- event.preventDefault();
-
- if ( ! window.confirm( wp.updates.l10n.aysDelete.replace( '%s', $themeRow.find( '.theme-title strong' ).text() ) ) ) {
- return;
- }
-
- wp.updates.maybeRequestFilesystemCredentials( event );
-
- wp.updates.deleteTheme( {
- slug: $themeRow.data( 'slug' )
- } );
- } );
-
- /**
- * Bulk action handler for plugins and themes.
- *
- * Handles both deletions and updates.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $bulkActionForm.on( 'click', '[type="submit"]', function( event ) {
- var bulkAction = $( event.target ).siblings( 'select' ).val(),
- itemsSelected = $bulkActionForm.find( 'input[name="checked[]"]:checked' ),
- success = 0,
- error = 0,
- errorMessages = [],
- type, action;
-
- // Determine which type of item we're dealing with.
- switch ( pagenow ) {
- case 'plugins':
- case 'plugins-network':
- type = 'plugin';
- break;
-
- case 'themes-network':
- type = 'theme';
- break;
-
- default:
- return;
- }
-
- // Bail if there were no items selected.
- if ( ! itemsSelected.length ) {
- event.preventDefault();
- $( 'html, body' ).animate( { scrollTop: 0 } );
-
- return wp.updates.addAdminNotice( {
- id: 'no-items-selected',
- className: 'notice-error is-dismissible',
- message: wp.updates.l10n.noItemsSelected
- } );
- }
-
- // Determine the type of request we're dealing with.
- switch ( bulkAction ) {
- case 'update-selected':
- action = bulkAction.replace( 'selected', type );
- break;
-
- case 'delete-selected':
- if ( ! window.confirm( 'plugin' === type ? wp.updates.l10n.aysBulkDelete : wp.updates.l10n.aysBulkDeleteThemes ) ) {
- event.preventDefault();
- return;
- }
-
- action = bulkAction.replace( 'selected', type );
- break;
-
- default:
- return;
- }
-
- wp.updates.maybeRequestFilesystemCredentials( event );
-
- event.preventDefault();
-
- // Un-check the bulk checkboxes.
- $bulkActionForm.find( '.manage-column [type="checkbox"]' ).prop( 'checked', false );
-
- $document.trigger( 'wp-' + type + '-bulk-' + bulkAction, itemsSelected );
-
- // Find all the checkboxes which have been checked.
- itemsSelected.each( function( index, element ) {
- var $checkbox = $( element ),
- $itemRow = $checkbox.parents( 'tr' );
-
- // Only add update-able items to the update queue.
- if ( 'update-selected' === bulkAction && ( ! $itemRow.hasClass( 'update' ) || $itemRow.find( 'notice-error' ).length ) ) {
-
- // Un-check the box.
- $checkbox.prop( 'checked', false );
- return;
- }
-
- // Add it to the queue.
- wp.updates.queue.push( {
- action: action,
- data: {
- plugin: $itemRow.data( 'plugin' ),
- slug: $itemRow.data( 'slug' )
- }
- } );
- } );
-
- // Display bulk notification for updates of any kind.
- $document.on( 'wp-plugin-update-success wp-plugin-update-error wp-theme-update-success wp-theme-update-error', function( event, response ) {
- var $itemRow = $( '[data-slug="' + response.slug + '"]' ),
- $bulkActionNotice, itemName;
-
- if ( 'wp-' + response.update + '-update-success' === event.type ) {
- success++;
- } else {
- itemName = response.pluginName ? response.pluginName : $itemRow.find( '.column-primary strong' ).text();
-
- error++;
- errorMessages.push( itemName + ': ' + response.errorMessage );
- }
-
- $itemRow.find( 'input[name="checked[]"]:checked' ).prop( 'checked', false );
-
- wp.updates.adminNotice = wp.template( 'wp-bulk-updates-admin-notice' );
-
- wp.updates.addAdminNotice( {
- id: 'bulk-action-notice',
- className: 'bulk-action-notice',
- successes: success,
- errors: error,
- errorMessages: errorMessages,
- type: response.update
- } );
-
- $bulkActionNotice = $( '#bulk-action-notice' ).on( 'click', 'button', function() {
- // $( this ) is the clicked button, no need to get it again.
- $( this )
- .toggleClass( 'bulk-action-errors-collapsed' )
- .attr( 'aria-expanded', ! $( this ).hasClass( 'bulk-action-errors-collapsed' ) );
- // Show the errors list.
- $bulkActionNotice.find( '.bulk-action-errors' ).toggleClass( 'hidden' );
- } );
-
- if ( error > 0 && ! wp.updates.queue.length ) {
- $( 'html, body' ).animate( { scrollTop: 0 } );
- }
- } );
-
- // Reset admin notice template after #bulk-action-notice was added.
- $document.on( 'wp-updates-notice-added', function() {
- wp.updates.adminNotice = wp.template( 'wp-updates-admin-notice' );
- } );
-
- // Check the queue, now that the event handlers have been added.
- wp.updates.queueChecker();
- } );
-
- if ( $pluginInstallSearch.length ) {
- $pluginInstallSearch.attr( 'aria-describedby', 'live-search-desc' );
- }
-
- /**
- * Handles changes to the plugin search box on the new-plugin page,
- * searching the repository dynamically.
- *
- * @since 4.6.0
- */
- $pluginInstallSearch.on( 'keyup input', _.debounce( function( event, eventtype ) {
- var $searchTab = $( '.plugin-install-search' ), data, searchLocation;
-
- data = {
- _ajax_nonce: wp.updates.ajaxNonce,
- s: event.target.value,
- tab: 'search',
- type: $( '#typeselector' ).val(),
- pagenow: pagenow
- };
- searchLocation = location.href.split( '?' )[ 0 ] + '?' + $.param( _.omit( data, [ '_ajax_nonce', 'pagenow' ] ) );
-
- // Clear on escape.
- if ( 'keyup' === event.type && 27 === event.which ) {
- event.target.value = '';
- }
-
- if ( wp.updates.searchTerm === data.s && 'typechange' !== eventtype ) {
- return;
- } else {
- $pluginFilter.empty();
- wp.updates.searchTerm = data.s;
- }
-
- if ( window.history && window.history.replaceState ) {
- window.history.replaceState( null, '', searchLocation );
- }
-
- if ( ! $searchTab.length ) {
- $searchTab = $( '<li class="plugin-install-search" />' )
- .append( $( '<a />', {
- 'class': 'current',
- 'href': searchLocation,
- 'text': wp.updates.l10n.searchResultsLabel
- } ) );
-
- $( '.wp-filter .filter-links .current' )
- .removeClass( 'current' )
- .parents( '.filter-links' )
- .prepend( $searchTab );
-
- $pluginFilter.prev( 'p' ).remove();
- $( '.plugins-popular-tags-wrapper' ).remove();
- }
-
- if ( 'undefined' !== typeof wp.updates.searchRequest ) {
- wp.updates.searchRequest.abort();
- }
- $( 'body' ).addClass( 'loading-content' );
-
- wp.updates.searchRequest = wp.ajax.post( 'search-install-plugins', data ).done( function( response ) {
- $( 'body' ).removeClass( 'loading-content' );
- $pluginFilter.append( response.items );
- delete wp.updates.searchRequest;
-
- if ( 0 === response.count ) {
- wp.a11y.speak( wp.updates.l10n.noPluginsFound );
- } else {
- wp.a11y.speak( wp.updates.l10n.pluginsFound.replace( '%d', response.count ) );
- }
- } );
- }, 500 ) );
-
- if ( $pluginSearch.length ) {
- $pluginSearch.attr( 'aria-describedby', 'live-search-desc' );
- }
-
- /**
- * Handles changes to the plugin search box on the Installed Plugins screen,
- * searching the plugin list dynamically.
- *
- * @since 4.6.0
- */
- $pluginSearch.on( 'keyup input', _.debounce( function( event ) {
- var data = {
- _ajax_nonce: wp.updates.ajaxNonce,
- s: event.target.value,
- pagenow: pagenow,
- plugin_status: 'all'
- },
- queryArgs;
-
- // Clear on escape.
- if ( 'keyup' === event.type && 27 === event.which ) {
- event.target.value = '';
- }
-
- if ( wp.updates.searchTerm === data.s ) {
- return;
- } else {
- wp.updates.searchTerm = data.s;
- }
-
- queryArgs = _.object( _.compact( _.map( location.search.slice( 1 ).split( '&' ), function( item ) {
- if ( item ) return item.split( '=' );
- } ) ) );
-
- data.plugin_status = queryArgs.plugin_status || 'all';
-
- if ( window.history && window.history.replaceState ) {
- window.history.replaceState( null, '', location.href.split( '?' )[ 0 ] + '?s=' + data.s + '&plugin_status=' + data.plugin_status );
- }
-
- if ( 'undefined' !== typeof wp.updates.searchRequest ) {
- wp.updates.searchRequest.abort();
- }
-
- $bulkActionForm.empty();
- $( 'body' ).addClass( 'loading-content' );
- $( '.subsubsub .current' ).removeClass( 'current' );
-
- wp.updates.searchRequest = wp.ajax.post( 'search-plugins', data ).done( function( response ) {
-
- // Can we just ditch this whole subtitle business?
- var $subTitle = $( '<span />' ).addClass( 'subtitle' ).html( wp.updates.l10n.searchResults.replace( '%s', _.escape( data.s ) ) ),
- $oldSubTitle = $( '.wrap .subtitle' );
-
- if ( ! data.s.length ) {
- $oldSubTitle.remove();
- $( '.subsubsub .' + data.plugin_status + ' a' ).addClass( 'current' );
- } else if ( $oldSubTitle.length ) {
- $oldSubTitle.replaceWith( $subTitle );
- } else {
- $( '.wrap h1' ).append( $subTitle );
- }
-
- $( 'body' ).removeClass( 'loading-content' );
- $bulkActionForm.append( response.items );
- delete wp.updates.searchRequest;
-
- if ( 0 === response.count ) {
- wp.a11y.speak( wp.updates.l10n.noPluginsFound );
- } else {
- wp.a11y.speak( wp.updates.l10n.pluginsFound.replace( '%d', response.count ) );
- }
- } );
- }, 500 ) );
-
- /**
- * Trigger a search event when the search form gets submitted.
- *
- * @since 4.6.0
- */
- $document.on( 'submit', '.search-plugins', function( event ) {
- event.preventDefault();
-
- $( 'input.wp-filter-search' ).trigger( 'input' );
- } );
-
- /**
- * Trigger a search event when the search type gets changed.
- *
- * @since 4.6.0
- */
- $( '#typeselector' ).on( 'change', function() {
- var $search = $( 'input[name="s"]' );
-
- if ( $search.val().length ) {
- $search.trigger( 'input', 'typechange' );
- }
- } );
-
- /**
- * Click handler for updating a plugin from the details modal on `plugin-install.php`.
- *
- * @since 4.2.0
- *
- * @param {Event} event Event interface.
- */
- $( '#plugin_update_from_iframe' ).on( 'click', function( event ) {
- var target = window.parent === window ? null : window.parent,
- update;
-
- $.support.postMessage = !! window.postMessage;
-
- if ( false === $.support.postMessage || null === target || -1 !== window.parent.location.pathname.indexOf( 'update-core.php' ) ) {
- return;
- }
-
- event.preventDefault();
-
- update = {
- action: 'update-plugin',
- data: {
- plugin: $( this ).data( 'plugin' ),
- slug: $( this ).data( 'slug' )
- }
- };
-
- target.postMessage( JSON.stringify( update ), window.location.origin );
- } );
-
- /**
- * Click handler for installing a plugin from the details modal on `plugin-install.php`.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $( '#plugin_install_from_iframe' ).on( 'click', function( event ) {
- var target = window.parent === window ? null : window.parent,
- install;
-
- $.support.postMessage = !! window.postMessage;
-
- if ( false === $.support.postMessage || null === target || -1 !== window.parent.location.pathname.indexOf( 'index.php' ) ) {
- return;
- }
-
- event.preventDefault();
-
- install = {
- action: 'install-plugin',
- data: {
- slug: $( this ).data( 'slug' )
- }
- };
-
- target.postMessage( JSON.stringify( install ), window.location.origin );
- } );
-
- /**
- * Handles postMessage events.
- *
- * @since 4.2.0
- * @since 4.6.0 Switched `update-plugin` action to use the queue.
- *
- * @param {Event} event Event interface.
- */
- $( window ).on( 'message', function( event ) {
- var originalEvent = event.originalEvent,
- expectedOrigin = document.location.protocol + '//' + document.location.hostname,
- message;
-
- if ( originalEvent.origin !== expectedOrigin ) {
- return;
- }
-
- try {
- message = $.parseJSON( originalEvent.data );
- } catch ( e ) {
- return;
- }
-
- if ( 'undefined' === typeof message.action ) {
- return;
- }
-
- switch ( message.action ) {
-
- // Called from `wp-admin/includes/class-wp-upgrader-skins.php`.
- case 'decrementUpdateCount':
- /** @property {string} message.upgradeType */
- wp.updates.decrementCount( message.upgradeType );
- break;
-
- case 'install-plugin':
- case 'update-plugin':
- /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
- window.tb_remove();
- /* jscs:enable */
-
- message.data = wp.updates._addCallbacks( message.data, message.action );
-
- wp.updates.queue.push( message );
- wp.updates.queueChecker();
- break;
- }
- } );
-
- /**
- * Adds a callback to display a warning before leaving the page.
- *
- * @since 4.2.0
- */
- $( window ).on( 'beforeunload', wp.updates.beforeunload );
- } );
- })( jQuery, window.wp, window._wpUpdatesSettings );
|