├── LICENSE ├── Lesson01 ├── 00_test_angular.html ├── 00a_test_bootstrap.html ├── 01_first_app.html ├── 02_sample_app_1.html ├── 02a_sample_app_1.html ├── angular-route.js ├── angular.min.js ├── bootstrap.min.js ├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ └── bootstrap.min.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── jquery.js └── js │ └── bootstrap.js ├── Lesson02 ├── 01_ng_repeat.html ├── 02_ng_repeat_objects.html ├── 03_objects.html ├── 04_filter1.html ├── 05_filter2.html ├── 06_filter_binding.html ├── 08_prettied_up.html ├── 08a_title_only.html ├── angular.min.js ├── bootstrap.min.js ├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ └── bootstrap.min.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── jquery.min.js ├── jquery.min.map └── js │ └── bootstrap.js ├── Lesson03 ├── 01_controller.css ├── 01_controller.html ├── 02_creation_paradigms.js ├── 03_add_album.css ├── 03_add_album.html ├── 03a_add_album.css ├── 03a_add_album.html ├── 04_validation.html ├── 05_validation.css ├── 05_validation.html ├── 06_validation.css ├── 06_validation.html ├── 07_multi_controllers_example.html ├── 08_multi_controllers.css ├── 08_multi_controllers.html ├── 08_user_partial.html ├── angular.min.js ├── bootstrap.min.js ├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ └── bootstrap.min.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── jquery.min.js ├── jquery.min.map └── js │ └── bootstrap.js ├── Lesson04 ├── 03_folders │ ├── app │ │ ├── app.js │ │ ├── controllers │ │ │ └── albumlistcontroller.js │ │ └── partials │ │ │ └── album_list.html │ ├── css │ │ ├── app.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── index.html │ └── js │ │ ├── angular-route.js │ │ ├── angular.min.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── jquery.min.js ├── 04_album_view │ ├── app │ │ ├── app.js │ │ ├── controllers │ │ │ ├── albumlistcontroller.js │ │ │ ├── albumviewercontroller.js │ │ │ └── photoviewercontroller.js │ │ └── partials │ │ │ ├── album_list.html │ │ │ ├── album_viewer.html │ │ │ └── photo_viewer.html │ ├── css │ │ ├── app.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── index.html │ └── js │ │ ├── angular-route.js │ │ ├── angular.min.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── jquery.min.js └── parts01_and_02 │ ├── 01_my_first_module.css │ ├── 01_my_first_module.html │ ├── 02_album_list_partial.html │ ├── 02_routes.css │ ├── 02_routes.html │ ├── angular-route.js │ ├── angular.min.js │ ├── bootstrap.min.js │ ├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ └── bootstrap.min.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ ├── jquery.min.js │ ├── jquery.min.map │ └── js │ └── bootstrap.js ├── Lesson05 ├── 01_services │ ├── app │ │ ├── app.js │ │ ├── controllers │ │ │ ├── albumlistcontroller.js │ │ │ ├── albumviewercontroller.js │ │ │ └── photoviewercontroller.js │ │ ├── partials │ │ │ ├── album_list.html │ │ │ ├── album_viewer.html │ │ │ └── photo_viewer.html │ │ └── services │ │ │ └── albumprovider.js │ ├── css │ │ ├── app.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── index.html │ └── js │ │ ├── angular-route.js │ │ ├── angular.min.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── jquery.min.js ├── 02_factories │ ├── app │ │ ├── app.js │ │ ├── controllers │ │ │ ├── albumlistcontroller.js │ │ │ ├── albumviewercontroller.js │ │ │ └── photoviewercontroller.js │ │ ├── partials │ │ │ ├── album_list.html │ │ │ ├── album_viewer.html │ │ │ └── photo_viewer.html │ │ └── services │ │ │ └── albumprovider.js │ ├── css │ │ ├── app.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── index.html │ └── js │ │ ├── angular-route.js │ │ ├── angular.min.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── jquery.min.js ├── 03_useful_factories.js ├── 04_remote_data │ ├── back │ │ ├── index.js │ │ ├── package.json │ │ └── photo_albums.json │ └── front │ │ ├── app │ │ ├── app.js │ │ ├── controllers │ │ │ ├── albumlistcontroller.js │ │ │ ├── albumviewercontroller.js │ │ │ └── photoviewercontroller.js │ │ ├── partials │ │ │ ├── album_list.html │ │ │ ├── album_viewer.html │ │ │ └── photo_viewer.html │ │ └── services │ │ │ ├── albumprovider.js │ │ │ └── configprops.js │ │ ├── css │ │ ├── app.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ │ ├── index.html │ │ └── js │ │ ├── angular-route.js │ │ ├── angular.min.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── jquery.min.js └── 05_uploads │ ├── back │ ├── index.js │ ├── package.json │ └── photo_albums.json │ └── front │ ├── app │ ├── app.js │ ├── controllers │ │ ├── albumlistcontroller.js │ │ ├── albumuploadcontroller.js │ │ ├── albumviewercontroller.js │ │ └── photoviewercontroller.js │ ├── partials │ │ ├── album_list.html │ │ ├── album_uploader.html │ │ ├── album_viewer.html │ │ └── photo_viewer.html │ └── services │ │ ├── albumprovider.js │ │ └── configprops.js │ ├── css │ ├── app.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ └── bootstrap.min.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ ├── index.html │ └── js │ ├── angular-file-upload.js │ ├── angular-route.js │ ├── angular.min.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ └── jquery.min.js ├── Lesson06 └── filters_directives │ ├── back │ ├── index.js │ ├── package.json │ └── photo_albums.json │ └── front │ ├── app │ ├── app.js │ ├── controllers │ │ ├── albumlistcontroller.js │ │ ├── albumuploadcontroller.js │ │ ├── albumviewercontroller.js │ │ └── photoviewercontroller.js │ ├── partials │ │ ├── album_list.html │ │ ├── album_uploader.html │ │ ├── album_viewer.html │ │ └── photo_viewer.html │ └── services │ │ ├── albumprovider.js │ │ └── configprops.js │ ├── css │ ├── app.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ └── bootstrap.min.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ ├── index.html │ └── js │ ├── angular-file-upload.js │ ├── angular-route.js │ ├── angular.min.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ └── jquery.min.js ├── Lesson07 ├── 01_cleaning_up │ ├── LICENSE │ ├── README.md │ ├── back │ │ ├── index.js │ │ ├── package.json │ │ └── photo_albums.json │ └── front │ │ ├── app │ │ ├── app.js │ │ ├── controllers │ │ │ ├── albumlistcontroller.js │ │ │ ├── albumuploadcontroller.js │ │ │ ├── albumviewcontroller.js │ │ │ └── photoviewcontroller.js │ │ ├── partials │ │ │ ├── .#album_uploader.html │ │ │ ├── album_list_partial.html │ │ │ ├── album_uploader.html │ │ │ ├── album_view_partial.html │ │ │ ├── pa-album-directive.html │ │ │ └── photo_view.html │ │ └── services │ │ │ └── albumservice.js │ │ ├── css │ │ ├── app.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ │ ├── index.html │ │ └── js │ │ ├── angular-animate.js │ │ ├── angular-cookies.js │ │ ├── angular-file-upload.js │ │ ├── angular-route.min.js │ │ ├── angular-route.min.js.map │ │ ├── angular.min.js │ │ ├── bootstrap.min.js │ │ ├── jquery.js │ │ └── ui-bootstrap-tpls-0.10.0.min.js └── 02_testing │ ├── LICENSE │ ├── README.md │ ├── back │ ├── index.js │ ├── package.json │ └── photo_albums.json │ └── front │ ├── app │ ├── app.js │ ├── controllers │ │ ├── albumlistcontroller.js │ │ ├── albumuploadcontroller.js │ │ ├── albumviewcontroller.js │ │ └── photoviewcontroller.js │ ├── partials │ │ ├── .#album_uploader.html │ │ ├── album_list_partial.html │ │ ├── album_uploader.html │ │ ├── album_view_partial.html │ │ ├── pa-album-directive.html │ │ └── photo_view.html │ └── services │ │ └── albumservice.js │ ├── css │ ├── app.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ └── bootstrap.min.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ ├── index.html │ ├── js │ ├── angular-animate.js │ ├── angular-cookies.js │ ├── angular-file-upload.js │ ├── angular-route.min.js │ ├── angular-route.min.js.map │ ├── angular.min.js │ ├── bootstrap.min.js │ ├── jquery.js │ └── ui-bootstrap-tpls-0.10.0.min.js │ └── tests │ ├── albumlistcontroller.tests.js │ ├── angular-mocks.js │ └── test.config.js └── README.md /Lesson01/00_test_angular.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Everybody wanna shout "{{ "Hello World" }}" 7 | 8 | 9 | -------------------------------------------------------------------------------- /Lesson01/00a_test_bootstrap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | Everybody wanna shout "{{ "Hello World" }}" 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Lesson01/01_first_app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |

11 | Everybody wanna shout "{{ messageText | uppercase }}" 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Lesson01/02_sample_app_1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 |

Filter list:

15 | 16 | 19 |

There are {{ albums.length }} albums so far!

20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Lesson01/02a_sample_app_1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 |
16 |
{{ album.name }} ({{ album.date }})
17 |
18 | {{ album.description }} 19 |
20 |
21 |
22 |

There are {{ albums.length }} albums so far!

23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Lesson01/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson01/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson01/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson01/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson01/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson01/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson02/01_ng_repeat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Lesson02/02_ng_repeat_objects.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 |

There are {{albums.length}} albums so far!

16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Lesson02/03_objects.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 |
{{key}} {{value}}
25 |
26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Lesson02/04_filter1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 |

There are {{albums.length}} albums so far!

16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Lesson02/05_filter2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 |

There are {{albums.length}} albums so far!

16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Lesson02/06_filter_binding.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | {{ searchFor }} 17 | 18 |

There are {{albums.length}} albums so far!

19 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Lesson02/08_prettied_up.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 |

16 | 17 |

18 | 19 |
20 |
{{ album.title }}
{{ album.date }}
21 |
22 | {{ album.description }} 23 |
24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Lesson02/08a_title_only.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 |

16 | 17 |

