Commits

Christoffer Niska committed 0e61b64

Added new widgets, rewrote all the javascript and fixed some issues.

Added support for rendering captcha blocks.
Added BootPopover, BootModal, BootTabs and BootPills widgets.
Renamed BootFlash to BootAlert.

  • Participants
  • Parent commits 42ba35d

Comments (0)

Files changed (19)

assets/js/jquery.bootflash.js

-/*!
- * Bootstrap Flash jQuery plugin file.
- * @author Christoffer Niska <ChristofferNiska@gmail.com>
- * @copyright  Copyright &copy; Christoffer Niska 2011-
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @see http://twitter.github.com/bootstrap
- */
-
-(function($) {
-
-	/**
-	 * Plugin default settings.
-	 * @type Object
-	 */
-	var defaults = {
-		displayTime: 5000,
-		fadeOutTime: 350
-	};
-
-	/**
-	 * Private plugin methods.
-	 * @type Object
-	 */
-	var methods = {
-		/**
-		 * Initializes the plugin.
-		 * @param {Object} options The plugin options
-		 * - displayTime: The time the alert is displayed.
-		 * - fadeOutTime: The fade out time for the alert when it is closed.
-		 */
-		init: function( options ) {
-			var settings = $.extend( defaults, options || {} );
-
-			return this.each(function() {
-				var element = $( this ),
-					alerts = element.children();
-
-				for ( var i = 0, l = alerts.length; i < l; ++i ) {
-					var alert = $( alerts[ i ] );
-
-					$( '<a class="close" href="#">x</a>' )
-						.click( function( e ) {
-							methods.close( alert, settings.fadeOutTime );
-							e.preventDefault();
-							return false;
-						} ).prependTo( alert.children() );
-
-					if ( settings.fadeOutTime > 0 ) {
-						setTimeout( function() {
-							methods.close( alert, settings.fadeOutTime );
-						}, settings.displayTime );
-					}
-				}
-			});
-		},
-		/**
-		 * Closes a specific alert.
-		 * @param {Object} element The alert element.
-		 * @param {Number} fadeTime The fade out time.
-		 */
-		close: function( element, fadeTime ) {
-			element.fadeOut( fadeTime, function() {
-				$( this ).html( '' );
-			});
-		},
-		/**
-		 * Destructs the plugin.
-		 * Frees up all storage used and unbinds the events.
-		 */
-		destroy: function() {
-			// Nothing here for now...
-		}
-	};
-
-	/**
-	 * Bootstrap Flash jQuery plugin.
-	 * @param method The method to call.
-	 */
-	$.fn.bootflash = function( method ) {
-		if ( method instanceof String && method.indexOf( '_' ) !== 0 && methods[ method ] ) {
-			return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
-		} else if ( typeof method === 'object' || ! method ) {
-			return methods.init.apply( this, arguments );
-		} else {
-			$.error( 'Method ' +  method + ' does not exist on jQuery.bootflash.' );
-		}
-	};
-
-})(jQuery);

assets/js/jquery.bootpopover.js

