Clean zones and widget order

Topics: General
Oct 4, 2011 at 4:42 PM

Hi,

I have a custom zone called Aside. In this zone I have two widgets (one on top of each other). Within coreshapes.cs it wraps the zone in a DIV tag and adds a class zone-aside. I don't want this div so I created an alternative in my theme called Zone.cshtml.

This is fine, except that the ordered_hack function that sits in coreshapes.cs and orders the widgets doesn't get called and my widgets appear in a random order not in the order in which the position is set.

Is there an elegant way to have clean zones and have the widget ordering?

Orchard V1.2

 

Many thanks.

Steve

Oct 12, 2011 at 4:16 PM

Hi,

Does anyone know of a solution to this?

thanks

Steve

Coordinator
Oct 12, 2011 at 9:48 PM

Well, you should in principle be able to reproduce everything the shape method is doing, in your alternate template. You can see a similar thing with the list shape method in this post: http://weblogs.asp.net/bleroy/archive/2011/05/23/orchard-list-customization-first-item-template.aspx

What specific problem do you see when attempting this?

Oct 13, 2011 at 8:14 AM

Hi,

So, my layout.cs file looks like this:

<aside class="sidebar">@Zone(Model.Aside)</aside>

Which produces this end results in the markup:

<aside class="sidebar">
    <div class="zone zone-aside">
        <!-- widgets go here -->
    </div>
</aside>

Now all is fine at this stage except I want to remove the superfluous DIV tag inside my zone. So my next step was to override the Zone.cshml file in my view to eliminate all these DIV's from all my zones. My Zone.cshtml looks like this:

 

@DisplayChildren(Model)

Which works fine, except that the order of which the widgets get displayed in that zone is random and doesn't comply with the "position" of the widget set from the admin screen, The reason for this is that in coreshapes.cs the "ordered_hack" function never gets called due to my override.

So in summary, i want to control the markup fully whilst still maintaining the widget positions.

Is there a way to override the zone wrapper without modifing the coreshapes.cs file?

My first thoughts were to override the shape and replicate the zone shape with modifications:

 [Shape]
        public void Zone(dynamic Display, dynamic Shape, TextWriter Output) {
            string id = Shape.Id;
            IEnumerable<string> classes = Shape.Classes;
            IDictionary<string, string> attributes = Shape.Attributes;
            var zoneWrapper = GetTagBuilder("div", id, classes, attributes);
            Output.Write(zoneWrapper.ToString(TagRenderMode.StartTag));
            foreach (var item in ordered_hack(Shape))
                Output.Write(Display(item));
            Output.Write(zoneWrapper.ToString(TagRenderMode.EndTag));
        }
 private static IEnumerable<dynamic> ordered_hack(dynamic shape) {
            IEnumerable<dynamic> unordered = shape;
            if (unordered == null || unordered.Count() < 2)
                return shape;

            var i = 1;
            var progress = 1;
            var flatPositionComparer = new FlatPositionComparer();
            var ordering = unordered.Select(item => {
                var position = (item == null || item.GetType().GetProperty("Metadata") == null || item.Metadata.GetType().GetProperty("Position") == null)
                                   ? null
                                   : item.Metadata.Position;
                return new { item, position };
            }).ToList();

            // since this isn't sticking around (hence, the "hack" in the name), throwing (in) a gnome 
            while (i < ordering.Count()) {
                if (flatPositionComparer.Compare(ordering[i].position, ordering[i - 1].position) > -1) {
                    if (i == progress)
                        progress = ++i;
                    else
                        i = progress;
                }
                else {
                    var higherThanItShouldBe = ordering[i];
                    ordering[i] = ordering[i - 1];
                    ordering[i - 1] = higherThanItShouldBe;
                    if (i > 1)
                        --i;
                }
            }

            return ordering.Select(ordered => ordered.item).ToList();
        }

But the ordered_hack method is "private" and can't be called externally. Do I need to replicate the Zone shape and ordered_hack method in my new Zone.cshtml to get around this?

Thanks

Steve

Coordinator
Oct 13, 2011 at 9:23 PM

I'm afraid for now you'd have to replicate everything. Maybe it's time to expose that logic publicly and clean it up a bit. Please open a bug for this.

Oct 14, 2011 at 12:13 PM

Bug item created. 

Thanks

Steve

Dec 16, 2013 at 12:28 PM
Hi stevetayloruk.

Did you solve that issue? I have the same problem, i want to override the Zone.cshml to eliminate extra divs, but i want to mantaing the widget positions.
Can you help me?

Thanks
Jul 3, 2014 at 12:11 PM
Hi fudre.
Maybe too late but for anyone having the same isue, you can use CoreShapes.Order static method on your .cshtml file
    @foreach (var item in CoreShapes.Order(Model)) {
        @Display(item.Content)
    }