18 | 19 |
20 |
{{ album.title }}
{{ album.date }}
21 |
22 | {{ album.description }} 23 |
24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Lesson02/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson02/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson02/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson02/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson02/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson02/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson03/01_controller.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .album { 12 | width: 300px; 13 | float: left; 14 | margin-right: 10px; 15 | } 16 | 17 | div.album div.title { 18 | float: right; 19 | } -------------------------------------------------------------------------------- /Lesson03/01_controller.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 | 16 |
17 |
{{ album.title }}
{{ album.date }}
18 |
19 | {{ album.description }} 20 |
21 |
22 | 23 | 24 | 25 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Lesson03/02_creation_paradigms.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function ObjectClass () { 4 | 5 | this.net_connection = NetConnection.create(); 6 | 7 | } 8 | 9 | 10 | 11 | function ObjectClass () { 12 | 13 | var factory = _g_serviceFactory.getFactory(); 14 | 15 | this.net_connection = factory.get(TYPE.NetConnection); 16 | 17 | } 18 | 19 | 20 | function ObjectClass ($net_connection) { 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Lesson03/03_add_album.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | textarea { 12 | padding: 3px; 13 | border-radius: 5px; 14 | border: 1px solid #bbb; 15 | } 16 | 17 | .album { 18 | width: 300px; 19 | float: left; 20 | margin-right: 10px; 21 | } 22 | 23 | div.album div.title { 24 | float: right; 25 | } -------------------------------------------------------------------------------- /Lesson03/03_add_album.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 | 16 |
17 |
{{ album.title }}
{{ album.date }}
18 |
19 | {{ album.description }} 20 |
21 |
22 | 23 |
24 | 25 |

Add new album

26 |
27 |
28 |
29 | 30 |
31 | 32 |
33 |
34 |
35 |

36 | 37 |

38 |

39 | 40 |

41 | 42 |
43 |
44 |
45 | 46 | 47 | 48 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Lesson03/03a_add_album.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | textarea { 12 | padding: 3px; 13 | border-radius: 5px; 14 | border: 1px solid #bbb; 15 | } 16 | 17 | .album { 18 | width: 300px; 19 | float: left; 20 | margin-right: 10px; 21 | } 22 | 23 | div.album div.title { 24 | float: right; 25 | } -------------------------------------------------------------------------------- /Lesson03/03a_add_album.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 | 16 |
17 |
{{ album.title }}
{{ album.date }}
18 |
19 | {{ album.description }} 20 |
21 |
22 | 23 |
24 | 25 |

Add new album

26 |
27 |
28 | 29 |
30 | 31 |
32 |
33 |
34 |

35 | 36 |

37 |

38 | 39 |

40 | 41 |
42 |
43 | 44 | 45 | 46 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Lesson03/04_validation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Lesson03/05_validation.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } -------------------------------------------------------------------------------- /Lesson03/05_validation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 | 16 |
17 |
{{ album.title }}
{{ album.date }}
18 |
19 | {{ album.description }} 20 |
21 |
22 | 23 |
24 | 25 |

Add new album

26 |
27 |
{{add_error_text}}
28 |
29 |
30 | 31 |
32 | 35 |
36 |
37 |
38 |

39 | 40 |

41 |

42 | 49 |

50 | 51 |
52 |
53 |
54 | 55 | 56 | 57 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Lesson03/06_validation.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } -------------------------------------------------------------------------------- /Lesson03/06_validation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 | 16 |
17 |
{{ album.title }}
{{ album.date }}
18 |
19 | {{ album.description }} 20 |
21 |
22 | 23 |
24 | 25 |

Add new album

26 |
27 |
{{add_error_text}}
28 |
29 |
30 | 31 |
32 | 35 |
36 |
37 |
38 |

39 | 40 |

41 |

42 | 49 |

50 | 51 |
52 |
53 |
54 | 55 | 56 | 57 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Lesson03/07_multi_controllers_example.html: -------------------------------------------------------------------------------- 1 |
2 | Logged in {{ user.Logged_IN }} 3 | User Name {{ user.name }} 4 | etc 5 |
6 |
7 | etc 8 |
9 | 10 | -------------------------------------------------------------------------------- /Lesson03/08_multi_controllers.css: -------------------------------------------------------------------------------- 1 | body { 2 | 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | 22 | div#album_list { 23 | padding: 50px; 24 | } 25 | 26 | 27 | .album { 28 | width: 300px; 29 | float: left; 30 | margin-right: 10px; 31 | } 32 | 33 | div.album div.title { 34 | float: right; 35 | } -------------------------------------------------------------------------------- /Lesson03/08_user_partial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | Logged in as: {{ user.username }} 5 |
6 | 7 | 8 | -------------------------------------------------------------------------------- /Lesson03/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson03/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson03/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson03/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson03/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson03/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson04/03_folders/app/app.js: -------------------------------------------------------------------------------- 1 | var photoApp = angular.module("photoSharingApp", [ "ngRoute" ]); 2 | 3 | photoApp.config(function ($routeProvider) { 4 | $routeProvider 5 | .when("/albums", { controller: "AlbumListController", templateUrl: "/app/partials/album_list.html" }) 6 | .when("/", { redirectTo: "/albums" }) 7 | .otherwise({ redirectTo: "/404_page" }); 8 | }); 9 | 10 | -------------------------------------------------------------------------------- /Lesson04/03_folders/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumListController ($scope) { 4 | 5 | $scope.new_album = {}; 6 | $scope.add_error_text = ''; 7 | 8 | $scope.albums = [ 9 | { name: 'madrid1309', title: 'Weekend in Madrid', date: '2013-09-01', description: 'My favourite trip' }, 10 | { name: 'iceland1404', title: 'Holiday in Iceland', date: '2014-04-15', description: 'This place is cold' }, 11 | { name: 'thailand1210', title: 'Surfing in Thailand', date: '2012-10-01', description: 'So hot!' }, 12 | { name: 'australia1207', title: 'Wedding in Australia', date: '2012-07-31', description: 'So many kangaroos and koalas!' } 13 | ]; 14 | 15 | $scope.addAlbum = function (album_data) { 16 | if (!album_data.title) 17 | $scope.add_error_text = "Missing title"; 18 | else if (!album_data.date) 19 | $scope.add_error_text = "You must specify a date (yyyy/mm/dd)"; 20 | else if (!album_data.description) 21 | $scope.add_error_text = "Missing description"; 22 | else if (!album_data.name) 23 | $scope.add_error_text = "Short album name must be at least 6 chars (ironic, yes)"; 24 | else { 25 | try { 26 | var d = new Date(album_data.date.trim()); 27 | if (isNaN(d.getTime())) throw new Error("invalid date"); 28 | // if we made it here the date is good 29 | $scope.albums.push(album_data); 30 | $scope.new_album = {}; 31 | $scope.add_error_text = ''; 32 | } catch (e) { 33 | $scope.add_error_text = "You must specify a valid date (yyyy/mm/dd)"; 34 | } 35 | } 36 | }; 37 | } 38 | 39 | photoApp.controller("AlbumListController", AlbumListController); 40 | 41 | })(); 42 | -------------------------------------------------------------------------------- /Lesson04/03_folders/app/partials/album_list.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 |
{{ album.title }}
{{ album.date }}
7 |
8 | {{ album.description }} 9 |
10 |
11 | 12 |
13 | 14 |

Add new album

15 |
16 |
{{add_error_text}}
17 |
18 |
19 | 20 |
21 | 24 |
25 |
26 |
27 |

28 | 29 |

30 |

31 | 38 |

39 | 40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /Lesson04/03_folders/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } -------------------------------------------------------------------------------- /Lesson04/03_folders/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/03_folders/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson04/03_folders/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/03_folders/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson04/03_folders/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/03_folders/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson04/03_folders/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/app/app.js: -------------------------------------------------------------------------------- 1 | var photoApp = angular.module("photoSharingApp", [ "ngRoute" ]); 2 | 3 | photoApp.config(function ($routeProvider) { 4 | $routeProvider 5 | .when("/albums", { controller: "AlbumListController", templateUrl: "/app/partials/album_list.html" }) 6 | .when("/album/:album_name", { controller: "AlbumViewerController", templateUrl: "/app/partials/album_viewer.html" }) 7 | .when("/album/:album_name/photos/:photo_filename", { controller: "PhotoViewerController", templateUrl: "/app/partials/photo_viewer.html" }) 8 | .when("/", { redirectTo: "/albums" }) 9 | .otherwise({ redirectTo: "/404_page" }); 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumListController ($scope) { 4 | 5 | $scope.new_album = {}; 6 | $scope.add_error_text = ''; 7 | 8 | $scope.albums = [ 9 | { name: 'madrid1309', title: 'Weekend in Madrid', date: '2013-09-01', description: 'My favourite trip' }, 10 | { name: 'iceland1404', title: 'Holiday in Iceland', date: '2014-04-15', description: 'This place is cold' }, 11 | { name: 'thailand1210', title: 'Surfing in Thailand', date: '2012-10-01', description: 'So hot!' }, 12 | { name: 'australia1207', title: 'Wedding in Australia', date: '2012-07-31', description: 'So many kangaroos and koalas!' } 13 | ]; 14 | 15 | $scope.addAlbum = function (album_data) { 16 | if (!album_data.title) 17 | $scope.add_error_text = "Missing title"; 18 | else if (!album_data.date) 19 | $scope.add_error_text = "You must specify a date (yyyy/mm/dd)"; 20 | else if (!album_data.description) 21 | $scope.add_error_text = "Missing description"; 22 | else if (!album_data.name) 23 | $scope.add_error_text = "Short album name must be at least 6 chars (ironic, yes)"; 24 | else { 25 | try { 26 | var d = new Date(album_data.date.trim()); 27 | if (isNaN(d.getTime())) throw new Error("invalid date"); 28 | // if we made it here the date is good 29 | $scope.albums.push(album_data); 30 | $scope.new_album = {}; 31 | $scope.add_error_text = ''; 32 | } catch (e) { 33 | $scope.add_error_text = "You must specify a valid date (yyyy/mm/dd)"; 34 | } 35 | } 36 | }; 37 | } 38 | 39 | photoApp.controller("AlbumListController", AlbumListController); 40 | 41 | })(); 42 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/app/controllers/albumviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | 4 | function AlbumViewerController ($scope, $routeParams) { 5 | $scope.album_name = $routeParams.album_name; 6 | 7 | switch ($routeParams.album_name) { 8 | case "madrid1309": 9 | $scope.photos = [ 10 | { filename: "madrid1309-001.jpg", 11 | date: "2013/09/05", 12 | description: "I love this place" }, 13 | { filename: "madrid1309-002.jpg", 14 | date: "2013/09/05", 15 | description: "so much winning!!!" } ]; 16 | break; 17 | default: 18 | $scope.page_loading_error = "I don't know about that album yet, sorry"; 19 | } 20 | 21 | } 22 | 23 | 24 | photoApp.controller("AlbumViewerController", AlbumViewerController); 25 | 26 | })(); 27 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/app/controllers/photoviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // what about date and description??? 4 | // for next lesson!!! 5 | function PhotoViewerController ($scope, $routeParams) { 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.photo_filename = $routeParams.photo_filename; 8 | } 9 | 10 | 11 | photoApp.controller("PhotoViewerController", PhotoViewerController); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/app/partials/album_list.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 |
7 | {{ album.title }} 8 |
{{ album.date }}
9 |
10 |
11 | {{ album.description }} 12 |
13 |
14 | 15 |
16 | 17 |

Add new album

18 |
19 |
{{add_error_text}}
20 |
21 |
22 | 23 |
24 | 27 |
28 |
29 |
30 |

31 | 32 |

33 |

34 | 41 |

42 | 43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/app/partials/album_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
{{page_loading_error}}
4 | 5 |
6 | 7 | 8 | 9 | 10 |

{{ photo.description }}

11 |
12 | 13 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/app/partials/photo_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | {{album_name}} 6 |
7 |
8 |
9 | 10 |
11 |
12 | I'd like to have the description here. 13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /Lesson04/04_album_view/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } 30 | 31 | 32 | div.album .panel-heading a { 33 | text-decoration: none; 34 | color: white; 35 | } 36 | div.album .panel-heading a:hover { 37 | text-decoration: underline; 38 | color: white; 39 | } -------------------------------------------------------------------------------- /Lesson04/04_album_view/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/04_album_view/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson04/04_album_view/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/04_album_view/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson04/04_album_view/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/04_album_view/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson04/04_album_view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/01_my_first_module.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/01_my_first_module.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 | 16 |
17 |
{{ album.title }}
{{ album.date }}
18 |
19 | {{ album.description }} 20 |
21 |
22 | 23 |
24 | 25 |

Add new album

26 |
27 |
{{add_error_text}}
28 |
29 |
30 | 31 |
32 | 35 |
36 |
37 |
38 |

39 | 40 |

41 |

42 | 49 |

50 | 51 |
52 |
53 |
54 | 55 | 56 | 57 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/02_album_list_partial.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 |
{{ album.title }}
{{ album.date }}
7 |
8 | {{ album.description }} 9 |
10 |
11 | 12 |
13 | 14 |

Add new album

15 |
16 |
{{add_error_text}}
17 |
18 |
19 | 20 |
21 | 24 |
25 |
26 |
27 |

28 | 29 |

30 |

31 | 38 |

39 | 40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/02_routes.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/02_routes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/parts01_and_02/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/parts01_and_02/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson04/parts01_and_02/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson04/parts01_and_02/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson05/01_services/app/app.js: -------------------------------------------------------------------------------- 1 | var photoApp = angular.module("photoSharingApp", [ "ngRoute" ]); 2 | 3 | photoApp.config(function ($routeProvider) { 4 | $routeProvider 5 | .when("/albums", { controller: "AlbumListController", templateUrl: "/app/partials/album_list.html" }) 6 | .when("/album/:album_name", { controller: "AlbumViewerController", templateUrl: "/app/partials/album_viewer.html" }) 7 | .when("/album/:album_name/photos/:photo_filename", { controller: "PhotoViewerController", templateUrl: "/app/partials/photo_viewer.html" }) 8 | .when("/", { redirectTo: "/albums" }) 9 | .otherwise({ redirectTo: "/404_page" }); 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /Lesson05/01_services/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumListController ($scope, albumProvider) { 4 | 5 | $scope.new_album = {}; 6 | $scope.add_error_text = ''; 7 | 8 | $scope.albums = albumProvider.getAlbums(); 9 | 10 | $scope.addAlbum = function (album_data) { 11 | try { 12 | albumProvider.addAlbum(album_data); 13 | $scope.new_album = {}; 14 | $scope.add_error_text = ''; 15 | 16 | } catch (e) { 17 | if (e.message == "missing_title") 18 | $scope.add_error_text = "Missing title"; 19 | else if (e.message == "bad_date") 20 | $scope.add_error_text = "You must specify a date (yyyy/mm/dd)"; 21 | else if (e.message == "missing_description") 22 | $scope.add_error_text = "Missing description"; 23 | else if (e.message == "bad_name") 24 | $scope.add_error_text = "Short album name must be at least 6 chars (ironic, yes)"; 25 | } 26 | }; 27 | } 28 | 29 | photoApp.controller("AlbumListController", AlbumListController); 30 | 31 | })(); 32 | -------------------------------------------------------------------------------- /Lesson05/01_services/app/controllers/albumviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | 4 | function AlbumViewerController ($scope, $routeParams, albumProvider) { 5 | $scope.album_name = $routeParams.album_name; 6 | 7 | try { 8 | var album = albumProvider.getAlbumByName($scope.album_name); 9 | $scope.photos = album.photos; 10 | } catch (e) { 11 | if (e.message == "no_such_album") 12 | $scope.page_loading_error = "I don't know about that album yet, sorry"; 13 | else 14 | $scope.page_loading_error = "Unexpected error. Bug!"; 15 | } 16 | } 17 | 18 | 19 | photoApp.controller("AlbumViewerController", AlbumViewerController); 20 | 21 | })(); 22 | -------------------------------------------------------------------------------- /Lesson05/01_services/app/controllers/photoviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // what about date and description??? 4 | // for next lesson!!! 5 | function PhotoViewerController ($scope, $routeParams) { 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.photo_filename = $routeParams.photo_filename; 8 | } 9 | 10 | 11 | photoApp.controller("PhotoViewerController", PhotoViewerController); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /Lesson05/01_services/app/partials/album_list.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 |
7 | {{ album.title }} 8 |
{{ album.date }}
9 |
10 |
11 | {{ album.description }} 12 |
13 |
14 | 15 |
16 | 17 |

Add new album

18 |
19 |
{{add_error_text}}
20 |
21 |
22 | 23 |
24 | 26 |
27 |
28 |
29 |

30 | 31 |

32 |

33 | 40 |

41 | 42 |
43 |
44 |
45 | -------------------------------------------------------------------------------- /Lesson05/01_services/app/partials/album_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
{{page_loading_error}}
4 | 5 |
6 | 7 | 8 | 9 | 10 |

{{ photo.description }}

11 |
12 | 13 | -------------------------------------------------------------------------------- /Lesson05/01_services/app/partials/photo_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | {{album_name}} 6 |
7 |
8 |
9 | 10 |
11 |
12 | I'd like to have the description here. 13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /Lesson05/01_services/app/services/albumprovider.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function albumProvider () { 4 | 5 | var albums = [ 6 | { 7 | name: 'madrid1309', 8 | title: 'Weekend in Madrid', 9 | date: '2013-09-01', 10 | description: 'My favourite trip', 11 | photos: [ 12 | { 13 | filename: "madrid1309-001.jpg", 14 | date: "2013/09/05", 15 | description: "I love this place, so much good food." }, 16 | { 17 | filename: "madrid1309-002.jpg", 18 | date: "2013/09/06", 19 | description: "The museo del prado we had a wonderful time here." 20 | } 21 | ] 22 | }, 23 | { 24 | name: 'iceland1404', 25 | title: 'Holiday in Iceland', 26 | date: '2014-04-15', 27 | description: 'This place is cold', 28 | photos: [ 29 | { 30 | filename: "iceland1404-001.jpg", 31 | date: "2014/04/14", 32 | description: "So cold and so much snow!" }, 33 | { 34 | filename: "iceland1404-002.jpg", 35 | date: "2014/04/15", 36 | description: "The northern lights are extremely clear here." 37 | } 38 | ] 39 | }, 40 | { 41 | name: 'thailand1210', 42 | title: 'Surfing in Thailand', 43 | date: '2012-10-01', 44 | description: 'So hot!', 45 | photos: [ 46 | { 47 | filename: "thailand1210-001.jpg", 48 | date: "2012/10/01", 49 | description: "Getting mah surf on!" 50 | }, 51 | { 52 | filename: "thailand1210-002.jpg", 53 | date: "2012/10/02", 54 | description: "Thai food FTW!!!11!one!1" 55 | } 56 | ] 57 | }, 58 | { 59 | name: 'australia1207', 60 | title: 'Wedding in Australia', 61 | date: '2012-07-31', 62 | description: 'So many kangaroos and koalas!', 63 | photos: [ 64 | { 65 | filename: "australia1207-001.jpg", 66 | date: "2012/07/25", 67 | description: "The wedding was lovely." 68 | }, 69 | { 70 | filename: "australia1207-002.jpg", 71 | date: "2012/07/27", 72 | description: "Great Ocean Road." 73 | } 74 | ] 75 | } 76 | ]; 77 | 78 | this.getAlbums = function () { 79 | return albums; 80 | }; 81 | 82 | this.addAlbum = function (album_data) { 83 | for (var i = 0; i < albums.length; i++) { 84 | if (albums[i].name == album_data.name) 85 | throw new Error("duplicate_album_name"); 86 | } 87 | 88 | if (!album_data.title) throw new Error("missing_title"); 89 | if (!album_data.description) throw new Error("missing_description"); 90 | if (!album_data.date) throw new Error("bad_date"); 91 | 92 | var d = new Date(album_data.date.trim()); 93 | if (isNaN(d.getTime())) throw new Error("bad_date"); 94 | albums.push(JSON.parse(JSON.stringify(album_data))); 95 | }; 96 | 97 | 98 | this.getAlbumByName = function (name) { 99 | for (var i = 0; i < albums.length; i++) { 100 | if (albums[i].name == name) 101 | return JSON.parse(JSON.stringify(albums[i])); 102 | } 103 | 104 | throw new Error("no_such_album"); 105 | }; 106 | } 107 | 108 | photoApp.service("albumProvider", albumProvider); 109 | 110 | })(); 111 | -------------------------------------------------------------------------------- /Lesson05/01_services/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } 30 | 31 | 32 | div.album .panel-heading a { 33 | text-decoration: none; 34 | color: white; 35 | } 36 | div.album .panel-heading a:hover { 37 | text-decoration: underline; 38 | color: white; 39 | } -------------------------------------------------------------------------------- /Lesson05/01_services/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/01_services/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson05/01_services/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/01_services/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson05/01_services/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/01_services/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson05/01_services/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Lesson05/02_factories/app/app.js: -------------------------------------------------------------------------------- 1 | var photoApp = angular.module("photoSharingApp", [ "ngRoute" ]); 2 | 3 | photoApp.config(function ($routeProvider) { 4 | $routeProvider 5 | .when("/albums", { controller: "AlbumListController", templateUrl: "/app/partials/album_list.html" }) 6 | .when("/album/:album_name", { controller: "AlbumViewerController", templateUrl: "/app/partials/album_viewer.html" }) 7 | .when("/album/:album_name/photos/:photo_filename", { controller: "PhotoViewerController", templateUrl: "/app/partials/photo_viewer.html" }) 8 | .when("/", { redirectTo: "/albums" }) 9 | .otherwise({ redirectTo: "/404_page" }); 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /Lesson05/02_factories/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumListController ($scope, AlbumProvider) { 4 | 5 | $scope.new_album = {}; 6 | $scope.add_error_text = ''; 7 | 8 | $scope.albums = AlbumProvider.getAlbums(); 9 | 10 | $scope.addAlbum = function (album_data) { 11 | try { 12 | AlbumProvider.addAlbum(album_data); 13 | $scope.new_album = {}; 14 | $scope.add_error_text = ''; 15 | 16 | } catch (e) { 17 | if (e.message == "missing_title") 18 | $scope.add_error_text = "Missing title"; 19 | else if (e.message == "bad_date") 20 | $scope.add_error_text = "You must specify a date (yyyy/mm/dd)"; 21 | else if (e.message == "missing_description") 22 | $scope.add_error_text = "Missing description"; 23 | else if (e.message == "bad_name") 24 | $scope.add_error_text = "Short album name must be at least 6 chars (ironic, yes)"; 25 | } 26 | }; 27 | } 28 | 29 | photoApp.controller("AlbumListController", AlbumListController); 30 | 31 | })(); 32 | -------------------------------------------------------------------------------- /Lesson05/02_factories/app/controllers/albumviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | 4 | function AlbumViewerController ($scope, $routeParams, AlbumProvider) { 5 | $scope.album_name = $routeParams.album_name; 6 | 7 | try { 8 | var album = AlbumProvider.getAlbumByName($scope.album_name); 9 | $scope.photos = album.photos; 10 | } catch (e) { 11 | if (e.message == "no_such_album") 12 | $scope.page_loading_error = "I don't know about that album yet, sorry"; 13 | else 14 | $scope.page_loading_error = "Unexpected error. Bug!"; 15 | } 16 | } 17 | 18 | 19 | photoApp.controller("AlbumViewerController", AlbumViewerController); 20 | 21 | })(); 22 | -------------------------------------------------------------------------------- /Lesson05/02_factories/app/controllers/photoviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // what about date and description??? 4 | // for next lesson!!! 5 | function PhotoViewerController ($scope, $routeParams) { 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.photo_filename = $routeParams.photo_filename; 8 | } 9 | 10 | 11 | photoApp.controller("PhotoViewerController", PhotoViewerController); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /Lesson05/02_factories/app/partials/album_list.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 |
7 | {{ album.title }} 8 |
{{ album.date }}
9 |
10 |
11 | {{ album.description }} 12 |
13 |
14 | 15 |
16 | 17 |

Add new album

18 |
19 |
{{add_error_text}}
20 |
21 |
22 | 23 |
24 | 26 |
27 |
28 |
29 |

30 | 31 |

32 |

33 | 40 |

41 | 42 |
43 |
44 |
45 | -------------------------------------------------------------------------------- /Lesson05/02_factories/app/partials/album_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
{{page_loading_error}}
4 | 5 |
6 | 7 | 8 | 9 | 10 |

{{ photo.description }}

11 |
12 | 13 | -------------------------------------------------------------------------------- /Lesson05/02_factories/app/partials/photo_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | {{album_name}} 6 |
7 |
8 |
9 | 10 |
11 |
12 | I'd like to have the description here. 13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /Lesson05/02_factories/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } 30 | 31 | 32 | div.album .panel-heading a { 33 | text-decoration: none; 34 | color: white; 35 | } 36 | div.album .panel-heading a:hover { 37 | text-decoration: underline; 38 | color: white; 39 | } -------------------------------------------------------------------------------- /Lesson05/02_factories/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/02_factories/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson05/02_factories/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/02_factories/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson05/02_factories/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/02_factories/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson05/02_factories/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Lesson05/03_useful_factories.js: -------------------------------------------------------------------------------- 1 | 2 | function LoginFactory () { 3 | 4 | return function (login_type) { 5 | this.perform_login = function (un, pw) { 6 | switch (login_type) { 7 | case "gplus": /* do something */ break; 8 | case "fb": /* do sth */ break; 9 | default: 10 | local_login(un, pw); 11 | }; 12 | } 13 | } 14 | 15 | mymod.factory("LoginFactory", LoginFactory); 16 | 17 | 18 | 19 | function UserController ($scope, LoginFactory) { 20 | $scope.perform_login = function (login_type, un, pw) { 21 | var logger_inner = new LoginFactory(login_type); 22 | 23 | logger_inner.perform_login(un, pw); 24 | }; 25 | } 26 | 27 | mymod.controller("UserController", UserController); 28 | 29 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/back/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "photo_server", 3 | "description": "Simple Demo backend for our photo server.", 4 | "private": true, 5 | "dependencies": { 6 | "async": "0.2.x", 7 | "express": "3.x" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/back/photo_albums.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "asdfasf241", 4 | "title": "asdf", 5 | "date": "2014/1/1", 6 | "description": "asdfasdf", 7 | "photos": [] 8 | }, 9 | { 10 | "name": "york1401", 11 | "title": "york", 12 | "date": "2014/10/10", 13 | "description": "asdfadf", 14 | "photos": [] 15 | }, 16 | { 17 | "name": "veryovely234", 18 | "title": "new album", 19 | "date": "2013/1/23", 20 | "description": "so nice", 21 | "photos": [] 22 | } 23 | ] -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/app.js: -------------------------------------------------------------------------------- 1 | var photoApp = angular.module("photoSharingApp", [ "ngRoute" ]); 2 | 3 | photoApp.config(function ($routeProvider) { 4 | $routeProvider 5 | .when("/albums", { controller: "AlbumListController", templateUrl: "/app/partials/album_list.html" }) 6 | .when("/album/:album_name", { controller: "AlbumViewerController", templateUrl: "/app/partials/album_viewer.html" }) 7 | .when("/album/:album_name/photos/:photo_filename", { controller: "PhotoViewerController", templateUrl: "/app/partials/photo_viewer.html" }) 8 | .when("/", { redirectTo: "/albums" }) 9 | .otherwise({ redirectTo: "/404_page" }); 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumListController ($scope, albumProvider, $location) { 4 | 5 | $scope.new_album = {}; 6 | $scope.add_error_text = ''; 7 | $scope.page_load_error = ""; 8 | 9 | albumProvider.getAlbums(function (err, albums) { 10 | if (err) { 11 | $scope.page_load_error = "Unexpected error loading albums: " + e.message; 12 | } else { 13 | $scope.albums = albums; 14 | } 15 | }); 16 | 17 | $scope.addAlbum = function (album_data) { 18 | 19 | albumProvider.addAlbum(album_data, function (err, results) { 20 | if (err) { 21 | if (err.code == "missing_title") 22 | $scope.add_error_text = "Missing title"; 23 | else if (err.code == "bad_date") 24 | $scope.add_error_text = "You must specify a date (yyyy/mm/dd)"; 25 | else if (err.code == "missing_description") 26 | $scope.add_error_text = "Missing description"; 27 | else if (err.code == "bad_name") 28 | $scope.add_error_text = "Short album name must be at least 6 chars (ironic, yes)"; 29 | } else { 30 | // looks good! 31 | $scope.new_album = {}; 32 | $scope.add_error_text = ''; 33 | 34 | // now, redirect to load in the album! 35 | $location.path("/album/" + album_data.name); 36 | } 37 | 38 | }); 39 | }; 40 | } 41 | 42 | photoApp.controller("AlbumListController", AlbumListController); 43 | 44 | })(); 45 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/controllers/albumviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumViewerController ($scope, $routeParams, albumProvider) { 4 | $scope.album_name = $routeParams.album_name; 5 | 6 | albumProvider.getAlbumByName($scope.album_name, function (err, photos) { 7 | if (err) { 8 | if (err.error == "not_found") 9 | $scope.page_load_error = "No such album. Are you calling this right?"; 10 | else 11 | $scope.page_load_error = "Unexpected error loading albums: " + e.message; 12 | } else { 13 | $scope.photos = photos; 14 | } 15 | }); 16 | 17 | } 18 | 19 | photoApp.controller("AlbumViewerController", AlbumViewerController); 20 | 21 | })(); 22 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/controllers/photoviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // what about date and description??? 4 | // for next lesson!!! 5 | function PhotoViewerController ($scope, $routeParams) { 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.photo_filename = $routeParams.photo_filename; 8 | } 9 | 10 | 11 | photoApp.controller("PhotoViewerController", PhotoViewerController); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/partials/album_list.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | {{page_load_error}} 4 |
5 | 6 |

7 | 8 |

9 | 10 |
11 |
12 | {{ album.title }} 13 |
{{ album.date }}
14 |
15 |
16 | {{ album.description }} 17 |
18 |
19 | 20 |
21 | 22 |

Add new album

23 |
24 |
{{add_error_text}}
25 |
26 |
27 | 28 |
29 | 31 |
32 |
33 |
34 |

35 | 36 |

37 |

38 | 45 |

46 | 47 |
48 |
49 |
50 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/partials/album_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
{{page_loading_error}}
4 | 5 |

{{album_name}}

6 | 7 |
8 | 9 | 10 | 11 | 12 |

{{ photo.description }}

13 |
14 | 15 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/partials/photo_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | {{album_name}} 6 |
7 |
8 |
9 | 10 |
11 |
12 | I'd like to have the description here. 13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/services/albumprovider.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function albumProvider ($http) { 4 | 5 | this.getAlbums = function (callback) { 6 | $http.get("/v1/albums.json") 7 | .success(function (data, status, headers, conf) { 8 | callback(null, data); 9 | }) 10 | .error(function (data, status, headers, conf) { 11 | // just send back the error 12 | callback(data); 13 | }); 14 | }; 15 | 16 | this.addAlbum = function (album_data, callback) { 17 | 18 | if (!album_data.title) throw new Error("missing_title"); 19 | if (!album_data.description) throw new Error("missing_description"); 20 | if (!album_data.date) throw new Error("bad_date"); 21 | 22 | var d = new Date(album_data.date.trim()); 23 | if (isNaN(d.getTime())) throw new Error("bad_date"); 24 | 25 | $http.put("/v1/albums.json", album_data) 26 | .success(function (data, status, headers, conf) { 27 | callback(null, data); 28 | }) 29 | .error(function (data, status, headers, conf) { 30 | // just send back the error 31 | callback(data); 32 | }); 33 | }; 34 | 35 | 36 | this.getAlbumByName = function (name, callback) { 37 | 38 | $http.get("/v1/albums/" + name + "/photos.json") 39 | .success(function (data, status, headers, conf) { 40 | console.log(data); 41 | callback(null, data); 42 | }) 43 | .error(function (data, status, headers, conf) { 44 | // just send back the error 45 | callback(data); 46 | }); 47 | }; 48 | } 49 | 50 | photoApp.service("albumProvider", albumProvider); 51 | 52 | })(); 53 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/app/services/configprops.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | photoApp.constant("appConfigurationProps", { 4 | json_server_host: "localhost", 5 | json_server_port: 8082 6 | }); 7 | 8 | })(); 9 | -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } 30 | 31 | 32 | div.album .panel-heading a { 33 | text-decoration: none; 34 | color: white; 35 | } 36 | div.album .panel-heading a:hover { 37 | text-decoration: underline; 38 | color: white; 39 | } -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/04_remote_data/front/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/04_remote_data/front/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/04_remote_data/front/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson05/04_remote_data/front/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/back/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "photo_server", 3 | "description": "Simple Demo backend for our photo server.", 4 | "private": true, 5 | "dependencies": { 6 | "async": "0.2.x", 7 | "express": "3.x" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/back/photo_albums.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "york1402", 4 | "title": "York", 5 | "date": "2014/1/1", 6 | "description": "asdf", 7 | "photos": [] 8 | }, 9 | { 10 | "name": "asdfasdfzxcv", 11 | "title": "qwer", 12 | "date": "2014/1/1", 13 | "description": "zxcv", 14 | "photos": [] 15 | } 16 | ] -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/app.js: -------------------------------------------------------------------------------- 1 | var photoApp = angular.module("photoSharingApp", [ "ngRoute", 'angularFileUpload' ]); 2 | 3 | photoApp.config(function ($routeProvider) { 4 | $routeProvider 5 | .when("/albums", { controller: "AlbumListController", templateUrl: "/app/partials/album_list.html" }) 6 | .when("/album/:album_name", { controller: "AlbumViewerController", templateUrl: "/app/partials/album_viewer.html" }) 7 | .when("/album/:album_name/upload", { controller: "AlbumUploadController", templateUrl: "/app/partials/album_uploader.html" }) 8 | .when("/album/:album_name/photos/:photo_filename", { controller: "PhotoViewerController", templateUrl: "/app/partials/photo_viewer.html" }) 9 | .when("/", { redirectTo: "/albums" }) 10 | .otherwise({ redirectTo: "/404_page" }); 11 | }); 12 | 13 | 14 | 15 | photoApp.filter("OLD_YELLER", function () { 16 | return function (str) { 17 | if (typeof str != 'string') return str; 18 | return str.toUpperCase(); 19 | } 20 | }); 21 | 22 | 23 | photoApp.filter("pluralise", function () { 24 | return function (count, nouns) { 25 | if (count == 1) return count + " " + nouns.one; 26 | else return count + " " + nouns.more; 27 | } 28 | }); 29 | 30 | photoApp.filter("multifieldfilter", function () { 31 | return function (obj, params) { 32 | if (!Array.isArray(obj)) return obj; 33 | 34 | if (!params.findMe) return obj; 35 | if (!params.fields || !Array.isArray(params.fields)) return obj; 36 | 37 | var out = []; 38 | 39 | for (var i = 0; i < obj.length; i++) { 40 | for (var j = 0; j < params.fields.length; j++) { 41 | if (typeof obj[i][params.fields[j]] != 'string') break; 42 | if (obj[i][params.fields[j]].indexOf(params.findMe) != -1) { 43 | out.push(obj[i]); 44 | break; 45 | } 46 | } 47 | } 48 | 49 | return out; 50 | } 51 | }); 52 | 53 | 54 | photoApp.directive("mwAngry", function () { 55 | return { 56 | restrict: "A", 57 | link: function ($scope, element, attrs) { 58 | element.css({ "background-color": "yellow", 59 | color: "red" , 60 | padding: "10px" , 61 | "font-weight": "bold" }); 62 | 63 | } 64 | } 65 | }); 66 | 67 | 68 | photoApp.directive("mwAngryPlus", function () { 69 | return { 70 | restrict: "AE", 71 | template: ">:(>:(>:( ", 72 | transclude: true, 73 | link: function ($scope, element, attrs) { 74 | element.css({ "background-color": "yellow", 75 | color: "red" , 76 | padding: "10px" , 77 | "font-weight": "bold" }); 78 | 79 | } 80 | } 81 | }); 82 | 83 | photoApp.directive("mwAngryPlusPlus", function () { 84 | var angry = false; 85 | return { 86 | restrict: "AE", 87 | template: ">:(>:(>:( ", 88 | transclude: true, 89 | link: function ($scope, element, attrs, ctlr, tf) { 90 | var ot; 91 | tf(element, function (copy) { 92 | ot = copy.text(); 93 | }); 94 | if (ot.indexOf("HELLO") != -1) angry = true; 95 | if (angry) 96 | element.css({ "background-color": "yellow", 97 | color: "red" , 98 | padding: "10px" , 99 | "font-weight": "bold" }); 100 | else 101 | element.html(ot); 102 | } 103 | } 104 | }); 105 | 106 | 107 | photoApp.directive("paAlbum", function () { 108 | return { 109 | restrict: "AE", 110 | scope: { 111 | album: "=" 112 | }, 113 | template: "
{{album.title}}
{{album.description}}
", 114 | link: function ($scope, element, attrs) { 115 | // don't need to do anything here. 116 | } 117 | } 118 | }); 119 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumListController ($scope, albumProvider, $location) { 4 | 5 | $scope.new_album = {}; 6 | $scope.add_error_text = ''; 7 | $scope.page_load_error = ""; 8 | 9 | albumProvider.getAlbums(function (err, albums) { 10 | if (err) { 11 | $scope.page_load_error = "Unexpected error loading albums: " + e.message; 12 | } else { 13 | $scope.albums = albums; 14 | } 15 | }); 16 | 17 | $scope.addAlbum = function (album_data) { 18 | 19 | albumProvider.addAlbum(album_data, function (err, results) { 20 | if (err) { 21 | if (err.code == "missing_title") 22 | $scope.add_error_text = "Missing title"; 23 | else if (err.code == "bad_date") 24 | $scope.add_error_text = "You must specify a date (yyyy/mm/dd)"; 25 | else if (err.code == "missing_description") 26 | $scope.add_error_text = "Missing description"; 27 | else if (err.code == "bad_name") 28 | $scope.add_error_text = "Short album name must be at least 6 chars (ironic, yes)"; 29 | } else { 30 | // looks good! 31 | $scope.new_album = {}; 32 | $scope.add_error_text = ''; 33 | 34 | // now, redirect to load in the album! 35 | $location.path("/album/" + album_data.name); 36 | } 37 | 38 | }); 39 | }; 40 | } 41 | 42 | photoApp.controller("AlbumListController", AlbumListController); 43 | 44 | })(); 45 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/controllers/albumuploadcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function AlbumUploadController ($scope, $location, $routeParams, albumProvider) { 4 | $scope.album_name = $routeParams.album_name; 5 | $scope.page_load_error = ""; 6 | $scope.done_uploading = false; 7 | 8 | // ADD FIRST! 9 | albumProvider.getAlbumByName($scope.album_name, function (err, photos) { 10 | if (err) { 11 | if (err.error == "not_found") 12 | $scope.page_load_error = "No such album. Are you calling this right?"; 13 | else 14 | $scope.page_load_error = "Unexpected error loading albums: " + err.message; 15 | } else { 16 | $scope.photos = photos; 17 | } 18 | }); 19 | 20 | $scope.uploader = albumProvider.getUploader($scope.album_name, $scope); 21 | 22 | 23 | 24 | $scope.uploader.bind("completeall", function (event, items) { 25 | $scope.done_uploading = true; 26 | }); 27 | 28 | 29 | $scope.uploadFiles = function () { 30 | $scope.uploader.uploadAll(); 31 | } 32 | 33 | 34 | 35 | // FOR DESCRIPTIONS 36 | $scope.descriptions = {}; 37 | $scope.uploader.bind('beforeupload', function (event, item) { 38 | var fn = item.file.name; 39 | var d = item.file.lastModifiedDate; 40 | item.formData = [{ 41 | filename: _fix_filename(item.file.name), 42 | description: $scope.descriptions[item.file.name], 43 | date: d.getFullYear() + "/" + d.getMonth() + "/" + d.getDate() 44 | } ]; 45 | }); 46 | 47 | 48 | } 49 | 50 | photoApp.controller("AlbumUploadController", AlbumUploadController); 51 | 52 | 53 | /** 54 | * we'll be super fussy and only allow alnum, -, _, and . 55 | */ 56 | function _fix_filename(fn) { 57 | if (!fn || fn.length == 0) return "unknown"; 58 | 59 | var r = new RegExp("^[a-zA-Z0-9\\-_.]+$"); 60 | var out = ""; 61 | 62 | for (var i = 0; i < fn.length; i++) { 63 | if (r.exec(fn[i]) != null) 64 | out += fn[i]; 65 | } 66 | 67 | if (!out) out = "unknown_" + (new Date()).getTime(); 68 | return out; 69 | } 70 | 71 | 72 | 73 | })(); 74 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/controllers/albumviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumViewerController ($scope, $location, $routeParams, albumProvider) { 4 | $scope.album_name = $routeParams.album_name; 5 | $scope.page_load_error = ""; 6 | 7 | albumProvider.getAlbumByName($scope.album_name, function (err, photos) { 8 | if (err) { 9 | if (err.error == "not_found") 10 | $scope.page_load_error = "No such album. Are you calling this right?"; 11 | else 12 | $scope.page_load_error = "Unexpected error loading albums: " + err.message; 13 | } else { 14 | $scope.photos = photos; 15 | } 16 | }); 17 | } 18 | 19 | photoApp.controller("AlbumViewerController", AlbumViewerController); 20 | 21 | })(); 22 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/controllers/photoviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // what about date and description??? 4 | // for next lesson!!! 5 | function PhotoViewerController ($scope, $routeParams) { 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.photo_filename = $routeParams.photo_filename; 8 | } 9 | 10 | 11 | photoApp.controller("PhotoViewerController", PhotoViewerController); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/partials/album_list.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | {{page_load_error}} 4 |
5 | 6 |

HELLO THERE

7 | 8 |

Displaying {{ albums.length | pluralise:{one:"city", more:"cities"} }}

9 | 10 |

11 | 12 |

13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | {{ album.title }} 21 |
{{ album.date }}
22 |
23 |
24 | {{ album.description }} 25 |
26 |
27 | 28 |
29 | 30 |

Add new album

31 |
32 |
{{add_error_text}}
33 |
34 |
35 | 36 |
37 | 39 |
40 |
41 |
42 |

43 | 44 |

45 |

46 | 53 |

54 | 55 |
56 |
57 |
58 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/partials/album_uploader.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 |
4 | 5 |
6 |
{{page_load_error}}
7 | 8 |

9 | 10 |

11 | 12 |
13 |
Name: {{ item.file.name }}
14 |
Size: {{ item.file.size/1024/1024|number:2 }} Mb
15 |
16 | Description:
17 | 18 |
19 | 20 |

21 | Upload Progress: {{ item.progress }} 22 |

23 |
24 |
25 |

26 | 27 |
28 | 29 |
30 |
31 | 32 |
33 | 34 |
35 |
36 | Total progress: {{ uploader.progress }} 37 |
38 |
39 |
40 |
41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
54 | 55 | 56 | 57 |
58 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/partials/album_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
{{page_load_error}}
4 | 5 |

{{album_name}}

6 | 7 |
8 | 9 | 10 | 11 | 12 |

{{ photo.description }}

13 |
14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/partials/photo_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | {{album_name}} 6 |
7 |
8 |
9 | 10 |
11 |
12 | I'd like to have the description here. 13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/services/albumprovider.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function albumProvider ($http, $fileUploader) { 4 | 5 | this.getUploader = function (album_name, scope) { 6 | // create a uploader with options 7 | return $fileUploader.create({ 8 | scope: scope, 9 | method: "PUT", 10 | url: "/v1/albums/" + album_name + "/photos.json" 11 | }); 12 | }; 13 | 14 | this.getAlbums = function (callback) { 15 | $http.get("/v1/albums.json") 16 | .success(function (data, status, headers, conf) { 17 | callback(null, data); 18 | }) 19 | .error(function (data, status, headers, conf) { 20 | // just send back the error 21 | callback(data); 22 | }); 23 | }; 24 | 25 | this.addAlbum = function (album_data, callback) { 26 | 27 | if (!album_data.title) throw new Error("missing_title"); 28 | if (!album_data.description) throw new Error("missing_description"); 29 | if (!album_data.date) throw new Error("bad_date"); 30 | 31 | var d = new Date(album_data.date.trim()); 32 | if (isNaN(d.getTime())) throw new Error("bad_date"); 33 | 34 | $http.put("/v1/albums.json", album_data) 35 | .success(function (data, status, headers, conf) { 36 | callback(null, data); 37 | }) 38 | .error(function (data, status, headers, conf) { 39 | // just send back the error 40 | callback(data); 41 | }); 42 | }; 43 | 44 | 45 | this.getAlbumByName = function (name, callback) { 46 | $http.get("/v1/albums/" + name + "/photos.json") 47 | .success(function (data, status, headers, conf) { 48 | callback(null, data); 49 | }) 50 | .error(function (data, status, headers, conf) { 51 | // just send back the error 52 | callback(data); 53 | }); 54 | }; 55 | } 56 | 57 | photoApp.service("albumProvider", albumProvider); 58 | 59 | })(); 60 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/app/services/configprops.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | photoApp.constant("appConfigurationProps", { 4 | json_server_host: "localhost", 5 | json_server_port: 8082 6 | }); 7 | 8 | })(); 9 | -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } 30 | 31 | 32 | div.album .panel-heading a { 33 | text-decoration: none; 34 | color: white; 35 | } 36 | div.album .panel-heading a:hover { 37 | text-decoration: underline; 38 | color: white; 39 | } -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/05_uploads/front/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/05_uploads/front/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson05/05_uploads/front/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson05/05_uploads/front/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/back/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "photo_server", 3 | "description": "Simple Demo backend for our photo server.", 4 | "private": true, 5 | "dependencies": { 6 | "async": "0.2.x", 7 | "express": "3.x" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/back/photo_albums.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "york1402", 4 | "title": "York", 5 | "date": "2014/1/1", 6 | "description": "asdf", 7 | "photos": [] 8 | }, 9 | { 10 | "name": "asdfasdfzxcv", 11 | "title": "qwer", 12 | "date": "2014/1/1", 13 | "description": "zxcv", 14 | "photos": [] 15 | } 16 | ] -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/app.js: -------------------------------------------------------------------------------- 1 | var photoApp = angular.module("photoSharingApp", [ "ngRoute", 'angularFileUpload' ]); 2 | 3 | photoApp.config(function ($routeProvider) { 4 | $routeProvider 5 | .when("/albums", { controller: "AlbumListController", templateUrl: "/app/partials/album_list.html" }) 6 | .when("/album/:album_name", { controller: "AlbumViewerController", templateUrl: "/app/partials/album_viewer.html" }) 7 | .when("/album/:album_name/upload", { controller: "AlbumUploadController", templateUrl: "/app/partials/album_uploader.html" }) 8 | .when("/album/:album_name/photos/:photo_filename", { controller: "PhotoViewerController", templateUrl: "/app/partials/photo_viewer.html" }) 9 | .when("/", { redirectTo: "/albums" }) 10 | .otherwise({ redirectTo: "/404_page" }); 11 | }); 12 | 13 | 14 | 15 | photoApp.filter("OLD_YELLER", function () { 16 | return function (str) { 17 | if (typeof str != 'string') return str; 18 | return str.toUpperCase(); 19 | } 20 | }); 21 | 22 | 23 | photoApp.filter("pluralise", function () { 24 | return function (count, nouns) { 25 | if (count == 1) return count + " " + nouns.one; 26 | else return count + " " + nouns.more; 27 | } 28 | }); 29 | 30 | photoApp.filter("multifieldfilter", function () { 31 | return function (obj, params) { 32 | if (!Array.isArray(obj)) return obj; 33 | 34 | if (!params.findMe) return obj; 35 | if (!params.fields || !Array.isArray(params.fields)) return obj; 36 | 37 | var out = []; 38 | 39 | for (var i = 0; i < obj.length; i++) { 40 | for (var j = 0; j < params.fields.length; j++) { 41 | if (typeof obj[i][params.fields[j]] != 'string') break; 42 | if (obj[i][params.fields[j]].indexOf(params.findMe) != -1) { 43 | out.push(obj[i]); 44 | break; 45 | } 46 | } 47 | } 48 | 49 | return out; 50 | } 51 | }); 52 | 53 | 54 | photoApp.directive("mwAngry", function () { 55 | return { 56 | restrict: "A", 57 | link: function ($scope, element, attrs) { 58 | element.css({ "background-color": "yellow", 59 | color: "red" , 60 | padding: "10px" , 61 | "font-weight": "bold" }); 62 | 63 | } 64 | } 65 | }); 66 | 67 | 68 | photoApp.directive("mwAngryPlus", function () { 69 | return { 70 | restrict: "AE", 71 | template: ">:(>:(>:( ", 72 | transclude: true, 73 | link: function ($scope, element, attrs) { 74 | element.css({ "background-color": "yellow", 75 | color: "red" , 76 | padding: "10px" , 77 | "font-weight": "bold" }); 78 | 79 | } 80 | } 81 | }); 82 | 83 | 84 | 85 | photoApp.directive("paAlbum", function () { 86 | return { 87 | restrict: "AE", 88 | scope: { 89 | album: "=" 90 | }, 91 | template: "
{{album.title}}
{{album.description}}
", 92 | link: function ($scope, element, attrs) { 93 | // don't need to do anything here. 94 | } 95 | } 96 | }); 97 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumListController ($scope, albumProvider, $location) { 4 | 5 | $scope.new_album = {}; 6 | $scope.add_error_text = ''; 7 | $scope.page_load_error = ""; 8 | 9 | albumProvider.getAlbums(function (err, albums) { 10 | if (err) { 11 | $scope.page_load_error = "Unexpected error loading albums: " + e.message; 12 | } else { 13 | $scope.albums = albums; 14 | } 15 | }); 16 | 17 | $scope.addAlbum = function (album_data) { 18 | 19 | albumProvider.addAlbum(album_data, function (err, results) { 20 | if (err) { 21 | if (err.code == "missing_title") 22 | $scope.add_error_text = "Missing title"; 23 | else if (err.code == "bad_date") 24 | $scope.add_error_text = "You must specify a date (yyyy/mm/dd)"; 25 | else if (err.code == "missing_description") 26 | $scope.add_error_text = "Missing description"; 27 | else if (err.code == "bad_name") 28 | $scope.add_error_text = "Short album name must be at least 6 chars (ironic, yes)"; 29 | } else { 30 | // looks good! 31 | $scope.new_album = {}; 32 | $scope.add_error_text = ''; 33 | 34 | // now, redirect to load in the album! 35 | $location.path("/album/" + album_data.name); 36 | } 37 | 38 | }); 39 | }; 40 | } 41 | 42 | photoApp.controller("AlbumListController", AlbumListController); 43 | 44 | })(); 45 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/controllers/albumuploadcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function AlbumUploadController ($scope, $location, $routeParams, albumProvider) { 4 | $scope.album_name = $routeParams.album_name; 5 | $scope.page_load_error = ""; 6 | $scope.done_uploading = false; 7 | 8 | // ADD FIRST! 9 | albumProvider.getAlbumByName($scope.album_name, function (err, photos) { 10 | if (err) { 11 | if (err.error == "not_found") 12 | $scope.page_load_error = "No such album. Are you calling this right?"; 13 | else 14 | $scope.page_load_error = "Unexpected error loading albums: " + err.message; 15 | } else { 16 | $scope.photos = photos; 17 | } 18 | }); 19 | 20 | $scope.uploader = albumProvider.getUploader($scope.album_name, $scope); 21 | 22 | 23 | 24 | $scope.uploader.bind("completeall", function (event, items) { 25 | $scope.done_uploading = true; 26 | }); 27 | 28 | 29 | $scope.uploadFiles = function () { 30 | $scope.uploader.uploadAll(); 31 | } 32 | 33 | 34 | 35 | // FOR DESCRIPTIONS 36 | $scope.descriptions = {}; 37 | $scope.uploader.bind('beforeupload', function (event, item) { 38 | var fn = item.file.name; 39 | var d = item.file.lastModifiedDate; 40 | item.formData = [{ 41 | filename: _fix_filename(item.file.name), 42 | description: $scope.descriptions[item.file.name], 43 | date: d.getFullYear() + "/" + d.getMonth() + "/" + d.getDate() 44 | } ]; 45 | }); 46 | 47 | 48 | } 49 | 50 | photoApp.controller("AlbumUploadController", AlbumUploadController); 51 | 52 | 53 | /** 54 | * we'll be super fussy and only allow alnum, -, _, and . 55 | */ 56 | function _fix_filename(fn) { 57 | if (!fn || fn.length == 0) return "unknown"; 58 | 59 | var r = new RegExp("^[a-zA-Z0-9\\-_.]+$"); 60 | var out = ""; 61 | 62 | for (var i = 0; i < fn.length; i++) { 63 | if (r.exec(fn[i]) != null) 64 | out += fn[i]; 65 | } 66 | 67 | if (!out) out = "unknown_" + (new Date()).getTime(); 68 | return out; 69 | } 70 | 71 | 72 | 73 | })(); 74 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/controllers/albumviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function AlbumViewerController ($scope, $location, $routeParams, albumProvider) { 4 | $scope.album_name = $routeParams.album_name; 5 | $scope.page_load_error = ""; 6 | 7 | albumProvider.getAlbumByName($scope.album_name, function (err, photos) { 8 | if (err) { 9 | if (err.error == "not_found") 10 | $scope.page_load_error = "No such album. Are you calling this right?"; 11 | else 12 | $scope.page_load_error = "Unexpected error loading albums: " + err.message; 13 | } else { 14 | $scope.photos = photos; 15 | } 16 | }); 17 | } 18 | 19 | photoApp.controller("AlbumViewerController", AlbumViewerController); 20 | 21 | })(); 22 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/controllers/photoviewercontroller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // what about date and description??? 4 | // for next lesson!!! 5 | function PhotoViewerController ($scope, $routeParams) { 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.photo_filename = $routeParams.photo_filename; 8 | } 9 | 10 | 11 | photoApp.controller("PhotoViewerController", PhotoViewerController); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/partials/album_list.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | {{page_load_error}} 4 |
5 | 6 |

HELLO THERE

7 | 8 |

Displaying {{ albums.length | pluralise:{one:"city", more:"cities"} }}

9 | 10 |

11 | 12 |

13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | {{ album.title }} 21 |
{{ album.date }}
22 |
23 |
24 | {{ album.description }} 25 |
26 |
27 | 28 |
29 | 30 |

Add new album

31 |
32 |
{{add_error_text}}
33 |
34 |
35 | 36 |
37 | 39 |
40 |
41 |
42 |

43 | 44 |

45 |

46 | 53 |

54 | 55 |
56 |
57 |
58 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/partials/album_uploader.html: -------------------------------------------------------------------------------- 1 |
2 | Home 3 |
4 | 5 |
6 |
{{page_load_error}}
7 | 8 |

9 | 10 |

11 | 12 |
13 |
Name: {{ item.file.name }}
14 |
Size: {{ item.file.size/1024/1024|number:2 }} Mb
15 |
16 | Description:
17 | 18 |
19 | 20 |

21 | Upload Progress: {{ item.progress }} 22 |

23 |
24 |
25 |

26 | 27 |
28 | 29 |
30 |
31 | 32 |
33 | 34 |
35 |
36 | Total progress: {{ uploader.progress }} 37 |
38 |
39 |
40 |
41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
54 | 55 | 56 | 57 |
58 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/partials/album_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
{{page_load_error}}
4 | 5 |

{{album_name}}

6 | 7 |
8 | 9 | 10 | 11 | 12 |

{{ photo.description }}

13 |
14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/partials/photo_viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | {{album_name}} 6 |
7 |
8 |
9 | 10 |
11 |
12 | I'd like to have the description here. 13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/services/albumprovider.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function albumProvider ($http, $fileUploader) { 4 | 5 | this.getUploader = function (album_name, scope) { 6 | // create a uploader with options 7 | return $fileUploader.create({ 8 | scope: scope, 9 | method: "PUT", 10 | url: "/v1/albums/" + album_name + "/photos.json" 11 | }); 12 | }; 13 | 14 | this.getAlbums = function (callback) { 15 | $http.get("/v1/albums.json") 16 | .success(function (data, status, headers, conf) { 17 | callback(null, data); 18 | }) 19 | .error(function (data, status, headers, conf) { 20 | // just send back the error 21 | callback(data); 22 | }); 23 | }; 24 | 25 | this.addAlbum = function (album_data, callback) { 26 | 27 | if (!album_data.title) throw new Error("missing_title"); 28 | if (!album_data.description) throw new Error("missing_description"); 29 | if (!album_data.date) throw new Error("bad_date"); 30 | 31 | var d = new Date(album_data.date.trim()); 32 | if (isNaN(d.getTime())) throw new Error("bad_date"); 33 | 34 | $http.put("/v1/albums.json", album_data) 35 | .success(function (data, status, headers, conf) { 36 | callback(null, data); 37 | }) 38 | .error(function (data, status, headers, conf) { 39 | // just send back the error 40 | callback(data); 41 | }); 42 | }; 43 | 44 | 45 | this.getAlbumByName = function (name, callback) { 46 | $http.get("/v1/albums/" + name + "/photos.json") 47 | .success(function (data, status, headers, conf) { 48 | callback(null, data); 49 | }) 50 | .error(function (data, status, headers, conf) { 51 | // just send back the error 52 | callback(data); 53 | }); 54 | }; 55 | } 56 | 57 | photoApp.service("albumProvider", albumProvider); 58 | 59 | })(); 60 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/app/services/configprops.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | photoApp.constant("appConfigurationProps", { 4 | json_server_host: "localhost", 5 | json_server_port: 8082 6 | }); 7 | 8 | })(); 9 | -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | 5 | input[type=text] { 6 | padding: 3px; 7 | border-radius: 5px; 8 | border: 1px solid #bbb; 9 | } 10 | 11 | .error { 12 | color: #a00; 13 | } 14 | 15 | textarea { 16 | padding: 3px; 17 | border-radius: 5px; 18 | border: 1px solid #bbb; 19 | } 20 | 21 | .album { 22 | width: 300px; 23 | float: left; 24 | margin-right: 10px; 25 | } 26 | 27 | div.album div.title { 28 | float: right; 29 | } 30 | 31 | 32 | div.album .panel-heading a { 33 | text-decoration: none; 34 | color: white; 35 | } 36 | div.album .panel-heading a:hover { 37 | text-decoration: underline; 38 | color: white; 39 | } -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson06/filters_directives/front/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson06/filters_directives/front/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson06/filters_directives/front/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson06/filters_directives/front/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/README.md: -------------------------------------------------------------------------------- 1 | NodePhotoServer 2 | =============== 3 | 4 | ## Installation instructions 5 | 6 | This server assumes you have Node 0.10.x installed somewhere on your computer and in your path. To install, just download the source for this tree or clone it somewhere on your local hard drive and then copy your AngularJS application to the front/ folder within it. 7 | 8 | 9 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/back/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "photo_server", 3 | "description": "Simple Demo backend for our photo server.", 4 | "private": true, 5 | "dependencies": { 6 | "async": "0.2.x", 7 | "express": "3.x" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/back/photo_albums.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "asdfasfd", 4 | "title": "asdf", 5 | "date": "2222/2/2", 6 | "description": "asdfasdf", 7 | "photos": [ 8 | { 9 | "filename": "IMG_20140420_144009.jpg", 10 | "date": "2014/3/20", 11 | "description": "nice" 12 | }, 13 | { 14 | "filename": "IMG_20140420_144013.jpg", 15 | "date": "2014/3/20", 16 | "description": "woo" 17 | }, 18 | { 19 | "filename": "IMG_20140420_144029.jpg", 20 | "date": "2014/3/20", 21 | "description": "fun" 22 | }, 23 | { 24 | "filename": "IMG_20140420_144034.jpg", 25 | "date": "2014/3/20", 26 | "description": "awesome" 27 | }, 28 | { 29 | "filename": "IMG_20140420_154149.jpg", 30 | "date": "2014/3/20", 31 | "description": "asdfasdf" 32 | }, 33 | { 34 | "filename": "IMG_20140420_154247.jpg", 35 | "date": "2014/3/20", 36 | "description": "dijpasdofij" 37 | }, 38 | { 39 | "filename": "IMG_20140419_164913.jpg", 40 | "date": "2014/3/19", 41 | "description": "d1" 42 | }, 43 | { 44 | "filename": "IMG_20140419_164918.jpg", 45 | "date": "2014/3/19", 46 | "description": "d2" 47 | }, 48 | { 49 | "filename": "IMG_20140419_165222.jpg", 50 | "date": "2014/3/19", 51 | "description": "d3" 52 | }, 53 | { 54 | "filename": "IMG_20140419_165227.jpg", 55 | "date": "2014/3/19", 56 | "description": "d4" 57 | }, 58 | { 59 | "filename": "IMG_20140419_165746.jpg", 60 | "date": "2014/3/19", 61 | "description": "d5" 62 | }, 63 | { 64 | "filename": "IMG_20140419_165750.jpg", 65 | "date": "2014/3/19", 66 | "description": "d6" 67 | }, 68 | { 69 | "filename": "IMG_20140419_165754.jpg", 70 | "date": "2014/3/19", 71 | "description": "d7" 72 | }, 73 | { 74 | "filename": "IMG_20140419_170230.jpg", 75 | "date": "2014/3/19", 76 | "description": "d8" 77 | }, 78 | { 79 | "filename": "IMG_20130319_140649.jpg", 80 | "date": "2013/2/19", 81 | "description": "undefined" 82 | }, 83 | { 84 | "filename": "IMG_20130319_154722.jpg", 85 | "date": "2013/2/19", 86 | "description": "undefined" 87 | }, 88 | { 89 | "filename": "IMG_20130319_154829.jpg", 90 | "date": "2013/2/19", 91 | "description": "undefined" 92 | }, 93 | { 94 | "filename": "IMG_20130319_163227.jpg", 95 | "date": "2013/2/19", 96 | "description": "undefined" 97 | }, 98 | { 99 | "filename": "IMG_20130319_163229.jpg", 100 | "date": "2013/2/19", 101 | "description": "undefined" 102 | }, 103 | { 104 | "filename": "IMG_20130319_163234.jpg", 105 | "date": "2013/2/19", 106 | "description": "undefined" 107 | } 108 | ] 109 | }, 110 | { 111 | "name": "asdfasdf", 112 | "title": "sadfasdfasdf", 113 | "date": "2014/01/01", 114 | "description": "asodfipjas dofijas pdfoijas dfpoiasdjf apsoid", 115 | "photos": [] 116 | }, 117 | { 118 | "name": "qwerqwerqwre", 119 | "title": "qwerty", 120 | "date": "2014/1/2", 121 | "description": "asdofijp asdofija spdfoiasj f", 122 | "photos": [] 123 | }, 124 | { 125 | "name": "zxcvzxcvzxcv", 126 | "title": "zxcvzxcv", 127 | "date": "2013/3/3", 128 | "description": "asivpjoidjfaspdo fij", 129 | "photos": [] 130 | }, 131 | { 132 | "name": "fishyfish", 133 | "title": "fish", 134 | "date": "2013/4/5", 135 | "description": "asdfsf", 136 | "photos": [] 137 | }, 138 | { 139 | "name": "dogcatfish", 140 | "title": "dog cat", 141 | "date": "2012/3/5", 142 | "description": "asdiofjpasfoi", 143 | "photos": [] 144 | } 145 | ] -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function AlbumListController ($scope, $location, albumProvider, $modal) { 4 | $scope.page_load_error = ""; 5 | $scope.done_loading = false; 6 | 7 | albumProvider.getAlbums(function (err, albums) { 8 | if (err) { 9 | $scope.page_load_error = "Unexpected error loading albums: " + err.message; 10 | } else { 11 | $scope.done_loading = true; 12 | $scope.albums = albums; 13 | } 14 | }); 15 | 16 | $scope.openAddAlbumDialog = function () { 17 | var addAlbumDialog = $modal.open({ 18 | size: "sm", 19 | templateUrl: 'myModalContent.html', 20 | controller: AddAlbumDialogController, 21 | resolve: { 22 | } 23 | }); 24 | 25 | addAlbumDialog.result.then(function (album_name) { 26 | $location.path("/album/" + album_name) 27 | }, function () { 28 | console.info('Modal dismissed at: ' + new Date()); 29 | }); 30 | }; 31 | } 32 | 33 | photoApp.controller("AlbumListController", AlbumListController); 34 | 35 | 36 | 37 | function AddAlbumDialogController ($scope, $location, $modalInstance, albumProvider) { 38 | $scope.add_album_error = ""; 39 | $scope.adding_album = {}; 40 | 41 | $scope.addAlbum = function (new_album) { 42 | albumProvider.addAlbum(new_album, function (err, album) { 43 | if (err) { 44 | if (err.code == "missing_title") 45 | $scope.add_album_error = "You need to give a title"; 46 | else if (err.code == "missing_description") 47 | $scope.add_album_error = "You need to give a description"; 48 | else if (err.code == "missing_date") 49 | $scope.add_album_error = "You need to give a date"; 50 | else if (err.code == "missing_name") 51 | $scope.add_album_error = "You need to give a name"; 52 | else if (err.code == "bad_date") 53 | $scope.add_album_error = "That doesn't look like a good date."; 54 | else if (err.code == "duplicate_album_name") 55 | $scope.add_album_error = "An album of that name already exists!"; 56 | else 57 | $scope.add_album_error = "A completely unexpected error occurred: " + err.code + " " + err.message; 58 | } else { 59 | $modalInstance.close($scope.adding_album.name); 60 | } 61 | }); 62 | }; 63 | 64 | 65 | 66 | $scope.ok = function () { 67 | $scope.addAlbum($scope.adding_album); 68 | }; 69 | 70 | $scope.cancel = function () { 71 | $modalInstance.dismiss('cancel'); 72 | }; 73 | }; 74 | 75 | photoApp.controller("AddAlbumDialogController", AddAlbumDialogController); 76 | 77 | 78 | })(); 79 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/controllers/albumuploadcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | 4 | function AlbumUploadController ($scope, $routeParams, albumProvider) { 5 | $scope.album_name = $routeParams.album_name; 6 | $scope.page_load_error = ""; 7 | $scope.descriptions = {}; 8 | 9 | albumProvider.getPhotosForAlbum($scope.album_name, function (err, photos) { 10 | if (err) { 11 | if (err.code == "not_found") 12 | $scope.page_load_error = "No such album. Are you doing this right?"; 13 | else 14 | $scope.page_load_error = "Unexpected error loading page: " + err.code + " " + err.message; 15 | } else { 16 | $scope.photos = photos; 17 | $scope.uploader = albumProvider.getUploader($scope.album_name, $scope); 18 | 19 | $scope.uploader.bind("completeall", function (event, items) { 20 | $scope.done_uploading = true; 21 | albumProvider.albumChanged($scope.album_name); 22 | }); 23 | 24 | 25 | $scope.uploader.bind("beforeupload", function (event, item) { 26 | var fn = _fix_filename(item.file.name); 27 | var d = item.file.lastModifiedDate; 28 | var dstr = d.getFullYear() + "/" + d.getMonth() + "/" + d.getDate(); 29 | 30 | item.formData = [{ 31 | filename: fn, 32 | date: dstr ? dstr : "", 33 | description: $scope.descriptions[item.file.name] 34 | }]; 35 | }); 36 | } 37 | }); 38 | 39 | } 40 | 41 | photoApp.controller("AlbumUploadController", AlbumUploadController); 42 | 43 | 44 | 45 | /** 46 | * we'll be super fussy and only allow alnum, -, _, and . 47 | */ 48 | function _fix_filename(fn) { 49 | if (!fn || fn.length == 0) return "unknown"; 50 | 51 | var r = new RegExp("^[a-zA-Z0-9\\-_.]+$"); 52 | var out = ""; 53 | 54 | for (var i = 0; i < fn.length; i++) { 55 | if (r.exec(fn[i]) != null) 56 | out += fn[i]; 57 | } 58 | 59 | if (!out) out = "unknown_" + (new Date()).getTime(); 60 | return out; 61 | } 62 | 63 | 64 | 65 | 66 | 67 | })(); 68 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/controllers/albumviewcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | 4 | function AlbumViewController ($scope, $routeParams, albumProvider) { 5 | $scope.load_error_text = ""; 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.page_load_error = ""; 8 | $scope.album = null; 9 | 10 | albumProvider.getAlbum($scope.album_name, function (err, album) { 11 | if (err) { 12 | if (err.code == "not_found") 13 | $scope.page_load_error = "No such album. Are you doing this right?"; 14 | else 15 | $scope.page_load_error = "Unexpected error loading page: " + err.code + " " + err.message; 16 | } else { 17 | $scope.album = album; 18 | } 19 | }); 20 | 21 | } 22 | 23 | 24 | photoApp.controller("AlbumViewController", AlbumViewController); 25 | 26 | })(); 27 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/controllers/photoviewcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function PhotoViewController ($scope, $routeParams, albumProvider, $location, $rootScope) { 4 | $scope.album_name = $routeParams.album_name; 5 | $scope.page_load_error = ""; 6 | $scope.album = null; 7 | $scope.photo_filename = $routeParams.filename; 8 | $scope.photo_next_file = ''; 9 | $scope.photo_prev_file = ''; 10 | $scope.done_loading = false; 11 | $scope.description = ''; 12 | 13 | $rootScope.$on("keypress:39", function (e, ke) { 14 | if ($scope.photo_next_file) { 15 | setTimeout(function () { 16 | $scope.$apply(function () {$location.path("/album/" + $scope.album_name + "/photo/" + $scope.photo_next_file); }); 17 | }, 200); 18 | }; 19 | }); 20 | 21 | $rootScope.$on("keypress:37", function (e, ke) { 22 | if ($scope.photo_prev_file) { 23 | setTimeout(function () { 24 | $scope.$apply(function () {$location.path("/album/" + $scope.album_name + "/photo/" + $scope.photo_prev_file); }); 25 | }, 200); 26 | } 27 | }); 28 | 29 | albumProvider.getAlbum($scope.album_name, function (err, album) { 30 | if (err) { 31 | if (err.code == "not_found") 32 | $scope.page_load_error = "No such album. Are you doing this right?"; 33 | else 34 | $scope.page_load_error = "Unexpected error loading page: " + err.code + " " + err.message; 35 | } else { 36 | $scope.album = album; 37 | for (var i = 0; i < album.photos.length; i++) { 38 | if (album.photos[i].filename == $scope.photo_filename) { 39 | $scope.description = album.photos[i].description; 40 | if (i) $scope.photo_prev_file = album.photos[i -1].filename; 41 | if (i < album.photos.length - 1) 42 | $scope.photo_next_file = album.photos[i + 1].filename; 43 | break; 44 | } 45 | } 46 | 47 | if (i == album.photos.length) 48 | $scope.page_load_error = "This photo does not appear to exist."; 49 | else 50 | $scope.done_loading = true; 51 | } 52 | }); 53 | 54 | } 55 | 56 | 57 | photoApp.controller("PhotoViewController", PhotoViewController); 58 | 59 | })(); 60 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/partials/.#album_uploader.html: -------------------------------------------------------------------------------- 1 | livelessons@Kimidori.local.7430 -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/partials/album_list_partial.html: -------------------------------------------------------------------------------- 1 | 2 |
{{ page_load_error }}
3 | 4 |
Loading page data ....
5 | 6 | 7 |
8 | 9 |
10 |

11 |

12 | Displaying {{ albums.length | pluralise:{ sing: "album", plur: "albums"} }}: 13 |

14 | 15 | 16 | 17 |
18 | 19 | 20 |
21 | 51 |
52 | 53 | 54 | 55 |
56 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/partials/album_uploader.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
{{page_load_error}}
5 | 6 |

7 | 8 |

9 | 10 | 11 |
13 |
Name: {{ item.file.name }}
14 |
Size: {{ item.file.size/1024/1024|number:2 }} Mb
15 | 16 |
17 |
Description:
18 | 19 |
20 | 21 |

22 | Upload Progress: {{ item.progress }} 23 |

24 |
25 |
26 |

27 | 28 |
29 | 30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 | Total progress: {{ uploader.progress }} 38 |
39 |
40 |
41 |
42 | 43 | 44 | 45 |
46 | 47 | 48 |
49 | 50 | 51 | 52 |
53 | 54 | 55 |
56 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/partials/album_view_partial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 | Back to Albums 8 |
9 | 10 |
{{ page_load_error }}
11 | 12 |

{{ album.title }} ({{ album.name }})

13 | 14 |
{{ load_error_text }}
15 | 16 |
17 |
18 | {{ album.description }} 19 |
20 |
21 | 22 |
23 |
24 | 25 | 26 | 27 |
28 |

29 | {{ photo.description }} 30 |

31 |
32 | 33 |
34 | 35 |

36 | 37 | 38 | 39 |

40 | 41 |
42 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/partials/pa-album-directive.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | {{ albumdata.title }} 5 | 6 |
7 |
{{ albumdata.description }}
8 |
9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/partials/photo_view.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | 9 |
10 | {{ load_error_text }} 11 |
12 | 13 |
14 | Loading ... 15 |
16 |
17 |
18 | Back to Album 19 |
20 |
21 |
22 |
23 | Next 24 |
25 |
26 | Prev 27 |
28 |
29 | 30 |
31 |
32 |
33 | {{ description }} 34 | This is something a wee bit longer that I hope will wrap and show me the correc tpath to enlightenment. Only through fire shall our sins be cleansed. 35 |
36 |
37 | 38 |
39 |
40 | 41 | 42 |
43 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/app/services/albumservice.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function albumProvider ($http, $fileUploader) { 4 | 5 | var album_cache = {}; 6 | 7 | this.getUploader = function (album_name, scope) { 8 | return $fileUploader.create({ 9 | scope: scope, 10 | method: "PUT", 11 | url: "/v1/albums/" + album_name + "/photos.json" 12 | }); 13 | }; 14 | 15 | this.albumChanged = function (name) { 16 | if (album_cache[name]) delete album_cache[name]; 17 | }; 18 | 19 | this.getAlbums = function (callback) { 20 | $http.get("/v1/albums.json") 21 | .success(function (data, status, headers, conf) { 22 | callback(null, data); 23 | }) 24 | .error(function (data, status, headers, conf) { 25 | callback(data); 26 | }); 27 | }; 28 | 29 | this.getAlbum = function (name, callback) { 30 | if (album_cache[name]) return callback(null, album_cache[name]); 31 | 32 | $http.get("/v1/albums/" + name + ".json") 33 | .success(function (data, status, headers, conf) { 34 | album_cache[name] = data; 35 | callback(null, data); 36 | }) 37 | .error(function (data, status, headers, conf) { 38 | callback(data); 39 | }); 40 | }; 41 | 42 | this.getPhotosForAlbum = function (name, callback) { 43 | if (album_cache[name]) return callback(null, album_cache[name].photos); 44 | 45 | $http.get("/v1/albums/" + name + "/photos.json") 46 | .success(function (data, status, headers, conf) { 47 | album_cache[name] = data; 48 | callback(null, data); 49 | }) 50 | .error(function (data, status, headers, conf) { 51 | callback(data); 52 | }); 53 | }; 54 | 55 | 56 | this.addAlbum = function (album_data, callback) { 57 | 58 | if (!album_data.name) return callback({ code: "missing_name" }); 59 | if (!album_data.title) return callback({ code: "missing_title" }); 60 | if (!album_data.description) return callback({ code: "missing_description" }); 61 | if (!album_data.date) return callback({ code: "missing_date" }); 62 | if (!is_valid_date(album_data.date)) return callback({ code: "bad_date" }); 63 | 64 | $http.put("/v1/albums.json", album_data) 65 | .success(function (data, status, headers, conf) { 66 | callback(null, data); 67 | }) 68 | .error(function (data, status, headers, conf) { 69 | callback(data); 70 | }); 71 | }; 72 | } 73 | 74 | photoApp.service("albumProvider", albumProvider); 75 | 76 | 77 | 78 | 79 | 80 | function is_valid_date(the_date) { 81 | if (the_date.match(/^[0-9]{2,4}[\-\/\. ,][0-9]{1,2}[\-\/\. ,][0-9]{1,2}$/)) { 82 | var d = new Date(the_date); 83 | return !isNaN(d.getTime()); 84 | } else { 85 | return false; 86 | } 87 | } 88 | 89 | 90 | 91 | })(); 92 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | div#top_bar { 7 | text-align: left; 8 | background-color: #f2f2f2; 9 | border-bottom: 1px solid #ddd; 10 | height: 60px; 11 | } 12 | 13 | 14 | div#top_bar a { 15 | text-decoration: none; 16 | } 17 | div#top_bar .glyphicon { 18 | float: left; 19 | font-size: 400%; 20 | padding-left: 20px; 21 | padding-bottom: 10px; 22 | padding-top: 3px; 23 | padding-right: 20px; 24 | color: #666; 25 | } 26 | 27 | div#top_bar div#title { 28 | border-left: 1px solid #ccc; 29 | font-family: Helvetica; 30 | font-size: 28px; 31 | height: 60px; 32 | padding-left: 10px; 33 | margin-left: 95px; 34 | padding-top: 12px; 35 | font-weight: 100; 36 | color: #666; 37 | } 38 | 39 | 40 | input[type=text] { 41 | padding: 3px; 42 | border-radius: 4px; 43 | border: 1px solid #bbb; 44 | } 45 | 46 | textarea { 47 | padding: 3px; 48 | border-radius: 4px; 49 | border: 1px solid #bbb; 50 | } 51 | 52 | 53 | div.album { 54 | float: left; 55 | width: 300px; 56 | margin-right: 10px; 57 | min-height: 200px; 58 | } 59 | 60 | div.album div.description { 61 | padding: 5px; 62 | } 63 | 64 | div.album div.panel-heading a { 65 | color: white; 66 | } -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson07/01_cleaning_up/front/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson07/01_cleaning_up/front/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson07/01_cleaning_up/front/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
My Photo Albums
30 |
31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Lesson07/01_cleaning_up/front/js/angular-route.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.16 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()} 7 | var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){}, 8 | {prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b= 9 | "/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart", 10 | d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl= 11 | b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h !!!!", 110 | transclude: true, 111 | link: function ($scope, element, attrs) { 112 | element.css({ 113 | "background-color": "yellow", 114 | color: "red", 115 | padding: "10px", 116 | "font-weight": "bold" 117 | }); 118 | } 119 | }; 120 | }); 121 | 122 | 123 | 124 | photoApp.directive("paAlbum", function () { 125 | return { 126 | restrict: "AE", 127 | scope: { 128 | albumdata: "=" 129 | }, 130 | templateUrl: "/app/partials/pa-album-directive.html", 131 | link: function ($scope, element, attrs) { 132 | // do nothing 133 | } 134 | } 135 | }); 136 | 137 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/controllers/albumlistcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function AlbumListController ($scope, $location, albumProvider, $modal) { 4 | $scope.page_load_error = ""; 5 | $scope.done_loading = false; 6 | 7 | albumProvider.getAlbums(function (err, albums) { 8 | if (err) { 9 | $scope.page_load_error = "Unexpected error loading albums: " + err.message; 10 | } else { 11 | $scope.done_loading = true; 12 | $scope.albums = albums; 13 | } 14 | }); 15 | 16 | $scope.openAddAlbumDialog = function () { 17 | var addAlbumDialog = $modal.open({ 18 | size: "sm", 19 | templateUrl: 'myModalContent.html', 20 | controller: AddAlbumDialogController, 21 | resolve: { 22 | } 23 | }); 24 | 25 | addAlbumDialog.result.then(function (album_name) { 26 | $location.path("/album/" + album_name) 27 | }, function () { 28 | console.info('Modal dismissed at: ' + new Date()); 29 | }); 30 | }; 31 | } 32 | 33 | photoApp.controller("AlbumListController", AlbumListController); 34 | 35 | 36 | 37 | function AddAlbumDialogController ($scope, $location, $modalInstance, albumProvider) { 38 | $scope.add_album_error = ""; 39 | $scope.adding_album = {}; 40 | 41 | $scope.addAlbum = function (new_album) { 42 | albumProvider.addAlbum(new_album, function (err, album) { 43 | if (err) { 44 | if (err.code == "missing_title") 45 | $scope.add_album_error = "You need to give a title"; 46 | else if (err.code == "missing_description") 47 | $scope.add_album_error = "You need to give a description"; 48 | else if (err.code == "missing_date") 49 | $scope.add_album_error = "You need to give a date"; 50 | else if (err.code == "missing_name") 51 | $scope.add_album_error = "You need to give a name"; 52 | else if (err.code == "bad_date") 53 | $scope.add_album_error = "That doesn't look like a good date."; 54 | else if (err.code == "duplicate_album_name") 55 | $scope.add_album_error = "An album of that name already exists!"; 56 | else 57 | $scope.add_album_error = "A completely unexpected error occurred: " + err.code + " " + err.message; 58 | } else { 59 | $modalInstance.close($scope.adding_album.name); 60 | } 61 | }); 62 | }; 63 | 64 | 65 | 66 | $scope.ok = function () { 67 | $scope.addAlbum($scope.adding_album); 68 | }; 69 | 70 | $scope.cancel = function () { 71 | $modalInstance.dismiss('cancel'); 72 | }; 73 | }; 74 | 75 | photoApp.controller("AddAlbumDialogController", AddAlbumDialogController); 76 | 77 | 78 | })(); 79 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/controllers/albumuploadcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | 4 | function AlbumUploadController ($scope, $routeParams, albumProvider) { 5 | $scope.album_name = $routeParams.album_name; 6 | $scope.page_load_error = ""; 7 | $scope.descriptions = {}; 8 | 9 | albumProvider.getPhotosForAlbum($scope.album_name, function (err, photos) { 10 | if (err) { 11 | if (err.code == "not_found") 12 | $scope.page_load_error = "No such album. Are you doing this right?"; 13 | else 14 | $scope.page_load_error = "Unexpected error loading page: " + err.code + " " + err.message; 15 | } else { 16 | $scope.photos = photos; 17 | $scope.uploader = albumProvider.getUploader($scope.album_name, $scope); 18 | 19 | $scope.uploader.bind("completeall", function (event, items) { 20 | $scope.done_uploading = true; 21 | albumProvider.albumChanged($scope.album_name); 22 | }); 23 | 24 | 25 | $scope.uploader.bind("beforeupload", function (event, item) { 26 | var fn = _fix_filename(item.file.name); 27 | var d = item.file.lastModifiedDate; 28 | var dstr = d.getFullYear() + "/" + d.getMonth() + "/" + d.getDate(); 29 | 30 | item.formData = [{ 31 | filename: fn, 32 | date: dstr ? dstr : "", 33 | description: $scope.descriptions[item.file.name] 34 | }]; 35 | }); 36 | } 37 | }); 38 | 39 | } 40 | 41 | photoApp.controller("AlbumUploadController", AlbumUploadController); 42 | 43 | 44 | 45 | /** 46 | * we'll be super fussy and only allow alnum, -, _, and . 47 | */ 48 | function _fix_filename(fn) { 49 | if (!fn || fn.length == 0) return "unknown"; 50 | 51 | var r = new RegExp("^[a-zA-Z0-9\\-_.]+$"); 52 | var out = ""; 53 | 54 | for (var i = 0; i < fn.length; i++) { 55 | if (r.exec(fn[i]) != null) 56 | out += fn[i]; 57 | } 58 | 59 | if (!out) out = "unknown_" + (new Date()).getTime(); 60 | return out; 61 | } 62 | 63 | 64 | 65 | 66 | 67 | })(); 68 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/controllers/albumviewcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | 4 | function AlbumViewController ($scope, $routeParams, albumProvider) { 5 | $scope.load_error_text = ""; 6 | $scope.album_name = $routeParams.album_name; 7 | $scope.page_load_error = ""; 8 | $scope.album = null; 9 | 10 | albumProvider.getAlbum($scope.album_name, function (err, album) { 11 | if (err) { 12 | if (err.code == "not_found") 13 | $scope.page_load_error = "No such album. Are you doing this right?"; 14 | else 15 | $scope.page_load_error = "Unexpected error loading page: " + err.code + " " + err.message; 16 | } else { 17 | $scope.album = album; 18 | } 19 | }); 20 | 21 | } 22 | 23 | 24 | photoApp.controller("AlbumViewController", AlbumViewController); 25 | 26 | })(); 27 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/controllers/photoviewcontroller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function PhotoViewController ($scope, $routeParams, albumProvider, $location, $rootScope) { 4 | $scope.album_name = $routeParams.album_name; 5 | $scope.page_load_error = ""; 6 | $scope.album = null; 7 | $scope.photo_filename = $routeParams.filename; 8 | $scope.photo_next_file = ''; 9 | $scope.photo_prev_file = ''; 10 | $scope.done_loading = false; 11 | $scope.description = ''; 12 | 13 | $rootScope.$on("keypress:39", function (e, ke) { 14 | if ($scope.photo_next_file) { 15 | setTimeout(function () { 16 | $scope.$apply(function () {$location.path("/album/" + $scope.album_name + "/photo/" + $scope.photo_next_file); }); 17 | }, 200); 18 | }; 19 | }); 20 | 21 | $rootScope.$on("keypress:37", function (e, ke) { 22 | if ($scope.photo_prev_file) { 23 | setTimeout(function () { 24 | $scope.$apply(function () {$location.path("/album/" + $scope.album_name + "/photo/" + $scope.photo_prev_file); }); 25 | }, 200); 26 | } 27 | }); 28 | 29 | albumProvider.getAlbum($scope.album_name, function (err, album) { 30 | if (err) { 31 | if (err.code == "not_found") 32 | $scope.page_load_error = "No such album. Are you doing this right?"; 33 | else 34 | $scope.page_load_error = "Unexpected error loading page: " + err.code + " " + err.message; 35 | } else { 36 | $scope.album = album; 37 | for (var i = 0; i < album.photos.length; i++) { 38 | if (album.photos[i].filename == $scope.photo_filename) { 39 | $scope.description = album.photos[i].description; 40 | if (i) $scope.photo_prev_file = album.photos[i -1].filename; 41 | if (i < album.photos.length - 1) 42 | $scope.photo_next_file = album.photos[i + 1].filename; 43 | break; 44 | } 45 | } 46 | 47 | if (i == album.photos.length) 48 | $scope.page_load_error = "This photo does not appear to exist."; 49 | else 50 | $scope.done_loading = true; 51 | } 52 | }); 53 | 54 | } 55 | 56 | 57 | photoApp.controller("PhotoViewController", PhotoViewController); 58 | 59 | })(); 60 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/partials/.#album_uploader.html: -------------------------------------------------------------------------------- 1 | livelessons@Kimidori.local.7430 -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/partials/album_list_partial.html: -------------------------------------------------------------------------------- 1 | 2 |
{{ page_load_error }}
3 | 4 |
Loading page data ....
5 | 6 | 7 |
8 | 9 |
10 |