-/*!
- * Bootstrap Pop-over jQuery plugin file.
- * @author Christoffer Niska <ChristofferNiska@gmail.com>
- * @copyright  Copyright &copy; Christoffer Niska 2011-
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @see http://twitter.github.com/bootstrap
- */
-
-(function($) {
-
-	/**
-	 * Plugin default settings.
-	 * @type Object
-	 */
-	var defaults = {
-		placement: 'above',
-		showEvent: 'mouseenter',
-		hideEvent: 'mouseleave',
-		live: false
-	};
-
-	/**
-	 * Private plugin methods.
-	 * @type Object
-	 */
-	var methods = {
-		/**
-		 * Initializes the plugin.
-		 * @param {Object} options The plugin options.
-		 * - placement: The placement of the tooltip, valid options are: 'above', 'right', 'below' and 'left'.
-		 * - showEvent: The mouse event on which to show the tooltip. Defaults to 'mouseenter'.
-		 * - hideEvent: The mouse event on which to hide the tooltip. Defaults to 'mouseleave'.
-		 * - live: Whether to use the live or bind method. Defaults to false, meaning that 'bind' will be used.
-		 */
-		init: function( options ) {
-			var settings = $.extend( defaults, options || {} ),
-				popover = methods.createPopover( settings.placement );
-
-			return this.each(function() {
-				var element = $( this ),
-					title = element.attr( 'title' ),
-					content = element.attr( 'data-content' );
-
-				if ( title && title.length > 0 && content && content.length > 0 ) {
-					var data = methods._data( element ),
-						binder = settings.live ? 'live' : 'bind';
-
-					element.removeAttr( 'title' ); // remove the title to prevent it being displayed
-					element.attr( 'data-title', title);
-
-					data.popover = popover;
-					data.placement = settings.placement;
-					data.visible = false;
-
-					element[ binder ]( settings.showEvent, function( e ) {
-						methods.show( element );
-					});
-
-					element[ binder ]( settings.hideEvent, function( e ) {
-						methods.hide( element );
-					});
-				}
-			});
-		},
-		/**
-		 * Creates the pop-over element.
-		 * We only need to create one because we re-use it over and over.
-		 * @param {String} placement The placement for the pop-over.
-		 */
-		createPopover: function( placement ) {
-			var popover = $( '<div class="popover ' + placement + '">' )
-					.appendTo( 'body' )
-					.hide();
-
-			$( '<div class="arrow">' )
-					.appendTo( popover );
-
-			$( '<div class="inner"><h3 class="title"></h3><div class="content"><p></p></div>' )
-					.appendTo( popover );
-
-			return popover;
-		},
-		/**
-		 * Shows the tooltip.
-		 * @param {Object} element The element for which to show the tooltip.
-		 */
-		show: function( element ) {
-			var data = methods._data( element );
-
-			if ( !data.visible ) {
-				var position;
-				data.popover.find( '.title' ).html( element.attr( 'data-title' ) );
-				data.popover.find( '.content p' ).html( element.attr( 'data-content' ) );
-				position = methods._pos( element );
-				data.popover.css( {
-					top: position.top,
-					left: position.left
-				} ).show(); // todo: implement support for effects.
-
-				data.visible = true;
-			}
-		},
-		/**
-		 * Hides the pop-over.
-		 * @param {Object} element The element for which to hide the tooltip.
-		 */
-		hide: function( element ) {
-			var data = methods._data( element );
-
-			if ( data.visible ) {
-				data.popover.hide(); // todo: implement support for effects.
-				data.visible = false;
-			}
-		},
-		/**
-		 * Returns the offset for this pop-over.
-		 * @param {Object} element The element for which to get the tooltip offset.
-		 * @returns {Object} The offset.
-		 */
-		_pos: function( element ) {
-			var data = methods._data( element ),
-				offset = element.offset(),
-				top = 0,
-				left = 0;
-
-			switch ( data.placement ) {
-				case 'above':
-					top = offset.top - data.popover.outerHeight(),
-					left = offset.left + ( ( element.outerWidth() - data.popover.outerWidth() ) / 2 );
-					break;
-
-				case 'right':
-					top = offset.top + ( ( element.outerHeight() - data.popover.outerHeight() ) / 2 );
-					left = offset.left + element.outerWidth();
-					break;
-
-				case 'below':
-					top = offset.top + element.outerHeight(),
-					left = offset.left + ( ( element.outerWidth() - data.popover.outerWidth() ) / 2 );
-					break;
-
-				case 'left':
-					top = offset.top + ( ( element.outerHeight() - data.popover.outerHeight() ) / 2 );
-					left = offset.left - data.popover.outerWidth();
-					break;
-			}
-
-			return {
-				left: left,
-				top: top
-			};
-		},
-		/**
-		 * Returns the data for the pop-over from a specific element.
-		 * @param {Object} element The element for which to retrieve the data.
-		 * @returns {Object} The data.
-		 */
-		_data: function( element ) {
-			var data = $.data( element, 'popover' );
-
-			if ( !data ) {
-				data = $.data( element, 'popover', {} );
-			}
-
-			return data;
-		},
-	};
-
-	/**
-	 * Bootstrap Pop-over jQuery plugin.
-	 * @param method The method to call.
-	 */
-	$.fn.bootpopover = function( method ) {
-		if ( method instanceof String && method.indexOf( '_' ) !== 0 && methods[ method ] ) {
-			return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
-		} else if ( typeof method === 'object' || ! method ) {
-			return methods.init.apply( this, arguments );
-		} else {
-			$.error( 'Method ' +  method + ' does not exist on jQuery.bootpopover.' );
-		}
-	};
-
-})(jQuery);

assets/js/jquery.boottwipsy.js

