How to avoid " returned from twing - twig

I am using twig as below
res.render("screen/index.twig", {
name: 'word',
columns: columns,
});
It is working as excepted.
Now I want to switch to twing and used below code
const contents = await twing
.render("screen/index.twig", {
name: 'word',
columns: columns,
})
res.end(contents);
here contents give below
...
<script>
window.COLUMNS = [{"alignment":"left"}];
</script>
...
But I need the below output without using any .replace function. How can I achieve this? Can anyone tell why it working in twig and not in twing? Thanks.
...
<script>
window.COLUMNS = [{"alignment":"left"}];
</script>
...

Related

Cheerio how to remove DOM elements from selection

I am trying to write a bot to convert a bunch of HTML pages to markdown, in order to import them as Jekyll document. For this, I use puppeteer to get the HTML document, and cheerio to manipulate it.
The source HTML is pretty complex, and polluted with Google ADS tags, external scripts, etc. What I need to do, is to get the HTML content of a predefined selector, and then remove elements that match a predefined set of selectors from it in order to get a plain HTML with just the text and convert it to markdown.
Assume the source html is something like this:
<html>
<head />
<body>
<article class="post">
<h1>Title</h1>
<p>First paragraph.</p>
<script>That for some reason has been put here</script>
<p>Second paragraph.</p>
<ins>Google ADS</ins>
<p>Third paragraph.</p>
<div class="related">A block full of HTML and text</div>
<p>Forth paragraph.</p>
</article>
</body>
</html>
What I want to achieve is something like
<h1>Title</h1>
<p>First paragraph.</p>
<p>Second paragraph.</p>
<p>Third paragraph.</p>
<p>Forth paragraph.</p>
I defined an array of selectors that I want to strip from the source object:
stripFromText: ['.social-share', 'script', '.adv-in', '.postinfo', '.postauthor', '.widget', '.related', 'img', 'p:empty', 'div:empty', 'section:empty', 'ins'],
And wrote the following function:
const getHTMLContent = async ($, selector) => {
let value;
try {
let content = await $(selector);
for (const s of SELECTORS.stripFromText) {
// 1
content = await content.remove(s);
// 2
// await content.remove(s);
// 3
// content = await content.find(s).remove();
// 4
// await content.find(s).remove();
// 5
// const matches = await content.find(s);
// for (m of matches) {
// await m.remove();
// }
};
value = content.html();
} catch(e) {
console.log(`- [!] Unable to get ${selector}`);
}
console.log(value);
return value;
};
Where
$ is the cheerio object containing const $ = await cheerio.load(html);
selector is the dome selector for the container (in the example above it would be .post)
What I am unable to do, is to use cheerio to remove() the objects. I tried all the 5 versions I left commented in the code, but without success. Cheerio's documentation didn't help so far, and I just found this link but the proposed solution did not work for me.
I was wondering if someone more experienced with cheerio could point me in the right direction, or explain me what I am missing here.
I found a classical newby error in my code, I was missing an await before the .remove() call.
The working function now looks like this, and works:
const getHTMLContent = async ($, selector) => {
let value;
try {
let content = await $(selector);
for (const s of SELECTORS.stripFromText) {
console.log(`--- Stripping ${s}`);
await content.find(s).remove();
};
value = await content.html();
} catch(e) {
console.log(`- [!] Unable to get ${selector}`);
}
return value;
};
You can remove the elements with remove:
$('script,ins,div').remove()

I want to show images in my "index" with some delay

The images are named as "0.png", "1.png"...
at the moment I can only see the fourth picture.
How can I make them all show with 0.5 seconds delay?
const rootComponent = {
template: `<div style="text-align:center">
<QR/>
</div>`,
};
const QRComponent = {
created: function() {
for(let x=1;x<5;x++)
{
this.img = "685287/"+x+".png";
}
},
template: `<div class="QR"> <img v-bind:src='img'></div>`
};
const app = Vue.createApp(rootComponent);
app.component('QR', QRComponent);
const vm = app.mount("#app");
Your for loop is renaming the same property 4 times before returning. By the time the template is evaluated, this.img is only assigned to the most recent value in the loop. You need to do one of two things:
get rid of the loop and create 4 QR components that each set this.img only once
change this.img to an array and make your template iterate over the image array.
I'm not familiar with vue, but to get the 500ms delay you could probably set the values of this.img in a window.setTimeout()

Use jQuery for move variable to another html and load it

I'm working with twig for render data.
Here is my code:
function addProduct(product_id, product_image, product_name) {
product_ids.push(parseInt(product_id));
// console.log(file_id);
$.each(product_ids, function (i, val) {
products[i]= {id: product_id, image: product_image, name: product_name};
})
console.log(products);
$("#search-pop").slideUp();
$(".list-selected-product").append(
{% include '_layout/include/_render_product_select.html.twig' with {'products': products} %}
);
// console.log($(".list-selected-product").html(products));
}
Now i want to render_product_select but i don't know how can transmission products to this.
Please help me!
Thank so much.

Handlebars.js misses JSON data

