Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit 2a8f08c

Browse files
committed
Next chapter tutorial code. Making a directive that manipulates the DOM
1 parent c440144 commit 2a8f08c

26 files changed

+864
-0
lines changed

Chapter_ToolTip/categories.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
"Appetizers",
3+
"Salads",
4+
"Soups",
5+
"Main Dishes",
6+
"Side Dishes",
7+
"Desserts"
8+
]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.star-off {
2+
color: #6E6E6E;
3+
}
4+
.star-on {
5+
color: #FACC2E;
6+
}
7+
.stars {
8+
letter-spacing: -2px;
9+
cursor: pointer;
10+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
part of recipe_book;
2+
3+
/* Use the NgComponent annotation to indicate that this class is an
4+
* Angular Component.
5+
*
6+
* The selector field defines the CSS selector that will trigger the
7+
* component. Typically, the CSS selector is an element name.
8+
*
9+
* The templateUrl field tells the component which HTML template to use
10+
* for its view.
11+
*
12+
* The cssUrl field tells the component which CSS file to use.
13+
*
14+
* The publishAs field specifies that the component instance should be
15+
* assigned to the current scope under the name specified.
16+
*
17+
* The map field publishes the list of attributes that can be set on
18+
* the component. Users of this component will specify these attributes
19+
* in the html tag that is used to create the component. For example:
20+
*
21+
* <rating max-rating="5" rating="mycontrol.rating">
22+
*
23+
* The compnoent's public fields are available for data binding from the
24+
* component's view. Similarly, the component's public methods can be
25+
* invoked from the component's view.
26+
*/
27+
@NgComponent(
28+
selector: 'rating',
29+
templateUrl: 'component/rating_component.html',
30+
cssUrl: 'component/rating_component.css',
31+
publishAs: 'ctrl',
32+
map: const {
33+
'max-rating' : '@maxRating',
34+
'rating' : '<=>rating'
35+
}
36+
)
37+
class RatingComponent {
38+
String _starOnChar = "\u2605";
39+
String _starOffChar = "\u2606";
40+
String _starOnClass = "star-on";
41+
String _starOffClass = "star-off";
42+
43+
List<int> stars = [];
44+
45+
int rating;
46+
47+
set maxRating(String value) {
48+
stars = [];
49+
var count = value == null ? 5 : int.parse(value);
50+
for(var i=1; i <= count; i++) {
51+
stars.add(i);
52+
}
53+
}
54+
55+
String starClass(int star) {
56+
return star > rating ? _starOffClass : _starOnClass;
57+
}
58+
59+
String starChar(int star) {
60+
return star > rating ? _starOffChar : _starOnChar;
61+
}
62+
63+
void handleClick(int star) {
64+
if (star == 1 && rating == 1) {
65+
rating = 0;
66+
} else {
67+
rating = star;
68+
}
69+
}
70+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<span class="stars"
2+
ng-if="ctrl.rating != null"
3+
ng-repeat="star in ctrl.stars"
4+
ng-click="ctrl.handleClick(star)"
5+
ng-class="ctrl.starClass(star)">
6+
{{ctrl.starChar(star)}}
7+
</span>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
part of recipe_book;
2+
3+
@NgDirective(
4+
selector: '[tooltip]',
5+
map: const {
6+
'tooltip': '=>displayModel'
7+
}
8+
)
9+
class Tooltip {
10+
// not sure which one I will need.
11+
// ng-click uses node.
12+
// ng-show-hide uses element.
13+
dom.Element element;
14+
dom.Node node;
15+
Scope scope;
16+
TooltipModel displayModel;
17+
18+
dom.Element tooltipElem;
19+
20+
Tooltip(dom.Element this.element, dom.Node this.node,
21+
Scope this.scope) {
22+
23+
element.onMouseEnter.listen((event) {
24+
_createTemplate();
25+
});
26+
27+
element.onMouseLeave.listen((event) {
28+
_destroyTemplate();
29+
});
30+
}
31+
32+
_createTemplate() {
33+
assert(displayModel != null);
34+
35+
tooltipElem = new dom.DivElement();
36+
37+
dom.ImageElement imgElem = new dom.ImageElement();
38+
imgElem.width = displayModel.imgWidth;
39+
imgElem.src = displayModel.imgUrl;
40+
tooltipElem.append(imgElem);
41+
42+
if (displayModel.text != null) {
43+
dom.DivElement textSpan = new dom.DivElement();
44+
textSpan.appendText(displayModel.text);
45+
textSpan.style.color = "white";
46+
textSpan.style.fontSize = "smaller";
47+
textSpan.style.paddingBottom = "5px";
48+
49+
tooltipElem.append(textSpan);
50+
}
51+
52+
tooltipElem.style.padding = "5px";
53+
tooltipElem.style.paddingBottom = "0px";
54+
tooltipElem.style.backgroundColor = "black";
55+
tooltipElem.style.borderRadius = "5px";
56+
tooltipElem.style.width = "${displayModel.imgWidth.toString()}px";
57+
58+
// find the coordinates of the parent DOM element
59+
Rectangle bounds = element.getBoundingClientRect();
60+
int left = (bounds.left + dom.window.pageXOffset).toInt();
61+
int top = (bounds.top + dom.window.pageYOffset).toInt();
62+
int width = (bounds.width).toInt();
63+
int height = (bounds.height).toInt();
64+
65+
// position the tooltip.
66+
// Figure out where the containing element sits in the window.
67+
int tooltipLeft = left + width + 10;
68+
int tooltipTop = top - height;
69+
tooltipElem.style.position = "absolute";
70+
tooltipElem.style.top = "${tooltipTop}px";
71+
tooltipElem.style.left = "${tooltipLeft}px";
72+
73+
// Add the tooltip to the document body. We add it here because
74+
// we need to position it absolutely, without reference to its
75+
// parent element.
76+
dom.document.body.append(tooltipElem);
77+
}
78+
79+
_destroyTemplate() {
80+
tooltipElem.remove();
81+
}
82+
}
83+
84+
class TooltipModel {
85+
String imgUrl;
86+
String text;
87+
int imgWidth;
88+
89+
TooltipModel(String this.imgUrl, String this.text,
90+
int this.imgWidth);
91+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
part of recipe_book;
2+
3+
@NgFilter(name: 'categoryfilter')
4+
class CategoryFilter {
5+
call(recipeList, filterMap) {
6+
if (recipeList is List && filterMap != null && filterMap is Map) {
7+
// If there is nothing checked, treat it as "everything is checked"
8+
bool nothingChecked = filterMap.values.every((isChecked) => !isChecked);
9+
if (nothingChecked) {
10+
return recipeList.toList();
11+
}
12+
return recipeList.where((i) => filterMap[i.category] == true).toList();
13+
}
14+
}
15+
}
16+

Chapter_ToolTip/fonzie.jpg

88.2 KB
Loading

Chapter_ToolTip/index.html

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<!DOCTYPE html>
2+
<html ng-app>
3+
<head>
4+
<title>Chapter Five - A Simple Recipe Book</title>
5+
<link rel="stylesheet" href="style.css">
6+
</head>
7+
<body ng-cloak>
8+
9+
<div recipe-book>
10+
11+
<header id="header">
12+
<h2>Angular is fun! Here's a recipe book to prove it!</h2>
13+
</header>
14+
15+
<div ng-if="!ctrl.recipesLoaded || !ctrl.categoriesLoaded">
16+
{{ctrl.message}}
17+
</div>
18+
19+
<div ng-if="ctrl.recipesLoaded && ctrl.categoriesLoaded">
20+
<nav id="controls">
21+
<search-recipe
22+
name-filter-string="ctrl.nameFilter"
23+
category-filter-map="ctrl.categoryFilterMap">
24+
</search-recipe>
25+
26+
<a href="#/add"><input type="button" value="Add Recipe"></a><br/>
27+
</nav>
28+
29+
<nav id="search-results">
30+
<div id="recipe-list">
31+
<ul>
32+
<li ng-repeat="recipe in ctrl.allRecipes | orderBy:'name' | filter:{name:ctrl.nameFilter} | categoryfilter:ctrl.categoryFilterMap">
33+
<span tooltip="ctrl.tooltipForRecipe(recipe)">
34+
<rating max-rating="5" rating="recipe.rating"></rating>
35+
<a class="extra-space"
36+
href="#/recipe/{{recipe.id}}/view">{{recipe.name}}</a>
37+
</span>
38+
</li>
39+
</ul>
40+
</div>
41+
</nav>
42+
43+
<section id="details">
44+
<ng-view></ng-view>
45+
</section>
46+
47+
</div>
48+
49+
</div>
50+
51+
<script type="application/dart" src="main.dart"></script>
52+
<script src="packages/browser/dart.js"></script>
53+
</body>
54+
</html>

Chapter_ToolTip/karma.conf.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module.exports = function(config) {
2+
config.set({
3+
basePath: '.',
4+
frameworks: ['dart-unittest'],
5+
6+
// list of files / patterns to load in the browser
7+
files: [
8+
'main_test.dart',
9+
{pattern: '**/*.dart', watched: false, included: false, served: true},
10+
{pattern: 'packages/browser/dart.js', watched: false, included: true, served: true},
11+
{pattern: 'packages/browser/interop.js', watched: false, included: true, served: true},
12+
],
13+
14+
autoWatch: false,
15+
16+
plugins: [
17+
'karma-dart',
18+
'karma-chrome-launcher'
19+
]
20+
});
21+
};

0 commit comments

Comments
 (0)