jQuery: Work with text nodes and comment nodes

Nearly all jQuery traversal functions ignore elements that are not HTML tags.

To work with other type of nodes (like text, comment or CDATA sections) you need to:

  • Retrieve child nodes contents() (which behaves like children() except that it returns all types of child nodes)
  • Filter manually using either plain Javascript or jQuery's filter() method

Example

Let's write a function that takes a jQuery element and returns an array of all child nodes that are text nodes:

function selectTextNodes($container) {
  retu...

How to: Client-side language detection

When you have a localized website, you may want to redirect users to their preferred language when they visit the root path.
Here is how to do it without a server-side component (like a Rails application).

  • Use JavaScript's navigator.language (real browsers and IE11+) and navigator.userLanguage (old IEs).
  • Use a <meta> refresh as fallback
  • Provide buttons for paranoid users that disabled JavaScript and meta refreshs.

JavaScript

The following JavaScript will try to auto-detect a user's preferred language.

It understands string...

How to: Specify size of Selenium browser window

Applications often show or hide elements based on viewport dimensions, or may have components that behave differently (like mobile vs desktop navigation menus).
Since you want your integration tests to behave consistently, you want to set a specific size for your tests' browser windows.

Using WebDriver options / Chrome device metrics

For Google Chrome, the preferred way is setting "device metrics". This allows you to configure dimensions larger than your display and enable/disable touch behavior.

Simply use register_driver to set up...

Fixing authentication in legacy applications

Authentication is hard: there are many edge cases, and most users (including yourself) usually only go the "happy path" once and never see the edge cases. If you have rolled your own authentication, or been using older authentication solutions, or resorted to HTTP Basic Authentication, this card will tell you what to do to make your application safe.

Any application that stores sensitive data in the browser

That is: cookies, e.g. by offering a login.

  • Ask the admins to [turn on SSL](https://makandracards.com/makandra/1416-integrate-s...

Upgrading Cucumber and Capybara to the latest versions available for Rails 2

Specify these gem versions in your Gemfile:

gem 'cucumber', '~> 1.3.0'
gem 'cucumber-rails', '= 0.3.2' # max version for Rails 2
gem 'capybara', '< 2' # capybara 2+ requires Rails 3
gem 'mime-types', '< 2' # dependeny of capybara
gem 'nokogiri', '< 1.6' # dependency of capybara
gem 'rubyzip', '< 1' # dependency of selenium-webdriver, rubyzip 1+ requires Ruby 1.9
gem 'cucumber_factory'
gem 'database_cleaner', '< 1'
gem 'cucumber_spinner', '~> 0.2.5'
gem 'launchy', '~> 2.1.2'

With these versions set, `...

Testing regular expressions visually

Developing complex regular expressions quickly blows my mind. Here are some online regex editors that help you by highlighting matching text and capture groups:

Bookmarklet: cards Markup Link Bookmarklet

The cards editor has a feature "Cite other card" to create links to other cards in the same deck as mardown links.
If you want to reference a card from a different deck, this bookmarklet might be useful:

javascript:(function () {
  const doAlert = () => { alert("Maybe not a makandra card?") };
  let cardsPathPattern = /(\/[\w-]+\/\d+)-.+/;
  if (window.location.pathname.match(cardsPathPattern)) {
    let currentPath = window.location.pathname.match(cardsPathPattern)[1];
    let title = document.querySelector('h1.note--title')?.textCon...

Capybara: evaluate_script might freeze your browser

Capybara gives you two different methods for executing Javascript:

page.evaluate_script("$('input').focus()")
page.execute_script("$('input').focus()")

While you can use both, the first line (with evaluate_script) might freeze your browser window for 10 seconds.

The reason is that evaluate_script will always return a result. The return value will be converted back to Ruby objects, which in case of complex objects (e.g. a jQuery collection) is very expensive.

Because of this we recommend to only use evaluate_script whe...

Middleman configuration for Rails Developers

Middleman is a static page generator that brings many of the goodies that Rails developers are used to.

Out of the box, Middleman brings Haml, Sass, helpers etc. However, it can be configured to do even better. This card is a list of improvement hints for a Rails developer.

Gemfile

Remove tzinfo-data and wdm unless you're on Windows. Add these gems:

gem 'middleman-livereload'
gem 'middleman-sprockets' # Asset pipeline!

gem 'bootstrap-sass' # If you want to use Bootstrap

gem 'byebug'

gem 'capistrano'
gem 'capistrano-mid...

Capturing signatures on a touch device

If you need to capture signatures on an IPad or similar device, you can use Thomas J Bradley's excellent Signature Pad plugin for jQuery.

To implement, just follow the steps on the Github page.

The form

If you have a model Signature with name: string, signature: text, you can use it with regular rails form like this:

- form_for @signature, :html => { :class => 'signature_form' } do |form|
  %dl
    %dt
      = form...

Copy to clipboard without flash (clipboard.js)

We used zeroclipboard.js in some of our projects but now we switched to clipboard.js because it does not rely on flash. Flash support of the major browsers has ended.

Some more advantages of clipboard.js:

  • it consists only of a single javascript file, so it does not trigger additional requests with rails
  • it automagically provides user feedback by selecting the text it has copied
  • it provides callbacks for success and error which make it easier to add custom behaviour after copying to the clipboar...

Rails Assets

Automatically builds gems from Bower packages (currently 1700 gems available). Packaged Javascript files are then automatically available in your asset pipeline manifests.

Why we're not using it

At makandra we made a choice to use bower-rails instead. While we believe Rubygems/Bundler to be superior to Javascript package managers, we wanted to use something with enough community momentum behind it that it won't go away in 10 years...

Upgrade guide for moving a Rails app from Webpack 3 to Webpack 4

Webpacker is Rails' way of integrating Webpack, and version 4 has been released just a few days ago, allowing us to use Webpack 4.

I successfully upgraded an existing real-world Webpack 3 application. Below are notes on everything that I encountered.
Note that we prefer not using the Rails asset pipeline at all and serving all assets through Webpack for the sake of consistency.

Preparations

  • Remove version locks in Gemfile for webpacker
  • Remove version locks in package.json for webpack and webpack-dev-server
  • Install by ca...

HTML file inputs support picking directories

HTML's <input type="file"> accepts a single file. You can allow multiple files via <input type="file" multiple>.
But sometimes, selecting multiple files is not enough and can be cumbersome for the user. Enter webkitdirectory:

<input type="file" webkitdirectory multiple>

Using webkitdirectory switches the browser's file picker to select a directory. All files inside that directory, and inside any nested subdirectories, will be selected for the file input.

This can be useful when users want to upload all files from a nested dire...

Test that an exception or error page is raised in Capybara

You can use these step definitions:

Then /^I should not see an error$/ do
  (200 .. 399).should include(page.status_code)
end

Then /^I should see an error$/ do
  (400 .. 599).should include(page.status_code)
end

Note that you need to tag the scenario with @allow-rescue to test that an error is shown like this

@allow-rescue
Scenario: Accessing the admin area requires a login
  When I go to the admin area
  Then I should see an error

These step definitions will not work for @javascript scena...

parallel_tests: Disable parallel run for tagged scenarios

Note: This technique is confusing and slows down your test suite.


Copy the attached code to features/support. This gets you a new Cucumber tag @no_parallel which ensures that the tagged scenario does not run in parallel with other scenarios that are tagged with @no_parallel. Other scenarios not tagged will @no_parallel can still run in parallel with the tagged test. Please read the previous sentence again.

This can help when multiple test processes that access a single resource that is hard to shar...

Material Design Lite

CSS (+ some Javascript) framework, implementing Google's material design for static web pages.

Can be used for plain websites without requiring a full blown Javascript framework, unlike the (also excellent) Polymer paper elements, or Angular material.

Prelimiary impression:

I would recommend against using it at this stage, for a couple of reasons:

  • It is much less complete than you might expect from a CSS framewor...

What you need to know about Angular SEO

Search engines, such as Google and Bing are engineered to crawl static web pages, not javascript-heavy, client-side apps. This is typical of a search engine which does not render javascript when the search bot is crawling over web pages.

This is because our javascript-heavy apps need a javascript engine to run, like PhantomJS or v8, for instance. Web crawlers typically load a web page without using a javascript interpreter.

Are we out of luck for providing good SEO for our Angular apps? This article will show you exactly what you nee...

Using Firebug Lite to inspect HTML in Internet Explorer and other browsers

You know Firebug as a Firefox extension but there is also a "Lite" version which runs purely off JavaScript.

Though all major browsers offer inspection tools you may like the Firebug style. Also, for me this is a lot better than the IE8 developer tools -- and it works in older versions of IE, too.

Get the bookmarklet over at http://getfirebug.com/firebuglite#Stable. It usually loads the JavaScript code from a remote server but you can also download it to have it run locally. If adding the bookmarklet does not work in IE, add a new book...

Unpoly: Testing values for presence or blankness

In Ruby on Rails, all objects have a useful blank? method. It returns true for nil but also for empty strings or empty arrays. There is also a universal method present? which returns true for all values that are not blank?.

In JavaScript you need to roll your own implementation of blank? and present?.

If your application uses [Unpoly](...

How to detect touch-capable browsers

The easiest way to detect touch-capable browsers is to check for the presence of touch events. It is no 100% solution, but has by far the best cost-benefit ratio. (Know that this does not detect touch devices, but browsers.)

Javascript

var isTouchDevice = 'ontouchstart' in window

Coffeescript

isTouchDevice = 'ontouchstart' of window

On the difference between the Javascript and the Coffeescript version, see [Beware: Coffeescript "in" is not the Javascript "in"](https://makandracards.com/makandra/31073-beware-c...

How to make Webpacker compile once for parallel tests, and only if necessary

Webpack is the future. We're using it in our latest Rails applications.

For tests, we want to compile assets like for production.
For parallel tests, we want to avoid 8 workers compiling the same files at the same time.
When assets did not change, we do not want to spend time compiling them.

Here is our solution for all that.

Its concept should work for all test suites.

Copy the following to config/initializers/webpacker_compile_once.rb. It will patch Webpacker, but only for the test environment:

# Avoid hardcoded asset host...

Asset Pipeline Basics

The Rails asset pipeline improves delivery of application assets (javascripts, stylesheets, images, fonts). Here are some basic facts about its inner workings.

No magic

Manifests are the handle on your assets:

app/assets/stylesheets/application.css # use via: stylesheet_link_tag 'application'

The asset pipeline only considers files you explicitly require within your manifest files. The most common directives used in manifests are require some/file and require_tree some/directory. Paths may be **relative to the current director...

Nested Spreewald patiently blocks are now patient

In Spreewald 1.10.4+, nested patiently blocks are now patient.

Here is an example:

patiently do
  outer_code
  patiently do
    inner_code
  end
end

On spreewald 1.11.2+ the inner block will wait for the full configured wait time (by default 5 seconds). The outer patiently block would now be out of time, but it will always be retried at least a second time. This behavior allows with_scope to be patient, and it must be patient, as explained below.

In versions 1.10.4 - 1.11.1, inner blocks would keep giving the ou...