I've got template file loaded by Require.js via this:
main-app.js
define([
'backboneLoader',
'handlebars',
'text!templates/main.html',
'text!appdata.json'
],
function(
Backbone,
Handlebars,
MainTemplate,
AppData
) {
"use strict";
return Backbone.View.extend({
initialize : function() {
this.render();
},
render : function() {
var template = Handlebars.compile(MainTemplate);
var output = template(AppData);
this.$el.append(output);
console.log("appData:\n" + AppData);
console.log("MainTemplate:\n" + MainTemplate);
console.log("Output:\n" + output);
//smth extra
return this;
}
});
}
);
MainTemplate (main.html)
<ul>
<li><b>Version:</b> {{version}}</li>
<li><b>Author:</b> {{author}}</li>
</ul>
AppData (appdata.json)
{version: "0.0.1", author: "John Doe"}
And output:
<ul>
<li><b>Version:</b></li>
<li><b>Author:</b></li>
</ul>
While expected output:
<ul>
<li><b>Version:</b> 0.0.1</li>
<li><b>Author:</b> John Doe</li>
</ul>
Any ideas what am I doing wrong? Thank you!
UPD:
Problem solved. Here is updated main-app.js:
define([
'backboneLoader',
'handlebars',
'text!templates/main.html!strip',
'text!appdata.json'
],
function(
Backbone,
Handlebars,
mainTemplate,
appData
) {
"use strict";
return Backbone.View.extend({
initialize : function() {
this.render();
},
render : function() {
var template = Handlebars.compile(mainTemplate);
var output = template(eval("(" + appData + ")")); //Object is expected by template(), not JSON.
this.$el.append(output);
console.log("appData:\n" + appData);
console.log("template:\n" + mainTemplate);
console.log("Output:\n" + output);
//smth extra
return this;
}
});
}
);
The problem is AppData is a string of JSON, not an actual Object. Simply change from:
var output = template(AppData);
to
var output = template(JSON.parse(AppData));
You may need to include json2.js to add JSON support for older browsers (<=IE7).
Here is a jsFiddle repro of your template function, the template transformations seems working, the problem is probably located in the text! function in require.js code, try to debug the text! function.
Try also to add the !strip function when loading the template: 'text!templates/main.html!strip',
The documentation suggests it :For HTML/XML/SVG files, there is another option. You can pass !strip, which strips XML declarations so that external SVG and XML documents can be added to a document without worry.

plotting Graph with flot

I want to plot graph using flot and mysql but an exception occurs
getData.php
$sql = mysql_query("SELECT count(Msg_ID) as msgCount,From_user
FROM Messages
GROUP BY From_user");
echo "[";
while($result = mysql_fetch_array($sql))
{
//print_r($result);
echo "[".$result['msgCount'].",".$result['From_user']."]"."\n";
}
echo "]";
And for plotting
<div id="plotarea" style="width:600px;height:300px;">
<script type="text/javascript">
var options = {
lines: { show: true },
points: { show: true },
xaxis: { min:0,max:5 },
yaxis: { min:1 ,max:60},
};
$.ajax({
url:"getData.php",
type:"post",
success:function(data)
{
alert(data);
$.plot($("#plotarea"),data,options);
//alert(data);
}
})
</script>
</div>
What is wrong with this code?
Next I want to plot graph with one of the axis is time.
$sql = mysql_query("SELECT count(Msg_ID) as msgCount,From_user
FROM Messages
GROUP BY From_user");
while($result = mysql_fetch_array($sql))
{
$user_data[] = array($result['msgCount'],$result['From_user']);
}
echo json_encode($user_data);
The above will eliminate issues with comma separation (which, from what I can tell, you never resolved).
Next, the javascript:
<script type="text/javascript">
$(function () {
var options = {
lines: { show: true },
points: { show: true },
xaxis: { min:0,max:5 },
yaxis: { min:1 ,max:60},
};
$.get("getData.php", function(data){
$.plot($("#plotarea"),data,options);
},
json);
});
</script>
Notice that I changed $.ajax to $.get, since you weren't passing any data from the page to the script, a post is not necessary. And if you use $.get, all of the setting names are assumed.
Also notice that I pulled the script out of the html and put it within the jquery window.onload syntax : $(function () { . This would go in the head of your html.
From what I can tell, you aren't really in need of ajax, since you didn't define any sort of event that would trigger the $.ajax function. It looks like you are using ajax to call a script when you could just put the script into the same script that loads the page, like:
<?php
$sql = mysql_query("SELECT count(Msg_ID) as msgCount,From_user
FROM Messages
GROUP BY From_user");
while($result = mysql_fetch_array($sql))
{
$user_data[] = array($result['msgCount'],$result['From_user']);
}
?>
<script type="text/javascript">
$(function () {
var options = {
lines: { show: true },
points: { show: true },
xaxis: { min:0,max:5 },
yaxis: { min:1 ,max:60},
};
var userposts = <?php echo json_encode($user_data); ?>;
$.plot($("#plotarea"),userposts,options);
</script>
<style type="text/css">
#plotarea {
width: 600px, height: 300px;
}
</style>
</head>
<body>
.....//Put whatever before the div
<div id="plotarea"></div>
.....//Finish up the page.
Firstly it looks like the JavaScript list you are creating with your PHP code isn't separating each data point list item with a comma separator.
According to the jQuery $.ajax documentation the first argument passed to the success function is the data returned from the server, formatted according to the 'dataType' parameter. You haven't provided a dataType parameter. The docs say it will intelligently pass either responseXML or responseText to your success callback, based on the MIME type of the response if no dataType has been specified.
I'm guessing the data getting passed to the plot function is a plain old string instead of a JavaScript list object as expected by Flot. Adding a dataType: 'json' option to your $.ajax call should fix this up.
What you're trying to output is a json document in the php side, which will directly be parsed to a java script array (either manually or automatically by libraries like jquery)
So there is no need to print json in php instead you can easily feed data into a php array and use the json_encode function to easily convert it to a json string.
A small example could help
you were trying to output
echo "[".$result['msgCount'].",".$result['From_user']."]"."\n";
which in java script [] = array and you are creating [[]] = array inside array.
But when the array is big, it's cumbersome to echo in php.
What do we do.
An array structure is similar in php.
You will need to add data into php as an "array inside array"
eg: php array(array(1,2,3)) = [[1,2,3]].
How to map it to json?
easy==> echo json_encode(array(array(1,2,3));
Cheers

Resources