Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle templates embedded in script tags (WIP) #8

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dmarcotte
Copy link
Owner

Templates which are inlined in an html page can be pretty handy, so let's get the plugin working for them...

The Handlebars docs suggest embedding templates in script tags of type text/x-handlebars-template, so we should support that use case by default, but also ensure that the Handlebars lang definition allows users to inject it where ever they want using Settings->Language Injection.

Note: The current implementation of this relies on the the IntelliLang plugin being installed (it is part of the default plugin bundle, so it probably will be for most users).

@dmarcotte
Copy link
Owner Author

@neuro159 I was hoping I could take you up on your offer for help... I'm running into a blocker trying to implement this feature.

I need to get IDEA to hand over the entirety of certain script nodes to my plugin, but I'm not seeing any way to coax the current language injection code to do my bidding.

The core problem is that the obvious injection host (the text node child of the script node I choose) is incapable of including html tags (the parser creates new nodes for them). Does that make sense?

Here's a sample template, annotated to try and illustrate the problem:

<script type="text/x-handlebars-template">
    <!-- we need everything in this script tag to be handled by the Handlebars plugin -->
    {{#block}} <!-- the current impl will correctly parse this... -->
    <div> <!--... but right here the HTML parser creates a new node and we're no longer in the injection host -->
        {{some template stuff}}
    </div>
    {{/block}}
</script>

I hope that's clear (if not, let me know!). Any guidance would be much appreciated; this is a pretty key feature for the plugin.

@dmarcotte
Copy link
Owner Author

This pull is addressing issue #3

@neuro159
Copy link

I'll try to get one of our specialists give you proper advice on this.

On Sun, Jul 29, 2012 at 10:33 PM, dmarcotte <
[email protected]

wrote:

@neuro159 I was hoping I could take you up on your offer for help... I'm
running into a blocker trying to implement this feature.

I need to get IDEA to hand over the entirety of certain script nodes to my
plugin, but I'm not seeing any way to coax the current language injection
code to do my bidding.

The core problem is that the obvious injection host (the text node child
of the script node I choose) is incapable of including html tags (the
parser creates new nodes for them). Does that make sense?

The code which injects into the appropriate text node is here.
This implementation works great as long there are no HTML tags in the
embedded template (which is obviously not good enough...)

Here's a sample template, annotated to try and illustrate the problem:

<script type="text/x-handlebars-template">
    <!-- we need everything in this script tag to be handled by the
Handlebars plugin -->
    {{#block}} <!-- the current impl will correctly parse this... -->
    <div> <!--... but right here the HTML parser creates a new node and
we're no longer in the injection host -->
        {{some template stuff}}
    </div>
    {{/block}}
</script>

I hope that's clear (if not, let me know!). Any guidance would be much
appreciated; this is a pretty key feature for the plugin.


Reply to this email directly or view it on GitHub:
#8 (comment)

WBR, Alexey

@dmarcotte
Copy link
Owner Author

Thanks!

@dmarcotte
Copy link
Owner Author

Just occurred to me that the workaround discussed in issue #3 wasn't linked here... rectifying that:

Workaround

@rafi
Copy link

rafi commented Sep 18, 2012

Adding my 2cents: Depending on the library used to grab inline templates and rendering them, we're using ICanHaz + Mustache.js, which involves placing an "id" attribute on the script tag, e.g.: <script id="template_numeric_rule" type="text/html">

@dmarcotte
Copy link
Owner Author

@rafi that helps. I hadn't considered that use case... if we can get some traction on this, I'll make sure that case is addressed.

@dmarcotte
Copy link
Owner Author

@neuro159 I see in WI-2914 you guys are working on building an in-house version of Mustache support. Two things about this, one generous and one selfish:

  • Generous: that's awesome! And note that you guys can steal code from this project wholesale if you want. I'd be pumped to know that I helped. Either way, if you guys obsolete this plugin with way better built-in capabilities, I'll be as happy as anyone.
  • Selfish: does this mean I'm not going to get any traction on this request? I'm planning to keep maintaining/improving this plugin until you guys succeed in obsoleting it, so I'd still love a hand if it's possible.

@diosney
Copy link

diosney commented Dec 19, 2012

👍 Any update on this? I've installed this plugin only seeking this very one feature.

@dmarcotte
Copy link
Owner Author

Hey @diosney, glad you're trying out the plugin!

Unfortunately, there's no updates on this yet, but I promise I haven't abandoned it completely. In the meantime, the workaround works pretty well (let me know if that's not true for you...).

@diosney
Copy link

diosney commented Dec 20, 2012

Hey thanks! At least now I don't get these ugly syntax errors!

It seems that code completion neither auto-insert of closing tags aren't working. Any advice on this?

I've using handlebars with multiples templates inside *.html files.

Thanks again :D

@dmarcotte
Copy link
Owner Author

Great! Glad that's working for you.

As for code completion, that's not implemented yet.

Auto-insert of close tags should work though... when you type the final } in an open block mustache like {{#foo)), the plugin will add the {{/foo}} for you. If that's not working on your end, give me some details (what IDE, version, OS, etc.) and I'll get you fixed up.

Oh, and also verify that "Automatically insert close tag" is checked on the Settings->Handlebars/Mustache page.

@diosney
Copy link

diosney commented Dec 20, 2012

Oh, sorry, is working fine, I just misunderstood the functionality itself. It is that I'm too lazy and I wanted the plugin autocompleted the }} brackets for me, haha.

Thanks

@dmarcotte
Copy link
Owner Author

No worries @diosney! Glad things are working well. Hope you enjoy the plugin!

@dmarcotte
Copy link
Owner Author

I've been giving this a renewed look, and digging in the IDEA source I've pretty much validated my hypothesis that the language injection system can't be used for this purpose.

An extension point named HtmlScriptContentProvider was recently added though, and it looks promising... I've opened a thread on the Jetbrains dev forum to see if that (or some other option) will finally unlock this for us.

@fkorotkov
Copy link
Contributor

What if the plugin will just change a file type of an html file with such script tags to handlebars file type?

@dmarcotte
Copy link
Owner Author

Interesting thought @fkorotkov... it didn't occur to me that we could formalize the workaround in the code. It's almost tempting...

Seems risky though. A couple of quick thoughts to illustrate this:

  • this will have some weird corner cases when there are multiple script-tag embedded in the page or when there's mustaches outside a script tag
  • Django and PHP files (which many users of the plugin would like to embed templates in) are almost certain to cause problems. I know for instance that Django templates are not template-able, so we'd need to do extra work to extend this to them.

When I think of this problem, I keep coming back to the fact that language injection gets us sooo close... for example, if you fire up the branch in this pull request, and then inject a Handlebars template into a non-XML injection place, pretty much everything works great (you even get HTML editing if you do "Edit Handlebars Fragment"!). To check it out, any multi-line injection host is pretty convenient; here's a Groovy string for instance:

'''
 {{#foo}}
     <div class="my-class">
         <span>
             Injecting Handlebars here works really well.
         </span>
     </a>
 {{/foo}}
'''

I'm imagining it should be possible to modify XML injection to behave similarly... i.e. if we detect such a script tag, we replace all child Psi Elements of that tag with some special new Xml element (XmlForeignText or something; can't use regular XmlText because of the validations it does on its text) and then we make that an injection host. This would be handy for all sorts of new injections too, and IDEA could start automatically switching on various injections based on the mime type in a script tag's "type" attribute.

What are your thoughts on that?

@fkorotkov
Copy link
Contributor

Thank you for the information! I'll check it. I've just started learning about Handlbars. :-) Where can I find use cases of Handlerbars within Django and PHP?

@dmarcotte
Copy link
Owner Author

My pleasure! Glad to help.

As for Django and PHP, the use case is very similar to the basic HTML usage, just with the wrinkle that project happens to be composing its HTML using Django or PHP. So there's no interaction necessarily between the Django or PHP and the Handlebars; these projects simply do some of their templating on the server side (using Django or PHP), and then end up with an HTML response which contains some js and some Handlebars templates in script tags to be handled on the client side.

These use cases are important for the plugin to consider because we need to make sure that how IDEA Handles those file types does not conflict with anything the plugin does. The Django case in particular is a pretty special case since Django templates have a ".html" extension and are handled by IDEA using language substitution (I found this out the hard way in #40)

Hope that helps... let me know if there's anything else!

@fkorotkov
Copy link
Contributor

Please vote for http://youtrack.jetbrains.com/issue/IDEA-106449

@dmarcotte
Copy link
Owner Author

Voted :)

@fkorotkov
Copy link
Contributor

Thanks! I'll alos try to promote the issue offline. :-)

@ideea
Copy link

ideea commented Oct 22, 2013

+1

@cdeszaq
Copy link

cdeszaq commented Dec 17, 2013

A major usecase for this is with Ember templates. We have our templates in *.html files, and it would be nice to get support in those files.

@dmarcotte
Copy link
Owner Author

Thanks for the note @cdeszaq. Totally agree this would be nice :) Glad to see you voted for the YouTrack issue. We need that enhancement in core to get this feature in, and the votes help it get prioritized.

In the meantime, have you tried the workaround? Should work great for Ember html files.

@dmarcotte
Copy link
Owner Author

Thanks @rodolfo42, really glad you're enjoying the plugin.

And yeah, it's too bad it's been this long, but I know JetBrains does their best to prioritize stuff, and I know the issue votes make a difference, so thanks for adding yours!

@Cediddi
Copy link

Cediddi commented Sep 1, 2016

(2012-2014)-2016 still no merge... I'm disappointed.
I'm also disappointed in WEB-7671 (2013-2014)-2016

@joegaudet
Copy link

Hey, just wondering if there's any plan to add more to this.

@Cediddi
Copy link

Cediddi commented Nov 25, 2019

I don't think so joe. There's an issue that covers this but that issue is also seems dead.

https://youtrack.jetbrains.com/issue/WEB-679

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants