Return to Snippet

Revision: 17542
at September 9, 2009 11:55 by pdswan


Updated Code
var Panels = Class.create({
	initialize: function(){
		this.element = $(arguments[0]);
		this.element.identify();
		if( !this.element ){
			throw 'Panels: invalid contianer element'
		}
		this.element.setStyle({
			overflow: 'hidden'
		});
		this.element.makePositioned();
		this.options = Object.extend({
			force_horizontal: false,
			panel_selector: '.panel',
			only_children: false,
			start_index: 0,
			active_class: 'active',
			onInitialized: Prototype.emptyFunction,
			animation_scope: 'Panels'+this.element.identify(),
			animation: function(offsets){
				return new Effect.Scroll( this.element, {
					x: offsets.left,
					y: offsets.top,
					mode: 'absolute',
					duration: 1.0,
					queue: {scope: this.options.animation_scope}
				});
			}
		}, arguments[1] || {});
		this.width_calculated = false;
		this.panels = 
			this.options.only_children ? 
			this.element.childElements().findAll( function(e){ 
				return e.match(this.options.panel_selector);
			}.bind(this) ) : 
			this.element.select(this.options.panel_selector);
			
		this.controls = {
			gotos: $H(),
			previous: $A(),
			next: $A()
		}
		
		this.initialize_controls();
		if (this._calculate_width()) {
			this._finish();
		}
	},
	_finish: function(){
		this._calculate_offsets();
		this.goto_panel(this.options.start_index);
		this.options.onInitialized.call(this);
	},
	_calculate_offsets: function(){
		this.offsets = $H();
		this.panels.each(function(p){
			this.offsets.set(p.identify(), p.positionedOffset());
		}, this);
	},
	_calculate_width: function(force){
		if( this.options.force_horizontal && (!this.width_calculated || force) ){
			if( !this.container ){
				// find the largest panel height
				this.force_horizontal_height = this.panels.map(function(p){
					var position = p.getStyle('position');
					p.setStyle({'position': 'absolute'});
					var height = p.getHeight();
					p.setStyle({'position': position});
					return height;
				}).max();
				this.container = new Element('div').setStyle({overflow: 'hidden', width: '100000px'});
				this.panels.each(function(e){
					this.container.insert(e.remove().setStyle({'float': 'left'}));
				}, this);
				this.element.insert(this.container);
				this.default_width = this.element.getWidth();
			}
			var temp = new Element('div').setStyle({'float': 'left', 'width': '1px', 'height': '1px'});
			this.panels.last().insert({after: temp});
			return this._set_width(temp);
		}
		return true;
	},
	_set_width: function( elm, finish){
		var width = elm.positionedOffset()[0];
		/*
		 * if the scroll height of the container is greater than the maximum panel height, then all of the panels have not yet
		 * been inserted into the container. or height container height has not been properly computed yet.
		 */
		if( (this.default_width && width <= this.default_width) || (this.force_horizontal_height && this.container.scrollHeight > this.force_horizontal_height)){
			this._set_width.bind(this, elm, 1).defer();
			return false;
		}else{
			this.container.setStyle({width: width + 'px'});
			this.width_calculated = true;
			elm.remove();
			if( finish ){
				this._finish();
			}else{
				return true;
			}
		}
	},
	initialize_controls: function(){
		var find = arguments[0] ? $(arguments[0]).select : $$;
		this.panels.each(function(p){
			var gotos = find('a[href=#' + p.identify() + ']').invoke('observe', 'click', this.goto_panel.bindAsEventListener(this, p));
			this.controls.gotos.set(p.identify(), (this.controls.gotos.get(p.identify) || $A()).concat(gotos));
		}, this);
		var next = $$('a[href=#next].' + this.element.identify() + '_control[href=#next]').invoke('observe', 'click', this.next.bindAsEventListener(this));
		this.controls.next = this.controls.next.concat(next);
		var previous = $$('a.' + this.element.identify() + '_control[href=#previous]').invoke('observe', 'click', this.previous.bindAsEventListener(this));
		this.controls.previous = this.controls.previous.concat(previous);
	},
	goto_panel: function(){
		var elm = null;
		if( arguments.length > 1 ){
			arguments[0].stop();
			elm = arguments[1];
		}else{
			elm = arguments[0];
		}
		var id = null;
		if (!Object.isString(elm)) {
			if( Object.isNumber(elm)){
				elm = this.panels[parseInt(elm)];
			}
			id = elm.identify();
		}else{
			id = elm;
			elm = $(id);
		}
		if( elm === this.current_panel ){
			return;
		}
		var offsets = this.offsets.get(id);
		if( offsets ){
			if (this.current_panel) {
				this.current_panel.removeClassName(this.options.active_class);
				this.controls.gotos.get(this.current_panel.identify()).invoke('removeClassName', this.options.active_class);
			}
			this.current_panel = elm;
			this.current_panel.addClassName(this.options.active_class);
			this.controls.gotos.get(this.current_panel.identify()).invoke('addClassName', this.options.active_class);
			try {
				this.options.animation.call(this, offsets);
			}catch(ex){
				this.element.scrollTop = offsets.top;
				this.element.scrollLeft = offsets.left;
			}
		}
	},
	next: function(){
		if( arguments.length ){
			arguments[0].stop();
		}
		var index = this.panels.indexOf(this.current_panel) + 1;
		index = index > this.panels.length - 1 ? 0 : index;
		this.fire('panels:next', {panels: this.panels, index: index});
		this.goto_panel(index);
	},
	previous: function(){
		if( arguments.length ){
			arguments[0].stop();
		}
		var index = this.panels.indexOf(this.current_panel) - 1;
		index = index < 0 ? this.panels.length - 1 : index;
		this.fire('panels:previous', {panels: this.panels, index: index});
		this.goto_panel(index);
	},
	observe: function(){
		this.element.observe.apply(this.element, arguments);
	},
	fire: function(){
		this.element.fire.apply(this.element, arguments);
	},
	destroy: function(){
		this.controls.previous.concat(this.controls.next).concat(this.controls.gotos.values().flatten()).invoke('stopObserving');
	}
});

