Thursday, January 01, 2015

fahd.blog in 2014

Happy 2015, everyone!
I'd like to wish everyone a great start to an even greater new year!

In keeping with tradition, here's one last look back at fahd.blog in 2014.

During 2014, I posted a measly 19 new entries on fahd.blog. That's not a lot (I blame work and stackoverflow!) but I promise to write more this year. Thanks for reading and especially for giving feedback.

Top 5 posts of 2014:

I'm going to be writing a lot more this year, so stay tuned for more great techie tips, tricks and hacks! :)

Related posts:

Saturday, December 27, 2014

A Bookmarklet to Tick All Checkboxes on a Webpage

Recently, I found myself on a website where I had to tick 100+ checkboxes and there was no "Select all" button on the page. Obviously, I couldn't do this manually, so I wrote the following bookmarklet.

javascript:(function(){for(i of document.getElementsByTagName('input')){if(i.type=='checkbox') i.checked=!i.checked;}})()

Save this as a bookmark in your browser and click on it to toggle all checkboxes on the page you are on.

Sunday, November 30, 2014

Logging the Duration of Ext Ajax Requests

The following snippet shows how to log the duration of ajax requests in your Ext JS application:

Ext.Ajax.on('beforerequest', function(conn, response, options){
    console.log("Requesting:" + response.url);
    console.time(response.url);
});
Ext.Ajax.on('requestcomplete', function(conn, response, options){
    console.timeEnd(options.url);
});

Note that this code uses console.time(), which is a non-standard feature and may not work in all browsers.

Saturday, November 22, 2014

Ext JS - Caching AJAX Responses to HTML5 Web Storage for Better Performance

This post shows how you can improve performance of your Ext JS applications by using a "Caching AJAX Proxy". This proxy saves URL responses to HTML5 Web Storage (e.g. session storage or local storage), which means that when the same URL is requested multiple times, a cached response is returned, instead of sending a request to the server each time. This makes the application more responsive and also reduces load on the server handling the requests.

/**
 * A Caching Ajax Proxy which uses AJAX requests to get data from a server and
 * then stores the data to HTML5 Web Storage. If the storage fills up, it removes
 * entries from the cache until space is available.
 * (Compatible with Ext JS 4.2)
 */
Ext.define('App.data.proxy.CachingAjax', {
  extend: 'Ext.data.proxy.Ajax',
  alias: 'proxy.cachingajax',

  // use session storage, but can be configured to localStorage too
  storage: window.sessionStorage,

  // @Override
  doRequest: function(operation, callback, scope) {
    var cachedResponse = this.getItemFromCache(this.url);
    if (!cachedResponse) {
        this.callParent(arguments);
    }
    else {
        console.log('Got cached data for: ' + this.url);
        this.processResponse(true, operation, null, cachedResponse,
                             callback, scope, true);
    }
  },

  // @Override
  processResponse: function(success, operation, request, response,
                            callback, scope, isCached) {
    if (success === true && !isCached) {
        this.putItemInCache(this.url, response.responseText);
    }
    this.callParent(arguments);
  },

  /**
   * @private
   * Returns the data from the cache for the specified key
   * @param {String} the url
   * @return {String} the cached url response, or null if not in cache
   */
  getItemFromCache: function(key) {
    return this.storage ? this.storage.getItem(key) : null;
  },

  /**
   * @private
   * Puts an entry in the cache.
   * Removes a third of the entries if the cache is full.
   * @param {String} the url
   * @param {String} the data
   */
  putItemInCache: function(key, value) {
    if (!this.storage) return;
    try {
      this.storage.setItem(key, value);
    } catch (e) {
      // this might happen if the storage is full.
      // Remove a third of the items and retry.
      // If it fails again, disable the cache quietly.
      console.log('Error putting data in cache. CacheSize: ' + this.storage.length +
                  ', ErrorCode: ' + e.code + ', Message: ' + e.name);

      while (this.storage.length != 0) {
        var toRemove = this.storage.length / 3;
        for (var i = 0; i < toRemove ; i++) {
          var item = this.storage.key(0);
          if (item) this.storage.removeItem(item);
          else break;
        }
        console.log('Removed one-third of the cache. Cache size is now: ' + this.storage.length);
        try {
          this.storage.setItem(key, value);
          break;
        } catch (e) {
          console.log('Error putting data in cache again. CacheSize: ' + this.storage.length +
                      ', ErrorCode: ' + e.code + ', Message: ' + e.name);
        }
      }
      if (this.storage.length == 0) {
        console.log("Cache disabled");
        this.storage = null;
      }
    }
  }
});
Usage:
var store = Ext.create('Ext.data.Store', {
  model: 'User',
  proxy: {
    type: 'cachingajax',
    url : 'http://mywebsite/path'
  }
});

Obviously, you should only use this caching proxy when the server-side data is static, because if it is changing frequently your application will end up displaying stale, cached data.

This proxy can also be extended in the future to remove cached entries after specific time intervals or clear out the entire cache when the application starts up.

Saturday, October 25, 2014

stackoverflow - 90k rep

Five months after crossing the 80k milestone, I have now reached a reputation of 90k on stackoverflow!

The following table shows some stats about my journey so far:

0-10k 10-20k 20-30k 30-40k 40-50k 50-60k 60-70k 70-80k 80-90k Total
Date achieved 01/2011 05/2011 01/2012 09/2012 02/2013 07/2013 12/2013 05/2014 10/2014
Questions answered 546 376 253 139 192 145 66 58 32 1807
Questions asked 46 1 6 0 1 0 0 0 2 56
Tags covered 609 202 83 10 42 14 11 14 4 989
Badges
(gold, silver, bronze)
35
(2, 10, 23)
14
(0, 4, 10)
33
(2, 8, 23)
59
(3, 20, 36)
49
(0, 19, 30)
65
(2, 26, 37)
60
(5, 22, 33)
50
(2, 24, 24)
50
(7, 21, 25)
418
(23, 154, 241)

I'm a bit disappointed that I only managed to answer 32 questions over the last 5 months. It's because work has been keeping me so busy! For me, stackoverflow has not simply been a quest for reputation, but more about learning new technologies and picking up advice from other people on the site. I like to take on challenging questions, rather than the easy ones, because it pushes me to do research into areas I have never looked at before, and I learn so much during the process.

Next stop, 100k!