-/*!
- * Bootstrap Twipsy jQuery plugin file.
- * @author Christoffer Niska <ChristofferNiska@gmail.com>
- * @copyright  Copyright &copy; Christoffer Niska 2011-
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @see http://twitter.github.com/bootstrap
- */
-
-(function($) {
-
-	/**
-	 * Plugin default settings.
-	 * @type Object
-	 */
-	var defaults = {
-		placement: 'above',
-		showEvent: 'mouseenter',
-		hideEvent: 'mouseleave',
-		live: false
-	};
-
-	/**
-	 * Private plugin methods.
-	 * @type Object
-	 */
-	var methods = {
-		/**
-		 * Initializes the plugin.
-		 * @param {Object} options The plugin options.
-		 * - placement: The placement of the tooltip, valid options are: 'above', 'right', 'below' and 'left'.
-		 * - showEvent: The mouse event on which to show the tooltip. Defaults to 'mouseenter'.
-		 * - hideEvent: The mouse event on which to hide the tooltip. Defaults to 'mouseleave'.
-		 * - live: Whether to use the live or bind method. Defaults to false, meaning that 'bind' will be used.
-		 */
-		init: function( options ) {
-			var settings = $.extend( defaults, options || {} ),
-				twipsy = methods.createTwipsy( settings.placement );
-			
-			return this.each(function() {
-				var element = $( this ),
-					title = element.attr( 'title' );
-
-				if ( title && title.length > 0 ) {
-					var data = methods._data( element ),
-						binder = settings.live ? 'live' : 'bind';
-
-					element.removeAttr( 'title' ); // remove the title to prevent it being displayed
-					element.attr( 'data-title', title);
-
-					data.twipsy = twipsy;
-					data.placement = settings.placement;
-					data.visible = false;
-
-					element[ binder ]( settings.showEvent, function( e ) {
-						methods.show( element );
-					});
-
-					element[ binder ]( settings.hideEvent, function( e ) {
-						methods.hide( element );
-					});
-				}
-			});
-		},
-		/**
-		 * Creates the twipsy element.
-		 * We only need to create one because we re-use it over and over.
-		 * @param {String} placement The placement for the tooltip.
-		 */
-		createTwipsy: function( placement ) {
-			var twipsy = $( '<div class="twipsy ' + placement + '">' )
-					.appendTo( 'body' )
-					.hide();
-
-			$( '<div class="twipsy-arrow">' )
-					.appendTo( twipsy );
-
-			$( '<div class="twipsy-inner">' )
-					.appendTo( twipsy );
-
-			return twipsy;
-		},
-		/**
-		 * Shows the tooltip.
-		 * @param {Object} element The element for which to show the tooltip.
-		 */
-		show: function( element ) {
-			var data = methods._data( element );
-
-			if ( !data.visible ) {
-				var position;
-				data.twipsy.find( '.twipsy-inner' ).html( element.attr( 'data-title' ) );
-				position = methods._pos( element );
-				data.twipsy.css( {
-					top: position.top,
-					left: position.left
-				} ).show(); // todo: implement support for effects.
-
-				data.visible = true;
-			}
-		},
-		/**
-		 * Hides the tooltip.
-		 * @param {Object} element The element for which to hide the tooltip.
-		 */
-		hide: function( element ) {
-			var data = methods._data( element );
-
-			if ( data.visible ) {
-				data.twipsy.hide(); // todo: implement support for effects.
-				data.visible = false;
-			}
-		},
-		/**
-		 * Returns the offset for this tooltip.
-		 * @param {Object} element The element for which to get the tooltip offset.
-		 * @returns {Object} The offset.
-		 */
-		_pos: function( element ) {
-			var data = methods._data( element ),
-				offset = element.offset(),
-				top = 0,
-				left = 0;
-
-			switch ( data.placement ) {
-				case 'above':
-					top = offset.top - data.twipsy.outerHeight(),
-					left = offset.left + ( ( element.outerWidth() - data.twipsy.outerWidth() ) / 2 );
-					break;
-
-				case 'right':
-					top = offset.top + ( ( element.outerHeight() - data.twipsy.outerHeight() ) / 2 );
-					left = offset.left + element.outerWidth();
-					break;
-
-				case 'below':
-					top = offset.top + element.outerHeight(),
-					left = offset.left + ( ( element.outerWidth() - data.twipsy.outerWidth() ) / 2 );
-					break;
-
-				case 'left':
-					top = offset.top + ( ( element.outerHeight() - data.twipsy.outerHeight() ) / 2 );
-					left = offset.left - data.twipsy.outerWidth();
-					break;
-			}
-
-			return {
-				left: left,
-				top: top
-			};
-		},
-		/**
-		 * Returns the data for the tooltip from a specific element.
-		 * @param {Object} element The element for which to retrieve the data.
-		 * @returns {Object} The data.
-		 */
-		_data: function( element ) {
-			var data = $.data( element, 'twipsy' );
-
-			if ( !data ) {
-				data = $.data( element, 'twipsy', {} );
-			}
-
-			return data;
-		},
-		/**
-		 * Destructs the plugin.
-		 * Frees up all storage used and unbinds the events.
-		 */
-		destroy: function() {
-			var window = $( window );
-
-			return this.each(function() {
-				window.unbind( '.twipsy' );
-			});
-		}
-	};
-
-	/**
-	 * Bootstrap Twipsy jQuery plugin.
-	 * @param method The method to call.
-	 */
-	$.fn.boottwipsy = function( method ) {
-		if ( method instanceof String && method.indexOf( '_' ) !== 0 && methods[ method ] ) {
-			return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
-		} else if ( typeof method === 'object' || ! method ) {
-			return methods.init.apply( this, arguments );
-		} else {
-			$.error( 'Method ' +  method + ' does not exist on jQuery.boottwipsy.' );
-		}
-	};
-
-})(jQuery);

assets/js/jquery.ui.bootalert.js

