Run script in wkhtmltopdf process - javascript

I use wkhtmltopdf to create pdf(s) from html(s)
I have next function :
private void CreateTempPdf(string htmlPath, string pdfPathTemp)
{
var processorInfo = new System.Diagnostics.ProcessStartInfo
{
Arguments =
"--margin-top 27 \"" + htmlPath + "\" \"" + pdfPathTemp +
"\" ",
FileName = PublisherConfigurationManager.Pdf2HtmlConverter,
UseShellExecute = true
};
using (var proc = new System.Diagnostics.Process())
{
proc.StartInfo = processorInfo;
proc.Start();
proc.WaitForExit();
}
}
in which i pass paths of html file and destination file.
I want to add some js script to run, before pdf will be generated.
I add my code : --run-script <js> into Arguments after pdfPathTemp but script isn't applied to pdf. I also add it before --margin but this case also doesn't help me.
How correctly add scripts into wkhtmltopdf process?

I would simply add the script directly into the HTML page. In this case I would load the HTML from the path into a string, inject the script, then write a tempfile for the process duration.
As for why --run-script does not work, I have no idea. Have you tried it directly in the command line with a very simple script and HTML to see if a minimal example works for you?
If that is not an option, you might have to play around with different files for differnt js arguments, if you require such things.

Related

Require file in Cypress using string templates

I'm trying to require a js file in cypress and it works with a static string but as soon as I try string templates, it no longer finds the file.
const page = require('../../cypress/model/page/web/app/Homepage.js');
//const page = require(`../../cypress/model/page/web/app/${pageName}.js`);
As # pavelsaman already commented, you should first check what is in pagename. simply a console.log(pagename). Maybe you can find the error here.
If pagename looks good you can try with concatination:
pageName = 'somePage' + '.js';
const page = require('../../cypress/model/page/web/app/' + pageName);

Python/Javascript - Self Updating Webpage

I am hoping that I can be pointed in the right direction as I am completely unsure of how to approach the task I have at hand. I have created a python program that is able to execute some tests and gather information pertinent to the test. My task at hand is to make it so that the information I get is put on a webpage.
The way I am handling the directory is as follows
Project
|
+--index.html
+--testcases
|
+--testline1
|
+--build1
|
+--date1
|
+--relevantdata.txt
+--index.html
+--date2
+--build2
+--testline2
+--testline3
Every time I complete a testcase I update the appropriate testline + build by creating a directory with the date and putting relevant information in that directory. Every test case I run creates it's own html page that I would like to be accessible to the user.
Is there a way for me to update the outermost index.html automatically to reflect these changes? I am imagining that the html page will have a sidebar that lets the user pick testline + build + date. Is there a way to update this menu when test cases are completed?
so let me understand this correctly:
you have script.py that does some magic, and creates testline N directory + associated files. you then want Project/index.html to list all N testlines.
is that correct?
if so, the SIMPLEST way to achieve this is to code the html in a python string, and then programmatically add the new testline link to that string, and then finally write that string to a index.html file.
another way to do this is to create a javascript (jquery) in a "mylinks.js" file and have that mylinks.js loaded in index.html
<script src="mylinks.js" type="text/javascript">
your my links would look something like this:
$window.onload(function() {
var $input = $('<input type="button" value="TESTLINE - N" />');
$input.appendTo($("body"));
});
now all you need to do is programatically (in python), write the for loop in mylinks.js
string = ''
for [python get number of dirs matching testlineN]:
string += '$window.onload(function() {
var $input = $('<input type="button" value="TESTLINE - N" />');
$input.appendTo($("body"));
});'
python write to file
some what pseudo code ish, but you should get the gist of it,

Adding a javascript file to an already-running Java FX webengine

