Don't miss out Virtual Happy Hour this Friday (April 26).

Try our conversational search powered by Generative AI!

Adding TinyMCE custom URL configuration for media content (Pdf files)

Vote:
 

Hi,

When I upload a pdf file within my accordion component block and publish this, the URL for the pdf document becomes the edit mode url:

 https://localhost:55388/EPiServer/CMS/Content/siteassets/pdfs/investors/202-general/--22-march-2023.pdf,,24089?epieditmode=false

This prevents me from accessing the file and gives me the following message on screen - "Preview is not available for this item".

The url should be in the following format: https://localhost:55388/siteassets/pdfs/investors/2020-general/kry---22-march-2023.pdf

I was wondering if there is a way that I could prevent this from occuring by including some config within the TinyMceConfiguration class.

 public static void ExtendingTinyMce(this IServiceCollection services)
        {
            services.Configure<TinyMceConfiguration>(config =>
            {
                config.For<AccordionItemBlock>(p => p.Content). // ensuring that Urls for PDF files are generated correctly.

                config.InheritSettingsFromAncestor = true;

                config.For<TextBlock>(p => p.Text)
                .BlockFormats("Paragraph=p; Heading 2=h2; Heading 3=h3; Heading 4=h4; Heading 5=h5; Heading 6=h6; Preformatted=pre; Normal=div")
                .StyleFormats(
                        new { title = "Check List", classes = "check-list", selector = "ul" },
                        new { title = "Check List Product", classes = "check-list-product", selector = "ul" }
                    )
            .Menubar("file edit insert view format table tools")
            .ClearPlugins()
}

Any answers would be greatly appreciated.

Thank you

#300260
Edited, Apr 17, 2023 17:32
Vote:
 

How do you render your (XHTML String?) property? Note that links will have different formats depending on in which context they're rendered.

#300320
Apr 18, 2023 14:00
Vote:
 

Hi Johan,

below is the response handler:

if (request.Block == null)
            {
                throw new ArgumentNullException(nameof(request.Block));
            }

            var response = await Task.FromResult(new AccordionResponse
            {
                Title = request.Block.Title,
                AccordionContent = request.Block.AccordionItems?.FilteredItems?.Select(x =>
                        _contentService.TryGet<AccordionItemBlock>(x.ContentLink, out var item)
                            ? new AccordionItemResponse
                            {
                                Title = item.Title,
                                Content = _contentService.GetPageMode() == ContextMode.Preview
                                    ? item.Content?.ToEditString()
                                    : item.Content?.ToHtmlString()
                            }
                            : null)
                    .Where(x => x != null)
            });

            _logger.LogDebug(nameof(Handle), "Returning {response}", response);

            return response;

The accordion block

 public class AccordionBlock : SiteBlockData
    {
        [Display(Name = "Title",
            GroupName = SystemTabNames.Content,
            Order = 10)]
        [Searchable]
        [CultureSpecific]
        [Required]
        public virtual string Title { get; set; }

        [Display(Name = "Accordion Items",
            GroupName = SystemTabNames.Content,
            Order = 10)]
        [CultureSpecific]
        [AllowedTypes(typeof(AccordionItemBlock))]
        public virtual ContentArea AccordionItems { get; set; }

    }

Below is the accordion item block which is whats used in the ContentArea for the accordion block

public class AccordionItemBlock : ChildBlock
    {
      
        [Display(Name = "Title",
            GroupName = SystemTabNames.Content,
            Order = 10)]
        [Searchable]
        [CultureSpecific]
        [Required]
        public virtual string Title { get; set; }

        [Display(Name = "Description",
            GroupName = SystemTabNames.Content,
            Order = 20)]
        [Searchable]
        [CultureSpecific]
        [Required]
        public virtual XhtmlString Content { get; set; }
    }

The block is then rendered through the view below:

@using React.AspNet
@using React.RenderFunctions
@model Weir.Global.CMS.Web.ViewModels.BlockViewModel

@{
    var mainStyledComponentsFunctions = new StyledComponentsFunctions();
    var mainChainedFunctions = new ChainedRenderFunctions(mainStyledComponentsFunctions);

}

@Html.React(Model.ComponentName, Model.Block, renderFunctions: mainChainedFunctions)

@Html.Raw(mainStyledComponentsFunctions.RenderedStyles)

We are then using the method below to load the content onto the page for the accordion block. When dubugging through the code it says we are using the Episerver.core.html.stringparsing.URLFragment for the links, which is giving back an internal format of "~/link/cc4aa3a906084771af57ddc69fe80413.aspx"

 public bool TryGet<T>(ContentReference contentReference, out T content) where T: IContentData
        {
            return _contentLoader.TryGet<T>(contentReference, out content);
        }

Ive been trying to look for a solution for a while now and ive got told to include something in the TinyMce Configuration that would prevent the Edit mode url from being generated after publishing the block component?

#300326
Edited, Apr 18, 2023 19:45
Vote:
 

item.Content?.ToHtmlString() will give you an internal format. Not sure what your "response handler" is, but if you have access to an IHtmlHelper, you can call the extension method XhtmlString on it: htmlHelper.XhtmlString(item.Content);

#300379
Edited, Apr 19, 2023 13:03
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.