Listening for Browser Changes

Have you ever wanted to adjust your design when the user resizes their browser or changes their font-size? While some browsers have added special (non-standard) events, so that you can listener for these changes, most browser have not. Today I will show you how to use YUI custom events to subscribe to manage events that fire when the user changes the browsers font-size or resizes their browser window.

Here is the module BrowserEventMonitor.js:

Example 1: Browser Event Monitor

Core.Widget.BrowserEventMonitor = (function() {

	// Module Private Variables

	var Dom = YAHOO.util.Dom,
		CE = YAHOO.util.CustomEvent,
		F = function() {},
		that = null,
		monitors = []; // collection of monitors

	// event namespace
	var evt = {

		/**
		 * The CustomEvent to fire when font resizes.
		 * @property ceFontResize
		 * @type {Number}
		 * @private
		 * @const
		 */
		cefontresize: new CE(fontResize, that, true, CE.FLAT),

		/**
		 * The CustomEvent to fire when window resizes.
		 * @property ceWindowResize
		 * @type {Number}
		 * @private
		 * @const
		 */
		cewindowresize: new CE(windowResize, that, true, CE.FLAT)
	};

	// Public Methods and Variables
	F.prototype = {

		/**
		 * The Event name constant for listening to "change" CustomEvent events.
		 * @property FONT_RESIZE
		 * @type {String}
		 * @const
		 * @static
		 */
		FONT_RESIZE: fontResize,
	
		/**
		 * The Event name constant for listening to "windowResize" JavaScript events.
		 * @property WINDOW_RESIZE
		 * @type {String}
		 * @const
		 * @static
		 */
		WINDOW_RESIZE: windowResize,

		/**
		 * Subscribe to the custom events for this object.
		 * @method subscribe
		 * @param type {String} Required. The custom event name.
		 * @param func {Fucntion} Required. The callback function to be fired on event.
		 * @param obj {Object} Optional. The arbitrary data passed through.
		 * @public
		 */
		subscribe: function(type, func, obj) {
			var name = ce + ( + type).toLowerCase();
			if (evt[name]) {evt[name].subscribe(func, obj);}
		}
	};

	that = new F();

	// Define windowResizeEvent
	var size = Core.Client.getViewportSize();
	monitors[0] = {
		evt: evt.cewindowresize,
		test: function() {
			var size = Core.Client.getViewportSize(),
				value = size.x + - + size.y;

			if (monitors[0].value !== value) {
				monitors[0].value = value;
				return true;
			}
			else {
				return false;
			}
		},
		value: size.x + - + size.y
	};

	// Define fontResizeEvent
	var bd = Core.Client.getBody();
	monitors[1] = {
		evt: evt.cefontresize,
		test: function() {
			var fontSize = Dom.getStyle(bd, font-size);

			if (monitors[1].value !== fontSize) {
				monitors[1].value = fontSize;
				return true;
			}
			else {
				return false;
			}
		},
		value: Dom.getStyle(bd, font-size)
	};

	// Start timer
	setInterval(function() {
		// iterate on the monitors and trigger custom events as necessary
		monitors.batch(function(o) {
			if (o.test()) {o.evt.fire(that);}
		});
	}, 250);
	
	return that;
})();

The code is pretty simple. We first create 2 custom events and apply the subscription pattern to the public part of the module, so that the rest of your application can listen for these events. We then create an array of internal monitor objects with three keys: evt, test, value. The evt is a pointer to the CustomEvent for the monitor and the value is the current value being monitored. The test function should see if the value you are monitoring has changes, updating value if necessary and returning true or false. If you decide to monitor additional browser events, you simply need to append them to the monitors array. Lastly, we have an interval timer that calls the test function on each monitor in the monitors array every 250ms, firing a CustomEvent whenever the test function returns true.

To subscribe to either of these events, use the following:

Example 2: Subscribing to Browser Event

var Monitor = Core.Widget.BrowserEventMonitor;

Monitor.subscribe(Monitor.FONT_RESIZE, function() {
	// your code here
});

Monitor.subscribe(Monitor.WINDOW_RESIZE, function() {
	// your code here
});

I have also put together a simple test page, so you can see the BrowserEventMonitor working.