I'm using PhantomJS 2.1.1
to be able to grab a webpage and generate a screenshot.
It's working... BUT I want do to some DOM manipulation (in javascript) before rendering the page into a png.
What I am doing is (in few step to summarize):
page.open(http://my_url.htm), function(status) {
if (status === 'sucess') {
waitFor(isPageLoaded, grabPage, 30000); //waitFor function is one provided by PhantomJS in example
}
};
function grabPage() {
page.render('screenshot_raw.png'); //this is working well
page.evaluate(function() {
document.querySelector('[id^="boardBackgroundImg-"]').style.filter = 'invert(1)';
}
page.render('screenshot_remodel.png'); //same screenshot as before
phantom.exit();
}
When doing myself in a firefox consol, the:
document.querySelector('[id^="boardBackgroundImg-"]').style.filter = 'invert(1)';
it's working weel!
But into my phantomjs script... it does nothing (but no error).
I've tried to put it in a external js file and use injectJS() or includeJS() but it does not help more.
Is someone having an idea?
Obviously I want to do some little bit more DOM transformation (removing some node).
Regards.
Update
I've updated my code to do at the end:
fs.write("test.htm", page.content, 'w');
phantom.exit()
The file content does not contains the DOM change I've provided.
So it seems that page.evaluate(...) is readonly. Just here to grab data from page content.
Is there a way to modify the DOM before rendering the page in PhantomJS?
Regards
PhantomJS v2.1.1's Webkit rendering engine is rather old now and it doesn't fully support modern CSS or Javascript. Try using puppeteer if you can.
Related
I'm attempting to dynamically conditionally load additional JavaScript while using hyperHTML. I've narrowed the failure to the onload event.
Here's an attempt at a minimal, complete, and verifiable example:
class ScriptLoader extends hyperHTML.Component {
onload(event) {
notie.alert({ text: "notie loaded" });
}
render() {
return this.html`
<script
src=https://unpkg.com/notie
type=text/javascript
async=false
onload=${this}
/>
`;
}
}
hyperHTML.bind(document.body)`
<h2>onload test (notie)</h2>
${new ScriptLoader}
`;
<script src="https://unpkg.com/hyperhtml#2.4.0/min.js"></script>
As you can see notie.alert is never called, even though the script is inserted correctly.
This some process works correctly using vanilla JS with addEventListener('load', and appendChild(.
Update this was an issue with Firefox and Web (Safari) considering death nodes scripts injected via innerHTML, even if through a template and after imported.
That means the issue was not with the onload per-se, rather the fact no network request was ever triggered so that onload would never happen indeed.
As you can verify now in the Code Pen eaxmple, which uses your exact same snippet I rewrite in part to make SO happy about me linking Code Pen, both Firefox and Safari, as well as Chrome and Edge should work just fine.
hyperHTML.bind(document.body)`
<h2>onload test (notie)</h2>
${new ScriptLoader}
`;
I am keeping part of the old edit just to make you, or any other reader, aware of a little caveat that JSX affectionate might overuse.
There is one thing you should be careful with: hyperHTML does not parse HTML and <script/> is not valid HTML.
You are risking to find nodes where you shouldn't if you don't close non-void tags regularly, and this is beyond hyperHTML capabilities, unfortunately how HTML works in general.
<p/><b>unexpected</b>
I understand for this demo case you had to do that or the parse would complain with a closing script in the page but remember, you can always do this instead, when necessary:
`<script><\x2fscript>`
I am optimizing the performance of my Moodle site, it is showing the high loading time on loading the .js files of the page. That is why I want to include the defer='defer' attribute in the page which is calling or including the javascript files as follow.
if (!empty($CFG->cachejs) and !empty($CFG->jsrev) and $CFG->jsrev > 0 and substr($url, -3) === '.js') {
if (empty($CFG->slasharguments)) {
return new moodle_url($CFG->httpswwwroot.'/lib/javascript.php', array('rev'=>$CFG->jsrev, 'jsfile'=>$url));
} else {
$returnurl = new moodle_url($CFG->httpswwwroot.'/lib/javascript.php');
$returnurl->set_slashargument('/'.$CFG->jsrev.$url);
return $returnurl;
}
} else {
return new moodle_url($CFG->httpswwwroot.$url);
}
So how can I add the defer='defer' attribute on this? Please suggest me.
there are multiple locations where javascript is embedded in the Moodle page, the biggest one is for the YUI3 library.
To add the defer tag, look in file /lib/outputrequirementslib.php. The exact line number depends on your Moodle version. The trickiest one is to add it to the static.js as this is handled in the html_writer class.
Please note that the tag should be "defer" and not "defer='defer'" as Moodle uses the HTML5 doctype.
Also the loading order for Moodle is important due to the way they have build it. Adding the defer attribute will probably break your Moodle.
I'm adding a TinyMCE editor to one of our pages. For reasons above my pay-grade, we're using TinyMCE 3.5.4.1.
It's gone pretty well, except when I try to wire in an onFocus event handler. If I don't try to use the handler, the editors show up and work fine but on pages where I define a handler, there are boatloads of exceptions inside TinyMCE for the browser types I've tried (IE8,9,10 and Chrome).
I've been using templates from other posts I've seen on here but I haven't seen mention of all these TinyMCE exceptions. Of course, trying to unwind the minified script is a real pain.
The first example I found here had a setup function in the TinyMCE config like this:
, setup: function (ed) {
ed.onInit.add(function (ed, evt) {
if (!myFocus) return; // global for the handler to use
var dom = ed.dom;
var doc = ed.getDoc();
tinymce.dom.Event.add(doc, 'focus', myFocus);
});
}
When myFocus is defined, there are a number of exceptions TinyMCE throws starting with
if (j.isIE){l.attachEvent(...)} complaining that l.attachEvent doesn't exist. Then it moves on to all kinds of variable type mismatches.
Chrome developer tools are much more awkward fiddling with minified code, so I'm not sure what all it doesn't like.
Another post I found here suggested doing some minimal browser detection but this helped neither IE nor Chrome.
var doc = s.content_editable ? ed.getBody() : (tinymce.isGecko ? ed.getDoc() : ed.getWin())
Another post suggested a different approach, but I still had all the same errors in both browsers.
, setup: function (ed) {
ed.onInit.add(function (ed, evt) {
if (!myFocus) return;
ed.onFocus.add(myFocus);
});
}
I've also just tried (in vain)
, setup: function (ed) {
if (!myFocus) return;
ed.onFocus.add(myFocus);
}
Is event handling in TinyMCE just very fragile? Not well supported across browsers? Should I just steer clear of it and try using jQuery or something else?
Thanks
Mark
Turns out to be a pilot-error bug being deferred until the extend calls created the editor.
Due to some caching issues, I need to explicitly bypass the cache, for a specific module, if certain URL parameters are present. The workaround I've arrived at is to hack the render() function in libraries/joomla/document/html/renderer/module.php, along the lines of:
function render( $module, $params = array(), $content = null )
{
// Existing code:
$mod_params = new JParameter( $module->params );
// My hack:
if ($module->module == 'mod_foo')
{
if (certain URL parameters are present)
{
$mod_params->set('cache', 0);
}
}
...
}
Of course, hacking the core joomla code is a terrible idea, one which I'd like to avoid if at all possible. So, is there an appropriate hook I can plugin to in order to achieve the same? I don't think I can do anything at the module level, since it won't even be inspected if the renderer has already decided to fetch it from cache.
To answer the first question no there isn't a module render event, here's the plugin doc's and the list of events in Joomla!
Turn off caching for your module.
See this article on The Art Of Joomla, additional articles you could look at:
Using Cache to Speed Up your code
JCache API
I'm trying to dump the whole contents of a certain site using HTMLUnit, but when I try to do this in a certain (rather intrincate) site, I get an empty file (not an empty file per se, but it has an empty head tag, an empty body tag and that's it).
The site is https://www.abcdin.cl/abcdin/abcdin.nsf#https://www.abcdin.cl/abcdin/abcdin.nsf/linea?openpage&cat=Audio&cattxt=TV%20y%20Audio&catpos=03&linea=LCD&lineatxt=LCD%20&
And here's my code:
BufferedWriter writer = new BufferedWriter(new FileWriter(fullOutputPath));
HtmlPage page;
final WebClient webClient = new WebClient(BrowserVersion.INTERNET_EXPLORER_8);
webClient.setCssEnabled(false);
webClient.setPopupBlockerEnabled(true);
webClient.setRedirectEnabled(true);
webClient.setThrowExceptionOnScriptError(false);
webClient.setThrowExceptionOnFailingStatusCode(false);
webClient.setUseInsecureSSL(true);
webClient.setJavaScriptEnabled(true);
page = webClient.getPage(url);
dumpString += page.asXml();
writer.write(dumpString);
writer.close();
webClient.closeAllWindows();
Some people say that I need to introduce a pause in my code, since the page takes a while to load in Google Chrome, but I set long pauses and it doesn't work.
Thanks in advanced.
Just some ideas...
Retrieving that URL with wget returns a non-trivial HTML file. Likewise running your code with webClient.setJavaScriptEnabled(false). So it's definitely something to do with the Javascript in the page.
With Javascript enabled, I see from the logs that a bunch of Javascript jobs are being queued up, and I get see corresponding errors like this:
EcmaError: lineNumber=[49] column=[0] lineSource=[<no source>] name=[TypeError] sourceName=[https://www.abcdin.cl/js/jquery/jquery-1.4.2.min.js] message=[TypeError: Cannot read property "nodeType" from undefined (https://www.abcdin.cl/js/jquery/jquery-1.4.2.min.js#49)]
com.gargoylesoftware.htmlunit.ScriptException: TypeError: Cannot read property "nodeType" from undefined (https://www.abcdin.cl/js/jquery/jquery-1.4.2.min.js#49)
at
com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:601)
Maybe those jobs are meant to populate your HTML? So when they fail, the resulting HTML is empty?
The error looks strange, as HtmlUnit usually has no issues with JQuery. I suspect the issue is with the code calling that particular line of the JQuery library.