javascript convert math text into latex/graphic - javascript

I am trying to find a plugin that can convert this text
1*2^3 + 0*2^2 + 1*2^1 = 1 + 0 + 3 = 5
into latex so it can be more easily readable and user friendly
I dont mind if i need to make simple modifications on the syntax...

If you only need a very basic markup, regular expressions are your friend.
The following example replaces each * with a middle dot · and adds some HTML markup (<sup>) to create those exponents. Of course this is just a very simple example that can be extended.
<span class="math">1*2^3 + 0*2^2 + 1*2^1 = 1 + 0 + 3 = 5</span>
<script>
(function(){
function convert(str) {
str = str.replace(/\*/g, "·");
str = str.replace(/\^(.)\s/g, "<sup>$1</sup> ");
return str;
};
var math = document.getElementsByClassName("math");
for (var i = 0, l = math.length; i < l; ++i) {
math[i].innerHTML = convert(math[i].innerHTML);
}
})();
</script>
Demo (JSFiddle)
However, as #Mathias suggested, MathJax is definitely worth a look if you want to display more complex mathematics.

Related

Make a mountain out of a molehill by replacing it with JavaScript

I want to replace multiple words on a website with other words. That is, I am interested in finding all instances of a source word and replacing it with a target word.
Sample Cases:
Source | Target
Molehill => Mountain
Green => Grey
Google => <a href="http://google.com">
Sascha => Monika
Football => Soccer
This is somewhat of a half answer. It shows the basic process, but also illustrates some of the inherent difficulties in a process like this. Detecting capitalization and properly formatting the replacements would be a bit intensive (probably utilizing something like this on a case-by-case basis How can I test if a letter in a string is uppercase or lowercase using JavaScript?). Also, when dealing with text nodes, innerHTML isn't an option, so the google replacement comes out as plain text instead of HTML.
TLDR - If you have another way to do this that doesn't involve javascript, do it that way.
var body = document.querySelector('body')
function textNodesUnder(el){
var n, a=[], walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
while(n=walk.nextNode()) a.push(n);
return a;
}
function doReplacements(txt){
txt = txt.replace(/sascha/gi, 'monika')
txt = txt.replace(/mountain/gi, 'molehill')
txt = txt.replace(/football/gi, 'soccer')
txt = txt.replace(/google/gi, 'google')
console.log(txt)
return txt
}
var textnodes = textNodesUnder(body),
len = textnodes.length,
i = -1, node
console.log(textnodes)
while(++i < len){
node = textnodes[i]
node.textContent = doReplacements(node.textContent)
}
<div>Mountains of Sascha</div>
<h1>Playing football, google it.</h1>
<p>Sascha Mountain football google</p>
Here is the JS:
function replaceWords () {
var toReplace = [
["Green","Grey"],
["Google","<a href='http://google.com'>"]
];
var input = document.getElementById("content").innerHTML;
console.log("Input: " + input);
for (var i = 0; i < toReplace.length; i++) {
var reg = new RegExp(toReplace[i][0],"g");
input = input.replace(reg,toReplace[i][1]);
}
document.getElementById("content").innerHTML = input;
};
replaceWords();

.replace method in JavaScript and duplicated characters

