Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit c78f1ee

Browse files
committed
docs(app): refactor the Docs App based on the MD prototype
I incorporated the prototype detailed in gkalpak#3. Things that are different from the prototype (besides using actual data): * The left sidenav (toc) is not styled properly (or even readably). * The subheaders in the left sidenav are not "stickying" properly (only `ng` becomes sticky). * Icons are missing (since we are not using FontAwesome). E.g. search-fab, toc-toggle, results * In the right sidenav (search) there are some unwanted horizontal scrollbars. (This section probably needs rethinking anyway.) * I have implemented a `responsiveMenu` directive to show the options in the header-menus (Learn/Develop/Discuss). The purpose is to show the options in a "dropdown-ish" menu on larger screens and using a BottomSheet on smaller. At the moment a BottomSheet is used on every screen-size. Notes: - Still no version-picker and breadcrumbs (I have left the original implementation of those two commented out). - I have replaced the previous docs.css with a new one containing the style of the prototype. I have renamed the old one to `docs_old.css` and left it there temporarily for quick reference. We need to clean up this and the rest of the old CSS files. - The main content area is totally unstyled and needs some love (a lot actually). I have also "sprinkled" the code with a few more TODOs/FIXMEs. (For more details on known issues and missing features take a look at gkalpak#3)
1 parent 5da8d46 commit c78f1ee

File tree

14 files changed

+1390
-915
lines changed

14 files changed

+1390
-915
lines changed

Diff for: docs/app/assets/css/docs.css

+103-637
Large diffs are not rendered by default.

Diff for: docs/app/assets/css/docs_old.css

+696
Large diffs are not rendered by default.

Diff for: docs/app/src/app.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use strict';
22