+/*!
+ * Bootstrap Alert jQuery UI widget file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright  Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @see http://twitter.github.com/bootstrap
+ */
+
+( function( $ ) {
+	"use strict" // set strict mode
+
+	var widget = $.extend( {}, $.ui.bootWidget.prototype, {
+		/**
+		 * The name of the widget.
+		 * @type String
+		 */
+		name: 'alert',
+		/**
+		 * Widget options.
+		 * @type Object
+		 */
+		options: {
+			keys: [ 'success', 'info', 'warning', 'error' ],
+			template: '<div class="alert-message {key}"><p>{message}</p></div>',
+			displayTime: 5000,
+			fadeOutTime: 350
+		},
+		/**
+		 * Creates the widget.
+		 */
+		_create: function() {
+			var alerts = this.element.find( '.alert-message' );
+
+			for ( var i = 0, l = alerts.length; i < l; ++i ) {
+				var alert = $( alerts[ i ] );
+				this._appendCloseLink( alert );
+			}
+		},
+		/**
+		 * Creates a new alert message.
+		 * @param {String} key The message type, e.g. 'success'.
+		 * @param {String} message The message.
+		 */
+		alert: function( key, message ) {
+			if ( this.options.keys.indexOf( key ) !== -1 ) {
+				var template = this.options.template;
+				template = template.replace( '{key}', key );
+				template = template.replace( '{message}', message );
+
+				var alert = $( template )
+					.appendTo( this.element );
+
+				this._appendCloseLink( alert );
+			}
+
+			return this;
+		},
+		/**
+		 * Closes the alert.
+		 * @param {HTMLElement} alert The alert element.
+		 */
+		close: function( alert ) {
+			alert.fadeOut( this.options.fadeTime, function() {
+				alert.html( '' );
+			});
+
+			return this;
+		},
+		/**
+		 * Creates the close link for a specific alert message.
+		 * @param {HTMLElement} alert The alert element.
+		 */
+		_appendCloseLink: function( alert ) {
+			var self = this;
+
+			$( '<a class="close" href="#">x</a>' )
+				.bind( 'click', function( event ) {
+					self.close( alert, self.options.fadeOutTime );
+					event.preventDefault();
+					return false;
+				} ).prependTo( self.element.children() );
+
+			if ( self.options.fadeOutTime > 0 ) {
+				setTimeout( function() {
+					self.close( alert, self.options.fadeOutTime );
+				}, self.options.displayTime );
+			}
+		},
+		/**
+		 * Destructs this widget.
+		 */
+		_destroy: function() {
+			// Nothing here yet...
+		}
+	} );
+
+	/**
+	 * BootAlert jQuery UI widget.
+	 */
+	$.widget( 'ui.bootAlert', widget );
+
+} )( jQuery );

assets/js/jquery.ui.bootmodal.js

