Skip to content

Commit

Permalink
Allow to specify which files choosen from CKBox are downloadable.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mati365 committed Jan 3, 2025
1 parent 4896a62 commit ef3dd15
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 8 deletions.
62 changes: 54 additions & 8 deletions packages/ckeditor5-ckbox/src/ckboxcommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
CKBoxAssetImageDefinition,
CKBoxAssetLinkAttributesDefinition,
CKBoxAssetLinkDefinition,
CKBoxConfig,
CKBoxRawAssetDefinition
} from './ckboxconfig.js';

Expand Down Expand Up @@ -189,6 +190,7 @@ export default class CKBoxCommand extends Command {
const editor = this.editor;
const model = editor.model;
const shouldInsertDataId = !editor.config.get( 'ckbox.ignoreDataId' );
const downloadableFilesConfig = editor.config.get( 'ckbox.downloadableFiles' );

// Refresh the command after firing the `ckbox:*` event.
this.on<CKBoxEvent>( 'ckbox', () => {
Expand Down Expand Up @@ -230,6 +232,7 @@ export default class CKBoxCommand extends Command {

const assetsToProcess = prepareAssets( {
assets,
downloadableFilesConfig,
isImageAllowed: imageCommand.isEnabled,
isLinkAllowed: linkCommand.isEnabled
} );
Expand Down Expand Up @@ -379,7 +382,8 @@ export default class CKBoxCommand extends Command {
* Parses the chosen assets into the internal data format. Filters out chosen assets that are not allowed.
*/
function prepareAssets(
{ assets, isImageAllowed, isLinkAllowed }: {
{ downloadableFilesConfig, assets, isImageAllowed, isLinkAllowed }: {
downloadableFilesConfig: CKBoxConfig['downloadableFiles'];
assets: Array<CKBoxRawAssetDefinition>;
isImageAllowed: boolean;
isLinkAllowed: boolean;
Expand All @@ -395,7 +399,7 @@ function prepareAssets(
{
id: asset.data.id,
type: 'link',
attributes: prepareLinkAssetAttributes( asset )
attributes: prepareLinkAssetAttributes( downloadableFilesConfig, asset )
} as const
)
.filter( asset => asset.type === 'image' ? isImageAllowed : isLinkAllowed );
Expand Down Expand Up @@ -424,12 +428,16 @@ export function prepareImageAssetAttributes( asset: CKBoxRawAssetDefinition ): C
/**
* Parses the assets attributes into the internal data format.
*
* @param origin The base URL for assets inserted into the editor.
* @param config The CKBox download asset configuration.
* @param asset The asset to prepare the attributes for.
*/
function prepareLinkAssetAttributes( asset: CKBoxRawAssetDefinition ): CKBoxAssetLinkAttributesDefinition {
function prepareLinkAssetAttributes(
config: CKBoxConfig['downloadableFiles'],
asset: CKBoxRawAssetDefinition
): CKBoxAssetLinkAttributesDefinition {
return {
linkName: asset.data.name,
linkHref: getAssetUrl( asset )
linkHref: getAssetUrl( config, asset )
};
}

Expand All @@ -449,16 +457,54 @@ function isImage( asset: CKBoxRawAssetDefinition ) {
/**
* Creates the URL for the asset.
*
* @param origin The base URL for assets inserted into the editor.
* @param config The CKBox download asset configuration.
* @param asset The asset to create the URL for.
*/
function getAssetUrl( asset: CKBoxRawAssetDefinition ) {
function getAssetUrl( config: CKBoxConfig['downloadableFiles'], asset: CKBoxRawAssetDefinition ) {
const url = new URL( asset.data.url );

url.searchParams.set( 'download', 'true' );
if ( isDownloadableAsset( config, asset ) ) {
url.searchParams.set( 'download', 'true' );
}

return url.toString();
}

/**
* Determines if download should be enabled for given asset based on configuration.
*
* @param config The CKBox download asset configuration.
* @param asset The asset to check.
*/
function isDownloadableAsset(
config: CKBoxConfig['downloadableFiles'],
asset: CKBoxRawAssetDefinition
): boolean {
// If the configuration is not provided, the asset is always downloadable.
if ( config === undefined ) {
return true;
}

// If the configuration is a boolean, it's the global setting for all assets.
if ( typeof config === 'boolean' ) {
return config;
}

// If the configuration is an array, it's a list of file extensions that should be downloadable.
if ( Array.isArray( config ) ) {
const extension = asset.data.name.split( '.' ).pop()?.toLowerCase();

return extension ? config.includes( extension ) : false;
}

// If the configuration is a function, it's a custom logic to determine if the asset is downloadable.
if ( typeof config === 'function' ) {
return config( asset );
}

return false;
}

/**
* Fired when the command is executed, the dialog is closed or the assets are chosen.
*
Expand Down
25 changes: 25 additions & 0 deletions packages/ckeditor5-ckbox/src/ckboxconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,31 @@ export interface CKBoxConfig {
* ```
*/
choosableFileExtensions?: Array<string>;

/**
* Configures how the download attribute should be handled for inserted links.
*
* You can set this to:
* * `false` - to disable download attribute for all assets
* * `true` - to enable download attribute for all assets (default)
* * an array of extensions (e.g. ['pdf', 'zip']) - to enable download only for specific file types
* * a function that takes asset data and returns boolean - for custom logic
*
* ```ts
* const ckboxConfig = {
* // Enable download for specific extensions
* downloadableFiles: ['zip', 'rar', '7z', 'pdf'],
*
* // Or use a custom function
* downloadableFiles: ( asset ) => {
* return asset.data.name.endsWith( '.pdf' );
* }
* };
* ```
*
* @default true
*/
downloadableFiles?: boolean | Array<string> | ( ( asset: CKBoxRawAssetDefinition ) => boolean );
}

export interface CKBoxDialogConfig {
Expand Down

0 comments on commit ef3dd15

Please sign in to comment.