We use MathJax on our course website, which is implemented in Jekyll and hosted on GitHub pages. For small, straightforward equations, MathJax works great but I've never been able to get even slightly more complicated equations to work. I've spent many hours investigating and experimenting, so I thought I'd finally ask here.
For example, the following fails to render:
$$
S_{i} =
\begin{cases}
X_{1} & \text{if i = 1}\\
\alpha \cdot X_{i} + (1 - \alpha) \cdot S_{i-1} & \text{if i $>$ 1}
\end{cases}
$$
The rendered output in the web browser is literally blank.
When I look at the rendered html, I see:
<p>
<span class="MathJax_Preview" style="color: inherit; display: none;"></span>
<span id="MathJax-Element-5-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" data-mathml="
<math
xmlns="http://www.w3.org/1998/Math/MathML" />" role="presentation" style="font-size: 113%; position: relative;">
<span id="MJXc-Node-149" class="mjx-math" aria-hidden="true">
<span id="MJXc-Node-150" class="mjx-mrow"></span>
</span>
<span class="MJX_Assistive_MathML" role="presentation">
<math
xmlns="http://www.w3.org/1998/Math/MathML">
</math>
</span>
</span>
<script type="math/tex" id="MathJax-Element-5">%
<![CDATA[ S_{i} = \begin{cases} X_{1} & \text{if i = 1}\\ \alpha \cdot X_{i} + (1 - \alpha) \cdot S_{i-1} & \text{if i $>$ 1} \end{cases} %]]>
</script>
</p>
I'm not a LaTeX expert so I often write equations (or at least check them) in online editors like https://www.codecogs.com/latex/eqneditor.php or OverLeaf. They render fine there.
I asked this first (link) at the tex StackExchange but they said it was offtopic.
UPDATE: I ended up asking this on the MathJax user group (link) and received a working solution, which is described in detail on GitHub. Thanks all for your responses!
It looks like Jekyll inserts the math as MathJax <script> tags (<script type="math/tex">), and the contents of that tag are the TeX expression. Unfortunately, the plugin is inserting some additional text to mark the contents as CDATA. This is not needed in HTML, but may be for XHTML. Is your page XHTML (I don't know what Jekyll produces)?
In any case, the plugin probably originally inserted
<script type="math/tex">
% <![CDATA[
... your expression...
% ]]>
</script>
That would have worked (even if it is unnecessary), because the % in TeX marks a comment, so the <![CDATA[ will be ignored, and so will the closing ]]>.
Except that GitHub pages removes line breaks, and so you got
<script type="math/tex">% <![CDATA[... your expression...% ]]></script>
all on one line. That means the first % makes the entire rest of the expression into a comment, and the math is effectively commented out. That means you get no output, since the math expression is actually empty.
This has come up before, and I provided a work-around
for version 2:
<script type="text/x-mathjax-config">
MathJax.Hub.Register.StartupHook('TeX Jax Ready', function () {
MathJax.InputJax.TeX.prefilterHooks.Add(function (data) {
data.math = data.math.replace(/^% <!\[CDATA\[/, '').replace(/%\]\]>$/, '');
});
});
</script>
and a version 3 as well:
<script>
MathJax = {
startup: {
ready: function() {
var HTMLDomStrings = MathJax._.handlers.html.HTMLDomStrings.HTMLDomStrings;
var handleTag = HTMLDomStrings.prototype.handleTag;
HTMLDomStrings.prototype.handleTag = function (node, ignore) {
if (this.adaptor.kind(node) === '#comment') {
var text = this.adaptor.textContent(node);
if (text.match(/^\[CDATA\[(?:\n|.)*\]\]$/)) {
this.string += '<!'
this.extendString(node, text);
this.string += '>';
return this.adaptor.next(node);
}
}
return handleTag.call(this, node, ignore);
}
MathJax.startup.defaultReady();
MathJax.startup.document.inputJax[0].preFilters.add(function (data) {
data.math.math = data.math.math.replace(/^% <!\[CDATA\[/, '').replace(/%\]\]>$/, '');
});
}
}
};
</script>
In any case, it is the (probably unnecessary) CDATA "comments", together with the removal of line breaks, that is causing the problem.
Related
I am trying to remove all the html tags out of a string in Javascript.
Heres what I have... I can't figure out why its not working....any know what I am doing wrong?
<script type="text/javascript">
var regex = "/<(.|\n)*?>/";
var body = "<p>test</p>";
var result = body.replace(regex, "");
alert(result);
</script>
Thanks a lot!
Try this, noting that the grammar of HTML is too complex for regular expressions to be correct 100% of the time:
var regex = /(<([^>]+)>)/ig
, body = "<p>test</p>"
, result = body.replace(regex, "");
console.log(result);
If you're willing to use a library such as jQuery, you could simply do this:
console.log($('<p>test</p>').text());
This is an old question, but I stumbled across it and thought I'd share the method I used:
var body = '<div id="anid">some text</div> and some more text';
var temp = document.createElement("div");
temp.innerHTML = body;
var sanitized = temp.textContent || temp.innerText;
sanitized will now contain: "some text and some more text"
Simple, no jQuery needed, and it shouldn't let you down even in more complex cases.
Warning
This can't safely deal with user content, because it's vulnerable to script injections. For example, running this:
var body = '<img src=fake onerror=alert("dangerous")> Hello';
var temp = document.createElement("div");
temp.innerHTML = body;
var sanitized = temp.textContent || temp.innerText;
Leads to an alert being emitted.
This worked for me.
var regex = /( |<([^>]+)>)/ig
, body = tt
, result = body.replace(regex, "");
alert(result);
This is a solution for HTML tag and   etc and you can remove and add conditions
to get the text without HTML and you can replace it by any.
convertHtmlToText(passHtmlBlock)
{
str = str.toString();
return str.replace(/<[^>]*(>|$)| ||»|«|>/g, 'ReplaceIfYouWantOtherWiseKeepItEmpty');
}
Here is how TextAngular (WYSISYG Editor) is doing it. I also found this to be the most consistent answer, which is NO REGEX.
#license textAngular
Author : Austin Anderson
License : 2013 MIT
Version 1.5.16
// turn html into pure text that shows visiblity
function stripHtmlToText(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
var res = tmp.textContent || tmp.innerText || '';
res.replace('\u200B', ''); // zero width space
res = res.trim();
return res;
}
you can use a powerful library for management String which is undrescore.string.js
_('a link').stripTags()
=> 'a link'
_('a link<script>alert("hello world!")</script>').stripTags()
=> 'a linkalert("hello world!")'
Don't forget to import this lib as following :
<script src="underscore.js" type="text/javascript"></script>
<script src="underscore.string.js" type="text/javascript"></script>
<script type="text/javascript"> _.mixin(_.str.exports())</script>
my simple JavaScript library called FuncJS has a function called "strip_tags()" which does the task for you — without requiring you to enter any regular expressions.
For example, say that you want to remove tags from a sentence - with this function, you can do it simply like this:
strip_tags("This string <em>contains</em> <strong>a lot</strong> of tags!");
This will produce "This string contains a lot of tags!".
For a better understanding, please do read the documentation at
GitHub FuncJS.
Additionally, if you'd like, please provide some feedback through the form. It would be very helpful to me!
For a proper HTML sanitizer in JS, see http://code.google.com/p/google-caja/wiki/JsHtmlSanitizer
<html>
<head>
<script type="text/javascript">
function striptag(){
var html = /(<([^>]+)>)/gi;
for (i=0; i < arguments.length; i++)
arguments[i].value=arguments[i].value.replace(html, "")
}
</script>
</head>
<body>
<form name="myform">
<textarea class="comment" title="comment" name=comment rows=4 cols=40></textarea><br>
<input type="button" value="Remove HTML Tags" onClick="striptag(this.form.comment)">
</form>
</body>
</html>
The selected answer doesn't always ensure that HTML is stripped, as it's still possible to construct an invalid HTML string through it by crafting a string like the following.
"<<h1>h1>foo<<//</h1>h1/>"
This input will ensure that the stripping assembles a set of tags for you and will result in:
"<h1>foo</h1>"
additionally jquery's text function will strip text not surrounded by tags.
Here's a function that uses jQuery but should be more robust against both of these cases:
var stripHTML = function(s) {
var lastString;
do {
s = $('<div>').html(lastString = s).text();
} while(lastString !== s)
return s;
};
The way I do it is practically a one-liner.
The function creates a Range object and then creates a DocumentFragment in the Range with the string as the child content.
Then it grabs the text of the fragment, removes any "invisible"/zero-width characters, and trims it of any leading/trailing white space.
I realize this question is old, I just thought my solution was unique and wanted to share. :)
function getTextFromString(htmlString) {
return document
.createRange()
// Creates a fragment and turns the supplied string into HTML nodes
.createContextualFragment(htmlString)
// Gets the text from the fragment
.textContent
// Removes the Zero-Width Space, Zero-Width Joiner, Zero-Width No-Break Space, Left-To-Right Mark, and Right-To-Left Mark characters
.replace(/[\u200B-\u200D\uFEFF\u200E\u200F]/g, '')
// Trims off any extra space on either end of the string
.trim();
}
var cleanString = getTextFromString('<p>Hello world! I <em>love</em> <strong>JavaScript</strong>!!!</p>');
alert(cleanString);
If you want to do this with a library and are not using JQuery, the best JS library specifically for this purpose is striptags.
It is heavier than a regex (17.9kb), but if you need greater security than a regex can provide/don't care about the extra 17.6kb, then it's the best solution.
Like others have stated, regex will not work. Take a moment to read my article about why you cannot and should not try to parse html with regex, which is what you're doing when you're attempting to strip html from your source string.
I'm using uncode theme and I have a page heading that is showing 'Archive: Portfolio'
I want to remove the 'Archive:' bit from that heading.
In the source it looks like this:
<h1 class="header-title h1"><span>Archives: Projects</span></h1>
I have tried removing Archive from all the page titles with Yoast SEO plugin but it is still showing.
Is there a way to remove that word with javascript maybe does anyone know?
Thanks!
I'd be wary in removing it via javascript. It seems to me that adding a piece of text somewhere in the code's execution, and then removing it on the client-side smells like "contrived complexity".
Take a look at the wordpress template hierarchy, and manually search for the template file that's rendering the Archives: string of text.
I'd start with archive.php, and then fall my way up through other archive-*.php pages, then to taxonomy.php category.php, and so on.
If you're comfy in the command line, you might also consider grepping for the string: grep -r /path/to/wp/theme "Archive:" and sifting through the results to find the template file(s) with that on one of their lines.
But if you insist on removing the string via javascript, you might try dropping something like this at the bottom of the <body>, via a function in functions.php:
function remove_archive_text_via_js() {
if (is_archive()) { ?>
<script type="text/javascript">
var archiveHeaders = document.getElementsByClassName('header-title');
for (i = 0, headerCount = archiveHeaders.length; i < headerCount; i++) {
var replacedText = archiveHeaders[i].textContent.replace('Archives: ', '');
archiveHeaders[i].textContent = replacedText;
}
</script>
<?php }
}
add_action('wp_footer', 'remove_archive_text_via_js');
var elem = document.getElementsByClassName('header-title h1');
var innerSpan = elem[0].getElementsByTagName('span');
innerSpan[0].innerHTML = innerSpan[0].innerHTML.replace('Archives: ', 'jsfiddle');
jsfiddle: https://jsfiddle.net/orcadj3u/
$(function() {
$( "h1 span" ).each(function( index ) {
var newtext = $(this).text().replace("Archives: ", " ");
$(this).html(newtext);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h1 class="header-title h1"><span>Archives: Projects</span></h1><br>
<h1 class="header-title h1"><span>Archives: Solutions</span></h1><br>
<h1 class="header-title h1"><span>Archives: Yozgat</span></h1><br>
<h1 class="header-title h1"><span>Archives: Turkey</span></h1><br>
Please forgive me as I've never used Apache Velocity before but I have to figure this out!
I'm using an adobe recommendation template for products and I'm now adding a star rating system into it as noted in the image below:
However, as you can see the logic i have added (In JS) is only being executed the first time. and obviously not running through the loop, since it is in Velocity.
My question to the community is; how do i go about making this work?
I've tried for a day now to no avail, so ANY help would be greatly appreciated.
Please see the code below! (And thanks!)
[The #foreach loops is the velocity, and everything between the script tags is my appended code]
<div class="line">
<h2>More for You</h2>
#set($count=1)
#foreach($e in $entities)
#if($e.id != "" && $count < $entities.size() && $count <=18)
<li>
<script type="text/javascript">
var myString = $e.rating;
if (myString >= 5) { myString = 5;}
var myRegexp2 = /\d(?!.*\d)/;
var match2 = myRegexp2.exec(myString);
var starIMG = "<img src='http://kirklands.ugc.bazaarvoice.com/3768-en_us/" + match + "_" + match2 + "/5/rating.gif' alt='' />";
var myRegexp3 = /\d/;
var match = myRegexp3.exec(myString);
function myFunction() {
return(match);
}
</script>
<a class="productBlock" onclick="var s = s_gi(s_account);
s.linkTrackVars='events,eVar21';
s.linkTrackEvents='event16';
s.events='event16';
s.eVar21='';
s.tl(this,'o','Product Detail Cross-Sell');" href="$e.pageUrl?icid=hpFS ">
<img title="$e.name" alt="$e.name" src="$e.thumbnailUrl">
<h3>$e.name</h3>
<div id="starRating"><script>document.getElementById("starRating").innerHTML =
starIMG;</script></div>
<p>$$e.value</p>
</a>
</li>
#set($count = $count + 1)
#end
#end
</ul>
</div>
<div class="scroolBtn btnRight"><span class="btn" id="scrool-forward"></span></div>
</div>
jQuery(function () {
jQuery('#scrool').scrollbox({
direction: 'h',
switchItems: 3,
distance: 450,
autoPlay:false
});
jQuery('#scrool-backward').click(function () {
jQuery('#scrool').trigger('backward');
});
jQuery('#scrool-forward').click(function () {
jQuery('#scrool').trigger('forward');
});
});
I have not used Velocity template scripts for years but wild guess is an escaping problem. Everything you include in a velocity template is actually run by Velocity engine, you must escape $variable literals.
http://velocity.apache.org/engine/devel/user-guide.html#escapingvalidvtlreferences
edit No wait, you mean you wanted to run javascript code at server side, each foreach item step should evaluate javascript code?
The only way I know how to print a huge string without using += is to use \ backslashes. ugly!
<div id="foo"></div>
<script type="text/javascript">
var longString = '<div id="lol">\
<div id="otherstuff">\
test content. maybe some code\
</div>\
</div>';
document.getElementById('foo').innerHTML = longString;
</script>
is there any way to do this where the longString is untainted? php has $foo = ''' long multiline string '''; I want this in javascript!
Anyone know of a better method for printing long, multi-line strings in javascript?
In general, the answer is: not in the language syntax. Though as Ken pointed out in his answer there are many work-arounds (my personal method is to load a file via AJAX). In your specific case though, I'd prefer creating a HTML constructor function so you can then define the HTML structure using javascript object literals. Something like:
var longString = makeHTML([{
div : {
id : "lol",
children : [{
div : {
id : "otherstuff",
children : [{
text : "test content. maybe some code"
}]
}]
}]
which I find to be much easier to handle. Plus, you this would allow you to use real function literals when you need it to avoid string quoting hell:
makeHTML([{
span : {
onclick : function (event) {/* do something */}
}
}]);
note: the implementation of makeHTML is left as exercise for the reader
Additional answer:
Found some old code after a quick scan through my hard disk. It's a bit different from what I suggested above so I thought I'd share it to illustrate one of the many ways you can write functions like this. Javascript is a very flexible language and there is not much that forces you to write code one way or another. Choose the API you feel most natural and comfortable and write code to implement it.
Here's the code:
function makeElement (tag, spec, children) {
var el = document.createElement(tag);
for (var n in spec) {
if (n == 'style') {
setStyle(el,spec[n]);
}
else {
el[n] = spec[n];
}
}
if (children && children.length) {
for (var i=0; i<children.length; i++) {
el.appendChild(children[i]);
}
}
return el;
}
/* implementation of setStyle is
* left as exercise for the reader
*/
Using it would be something like:
document.getElementById('foo').appendChild(
makeElement(div,{id:"lol"},[
makeElement(div,{id:"otherstuff"},[
makeText("test content. maybe some code")
])
])
);
/* implementation of makeText is
* left as exercise for the reader
*/
One technique if you have a big block is a <script> tag with an invalid type. It will be ignored by browsers.
<script type="text/x-my-stuff" id="longString">
<div id="lol">
<div id="otherstuff">
test content. maybe some code
</div>
</div>
</script>
<script type="text/javascript">
var longString = document.getElementById("longString").text;
document.getElementById('foo').innerHTML = longString;
</script>
A few somewhat unattractive options are discussed in the answers to this question.
You really could minimize this ugliness by creating your <div id="lol"> as HTML, and set its content with .innerHTML = "test content. maybe some code"
I don't like creating HTML in Javascript because of this exact issue, and instead use "template" elements which i simply clone then manipulate.
var lol = document.getElementById("template_lol").clone();
lol.firstChild.innerHTML = "code and stuff";
foo.appendChild(lol);
And this is the HTML:
<body>
<div>normal stuff</div>
<div style="display:none" id="templateBucket">
<div id="template_lol"><div class="otherstuff"></div></div>
</div>
</body>
This works too :
var longString =
'<div id="lol">' +
'<div id="otherstuff">' +
'test content. maybe some code' +
'</div>' +
'</div>';
Though I've never heard of this but, is it possible to retrieve a node from the DOM using JS, and then find out on what line of the file that node occurred on?
I'm open to anything, alternative browsers plugins/add-ons etc...it doesn't need to be cross-browser per say.
I would assume that this would be possible somehow considering that some JS debuggers are capable of finding the line number within a script tag, but I'm not entirely sure.
Ok, forgive me for how large this is. I thought this was a very interesting question but while playing with it, I quickly realized that innerHTML and its ilk are quite unreliable wrt maintaining whitespace, comments, etc. With that in mind, I fell back to actually pulling down a full copy of the source so that I could be absolutely sure I got the full source. I then used jquery and a few (relatively small) regexes to find the location of each node. It seems to work well although I'm sure I've missed some edge cases. And, yeah, yeah, regexes and two problems, blah blah blah.
Edit: As an exercise in building jquery plugins, I've modified my code to function reasonably well as a standalone plugin with an example similar to the html found below (which I will leave here for posterity). I've tried to make the code slightly more robust (such as now handling tags inside quoted strings, such as onclick), but the biggest remaining bug is that it can't account for any modifications to the page, such as appending elements. I would need probably need to use an iframe instead of an ajax call to handle that case.
<html>
<head id="node0">
<!-- first comment -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<style id="node1">
/* div { border: 1px solid black; } */
pre { border: 1px solid black; }
</style>
<!-- second comment -->
<script>
$(function() {
// fetch and display source
var source;
$.ajax({
url: location.href,
type: 'get',
dataType: 'text',
success: function(data) {
source = data;
var lines = data.split(/\r?\n/);
var html = $.map(lines, function(line, i) {
return ['<span id="line_number_', i, '"><strong>', i, ':</strong> ', line.replace(/</g, '<').replace(/>/g, '>'), '</span>'].join('');
}).join('\n');
// now sanitize the raw html so you don't get false hits in code or comments
var inside = false;
var tag = '';
var closing = {
xmp: '<\\/\\s*xmp\\s*>',
script: '<\\/\\s*script\\s*>',
'!--': '-->'
};
var clean_source = $.map(lines, function(line) {
if (inside && line.match(closing[tag])) {
var re = new RegExp('.*(' + closing[tag] + ')', 'i');
line = line.replace(re, "$1");
inside = false;
} else if (inside) {
line = '';
}
if (line.match(/<(script|!--)/)) {
tag = RegExp.$1;
line = line.replace(/<(script|xmp|!--)[^>]*.*(<(\/(script|xmp)|--)?>)/i, "<$1>$2");
var re = new RegExp(closing[tag], 'i');
inside = ! (re).test(line);
}
return line;
});
// nodes we're looking for
var nodes = $.map([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(num) { return $('#node' + num) });
// now find each desired node in both the DOM and the source
var line_numbers = $.map(nodes, function(node) {
var tag = node.attr('tagName');
var tags = $(tag);
var index = tags.index(node) + 1;
var count = 0;
for (var i = 0; i < clean_source.length; i++) {
var re = new RegExp('<' + tag, 'gi');
var matches = clean_source[i].match(re);
if (matches && matches.length) {
count += matches.length;
if (count >= index) {
console.debug(node, tag, index, count, i);
return i;
}
}
}
return count;
});
// saved till end to avoid affecting source html
$('#source_pretty').html(html);
$('#source_raw').text(source);
$('#source_clean').text(clean_source.join('\n'));
$.each(line_numbers, function() { $('#line_number_' + this).css('background-color', 'orange'); });
},
});
var false_matches = [
"<div>",
"<div>",
"</div>",
"</div>"
].join('');
});
</script>
</head>
<!-- third comment -->
<body id="node2">
<div>
<pre id="source_pretty">
</pre>
<pre id="source_raw">
</pre>
<pre id="source_clean">
</pre>
</div>
<div id="node3">
<xmp>
<code>
// <xmp> is deprecated, you should put it in <code> instead
</code>
</xmp>
</div>
<!-- fourth comment -->
<div><div><div><div><div><div><span><div id="node4"><span><span><b><em>
<i><strong><pre></pre></strong></i><div><div id="node5"><div></div></div></div></em>
</b></span><span><span id="node6"></span></span></span></div></span></div></div></div></div></div></div>
<div>
<div>
<div id="node7">
<div>
<div>
<div id="node8">
<span>
<!-- fifth comment -->
<div>
<span>
<span>
<b>
<em id="node9">
<i>
<strong>
<pre>
</pre>
</strong>
</i>
<div>
<div>
<div>
</div>
</div>
</div>
</em>
</b>
</span>
<span>
<span id="node10">
</span>
</span>
</span>
</div>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Something like this?
var wholeDocument = document.getElementsByTagName('html')[0]
var findNode = document.getElementById('whatever')
var documentUpToFindNode = wholeDocument.substr(0, wholeDocument.indexOf(findNode.outerHTML))
var nlsUpToFindNode = documentUpToFindNode.match(/\n/g).length
This can be done. Start by getting the highest node in the document like this:
var htmlNode = document.getElementsByTagName('html')[0];
var node = htmlNode;
while (node.previousSibling !== null) {
node = node.previousSibling;
}
var firstNode = node;
(this code was tested and retrieved both the doctype node as well as comments above the html node)
Then you loop through all nodes (both siblings and children). In IE, you'll only see the elements and comments (not text nodes), so it'll be best to use FF or chrome or something (you said it wouldn't have to be cross browser).
When you get to each text node, parse it to look for carriage returns.
You could try: -
- start at the 'whatever' node,
- traverse to each previous node back to the doc begining while concatenating the html of each node,
- then count the new lines in your collected HTML.
Post the code once you nut it out coz thats a good question :)