+/*!
+ * Bootstrap Modal jQuery UI widget file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright  Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @see http://twitter.github.com/bootstrap
+ */
+
+( function( $ ) {
+	"use strict" // set strict mode
+
+	var widget = $.extend( {}, $.ui.bootWidget.prototype, {
+		/**
+		 * The name of the widget.
+		 * @type String
+		 */
+		name: 'modal',
+		/**
+		 * The backdrop element.
+		 * @type Object
+		 */
+		backdrop: null,
+		/**
+		 * Indicates whether this modal is visible.
+		 * @type Boolean
+		 */
+		visible: false,
+		/**
+		 * Widget options.
+		 * - backdropClose: Indicates whether clicking on the backdrop closes the modal.
+		 * - buttons: Button configurations.
+		 * - closeTime: The delay for closing the modal.
+		 * - escapeClose: Indicates whether pressing escape closes the modal.
+		 * - open: Indicates whether to open the modal on initialization.
+		 * - title: The modal title text.
+		 * @type Object
+		 */
+		options: {
+			backdropClose: false,
+			buttons: [],
+			closeTime: 350,
+			escapeClose: false,
+			open: false,
+			openTime: 1000,
+			title: ''
+		},
+		/**
+		 * Creates the widget.
+		 */
+		_create: function() {
+			var self = this,
+				element = self.element,
+				header = self._createHeader(),
+				body = self._createBody(),
+				footer = self._createFooter();
+
+			element.remove()
+				.html( '' );
+
+			header.appendTo( element );
+			body.appendTo( element );
+			footer.appendTo( element );
+			element.addClass( 'modal' )
+				.hide()
+				.appendTo( 'body' );
+		},
+		/**
+		 * Initializes the widget.
+		 */
+		_init: function() {
+			var self = this;
+
+			if ( self.options.open ) {
+				self.open();
+			}
+
+			if ( self.options.escapeClose ) {
+				$( document ).bind( 'keyup.bootModal', function ( event ) {
+					if ( event.which === 27 ) {
+						self.close();
+					}
+				})
+			}
+		},
+		/**
+		 * Opens the modal.
+		 */
+		open: function() {
+			var self = this,
+				options = self.options;
+
+			if ( !self.visible ) {
+				var backdrop = self._getBackdrop();
+				backdrop.show();
+				self.element.fadeIn( options.openTime );
+				self.visible = true;
+			}
+
+			return this;
+		},
+		/**
+		 * Closes the modal.
+		 */
+		close: function() {
+			var self = this,
+				options = self.options;
+
+			if ( self.visible ) {
+				self.element.fadeOut( options.closeTime, function() {
+					var backdrop = self._getBackdrop();
+					backdrop.hide();
+				});
+				self.visible = false;
+			}
+
+			return self;
+		},
+		/**
+		 * Creates the modal header element.
+		 * @return {Object} The element.
+		 */
+		_createHeader: function() {
+			var header = $( '<div class="modal-header">' );
+
+			$( '<h3>' )
+				.html( this.options.title )
+				.appendTo( header );
+
+			var closeLink = this._createCloseLink();
+			closeLink.prependTo( header );
+
+			return header;
+		},
+		/**
+		 * Creates the modal body element.
+		 * @return {Object} The element.
+		 */
+		_createBody: function() {
+			return $( '<div class="modal-body">' )
+				.html( this.element.html() );
+		},
+		/**
+		 * Creates the modal footer element.
+		 * @return {Object} The element.
+		 */
+		_createFooter: function() {
+			var i, l, config, button,
+				footer = $( '<div class="modal-footer">' );
+
+			for ( i = 0, l = this.options.buttons.length; i < l; ++i ) {
+				config = this.options.buttons[ i ];
+				button = this._createButton( config );
+				button.prependTo( footer );
+			}
+
+			return footer;
+		},
+		/**
+		 * Creates a button element from the given config array.
+		 * @param {Array} config The button config.
+		 * @returns {Object} The element.
+		 */
+		_createButton: function( config ) {
+			var button = $( '<button>' ),
+				property;
+
+			for ( property in config ) {
+				switch ( property ) {
+					case 'class':
+						button.addClass( config[ property ] );
+						break;
+
+					case 'click':
+						button.bind( 'click', config[ property ] );
+						break;
+
+					case 'label':
+						button.html( config[ property ] );
+						break;
+
+					default:
+				}
+			}
+
+			return button;
+		},
+		/**
+		 * Creates a close link for this modal.
+		 */
+		_createCloseLink: function() {
+			var self = this;
+
+			return $( '<a class="close" href="#">x</a>' )
+				.bind( 'click', function( event ) {
+					self.close();
+					event.preventDefault();
+					return false;
+				} );
+		},
+		/**
+		 * Returns the backdrop element creating it if it doesn't exist.
+		 * @returns {Object} The element.
+		 */
+		_getBackdrop: function() {
+			var self = this,
+				backdrop = $( '.modal-backdrop' );
+
+			if ( backdrop.length === 0 ) {
+				backdrop = $( '<div class="modal-backdrop">' )
+					.hide()
+					.appendTo( 'body' );
+
+				if ( this.options.backdropClose ) {
+					backdrop.bind( 'click', function( event ) {
+						self.close();
+						event.preventDefault();
+						return false;
+					} );
+				}
+			}
+
+			return backdrop;
+		},
+		/**
+		 * Destructs the widget.
+		 */
+		_destroy: function() {
+			if ( this.options.escapeClose ) {
+				$( document ).unbind( 'keyup.bootModal' );
+			}
+		}
+	} );
+
+	/**
+	 * BootModal jQuery UI widget.
+	 */
+	$.widget( 'ui.bootModal', widget );
+
+} )( jQuery );

assets/js/jquery.ui.bootpopover.js

+/*!
+ * Bootstrap Popover jQuery UI widget file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright  Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @see http://twitter.github.com/bootstrap
+ */
+
+( function( $ ) {
+	"use strict" // set strict mode
+
+	var widget = $.extend( {}, $.ui.bootTwipsy.prototype, {
+		/**
+		 * The name of the widget.
+		 * @type String
+		 */
+		name: 'popover',
+		/**
+		 * The value of the tooltip id attribute.
+		 * @type String
+		 */
+		tooltipId: 'popover',
+		/**
+		 * Widget options.
+		 * @type Object
+		 */
+		options: {
+			placement: 'above',
+			showEvent: 'mouseenter',
+			hideEvent: 'mouseleave',
+			live: false
+		},
+		/**
+		 * Shows the tooltip.
+		 */
+		show: function() {
+			if ( !this.visible ) {
+				var tooltip = this._getTooltip(),
+					position;
+				
+				tooltip.find( '.title' ).html( this.element.attr( 'data-title' ) );
+				tooltip.find( '.content p' ).html( this.element.attr( 'data-content' ) );
+				position = this._pos();
+				tooltip.css( {
+					top: position.top,
+					left: position.left
+				} ).show(); // todo: implement support for effects.
+
+				this.visible = true;
+			}
+		},
+		/**
+		 * Creates the tooltip element and appends it to the body element.
+		 * @returns {HTMLElement} The element.
+		 */
+		_createTooltip: function() {
+			var tooltip = $( '<div class="popover">' )
+				.attr( 'id', this.tooltipId )
+				.addClass( this.options.placement )
+				.appendTo( 'body' )
+				.hide();
+
+			$( '<div class="arrow">' )
+				.appendTo( tooltip );
+
+			$( '<div class="inner"><h3 class="title"></h3><div class="content"><p></p></div>' )
+				.appendTo( tooltip );
+
+			return tooltip;
+		}
+	} );
+
+	/**
+	 * BootPopover jQuery UI widget.
+	 */
+	$.widget( 'ui.bootPopover', widget );
+
+} )( jQuery );

