I used ejs and heredoc to compile xml files :
const ejs = require('ejs');
const heredoc = require('heredoc');
var tpl = heredoc(function(){/*
<xml>
<ToUserName><![CDATA[<%= toUserName %>]]></ToUserName>
<FromUserName><![CDATA[<%= fromUserName %>]]></FromUserName>
....
</xml>
*/});
however,after using jslint and compiling by babel,it becomes like this :
var ejs=require("ejs"),heredoc=require("heredoc"),
tpl=heredoc(function(){});
the content in heredoc was missing. It seems that the compiler regards the code inside as comments.
Does anyone know how to solve this ?
Related
Overview:
I am working on a project that has dozens of .Liquid (Shopify) snippets with <script> tags inside of them containing JS code.
They're similar to HTML, they look something like this:
{% assign variable = 'test' %}
<p>hey {{variable}}</p>
<script>console.log("hey")</script>
{% schema %}
{
...json stuff
}
{% endschema %}
Issue:
Basically what I wanna do is get the content inside <script>, manipulate it and replace with the new manipulated one.
I managed to do this using cheerio, but it ends up messing up the Liquid variables since it doesn't recognize them.
My previous code was looking something like this:
let html = cheerio.load(code, { _useHtmlParser2: true });
const { data: js } = html("script").get()[0].children[0];
html("script").get()[0].children[0].data = await minifyJS(js);
const result = html.html();
Expected Behavior:
I need to:
Find all script tags in a HTML string;
Get the code inside of the <script> tag;
Manipulate this code (minify, essentially);
Replace it with the now minified code.
I am trying to avoid using regex, but I can't foresee any other solutions.
Any suggestion is greatly appreciated.
Thank you!
To get the content inside tags you can use Regular Expressions
<script(.|\n)*?<\/script>
This is just the regex
let str = <Whatever string or data you want to extract script tags>;
let result = let result = str.match(/<script(.|\n)*?<\/script>
/g);
console.log(result);
in result you will get the content inside the script tag
I am using Showdown.
When I run this code:
const showdown = require("showdown")
converter = new showdown.Converter()
const myMarkdownText = '## Some important text'
const myHtmlText = converter.makeHtml(myMarkdownText)
I get
<h2 id="someimportanttext">Some important text</h2>
which is the expected result.
But when I run this code:
const showdown = require("showdown")
converter = new showdown.Converter()
const myMarkdownText = '<div markdown = "1"> ## Some important text </div>'
const myHtmlText = converter.makeHtml(myMarkdownText)
I get
<div markdown = "1"><p>## Some important text </p></div>
Which means that Showdown didn't parse the stuff inside the html div.
Any help on how to make it work?
After reading the Showdown documentation (https://github.com/showdownjs/showdown#valid-options) my conclusion is that you should probably enable the backslashEscapesHTMLTags option and backslash the html tags.
A bit late but for future reference:
To enable parsing of markdown inside HTML tags you have to put markdown="1" as a property on the HTML tag like:
<div markdown="1"># I will be parsed</div>
There is more information in the documentation
I am using express-handlebars in my project and have the following problem:
Question
I want to be able to add <script> oder such tags to my overall views head from a partial that is called inside the view.
Example:
The view
{{#layout/master}}
{{#*inline "head-block"}}
<script src="some/source/of/script">
{{/inline}}
...
{{>myPartial}}
{{/layout/master}}
The view is extending another partial (layouts/master) that I use as a layout. It adds its content to that ones head block through the inline partial notation, which works fine
the Partial "myPartial
<script src="another/script/src/bla"></script>
<h1> HELLO </h1>
Now I would like that particular script tag in there to be added to my views head-block. I tried going via #root notation but can only reference context there. Not change anything.
I know I could use jquery or similar to just add the content by referencing the documents head and such. But I wanted to know if this is possible at all via Handlebars.
I do doubt it is in any way. But if you have any ideas or suggestions, please do send them my way! Many thanks!!!
UPDATE
This wont work if you have more than one thing injected into your layout / view. Since this happens when the browser loads the page, it creates some kind of raceconditions where the helpers has to collect the things that have to be injected into the parent file. If its not quick enough, the DOMTree will be built before the helper resolves. So all in all, this solution is NOT what I hoped for. I will research more and try to find a better one...
Here is how I did it. Thanks to Marcel Wasilewski who commented on the post and pointed me to the right thing!
I used the handlebars-extend-block helper. I did not install the package, as it is not compatible with express-handlebars directly (Disclaimer: There is one package that says it is, but it only threw errors for me)
So I just used his helpers that he defines, copied them from the github (I am of course linking to his repo and crediting him!) like so:
var helpers = function() {
// ALL CREDIT FOR THIS CODE GOES TO:
// https://www.npmjs.com/package/handlebars-extend-block
// https://github.com/defunctzombie/handlebars-extend-block
var blocks = Object.create(null);
return {
extend: function (name,context) {
var block = blocks[name];
if (!block) {
block = blocks[name] = [];
}
block.push(context.fn(this));
},
block: function (name) {
var val = (blocks[name] || []).join('\n');
// clear the block
blocks[name] = [];
return val;
}
}
};
module.exports.helpers = helpers;
I then required them into my express handlebars instance like so:
let hbsInstance = exphbs.create({
extname: 'hbs',
helpers: require('../folder/toHelpers/helpersFile').helpers() ,
partialsDir: partialDirs
});
Went into my central layout/master file that`is extended by my view Partial and added this to its <head> section
{{{block 'layout-partial-hook'}}}
(The triple braces are required because the content is HTML. Else handlebars wont recognize that)
Then in the partial itself I added things like so:
{{#extend "layout-partial-hook"}}
<link rel="stylesheet" href="/css/index.css"/>
{{/extend}}
And that did the trick! Thanks!!!
I am using cheerio to mutate a xml file in node. I am inserting the node/element <target> after <source> which works with the insertAfter() api in oldEl.translation.insertAfter(msgSourceEl);.
However, I loose my indention:
<trans-unit id="title" datatype="html">
<source>Login</source><target>iniciar sesión</target>
Is it possible, or is there a way, to indent the newly inserted <target>iniciar sesión</target> underneath the <source> element?
Just fix the final XML indentation :
It is possible to use xml-beautifier to achieve the human-readable indented XML
import beautify from 'xml-beautifier';
const HumanXML = beautify(XML);
console.log(HumanXML); // => will output correctly indented elements
(EXTRA) No need for Cheerio :
In the following example we will be using xml2js to manipulate the XML as a JSON and then build it back to the original XML format
var xml2js = require('xml2js');
var xml = "<trans-unit id=\"title\" datatype=\"html\"><source>Login</source></trans-unit>"
xml2js.parseString(xml, function (err, result) {
result["trans-unit"].target=["iniciar sessión"]
var builder = new xml2js.Builder();
var xml = builder.buildObject(result);
console.log(xml)
});
Final Output :
<trans-unit id="title" datatype="html">
<source>Login</source>
<target>iniciar sessión</target>
</trans-unit>
I am sure you are doing this as part of a loop, so it shouldn't be hard to extrapolate the example to make it work . I suggest using underscore for the usual (each, map, reduce, filter...)
First of all, since source is an empty element, cheerio does not keep the <source>Login</source>. It converts it to <source>Login
So for demonstrating element indentation I will use a <source2> element.
As shown below, providing newlines and tabs as part of the given html solves the issue.
let $ = require('cheerio').load(`
<trans-unit id="title" datatype="html">
<source2>Login</source2>
</trans-unit>`)
$(`
<target>iniciar sesión</target>`).insertAfter($('source2'));
console.log($.html('trans-unit'))
output
<trans-unit id="title" datatype="html">
<source2>Login</source2>
<target>iniciar sesión</target>
</trans-unit>
I have a global header used in a couple of places and I was trying to define its location in a variable that could be passed when rendering a template.
Something like:
var headerLocation = 'some/location/header.ejs';
res.render( viewDir + '/index', {
header: headerLocation
} );
And in a template file:
<% include header %>
header being the value passed in with the render.
It doesn't seem to be possible but maybe I missed something so thought I'd ask here.
EDIT:
This is mentioned in comments on answers below but to summarize, this is now available in version 2 of EJS.
See here: https://github.com/mde/ejs#includes
And related discussion here: https://github.com/tj/ejs/issues/93
Here is some demo code that can accomplish dynamic includes.
View
<div flex class="main-container">
<%- include(page) %>
</div>
Router
router.get('/', function (req, res, next) {
res.render('pages/index', {
page: 'home'
});
});
This feature has been added: if it is not path (file not found), it is evaluated as variable name. https://github.com/visionmedia/ejs/pull/156
Even though its an old question, answering it for others sake.
As per the github documentation, it seems EJS has no notion of blocks, only compile-time include. Since its compile time include, you need to hardcode the location.
So you are left with passing some flags and doing if checks in the header or parse the header as html and pass it to all the templates...
Old subject, but it may help someone.
The great thing about EJS is that it is just Javascript. So something like the following should work:
<%
const fs = require('fs');
const content = fs.readFileSync(partial);
%>
<%- content %>
Hope it helps.