fast npm install check to ensure it is up to date

Ensures that everyone has npm up to date without running “npm install”
Ideally this should be wrapped as “npm check” command, but we use a ruby/rake based workflow anyway.

  desc 'make sure npm is installed'
  task :ensure_npm do
    expected = JSON.parse(File.read('package-lock.json')).fetch('dependencies')
    satisfied = expected.all? do |name, data|
      expected_version = data.fetch('version')
      pack = "node_modules/#{name}/package.json"
      next unless File.exist?(pack)
      resolved = JSON.parse(File.read(pack))
      resolved.fetch('version') == expected_version || # regular
        resolved.fetch('_resolved') == expected_version # git
    end
    sh "npm install" unless satisfied
  end

Transparant redirect for jquery ajax requests in rails with status code 278

There is no perfect backwards compatible solution out there afaik, but this is getting me pretty close to where I want it to be.

  • instead of redirecting set a empty 278 response (made up status code) for xhr requests
  • tell jquery to redirect when receiving a 278 response
  • the success handlers are still executed / there is no way to stop them, but they can either just insert the blank reply or do a != '' check
// application.js
// when we get a fake redirect response, go there
// this will still execute success handlers, but hopefully the fail or are not ugly ...
$.ajaxSetup({
  statusCode: {
    278: function(_,_,response){
      // using turbolinks to not lose back functionality
      Turbolinks.visit(response.getResponseHeader('X-278-redirect'));
    }
  }
})
# some controller
redirect_to_with_xhr signup_path

# application_controller.rb
# ajax requests follow all redirects, so we have to improvise with a
# special code and header to not get placeholders replaced with full pages.
def redirect_to_with_xhr(path)
  if request.xhr?
    response.headers["X-278-redirect"] = path
    head 278
  else
    redirect_to path
  end
end

jQuery extension to ajax-ify selected links to stay inside a container

Make your links stay in a container, great for will_paginate / sorting headers and friends 🙂

Usage
// ajaxify all links that have “tab=my_container” in their href
$(“#my_container”).ajaxifyContainer(‘a[href*=”tab=my_container”]’)

Code

  // make selected links in a container replace the container
  // https://grosser.it/2012/06/21/jquery-pjaxcontainer-extensions
  $.fn.ajaxifyContainer = function(selector){
    selector = selector || 'a';
    var $container = $(this);
    $(selector, $container).live('click', function(){
      $container.html("Loading ...").load($(this).attr("href"));
      return false;
    });
  };

jQuery .load extension to indicate loading and errors

  // show loading animation and errors inside the container that is being replaced
  // https://grosser.it/2012/06/21/jquery-load-extension-to-indicate-loading-and-errors
  $.fn.responsiveLoad = function(url, callback){
    var loading = 'Loading';
    var $container = $(this);
    $container.html(loading).load(url, function(response, status, xhr){
      if (status == "error") {
        $container.html("Error:" + xhr.status + " " + xhr.statusText);
      } else {
        if(callback) callback(response, status, xhr);
      }
    });
  };

A chosen.js select filled via Ember.js

We have a lot of chosen in our ember app, and extracted this superclass to make interaction with them easier, it takes care of refreshing/filling/selecting stuff.

// fix chosen picks up ember script tags -> weird output when search for t or i
// this breaks the bindings within the options tags
// works around https://github.com/harvesthq/chosen/issues/581
App.UnboundSelectOption = Ember.SelectOption.extend({
  template: Ember.Handlebars.compile('{{unbound label}}')
});

App.ChosenSelect = Ember.Select.extend({
  chosenOptions: {},

  template: Ember.Handlebars.compile(
    '{{#if prompt}}{{unbound prompt}}{{/if}}' +
    '{{#each content}}{{view App.UnboundSelectOption contentBinding="this"}}{{/each}}'
  ),

  didInsertElement: function(){
    this._super();
    this.$().chosen(this.chosenOptions());
  },

  _closeChosen: function(){
    // trigger escape to close chosen
    this.$().next('.chzn-container-active').find('input').trigger({type:'keyup', which:27});
  },

  rerender: function(){
    if(this.get('state') == 'inDOM'){
     // remove now disconnected html
      this.$().next('.chzn-container').remove();
    }
    this._super();
  },

  rerenderChosen: function() {
    this.$().trigger('liszt:updated');
  }
});