assets/js/jquery.ui.boottwipsy.js

+/*!
+ * Bootstrap Twipsy jQuery UI widget file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright  Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @see http://twitter.github.com/bootstrap
+ */
+
+( function( $ ) {
+	"use strict" // set strict mode
+
+	var widget = $.extend( {}, $.ui.bootWidget.prototype, {
+		/**
+		 * The name of the widget.
+		 * @type String
+		 */
+		name: 'twipsy',
+		/**
+		 * The value of the tooltip id attribute.
+		 * @type String
+		 */
+		tooltipId: 'twipsy',
+		/**
+		 * Indicates whether the tooltip is visible.
+		 * @type Boolean
+		 */
+		visible: false,
+		/**
+		 * Widget options.
+		 * @type Object
+		 */
+		options: {
+			placement: 'above',
+			showEvent: 'mouseenter',
+			hideEvent: 'mouseleave',
+			live: false
+		},
+		/**
+		 * Creates the widget.
+		 */
+		_create: function() {
+			var self = this,
+				element = self.element,
+				options = self.options,
+				title = self.element.attr( 'title' ),
+				binder = options.live ? 'live' : 'bind';
+
+			if ( title && title.length > 0 ) {
+				element.removeAttr( 'title' ); // remove the title to prevent it being displayed
+				element.attr( 'data-title', title );
+
+				element[ binder ]( options.showEvent, function() {
+					self.show();
+				});
+
+				element[ binder ]( options.hideEvent, function() {
+					self.hide();
+				});
+			}
+		},
+		/**
+		 * Shows the tooltip.
+		 */
+		show: function() {
+			if ( !this.visible ) {
+				var tooltip = this._getTooltip(),
+					position;
+
+				tooltip.find( '.twipsy-inner' ).html( this.element.attr( 'data-title' ) );
+				position = this._pos();
+				tooltip.css( {
+					top: position.top,
+					left: position.left
+				} ).show(); // todo: implement support for effects.
+
+				this.visible = true;
+			}
+
+			return this;
+		},
+		/**
+		 * Hides the tooltip.
+		 */
+		hide: function() {
+			if ( this.visible ) {
+				var tooltip = this._getTooltip();
+				tooltip.hide(); // todo: implement support for effects.
+				this.visible = false;
+			}
+
+			return this;
+		},
+		/**
+		 * Calculates the position for the tooltip based on the element.
+		 * @return {Object} The offset, an object with "top" and "left" properties.
+		 */
+		_pos: function() {
+			var twipsy = this._getTooltip(),
+				element = this.element,
+				offset = element.offset(),
+				top = 0,
+				left = 0;
+
+			switch ( this.options.placement ) {
+				case 'above':
+					top = offset.top - twipsy.outerHeight(),
+					left = offset.left + ( ( element.outerWidth() - twipsy.outerWidth() ) / 2 );
+					break;
+
+				case 'right':
+					top = offset.top + ( ( element.outerHeight() - twipsy.outerHeight() ) / 2 );
+					left = offset.left + element.outerWidth();
+					break;
+
+				case 'below':
+					top = offset.top + element.outerHeight(),
+					left = offset.left + ( ( element.outerWidth() - twipsy.outerWidth() ) / 2 );
+					break;
+
+				case 'left':
+					top = offset.top + ( ( element.outerHeight() - twipsy.outerHeight() ) / 2 );
+					left = offset.left - twipsy.outerWidth();
+					break;
+			}
+
+			return {
+				left: left,
+				top: top
+			};
+		},
+		/**
+		 * Creates the tooltip element and appends it to the body element.
+		 * @returns {HTMLElement} The element.
+		 */
+		_createTooltip: function() {
+			var tooltip = $( '<div class="twipsy">' )
+				.attr( 'id', this.tooltipId )
+				.addClass( this.options.placement )
+				.appendTo( 'body' )
+				.hide();
+
+			$( '<div class="twipsy-arrow">' )
+				.appendTo( tooltip );
+
+			$( '<div class="twipsy-inner">' )
+				.appendTo( tooltip );
+
+			return tooltip;
+		},
+		/**
+		 * Returns the tooltip element from the body element.
+		 * The element is created if it doesn't already exist.
+		 * @return {HTMLElement} The element.
+		 */
+		_getTooltip: function() {
+			var tooltip = $( '#' + this.tooltipId );
+
+			if ( tooltip.length === 0 ) {
+				tooltip = this._createTooltip();
+			}
+
+			return tooltip;
+		},
+		/**
+		 * Destructs this widget.
+		 */
+		_destroy: function() {
+			this.element.unbind( this.options.showEvent );
+			this.element.unbind( this.options.hideEvent );
+		}
+	} );
+
+	/**
+	 * BootTwipsy jQuery UI widget.
+	 */
+	$.widget( 'ui.bootTwipsy', widget );
+
+} )( jQuery );

assets/js/jquery.ui.bootwidget.js

