From 3afcaa493c461b5ae63e307decd56f301f9adc9c Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Sun, 17 Feb 2013 10:00:13 +0000 Subject: [PATCH] feat(accordion): enable HTML in accordion headings Defines a new directive that can be used below elements to provide HTML to be transcluded into the group's heading. The transcluded headfng is compiled and linked to the same scope as the transcluded body - so it can contain AngularJS directives itself. --- src/accordion/accordion.js | 56 ++++++++++++++++++++++--- src/accordion/test/accordionSpec.js | 50 +++++++++++++++++++--- template/accordion/accordion-group.html | 2 +- 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/accordion/accordion.js b/src/accordion/accordion.js index 9570d7ac66..421a118399 100644 --- a/src/accordion/accordion.js +++ b/src/accordion/accordion.js @@ -39,11 +39,11 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse']) } }; -}]); +}]) // The accordion directive simply sets up the directive controller // and adds an accordion CSS class to itself element. -angular.module('ui.bootstrap.accordion').directive('accordion', function () { +.directive('accordion', function () { return { restrict:'EA', controller:'AccordionController', @@ -51,10 +51,10 @@ angular.module('ui.bootstrap.accordion').directive('accordion', function () { replace: false, templateUrl: 'template/accordion/accordion.html' }; -}); +}) // The accordion-group directive indicates a block of html that will expand and collapse in an accordion -angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) { +.directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) { return { require:'^accordion', // We need this directive to be inside an accordion restrict:'EA', @@ -62,6 +62,11 @@ angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse', replace: true, // The element containing the directive will be replaced with the template templateUrl:'template/accordion/accordion-group.html', scope:{ heading:'@' }, // Create an isolated scope and interpolate the heading attribute onto this scope + controller: function($scope) { + this.setHeading = function(element) { + this.heading = element; + }; + }, link: function(scope, element, attrs, accordionCtrl) { var getIsOpen, setIsOpen; @@ -89,7 +94,48 @@ angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse', setIsOpen(scope.$parent, value); } }); + } + }; +}]) +// Use accordion-heading below an accordion-group to provide a heading containing HTML +// +// Heading containing HTML - +// +.directive('accordionHeading', function() { + return { + restrict: 'E', + transclude: true, // Grab the contents to be used as the heading + template: '', // In effect remove this element! + replace: true, + require: '^accordionGroup', + compile: function(element, attr, transclude) { + return function link(scope, element, attr, accordionGroupCtrl) { + // Pass the heading to the accordion-group controller + // so that it can be transcluded into the right place in the template + // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat] + accordionGroupCtrl.setHeading(transclude(scope, function() {})); + }; } }; -}]); +}) + +// Use in the accordion-group template to indicate where you want the heading to be transcluded +// You must provide the property on the accordion-group controller that will hold the transcluded element +//
+// +// ... +//
+.directive('accordionTransclude', function() { + return { + require: '^accordionGroup', + link: function(scope, element, attr, controller) { + scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) { + if ( heading ) { + element.html(''); + element.append(heading); + } + }); + } + }; +}); diff --git a/src/accordion/test/accordionSpec.js b/src/accordion/test/accordionSpec.js index 3d0d0becef..acad565a2f 100644 --- a/src/accordion/test/accordionSpec.js +++ b/src/accordion/test/accordionSpec.js @@ -104,12 +104,6 @@ describe('accordion', function () { describe('accordion-group', function () { var scope, $compile; - - beforeEach(inject(function(_$rootScope_, _$compile_) { - scope = _$rootScope_; - $compile = _$compile_; - })); - var element, groups; var findGroupLink = function (index) { return groups.eq(index).find('a').eq(0); @@ -118,6 +112,16 @@ describe('accordion', function () { return groups.eq(index).find('.accordion-body').eq(0); }; + + beforeEach(inject(function(_$rootScope_, _$compile_) { + scope = _$rootScope_; + $compile = _$compile_; + })); + + afterEach(function () { + element = groups = scope = $compile = undefined; + }); + describe('with static groups', function () { beforeEach(function () { var tpl = @@ -257,5 +261,39 @@ describe('accordion', function () { expect(findGroupBody(1)[0].clientHeight).toBe(0); }); }); + + describe('accordion-heading element', function() { + beforeEach(function() { + var tpl = + '' + + '' + + 'Heading Element {{x}} ' + + 'Body' + + '' + + ''; + element = $compile(tpl)(scope); + scope.$digest(); + groups = element.find('.accordion-group'); + }); + it('transcludes the content into the heading link', function() { + expect(findGroupLink(0).text()).toBe('Heading Element 123 '); + }); + it('attaches the same scope to the transcluded heading and body', function() { + expect(findGroupLink(0).find('span').scope().$id).toBe(findGroupBody(0).find('span').scope().$id); + }); + + }); + + describe('accordion-heading, with repeating accordion-groups', function() { + it('should clone the accordion-heading for each group', function() { + element = $compile('{{x}}')(scope); + scope.$digest(); + groups = element.find('.accordion-group'); + expect(groups.length).toBe(3); + expect(findGroupLink(0).text()).toBe('1'); + expect(findGroupLink(1).text()).toBe('2'); + expect(findGroupLink(2).text()).toBe('3'); + }); + }); }); }); diff --git a/template/accordion/accordion-group.html b/template/accordion/accordion-group.html index df308a6d67..85e1a2a51b 100644 --- a/template/accordion/accordion-group.html +++ b/template/accordion/accordion-group.html @@ -1,5 +1,5 @@ \ No newline at end of file