Eugene Khudoy
Eugene Khudoy

Reputation: 211

Orchard. How to render something before 'HeadScripts' shape?

Sometimes javascript code needs some data from server (e.g. constants or configs shared between JS and C#). I don't want to pull this data via Ajax. I want to render this data into html page on server.

Let's say, I have a component which consits of C# server-side code and JS client-side code. Component defines some C# constants to be provided for a specific JS code. This definition can be done somehow in ResourceManifest. Defined C# constants should be rendered into html before JS script links. The first part of JS links is rendered in 'HeadScripts' shape.

The question is how to render something before 'HeadScripts' shape?

I tried to wrap 'HeadScripts' shape. But it didn't help.

Wrapper in IShapeTableProvider implementation:

builder.Describe("HeadScripts").Configure(desc => desc.Wrappers.Add("HeadScriptsWrapper"));

HeadScriptsWrapper.cshtml:

<script>
    var ServerConstants = {
        const1: 'value1',
        const2: 'value2'
    };
</script>
@Display(Model.Child)

The result is:

...
<script src="/.../jquery-1.11.1.js" type="text/javascript"></script>
<script src="/.../some.js" type="text/javascript"></script>
<script src="/.../onemore.js" type="text/javascript"></script>
...
<meta content="Orchard" name="generator" />
<meta content="utf-8" name="charset" />
...
<link href="/.../favicon.png" rel="shortcut icon" type="image/x-icon" />
<script>
    var ServerConstants = {
        const1: 'value1',
        const2: 'value2'
    };
</script>

As you can see code from wrapper is rendered after 'HeadScripts'. Please help.

Upvotes: 2

Views: 165

Answers (1)

Eugene Khudoy
Eugene Khudoy

Reputation: 211

I've managed to render custom string before 'HeadScripts' shape.

public class BeforeHeadScriptsShapeProvider : IShapeTableProvider
{
    private readonly Work<IOrchardServices> orchardServices;

    public BeforeHeadScriptsShapeProvider(Work<IOrchardServices> orchardServices)
    {
        this.orchardServices = orchardServices;
    }

    public void Discover(ShapeTableBuilder builder)
    {
        builder.Describe("HeadScripts")
            .OnCreated(created =>
            {
                orchardServices.Value.WorkContext.Layout.Head.Add(created.New.BeforeHeadScriptsShape());
            });
    }

    [Shape]
    public void BeforeHeadScriptsShape(HtmlHelper Html)
    {
        Html.ViewContext.Writer.WriteLine("<script type=\"text/javascript\"> alert('TEST');</script>");
    }
}

I can't explain this code in details, but I've found that some shapes are rendered through TextWriter Output parameter. But Output always renders after 'HeadScripts'. 'HeadScripts' (which is a set of 'Script' shapes) uses writer from HtmlHelper Html parameter. So, using HtmlHelper Html allows you to render custom content before 'HeadScripts'.

Upvotes: 1

Related Questions