Infinitely nested hashes in Javascript (Coffeescript)
The NestedHash
class allows you to read and write hashes of any depth. Examples:
hash = {}
NestedHash.write hash, 'a', 'b', 'c', 'value' # => { a: { b: { c: 'value' } } }
NestedHash.read hash, 'a', 'b', 'c' # => 'value'
NestedHash.read hash, 'a' # => { b: { c: 'value' } }
NestedHash.read hash, 'foo', 'bar' # => undefined
Inspired by victusfate.
Code
class @NestedHash
@read: (objekt, keys...) ->
if objekt and keys.length
@read objekt[keys[0]], keys[1...]...
...
IE11: Trigger native mouse events with Javascript
The attached Coffeescript helper will let you create mouse events:
$element = $('div')
Trigger.mouseover($element)
Trigger.mouseenter($element)
Trigger.mousedown($element)
Trigger.mouseup($element)
Trigger.mouseout($element)
Trigger.mouseleave($element)
Trigger.click($element)
The dispatched events are real DOM events, which will trigger both native and jQuery handlers.
jQuery's .trigger
is simpler, but will only trigger event handlers that were bound by jQuery's .on
.
Real user actions t...
Looping through iterators in Coffeescript
Some modern Javascript APIs return iterators instead of arrays.
In plain Javascript you can loop through an iterator using
for...of
:
var iterator = ...;
for (var value of iterator) {
console.log(value);
}
While there is a for...of
construct in Coffeescript, it iterates through property/value pairs and **...
Manually uploading files via AJAX
To upload a file via AJAX (e.g. from an <input type='file'>
) you need to wrap your params in a FormData
object.
You can initialize a FormData
using the contents of a form:
var form = document.querySelector('form.my-form') // Find the <form> element
var formData = new FormData(form); // Wrap form contents
Or you can construct it manually, param by param:
var fileInput = document.querySelector('form input[type=file]');
var attachment = fileInput.files[0];
var f...
Heads up: Angular may break links to the current URL (e.g. when using ngInclude)
Angular's location provider stalls links to the current URL, i.e. window.location. As soon as the $location service is activated in an Angular app, it will intercept links. The click event handler is registered in $LocationProvider.$get()
.
The motivation is reasonable, as they want to keep the Browser history clean when Angular is controlling it. However, when Angular is NOT controlling your interaction with the browser history (i.e. you're just using Angular as JS sugar on your page), Angular will create the above issue as soon as you u...
Don't open user-supplied links with target="_blank"
This will give the target site full access to your Javascript environment through window.opener
, if the target is on the same domain.
Even if the target site is on another domain, it still has some access and can for example manipulate window.location
to perform a phishing attack.
You may use a rel="noopener"
attribute to avoid this in modern browsers, except IE or Edge.
Capybara: Find the innermost DOM element that contains a given string
Let's say you want to find the element with the text hello
in the following DOM tree:
<html>
<body>
<article>
<strong>hello</strong>
<strong>world</strong>
</article>
</body>
</html>
You might think of XPath's contain()
function:
page.find(:xpath, ".//*[contains(text(), 'hello')")
Unfortunately that returns a lot more elements than you expect:
[ <html>...<html>,
<body>...</body>,
<article>...</article>,
<strong>hello</strong> ]
What you need to do instead is to *find all...
HTTP 302 redirects for PATCH or DELETE will not redirect with GET
A HTTP 302 Found
redirect to PATCH
and DELETE
requests will be followed with PATCH
or DELETE
. Redirect responses to GET
and POST
will be followed with a GET
. The Rails form_for
helper will use a workaround to send POST
requests with a _method
param to avoid this issue for PATCH
/DELETE
.
If you make requests yourself, watch out for the following behavior.
When you make an AJAX request PATCH /foo
and the /foo
action redirects to /bar
, browsers will request PATCH /bar
. You probably expected the second requ...
IIFEs in Coffeescript
In JavaScript we often use Immediately Invoked Function Expessions (or IIFEs) to prevent local variables from bleeding into an outside scope:
(function() {
var foo = "value"; // foo is scoped to this IIFE
})();
In Coffeescript an IIFE looks like this:
(->
foo = "value" # foo is scoped to this IIFE
)()
There is also a shorthand syntax with do
:
do ->
foo = "value" # foo is scoped to this IIFE
You can also use do
with arguments t...
Useful tricks for logging debugging information to the browser console
During debugging you might pepper your code with lines like these:
console.log('foo = ' + foo + ', bar = ' + bar)
I recommend to use variable interpolation instead:
console.log('foo = %o, bar = %o', foo, bar)
This has some advantages:
- It's easier to write
- Variables are colored in the console output
- You don't need to stringify arguments so the
+
operator doesn't explode - If the variable is a structured object like a D...
How to generate a Rails-compatible query string
From Rails 3.0.9, there is a method Hash#to_query that will turn a Hash into a query string:
>> {:a => "a", :b => ["c", "d", "e"]}.to_query
=> "a=a&b%5B%5D=c&b%5B%5D=d&b%5B%5D=e"
>> CGI.unescape _
=> "a=a&b[]=c&b[]=d&b[]=e"
If you're on the browser side, you can serialize nestd objects to query strings using jQuery's $.param
.
Use jQuery's selector engine on vanilla DOM nodes
There are cases when you need to select DOM elements without jQuery, such as:
- when jQuery is not available
- when your code is is extremely performance-sensitive
- when you want to operate on an entire HTML document (which is hard to represent as a jQuery collection).
To select descendants of a vanilla DOM element (i.e. not a jQuery collection), one option is to use your browser's native querySelector
and [querySelectorAll
](https://developer.mozilla.org/de/docs/We...
How to open a new tab with Selenium
Until recently, you could open a new tab via window.open
when using execute_script
in Selenium tests. It no longer works in Chrome (will show a "popup blocked" notification).
This is because browsers usually block window.open
unless the user interacted with an element for security reasons. I am not sure why it did work via Selenium before.
Here is an approach that will insert a link into the page, and have Selenium click it:
path = "/your/path/here"
id = "helper_#{SecureRandom.hex(8)}"
execute_script <<-JAVASCRIPT
...
CSS: Select elements that contain another selector
CSS4 comes with :has
. E.g. h1:has(b)
would select all <h1>
tags that contain a <b>
tag.
This is implemented in no browser but the jQuery query engine already supports it as a custom extension.
Using regular expressions in JavaScript
Regular expressions in Javascript are represented by a RegExp
object. There also is a regex literal as in many other languages: /regex/
. However, they are used slightly differently.
Regex literal
- Usage:
/foo+/
- Shorthand for creating a regular expression object
RegExp() object
- Usage:
RegExp("foo+")
ornew RegExp("foo+")
- No surrounding slashes required (they're the literal markers)
- Since the argument is a string, backslashes need to be escaped as well:
RegExp("\\d+")
Gotchas
- Regex objects [never eq...
IFrame Resizer
A JS library that allows you to embed an iframe that automatically shrinks or expands to match its content.
(Untried.)
jQuery: How to attach an event handler only once
With "attaching an event handler once" you possibly mean one of these two things:
Register a function for an event, and discard it once that event has happened
Use one
instead of on
.
$(element).one('eventName', function() { ... });
It has the same API has on
.
When code is run multiple times that registers a function for an event, do that only once
With jQuery, you can de-register callbacks. You can use that to achieve registering a function only once.
function myAction() { ... }; // defined somewhere globally o...
Lazy-loading images
Note
This card does not reflect the current state of lazy loading technologies. The native lazy attribute could be used, which is supported by all major browsers since 2022.
Since images are magnitudes larger in file size than text (HTML, CSS, Javascript) is, loading the images of a large web page takes a significant amount of the total load time. When your internet connection is good, this is usually not an issue. However, users with limited bandwidth (i.e. on mobile) need to mine their data budget...
Ag: Very fast grep replacement
Ag
(aka "the silver searcher") is a very fast replacement for grep
.
It will parse your .gitignore
for additional speedup. To ignore even more files (node_modules
, *.min.js
etc), add an .ignore
with syntax identical to .gitignore
.
See Faster Grepping in Vim for hints about vim integration.
AngularJS: How to force Content-Type on GET and DELETE requests
While you usually do not need a Content-Type
on GET request (which have a blank body), an external API may still force you to send one.
Angular's $http
service will strip that header when the request data (body) is blank. [1] This is possibly a misconception of RFC2616.
Here is how to send GET requests with a Content-Type
header in Angular.
Example
Consider this request:
$http({ me...
Show or hide a jQuery element given a condition
If you have jQuery code like this:
if (condition) {
$element.show();
} else {
$element.hide();
}
... you can shorten this to:
$element.toggle(condition);
A case for Redactor
Redactor is yet another WYSIWYG editor. It definitely has its weak points, but I want to point out that it has clear strengths, too.
Pro
- Simple and beautiful interface.
- Outstandingly organized source code. Have never seen a JS library that was this structured.
- Clear, comprehensive and searchable API documentation. Filled with code examples.
- Easily customizable: specify toolbar buttons, pass various callbacks, etc.
- Features a collection of great [plugins](ht...
Keeping web applications fast
Our applications not only need to be functional, they need to be fast.
But, to quote Donald Knuth,
premature optimization is the root of all evil (or at least most of it) in programming
The reasoning is that you should not waste your time optimizing code where it does not even matter. However, I believe there are some kinds of optimizations you should do right away, because
- they are either obvious and easy
- or they are very hard to do optimize later
This is an attempt to list some of those things:
On the server
...