JS Pattern - Composite
Updated at 2013-05-04 11:40
Composite pattern allows tree-like structure for JavaScript objects. This is much more useful pattern than inheritance.
/**
* Gallery Composite
* @param {String} heading
* @param {String} id
*/
var GalleryComposite = function (heading, id) {
this.children = [];
this.$element = $('<div>').attr('id', id).addClass('composite-gallery');
this.$element.append('<h2>' + heading + '</h2>');
}
GalleryComposite.prototype = {
add: function( child ) {
// Add child to the list we maintain.
this.children.push( child );
// Render the child.
this.$element.append( child.getElement() );
},
remove: function( toRemove ) {
// Search for the child to remove.
for ( var child, i = 0; child = this.getChild(i); i++ ) {
// If this contains the child that is to be removed.
if ( child == toRemove ) {
this.children.splice(i, 1);
this.$element.detach( toRemove.getElement() );
return true;
}
// If a child contains the child that is to be removed.
if ( child.remove(toRemove) ) {
return true;
}
}
// Did not find the child.
return false;
},
getChild: function(i) {
return this.children[i];
},
hide: function() {
// Hide all children.
for (var child, i = 0; child = this.getChild(i); i++) {
child.hide();
}
// Hide this element.
this.$element.hide();
},
show: function() {
// Show all children.
for (var child, i = 0; child = this.getChild(i); i++) {
child.show();
}
// Show this element.
this.$element.show();
},
getElement: function() {
return this.$element;
}
}
/**
* Gallery Image
*/
var GalleryImage = function (src, id) {
this.children = [];
this.$element = $('<img>').attr({
'id': id,
'src': src
});
}
// This uses other style of defining a prototype.
// Due to this being a leaf, it doesn't use these methods,
// but must implement them to count as implementing the
// Composite interface.
GalleryImage.prototype.add = function() {};
GalleryImage.prototype.remove = function() {};
GalleryImage.prototype.getChild = function() {};
GalleryImage.prototype.hide = function() {
this.$element.hide();
};
GalleryImage.prototype.show = function() {
this.$element.show();
};
GalleryImage.prototype.getElement = function() {
return this.$element;
};
/**
* Following code generates:
* <div id="allgalleries" class="composite-gallery">
* <h2></h2>
* <div id="gallery1" class="composite-gallery">
* <h2>Gallery 1</h2>
* <img id="img1" src="image1.jpg">
* <img id="img2" src="image2.jpg">
* </div>
* <div id="gallery2" class="composite-gallery">
* <h2>Gallery 2</h2>
* <img id="img3" src="image3.jpg">
* <img id="img4" src="image4.jpg">
* </div>
* </div>
*/
var container = new GalleryComposite('', 'allgalleries');
var gallery1 = new GalleryComposite('Gallery 1', 'gallery1');
var gallery2 = new GalleryComposite('Gallery 2', 'gallery2');
var image1 = new GalleryImage('image1.jpg', 'img1');
var image2 = new GalleryImage('image2.jpg', 'img2');
var image3 = new GalleryImage('image3.jpg', 'img3');
var image4 = new GalleryImage('image4.jpg', 'img4');
gallery1.add(image1);
gallery1.add(image2);
gallery2.add(image3);
gallery2.add(image4);
container.add(gallery1);
container.add(gallery2);
// Make sure to add the top container to the body,
// otherwise it'll never show up.
container.getElement().appendTo('body');
container.show();