You are browsing the archives of javascript.
javascript
Python NaN equality rules (and cw.eq.equals)
>>> float('nan') == float('nan')
False
>>> n = float('nan')
>>> n
nan
>>> n == n
False
>>> [float('nan')] == [float('nan')]
False # Note: in PyPy, True
>>> [n] == [n]
True
>>> nl = [float('nan')]
>>> nl == nl
True
Got it? Good. (The behavior above is caused by various object-identity shortcuts for either the NaN or the list object.)
If you’re wondering how this works in JavaScript, well, it doesn’t, because JavaScript doesn’t have any kind of deep-equality comparison. JavaScript Arrays and Objects compare by identity. But in Coreweb’s cw.eq.equals, I didn’t implement the object-identity shortcut, so NaN comparison works correctly:
>>> Number.NaN == Number.NaN
false
>>> n = Number.NaN
NaN
>>> n == n
false
>>> cw.eq.equals([Number.NaN], [Number.NaN])
false
>>> cw.eq.equals([n], [n])
false
>>> nl = [Number.NaN]
[NaN]
>>> cw.eq.equals(nl, nl)
false
Preserving italics in pastes from webpages
Tired of losing italics in pastes from websites to your plain-text editor? For a while, I thought I needed to switch to a rich-text editor to handle these pastes, but that would be a pain for several reasons. A few days ago I realized I just needed to mutate the webpage by surrounding italic text with slashes. I would run a bookmarklet, then copy/paste. (Skip below for a working bookmarklet).
My first attempt at this used the :before and :after CSS pseudo-elements:
javascript:(function() { var newSS, styles='em:before, em:after, i:before, i:after { content: "/" }'; if(document.createStyleSheet) { document.createStyleSheet("javascript:'" + styles + "'"); } else { newSS = document.createElement('link'); newSS.rel = 'stylesheet'; newSS.href = 'data:text/css,' + escape(styles); document.getElementsByTagName("head")[0].appendChild(newSS); } })();
If you run the above (paste into your URL bar and hit enter), it looks like it works until you try to paste the text containing slashes; neither Chrome 10 or Firefox 4 will put the slashes in your clipboard. I threw out the simple clean non-working code and went for a terrible hack:
javascript:(function() { document.body.innerHTML = document.body.innerHTML. replace(/<em(\s.*?)?>([\s\S]+?)<\/em>/gi, "/<em$1>$2</em>/"). replace(/<i(\s.*?)?>([\s\S]+?)<\/i>/gi, "/<i$1>$2</i>/"). replace(/<span style="font-style: italic;">([\s\S]+?)<\/span>/gi, '/<span style="font-style: italic;">$1</span>/'). replace(/<strong(\s.*?)?>([\s\S]+?)<\/strong>/gi, "*<strong$1>$2</strong>*"). replace(/<b(\s.*?)?>([\s\S]+?)<\/b>/gi, "*<b$1>$2</b>*"); })();
This above replaces document.body.innerHTML with a new string where italics are surrounded with “/” and bold surrounded by “*”. This is terrible in several ways: it may break or re-run JavaScript code on the page, or somehow make you vulnerable to XSS (in a manner likely similar to the IE8 XSS “blocker”). Only while writing this post did I realize the security implications of the above. I decided to implement it using DOM manipulation (requires CSS3 selectors and querySelectorAll):
javascript:(function() { var wrapElements = function(selector, wrapperText) { var elements = document.querySelectorAll(selector); for(var i=0; i < elements.length; i++) { var surround = elements[i]; if(surround.parentNode) { surround.parentNode.insertBefore( document.createTextNode(wrapperText), surround); } surround.appendChild( document.createTextNode(wrapperText)); } }; var getStyleAttrVariations = function(elem, property, value) { return [ elem + '[style="' + property + ': ' + value + ';"]' ,elem + '[style="' + property + ': ' + value + '"]' ,elem + '[style="' + property + ':' + value + ';"]' ,elem + '[style="' + property + ':' + value + '"]' ]; }; wrapElements('em, i, span[class~="emphasis"], span[class~="italic"]', '/'); wrapElements(getStyleAttrVariations('span', 'font-style', 'italic').join(' ,'), '/'); wrapElements('strong, b, span[class~="bold"]', '*'); wrapElements(getStyleAttrVariations('span', 'font-weight', 'bold').join(' ,'), '*'); })();
If you don’t want to manually create a bookmark with the above code, you can drag this link to your toolbar or bookmarks:
I use a bookmark keyword in Firefox to activate it; keywords are not just for searches.
Here’s some bold and italic text so you know it’s working: bold, italic.
JavaScript’s sort: wonders never cease
>>> [1, 2, 10, 20].sort() [1, 10, 2, 20] >>> [3, "3", 3, "3", "3", "3", 3, 3, 3].sort() ["3", "3", "3", 3, 3, 3, "3", 3, 3]
The above was tested in Chrome 5. Sort varies by browser. Bedtime reading: ECMA-262 15.4.4.11 Array.prototype.sort(comparefn)
Clock jumps and browsers
If you’re trying to build reliable web applications, you might have wondered what happens to existing timeouts and intervals after the system clock jumps. Not that clock jumps happen very often, but it’s nice to think of setTimeout(func, 0) (or similar) as a reliable abstraction. Unfortunately, it isn’t. See Clock jump test page for the results of my testing, or to do your own tests.
In some browsers on some OSes, if the clock jumps backwards, an existing timer might not fire for a long time. If the clock jumps forwards, an existing timer might fire too early, possibly causing misbehavior if you were relying on a correct time duration.
A summary of the test page: IE and Opera on any OS use the monotonic clock to schedule timeouts. Firefox on Windows uses the monotonic clock, but a setInterval timer is broken after a backwards clock jump. Every other OS/browser combination schedules by the system time, or behaves strangely when the time jumps.
Here’s the bug for Chromium, but a lot more bugs need to be filed.