11 |

12 | Displaying {{ albums.length | pluralise:{ sing: "album", plur: "albums"} }}: 13 |

14 | 15 | 16 | 17 |
18 | 19 | 20 |
21 | 51 |
52 | 53 | 54 | 55 |
56 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/partials/album_uploader.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
{{page_load_error}}
5 | 6 |

7 | 8 |

9 | 10 | 11 |
13 |
Name: {{ item.file.name }}
14 |
Size: {{ item.file.size/1024/1024|number:2 }} Mb
15 | 16 |
17 |
Description:
18 | 19 |
20 | 21 |

22 | Upload Progress: {{ item.progress }} 23 |

24 |
25 |
26 |

27 | 28 |
29 | 30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 | Total progress: {{ uploader.progress }} 38 |
39 |
40 |
41 |
42 | 43 | 44 | 45 |
46 | 47 | 48 |
49 | 50 | 51 | 52 |
53 | 54 | 55 |
56 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/partials/album_view_partial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 | Back to Albums 8 |
9 | 10 |
{{ page_load_error }}
11 | 12 |

{{ album.title }} ({{ album.name }})

13 | 14 |
{{ load_error_text }}
15 | 16 |
17 |
18 | {{ album.description }} 19 |
20 |
21 | 22 |
23 |
24 | 25 | 26 | 27 |
28 |

