You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.3 KiB
231 lines
7.3 KiB
/*
|
|
* jQuery UI jb.overflowmenu
|
|
*
|
|
* Copyright 2011, Jesse Baird <jebaird@gmail.com> jebaird.com
|
|
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
*
|
|
* http://jebaird.com/blog/overflow-menu-jquery-ui-widget
|
|
*
|
|
* Depends:
|
|
* jquery.ui.core.js
|
|
* jquery.ui.widget.js
|
|
*
|
|
*
|
|
* suggested markup
|
|
* <nav>
|
|
* <ul>
|
|
* <li>
|
|
* </ul>
|
|
* </nav>
|
|
*
|
|
* $('nav').overflowmenu()
|
|
*
|
|
*
|
|
*
|
|
* events
|
|
* change - after items are moved to / from the secondary menu
|
|
* beforeChange - called before items are moved to / from the secondary menu
|
|
* open - when the secondary menu is shown
|
|
* close - when the secondary menu is closed
|
|
*/
|
|
|
|
(function( $, undefined ) {
|
|
|
|
$.widget( "jb.overflowmenu", {
|
|
options: {
|
|
items: '> *',
|
|
itemsParentTag: 'ul',
|
|
label: '<i class="icon-ellipsis-vertical"></i>',
|
|
//call the refresh method when this element changes size, with out a special event window is the only element that this gets called on
|
|
refreshOn: $( window ),
|
|
|
|
//attempt to guess the height of the menu, if not the target element needs to have a height
|
|
guessHeight: true
|
|
},
|
|
|
|
_create: function() {
|
|
var self = this;
|
|
|
|
this.element
|
|
.addClass('jb-overflowmenu');
|
|
|
|
this.primaryMenu = this.element
|
|
.children( this.options.itemsParentTag )
|
|
.addClass( 'jb-overflowmenu-menu jb-overflowmenu-menu-primary jb-overflowmenu-helper-postion' );
|
|
|
|
this._setHeight();
|
|
|
|
//TODO: allow the user to change the markup for this because they might not be using ul -> li
|
|
this.secondaryMenuContainer = $(
|
|
[
|
|
'<div class="jb-overflowmenu-container jb-overflowmenu-helper-postion">',
|
|
'<a href="javascript://" class="jb-overflowmenu-menu-secondary-handle"></a>',
|
|
'<' + this.options.itemsParentTag + ' class="jb-overflowmenu-menu jb-overflowmenu-menu-secondary jb-overflowmenu-helper-postion"></' + this.options.itemsParentTag + '>',
|
|
'</div>'
|
|
].join('')
|
|
)
|
|
.appendTo( this.element )
|
|
|
|
this.secondaryMenu = this.secondaryMenuContainer.find('ul');
|
|
|
|
this.secondaryMenuContainer.children( 'a' ).bind( 'click.overflowmenu', function( e ){
|
|
self.toggle();
|
|
});
|
|
|
|
//has to be set first
|
|
this._setOption( 'label', this.options.label )
|
|
this._setOption( 'refreshOn', this.options.refreshOn )
|
|
this.secondaryMenuContainer.find('i.icon-sort-down').remove('i.icon-sort-down');
|
|
},
|
|
|
|
destroy: function() {
|
|
this.element
|
|
.removeClass('jb-overflowmenu')
|
|
|
|
this.primaryMenu
|
|
.removeClass('jb-overflowmenu-menu-primary jb-overflowmenu-helper-postion')
|
|
.find( this.options.items )
|
|
.filter( ':hidden' )
|
|
.css( 'display', '' )
|
|
|
|
this.options.refreshOn.unbind( 'resize.overflowmenu' );
|
|
|
|
this.secondaryMenuContainer.remove()
|
|
|
|
//TODO: possibly clean up the height & right on the ul
|
|
|
|
$.Widget.prototype.destroy.apply( this, arguments );
|
|
},
|
|
|
|
|
|
refresh: function() {
|
|
|
|
this._trigger( 'beforeChange', {}, this._uiHash() );
|
|
|
|
//move any items in the secondary menu back in to the primary
|
|
this.secondaryMenu
|
|
.children()
|
|
.appendTo( this.primaryMenu )
|
|
|
|
|
|
var vHeight = this.primaryMenuHeight,
|
|
hWidth = this.secondaryMenuContainer.find('.jb-overflowmenu-menu-secondary-handle')
|
|
.outerWidth(),
|
|
vWidth = this.primaryMenuWidth - hWidth,
|
|
previousRight = this.primaryMenu.offset().left;
|
|
|
|
// Items classed 'primary-only' should always be primary
|
|
this._getItems()
|
|
.each(function() {
|
|
var $this = $(this);
|
|
if ($this.hasClass('primary-only'))
|
|
vWidth -= $this.outerWidth(true);
|
|
});
|
|
|
|
//get the items, filter out the visible ones
|
|
itemsToHide = this._getItems()
|
|
.filter(function() {
|
|
var $this = $(this),
|
|
left = $this.offset().left,
|
|
dLeft = Math.max(0, left - previousRight);
|
|
previousRight = left + $this.width();
|
|
|
|
if ($this.hasClass('primary-only'))
|
|
return false;
|
|
|
|
vWidth -= dLeft + $this.outerWidth(true);
|
|
return vWidth < 1;
|
|
});
|
|
|
|
itemsToHide.appendTo( this.secondaryMenu )
|
|
.find('i.icon-sort-down').remove('i.icon-sort-down');
|
|
|
|
|
|
if( itemsToHide.length == 0 ){
|
|
this.close();
|
|
}
|
|
|
|
//TODO: add the items to the UI Hash
|
|
this._trigger( 'change', {}, this._uiHash() );
|
|
return this;
|
|
},
|
|
|
|
//more menu opitons
|
|
|
|
open: function(){
|
|
if( this.secondaryMenu.find( this.options.items ).length == 0){
|
|
return;
|
|
}
|
|
this.primaryMenu.css( 'right', this.primaryMenu.data( 'right' ) )
|
|
this.secondaryMenu.show();
|
|
this._trigger( 'open', {}, this._uiHash() );
|
|
return this;
|
|
},
|
|
close: function(){
|
|
this.secondaryMenu.hide();
|
|
this._trigger( 'close', {}, this._uiHash() );
|
|
return this;
|
|
},
|
|
toggle: function(){
|
|
if( this.secondaryMenu.is( ':visible') ){
|
|
this.close();
|
|
}else{
|
|
this.open();
|
|
}
|
|
return this;
|
|
},
|
|
_getItems: function(){
|
|
return this.primaryMenu.find( this.options.items );
|
|
},
|
|
_setHeight: function(){
|
|
if( this.options.guessHeight ){
|
|
//get the first items height and set that as the height of the parent
|
|
this.primaryMenuHeight = this.primaryMenu.find( this.options.items ).filter(':first').outerHeight();
|
|
this.primaryMenu.css('height', this.primaryMenuHeight )
|
|
|
|
}else{
|
|
this.primaryMenuHeight = this.element.innerHeight();
|
|
}
|
|
this.primaryMenuWidth = this.options.width ||
|
|
this.element.innerWidth();
|
|
|
|
},
|
|
_setOption: function( key, value ) {
|
|
var self = this;
|
|
if( key == 'refreshOn' && value ){
|
|
this.options.refreshOn.unbind( 'resize.overflowmenu' );
|
|
|
|
this.options.refreshOn = $( value )
|
|
.bind( 'resize.overflowmenu', function(){
|
|
self.refresh();
|
|
})
|
|
//call to set option
|
|
self.refresh();
|
|
|
|
}else if( key == 'label' && value ){
|
|
//figure out the width of the hadel and subtract that from the parend with and set that as the right
|
|
|
|
var width = this.secondaryMenuContainer.find('.jb-overflowmenu-menu-secondary-handle')
|
|
.html( value )
|
|
.outerWidth();
|
|
this.primaryMenu.data( 'right', width )
|
|
|
|
}
|
|
|
|
$.Widget.prototype._setOption.apply( this, arguments );
|
|
},
|
|
_uiHash: function(){
|
|
return {
|
|
primary: this.primaryMenu,
|
|
secondary: this.secondaryMenu,
|
|
container: this.secondaryMenuContainer
|
|
};
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
})( jQuery );
|