Referencing JS code stored in CSS Content property - javascript

UPDATE: After having the code out in the wild for a while, I found two issues on Citrix and iOS Safari. Both seem to be around the use of Eval. The citrix issue could have been resolved by updating the CSS to :
emailerrormessage = 'please enable Javascript'; ahref.attr('data-edomain') + '\0040' + ahref.attr('data-ename');
The iOS Safari issue was not something I managed to resolve. I ended up cutting out the CSS element altogether.
EDIT: I'm opening up this question for recommendations on why my solution might be considered bad programming in general, and if anyone else has a better way of obfuscating emails through a combination of CSS, HTML and JS. I've added an answer of my own findings, but haven't marked it as the answer in case someone else might have better insight into this technique.
I've been tasked to obfuscate email addresses on some webpages, and after encountering an answer suggesting use of CSS and data attributes I tried implementing it myself and found that getting the produced email address back into a mailto element was impossible without some JavaScript. The next problem encountered was that the JavaScript I ended up using to grab the rendered email address was not cross-browser as some browsers retrieve "attr(data-xx)" instead of the actual value. However I still like the idea of producing a solution that spans HTML, JS and CSS for maximum complexity. The last resort was to store a line of JS in the CSS content property, and use eval to produce the final email address.
Obfuscation is not supposed to be pretty, but I want to know if what I've done is potentially compromising security or performance by introducing eval() and/or storing JS in CSS. I haven't found another example of someone doing something similar (maybe for good reason).
My HTML is
<a class="redlinktext ninjemail" data-ename="snoitagitsevni" data-edomain="ua.moc.em" data-elinktext="click me"></a>
My CSS is
.ninjemail:before {
content: "'please enable Javascript'; ahref.attr('data-edomain') + '\0040' + ahref.attr('data-ename');"
}
My JavaScript is
$('.ninjemail').each(function () {
var fullLink = "ma";
var ahref = $(this);
fullLink += "ilto" + ":";
var codeLine = window.getComputedStyle(this, ':before').content.replace(/\"|\\/g, '');
var emailAddress = eval(codeLine);
emailAddress = emailAddress.split('').reverse().join('');
fullLink += emailAddress;
ahref.attr('href', fullLink);
var linkText = ahref.attr('data-elinktext');
if (linkText && linkText.length > 0) {
ahref.text(linkText);
} else {
ahref.text(emailAddress);
}
ahref.removeClass('ninjemail');
});

Based on the research I've done so far the only real drawback from using this method for obfuscation is that in teams where there is a clear separation of roles, Javascript in CSS files may confuse layout designers, and vice versa (programmers won't want to have to edit CSS files).
Performance wise there will always be more overhead in processing the email address across the three technologies. I can't say I'm an expert on performance testing, but I did a page refresh timing of before and after and got a DOMContentLoaded time of .956s vs .766s without obfuscation. Load time was 1.22s vs 1.17s without obfuscation. Not a concern for my own situation, but may be an issue on more intensive applications. Note that this was a once off test, and not an average of multiple runs in a controlled environment.

Related

Problems with a custom self-closing tag in CKEditor