33
angular.module('docsApp', [
4-
'ngRoute',
5-
'ngCookies',
6-
'ngSanitize',
7-
'ngAnimate',
4+
'ngMaterial',
5+
'HeaderController',
6+
'FooterController',
87
'DocsController',
8+
'ViewUtils',
99
'versionsData',
1010
'pagesData',
1111
'navData',
@@ -15,8 +15,7 @@ angular.module('docsApp', [
1515
'search',
1616
'tutorials',
1717
'versions',
18-
'bootstrap',
19-
'ui.bootstrap.dropdown'
18+
'responsiveMenu'
2019
])
2120

2221
.config(['$locationProvider', function($locationProvider) {

Diff for: docs/app/src/directives.js

+22-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
angular.module('directives', [])
22

33
/**
4-
* backToTop Directive
5-
* @param {Function} $anchorScroll
4+
* scrollTo Directive
65
*
7-
* @description Ensure that the browser scrolls when the anchor is clicked
6+
* @description
7+
* Upon click, scroll to the target element (identified by the selector provided via the `scroll-to`
8+
* attribute).
89
*/
9-
.directive('backToTop', ['$anchorScroll', '$location', function($anchorScroll, $location) {
10-
return function link(scope, element) {
11-
element.on('click', function(event) {
12-
$location.hash('');
13-
$anchorScroll();
14-
});
10+
.directive('scrollTo', ['$document', '$location', function($document, $location) {
11+
var doc = $document[0];
12+
13+
return {
14+
restrict: 'A',
15+
link: function scrollToPostLink(scope, elem, attrs) {
16+
elem.on('click', onClick);
17+
18+
function onClick() {
19+
var targetSelector = attrs.scrollTo;
20+
var targetElem = doc.querySelector(targetSelector);
21+
22+
if (targetElem) {
23+
targetElem.scrollIntoView();
24+
}
25+
}
26+
}
1527
};
1628
}])
1729

@@ -30,6 +42,7 @@ angular.module('directives', [])
3042
};
3143
}])
3244

45+
3346
.directive('scrollYOffsetElement', ['$anchorScroll', function($anchorScroll) {
3447
return function(scope, element) {
3548
$anchorScroll.yOffset = element;

Diff for: docs/app/src/docs.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
angular.module('DocsController', [])
1+
angular.module('DocsController', ['ViewUtils'])
22

33
.controller('DocsController', [
4-
'$scope', '$rootScope', '$location', '$window', '$cookies', 'openPlunkr',
4+
'$scope', '$rootScope', '$location', '$window', 'openPlunkr', 'ViewUtils',
55
'NG_PAGES', 'NG_NAVIGATION', 'NG_VERSION',
6-
function($scope, $rootScope, $location, $window, $cookies, openPlunkr,
6+
function($scope, $rootScope, $location, $window, openPlunkr, ViewUtils,
77
NG_PAGES, NG_NAVIGATION, NG_VERSION) {
88

9+
$scope.vu = ViewUtils;
10+
911
$scope.openPlunkr = openPlunkr;
1012

1113
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
@@ -53,8 +55,6 @@ angular.module('DocsController', [])
5355
Initialize
5456
***********************************/
5557

56-
$scope.versionNumber = angular.version.full;
57-
$scope.version = angular.version.full + " " + angular.version.codeName;
5858
$scope.loading = 0;
5959

6060

Diff for: docs/app/src/footer-conroller.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
angular.
2+
module('FooterController', []).
3+
controller('FooterController', FooterController);
4+
5+
FooterController.$inject = [];
6+
function FooterController() {
7+
var v = angular.version;
8+
this.versionNumber = v.full;
9+
this.version = v.full + ' ' + v.codeName;
10+
}

Diff for: docs/app/src/header-conroller.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
angular.
2+
module('HeaderController', []).
3+
controller('HeaderController', HeaderController);
4+
5+
HeaderController.$inject = [];
6+
function HeaderController() {
7+
this.learnItems = [
8+
{label: 'Why AngularJS?', url: '//angularjs.org/'},
9+
{label: 'Watch', url: '//www.youtube.com/user/angularjs'},
10+
{label: 'Tutorial', url: 'tutorial'},
11+
{label: 'Case Studies', url: '//builtwith.angularjs.org/'},
12+
{label: 'Seed App project template', url: '//github.com/angular/angular-seed'},
13+
{label: 'FAQ', url: 'misc/faq'}
14+
];
15+
16+
this.developItems = [
17+
{label: 'Why AngularJS?', url: '//angularjs.org/'},
18+
{label: 'Tutorial', url: 'tutorial'},
19+
{label: 'Developer Guide', url: 'guide'},
20+
{label: 'API Reference', url: 'api'},
21+
{label: 'Error Reference', url: 'error'},
22+
{label: 'Contribute', url: 'misc/contribute'},
23+
{label: 'Download', url: '//code.angularjs.org/'}
24+
];
25+
26+
this.discussItems = [
27+
{label: 'Blog', url: '//blog.angularjs.org'},
28+
{label: 'Mailing List', url: '//groups.google.com/group/angular'},
29+
{label: 'Chat Room', url: '//webchat.freenode.net/?channels=angularjs&uio=d4'},
30+
{label: 'Twitter', url: '//twitter.com/#!/angularjs'},
31+
{label: 'Google+', url: '//plus.google.com/110323587230527980117'},
32+
{label: 'GitHub', url: '//github.com/angular/angular.js'},
33+
{label: 'Issue Tracker', url: '//github.com/angular/angular.js/issues'},
34+
];
35+
}

Diff for: docs/app/src/responsive-menu.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
angular.
2+
module('responsiveMenu', ['ngMaterial', 'ViewUtils']).
3+
directive('responsiveMenu', responsiveMenuDirective);
4+
5+
responsiveMenuDirective.$inject = ['$mdBottomSheet', 'ViewUtils'];
6+
function responsiveMenuDirective($mdBottomSheet, ViewUtils) {
7+
// TODO: Create showFns for various sizes (not necessarily all)
8+
var showFns = {
9+
// 'gt-lg': '',
10+
// 'lg': '',
11+
// 'md': '',
12+
'sm': function showSmFn(items) {
13+
$mdBottomSheet.show({
14+
template: _getResponsiveMenuSmTemplate(),
15+
controller: ['$mdBottomSheet', '$scope',
16+
function ResponsiveMenuSmController($mdBottomSheet, $scope) {
17+
$scope.items = items;
18+
$scope.onItemClick = $mdBottomSheet.hide.bind($mdBottomSheet);
19+
}
20+
]
21+
});
22+
}
23+
};
24+
25+
var defaultShowFn = showFns.sm;
26+
27+
return {
28+
restrict: 'A',
29+
scope: {
30+
items: '=rmItems'
31+
},
32+
controller: ['$element', '$scope', function ResponsiveMenuController($element, $scope) {
33+
$element.on('click', onClick.bind(this));
34+
35+
function onClick(evt) {
36+
var showFn = ViewUtils.getValueForSize(showFns, defaultShowFn);
37+
showFn($scope.items);
38+
}
39+
}]
40+
};
41+
}
42+
43+
function _getResponsiveMenuSmTemplate() {
44+
return [
45+
'<md-bottom-sheet>',
46+
' <md-list>',
47+
' <md-item ng-repeat="item in items">',
48+
' <md-button aria-label="{{item.label}}" ng-click="onItemClick(item)">',
49+
' <a ng-href="{{item.url}}">{{item.label}}</a>',
50+
' </md-button>',
51+
' </md-item>',
52+
' </md-list>',
53+
'</md-bottom-sheet>',
54+
''].join('\n');
55+
}

Diff for: docs/app/src/search.js

+90-68
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,84 @@
1-
angular.module('search', [])
1+
angular.module('search', ['ViewUtils'])
22

3-
.controller('DocsSearchCtrl', ['$scope', '$location', 'docsSearch', function($scope, $location, docsSearch) {
4-
function clearResults() {
5-
$scope.results = [];
6-
$scope.colClassName = null;
7-
$scope.hasResults = false;
8-
}
3+
.controller('DocsSearchController', ['$scope', '$location', 'docsSearch', 'ViewUtils',
4+
function($scope, $location, docsSearch, ViewUtils) {
5+
$scope.hideResults = hideResults;
6+
$scope.search = search;
7+
$scope.submit = submit;
98

10-
$scope.search = function(q) {
11-
var MIN_SEARCH_LENGTH = 2;
12-
if(q.length >= MIN_SEARCH_LENGTH) {
13-
docsSearch(q).then(function(hits) {
14-
var results = {};
15-
angular.forEach(hits, function(hit) {
16-
var area = hit.area;
9+
// TODO: Probably use some event on the input field, when
10+
// https://github.com/angular/material/pull/848 is resolved
11+
$scope.$watch('q', search);
1712

18-
var limit = (area === 'api') ? 40 : 14;
19-
results[area] = results[area] || [];
20-
if(results[area].length < limit) {
21-
results[area].push(hit);
22-
}
23-
});
13+
clearResults();
2414

25-
var totalAreas = Object.keys(results).length;
26-
if(totalAreas > 0) {
27-
$scope.colClassName = 'cols-' + totalAreas;
28-
}
29-
$scope.hasResults = totalAreas > 0;
30-
$scope.results = results;
31-
});
32-
} else {
33-
clearResults();
15+
function clearResults() {
16+
$scope.results = {};
17+
$scope.colClassName = null;
18+
$scope.hasResults = false;
3419
}
35-
if(!$scope.$$phase) $scope.$apply();
36-
};
3720

38-
$scope.submit = function() {
39-
var result;
40-
if ($scope.results.api) {
41-
result = $scope.results.api[0];
42-
} else {
43-
for(var i in $scope.results) {
44-
result = $scope.results[i][0];
45-
if(result) {
46-
break;
47-
}
21+
function hideResults(path) {
22+
ViewUtils.closeSidenav('search');
23+
clearResults();
24+
$scope.q = '';
25+
26+
if (arguments.length) {
27+
$location.path(path);
4828
}
4929
}
50-
if(result) {
51-
$location.path(result.path);
52-
$scope.hideResults();
30+
31+
function search(q) {
32+
var MIN_SEARCH_LENGTH = 2;
33+
q = q || '';
34+
35+
if (q.length >= MIN_SEARCH_LENGTH) {
36+
docsSearch(q).then(function(hits) {
37+
var results = {};
38+
angular.forEach(hits, function(hit) {
39+
var area = hit.area;
40+
41+
var limit = (area === 'api') ? 40 : 14;
42+
results[area] = results[area] || [];
43+
if(results[area].length < limit) {
44+
results[area].push(hit);
45+
}
46+
});
47+
48+
var totalAreas = Object.keys(results).length;
49+
if (totalAreas > 0) {
50+
// TODO: Use `colClassName` or remove it
51+
$scope.colClassName = 'cols-' + totalAreas;
52+
}
53+
$scope.hasResults = totalAreas > 0;
54+
$scope.results = results;
55+
});
56+
} else {
57+
clearResults();
58+
}
59+
60+
// FIXME: Don't use private `$$phase` property
61+
if (!$scope.$$phase) $scope.$apply();
5362
}
54-
};
5563

56-
$scope.hideResults = function() {
57-
clearResults();
58-
$scope.q = '';
59-
};
60-
}])
64+
function submit() {
65+
var result;
66+
67+
if ($scope.results.api) {
68+
result = $scope.results.api[0];
69+
} else {
70+
Object.keys($scope.results).some(function(key) {
71+
return (result = $scope.results[key][0]);
72+
});
73+
}
74+
75+
if (result) {
76+
$location.path(result.path);
77+
$scope.hideResults();
78+
}
79+
}
80+
}
81+
])
6182

6283

6384
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch',
@@ -173,24 +194,25 @@ angular.module('search', [])
173194
};
174195
})
175196

176-
.directive('focused', function($timeout) {
177-
return function(scope, element, attrs) {
178-
element[0].focus();
179-
element.on('focus', function() {
180-
scope.$apply(attrs.focused + '=true');
181-
});
182-
element.on('blur', function() {
183-
// have to use $timeout, so that we close the drop-down after the user clicks,
184-
// otherwise when the user clicks we process the closing before we process the click.
185-
$timeout(function() {
186-
scope.$eval(attrs.focused + '=false');
187-
});
188-
});
189-
// TODO(gkalpak): Do we need this if we first register the listeners
190-
// and the call `.focus()` ?
191-
scope.$eval(attrs.focused + '=true');
192-
};
193-
})
197+
// TODO: Do we need this ?
198+
// .directive('focused', function($timeout) {
199+
// return function(scope, element, attrs) {
200+
// element[0].focus();
201+
// element.on('focus', function() {
202+
// scope.$apply(attrs.focused + '=true');
203+
// });
204+
// element.on('blur', function() {
205+
// // have to use $timeout, so that we close the drop-down after the user clicks,
206+
// // otherwise when the user clicks we process the closing before we process the click.
207+
// $timeout(function() {
208+
// scope.$eval(attrs.focused + '=false');
209+
// });
210+
// });
211+
// // TODO(gkalpak): Do we need this if we first register the listeners
212+
// // and the call `.focus()` ?
213+
// scope.$eval(attrs.focused + '=true');
214+
// };
215+
// })
194216

195217
.directive('docsSearchInput', ['$document', function($document) {
196218
var doc = $document[0];

0 commit comments

Comments
 (0)