+/*!
+ * Bootstrap Widget jQuery UI widget file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright  Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @see http://twitter.github.com/bootstrap
+ */
+
+(function($) {
+	"use strict" // set strict mode
+
+	var widget = {
+		/**
+		 * The name of the widget.
+		 * @type String
+		 */
+		name: 'widget'
+	};
+
+	/**
+	 * BootWidget jQuery UI widget.
+	 * The base widget for all Bootstrap widgets.
+	 */
+	$.widget( 'ui.bootWidget', widget );
+
+})(jQuery);

widgets/BootActiveForm.php

 	}
 
 	/**
+	 * Renders a captcha block.
+	 * @param CModel $model the data model
+	 * @param string $attribute the attribute
+	 * @param array $htmlOptions additional HTML attributes
+	 * @return string the generated block
+	 * @since 0.9.3
+	 */
+	public function captchaBlock($model, $attribute, $htmlOptions = array())
+	{
+		return $this->inputBlock('captcha', $model, $attribute, null, $htmlOptions);
+	}
+
+	/**
 	 * Renders a boolean input field within a label for a model attribute.
 	 * @param string $type the input type
 	 * @param CModel $model the data model

widgets/BootAlert.php

+<?php
+/**
+ * BootAlert class file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright  Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+Yii::import('ext.bootstrap.widgets.BootWidget');
+class BootAlert extends BootWidget
+{
+	/**
+	 * @property array the keys for which to get flash messages.
+	 */
+	public $keys = array('success','info','warning','error');
+	/**
+	 * @property string the template to use for displaying flash messages.
+	 */
+	public $template = '<div class="alert-message {key}"><p>{message}</p></div>';
+	/**
+	 * @property array the html options.
+	 */
+	public $htmlOptions = array('class'=>'alert');
+
+	/**
+	 * Initializes the widget.
+	 */
+	public function init()
+	{
+		parent::init();
+		$this->registerScriptFile('jquery.ui.bootalert.js');
+	}
+
+	/**
+	 * Runs the widget.
+	 */
+	public function run()
+	{
+		$id = $this->getId();
+
+		if (isset($this->htmlOptions['id']))
+			$id = $this->htmlOptions['id'];
+		else
+			$this->htmlOptions['id'] = $id;
+
+		if (is_string($this->keys))
+			$this->keys = array($this->keys);
+
+		$markup = '';
+		foreach ($this->keys as $key)
+			if (Yii::app()->user->hasFlash($key))
+				$markup .= strtr($this->template, array('{key}'=>$key, '{message}'=>Yii::app()->user->getFlash($key)));
+
+		echo CHtml::openTag('div',$this->htmlOptions);
+		echo $markup;
+		echo '</div>';
+
+		$this->options['keys'] = $this->keys;
+		$this->options['template'] = $this->template;
+
+		$options = CJavaScript::encode($this->options);
+		Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').bootAlert({$options});");
+	}
+}

widgets/BootCrumb.php

 				$links[] = $this->renderItem(Yii::t('bootstrap', 'Home'), true);
 		}
 		else if ($this->homeLink !== false)