I have a plugin for inserting tag <cut /> in text.
It works fine, result is expectable, but in editor window <cut /> transforms into <cut></cut>, wraps the paragraphs below and hampers further edits.
GIF - http://gyazo.com/dd7c36ba7cb7bc7cb00186cfb83e5fbc
Any ideas how to fix it?
CKEDITOR.plugins.add('pagecut', {
lang: 'de,en,ru',
onLoad: function(){
var css = ('display:block;clear:both;width:100%;border-top:#999 1px dotted;padding:0;height:1px;cursor:default;');
var cssBefore = (
'content:"";' +
'background: url(' + CKEDITOR.getUrl( this.path + 'images/image.png' ) + ') no-repeat right center;' +
'height:14px;width:25px;position:relative;display:block;top:-8px;float:right;'
);
CKEDITOR.addCss( 'cut{' + css + '} cut:before{' + cssBefore + '}' );
},
init: function(editor) {
CKEDITOR.dtd['cut'] = {};
CKEDITOR.dtd.$empty['cut'] = 1;
CKEDITOR.dtd.$nonEditable['cut'] = 1;
CKEDITOR.dtd.$object['cut'] = 1;
editor.addCommand('insertPagecut', {
exec: function(editor) {
var element = CKEDITOR.dom.element.createFromHtml('<cut />');
editor.insertElement(element);
}
});
editor.ui.addButton('Pagecut', {
label: editor.lang.pagecut.toolbar,
command: 'insertPagecut',
icon: this.path + 'images/icon.png',
toolbar: 'links'
});
}
});
Uh, I'm sure that I explained this thoroughly in some question, but I can't find it, so here goes another explanation :D.
There are two important facts that one must understand before trying to edit non-HTML tags in CKEditor:
CKEditor is an HTML editor.
Of course custom tags start to be more and more popular in HTML. You can also say that XML is some kind of generalisation of HTML (although not precisely, because it has other rules), so if CKEditor handles HTML why doesn't it handle other tags equally well. Well - the answer is simple - because HTML tags have a meaning and CKEditor knows it. But it does not know meaning of your custom tags. And the meaning of tags (what a list is, that it has items, that they are block elements, etc.) is crucial to implement editing algorithms.
Fair enough, you could say. But why wasn't CKEditor's configuration (e.g. the CKEDITOR.dtd object) generalised so meaning of every possible tag can be configured? Because every generalisation increases complexity and HTML editing is already complex enough.
So why does the CKEDITOR.dtd object exist at all? Because some components of CKEditor are configurable to some extent. The DTD has the biggest impact on CKEditor's HTML parser (which is used mostly during data processing) so this is the most configurable component. Other algorithms, like the enter key handling, backspace/delete, lists editing (which is a very complex task) are only slightly configurable and there is no guarantee given that they will work with your custom tags.
The editing happens in the browsers and is partially handled by the browsers.
This fact is important because it means that browsers' capabilities are affecting CKEditor's limits too. Browser must be able to parse and render your tags (fortunately, this part works rather well in modern browsers - IE8 is the last one with a huge problems) and must be able to edit it. This means - render caret, handle selection, handle backspace, enter, etc. Since browsers are not easily extensible and their implementations of contentEditable are highly inconsistent, incompatible and buggy, from release to release CKEditor overrides more and more of their native behaviours. Not all yet (actually - it will never override all, because that could be disastrous for certain reasons), but a significant amount. For instance, all the enter key behaviour is custom, on Webkit and Blink CKEditor handles backspace and delete in many scenarios due to still unresolved bugs (1 and 2), it implements its own undo system, intercepts pasted and dropped content and perform custom HTML insertion (I remember that when we implemented it this closed a huge number of tickets), etc., etc.
One of the greatest efforts to ensure consistent, configurable and powerful editing experience is the widgets system. It is full of hacks inside, but it exposes a clean and pretty powerful API to the developer and a very consistent behaviour to the end user. It allows to implement a "special rich content units that are groups of elements which are treated as a single entity inside the editor". So the widgets system has the power to encapsulate part of your content and isolate it from the browsers.
After this short introduction I can finally answer your question. You need to implement your <cut> tag as a widget. You already configured your DTD pretty well (you only forgot to set in what elements the <cut> element can exist and whether it is more like a block or inline element), so the parser will accept it and handle as an empty tag. Now you need to wrap it with a widget in order to isolate it so it does not break the editing experience. That should do the trick.

Find all string variables in javascript files

