( function( $, as3cfModal ) { var savedSettings = {}; var bucketNamePattern = /[^a-z0-9.-]/; var $body = $( 'body' ); var $tabs = $( '.as3cf-tab' ); var $settings = $( '.as3cf-settings' ); var $activeTab; /** * Return the serialized string of the settings form * excluding the bucket and region inputs as they get saved via AJAX * * @param string tab * * @returns {string} */ function serializedForm( tab ) { return $( '#' + tab + ' .as3cf-main-settings form' ).find( 'input:not(.no-compare)' ).serialize(); } /** * Set checkbox * * @param string checkbox_wrap */ function setCheckbox( checkbox_wrap ) { var $switch = $activeTab.find( '#' + checkbox_wrap ); var $checkbox = $switch.find( 'input[type=checkbox]' ); $switch.toggleClass( 'on' ).find( 'span' ).toggleClass( 'checked' ); var switchOn = $switch.find( 'span.on' ).hasClass( 'checked' ); $checkbox.prop( 'checked', switchOn ).trigger( 'change' ); } /** * Validate custom domain * * @param {object} $input */ function validateCustomDomain( $input ) { var $error = $input.next( '.as3cf-validation-error' ); var $submit = $( '#' + $activeTab.attr( 'id' ) + ' form button[type="submit"]' ); var pattern = /[^a-zA-Z0-9\.\-]/; if ( pattern.test( $input.val() ) ) { $error.show(); $submit.prop( 'disabled', true ); } else { $error.hide(); $submit.prop( 'disabled', false ); } } as3cf.tabs = { defaultTab: 'media', /** * Toggle settings tab * * @param string hash * @param boolean persist_updated_notice */ toggle: function( hash, persist_updated_notice ) { hash = as3cf.tabs.sanitizeHash( hash ); $tabs.hide(); $activeTab = $( '#tab-' + hash ); $activeTab.show(); $( '.nav-tab' ).removeClass( 'nav-tab-active' ); $( 'a.nav-tab[data-tab="' + hash + '"]' ).addClass( 'nav-tab-active' ); $( '.as3cf-main' ).data( 'tab', hash ); if ( $activeTab.data( 'prefix' ) ) { as3cfModal.prefix = $activeTab.data( 'prefix' ); } if ( ! persist_updated_notice ) { $( '.as3cf-updated' ).removeClass( 'show' ); } if ( 'support' === hash ) { as3cf.tabs.getDiagnosticInfo(); } }, /** * Update display of diagnostic info. */ getDiagnosticInfo: function() { var $debugLog = $( '.debug-log-textarea' ); $debugLog.html( as3cf.strings.get_diagnostic_info ); var data = { action: 'as3cf-get-diagnostic-info', _nonce: as3cf.nonces.get_diagnostic_info }; $.ajax( { url: ajaxurl, type: 'POST', dataType: 'JSON', data: data, error: function( jqXHR, textStatus, errorThrown ) { $debugLog.html( errorThrown ); }, success: function( data, textStatus, jqXHR ) { if ( 'undefined' !== typeof data[ 'success' ] ) { $debugLog.html( data[ 'diagnostic_info' ] ); } else { $debugLog.html( as3cf.strings.get_diagnostic_info_error ); $debugLog.append( data[ 'error' ] ); } } } ); }, /** * Sanitize hash to ensure it references a real tab. * * @param string hash * * @return string */ sanitizeHash: function( hash ) { var $newTab = $( '#tab-' + hash ); if ( 0 === $newTab.length ) { hash = as3cf.tabs.defaultTab; } return hash; } }; /** * Handle the bucket selection, either inline or in a modal */ as3cf.buckets = { /** * Buckets must be at least this many characters */ validLength: 3, /** * Process lock for setting a bucket */ bucketSelectLock: false, /** * Load bucket list * * @param {boolean} [forceUpdate] */ loadList: function( forceUpdate ) { if ( 'undefined' === typeof forceUpdate ) { forceUpdate = false; } var $selectBucketForm = $( '.as3cf-bucket-container.' + as3cfModal.prefix + ' .as3cf-bucket-select' ); var $selectBucketRegion = $selectBucketForm.find( '.bucket-select-region' ); var $bucketList = $selectBucketForm.find( '.as3cf-bucket-list' ); var selectedBucket = $( '#' + as3cfModal.prefix + '-bucket' ).val(); if ( false === forceUpdate && $bucketList.find( 'li' ).length > 1 ) { $( '.as3cf-bucket-list a' ).removeClass( 'selected' ); $( '.as3cf-bucket-list a[data-bucket="' + selectedBucket + '"]' ).addClass( 'selected' ); this.scrollToSelected(); return; } $bucketList.html( '
  • ' + $bucketList.data( 'working' ) + '
  • ' ); // Stop accidental submit while reloading list. this.disabledButtons(); var data = { action: as3cfModal.prefix + '-get-buckets', _nonce: window[ as3cfModal.prefix.replace( /-/g, '_' ) ].nonces.get_buckets }; if ( $selectBucketRegion.val() ) { data[ 'region' ] = $selectBucketRegion.val(); } var that = this; $.ajax( { url: ajaxurl, type: 'POST', dataType: 'JSON', data: data, error: function( jqXHR, textStatus, errorThrown ) { $bucketList.html( '' ); that.showError( as3cf.strings.get_buckets_error, errorThrown, 'as3cf-bucket-select' ); }, success: function( data, textStatus, jqXHR ) { $bucketList.html( '' ); if ( 'undefined' !== typeof data[ 'success' ] ) { $( '.as3cf-bucket-error' ).hide(); if ( 0 === data[ 'buckets' ].length ) { $bucketList.html( '
  • ' + $bucketList.data( 'nothing-found' ) + '
  • ' ); } else { $( data[ 'buckets' ] ).each( function( idx, bucket ) { var bucketClass = bucket.Name === selectedBucket ? 'selected' : ''; $bucketList.append( '
  • ' + bucket.Name + '
  • ' ); } ); that.scrollToSelected(); that.disabledButtons(); } } else { that.showError( as3cf.strings.get_buckets_error, data[ 'error' ], 'as3cf-bucket-select' ); } } } ); }, /** * Scroll to selected bucket */ scrollToSelected: function() { if ( ! $( '.as3cf-bucket-list a.selected' ).length ) { return; } var offset = $( 'ul.as3cf-bucket-list li' ).first().position().top + 150; $( '.as3cf-bucket-list' ).animate( { scrollTop: $( 'ul.as3cf-bucket-list li a.selected' ).position().top - offset } ); }, /** * Set the selected bucket in list. * * @param {object} $link */ setSelected: function( $link ) { $( '.as3cf-bucket-list a' ).removeClass( 'selected' ); $link.addClass( 'selected' ); $( '#' + as3cfModal.prefix + '-bucket-select-name' ).val( $link.data( 'bucket' ) ); }, /** * Disable bucket buttons */ disabledButtons: function() { var $createBucketForm = $( '.as3cf-bucket-container.' + as3cfModal.prefix + ' .as3cf-bucket-create' ); var $manualBucketForm = $( '.as3cf-bucket-container.' + as3cfModal.prefix + ' .as3cf-bucket-manual' ); var $selectBucketForm = $( '.as3cf-bucket-container.' + as3cfModal.prefix + ' .as3cf-bucket-select' ); if ( 0 === $createBucketForm.length && 0 === $manualBucketForm.length && 0 === $selectBucketForm.length ) { return; } if ( 0 < $createBucketForm.length && this.isValidName( $createBucketForm.find( '.as3cf-bucket-name' ).val() ) ) { $createBucketForm.find( 'button[type=submit]' ).prop( 'disabled', false ); } else { $createBucketForm.find( 'button[type=submit]' ).prop( 'disabled', true ); } if ( 0 < $manualBucketForm.length && this.isValidName( $manualBucketForm.find( '.as3cf-bucket-name' ).val() ) ) { $manualBucketForm.find( 'button[type=submit]' ).prop( 'disabled', false ); } else { $manualBucketForm.find( 'button[type=submit]' ).prop( 'disabled', true ); } if ( 0 < $selectBucketForm.length && 1 === $selectBucketForm.find( '.as3cf-bucket-list a.selected' ).length ) { $selectBucketForm.find( 'button[type=submit]' ).prop( 'disabled', false ); } else { $selectBucketForm.find( 'button[type=submit]' ).prop( 'disabled', true ); } }, /** * Show bucket error * * @param {string} title * @param {string} error * @param {string} [context] */ showError: function( title, error, context ) { var $activeView = $( '.as3cf-bucket-container' ).children( ':visible' ); var $bucketError = $activeView.find( '.as3cf-bucket-error' ); context = ( 'undefined' === typeof context ) ? null : context; if ( context && ! $activeView.hasClass( context ) ) { return; } $bucketError.find( 'span.title' ).html( title + ' —' ); $bucketError.find( 'span.message' ).html( error ); $bucketError.show(); // Unlock setting the bucket this.bucketSelectLock = false; }, /** * Check for a valid bucket name * * Bucket names must be at least 3 and no more than 63 characters long. * They can contain lowercase letters, numbers, periods and hyphens. * * @param {string} bucketName * * @return boolean */ isValidName: function( bucketName ) { if ( bucketName.length < 3 || bucketName.length > 63 ) { return false; } if ( true === bucketNamePattern.test( bucketName ) ) { return false; } return true; }, /** * Update invalid bucket name notice * * @param {string} bucketName */ updateNameNotice: function( bucketName ) { var message = null; if ( true === bucketNamePattern.test( bucketName ) ) { message = as3cf.strings.create_bucket_invalid_chars; } else if ( bucketName.length < 3 ) { message = as3cf.strings.create_bucket_name_short; } else if ( bucketName.length > 63 ) { message = as3cf.strings.create_bucket_name_long; } if ( message && bucketName.length > 0 ) { $( '.as3cf-invalid-bucket-name' ).html( message ); } else { $( '.as3cf-invalid-bucket-name' ).html( '' ); } } }; /** * Reload the page, and show the persistent updated notice. * * Intended for use on plugin settings page. */ as3cf.reloadUpdated = function() { var url = location.pathname + location.search; if ( ! location.search.match( /[?&]updated=/ ) ) { url += '&updated=1'; } url += location.hash; location.assign( url ); }; /** * Show the standard "Settings saved." notice if not already visible. */ as3cf.showSettingsSavedNotice = function() { if ( 0 < $( '#setting-error-settings_updated:visible' ).length || 0 < $( '#as3cf-settings_updated:visible' ).length ) { return; } var settingsUpdatedNotice = '

    ' + as3cf.strings.settings_saved + '

    '; $( 'h2.nav-tab-wrapper' ).after( settingsUpdatedNotice ); $( document ).trigger( 'wp-updates-notice-added' ); // Hack to run WP Core's makeNoticesDismissible() function. }; /** * Get the link to the bucket on the AWS Console and update the DOM * * @returns {string} */ function setBucketLink() { var bucket = $( '#' + as3cfModal.prefix + '-bucket' ).val(); var $objectPrefix = $activeTab.find( 'input[name="object-prefix"]' ); var prefix = $objectPrefix.val(); if ( '' !== prefix ) { prefix = as3cf.provider_console_url_prefix_param + encodeURIComponent( prefix ); } var url = as3cf.provider_console_url + bucket + prefix; $( '#' + as3cfModal.prefix + '-view-bucket' ).attr( 'href', url ); } /* * Toggle the lost files notice */ function toggleLostFilesNotice() { if ( $( '#as3cf-remove-local-file' ).is( ':checked' ) && $( '#as3cf-serve-from-s3' ).is( ':not(:checked)' ) ) { $( '#as3cf-lost-files-notice' ).show(); } else { $( '#as3cf-lost-files-notice' ).hide(); } } /* * Toggle the remove local files notice */ function toggleRemoveLocalNotice() { if ( $( '#as3cf-remove-local-file' ).is( ':checked' ) ) { $( '#as3cf-remove-local-notice' ).show(); } else { $( '#as3cf-remove-local-notice' ).hide(); } } /* * Toggle the seo friendly url notice. */ function toggleSEOFriendlyURLNotice( seo_friendly ) { if ( true !== seo_friendly ) { $( '#as3cf-seo-friendly-url-notice' ).show(); } else { $( '#as3cf-seo-friendly-url-notice' ).hide(); } } /** * Generate URL preview */ function generateUrlPreview() { $( '.as3cf-url-preview' ).html( 'Generating...' ); var data = { _nonce: as3cf.nonces.get_url_preview }; $.each( $( '#tab-' + as3cf.tabs.defaultTab + ' .as3cf-main-settings form' ).serializeArray(), function( i, o ) { var n = o.name, v = o.value; n = n.replace( '[]', '' ); data[ n ] = undefined === data[ n ] ? v : $.isArray( data[ n ] ) ? data[ n ].concat( v ) : [ data[ n ], v ]; } ); // Overwrite the save action stored in the form data[ 'action' ] = 'as3cf-get-url-preview'; $.ajax( { url: ajaxurl, type: 'POST', dataType: 'JSON', data: data, error: function( jqXHR, textStatus, errorThrown ) { alert( as3cf.strings.get_url_preview_error + errorThrown ); }, success: function( data, textStatus, jqXHR ) { if ( 'undefined' !== typeof data[ 'success' ] ) { $( '.as3cf-url-preview' ).html( data[ 'url' ] ); toggleSEOFriendlyURLNotice( data[ 'seo_friendly' ] ); } else { alert( as3cf.strings.get_url_preview_error + data[ 'error' ] ); } } } ); } /** * Update the UI with the current active tab set in the URL hash. */ function renderCurrentTab() { // If rendering the default tab, or a bare hash clean the hash. if ( '#' + as3cf.tabs.defaultTab === location.hash ) { location.hash = ''; return; } as3cf.tabs.toggle( location.hash.replace( '#', '' ), true ); $( document ).trigger( 'as3cf.tabRendered', [ location.hash.replace( '#', '' ) ] ); } $( document ).ready( function() { // Tabs // -------------------- renderCurrentTab(); /** * Set the hashchange callback to update the rendered active tab. */ window.onhashchange = function( event ) { // Strip the # if still on the end of the URL if ( 'function' === typeof history.replaceState && '#' === location.href.slice( -1 ) ) { history.replaceState( {}, '', location.href.slice( 0, -1 ) ); } renderCurrentTab(); }; // Move any compatibility errors below the nav tabs var $navTabs = $( '.as3cf-main .nav-tab-wrapper' ); $( '.as3cf-compatibility-notice, div.updated, div.error, div.notice' ).not( '.below-h2, .inline' ).insertAfter( $navTabs ); // Settings // -------------------- // Save the original state of the forms for comparison later if ( $tabs.length ) { $tabs.each( function( i, tab ) { savedSettings[ tab.id ] = serializedForm( tab.id ); } ); } // Prompt user with dialog if leaving the settings page with unsaved changes $( window ).on( 'beforeunload.as3cf-settings', function() { if ( $.isEmptyObject( savedSettings ) ) { return; } var tab = $activeTab.attr( 'id' ); if ( serializedForm( tab ) !== savedSettings[ tab ] ) { return as3cf.strings.save_alert; } } ); // Let the save settings submit happen as normal $( document ).on( 'submit', '.as3cf-main-settings form', function( e ) { // Disable unload warning $( window ).off( 'beforeunload.as3cf-settings' ); } ); $( '.as3cf-switch' ).on( 'click', function( e ) { if ( ! $( this ).hasClass( 'disabled' ) ) { setCheckbox( $( this ).attr( 'id' ) ); } } ); $tabs.on( 'change', '.sub-toggle', function( e ) { var setting = $( this ).attr( 'id' ); $( '.as3cf-setting.' + setting ).toggleClass( 'hide' ); } ); $( '.as3cf-domain' ).on( 'change', 'input[type="radio"]', function( e ) { var $selected = $( this ).closest( 'input:radio[name="domain"]:checked' ); var domain = $selected.val(); var $cloudfront = $( this ).parents( '.as3cf-domain' ).find( '.as3cf-setting.cloudfront' ); var cloudfrontSelected = ( 'cloudfront' === domain ); $cloudfront.toggleClass( 'hide', ! cloudfrontSelected ); } ); $( '.url-preview' ).on( 'change', 'input', function( e ) { generateUrlPreview(); } ); toggleLostFilesNotice(); $( '#as3cf-serve-from-s3,#as3cf-remove-local-file' ).on( 'change', function( e ) { toggleLostFilesNotice(); } ); toggleRemoveLocalNotice(); $( '#as3cf-remove-local-file' ).on( 'change', function( e ) { toggleRemoveLocalNotice(); } ); // Don't allow 'enter' key to submit form on text input settings $( '.as3cf-setting input[type="text"]' ).keypress( function( event ) { if ( 13 === event.which ) { event.preventDefault(); return false; } } ); // Validate custom domain $( 'input[name="cloudfront"]' ).on( 'keyup', function( e ) { validateCustomDomain( $( this ) ); } ); // Re-enable submit button on domain change $( 'input[name="domain"]' ).on( 'change', function( e ) { var $input = $( this ); var $submit = $( '#' + $activeTab.attr( 'id' ) + ' form button[type="submit"]' ); if ( 'cloudfront' !== $input.val() ) { $submit.prop( 'disabled', false ); } else { validateCustomDomain( $input.next( '.as3cf-setting' ).find( 'input[name="cloudfront"]' ) ); } } ); // Change bucket link when custom path changes $( 'input[name="object-prefix"]' ).on( 'change', function( e ) { setBucketLink(); } ); // Bucket select // -------------------- // Move bucket errors $( '#tab-media > .as3cf-bucket-error' ).detach().insertAfter( '.as3cf-bucket-container h3' ); // Enable/disable change bucket's save buttons. as3cf.buckets.disabledButtons(); // Bucket list refresh handler $body.on( 'click', '.bucket-action-refresh', function( e ) { e.preventDefault(); as3cf.buckets.loadList( true ); } ); // Bucket list refresh on region change handler $body.on( 'change', '.bucket-select-region', function( e ) { e.preventDefault(); as3cf.buckets.loadList( true ); } ); // If select bucket form is available on load, populate its list. if ( 0 < $( '.as3cf-bucket-container.' + as3cfModal.prefix + ' .as3cf-bucket-select' ).length ) { as3cf.buckets.loadList( true ); } // Bucket list click handler $body.on( 'click', '.as3cf-bucket-list a', function( e ) { e.preventDefault(); as3cf.buckets.setSelected( $( this ) ); as3cf.buckets.disabledButtons(); } ); // External links click handler $( '.as3cf-bucket-container' ).on( 'click', 'a.js-link', function( e ) { e.preventDefault(); window.open( $( this ).attr( 'href' ) ); return false; } ); // Validate bucket name on create $body.on( 'input keyup', '.as3cf-bucket-create .as3cf-bucket-name', function( e ) { var bucketName = $( this ).val(); as3cf.buckets.updateNameNotice( bucketName ); as3cf.buckets.disabledButtons(); } ); $body.on( 'input keyup', '.as3cf-bucket-manual .as3cf-bucket-name', function( e ) { var bucketName = $( this ).val(); as3cf.buckets.updateNameNotice( bucketName ); as3cf.buckets.disabledButtons(); } ); // Don't allow 'enter' key to submit form on text input settings $( '.as3cf-bucket-container input[type="text"]' ).keypress( function( event ) { if ( 13 === event.which ) { event.preventDefault(); return false; } } ); } ); } )( jQuery, as3cfModal );