I studied the loading behavior of Chrome/FireFox/Safari, all of them will be blocked while inline JavaScript running. Any impacts if do a rough sanning for remaining unparsed document and launch new sub resource downloading task?
Below is my testing page:
<script>
i=0;
while(i<100000)
{
i = i+1;
document.getElementById("output").innerHTML = i;
}
</script>
<img src="http://images.csdn.net/20130516/HK.jpg" />
Looking forward to learn detail of why browser block until the inline script is performed finished?
These days it's considered best to put all your Javascript includes and code just before you close the <body> tag, so that the browser can get on with downloading all the stuff in parallel that it can (e.g. images, css) in the mean time.
Related
I was pretty easily able to get npm's mathjax-full working, for parsing TeX to CommonHTML:
const MathJax = await require("mathjax-full").init({
options: {
enableAssistiveMml: true
},
loader: {
source: {},
load: ["adaptors/liteDOM", "tex-chtml"]
},
tex: {
packages: ["base", "ams", "newcommand"]
},
chtml: {
fontURL: "https://cdn.jsdelivr.net/npm/mathjax#3/es5/output/chtml/fonts/woff-v2"
},
startup: {
typeset: false
}
});
MathJax.tex2chtmlPromise("x^2-2x+1", {
display: true,
em: 16,
ex: 8
}).then((node) => {
var adaptor = MathJax.startup.adaptor;
console.log(adaptor.outerHTML(node));
});
However, unlike typeset/typesetPromise, rather than a DOM node or string of HTML, this works with the TeX directly. Of course I could parse the page myself, finding MathJax delimiters (outside of code blocks) and passing the contents to tex2chtmlPromise, but this would have the potential of bugs or differences in behavior between a client-side preview using MathJax's typeset and the server-side rendered version.
I've looked around in the internals of the liteDOM adaptor quite a bit, but can't seem to find any way of setting the innerHTML of its body, if that would be the correct approach (which would allow me to just use typesetPromise normally).
Is there a recommended way to do what I'm trying to do, namely, take some HTML, and typeset it with MathJax without parsing for the delimiters myself?
The MathJax node demos repository includes examples of how to process an HTML page that should give you what you need. There are several different ways to load and call mathJax, so there are separate directories that illustrate each of them. You are using the "simple" approach, but may also want to look at the "component" and "direct" approaches. Look for files that end in -page.
The main idea for the simple case is to use the document option in the startup section of your MathJax configuration. This allows you to provide a serialized HTML string to be used as the document to be processed. So in your case, you could change
startup: {
typeset: false
}
to
startup: {
typeset: false,
document: html
}
where html is the HTML string to be processed. E.g.,
html = `
<!DOCTYPE html>
<html>
<head>
<title>My Document</title>
</head>
<body>
<p>
Some math: \(E = mc^2\).
</p>
</body>
</html>
`;
If you want the same invocation of your node app to be able to process multiple pages, then you will need to use the "direct" approach, as illustrated in direct/tex2chtml-page, and do these lines for each html file you want to process. You can reuse the same output jax, but should create a new InputJax and MathDocument for each page you process.
Our Firefox addon issues queries to Google at the backend (main.js), then extracts some content through xpath. For this purpose, we use innerHTML to create a document instance for xpath parsing. But when we submit this addon to Mozilla, we got rejected because:
This add-on is creating DOM nodes from HTML strings containing potentially unsanitized data, by assigning to innerHTML, jQuery.html, or through similar means. Aside from being inefficient, this is a major security risk. For more information, see https://developer.mozilla.org/en/XUL_School/DOM_Building_and_HTML_Insertion
Following the link provided, we tried to replace innerHTML with nsIParserUtils.parseFragment(). However, the example code:
let { Cc, Ci } = require("chrome");
function parseHTML(doc, html, allowStyle, baseURI, isXML) {
let PARSER_UTILS = "#mozilla.org/parserutils;1";
...
The Cc, Ci utilities can only be used on main.js, while the function requires a document (doc) as the argument. But we could not find any examples about creating a document inside main.js, where we could not use document.implementation.createHTMLDocument("");. Because main.js is a background script, which does not have reference to the global built-in document.
I googled a lot, but still could not find any solutions. Could anybody kindly help?
You probably want to use nsIDOMParser instead, which is the same as the standard DOMParser accessible in window globals except that you can use it from privileged contexts without a window object.
Although that gives you a whole document with synthesized <html> and <body> elements if you don't provide your own. If you absolutely need a fragment you can use the html5 template element to extract a fragment via domparser:
let partialHTML = "foo <b>baz</b> bar"
let frag = parser.parseFromString(`<template>${partialHTML}</template>`, 'text/html').querySelector("template").content
Following basic setup with python3.4, jinja2, flask_moment (0.5.1), Flask(0.10.1) integration.
I am trying out the capability to simply understand the workings.
The example is nonsensical but I want to get browser to display:
firstly, the actual time in real time ("The local time is ...") continually updated in real time
secondly, the time elapsed ("That was ...").
Jinja2 code:
<p>The local time is {{ moment(current_time).format('LT', refresh=True) }}.</p>
<p>That was {{ moment(current_time).fromNow(refresh=True) }}</p>
The second line refresh works fine in the browser ("That was 1/2/3 minutes ago"), indicating all libraries working correctly, but the first line refresh doesn't work.
The method moment(current_time).format('LT', refresh=True) I thought would display the time in real time with the refresh option set to "True", but it doesn't.
Looking at browser markup, all the libraries are there and there are no errors. See markup below.
Any hints appreciated or maybe I am misunderstanding the capability?
Browser source:
<div class="container">
<div class="page-header">
<h1>Hello, Flask!</h1>
</div>
</div>
<p>The local time is <span class="flask-moment" data-timestamp="2016-01-28T12:19:20Z" data-format="format('LT')" data-refresh="60000" style="display: none">2016-01-28T12:19:20Z</span>.</p>
<p>That was <span class="flask-moment" data-timestamp="2016-01-28T12:19:20Z" data-format="fromNow(0)" data-refresh="60000" style="display: none">2016-01-28T12:19:20Z</span></p>
<script src="/static/bootstrap/jquery.min.js?bootstrap=3.3.5.7"></script>
<script src="/static/bootstrap js/bootstrap.min.js?bootstrap=3.3.5.7"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment-with-locales.min.js"></script>
<script>
moment.locale("en");
function flask_moment_render(elem) {
$(elem).text(eval('moment("' + $(elem).data('timestamp') + '").' + $(elem).data('format') + ';'));
$(elem).removeClass('flask-moment').show();
}
function flask_moment_render_all() {
$('.flask-moment').each(function() {
flask_moment_render(this);
if ($(this).data('refresh')) {
(function(elem, interval) { setInterval(function() { flask_moment_render(elem) }, interval); })(this, $(this).data('refresh'));
}
})
}
$(document).ready(function() {
flask_moment_render_all();
});
This is a misunderstanding on how Flask-Moment works, probably due to my not very clear documentation.
The moment(current_time).format('LT', refresh=True) expression that you put in the Jinja template runs in the server, not the browser. In particular, the current_time variable has a fixed value that I presume you assigned in the Python code.
The result of running this expression is some Javascript code that runs on the browser. When you pass refresh=True, this Javascript code runs every minute. But while the code does run repeatedly, the rendered time is always the same, because a value for current_time was set on the server and isn't being updated. The use of auto-refresh only makes sense with one of the "dynamic" rendering options of moment.js, such as the "X secs/mins ago" format, because those change as time passes.
If you wanted to implement something like a clock, that updates the time, then you would probably need a solution that does it all in Javascript on the browser.
So it appears that according to the documentation, the refresh=true is only going to be updated every minute. Have you given it a minute to verify that it's not refreshing?
The rendered dates and times can be refreshed periodically by passing
a refresh = True argument to any of the above functions. This is
useful for the relative formats, because they are updated as time
passes. The refresh interval is fixed at one minute.
http://blog.miguelgrinberg.com/post/flask-moment-flask-and-jinja2-integration-with-momentjs
we've set up a simple inline webstore installer for our app.
The app site has been verified. The inline installation does work correctly for half of us inside our company, but it doesn't work for the other half. They would get "Uncaught TypeError: Cannot call method 'install' of undefined testsupport.html:15
Uncaught SyntaxError: Unexpected token ). It's as though the chrome or chrome.web variable isn't initialized.
Why does the inline installation work only on some machines but not on others? All these machines have the same chrome browser version.
TIA
I've not seen this issue before but I will try to provide a breakdown of the setup I use to manage inline installations for the multiple Chrome extensions on my website.
Within the head node of every page (optionally, only pages that may include one or more Install links) I add the required links to each extension/app page on the Chrome Web Store. This allows me to easily add install links anywhere on the page for various extensions/apps. The JavaScript simply binds an event handler to each of the install links once the DOM has finished loading. This event handler's sole purpose is to install the extension/app that it links to when clicked and then to change its state to prevent further install attempts.
<!DOCTYPE html>
<html>
<head>
...
<!-- Link for each extension/app page -->
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/dcjnfaoifoefmnbhhlbppaebgnccfddf">
<script>
// Ensure that the DOM has fully loaded
document.addEventListener('DOMContentLoaded', function() {
// Support other browsers
var chrome = window.chrome || {};
if (chrome.app && chrome.webstore) {
// Fetch all install links
var links = document.querySelectorAll('.js-chrome-install');
// Create "click" event listener
var onClick = function(e) {
var that = this;
// Attempt to install the extension/app
chrome.webstore.install(that.href, function() {
// Change the state of the button
that.innerHTML = 'Installed';
that.classList.remove('js-chrome-install');
// Prevent any further clicks from attempting an install
that.removeEventListener('click', onClick);
});
// Prevent the opening of the Web Store page
e.preventDefault();
};
// Bind "click" event listener to links
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', onClick);
}
}
});
</script>
...
</head>
<body>
...
<!-- Allow inline installation links to be easily identified -->
Install
...
</body>
</html>
In order for this system to work fully you also need to support scenarios where the user has returned to your website after installing your extension/app. Although the official documentation suggests using chrome.app.isInstalled this doesn't work when multiple extensions/apps can be installed from a single page. To get around this issue you can simply add a content script to your extension/app like the following install.js file;
// Fetch all install links for this extension/app running
var links = document.querySelectorAll('.js-chrome-install[href$=dcjnfaoifoefmnbhhlbppaebgnccfddf]');
// Change the state of all links
for (var i = 0; i < links.length; i++) {
links[i].innerHTML = 'Installed';
// Website script will no longer bind "click" event listener as this will be executed first
links[i].classList.remove('js-chrome-install');
}
Then you just need to modify your manifest.json file to ensure this content script is executed on your domain.
{
...
"content_scripts": [
{
"js": ["install.js"],
"matches": ["*://*.yourdomain.com/*"],
"run_at": "document_end"
}
]
...
}
This will result in the content script being run before the JavaScript on your website so there will be no install links with the js-chrome-install class by the time it is executed, thus no event handlers will be bound etc.
Below is an example of how I use this system;
Homepage: http://neocotic.com
Project Homepage: http://neocotic.com/template
Project Source Code: https://github.com/neocotic/template
Your inline installation markup is:
<a href="#" onclick="chrome.webstore.install()">
CaptureToCloud Chrome Extension Installation
</a>
(per one of the comments, it used javascript:void(0) before, which is equivalent to # in this case).
Your <a> tag both navigates the page and has an onclick handler. In some cases, the navigation takes place before the onclick handler finishes running, which disturbs the code that supports inline installation.
If you switch to using a plain <span> (styled to look like a like, if you'd like), then you should no longer have this problem:
<span onclick="chrome.webstore.install()" style="text-decoration: underline; color:blue">
CaptureToCloud Chrome Extension Installation
</span>
Alternatively, you can return false from your onclick handler to prevent the navigation:
<a href="#" onclick="chrome.webstore.install(); return false;">
CaptureToCloud Chrome Extension Installation
</a>
(though since you're not actually linking anywhere, there isn't much point in using the <a> tag)
I get the error you mentioned AND a popup window that allows me to install the extension. So probably everybody get the error but for some it is preventing installation.
I got rid of the error by replacing javascript:void() by # in href.
CaptureToCloud Chrome Extension Installation
How to tell google syndication not to wait forever to load the ads in case of slow internet connection or otherwise too? Can we fix a time that says okay go and search for 5ms to get ads otherwise don’t delay the load of rest of page.
The YSlow extension for Firebug is great for this sort of thing, it benchmarks your page loading and tells you what's slow, and advises what techniques you can use to improve things.
For example, it gives you advice on where to put your javascript to aid the speed of your site as perceived by the user.
Assuming you mean this is on your site, be sure that your javascript is loaded at the end of the page so your other content can load first
see this blog item "Google Ads Async (asynchronous)" might give you a good starting point for this:
<script type="text/javascript"><!--
// dynamically Load Ads out-of-band
setTimeout((function ()
{
// placeholder for ads
var eleAds = document.createElement("ads");
// dynamic script element
var eleScript = document.createElement("script");
// remember the implementation of document.write function
w = document.write;
// override and replace with our version
document.write = (function(params)
{
// replace our placeholder with real ads
eleAds.innerHTML = params;
// put the old implementation back in place
document.write=w;
});
// setup the ads script element
eleScript.setAttribute("type", "text/javascript");
eleScript.setAttribute("src", "http://pagead2.googlesyndication.com/pagead/show_ads.js");
// add the two elements, causing the ads script to run
document.body.appendChild(eleAds);
document.body.appendChild(eleScript);
}), 1);
//-->
</script>