Skip to content

Commit

Permalink
feat(dropdown): support programatic trigger & toggle callback
Browse files Browse the repository at this point in the history
  • Loading branch information
bekos committed Jan 20, 2014
1 parent 16b4c9a commit f13967b
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 103 deletions.
60 changes: 50 additions & 10 deletions src/dropdownToggle/docs/demo.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,50 @@
<li class="dropdown" ng-controller="DropdownCtrl">
<a class="dropdown-toggle">
Click me for a dropdown, yo!
</a>
<ul class="dropdown-menu">
<li ng-repeat="choice in items">
<a>{{choice}}</a>
</li>
</ul>
</li>

<div ng-controller="DropdownCtrl">
<!-- Simple dropdown -->
<span class="dropdown" on-toggle="toggled(open)">
<a class="dropdown-toggle">
Click me for a dropdown, yo!
</a>
<ul class="dropdown-menu">
<li ng-repeat="choice in items">
<a>{{choice}}</a>
</li>
</ul>
</span>

<!-- Single button -->
<div class="btn-group" dropdown is-open="status.isopen">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
Button dropdown <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</div>

<!-- Split button -->
<div class="btn-group" dropdown>
<button type="button" class="btn btn-danger">Action</button>
<button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Split button!</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</div>

<hr />
<p>
<button type="button" class="btn btn-default btn-sm" ng-click="toggleDropdown($event)">Toggle button dropdown</button>
</p>

</div>
14 changes: 14 additions & 0 deletions src/dropdownToggle/docs/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,18 @@ function DropdownCtrl($scope) {
'And another choice for you.',
'but wait! A third!'
];

$scope.status = {
isopen: false
};

$scope.toggled = function(open) {
console.log('Dropdown is now: ', open);
};

$scope.toggleDropdown = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.status.isopen = !$scope.status.isopen;
};
}
130 changes: 89 additions & 41 deletions src/dropdownToggle/dropdownToggle.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,100 @@
/*
* dropdownToggle - Provides dropdown menu functionality in place of bootstrap js
* @restrict class or attribute
* @example:
<li class="dropdown">
<a class="dropdown-toggle">My Dropdown Menu</a>
<ul class="dropdown-menu">
<li ng-repeat="choice in dropChoices">
<a ng-href="{{choice.href}}">{{choice.text}}</a>
</li>
</ul>
</li>
*/

angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', function ($document) {
var openElement = null,
closeMenu = angular.noop;
angular.module('ui.bootstrap.dropdownToggle', [])

.constant('dropdownConfig', {
openClass: 'open'
})

.service('dropdownService', ['$document', function($document) {
var self = this, openScope = null;

this.open = function( dropdownScope ) {
if ( !openScope ) {
$document.bind('click', documentClickBind);
}

if ( openScope && openScope !== dropdownScope ) {
openScope.isOpen = false;
}

openScope = dropdownScope;
};

this.close = function( dropdownScope ) {
if ( openScope === dropdownScope ) {
openScope = null;
$document.unbind('click', documentClickBind);
}
};

var documentClickBind = function() {
openScope.$apply(function() {
openScope.isOpen = false;
});
};
}])

.controller('DropdownController', ['$scope', '$attrs', 'dropdownConfig', 'dropdownService', function($scope, $attrs, dropdownConfig, dropdownService) {
var self = this, openClass = dropdownConfig.openClass;

this.init = function( element ) {
self.$element = element;
$scope.isOpen = angular.isDefined($attrs.isOpen) ? $scope.$parent.$eval($attrs.isOpen) : false;
};

this.toggle = function() {
$scope.isOpen = !$scope.isOpen;
};

$scope.$watch('isOpen', function( value ) {
self.$element.toggleClass( openClass, value );

if ( value ) {
dropdownService.open( $scope );
} else {
dropdownService.close( $scope );
}

$scope.onToggle({ open: !!value });
});

$scope.$on('$locationChangeSuccess', function() {
$scope.isOpen = false;
});
}])

.directive('dropdown', function() {
return {
restrict: 'CA',
link: function(scope, element, attrs) {
scope.$on('$locationChangeSuccess', function() { closeMenu(); });
element.parent().bind('click', function() { closeMenu(); });
element.bind('click', function (event) {
controller: 'DropdownController',
scope: {
isOpen: '=?',
onToggle: '&'
},
link: function(scope, element, attrs, dropdownCtrl) {
dropdownCtrl.init( element );
}
};
})

var elementWasOpen = (element === openElement);
.directive('dropdownToggle', function() {
return {
restrict: 'CA',
require: '?^dropdown',
link: function(scope, element, attrs, dropdownCtrl) {
if ( !dropdownCtrl ) {
return;
}

element.bind('click', function(event) {
event.preventDefault();
event.stopPropagation();

if (!!openElement) {
closeMenu();
}

if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) {
element.parent().addClass('open');
openElement = element;
closeMenu = function (event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
$document.unbind('click', closeMenu);
element.parent().removeClass('open');
closeMenu = angular.noop;
openElement = null;
};
$document.bind('click', closeMenu);
if ( !element.hasClass('disabled') && !element.prop('disabled') ) {
scope.$apply(function() {
dropdownCtrl.toggle();
});
}
});
}
};
}]);
});
Loading

0 comments on commit f13967b

Please sign in to comment.