Snippets

These snippets are my attempt to save and organize various bits of code, best practices, and resources relating to web development and design. They also function as a to do list of sorts, for things I want to implement in my own code, but haven't yet. The concept is inspired by Jeremy Keith's links and CSS-Tricks, among other things. Enjoy.

Drupal 8, behaviors, and jQuery Once

When porting some front-end code from Drupal 7 to Drupal 8, I ran into an unexpected change in the use of jQuery.once(). In Drupal 7, you’d do this in a behavior:

Code language: JavaScript

Drupal.behaviors.exampleBehavior = {
  attach: function(context, settings) {
    $('.example', context).once('example-behavior', function() {
      // Do stuff.
    });
  },
  detach: function(context, settings, trigger) {
    $('.example', context).removeOnce('example-behavior', function() {
      // Undo stuff.
    });
  }
};

In Drupal 8, however, you can’t pass in a function to jQuery.once(), as the API for that jQuery plugin has changed. It now acts like jQuery.filter(), in that it filters out any elements that have already been processed so they aren’t processed more than once, and returns a jQuery collection. So, in Drupal 8, the example would be:

Code language: JavaScript

Drupal.behaviors.exampleBehavior = {
  attach: function(context, settings) {
    $('.example', context).once('example-behavior').each(function() {
      // Do stuff.
    });
  },
  detach: function(context, settings, trigger) {
    $('.example', context).removeOnce('example-behavior').each(function() {
      // Undo stuff.
    });
  }
};

BEM class selectors and the Sass ampersand

The Sass ampersand is incredibly useful in building selectors based on the parent selector, but it has a limitation. Take the following nested BEM-style selectors:

Code language: Sass

.component {
  // A BEM modifier.
  &--reversed {
    background: white;
    border-color: lightgray;
 
    // Target a descendent only when the parent has the modifier? Not exactly...
    &__child-element {
      background: rebeccapurple;
    }
  }
}

The linked post explains the problem:

Wait, why is this not working? The problem is that the & has a scope of .component--reversed, so &__child-element compiles to .component--reversed__child-element, which doesn’t [exist] in the markup.

The fix is to save the & to a variable in the parent and use that in the child selector:

Code language: Sass

.component {
  // Save the current value of & as $self.
  $self: &;
 
  &--reversed {
    background: white;
    border-color: lightgray;
 
    // Print $self in place of & to get the correct scope of the parent above.
    #{$self}__child-element {
      background: rebeccapurple;
    }
  }
}

The compiled CSS for that element is now .component--reversed .component__child-element[.]

Allow Ctrl- and Shift-clicking links in event handlers

I just recently updated a bunch of my click handlers to not act when the Ctrl or Shift keys are pressed during the click, so that links can be opened in new tabs or windows by the user if so wanted:

Code language: JavaScript

// Don't do anything and defer to the default action if a modifier key
// was pressed during the click (to open the link in a new tab, window,
// etc.) - note that this is a truthy check rather than a strict check
// for the existence of and boolean true value of the various event
// properties:
// * https://ambientimpact.com/web/snippets/conditional-statements-and-truthy-values-robust-client-side-javascript
// * https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/ctrlKey
// * https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/shiftKey
if (event.ctrlKey || event.shiftKey) {
  return;
}