I have a Java application that is running a Java FX webengine (the end goal of all of this is to dynamically draw a D3.js plot). I'd like to be able to add new javascript files to it while it's already running, and then ideally unload them again when the javascript tells it to.
This has the effect of making some functionality available to the user or not (drawing certain features) without having to load all of the code in at once. It also helps me avoid future headaches with a forest of brittle if/then statements inside my javascript.
Question 1: Is "unloading" files from a running webengine even possible? At least, possible without redrawing the whole thing. I'm pretty sure that calling loadContent() with my new filepaths will make them available the way that I want, but I haven't come across anything talking about how you can remove existing source code from your HTML block.
Question 2: Any recommendations on how to elegantly approach feeding the extra sources into the webView? My thought process right now is stuck on brute force, but I haven't been even been able to brute force my way to a solution that works, so maybe I'm barking up the wrong tree.
Question 3: Is this even a good idea? It's possible to do this solely in the Javascript, but I want the appearance and disappearance of options directly tied to a java-side feature that's later going to be executed from the class Bridge, the same place I'm trying to load new content from right now.
I asked a lot of questions, but any help is appreciated!
Right now I am setting up the webengine's content like so:
final ResourceExtractor RESOURCE_EXTRACTOR
= new ResourceExtractor(JavaScriptPlot.class);
// prepare the local URI for d3.js
final URI D3_JS_URI = RESOURCE_EXTRACTOR
.extractResourceAsPath("d3.min.js")
.toUri();
// prepare the local URI for numeric.js
final URI NUMERIC_JS_URI = RESOURCE_EXTRACTOR
.extractResourceAsPath("numeric.min.js")
.toUri();
// prepare the local URI for topsoil.js
final URI TOPSOIL_JS_URI = RESOURCE_EXTRACTOR
.extractResourceAsPath("topsoil.js")
.toUri();
// build the HTML template (comments show implicit elements/tags)
HTML_TEMPLATE = (""
+ "<!DOCTYPE html>\n"
// <html>
// <head>
+ "<style>\n"
+ "body {\n"
+ " margin: 0; padding: 0;\n"
+ "}\n"
+ "</style>\n"
// </head>
+ "<body>"
+ "<script src=\"" + D3_JS_URI + "\"></script>\n"
+ "<script src=\"" + NUMERIC_JS_URI + "\"></script>\n"
+ "<script src=\"" + TOPSOIL_JS_URI + "\"></script>\n"
+ "<script src=\"%s\"></script>\n" // JS file for plot
// </body>
// </html>
+ "").replaceAll("%20", "%%20");
The source path to replace %s is created here:
public class BasePlot extends JavaScriptPlot {
private static final ResourceExtractor RESOURCE_EXTRACTOR
= new ResourceExtractor(BasePlot.class);
private static final String RESOURCE_NAME = "BasePlot.js";
public BasePlot() {
super(
RESOURCE_EXTRACTOR.extractResourceAsPath(RESOURCE_NAME),
new BasePlotDefaultProperties());
}
}
And then later I take a file path already extracted as a resource, sourcePath, and insert it into the HTML block:
String buildContent() {
return String.format(HTML_TEMPLATE, sourcePath.toUri());
}
Then I build my web view using the return value of buildContent()
private void initializeWebView() {
runOnFxApplicationThread(() -> {
// initialize webView and associated variables
webView = new WebView();
webView.setContextMenuEnabled(false);
WebEngine webEngine = webView.getEngine();
webEngine.getLoadWorker().stateProperty().addListener(
(observable, oldValue, newValue) -> {
if (newValue == SUCCEEDED) {
if (new IsBlankImage().test(screenCapture())) {
webEngine.loadContent(buildContent());
}
topsoil = (JSObject) webEngine.executeScript("topsoil");
topsoil.setMember("bridge", new Bridge());
}
});
// asynchronous
webEngine.loadContent(buildContent());
});
}
And the Javascript can fire off the method in the class below to trigger the change. Right now it's manually creating a hardcoded resource, but once I work out once going wrong I'll make this part more elegant/logically organized.
//loads appropriate JS files into webview based on BasePlot's isotope type
public class Bridge {
final URI ISOTOPE_URI = ISOTOPE_RESOURCE_EXTRACTOR
.extractResourceAsPath("Concordia.js")
.toUri();
String finalHtml = buildContent().concat("<script src=\""+ISOTOPE_URI.toString()+"\"></script>\n");
webView.getEngine().loadContent(finalHtml);
}
}
The loadContent() above is giving me an application thread error: "ReferenceError: Can't find variable: topsoil"