i am facing the problem that i have to translate a larger html and javascript project into several languages. The html content was no problem, but the numerous javascript files are problematic, since i was a bit lazy during the development process. For instance, if i needed a message text, i just added it in the concerning position.
My approach now is, that i am using a build-in file search (Eclipse) for every occurrence of " and ', which i am getting line-wise. This would be extremely time consuming and errors are unavoidable.
Here are some examples that occur in the files:
var d = "Datum: " + d.getDate()+"."+(d.getMonth()+1)+"."+d.getFullYear();
showYesNoDialog("heading text","Are you sure?",function(){};
Sometimes i am mixing " and ', sometimes a string goes over several lines:
var list="";
list+='<li data-role="list-divider">';
list+='Text To Translate';
list+='</li>';
Things i don't want to get, are jquery selectors, e.g.:
$("input[name^=checkbox]").each(function () {};
Do you see any time saving method to get all of the strings that i would like to translate?
Regex? A java interpreter? Grep?
I know, that is a bit unusual question.
So any suggestion would be great.
Thanks in advance!
It is better to use some kind of the lexical scanner that converts the code into the tokens and then walk over the list of tokens (or syntax tree). There is a number of such tools (I even created one of them myself - here you can find some of the examples https://github.com/AlexAtNet/spelljs/blob/master/test/scan.js).
With it you can scan the JS file and just iterate over the tokens:
var scan = require('./..../scan.js');
scan(text).forEach(function (item) {
if (item.str) {
console.log(item);
}
});

different ways to append html?

I just wanted to know the differences between the methods of adding html in jquery.
both will do samething right?
$('body').append($("<div><img src='somesource' alt='something'></div>"));
and
var div = $("<div>");
var img = $("<img>").attr({"src" : "somesource", "alt" : "something"});
div.append(img);
$('body').append(div);
which is the best practice to follow?
The second is better. Because you often see people doing this:
var alt = 'This is " the title containing a double quote';
$('body').append($('<div><img src="somesource" alt="' + alt + '"></div>'));
and then wonder why something got eaten :-). Whereas when you use the second you have absolutely nothing to worry about:
var alt = 'This is " the title containing a double quote';
var div = $('<div>');
var img = $('<img>').attr({ src : 'somesource', alt : alt });
div.append(img);
$('body').append(div);
UPDATE:
I was too hasty in saying that you have nothing to worry about with the second approach. As others have already pointed out you have to worry about performance.
The second method looks better and there are lesser chances of error. But performance wise, the second method is slower. So if you're going to be doing a lot of appending, I would recommend going with the the first case - albeit, carefully.
Here's a small test case up on JS-Perf comparing the two methods
Normally I would say DOM-scripting is the better option (the second approach); it's more structured, and easier to catch issues than by inserting a mass of HTML prepared as a string.
That said, there are performance concerns. Inserting loads of elements via DOM-scripting, particularly in a loop, can cause significant slowdown and there are cases where inserting as a string is much quicker.
Also, the fewer inserts you do - by whatever means - the fewer repaints/refreshes you force the browser to make. Again, these all require browser attention, so the fewer the better.
I believe you are better off using template libraries for inserting objects. An example of one such library is here: http://api.jquery.com/category/plugins/templates/
Those libraries are build for performance and ease the burden on parsing HTML blobs.
Adding a string of HTML content is about 10 times faster
than using second method
Here is a reference
See also my answer on When do you use DOM-based Generation vs. using strings/innerHTML/JQuery to generate DOM content?
The difference is that you have two variables pointing to the jQuery instances. You might can need them for eventListener-adding or manipulating them lateron in the code.
Also, DOM-based element generation has the advantage of automatically escaping the strings, which is especially useful when designing functions with parameters and absolutely needed for user input.
Therefore, the second method is most often preferred. You can also nest the appending process to make the structure clear (OK, in this example the one-liner would be clear as well):
var div = $("<div>");
var img = $("<img>", {"src":"somesource", "alt":"something"});
$('body').append(
div.append(
img
)
);
I would prefer the second one as the first one could lead to very long lines and if you need to bind events to certain elements you already have a variable that is pointing to it.

How to clean up divs contents?

I heared that simply to say document.getElementById('divId').innerHTML = ""; is not safe for future divId contents editing via JS so how to clean up divs contents safely?
What should always work is:
var div = document.getElementById('divId');
while(div.hasChildNodes()) {
div.removeChild(div.firstChild);
}
innerHTML is not part of any specification but is widely supported by browsers.
I wrote something similar to Felix Kling, only diffirence is that I wanted to pass the id or the reference. So I wrote it like this:
function removeAllChildNodes(node) {
i = (typeof(node) == "object") ? node : document.getElementById(node);
while (i.hasChildNodes()) {
i.removeChild(i.firstChild);
}
}
Setting the innerHTML attribute to nothing will eliminate any DOM nodes withing the specified DIV. There is no risk of "safety".
You can do this safely :P
I believe this is where JS frameworks, such as jQuery, come to light... they are optimized for cross-browser security - which includes secure DOM element removal, although you will loose a bit of computing speed (setting innerHTML is always the fastest way)
as for others wondering about security of this, some browsers (notably MSIE) have flaws that would crash the browser or allow malicious procedures to be executed on client's side under certain conditions, so that's why setting innerHTML might not be as secure as people use to think ;-)

is the + operator less performant than StringBuffer.append()

On my team, we usually do string concatentation like this:
var url = // some dynamically generated URL
var sb = new StringBuffer();
sb.append("<a href='").append(url).append("'>click here</a>");
Obviously the following is much more readable:
var url = // some dynamically generated URL
var sb = "<a href='" + url + "'>click here</a>";
But the JS experts claim that the + operator is less performant than StringBuffer.append(). Is this really true?
Your example is not a good one in that it is very unlikely that the performance will be signficantly different. In your example readability should trump performance because the performance gain of one vs the other is negligable. The benefits of an array (StringBuffer) are only apparent when you are doing many concatentations. Even then your mileage can very depending on your browser.
Here is a detailed performance analysis that shows performance using all the different JavaScript concatenation methods across many different browsers; String Performance an Analysis
More:
Ajaxian >> String Performance in IE: Array.join vs += continued
Internet Explorer is the only browser which really suffers from this in today's world. (Versions 5, 6, and 7 were dog slow. 8 does not show the same degradation.) What's more, IE gets slower and slower the longer your string is.
If you have long strings to concatenate then definitely use an array.join technique. (Or some StringBuffer wrapper around this, for readability.) But if your strings are short don't bother.
Yes it's true but you shouldn't care. Go with the one that's easier to read. If you have to benchmark your app, then focus on the bottlenecks.
I would guess that string concatenation isn't going to be your bottleneck.
Agreed with Michael Haren.
Also consider the use of arrays and join if performance is indeed an issue.
var buffer = ["<a href='", url, "'>click here</a>"];
buffer.push("More stuff");
alert(buffer.join(""));
Try this:
var s = ["<a href='", url, "'>click here</a>"].join("");
Like already some users have noted: This is irrelevant for small strings.
And new JavaScript engines in Firefox, Safari or Google Chrome optimize so
"<a href='" + url + "'>click here</a>";
is as fast as
["<a href='", url, "'>click here</a>"].join("");
JavaScript doesn't have a native StringBuffer object, so I'm assuming this is from a library you are using, or a feature of an unusual host environment (i.e. not a browser).
I doubt a library (written in JS) would produce anything faster, although a native StringBuffer object might. The definitive answer can be found with a profiler (if you are running in a browser then Firebug will provide you with a profiler for the JS engine found in Firefox).
In the words of Knuth, "premature optimization is the root of all evil!" The small defference either way will most likely not have much of an effect in the end; I'd choose the more readable one.
The easier to read method saves humans perceptible amounts of time when looking at the code, whereas the "faster" method only wastes imperceptible and likely negligible amounts of time when people are browsing the page.
I know this post is lame, but I accidentally posted something entirely different thinking this was a different thread and I don't know how to delete posts. My bad...
It is pretty easy to set up a quick benchmark and check out Javascript performance variations using jspref.com. Which probably wasn't around when this question was asked. But for people stumbling on this question they should take alook at the site.
I did a quick test of various methods of concatenation at http://jsperf.com/string-concat-methods-test.
I like to use functional style, such as:
function href(url,txt) {
return "<a href='" +url+ "'>" +txt+ "</a>"
}
function li(txt) {
return "<li>" +txt+ "</li>"
}
function ul(arr) {
return "<ul>" + arr.map(li).join("") + "</ul>"
}
document.write(
ul(
[
href("http://url1","link1"),
href("http://url2","link2"),
href("http://url3","link3")
]
)
)
This style looks readable and transparent. It leads to the creation of utilities which reduces repetition in code.
This also tends to use intermediate strings automatically.
As far I know, every concatenation implies a memory reallocation. So the problem is not the operator used to do it, the solution is to reduce the number of concatenations. For example do the concatenations outside of the iteration structures when you can.
Yes, according to the usual benchmarks. E.G : http://mckoss.com/jscript/SpeedTrial.htm.
But for the small strings, this is irrelevant. You will only care about performances on very large strings. What's more, in most JS script, the bottle neck is rarely on the string manipulations since there is not enough of it.
You'd better watch the DOM manipulation.

Categories