I'm trying to use JavaScript to insert HTML ruby characters on my text. The idea is to find the kanji and replace it with the ruby character that is stored on the fgana array. My code goes like this:
for (var i = 0; i < kanji.length; i++) {
phrase = phrase.replace(kanji[i],"<ruby><rb>" + kanji[i] + "</rb><rt>" + fgana[i] + "</rt></ruby>");
}
It does that just fine when there aren't duplicated characters to be replaced, but when there are the result is different from what I except. For example, if the arrays are like this:
kanji = ["毎朝","時","時"]
fgana = ["まいあさ"、"とき"、"じ"]
And the phrase is あの時毎朝6時におきていた the result becomes:
あの<ruby><rb><ruby><rb>時</rb><rt>じ</rt></ruby></rb><rt>とき</rt></ruby><ruby><rb>毎朝</rb><rt>まいあさ</rt></ruby> 6 時 におきていた。
Instead of the desired:
あの<ruby><rb>時</rb><rt>とき</rt></ruby><ruby><rb>毎朝</rb><rt>まいあさ</rt></ruby> 6 <ruby><rb>時</rb></ruby></rb><rt>じ</rt> におきていた。
To illustrate it better, look at the rendered example:
Look at how the first 時 receives both values とき and じ while the second receives nothing. The idea is to the first be とき and the second じ (as Japanese has different readings for the same character depending on some factors).
Whats might be the failure on my code?
Thanks in advance
It fails because the char you are looking for still exists in the replaced version:
...replace(kanji[i],"<ruby><rb>" + kanji[i]...
And this one should work:
var kanji = ["毎朝", "時", "時"],
fgana = ["まいあさ", "とき", "じ"],
phrase = "あの時毎朝 6 時におきていた",
rx = new RegExp("(" + kanji.join("|") + ")", "g");
console.log(phrase.replace(rx, function (m) {
var pos = kanji.indexOf(m),
k = kanji[pos],
f = fgana[pos];
delete kanji[pos];
delete fgana[pos];
return "<ruby><rb>" + k + "</rb><rt>" + f + "</rt></ruby>"
}));
Just copy and paste into console and you get:
あの<ruby><rb>時</rb><rt>とき</rt></ruby><ruby><rb>毎朝</rb><rt>まいあさ</rt></ruby> 6 <ruby><rb>時</rb><rt>じ</rt></ruby>におきていた
Above line is a bit different from your desired result thou, just not sure if you indeed want this:
...6 <ruby><rb>時</rb></ruby></rb><rt>じ</rt>...
^^^^^ here ^ not here?

to apply sequential line numbering to lines in a paragraph: is it possible?

Is it possible to have jquery/javascript insert sequential line number at the start of all lines in a paragraph and, better still, to follow the sequence through to subsequent paragraphs?
I want to be able to refer students quickly to particular lines of an article (in a classroom setting). I have lots of articles to which I would like to apply this functionality, each of which has varying numbers of paragraphs.
I was hoping this might be possible, even in a responsive page, where the width of the paragraphs changes, depending on the display device, and the consequent number of lines in each paragraph becomes greater or fewer.
Thanks in advance to anyone who can help.
Here is one approach that may suit your purposes.
Get the height of a one-line paragraph, for reference.
For each paragraph, get the actual height, and infer the number of lines.
Loop through the lines and add the numbering at absolute positions.
var refHeight = $("p").eq(0).height();
$("p").eq(0).remove();
var cnt = 1;
$("p").each(function(index) {
var pos = $(this).position();
var h = $(this).height();
var lines = h / refHeight;
var lineHeight = h / lines;
for (var i=pos.top ; i<pos.top+h ; i += lineHeight) {
var num = $("<p>", { class: "number" });
num.text(cnt++);
num.css("top", i);
$(this).before(num);
console.log(i);
}
});
(Fiddle)
Edit
If you wanted to use a fixed line length (so that everyone is seeing the same numbers), you could combine the above with the following:
Break the paragraphs into lines.
Wrap each line in a span/div, and re-append.
Block the browser from text wrapping.
$("p").each(function() {
var text = $(this).text();
$(this).html("");
var i=0;
while (i<text.length) {
lineCharWidth = charWidth;
while (i+lineCharWidth < text.length && text[i+lineCharWidth] != ' ') {
lineCharWidth++;
}
var line = $("<span>", { class: "line" }).text(text.substr(i, lineCharWidth));
$(this).append(line).append("<br/>");
i += lineCharWidth;
}
});
(Fiddle)
Here's a solution that uses a function to split the paragraph text on space characters based on a pre-determined line length and then replaces the text with an <ol> comprised of <li> elements each containing one line of text:
var lineNum = 1;
function splitLines(text, lineLen) {
var words = text.split(/\s/g), line = '', lines = [];
$.each(words, function(idx) {
line += this + ' ';
if (line.length > lineLen || idx == words.length - 1) {
lines.push(line);
line = '';
lineNum += 1;
}
});
return lines;
}
$('p').each(function() {
var $p = $(this), $ol = $('<ol start="' + lineNum + '">'), lineLen = 50;
$.each(splitLines($p.text(), lineLen), function(idx) {
$ol.append('<li>' + this + '</li>');
});
$p.text('').append($ol);
});
I'm not sure about the support for the start attribute of the <ol>. It does work in Chrome. Even still, I like using the list element because it's a little more semantically meaningful, in my opinion.
Sure. Just make sure you're encoding your line returns and use it to split up the text with a simple replace.
Sample text:
The quick
brown fox
jumped over
the lazy dog
for this, the actual string would be the following:
The quick\r\nbrown fox\r\njumped over\r\nthe lazy dog
I think something like this would work (without the document.write, and there could be performance improvements):
var input = '\r\nThe quick\r\nbrown fox\r\njumped over\r\nthe lazy dog';
input = input.replace(/\r\n/g, '<div class=\'index\'></div>');
document.write(input);
var idx = 0;
$('.index').each(function(){
$(this).text(idx++);
});
If I'm not mistaken, this should write out an index number on each line. Could use some testing/debugging, though :)
For an example of how this is done, check out Github's diff pages.

How to replace all html tags from <anything> to \n<anything>\n [using regexp (JavaScript)]

How to replace all HTML tags from <anything> to \n<anything> and </anything> to <anything>\n
var text = "<anything>welcome</anything><anything>Hello</anything>";
result
var text = "\n<anything>welcome</anything>\n\n<anything>Hello</anything>\n";
This code will help you (match all tags)
</?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)/?>
You can prettify xml without regex:
var text = "<anything>welcome</anything><anything>Hello</anything>";
var xml = new XML("<root>" + text + "</root>");
console.log(xml.children().toXMLString());
output:
<anything>welcome</anything>
<anything>Hello</anything>
Just don't parse HTML using regex. Read this: http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html
In JavaScript, you can turn HTML into DOM using the .innerHTML property, and after that you can use other DOM methods to traverse it.
Simple example (needs Firebug):
var div = document.createElement('div');
var html = '<p>foo <span>bar</span><br /></p>';
div.innerHTML = html;
function scan(node, depth)
{
depth = depth || 0;
var is_tag = node.nodeType == 1;
var self_contained = false;
if (is_tag) {
self_contained = node.childNodes.length == 0;
var tag_name = node.tagName.toLowerCase();
console.log('<' + tag_name + (self_contained ? ' /' : '') + '>', depth);
} else {
console.log(node.data);
}
for (var i = 0, n = node.childNodes.length; i < n; i++) {
scan(node.childNodes[i], depth + 1);
}
if (!self_contained && is_tag) {
console.log('</' + tag_name + '>', depth);
}
}
scan(div);
Output:
<div> 0
<p> 1
foo
<span> 2
bar
</span> 2
<br /> 2
</p> 1
</div> 0
You could also modify this to output attributes and use the depth argument for indentation.
Try this:
str.replace(/<(\/?)[a-zA-Z]+(?:[^>"']+|"[^"]*"|'[^']*')*>/g, function($0, $1) {
return $1 === "/" ? $0+"\n" : "\n"+$0;
})
Expanding on #Amarghosh's answer:
Assuming the HTML you are trying to parse is more complicated than your example (which I would guess it is) you may want to convert your HTML page into XHTML. This will allow you to use treat it as XML and do a number of things including:
Use an XSL to transform the data
Use .NET's extensive set of XML
libraries to extract and manipulate the data.
I have done this in the past with a free .NET library called SGML.
text = text.replace(/<(?!\/)/g, "\n<"); // replace every < (which are not followed by /) by \n<

Javascript obfuscation help

I need some help to understand how this code was obfuscated. The code is:
<a id="suggest" href="#" ajaxify="/ajax/social_graph/invite_dialog.php?class=FanManager&node_id=108463912505356" class=" profile_action actionspro_a" rel="dialog-post">Suggest to Friends</a>
And the obfuscation is:
\x3c\x61\x20\x69\x64\x3d\x22\x73\x75\x67\x67\x65\x73\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x23\x22\x20\x61\x6a\x61\x78\x69\x66\x79\x3d\x22\x2f\x61\x6a\x61\x78\x2f\x73\x6f\x63\x69\x61\x6c\x5f\x67\x72\x61\x70\x68\x2f\x69\x6e\x76\x69\x74\x65\x5f\x64\x69\x61\x6c\x6f\x67\x2e\x70\x68\x70\x3f\x63\x6c\x61\x73\x73\x3d\x46\x61\x6e\x4d\x61\x6e\x61\x67\x65\x72\x26\x61\x6d\x70\x3b\x6e\x6f\x64\x65\x5f\x69\x64\x3d\x31\x30\x38\x34\x36\x33\x39\x31\x32\x35\x30\x35\x33\x35\x36\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x20\x70\x72\x6f\x66\x69\x6c\x65\x5f\x61\x63\x74\x69\x6f\x6e\x20\x61\x63\x74\x69\x6f\x6e\x73\x70\x72\x6f\x5f\x61\x22\x20\x72\x65\x6c\x3d\x22\x64\x69\x61\x6c\x6f\x67\x2d\x70\x6f\x73\x74\x22\x3e\x53\x75\x67\x67\x65\x73\x74\x20\x74\x6f\x20\x46\x72\x69\x65\x6e\x64\x73\x3c\x2f\x61\x3e","\x73\x75\x67\x67\x65\x73\x74
Now I used unescape on the above obfuscated code to read it. What I want to know is what exactly was used to obfuscate the code like that? Basically, I need to customize the readable code to the same obfuscation.
Any help would be greatly appreciated.
If you are using unicode characters above 255, you will need some special handling. You will also need to make sure the hex codes are padded with 0s correctly, or the function will break for characters below 16 (such as \n and \t):
function obfuscate(str) {
var escaped = [];
for (var i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
var cs = "0000" + c.toString(16);
if (c < 256) {
cs = "\\x" + cs.substr(-2);
} else {
cs = "\\u" + cs.substr(-4);
}
escaped.push(cs);
}
return escaped.join('');
}
var ob = obfuscate("Hello world!");
alert(ob);
You shouldn't use obfuscation for anything serious, but it can be fun to play around with:
var readable = '<a id="suggest" href="#" ajaxify="/ajax/social_graph/invite_dialog.php?class=FanManager&node_id=108463912505356" class=" profile_action actionspro_a" rel="dialog-post">Suggest to Friends</a>';
Array.prototype.map.call(readable,
function(c){
return "\\x" + c.charCodeAt().toString(16);
}).join("");
Type the following code in the address bar:
javascript:alert("\x3c\x61\x20\x69\x64\x3d\x22\x73\x75\x67\x67\x65\x73\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x23\x22\x20\x61\x6a\x61\x78\x69\x66\x79\x3d\x22\x2f\x61\x6a\x61\x78\x2f\x73\x6f\x63\x69\x61\x6c\x5f\x67\x72\x61\x70\x68\x2f\x69\x6e\x76\x69\x74\x65\x5f\x64\x69\x61\x6c\x6f\x67\x2e\x70\x68\x70\x3f\x63\x6c\x61\x73\x73\x3d\x46\x61\x6e\x4d\x61\x6e\x61\x67\x65\x72\x26\x61\x6d\x70\x3b\x6e\x6f\x64\x65\x5f\x69\x64\x3d\x31\x30\x38\x34\x36\x33\x39\x31\x32\x35\x30\x35\x33\x35\x36\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x20\x70\x72\x6f\x66\x69\x6c\x65\x5f\x61\x63\x74\x69\x6f\x6e\x20\x61\x63\x74\x69\x6f\x6e\x73\x70\x72\x6f\x5f\x61\x22\x20\x72\x65\x6c\x3d\x22\x64\x69\x61\x6c\x6f\x67\x2d\x70\x6f\x73\x74\x22\x3e\x53\x75\x67\x67\x65\x73\x74\x20\x74\x6f\x20\x46\x72\x69\x65\x6e\x64\x73\x3c\x2f\x61\x3e","\x73\x75\x67\x67\x65\x73\x74")
and it will get decoded.

Categories

Resources