Revision: 17541
at September 9, 2009 10:51 by pdswan


Initial Code
var Panels = Class.create({
	initialize: function(){
		this.element = $(arguments[0]);
		this.element.identify();
		if( !this.element ){
			throw 'Panels: invalid contianer element'
		}
		this.element.setStyle({
			overflow: 'hidden'
		});
		this.element.makePositioned();
		this.options = Object.extend({
			force_horizontal: false,
			panel_selector: '.panel',
			only_children: false,
			start_index: 0,
			active_class: 'active',
			onInitialized: Prototype.emptyFunction,
			animation_scope: 'Panels'+this.element.identify(),
			animation: function(offsets){
				return new Effect.Scroll( this.element, {
					x: offsets.left,
					y: offsets.top,
					mode: 'absolute',
					duration: 1.0,
					queue: {scope: this.options.animation_scope}
				});
			}
		}, arguments[1] || {});
		this.width_calculated = false;
		this.panels = 
			this.options.only_children ? 
			this.element.childElements().findAll( function(e){ 
				return e.match(this.options.panel_selector);
			}.bind(this) ) : 
			this.element.select(this.options.panel_selector);
			
		this.controls = {
			gotos: $H(),
			previous: $A(),
			next: $A()
		}
		
		this.initialize_controls();
		if (this._calculate_width()) {
			this._finish();
		}
	},
	_finish: function(){
		this._calculate_offsets();
		this.goto_panel(this.options.start_index);
		this.options.onInitialized.call(this);
	},
	_calculate_offsets: function(){
		this.offsets = $H();
		this.panels.each(function(p){
			this.offsets.set(p.identify(), p.positionedOffset());
		}, this);
	},
	_calculate_width: function(force){
		if( this.options.force_horizontal && (!this.width_calculated || force) ){
			if( !this.container ){
				// find the largest panel height
				this.force_horizontal_height = this.panels.map(function(p){
					var position = p.getStyle('position');
					p.setStyle({'position': 'absolute'});
					var height = p.getHeight();
					p.setStyle({'position': position});
					return height;
				}).max();
				this.container = new Element('div').setStyle({overflow: 'hidden', width: '100000px'});
				this.panels.each(function(e){
					this.container.insert(e.remove().setStyle({'float': 'left'}));
				}, this);
				this.element.insert(this.container);
				this.default_width = this.element.getWidth();
				this.force_horizontal_height
			}
			var temp = new Element('div').setStyle({'float': 'left', 'width': '1px', 'height': '1px'});
			this.panels.last().insert({after: temp});
			return this._set_width(temp);
		}
		return true;
	},
	_set_width: function( elm, finish){
		var width = elm.positionedOffset()[0];
		/*
		 * if the scroll height of the container is greater than the maximum panel height, then all of the panels have not yet
		 * been inserted into the container. or height container height has not been properly computed yet.
		 */
		if( (this.default_width && width <= this.default_width) || (this.force_horizontal_height && this.container.scrollHeight > this.force_horizontal_height)){
			this._set_width.bind(this, elm, 1).defer();
			return false;
		}else{
			this.container.setStyle({width: width + 'px'});
			this.width_calculated = true;
			elm.remove();
			if( finish ){
				this._finish();
			}else{
				return true;
			}
		}
	},
	initialize_controls: function(){
		var find = arguments[0] ? $(arguments[0]).select : $$;
		this.panels.each(function(p){
			var gotos = find('a[href=#' + p.identify() + ']').invoke('observe', 'click', this.goto_panel.bindAsEventListener(this, p));
			this.controls.gotos.set(p.identify(), (this.controls.gotos.get(p.identify) || $A()).concat(gotos));
		}, this);
		var next = $$('a[href=#next].' + this.element.identify() + '_control[href=#next]').invoke('observe', 'click', this.next.bindAsEventListener(this));
		this.controls.next = this.controls.next.concat(next);
		var previous = $$('a.' + this.element.identify() + '_control[href=#previous]').invoke('observe', 'click', this.previous.bindAsEventListener(this));
		this.controls.previous = this.controls.previous.concat(previous);
	},
	goto_panel: function(){
		var elm = null;
		if( arguments.length > 1 ){
			arguments[0].stop();
			elm = arguments[1];
		}else{
			elm = arguments[0];
		}
		var id = null;
		if (!Object.isString(elm)) {
			if( Object.isNumber(elm)){
				elm = this.panels[parseInt(elm)];
			}
			id = elm.identify();
		}else{
			id = elm;
			elm = $(id);
		}
		if( elm === this.current_panel ){
			return;
		}
		var offsets = this.offsets.get(id);
		if( offsets ){
			if (this.current_panel) {
				this.current_panel.removeClassName(this.options.active_class);
				this.controls.gotos.get(this.current_panel.identify()).invoke('removeClassName', this.options.active_class);
			}
			this.current_panel = elm;
			this.current_panel.addClassName(this.options.active_class);
			this.controls.gotos.get(this.current_panel.identify()).invoke('addClassName', this.options.active_class);
			try {
				this.options.animation.call(this, offsets);
			}catch(ex){
				this.element.scrollTop = offsets.top;
				this.element.scrollLeft = offsets.left;
			}
		}
	},
	next: function(){
		if( arguments.length ){
			arguments[0].stop();
		}
		var index = this.panels.indexOf(this.current_panel) + 1;
		index = index > this.panels.length - 1 ? 0 : index;
		this.fire('panels:next', {panels: this.panels, index: index});
		this.goto_panel(index);
	},
	previous: function(){
		if( arguments.length ){
			arguments[0].stop();
		}
		var index = this.panels.indexOf(this.current_panel) - 1;
		index = index < 0 ? this.panels.length - 1 : index;
		this.fire('panels:previous', {panels: this.panels, index: index});
		this.goto_panel(index);
	},
	observe: function(){
		this.element.observe.apply(this.element, arguments);
	},
	fire: function(){
		this.element.fire.apply(this.element, arguments);
	},
	destroy: function(){
		this.controls.previous.concat(this.controls.next).concat(this.controls.gotos.values().flatten()).invoke('stopObserving');
	}
});

Initial URL


Initial Description


Initial Title
Prototype.js Panels

Initial Tags


Initial Language
JavaScript