222 lines
6.8 KiB
JavaScript
222 lines
6.8 KiB
JavaScript
( function( wp ) {
|
|
const { __ } = wp.i18n;
|
|
const { getBlockType, registerBlockType } = wp.blocks;
|
|
const { createElement: el, Fragment, useState } = wp.element;
|
|
const { InspectorControls, MediaUpload, MediaUploadCheck } = wp.blockEditor;
|
|
const { PanelBody, TextControl, TextareaControl, Button, ToggleControl, SelectControl, BaseControl, Notice } = wp.components;
|
|
const ServerSideRender = wp.serverSideRender;
|
|
|
|
const themeOptions = [
|
|
{ label: __( 'Modern Dark', 'modern-audio-player' ), value: 'modern-dark' },
|
|
{ label: __( 'Glassmorphism', 'modern-audio-player' ), value: 'glassmorphism' },
|
|
{ label: __( 'Podcast Style', 'modern-audio-player' ), value: 'podcast-style' }
|
|
];
|
|
|
|
function getAudioUrlWarning( value ) {
|
|
if ( ! value ) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
const url = new window.URL( value, window.location.origin );
|
|
const hostname = url.hostname.toLowerCase();
|
|
const pathname = url.pathname.toLowerCase();
|
|
|
|
if ( [ 'youtube.com', 'www.youtube.com', 'youtu.be', 'soundcloud.com', 'open.spotify.com', 'music.apple.com' ].includes( hostname ) ) {
|
|
return __( 'This URL looks like a page, not a direct audio file. Please use a direct MP3 or other audio file URL.', 'modern-audio-player' );
|
|
}
|
|
|
|
if ( /\.(html?|php)$/i.test( pathname ) ) {
|
|
return __( 'This URL does not look like a direct audio file. Please confirm it points directly to the audio asset.', 'modern-audio-player' );
|
|
}
|
|
} catch ( error ) {
|
|
return __( 'Please enter a valid audio URL.', 'modern-audio-player' );
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function formatPlaylistText( playlist ) {
|
|
if ( ! Array.isArray( playlist ) || ! playlist.length ) {
|
|
return '';
|
|
}
|
|
|
|
return playlist.map( function( track ) {
|
|
return [
|
|
track.title || '',
|
|
track.src || '',
|
|
track.image || ''
|
|
].join( ' | ' );
|
|
} ).join( '\n' );
|
|
}
|
|
|
|
function parsePlaylistText( value ) {
|
|
return String( value || '' )
|
|
.split( /\r\n|\r|\n/ )
|
|
.map( function( line ) {
|
|
return line.trim();
|
|
} )
|
|
.filter( function( line ) {
|
|
return line.length > 0;
|
|
} )
|
|
.map( function( line ) {
|
|
const parts = line.split( '|' ).map( function( part ) {
|
|
return part.trim();
|
|
} );
|
|
|
|
return {
|
|
title: parts[ 0 ] || '',
|
|
src: parts[ 1 ] || '',
|
|
image: parts[ 2 ] || ''
|
|
};
|
|
} )
|
|
.filter( function( track ) {
|
|
return !! track.src;
|
|
} );
|
|
}
|
|
|
|
const blockSettings = {
|
|
edit: function( props ) {
|
|
const attributes = props.attributes;
|
|
const setAttributes = props.setAttributes;
|
|
const initialPlaylistText = formatPlaylistText( attributes.playlist || [] );
|
|
const playlistState = useState( initialPlaylistText );
|
|
const playlistText = playlistState[ 0 ];
|
|
const setPlaylistText = playlistState[ 1 ];
|
|
const firstPlaylistTrack = Array.isArray( attributes.playlist ) && attributes.playlist.length ? attributes.playlist[ 0 ] : null;
|
|
const audioUrlWarning = getAudioUrlWarning( attributes.src || ( firstPlaylistTrack && firstPlaylistTrack.src ) || '' );
|
|
|
|
function onSelectAudio( media ) {
|
|
setAttributes( {
|
|
src: media && media.url ? media.url : '',
|
|
title: attributes.title || ( media && media.title ? media.title : '' )
|
|
} );
|
|
}
|
|
|
|
function onSelectImage( media ) {
|
|
setAttributes( {
|
|
image: media && media.url ? media.url : ''
|
|
} );
|
|
}
|
|
|
|
return el(
|
|
Fragment,
|
|
{},
|
|
el(
|
|
InspectorControls,
|
|
{},
|
|
el(
|
|
PanelBody,
|
|
{ title: __( 'Player Content', 'modern-audio-player' ), initialOpen: true },
|
|
el( TextControl, {
|
|
label: __( 'Track Title', 'modern-audio-player' ),
|
|
value: attributes.title || '',
|
|
onChange: function( value ) {
|
|
setAttributes( { title: value } );
|
|
}
|
|
} ),
|
|
el( TextControl, {
|
|
label: __( 'Audio Source URL', 'modern-audio-player' ),
|
|
value: attributes.src || '',
|
|
help: __( 'Paste a direct audio URL or choose one from the media library below. This remains the fallback single-track source.', 'modern-audio-player' ),
|
|
onChange: function( value ) {
|
|
setAttributes( { src: value } );
|
|
}
|
|
} ),
|
|
audioUrlWarning ? el( Notice, {
|
|
status: 'warning',
|
|
isDismissible: false
|
|
}, audioUrlWarning ) : null,
|
|
el(
|
|
BaseControl,
|
|
{ label: __( 'Audio File', 'modern-audio-player' ) },
|
|
el(
|
|
MediaUploadCheck,
|
|
{},
|
|
el( MediaUpload, {
|
|
onSelect: onSelectAudio,
|
|
allowedTypes: [ 'audio' ],
|
|
render: function( renderProps ) {
|
|
return el(
|
|
Button,
|
|
{ variant: 'secondary', onClick: renderProps.open },
|
|
attributes.src ? __( 'Replace Audio File', 'modern-audio-player' ) : __( 'Choose Audio File', 'modern-audio-player' )
|
|
);
|
|
}
|
|
} )
|
|
)
|
|
),
|
|
el(
|
|
BaseControl,
|
|
{ label: __( 'Cover Image', 'modern-audio-player' ) },
|
|
el(
|
|
MediaUploadCheck,
|
|
{},
|
|
el( MediaUpload, {
|
|
onSelect: onSelectImage,
|
|
allowedTypes: [ 'image' ],
|
|
render: function( renderProps ) {
|
|
return el(
|
|
Button,
|
|
{ variant: 'secondary', onClick: renderProps.open },
|
|
attributes.image ? __( 'Replace Cover Image', 'modern-audio-player' ) : __( 'Choose Cover Image', 'modern-audio-player' )
|
|
);
|
|
}
|
|
} )
|
|
)
|
|
),
|
|
el( TextareaControl, {
|
|
label: __( 'Playlist Tracks', 'modern-audio-player' ),
|
|
help: __( 'One track per line in this format: Title | Audio URL | Image URL. If empty, the single-track fields above are used.', 'modern-audio-player' ),
|
|
value: playlistText,
|
|
onChange: function( value ) {
|
|
setPlaylistText( value );
|
|
setAttributes( { playlist: parsePlaylistText( value ) } );
|
|
}
|
|
} )
|
|
),
|
|
el(
|
|
PanelBody,
|
|
{ title: __( 'Theme', 'modern-audio-player' ), initialOpen: false },
|
|
el( ToggleControl, {
|
|
label: __( 'Inherit Global Theme', 'modern-audio-player' ),
|
|
checked: !! attributes.useGlobalTheme,
|
|
onChange: function( value ) {
|
|
setAttributes( { useGlobalTheme: value } );
|
|
}
|
|
} ),
|
|
el( SelectControl, {
|
|
label: __( 'Theme Override', 'modern-audio-player' ),
|
|
value: attributes.theme || 'modern-dark',
|
|
options: themeOptions,
|
|
disabled: !! attributes.useGlobalTheme,
|
|
onChange: function( value ) {
|
|
setAttributes( { theme: value } );
|
|
}
|
|
} )
|
|
)
|
|
),
|
|
el(
|
|
'div',
|
|
{ className: 'map-editor-preview' },
|
|
el( ServerSideRender, {
|
|
block: props.name,
|
|
attributes: attributes
|
|
} )
|
|
)
|
|
);
|
|
},
|
|
save: function() {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
if ( ! getBlockType( 'velora/audio-player' ) ) {
|
|
registerBlockType( 'velora/audio-player', blockSettings );
|
|
}
|
|
|
|
if ( ! getBlockType( 'map/audio-player' ) ) {
|
|
registerBlockType( 'map/audio-player', blockSettings );
|
|
}
|
|
} )( window.wp );
|