Printing multiple files through javascript

I need to print multiple files using javascript. Print single file works fine but as soon as I try and print multiple files, I get only one printed.
My javacript is as under
function LoadPrint() {
if (document.getElementById("pdf").src !== "") {
var frm = document.getElementById("pdf").contentWindow;
frm.focus();
frm.print();
}
return false;
}
and I call it from c# as below
foreach (var str in filenames)
ClientScript.RegisterStartupScript(this.GetType(), "Print", "LoadPdfFile('" + "/Templates/" + str + "');", true);
How can I tell RegisterStartupScript to wait until the file is printed?
If you have a component to generate a pdf, you'll have the functionality to create one pdf by merging many.
I suggest you write a method to create a new pdf with a pagebreak between each one and let the server handle it instead of the client

WIX: Where and how should my CustomAction create and read a temporary file?

I have a script CustomAction (Yes, I know all about the opinions that say don't use script CustomActions. I have a different opinion.)
I'd like to run a command, and capture the output. I can do this using the WScript.Shell COM object, then invoking shell.Exec(). But, this flashes a visible console window for the executed command.
To avoid that, I understand I can use the shell.Run() call, and specify "hidden" for the window appearance. But .Run() doesn't give me access to the StdOut of the executed process, so that means I'd need to create a temporary file and redirect the exe output to the temp file, then later read that temp file in script.
Some questions:
is this gonna work?
How do I generate a name for the temporary file? In .NET I could use a static method in the System.IO namespace, but I am using script here. I need to insure that the use has RW access, and also that no anti-virus program is going to puke on this.
Better ideas? I am trying very hard to avoid C/C++.
I could avoid all this if there were a way to query websites in IIS7 from script, without resorting to the IIS6 Compatibility pack, without using .NET (Microsoft.Web.Administration.ServerManager), and without execing a process (appcmd list sites).
I already asked a separate question on that topic; any suggestions on that would also be appreciated.
Answering my own question...
yes, this is going to work.
Use the Scripting.FileSystemObject thing within Javascript. There's a GetTempName() method that produces a file name suitable for temporary use, and a GetSpecialFolder() method that gets the location of the temp folder. There's even a BuildPath() method to combine them.
so far I don't have any better ideas.
Here's the code I used:
function GetWebSites_IIS7_B()
{
var ParseOneLine = function(oneLine) {
...regex parsing of output...
};
LogMessage("GetWebSites_IIS7_B() ENTER");
var shell = new ActiveXObject("WScript.Shell");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var tmpdir = fso.GetSpecialFolder(SpecialFolders.TemporaryFolder);
var tmpFileName = fso.BuildPath(tmpdir, fso.GetTempName());
var windir = fso.GetSpecialFolder(SpecialFolders.WindowsFolder);
var appcmd = fso.BuildPath(windir,"system32\\inetsrv\\appcmd.exe") + " list sites";
// use cmd.exe to redirect the output
var rc = shell.Run("%comspec% /c " + appcmd + "> " + tmpFileName, WindowStyle.Hidden, true);
// WindowStyle.Hidden == 0
var ts = fso.OpenTextFile(tmpFileName, OpenMode.ForReading);
var sites = [];
// Read from the file and parse the results.
while (!ts.AtEndOfStream) {
var oneLine = ts.ReadLine();
var line = ParseOneLine(oneLine);
LogMessage(" site: " + line.name);
sites.push(line);
}
ts.Close();
fso.DeleteFile(tmpFileName);
return sites;
}

Categories

Resources