feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)

Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.

Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
  - Provider key: s3compatible
  - Reads user-configured endpoint URL from settings
  - Uses path-style URL access (required by most S3-compatible services)
  - Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
    AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
  - Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
This commit is contained in:
2026-03-03 12:30:18 +01:00
commit 3248cbb029
2086 changed files with 359427 additions and 0 deletions

161
assets/js/modal.js Normal file
View File

@@ -0,0 +1,161 @@
var as3cfModal = (function( $ ) {
var modal = {
prefix: 'as3cf',
loading: false,
dismissible: true
};
var modals = {};
/**
* Target to key
*
* @param {string} target
*
* @return {string}
*/
function targetToKey( target ) {
return target.replace( /[^a-z]/g, '' );
}
/**
* Check if modal exists in DOM or in Memory.
*
* @param {string} target
*
* @return {boolean}
*/
modal.exists = function( target ) {
var key = targetToKey( target );
if ( undefined !== modals[ key ] ) {
return true;
}
if ( $( target ).length ) {
return true;
}
return false;
};
/**
* Open modal
*
* @param {string} target
* @param {function} callback
* @param {string} customClass
*/
modal.open = function( target, callback, customClass ) {
var key = targetToKey( target );
// Overlay
$( 'body' ).append( '<div id="as3cf-overlay"></div>' );
var $overlay = $( '#as3cf-overlay' );
// Modal container
if ( modal.dismissible ) {
$overlay.append( '<div id="as3cf-modal"><span class="close-as3cf-modal">×</span></div>' );
} else {
$overlay.append( '<div id="as3cf-modal"></div>' );
}
var $modal = $( '#as3cf-modal' );
if ( undefined === modals[ key ] ) {
var content = $( target );
modals[ key ] = content.clone( true ).css( 'display', 'block' );
content.remove();
}
$modal.data( 'as3cf-modal-target', target ).append( modals[ key ] );
if ( undefined !== customClass ) {
$modal.addClass( customClass );
}
if ( 'function' === typeof callback ) {
callback( target );
}
// Handle modals taller than window height,
// overflow & padding-right remove duplicate scrollbars.
$( 'body' ).addClass( 'as3cf-modal-open' );
$overlay.fadeIn( 150 );
$modal.fadeIn( 150 );
$( 'body' ).trigger( 'as3cf-modal-open', [ target ] );
};
/**
* Close modal
*
* @param {function} callback
*/
modal.close = function( callback ) {
if ( modal.loading || ! modal.dismissible ) {
return;
}
var target = $( '#as3cf-modal' ).data( 'as3cf-modal-target' );
$( '#as3cf-overlay' ).fadeOut( 150, function() {
$( 'body' ).removeClass( 'as3cf-modal-open' );
$( this ).remove();
if ( 'function' === typeof callback ) {
callback( target );
}
} );
$( 'body' ).trigger( 'as3cf-modal-close', [ target ] );
};
/**
* Set loading state
*
* @param {boolean} state
*/
modal.setLoadingState = function( state ) {
modal.loading = state;
};
/**
* Set dismissible state.
*
* @param {boolean} state
*/
modal.setDismissibleState = function( state ) {
modal.dismissible = state;
};
// Setup click handlers
$( document ).ready( function() {
$( 'body' ).on( 'click', '[data-as3cf-modal]', function( e ) {
e.preventDefault();
modal.open( $( this ).data( 'as3cf-modal' ) + '.' + modal.prefix );
} );
$( 'body' ).on( 'click', '#as3cf-overlay, .close-as3cf-modal', function( e ) {
if ( 'A' === e.target.tagName ) {
return;
}
e.preventDefault();
// Don't allow children to bubble up click event
if ( e.target !== this ) {
return false;
}
modal.close();
} );
} );
return modal;
})( jQuery );