+			$links[] = $this->homeLink;
+
+		foreach ($this->links as $label=>$url)
 		{
-			$links[] = $this->homeLink;
-		}
-
-		foreach($this->links as $label=>$url)
-		{
-			if(is_string($label) || is_array($url))
+			if (is_string($label) || is_array($url))
 			{
 				$label = $this->encodeLabel ? BootHtml::encode($label) : $label;
 				$content = BootHtml::link($label, $url);

widgets/BootFlash.php

-<?php
-/**
- * BootFlash class file.
- * @author Christoffer Niska <ChristofferNiska@gmail.com>
- * @copyright  Copyright &copy; Christoffer Niska 2011-
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
- */
-
-Yii::import('ext.bootstrap.widgets.BootWidget');
-class BootFlash extends BootWidget
-{
-	/**
-	 * @property array the keys for which to get flash messages.
-	 */
-	public $keys = array('success','info','warning','error');
-	/**
-	 * @property string the template to use for displaying flash messages.
-	 */
-	public $template = '<div class="alert-message {key}"><p>{message}</p></div>';
-	/**
-	 * @property array the html options.
-	 */
-	public $htmlOptions = array('class'=>'flash');
-
-	/**
-	 * Initializes the widget.
-	 */
-	public function init()
-	{
-		parent::init();
-		$this->registerScriptFile('jquery.bootflash.js');
-	}
-
-	/**
-	 * Runs the widget.
-	 */
-	public function run()
-	{
-		$id = $this->getId();
-
-		if (isset($this->htmlOptions['id']))
-			$id = $this->htmlOptions['id'];
-		else
-			$this->htmlOptions['id'] = $id;
-
-		if (is_string($this->keys))
-			$this->keys = array($this->keys);
-
-		$markup = '';
-		foreach ($this->keys as $key)
-			if (Yii::app()->user->hasFlash($key))
-				$markup .= strtr($this->template, array('{key}'=>$key, '{message}'=>Yii::app()->user->getFlash($key)));
-
-		echo CHtml::openTag('div',$this->htmlOptions);
-		echo $markup;
-		echo '</div>';
-
-		$options = !empty($this->options) ? CJavaScript::encode($this->options) : '';
-		Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').bootflash({$options});");
-	}
-}

widgets/BootInputBlock.php

 	/**
 	 * @property string the input type.
 	 * Following types are supported: checkbox, checkboxlist, dropdownlist, filefield, passwordfield,
-	 * radiobutton, radiobuttonlist, textarea, textfield.
+	 * radiobutton, radiobuttonlist, textarea, textfield and captcha.
 	 */
 	public $type;
 	/**
 				$input = $this->form->textField($this->model, $this->attribute, $this->htmlOptions);
 				break;
 
+			case 'captcha':
+				$input = '<div class="captcha"><div class="widget">'.$this->widget('CCaptcha', array(), true).'</div>'
+						.$this->form->textField($this->model, $this->attribute, $this->htmlOptions).'</div>';
+				break;
+
 			default:
 				throw new CException(Yii::t('bootstrap',__CLASS__.': Failed to run widget! Input type is invalid.'));
 		}

widgets/BootModal.php

+<?php
+/**
+ * BootModal class file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @since 0.9.3
+ */
+
+Yii::import('ext.bootstrap.widgets.BootWidget');
+class BootModal extends BootWidget
+{
+	/**
+	 * @property string the name of the container element. Defaults to 'div'.
+	 */
+	public $tagName = 'div';
+
+	/**
+	 * Initializes the widget.
+	 */
+	public function init()
+	{
+		parent::init();
+		$this->registerScriptFile('jquery.ui.bootmodal.js');
+
+		$id = $this->getId();
+		if (isset($this->htmlOptions['id']))
+			$id = $this->htmlOptions['id'];
+		else
+			$this->htmlOptions['id'] = $id;
+
+		$options = !empty($this->options) ? CJavaScript::encode($this->options) : '';
+		Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').bootModal($options);");
+
+		echo CHtml::openTag($this->tagName, $this->htmlOptions).PHP_EOL;
+	}
+
+	/**
+	 * Runs the widget.
+	 */
+	public function run()
+	{
+		echo CHtml::closeTag($this->tagName);
+	}
+}

widgets/BootPopover.php

  * @author Christoffer Niska <ChristofferNiska@gmail.com>
  * @copyright Copyright &copy; Christoffer Niska 2011-
  * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @since 0.9.2
  */
 
 Yii::import('ext.bootstrap.widgets.BootWidget');
 	public function init()
 	{
 		parent::init();
-		$this->registerScriptFile('jquery.bootpopover.js');
+		$this->registerScriptFile('jquery.ui.boottwipsy.js');
+		$this->registerScriptFile('jquery.ui.bootpopover.js');
 	}
 
 	/**
 	{
 		$id = $this->getId();
 		$options = !empty($this->options) ? CJavaScript::encode($this->options) : '';
-		Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('{$this->selector}').bootpopover($options);");
+		Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('{$this->selector}').bootPopover($options);");
 	}
 }

widgets/BootTwipsy.php

 	public function init()
 	{
 		parent::init();
-		$this->registerScriptFile('jquery.boottwipsy.js');
+		$this->registerScriptFile('jquery.ui.boottwipsy.js');
 	}
 
 	/**
 	{
 		$id = $this->getId();
 		$options = !empty($this->options) ? CJavaScript::encode($this->options) : '';
-		Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('{$this->selector}').boottwipsy($options);");
+		Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('{$this->selector}').bootTwipsy($options);");
 	}
 }

widgets/BootWidget.php

 <?php
+/**
+ * BootWidget class file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ */
 
 class BootWidget extends CWidget
 {
 	/**
 	 * @property array the initial JavaScript options that should be passed to the Bootstrap plugin.
 	 */
-	public $options=array();
+	public $options = array();
 	/**
 	 * @property array the HTML attributes that should be rendered in the HTML tag representing the Bootstrap widget.
 	 */
-	public $htmlOptions=array();
+	public $htmlOptions = array();
 
 	/**
 	 * Initializes the widget.
 	public function init()
 	{
 		Yii::app()->clientScript->registerCoreScript('jquery');
+		Yii::app()->clientScript->registerCoreScript('jquery.ui');
+		
+		$this->registerScriptFile('jquery.ui.bootwidget.js');
 	}
 
 	/**

widgets/menu/BootPills.php

+<?php
+/**
+ * BootPills class file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @since 0.9.3
+ */
+
+Yii::import('zii.widgets.CMenu');
+class BootPills extends CMenu
+{
+	/**
+	 * @property array the HTML options used for {@link tagName}
+	 */
+	public $htmlOptions=array('class'=>'pills');
+}

widgets/menu/BootTabs.php

+<?php
+/**
+ * BootTabs class file.
+ * @author Christoffer Niska <ChristofferNiska@gmail.com>
+ * @copyright Copyright &copy; Christoffer Niska 2011-
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @since 0.9.3
+ */
+
+Yii::import('zii.widgets.CMenu');
+class BootTabs extends CMenu
+{
+	/**
+	 * @property array the HTML options used for {@link tagName}
+	 */
+	public $htmlOptions=array('class'=>'tabs');
+}