29 | {{ photo.description }} 30 |

31 |
32 | 33 |
34 | 35 |

36 | 37 | 38 | 39 |

40 | 41 |
42 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/partials/pa-album-directive.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
{{ albumdata.description }}
8 |
9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/partials/photo_view.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | 9 |
10 | {{ load_error_text }} 11 |
12 | 13 |
14 | Loading ... 15 |
16 |
17 |
18 | Back to Album 19 |
20 |
21 |
22 |
23 | Next 24 |
25 |
26 | Prev 27 |
28 |
29 | 30 |
31 |
32 |
33 | {{ description }} 34 | This is something a wee bit longer that I hope will wrap and show me the correc tpath to enlightenment. Only through fire shall our sins be cleansed. 35 |
36 |
37 | 38 |
39 |
40 | 41 | 42 |
43 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/app/services/albumservice.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | function albumProvider ($http, $fileUploader) { 4 | 5 | var album_cache = {}; 6 | 7 | this.getUploader = function (album_name, scope) { 8 | return $fileUploader.create({ 9 | scope: scope, 10 | method: "PUT", 11 | url: "/v1/albums/" + album_name + "/photos.json" 12 | }); 13 | }; 14 | 15 | this.albumChanged = function (name) { 16 | if (album_cache[name]) delete album_cache[name]; 17 | }; 18 | 19 | this.getAlbums = function (callback) { 20 | $http.get("/v1/albums.json") 21 | .success(function (data, status, headers, conf) { 22 | callback(null, data); 23 | }) 24 | .error(function (data, status, headers, conf) { 25 | callback(data); 26 | }); 27 | }; 28 | 29 | this.getAlbum = function (name, callback) { 30 | if (album_cache[name]) return callback(null, album_cache[name]); 31 | 32 | $http.get("/v1/albums/" + name + ".json") 33 | .success(function (data, status, headers, conf) { 34 | album_cache[name] = data; 35 | callback(null, data); 36 | }) 37 | .error(function (data, status, headers, conf) { 38 | callback(data); 39 | }); 40 | }; 41 | 42 | this.getPhotosForAlbum = function (name, callback) { 43 | if (album_cache[name]) return callback(null, album_cache[name].photos); 44 | 45 | $http.get("/v1/albums/" + name + "/photos.json") 46 | .success(function (data, status, headers, conf) { 47 | album_cache[name] = data; 48 | callback(null, data); 49 | }) 50 | .error(function (data, status, headers, conf) { 51 | callback(data); 52 | }); 53 | }; 54 | 55 | 56 | this.addAlbum = function (album_data, callback) { 57 | 58 | if (!album_data.name) return callback({ code: "missing_name" }); 59 | if (!album_data.title) return callback({ code: "missing_title" }); 60 | if (!album_data.description) return callback({ code: "missing_description" }); 61 | if (!album_data.date) return callback({ code: "missing_date" }); 62 | if (!is_valid_date(album_data.date)) return callback({ code: "bad_date" }); 63 | 64 | $http.put("/v1/albums.json", album_data) 65 | .success(function (data, status, headers, conf) { 66 | callback(null, data); 67 | }) 68 | .error(function (data, status, headers, conf) { 69 | callback(data); 70 | }); 71 | }; 72 | } 73 | 74 | photoApp.service("albumProvider", albumProvider); 75 | 76 | 77 | 78 | 79 | 80 | function is_valid_date(the_date) { 81 | if (the_date.match(/^[0-9]{2,4}[\-\/\. ,][0-9]{1,2}[\-\/\. ,][0-9]{1,2}$/)) { 82 | var d = new Date(the_date); 83 | return !isNaN(d.getTime()); 84 | } else { 85 | return false; 86 | } 87 | } 88 | 89 | 90 | 91 | })(); 92 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | div#top_bar { 7 | text-align: left; 8 | background-color: #f2f2f2; 9 | border-bottom: 1px solid #ddd; 10 | height: 60px; 11 | } 12 | 13 | 14 | div#top_bar a { 15 | text-decoration: none; 16 | } 17 | div#top_bar .glyphicon { 18 | float: left; 19 | font-size: 400%; 20 | padding-left: 20px; 21 | padding-bottom: 10px; 22 | padding-top: 3px; 23 | padding-right: 20px; 24 | color: #666; 25 | } 26 | 27 | div#top_bar div#title { 28 | border-left: 1px solid #ccc; 29 | font-family: Helvetica; 30 | font-size: 28px; 31 | height: 60px; 32 | padding-left: 10px; 33 | margin-left: 95px; 34 | padding-top: 12px; 35 | font-weight: 100; 36 | color: #666; 37 | } 38 | 39 | 40 | input[type=text] { 41 | padding: 3px; 42 | border-radius: 4px; 43 | border: 1px solid #bbb; 44 | } 45 | 46 | textarea { 47 | padding: 3px; 48 | border-radius: 4px; 49 | border: 1px solid #bbb; 50 | } 51 | 52 | 53 | div.album { 54 | float: left; 55 | width: 300px; 56 | margin-right: 10px; 57 | min-height: 200px; 58 | } 59 | 60 | div.album div.description { 61 | padding: 5px; 62 | } 63 | 64 | div.album div.panel-heading a { 65 | color: white; 66 | } -------------------------------------------------------------------------------- /Lesson07/02_testing/front/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson07/02_testing/front/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Lesson07/02_testing/front/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson07/02_testing/front/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Lesson07/02_testing/front/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcwan/AngularJSLiveLessons/cef58c015affd54f775a5415d81fa4799aa76f1e/Lesson07/02_testing/front/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Lesson07/02_testing/front/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
My Photo Albums
30 |
31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Lesson07/02_testing/front/js/angular-route.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.16 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()} 7 | var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){}, 8 | {prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b= 9 | "/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart", 10 | d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl= 11 | b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h