Inheriting alternates

Topics: General, Writing themes
Aug 15, 2013 at 2:30 PM
I keep hitting a similar problem while theming Orchard and if other people are hitting a similar problem, perhaps there is a nice way to solve it.

Sometimes a shape template will call Display to display shapes inside it and sometimes those shapes will call Display again.

This happens in FieldMediaLibraryPicker which then uses
Media which then uses
PartsImage

The only bit I want to change the shape template for is PartsImage, but the alternates available for that don't include any detail of the content type that contains the FieldMediaLibraryPicker. There doesn't seem to be a simple way to create an alternate template for PartsImage that is aware of the containing content type.

I might write a Media Alternates Factory ShapeDisplayEvent like I did for menu items.

But I was wondering if there was some way a shape could inherit the alternates of the shape that contained it and if this was a good enough idea to consider adding to Orchard.

This might be a bad idea, but I wondered what others thought and if other people were having this problem when theming?
Aug 15, 2013 at 3:00 PM
Edited Aug 15, 2013 at 3:02 PM
I use in my themes alternates on FieldMediaLibraryPicker, sometimes handling directly each MediaPart and sometimes calling Display as in the original, all this without problem ?
Aug 15, 2013 at 3:23 PM
Edited Aug 15, 2013 at 3:36 PM
If you handle the MediaPart directly don't you lose the flexibility of having the nested structure in the first place. It's also not obvious how to do that when you use the existing FieldMediaLibraryPicker template as your starting point.

Wouldn't it be easier and more flexible if there was a straight forward way to override the PartsImage template. I think when you're learning Orchard theming and you're using the shape tracing tool you expect to be able to directly override shape templates deep in the structure.
Aug 15, 2013 at 6:20 PM
Could you detail what you mean saying ' having the nested structure in the first place'
I simply use a loop adapted to my field content ?

for exemple I have an alternate template named MediaLibraryPicker-Image.cshtml for a field named Image in a contentItem named BSCarouselSlide with corresponding Part and containing only Images, and the code is
@using Orchard.ContentManagement
@using Orchard.MediaLibrary.Fields
@using Orchard.Utility.Extensions;
@using Contrib.BSCarouselSlide.Models;
@using Orchard.DisplayManagement.Shapes;
@{
    var field       = (MediaLibraryPickerField)Model.ContentField;
    string name     = field.DisplayName;
    var contents    = field.MediaParts;
    var carousel    = ((IContent)Model.ContentPart).As<BSCarouselSlidePart>();
    bool HasText    = carousel.HasText;
    bool HasImage   = carousel.HasImage;
    var imageClass  = carousel.ImageClass;
    string span     = ( HasText ) ? "span7" : "span12"; 
    
}
@if (HasImage )
{
    foreach(var content in contents) {
        <div class="@span @imageClass media-library-picker-field media-library-picker-field-@name.HtmlClassify() bscentertxt" >
            <img src="@Url.Content(content.MediaUrl)" alt="@content.AlternateText" />
        </div>
    }
}
Not very complex ?
But may be some case are more complicated.
Aug 15, 2013 at 9:07 PM
I mean the nested structure of the media picker using media, and media using parts-image. This structure allows you to show different types of media. I just think it would be nice to very easily use different media templates with alternates.

Once you see an example of accessing the media part directly from the media picker template it is simple, but that's not how the existing media picker template does it. And modifying existing templates is how you learn.
Developer
Aug 16, 2013 at 4:26 AM
One good way is writing a shape table provider, as you mentioned.
Another way is to override the "parent" view that renders the child shapes, but before you render them, add alternates to them. Or simply change their type to a name for which you have a view.
Aug 16, 2013 at 11:04 PM
sfmskywalker wrote:
One good way is writing a shape table provider, as you mentioned.
Another way is to override the "parent" view that renders the child shapes, but before you render them, add alternates to them. Or simply change their type to a name for which you have a view.
Sipke,
This second and third options you mention is very interesting, can you tell me were to find, or can you give me an example.

Thanks.
Sep 3, 2013 at 8:39 PM
Edited Sep 3, 2013 at 8:40 PM
nduarte wrote:
sfmskywalker wrote:
One good way is writing a shape table provider, as you mentioned.
Another way is to override the "parent" view that renders the child shapes, but before you render them, add alternates to them. Or simply change their type to a name for which you have a view.
Sipke,
This second and third options you mention is very interesting, can you tell me were to find, or can you give me an example.

Thanks.
\src\Orchard.Web\Themes\MyTheme01\Views\Fields.MediaLibraryPicker.cshtml

@using Orchard.ContentManagement
@using Orchard.MediaLibrary.Fields
@using Orchard.Utility.Extensions;
@using Orchard.DisplayManagement.Shapes;

@{
    var field = (MediaLibraryPickerField) Model.ContentField;
    string name = field.DisplayName;
    var contents = field.MediaParts;

    string parentMetadataType = Model.ContentItem.ContentType;
}
<section class="media-library-picker-field media-library-picker-field-@name.HtmlClassify()">
    @*<h3>@name</h3>*@
    @foreach(var content in contents) 
    {

        var _shape = BuildDisplay(content, "Summary");
        ShapeMetadata metadata = _shape.Metadata;

        string alternate = metadata.Type + "__" + parentMetadataType ;

        metadata.OnDisplaying(ctx =>
        {
            metadata.Alternates.Add(alternate);
        });
 
       <div>
          @Display(_shape)
       </div>
    }
</section>

and you have in shape tracing :
Create ~/Themes/MyTheme01/Views/Media-"<you parent type>".cshtml
Sep 10, 2013 at 11:03 PM
Negocifal,

Thank´s for your example, it has been very clarifying.

Nuno
Sep 14, 2013 at 9:26 PM
Edited Sep 14, 2013 at 9:29 PM
Question to Gurus:
Am I right that alternates don't work for EditorTemplate?
Instead of :
metadata.OnDisplaying(ctx =>
    {
       metadata.Alternates.Add(alternate);
    });
I should change TemplateName of EditorTemplate, for example in Content.Edit.cshtml :
            foreach (var Item in Model.Content.Items)
            {

                if (Item.TemplateName == "Parts.Comment") 
                { 
                  Item.TemplateName = Item.TemplateName + "-" + Model.parentMetadataType;
                }

                <div class="edit-item-content">
                  @Display(Item)
                </div>
            }
???
Coordinator
Sep 15, 2013 at 12:32 AM
I don't see why they wouldn't work. Where did you put the alternate?
Sep 15, 2013 at 1:24 PM
Edited Sep 15, 2013 at 4:39 PM
BertrandLeRoy wrote:
I don't see why they wouldn't work. Where did you put the alternate?
Sorry, I might ask not clear way : they work, but they work differently.
What I mean is I can not choose EditorTemplate alternate from shape tracing alternates list,
instead, I should put the alternate in
~\Themes\"<MyTheme01>"\Views\EditorTemplates\
folder
And if I want to change the name of the alternate I should change Model.TemplateName property,
instead of puting the name in OnDisplaying event.

Am I right ?
Coordinator
Sep 17, 2013 at 6:09 PM
Well, you can change shape names through placement, too.