-
Notifications
You must be signed in to change notification settings - Fork 709
Nav Controller #378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Nav Controller #378
Changes from all commits
64b7f99
d35a584
b207c09
1586f52
566d4cf
1ed7989
ccdae04
29f5b11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,23 +12,23 @@ | |
* It uses scrollable areas to avoid scroll issues. In the following figure you can | ||
* see the difference between fixed navbars and navbars with absolute positioning. | ||
* | ||
* <figure class="full-width-figure"> | ||
* <img src="/assets/img/figs/fixed-overflow.png" alt=""/> | ||
* <figure class='full-width-figure'> | ||
* <img src='/assets/img/figs/fixed-overflow.png' alt=''/> | ||
* </figure> | ||
* | ||
* Here is the basic markup to achieve this. | ||
* | ||
* ``` html | ||
* <div class="app"> | ||
* <div class="navbar navbar-app navbar-absolute-top"> | ||
* <div class='app'> | ||
* <div class='navbar navbar-app navbar-absolute-top'> | ||
* <!-- ... --> | ||
* </div> | ||
* | ||
* <div class="navbar navbar-app navbar-absolute-bottom"> | ||
* <div class='navbar navbar-app navbar-absolute-bottom'> | ||
* <!-- ... --> | ||
* </div> | ||
* | ||
* <div class="app-body"> | ||
* <div class='app-body'> | ||
* <ng-view></ng-view> | ||
* </div> | ||
* </div> | ||
|
@@ -53,24 +53,25 @@ | |
* Consider the following example: | ||
* | ||
* ``` html | ||
* <div class="navbar navbar-app navbar-absolute-top"> | ||
* <div class='navbar navbar-app navbar-absolute-top'> | ||
* | ||
* <div class="navbar-brand navbar-brand-center"> | ||
* <div class='navbar-brand navbar-brand-center'> | ||
* Navbar Brand | ||
* </div> | ||
* | ||
* <div class="btn-group pull-left"> | ||
* <div class="btn btn-navbar"> | ||
* <div class='btn-group pull-left'> | ||
* <div class='btn btn-navbar'> | ||
* Left Action | ||
* </div> | ||
* </div> | ||
* | ||
* <div class="btn-group pull-right"> | ||
* <div class="btn btn-navbar"> | ||
* <div class='btn-group pull-right'> | ||
* <div class='btn btn-navbar'> | ||
* Right Action | ||
* </div> | ||
* </div> | ||
* </div> | ||
* | ||
* ``` | ||
* | ||
* `.navbar-brand-center` is a specialization of BS3's `.navbar-brand`. It will | ||
|
@@ -85,48 +86,106 @@ | |
|
||
var module = angular.module('mobile-angular-ui.components.navbars', []); | ||
|
||
/** | ||
* @directive navbarAbsoluteTop | ||
* @restrict C | ||
* @description | ||
* | ||
* Setup absolute positioned top navbar. | ||
* | ||
* ``` html | ||
* <div class="navbar navbar-app navbar-absolute-top"> | ||
* <!-- ... --> | ||
* </div> | ||
* ``` | ||
*/ | ||
var global; | ||
|
||
/** | ||
* @directive navbarAbsoluteBottom | ||
* @restrict C | ||
* @description | ||
* | ||
* Setup absolute positioned bottom navbar. | ||
* | ||
* ``` html | ||
* <div class="navbar navbar-app navbar-absolute-bottom"> | ||
* <!-- ... --> | ||
* </div> | ||
* ``` | ||
*/ | ||
/** | ||
* @directive navbarAbsoluteTop | ||
* @restrict C | ||
* @description | ||
* | ||
* Setup absolute positioned top navbar. | ||
* | ||
* ``` html | ||
* <div class='navbar navbar-app navbar-absolute-top'> | ||
* <!-- ... --> | ||
* </div> | ||
* ``` | ||
*/ | ||
|
||
/** | ||
* @directive navbarAbsoluteBottom | ||
* @restrict C | ||
* @description | ||
* | ||
* Setup absolute positioned bottom navbar. | ||
* | ||
* ``` html | ||
* <div class='navbar navbar-app navbar-absolute-bottom'> | ||
* <!-- ... --> | ||
* </div> | ||
* ``` | ||
*/ | ||
angular.forEach(['top', 'bottom'], function(side) { | ||
var directiveName = 'navbarAbsolute' + side.charAt(0).toUpperCase() + side.slice(1); | ||
module.directive(directiveName, [ | ||
'$rootElement', | ||
function($rootElement) { | ||
return { | ||
restrict: 'C', | ||
link: function(scope) { | ||
controller: function() { | ||
this.registerController = function(name, ctrl) { | ||
this[name] = ctrl; | ||
}; | ||
}, | ||
link: function(scope, elem, attr, ctrl) { | ||
$rootElement.addClass('has-navbar-' + side); | ||
scope.$on('$destroy', function() { | ||
$rootElement.removeClass('has-navbar-' + side); | ||
}); | ||
if (!global) global = ctrl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No one liners without brackets pls, although this one would be a ligit one for conciseness.
I'd favor this form
|
||
global.registerController(side, new (function() { | ||
this.hide = function() { | ||
$rootElement.removeClass('has-navbar-' + side); | ||
elem.addClass('ng-hide'); | ||
}; | ||
this.show = function() { | ||
elem.removeClass('ng-hide'); | ||
$rootElement.addClass('has-navbar-' + side); | ||
}; | ||
this.slideout = function() { | ||
$rootElement.removeClass('has-navbar-' + side); | ||
elem.addClass('ng-hide'); | ||
}; | ||
this.slidein = function() { | ||
elem.removeClass('ng-hide'); | ||
$rootElement.addClass('has-navbar-' + side); | ||
}; | ||
})()); | ||
} | ||
}; | ||
} | ||
]); | ||
}); | ||
|
||
/** | ||
* @directive [hide|show|slidein|slideout][Top|Bottom|Both][Nav] | ||
* @restrict C | ||
* @description | ||
* | ||
* Toggle each(or both) nabar(s) with or without animations | ||
* | ||
* ``` html | ||
* <view class='[hide|show|slidein|slideout]-[top|bottom|both]-[nav]'> | ||
* <!-- ... --> | ||
* </view> | ||
* ``` | ||
*/ | ||
angular.forEach(['Top', 'Bottom', 'Both'], function(nav) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this a directive? I mean, i kinda got that you are invoking the controller while linking on a view element, so perhaps you like to react to page changes ( In that case, but also in general i suggest to re-approach the problem splitting it into 2 distinct phases:
Currently what you achieved with 2 directives could be done with a few css classes. Let's discuss outside the PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I can agree with that.
I don't think this is right though. The styles that fix the navbars are spread among classes at multiple node levels. I didn't really analyze the merit of that approach, because I assumed that there was a good reason for doing it(though I would have preferred if the height of the navbars could have been controlled by the font-size of the the nested copy). So you see in order to "eliminate" the styles at every level the controller has to know of all styles it is responsible for. Now I did, at one time, use a hacky css override like, I am assuming, you suggest. But that, of course, made it unnecessarily cumbersome to switch between states when the view state changes. This is much more versatile. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just remembered how I used to do it. So applying the override, selectively, outside of the |
||
angular.forEach(['hide', 'show', 'slidein', 'slideout'], function(method) { | ||
var name = method + nav + 'Nav'; | ||
module.directive(name, function() { | ||
return { | ||
restrict: 'C', | ||
link: function(scope, elem, attr) { | ||
if (global) | ||
if (nav === 'Both') { | ||
global.bottom[method](); | ||
global.top[method](); | ||
} else | ||
global[nav.toLowerCase()][method](); | ||
} | ||
}; | ||
}); | ||
}); | ||
}); | ||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,15 +21,15 @@ describe('components', function() { | |
|
||
describe('navbarAbsoluteTop', function() { | ||
it('adds class has-navbar-top if navbarAbsoluteTop is present', function() { | ||
let elem = angular.element('<div class="navbar-absolute-top" />'); | ||
let elem = angular.element('<div class="navbar-absolute-top" nav-controller />'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's cheating! :D That kind of coverage is useless, coverage is just a number after all, and unit tests requires isolation to be reliable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ya I didn't think that it would be very useful either. I was just using the On Sep 7, 2016 2:22 PM, "Maurizio Casimirri" notifications@github.com
|
||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).toContain('has-navbar-top'); | ||
}); | ||
|
||
it('removes class has-navbar-top if navbarAbsoluteTop is destroyed', function() { | ||
let elem = angular.element('<div class="navbar-absolute-top" />'); | ||
let elem = angular.element('<div class="navbar-absolute-top" nav-controller />'); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
scope.$destroy(); | ||
|
@@ -39,20 +39,105 @@ describe('components', function() { | |
|
||
describe('navbarAbsoluteBottom', function() { | ||
it('adds class has-navbar-bottom if navbarAbsoluteBottom is present', function() { | ||
let elem = angular.element('<div class="navbar-absolute-bottom" />'); | ||
let elem = angular.element('<div class="navbar-absolute-bottom" nav-controller />'); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).toContain('has-navbar-bottom'); | ||
}); | ||
|
||
it('removes class has-navbar-bottom if navbarAbsoluteBottom is destroyed', function() { | ||
let elem = angular.element('<div class="navbar-absolute-bottom" />'); | ||
let elem = angular.element('<div class="navbar-absolute-bottom" nav-controller />'); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
scope.$destroy(); | ||
expect($rootElement.attr('class')).not.toContain('has-navbar-bottom'); | ||
}); | ||
}); | ||
|
||
describe('hideTopNav', function() { | ||
it('hides the navbarAbsoluteTop when present within the nested view', function() { | ||
let value = '<div><top class="navbar-absolute-top" nav-controller />'; | ||
value += '<ng-view><div class="hide-top-nav"></div></ng-view></div>'; | ||
let elem = angular.element(value); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).not.toContain('has-navbar-top'); | ||
expect(elem.find('top').attr('class')).toContain('ng-hide'); | ||
}); | ||
}); | ||
|
||
describe('hideBottomNav', function() { | ||
it('hides the navbarAbsoluteBottom when present within the nested view', function() { | ||
let value = '<div><bottom class="navbar-absolute-bottom" nav-controller />'; | ||
value += '<ng-view><div class="hide-bottom-nav"></div></ng-view></div>'; | ||
let elem = angular.element(value); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).not.toContain('has-navbar-bottom'); | ||
expect(elem.find('bottom').attr('class')).toContain('ng-hide'); | ||
}); | ||
}); | ||
|
||
describe('slideoutBottomNav', function() { | ||
it('hides the navbarAbsoluteBottom when present within the nested view', function() { | ||
let value = '<div><bottom class="navbar-absolute-bottom" nav-controller />'; | ||
value += '<ng-view><div class="slideout-bottom-nav"></div></ng-view></div>'; | ||
let elem = angular.element(value); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).not.toContain('has-navbar-bottom'); | ||
expect(elem.find('bottom').attr('class')).toContain('ng-hide'); | ||
}); | ||
}); | ||
|
||
describe('slideoutTopNav', function() { | ||
it('hides the navbarAbsoluteTop when present within the nested view', function() { | ||
let value = '<div><top class="navbar-absolute-top" nav-controller />'; | ||
value += '<ng-view><div class="slideout-top-nav"></div></ng-view></div>'; | ||
let elem = angular.element(value); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).not.toContain('has-navbar-top'); | ||
expect(elem.find('top').attr('class')).toContain('ng-hide'); | ||
}); | ||
}); | ||
|
||
describe('hideBothNav', function() { | ||
it('hides both navbarAbsoluteTop && navbarAbsoluteBottom when present within the nested view', function() { | ||
let value = '<div><bottom class="navbar-absolute-bottom" nav-controller />'; | ||
value += '<top class="navbar-absolute-top" nav-controller /><ng-view>'; | ||
value += '<div class="hide-both-nav"></div></ng-view></div>'; | ||
let elem = angular.element(value); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).not.toContain('has-navbar-bottom'); | ||
expect($rootElement.attr('class')).not.toContain('has-navbar-top'); | ||
expect(elem.find('bottom').attr('class')).toContain('ng-hide'); | ||
expect(elem.find('top').attr('class')).toContain('ng-hide'); | ||
}); | ||
}); | ||
|
||
describe('slideoutBothNav', function() { | ||
it('hides both navbarAbsoluteTop && navbarAbsoluteBottom when present within the nested view', function() { | ||
let value = '<div><bottom class="navbar-absolute-bottom" nav-controller />'; | ||
value += '<top class="navbar-absolute-top" nav-controller /><ng-view>'; | ||
value += '<div class="slideout-both-nav"></div></ng-view></div>'; | ||
let elem = angular.element(value); | ||
compile(elem)(scope); | ||
scope.$digest(); | ||
|
||
expect($rootElement.attr('class')).not.toContain('has-navbar-bottom'); | ||
expect($rootElement.attr('class')).not.toContain('has-navbar-top'); | ||
expect(elem.find('bottom').attr('class')).toContain('ng-hide'); | ||
expect(elem.find('top').attr('class')).toContain('ng-hide'); | ||
}); | ||
}); | ||
|
||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's quite too generic to be understood, perhaps a more specific name would be better, also
global
is kind of reserved namespace in node.js, that makes it even more confusing.What is it supposed to hold, why u need a singleton for that?
I've still to read the rest but that looks like a very disruptive approach.
We'll fix it anyway i like your idea of supporting common patterns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not my directive. It was there already.
On Sep 7, 2016 2:28 PM, "Maurizio Casimirri" notifications@github.com
wrote:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its a code review, the comment is bound to a line on the diff. So each comment is specific to one line.
I was referring to
var global
specifically.A name like
var globalNavbarControllerSingleton
would have been better. Long names are not bad, although the usually feel strange.Abbreviations and generic names can be not obvious. Immagine i didn't even know what that line was related to. That may happen to someone editing your code after you.. in order to understand what is
var global
there for he/she should have read and understood all the rest of the code.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh... Ya I didn't like using that particular scope. But if you look at why
it is there either I am missing something important or it is just not
possible another way.
On Sep 7, 2016 3:08 PM, "Maurizio Casimirri" notifications@github.com
wrote: