I have some code which creates a 'typing text effect' on a page - i.e. javascript takes a string and outputs it on the screen in a way that makes it look like it is being typed. I took the code from a demo here.
The problem is that I want it to output html code, e.g. the output on the screen should be something like:
<html>
<body>
Something here etc etc...
</body>
</head>
In chrome, this works in a rather erratic fashion - sometimes it works perfectly, but other times it doesn't display the first left angle bracket, leaving me with the output of 'html>' rather than '<html>'. In safari, the left angle bracket doesn't display at all. I've tried various things, using '<' instead of the bracket, using unicode, but that everything I do seems to end with the same result.
Here is a github gist of the code, and here is a bl.ocks page to showing it in action. I tried to make a jsfiddle but couldn't get it to run properly, sorry!
Any help is much appreciated, it's been driving me nuts.
Cheers
Nick
Instead of
$span.append(thisLine[letterIndex]);
try
$span.text($span.text() + thisLine[letterIndex]);
Or, per crush's comment below, you could do a string replace:
$span.append(thisLine[letterIndex].replace(/</g,'<').replace(/>/g,'>'));
This works because when you want to display HTML tags, you need to use < and > rather than just < and >, otherwise the browser thinks you're putting in an actual HTML tag, if that makes sense to you. The jquery text method automatically escapes the brackets for you, and in my second example, we're just doing a string replace before passing the string to append.
It looks as if the code appends '<' as '&','l','t',';'. Not verified this but you might want to try:
function typeLetter(lineIndex, letterIndex, $span, line, callback) {
var thisLine = line;
var thisLength = line.length;
var chunk='';
// add the letter
chunk=thisLine[letterIndex];
if ('&'==thisLine[letterIndex]) {
for (var i=1; i<5; i++) {
letterIndex++;
chunk+=thisLine[letterIndex];
if (';'==thisLine[letterIndex] || letterIndex>=thisLength-1) break;
}
}
$span.append(chunk);
...
Related
I'm working on designing a website, and I want to make sure that no one can steal the code. I would like to prevent the code from being taken out of the website, and display an error message if a user tries to do so.
HTML Obfuscation is a transformational tool that both preserves the code and prevents it from being reverse-engineered. You can find out more about it here.
Here is an example of obfuscated code.
This is extremely simple HTML code:
Mail me
This can be turned into this:
<script type="text/javascript">
<!--
var s="=b!isfg>#nbjmup;tpnfpofAepnbjo/dpn#?Nbjm!nf=0b?";
m=""; for (i=0; i<s.length; i++).m+=String.fromCharCode(s.charCodeAt(i)-1); document.write(m);
//-->
</script>
<noscript>

<a href="mailto:someone@domain.com">Mail me</a>
</noscript>
This is called Combined obfuscation.
<script type="text/javascript">
<!--
var s="=b!isfg>#nbjmup;tpnfpofAepnbjo/dpn#?Nbjm!nf=0b?";
m=""; for (i=0; i<s.length; i++) m+=String.fromCharCode(s.charCodeAt(i)-1); document.write(m);
//-->
</script>
<noscript>
You must enable JavaScript to see this text.
</noscript>
This is called JavaScript obfuscation.

<a href="mailto:someone@domain.com">Mail me</a>

This is called Character Entities obfuscation.
All of these methods are entirely free on that website, and let you keep all your code private.
EDIT:
After further research, I found another website, JSF**K, which lets you encode items using a series of brackets, parentheses, exclamations and plus signs. Below is how it encodes a simple item:
alert(1)
becomes:
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
This is practically impossible to crack, as you'd need to "fuzz" the website with data to obtain the character codes and then use regular expressions to build a decoder.
#JBDouble05 gave a great answer to your question and I totally recommend it. I wanted to share an example that I threw together for fun, that employs some of the techniques he described. It uses HTML obfuscation via zero-width whitespace characters. I also threw in JSF*CK to really make the source code interesting :D
First, the URL which is serving the obfuscated code: http://jackpattishall.com/obfuscated.html
(Uses padStart, so you'll need to view in a browser that supports that!)
If you view the source (using Chrome), you'll notice that 98% or so of the markup visible is JSF*CK (basically all those() and []):
If you scroll long enough, you'll see a variable that seems to be assigned nothing:
The var m is actually assigned the following zero-width whitespace characters:
const m = "";
Try copy/pasting the previous line in Chrome console. You should get something like:
(Any text editor that shows special characters will do the same!)
The massive JSF*CK code is basically the following (but minified):
const zero_regex = new RegExp(zero, 'g');
const one_regex = new RegExp(one, 'g');
const binToText = text => {
let str = text.replace(zero_regex, '0').replace(one_regex, '1');
if (str.match(/[10]{8}/g)) {
return str.match(/([10]{8}|\s+)/g).map(val => {
return String.fromCharCode(parseInt(val, 2));
}).join('');
}
}
The script responsible for the obfuscation looks like:
// Our zero-width whitespace chars
const zero = '';
const one = '';
const textToBin = text => {
let len = text.length;
let output = [];
let i = 0;
for (; i < len; i++) {
output.push(text[i].charCodeAt().toString(2).padStart(8, '0'));
}
return output.join('').replace(/0/g, zero).replace(/1/g, one);
}
Here's a JSFiddle that shows a bit more of the magic:
http://jsfiddle.net/z5gu4bq1/
Hope this was helpful. Have fun with JavaScript! And please never do this in Production :)
Resources:
JSF*CK
White-space Obfuscation Reference
I realize that there are several similar questions here but none of the answers solve my case.
I need to be able to take the innerHTML of an element and truncate it to a given character length with the text contents of any inner HTML element taken into account and all HTML tags preserved.
I have found several answers that cover this portion of the question fine as well as several plugins which all do exactly this.
However, in all cases the solution will truncate directly in the middle of any inner elements and then close the tag.
In my case I need the contents of all inner tags to remain intact, essentially allowing any "would be" truncated inner tags to exceed the given character limit.
Any help would be greatly appreciated.
EDIT:
For example:
This is an example of a link inside another element
The above is 51 characters long including spaces. If I wanted to truncate this to 23 characters, we would have to shorten the text inside the </a> tag. Which is exactly what most solutions out there do.
This would give me the following:
This is an example of a
However, for my use case I need to keep any remaining visible tags completely intact and not truncated in any way.
So given the above example, the final output I would like, when attempting to truncate to 23 characters is the following:
This is an example of a link
So essentially we are checking where the truncation takes place. If it is outside of an element we can split the HTML string to exactly that length. If on the other hand it is inside an element, we move to the closing tag of that element, repeating for any parent elements until we get back to the root string and split it there instead.
It sounds like you'd like to be able to truncate the length of your HTML string as a text string, for example consider the following HTML:
'<b>foo</b> bar'
In this case the HTML is 14 characters in length and the text is 7. You would like to be able to truncate it to X text characters (for example 2) so that the new HTML is now:
'<b>fo</b>'
Disclosure: My answer uses a library I developed.
You could use the HTMLString library - Docs : GitHub.
The library makes this task pretty simple. To truncate the HTML as we've outlined above (e.g to 2 text characters) using HTMLString you'd use the following code:
var myString = new HTMLString.String('<b>foo</b> bar');
var truncatedString = myString.slice(0, 2);
console.log(truncatedString.html());
EDIT: After additional information from the OP.
The following truncate function truncates to the last full tag and caters for nested tags.
function truncate(str, len) {
// Convert the string to a HTMLString
var htmlStr = new HTMLString.String(str);
// Check the string needs truncating
if (htmlStr.length() <= len) {
return str;
}
// Find the closing tag for the character we are truncating to
var tags = htmlStr.characters[len - 1].tags();
var closingTag = tags[tags.length - 1];
// Find the last character to contain this tag
for (var index = len; index < htmlStr.length(); index++) {
if (!htmlStr.characters[index].hasTags(closingTag)) {
break;
}
}
return htmlStr.slice(0, index);
}
var myString = 'This is an <b>example ' +
'of a link ' +
'inside</b> another element';
console.log(truncate(myString, 23).html());
console.log(truncate(myString, 18).html());
This will output:
This is an <b>example of a link</b>
This is an <b>example of a link inside</b>
Although HTML is notorious for being terribly formed and has edge cases which are impervious to regex, here is a super light way you could hackily handle HTML with nested tags in vanilla JS.
(function(s, approxNumChars) {
var taggish = /<[^>]+>/g;
var s = s.slice(0, approxNumChars); // ignores tag lengths for solution brevity
s = s.replace(/<[^>]*$/, ''); // rm any trailing partial tags
tags = s.match(taggish);
// find out which tags are unmatched
var openTagsSeen = [];
for (tag_i in tags) {
var tag = tags[tag_i];
if (tag.match(/<[^>]+>/) !== null) {
openTagsSeen.push(tag);
}
else {
// quick version that assumes your HTML is correctly formatted (alas) -- else we would have to check the content inside for matches and loop through the opentags
openTagsSeen.pop();
}
}
// reverse and close unmatched tags
openTagsSeen.reverse();
for (tag_i in openTagsSeen) {
s += ('<\\' + openTagsSeen[tag_i].match(/\w+/)[0] + '>');
}
return s + '...';
})
In a nutshell: truncate it (ignores that some chars will be invisible), regex match the tags, push open tags onto a stack, and pop off the stack as you encounter closing tags (again, assumes well-formed); then close any still-open tags at the end.
(If you want to actually get a certain number of visible characters, you can keep a running counter of how many non-tag chars you've seen so far, and stop the truncation when you fill your quota.)
DISCLAIMER: You shouldn't use this as a production solution, but if you want a super light, personal, hacky solution, this will get basic well-formed HTML.
Since it's blind and lexical, this solution misses a lot of edge cases, including tags that should not be closed, like <img>, but you can hardcode those edge cases or, you know, include a lib for a real HTML parser if you want. Fortunately, since HTML is poorly formed, you won't see it ;)
You've tagged your question regex, but you cannot reliably do this with regular expressions. Obligatory link. So innerHTML is out.
If you're really talking characters, I don't see a way to do it other than to loop through the nodes within the element, recursing into descendant elements, totalling up the lengths of the text nodes you find as you go. When you find the point where you need to truncate, you truncate that text node and then remove all following ones — or probably better, you split that text node into two parts (using splitText) and move the second half into a display: none span (using insertBefore), and then move all subsequent text nodes into display: none spans. (This makes it much easier to undo it.)
Thanks to T.J. Crowder I soon came to the realization that the only way to do this with any kind of efficiency is to use the native DOM methods and iterate through the elements.
I've knocked up a quick, reasonably elegant function which does the trick.
function truncate(rootNode, max){
//Text method for cross browser compatibility
var text = ('innerText' in rootNode)? 'innerText' : 'textContent';
//If total length of characters is less that the limit, short circuit
if(rootNode[text].length <= max){ return; }
var cloneNode = rootNode.cloneNode(true),
currentNode = cloneNode,
//Create DOM iterator to loop only through text nodes
ni = document.createNodeIterator(currentNode, NodeFilter.SHOW_TEXT),
frag = document.createDocumentFragment(),
len = 0;
//loop through text nodes
while (currentNode = ni.nextNode()) {
//if nodes parent is the rootNode, then we are okay to truncate
if (currentNode.parentNode === cloneNode) {
//if we are in the root textNode and the character length exceeds the maximum, truncate the text, add to the fragment and break out of the loop
if (len + currentNode[text].length > max){
currentNode[text] = currentNode[text].substring(0, max - len);
frag.appendChild(currentNode);
break;
}
else{
frag.appendChild(currentNode);
}
}
//If not, simply add the node to the fragment
else{
frag.appendChild(currentNode.parentNode);
}
//Track current character length
len += currentNode[text].length;
}
rootNode.innerHTML = '';
rootNode.appendChild(frag);
}
This could probably be improved, but from my initial testing it is very quick, probably due to using the native DOM methods and it appears to do the job perfectly for me. I hope this helps anyone else with similar requirements.
DISCLAIMER: The above code will only deal with one level deep HTML tags, it will not deal with tags inside tags. Though it could easily be modified to do so by keeping track of the nodes parent and appending the nodes to the correct place in the fragment. As it stands, this is fine for my requirements but may not be useful to others.
When I use the new line character in java-script it is not working. I post my code below.
var i=1;
while(i<=5)
{
document.write(i+"\n");
i++;
}
The outcome looks like this.
1 2 3 4 5
since you are writing into HTML Document, you should write <br>
var i=1;
while(i<=5){
document.write(i+"<br/>");
i++;
}
Instead of "\n", use "<br/>", as the code below:
var i=1;
while(i<=5)
{
document.write(i+"<br/>");
i++;
}
Here is the JSFiddle. When accessing it, click run to see the code.
The reason that you are not seeing the newline characters as you expected is because you are likely trying to render this in HTML. If that is the case, "\n" is not rendered as a newline. Which is why #Yuriy Galanter said to include <br/> which is. If you were to write to the console.log then it would work as you have it written.
I am currently trying to code an input form where you can type and format a text for later use as XML entries. In order to make the HTML code XML-readable, I have to replace the code brackets with the corresponding symbol codes, i.e. < with < and > with >.
The formatted text gets transferred as HTML code with the variable inputtext, so we have for example the text
The <b>Genji</b> and the <b>Heike</b> waged a long and bloody war.
which needs to get converted into
The <b>Genji</b> and the <b>Heike</b> waged a long and bloody war.
I tried it with the .replace() function:
inputxml = inputxml.replace("<", "<");
inputxml = inputxml.replace(">", ">");
But this would just replace the first occurrence of the brackets. I'm pretty sure I need some sort of loop for this; I also tried using the each() function from jQuery (a friend recommended I looked at the jQuery package), but I'm still new to coding in general and I have troubles getting this to work.
How would you code a loop which would replace the code brackets within a variable as described above?
Additional information
You are, of course, right in the assumption that this is part of something larger. I am a graduate student in Japanese studies and currently, I am trying to visualize information about Japenese history in a more accessible way. For this, I am using the Simile Timeline API developed by MIT grad students. You can see a working test of a timeline on my homepage.
The Simile Timeline uses an API based on AJAX and Javascript. If you don't want to install the AJAX engine on your own server, you can implement the timeline API from the MIT. The data for the timeline is usually provided either by one or several XML files or JSON files. In my case, I use XML files; you can have a look at the XML structure in this example.
Within the timeline, there are so-called "events" on which you can click in order to reveal additional information within an info bubble popup. The text within those info bubbles originates from the XML source file. Now, if you want to do some HTML formatting within the info bubbles, you cannot use code bracket because those will just be displayed as plain text. It works if you use the symbol codes instead of the plain brackets, however.
The content for the timeline will be written by people absolutely and totally not accustomed to codified markup, i.e. historians, art historians, sociologists, among them several persons of age 50 and older. I have tried to explain to them how they have to format the XML file if they want to create a timeline, but they occasionally slip up and get frustrated when the timeline doesn't load because they forgot to close a bracket or to include an apostrophe.
In order to make it easier, I have tried making an easy-to-use input form where you can enter all the information and format the text WYSIWYG style and then have it converted into XML code which you just have to copy and paste into the XML source file. Most of it works, though I am still struggling with the conversion of the text markup in the main text field.
The conversion of the code brackets into symbol code is the last thing I needed to get working in order to have a working input form.
look here:
http://www.bradino.com/javascript/string-replace/
just use this regex to replace all:
str = str.replace(/\</g,"<") //for <
str = str.replace(/\>/g,">") //for >
To store an arbitrary string in XML, use the native XML capabilities of the browser. It will be a hell of a lot simpler that way, plus you will never have to think about the edge cases again (for example attribute values that contain quotes or pointy brackets).
A tip to think of when working with XML: Do never ever ever build XML from strings by concatenation if there is any way to avoid it. You will get yourself into trouble that way. There are APIs to handle XML, use them.
Going from your code, I would suggest the following:
$(function() {
$("#addbutton").click(function() {
var eventXml = XmlCreate("<event/>");
var $event = $(eventXml);
$event.attr("title", $("#titlefield").val());
$event.attr("start", [$("#bmonth").val(), $("#bday").val(), $("#byear").val()].join(" "));
if (parseInt($("#eyear").val()) > 0) {
$event.attr("end", [$("#emonth").val(), $("#eday").val(), $("#eyear").val()].join(" "));
$event.attr("isDuration", "true");
} else {
$event.attr("isDuration", "false");
}
$event.text( tinyMCE.activeEditor.getContent() );
$("#outputtext").val( XmlSerialize(eventXml) );
});
});
// helper function to create an XML DOM Document
function XmlCreate(xmlString) {
var x;
if (typeof DOMParser === "function") {
var p = new DOMParser();
x = p.parseFromString(xmlString,"text/xml");
} else {
x = new ActiveXObject("Microsoft.XMLDOM");
x.async = false;
x.loadXML(xmlString);
}
return x.documentElement;
}
// helper function to turn an XML DOM Document into a string
function XmlSerialize(xml) {
var s;
if (typeof XMLSerializer === "function") {
var x = new XMLSerializer();
s = x.serializeToString(xml);
} else {
s = xml.xml;
}
return s
}
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/replace
You might use a regular expression with the "g" (global match) flag.
var entities = {'<': '<', '>': '>'};
'<inputtext><anotherinputext>'.replace(
/[<>]/g, function (s) {
return entities[s];
}
);
You could also surround your XML entries with the following:
<![CDATA[...]]>
See example:
<xml>
<tag><![CDATA[The <b>Genji</b> and the <b>Heike</b> waged a long and bloody war.]]></tag>
</xml>
Wikipedia Article:
http://en.wikipedia.org/wiki/CDATA
What you really need, as mentioned in comments, is to XML-encode the string. If you absolutely want to do this is Javascript, have a look at the PHP.js function htmlentities.
I created a simple JS function to replace Greater Than and Less Than characters
Here is an example dirty string: < noreply#email.com >
Here is an example cleaned string: [ noreply#email.com ]
function RemoveGLthanChar(notes) {
var regex = /<[^>](.*?)>/g;
var strBlocks = notes.match(regex);
strBlocks.forEach(function (dirtyBlock) {
let cleanBlock = dirtyBlock.replace("<", "[").replace(">", "]");
notes = notes.replace(dirtyBlock, cleanBlock);
});
return notes;
}
Call it using
$('#form1').submit(function (e) {
e.preventDefault();
var dirtyBlock = $("#comments").val();
var cleanedBlock = RemoveGLthanChar(dirtyBlock);
$("#comments").val(cleanedBlock);
this.submit();
});
I have already asked this question in offical Flot google groups, but got no answear. Maybe because it is more javascript oriented, here is the question:
I have added the following code in my code:
var j = "d";
j = j.sub();
plot1 = $.plot($("#grafTemp"), [
{label: "Rosišče (°C): T" + j + "(t) = ---.---°C"
.... the rest does not matter.
And:
legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2) +"°C"));
I was using this example:
http://people.iola.dk/olau/flot/examples/tracking.html
Now, the subscript works ok, it displays T_d fine. But when I update
the graph (when user moves mouse over graph), then it displays
<sub>d</sub>
I know that the problem is at the legends.eq(i).text....., where
it returns pure string, with literal:
<sub>
I would like to know, how it would be possible to fix this issue. So it would use html element sub properly?
Glancing at the code, it looks like you'd replace the use of text (e.g., legends.eq(i).text(...)) with html (legends.eq(i).html(...)). But you'd need to be sure that there aren't other generated bits of it that would be a problem (for instance, if this stuff generated a string that had a < or & in it, that would need to be converted to < / & respectively before being fed into the html function).