How do I access HTML content from BodyPart in custom template

Topics: General
Sep 25, 2013 at 7:25 PM
I am using the markdown editor for the BodyPart on a content item. I would like to access the formatted HTML, but only see a Text property on the BodyPart? Thought it would be something like:
Model.ContentItem.BodyPart.Html
but doesn't exist.
Coordinator
Sep 25, 2013 at 8:40 PM
That's because it's transformed by a filter that the part itself knows nothing about. MD is a separate feature, not an aspect of the body part.

You can however call ProcessContent on a new MarkdownFilter.
Sep 25, 2013 at 8:51 PM
Thanks for the reply Bertrand, not quite clear on how to implement your reply though. Would you mind pointing me in the right direction and elaborating more.
Developer
Sep 26, 2013 at 2:54 AM
Edited Sep 26, 2013 at 3:00 AM
You could add a "computed" part without a backing record with a property that exposes a filtered HTML output (let's call this property Html) of a corresponding BodyPart.
Add a handler for that part that would set this Html value (lazily or not) to: _htmlFilters.Aggregate(part.As<BodyPart>().Text, (text, filter) => filter.ProcessContent(text, "markdown"));, where _htmlFilters is IEnumerable<IHtmlFilter>.

Core BodyPartDriver does exactly the same thing, but it does not expose the outcome - it's just pushed to the display shape as a model property.

You can also compute that value and push to your shape as a model property directly (exactly like it's done in BodyPartDriver) without adding any new parts. Way simpler, but you won't be able to access this value outside of that shape.
Coordinator
Sep 26, 2013 at 5:14 AM
That sounds a little convoluted. Wherever you need the html for the markdown, just do var html = (new MarkdownFilter()).ProcessContent(theBodyPart.Text, "markdown");
Sep 26, 2013 at 5:35 PM
Thanks guys. Haven't had chane to test just yet, but Betrands solve seems straight forward.
Developer
Sep 26, 2013 at 8:35 PM
SamuelGoldenbaum wrote:
Thanks guys. Haven't had chane to test just yet, but Betrands solve seems straight forward.
Yeah, that's more or less the same thing we're talking about but different way of getting the filter object for processing markdown (direct instance using new vs. fetching from the container). Bertrand's solution is indeed much simpler.

Anyway, it seems like a good idea to expose the final HTML output via some "lazy" property on the core BodyPart. What'd you think, Bertrand?
Coordinator
Sep 26, 2013 at 11:25 PM
You could build an extension method, but that's about the only way to make it work. Anything else would make body depend on markdown, which we don't want.
Sep 27, 2013 at 6:31 AM
Edited Sep 27, 2013 at 6:32 AM
+1 in having filters resulting html exposed in some core property, having a non saved part for this in core seems good idea
Coordinator
Sep 27, 2013 at 11:09 PM
Did you read my answer? If so, can you explain why you still disagree?
Sep 28, 2013 at 7:57 AM
I was not digging into details, being not totally convinced by your affirmation: 'that's about the only way to make it work' ?
Your solution is fast but dedicated to Markdown. By the way its is a correct answer to the question here.
I have seen many threads about 'getting access to the generated html' by filters and know it would be a nice feature if solid and in core (but in core ornot may be secondary concern)
Coordinator
Sep 28, 2013 at 9:57 PM
Edited Sep 28, 2013 at 9:58 PM
What I don't understand is how you think it could work, without introducing a reference from body to markdown? Do you just want an API that will find and run the filters on a body part? If so, inject IEnumerable<IHtmlFilter> _htmlFilters and do:
_htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text, GetFlavor(part)))
GetFlavor itself is the following, which exists on BodyPartDriver, and that it might make sense making public:
        private static string GetFlavor(BodyPart part) {
            var typePartSettings = part.Settings.GetModel<BodyTypePartSettings>();
            return (typePartSettings != null && !string.IsNullOrWhiteSpace(typePartSettings.Flavor))
                       ? typePartSettings.Flavor
                       : part.PartDefinition.Settings.GetModel<BodyPartSettings>().FlavorDefault;
        }
(this, by the way is what Piotr was proposing)

You could easily package that into an extension method.
Sep 29, 2013 at 8:28 AM
Looks good, but why do you say that it's what Piotr was proposing, I don't see the part he was evoking?
Developer
Sep 29, 2013 at 1:09 PM
CSADNT wrote:
Looks good, but why do you say that it's what Piotr was proposing, I don't see the part he was evoking?
I guess Bertrand meant the idea of filter injection - this was my initial proposition.

I intentionally stripped down the GetFlavor(part) part and replaced with hardcoded "markdown" for better fit to the actual question. But for a more generic solution retrieving the flavor from the part would be essential, of course (like the driver does).
Coordinator
Sep 29, 2013 at 10:32 PM
Yup. All in all, you now have all the code you need to build an extension method that does what you need, I think.