Created
June 22, 2010 19:22
-
-
Save cowboy/448926 to your computer and use it in GitHub Desktop.
Widget schema idea
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Say you have widgets in the page, and each one has its own option defaults. | |
You embed these widgets in the page, but as your site grows, you may want | |
to change the defaults in a way that affects only new widgets, leaving the | |
existing widgets unmodified. How do you manage these "schema" updates? | |
Sample HTML: | |
<div class="widget" data-schema="1" data-type="that_widget" data-params="bar=5&baz=6" style="width:200px;height:300px"> | |
Default content! | |
</div> | |
Sample JS: | |
// On DOM ready, init any widgets that haven't already been initialized. | |
$(function(){ | |
$('.widget').sampleWidget(); | |
}); | |
*/ | |
(function($){ | |
var widget_name = 'sampleWidget', | |
default_type = 'this_widget', | |
// Schema revisions (1-based). | |
schemas = [ | |
{ | |
_default: { | |
_init: init_widget, | |
width: 300, | |
height: 250, | |
params { | |
foo: 1, | |
bar: 2, | |
baz: function(options){ | |
return options.params.foo || window.foo || 'foo!'; | |
} | |
} | |
}, | |
this_widget: { | |
width: 160, | |
height: 600 | |
}, | |
that_widget: { | |
params: { | |
foo: 3 | |
} | |
} | |
} | |
// Future schema revisions go here! | |
]; | |
$.fn[ widget_name ] = function( opts ){ | |
return this.each(function(){ | |
var widget = $(this), | |
data, | |
matches, | |
style, | |
// Get schema rev and type from from data- attributes. | |
rev = widget.attr('data-schema') || 1, | |
type = widget.attr('data-type') || default_type, | |
defaults = [], | |
options = { | |
params: $.deparam( widget.attr('data-params') || '' ) // Yum, BBQ! | |
}; | |
// Init element data if not already initialized. | |
widget.data( sampleWidget, data = widget.data( sampleWidget ) || {} ); | |
// Don't re-initialize an already-initializied video player! | |
if ( data.ready ) { | |
return; | |
} | |
// For this widget, we only want to merge schemas array items from | |
// 0 <= N < rev. | |
$.each( schemas, function(i,v){ | |
defaults[i] = v; | |
return i < rev - 1; | |
}); | |
// Shallow merge defaults from end to beginning, overriding older defaults | |
// with newer defaults. | |
defaults = $.extend.apply( null, [ {} ].concat( defaults ) ); | |
// Override default width / height with any inline style width / height. | |
style = widget.attr( 'style' ) || ''; | |
if ( matches = style.match( /(?:^|\s|;)width\s*:\s*(\d+)px/i ) ) { | |
options.width = widget.width() || matches[ 1 ]; | |
} | |
if ( matches = style.match( /(?:^|\s|;)height\s*:\s*(\d+)px/i ) ) { | |
options.height = widget.height() || matches[ 1 ]; | |
} | |
// Deep-recurse into options object, executing any functions (except for | |
// the _init function). | |
(function revive( obj ) { | |
var k, v; | |
for ( k in obj ) { | |
v = obj[ k ]; | |
if ( Object.prototype.toString.call( v ) === '[object Object]' ) { | |
revive( v ); | |
} else if ( $.isFunction( v ) && k !== '_init' ){ | |
obj[ k ] = v( options ); | |
} | |
} | |
})( options ); | |
// Merge explicit data-options + width + height -> type-specific defaults | |
// -> global (_default) defaults. | |
options = $.extend( true, {}, defaults._default, defaults[ type ], options, opts ); | |
// If an init function is specified, run it now. If init function doesn't | |
// return false, assume success and set flag in widget data to prevent | |
// re-initialization. | |
if ( $.isFunction( options._init ) ) { | |
data.ready = options._init.call( widget, options ) !== false; | |
} | |
}); | |
}; | |
// Sample "default" widget init method. | |
function init_widget( options ) { | |
this.html( 'hello world' ); | |
}; | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment