Colored Console Output

const out = {

  end: '\x1b[0m',

  // Modifiers.
  blink: '\x1b[5m',
  bright: '\x1b[1m',
  dim: '\x1b[2m',
  hidden: '\x1b[8m',
  reverse: '\x1b[7m',
  underscore: '\x1b[4m',

  // Foreground Colors.
  black: '\x1b[30m',
  blue: '\x1b[34m',
  cyan: '\x1b[36m',
  green: '\x1b[32m',
  magenta: '\x1b[35m',
  red: '\x1b[31m',
  yellow: '\x1b[33m',
  white: '\x1b[37m',

  // Background Colors.
  bgBlack: '\x1b[40m',
  bgBlue: '\x1b[44m',
  bgCyan: '\x1b[46m',
  bgGreen: '\x1b[42m',
  bgMagenta: '\x1b[45m',
  bgRed: '\x1b[41m',
  bgYellow: '\x1b[43m',
  bgWhite: '\x1b[47m',
};

Usage:

console.log(out.red, 'Something went wrong:', err, out.end);

Validate the Crickets’ Nest

I have a problem getting values from deeply nested objects: if one of the properties along the namespace is incorrect|modified|removed, Javascript throws. To avoid this, you can end up with obnoxious validation:

// Trying to get this.data.homeScene.user.name
const isValid = (
  typeof this.data === 'object' &&
  typeof this.data.homeScene === 'object' &&
  typeof this.data.homeScene.user === 'object' &&
  typeof this.data.homeScene.user.name === 'string'
);
if (isValid) {
  const { name } = this.data.homeScene.user;
  ...
}

What if I made a reusable helper to validate the namespace and return the value?

export default function getNamespace(startObj, path) {
  const isValidArgs = (
    typeof startObj === 'object' &&
    typeof path === 'string'
  );
  if (!isValidArgs) return undefined;

  const finalValue = path
    .split('.')
    .reduce((obj, p) => ((typeof obj === 'object') 
      ? obj[p]
      : undefined
    ), startObj);{

  return finalValue;
}

Now the obnoxious validation looks like this:

// Trying to get this.data.homeScene.user.name
const name = getNamespace(this, 'data.homeScene.user.name');
if (name) { ... }

Dude! Sweet!

Alias for Git sanity

Git command line is pretty confusing. Here are some aliases that I found helpful that normalize it with other command line commands and add a little bit better context.

Open global .gitconfig file:

$ open ~/.gitconfig

If there isn’t an [alias] section already, add one:

[alias]
  cd = checkout
  ls = branch
  delete-merged = !git branch --merged | egrep -v \"(^\\*|master|development)\" | xargs git branch -d
  new-up = !git push -u origin `git symbolic-ref --short HEAD`
  stage = add
  unstage = reset HEAD

Update 2018-07:

To set VS Code as the default editor for commit and merge messages:

[core]
  editor = code --wait

Multi-line Text Ellipsis

CSS can only add ellipsis to a single line of text. Here’s how to do it in Javascript using lodash:

// Update wrapping text to limit the number of lines.
var maxLines = 2;
var textEls = document.getElementsByClassName('text-els-class');
var textMaxH = Math.ceil(textEls[0].getBoundingClientRect().height) * maxLines;

_.forEach(textEls, function(el) {

    el.style.whiteSpace = 'normal';

    var elH = el.getBoundingClientRect().height;
    var isOverflow = elH > textMaxH;
    var text = el.innerHTML;

    // Remove the last word until the height is within bounds.
    while (elH > textMaxH) {

        text = (text
            .split(' ')
            .slice(0,-1)
            .join(' ')
        );
        el.innerHTML = text;
        elH = el.getBoundingClientRect().height;
    }

    if (isOverflow) {
        title.innerHTML += ' ...';
        title.style.maxHeight = titleMaxH + 'px';
    }
});

Destroying a Javascript API

Problem:

  • A third party JS API doesn’t have a destroy method.
  • The JS API can only be instantiated once per page view.
  • Writing a single page app by its nature requires a dynamic DOM
  • Dynamic DOM will require the JS API to be spun up and destroyed on multiple elements during the life cycle of the page view

What to do?

Answer: Destroy it yourself. By highjacking the events as they are created, you can gather a collection of all events that the JS API has created during instantiation. When it’s time to destroy the JS API, reference your collection of events to remove them from the window:


var _apiE 		= []; // Array of JS API Events.
var _scriptTag 	= null; 

var _methods: {

	initJsApi: function() {
		// Hook the native event listener to capture JS API events.
		// Preserve the original native method.
		var ogAddEventListener = window.addEventListener;

		// Override the native method.
		window.addEventListener = function() {

			// Capture JS API events.
			_apiE.push({
				type: 			arguments[0],
				listener: 		arguments[1],
				useCapture: 	arguments[2]
			});

			// Call the original native method after capturing the event 
			// so JS API and the browser do their business as usual.
			ogAddEventListener.apply(this, arguments);
		};

		// Add the <script> tag to the DOM dynamically to load the JS API.
		// jQuery will inject ?_0000 cache buster to script tag src attribute value.
		// Some sites will not allow the JS API to be requested with the querystring present.
		// Use native element to work around this.
		_scriptTag = document.createElement('script');
		_scriptTag.setAttribute('src', 		'https://js-api-cdn.com/js/third-party-api.min.js');
		_scriptTag.setAttribute('type', 	'text/javascript');
		_scriptTag.setAttribute('id', 		'js-api-script');
		$('html').append(_scriptTag);

		// Wait for the JS API to instantiate after the <script> has been attached to the DOM.
		var intvl = setInterval(function() {

			if (window.jsApi) { // The actual name of the API object would go here.

				clearInterval(intvl);

				// Instantiate the JS API.
				window.jsApi.init({ options });

				// Reset the native event listener to the original method so we stop capturing events.
				window.addEventListener = ogAddEventListener;
			}
		}, 5);
	},

	destroyJsApi: function() {

		// Remove the <script> tag and instance of the JS API.
		$('#js-api-script').remove();
		delete window.jsApi;

		// Remove the events that the JS API added.
		$.each(_apiE, function(i, e) {

			window.removeEventListener(e.type, e.listener, e.useCapture);
		});
	}
};

Danger: other events that are registered while waiting for the JS API to instantiate will also get removed.

WordPress Child Pages

To get the child pages of a WordPress page, update options using query_posts or WP_Query:

$options = ( object ) array(
	'order' 		=> 'DESC',
	'orderby' 		=> 'menu_order',
	'post_parent' 	=> $pg[ 0 ]->ID,
	'post_status' 	=> 'publish',
	'post_type' 	=> 'page',
	'posts_per_page' => 100
);
WP_Query( $options );