├── .gitignore
├── README.md
├── data
├── bookmarks
│ └── default.json
└── categories
│ └── default.json
├── gulp
├── gulp.config.js
├── module.prefix
└── module.suffix
├── gulpfile.js
├── package.json
├── server
├── server-config.js
└── server.js
├── src
├── app
│ ├── categories
│ │ ├── bookmarks
│ │ │ ├── bookmarks.js
│ │ │ ├── bookmarks.tmpl.html
│ │ │ ├── create
│ │ │ │ ├── bookmark-create.js
│ │ │ │ └── bookmark-create.tmpl.html
│ │ │ └── edit
│ │ │ │ ├── bookmark-edit.js
│ │ │ │ └── bookmark-edit.tmpl.html
│ │ ├── categories.js
│ │ └── categories.tmpl.html
│ ├── common
│ │ └── models
│ │ │ ├── bookmarks-model.js
│ │ │ └── categories-model.js
│ └── eggly-app.js
├── assets
│ ├── fonts
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ └── img
│ │ └── eggly-logo.png
├── index.html
└── less
│ ├── animations.less
│ ├── eggly.less
│ └── main.less
└── vendor
└── angular-ui-router.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | build
3 | bin
4 | node_modules
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | eggly
2 | =====
3 |
4 | AngularJS bookmark manager.
5 |
--------------------------------------------------------------------------------
/data/bookmarks/default.json:
--------------------------------------------------------------------------------
1 | [
2 | {"id":0, "title": "AngularJS", "url": "http://angularjs.org", "category": "Development" },
3 | {"id":1, "title": "Egghead.io", "url": "http://egghead.io", "category": "Development" },
4 | {"id":2, "title": "A List Apart", "url": "http://alistapart.com/", "category": "Design" },
5 | {"id":3, "title": "One Page Love", "url": "http://onepagelove.com/", "category": "Design" },
6 | {"id":4, "title": "MobilityWOD", "url": "http://www.mobilitywod.com/", "category": "Exercise" },
7 | {"id":5, "title": "Robb Wolf", "url": "http://robbwolf.com/", "category": "Exercise" },
8 | {"id":6, "title": "Senor Gif", "url": "http://memebase.cheezburger.com/senorgif", "category": "Humor" },
9 | {"id":7, "title": "Wimp", "url": "http://wimp.com", "category": "Humor" },
10 | {"id":8, "title": "Dump", "url": "http://dump.com", "category": "Humor" }
11 | ]
--------------------------------------------------------------------------------
/data/categories/default.json:
--------------------------------------------------------------------------------
1 | [
2 | {"id": 0, "name": "Development"},
3 | {"id": 1, "name": "Design"},
4 | {"id": 2, "name": "Exercise"},
5 | {"id": 3, "name": "Humor"}
6 | ]
--------------------------------------------------------------------------------
/gulp/gulp.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |
3 | build_dir: 'build',
4 | compile_dir: 'bin',
5 | server: 'server/server.js',
6 |
7 | app_files: {
8 | // source, but NO specs
9 | js: ['src/**/*.js', '!src/**/*.spec.js'],
10 | js_compile: ['gulp/module.prefix', 'build/app/**/*.js', 'build/vendor/**/*.js', 'gulp/module.suffix'],
11 | vendor: ['vendor/**/*.js'],
12 | jsunit: ['src/**/*.spec.js'],
13 | // our partial templates
14 | atpl: ['src/app/**/*.tmpl.html', 'src/common/**/*.tmpl.html'],
15 | tpl_src: ["./build/vendor/**/*.js", "./build/app/**/*.js", "./build/assets/css/**/*.css"],
16 | // the index.html
17 | html: ['src/index.html'],
18 | less: 'src/less/main.less',
19 | styles: ['src/less/**/*.less'],
20 | data_compile: ['build/data/**/*.*'],
21 | assets_compile: ['build/assets/**/*.*', '!build/assets/css/**/*.*'],
22 | ngmin_js: ['./bin/**/*.js']
23 | },
24 |
25 | test_files: {
26 | js: [
27 | 'node_modules/jquery/dist/jquery.js',
28 | 'node_modules/angular-mocks/angular-mocks.js',
29 | 'node_modules/jasmine-jquery/lib/jasmine-jquery.js'
30 | ]
31 | },
32 |
33 | vendor_files: {
34 | // the vendor/ needs to be prefixed by the task
35 | js: [
36 | 'angular-ui-router.min.js'
37 | ],
38 | css: [],
39 | assets: []
40 | }
41 | };
--------------------------------------------------------------------------------
/gulp/module.prefix:
--------------------------------------------------------------------------------
1 | ;(function(window, angular, undefined) {
2 | "use strict;"
--------------------------------------------------------------------------------
/gulp/module.suffix:
--------------------------------------------------------------------------------
1 |
2 |
3 | }(window, angular, undefined));
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | del = require('del'),
3 | less = require('gulp-less'),
4 | inject = require("gulp-inject"),
5 | runSequence = require('run-sequence'),
6 | rename = require("gulp-rename"),
7 | nodemon = require('gulp-nodemon'),
8 | concat = require('gulp-concat'),
9 | html2js = require("gulp-ng-html2js"),
10 | ngmin = require("gulp-ng-annotate"),
11 | _ = require('lodash'),
12 | uglify = require('gulp-uglify'),
13 | pkg = require('./package.json'),
14 | jshint = require('gulp-jshint');
15 |
16 |
17 | var files = require('./gulp/gulp.config.js');
18 |
19 | /*
20 | The primary build task. We use runSequence to prevent any race-conditions.
21 | These conditions can occur because Gulp runs in parallel.
22 |
23 | We pass in a callback so that runSequence can notify gulp that the sequence is complete.
24 | */
25 | gulp.task('build', function (callback) {
26 | runSequence('clean',
27 | 'copy-build',
28 | 'html2js',
29 | 'less',
30 | 'index',
31 | callback);
32 | });
33 |
34 | /*
35 | The defualt task that runs when we type "gulp"
36 | */
37 | gulp.task('default', function (callback) {
38 | runSequence('build',
39 | 'watch',
40 | 'serve',
41 | callback);
42 | });
43 |
44 | /*
45 | Selectively build JUST the JS source.
46 | */
47 | gulp.task('build-src', function (callback) {
48 | runSequence('copy-build', 'index', callback)
49 | });
50 |
51 | /*
52 | Use 'del', a standard npm lib, to completely delete the build dir
53 | */
54 | gulp.task('clean', function () {
55 | return del(['./build'], {force: true});
56 | });
57 |
58 | /*
59 | Use 'del', a standard npm lib, to completely delete the bin (production) dir
60 | */
61 | gulp.task('clean-bin', function () {
62 | return del(['./bin'], {force: true});
63 | });
64 |
65 | gulp.task('copy-build', ['copy-assets', 'copy-app-js', 'copy-vendor-js']);
66 |
67 | gulp.task('copy-assets', function () {
68 | return gulp.src('./src/assets/**/*')
69 | .pipe(gulp.dest('./build/assets'));
70 | });
71 |
72 | gulp.task('copy-app-js', function () {
73 | return gulp.src(files.app_files.js)
74 | .pipe(gulp.dest('./build'));
75 | });
76 |
77 | gulp.task('copy-vendor-js', function () {
78 | return gulp.src(files.vendor_files.js, {cwd: 'vendor/**'})
79 | .pipe(gulp.dest('./build/vendor'));
80 | });
81 |
82 | gulp.task('copy-compile', ['copy-compile-assets']);
83 |
84 | gulp.task('copy-compile-assets', function () {
85 | return gulp.src(files.app_files.assets_compile)
86 | .pipe(gulp.dest('./bin/assets'));
87 | });
88 |
89 | gulp.task('html2js', function () {
90 | return gulp.src(files.app_files.atpl)
91 | .pipe(html2js({
92 | moduleName: "templates-app"
93 | }))
94 | .pipe(concat('templates-app.js'))
95 | .pipe(gulp.dest("./build/app"));
96 | });
97 |
98 | gulp.task('less', function () {
99 | return gulp.src('./src/less/main.less')
100 | .pipe(less({
101 | compile: true,
102 | compress: false,
103 | noUnderscores: false,
104 | noIDs: false,
105 | zeroUnits: false
106 | }))
107 | .pipe(rename(pkg.name + '-' + pkg.version + '.css'))
108 | .pipe(gulp.dest('./build/assets/css/'));
109 | });
110 |
111 | gulp.task('less-compile', function () {
112 | return gulp.src('./src/less/main.less')
113 | .pipe(less({
114 | compile: true,
115 | compress: true,
116 | noUnderscores: false,
117 | noIDs: false,
118 | zeroUnits: false
119 | }))
120 | .pipe(rename(pkg.name + '-' + pkg.version + '.css'))
121 | .pipe(gulp.dest('./bin/assets/css/'));
122 | });
123 |
124 | /*
125 | Used to populate the index.html template with JS sources
126 | from the "build" dir.
127 | */
128 | gulp.task('index', function () {
129 | return gulp.src('./src/index.html')
130 | .pipe(inject(
131 | gulp.src(files.app_files.tpl_src), {
132 | ignorePath: 'build'
133 | }))
134 | .pipe(gulp.dest("./build"));
135 | });
136 |
137 | /*
138 | Used to populate the index.html template with JS sources
139 | from the "bin" folder during compile task.
140 | */
141 | gulp.task('index-compile', function () {
142 | return gulp.src('./src/index.html')
143 | .pipe(inject(gulp.src(['./bin/**/*.js', './bin/**/*.css'], {read: false}), {
144 | ignorePath: files.compile_dir + '/'
145 | }))
146 | .pipe(gulp.dest("./" + files.compile_dir));
147 | });
148 |
149 | gulp.task('ngmin', function () {
150 | return gulp.src(files.app_files.ngmin_js)
151 | .pipe(ngmin())
152 | .pipe(gulp.dest(files.compile_dir));
153 | });
154 |
155 | gulp.task('uglify', function () {
156 | return gulp.src(files.app_files.ngmin_js)
157 | .pipe(uglify());
158 | });
159 |
160 | gulp.task('concat', function () {
161 |
162 | return gulp.src(files.app_files.js_compile)
163 | .pipe(concat(pkg.name + '-' + pkg.version + '.min.js'))
164 | .pipe(gulp.dest('./bin/assets'))
165 | });
166 |
167 | gulp.task('serve', function () {
168 | nodemon({script: files.server, watch: 'server/'})
169 | .on('restart', function () {
170 | console.log('restarted!')
171 | })
172 | });
173 |
174 | gulp.task('compile', function (callback) {
175 | runSequence('build',
176 | 'clean-bin',
177 | 'copy-compile',
178 | 'concat',
179 | 'ngmin',
180 | 'uglify',
181 | 'less-compile',
182 | 'index-compile',
183 | callback);
184 | });
185 |
186 | gulp.task('lint', function() {
187 | return gulp.src(files.app_files.js)
188 | .pipe(jshint())
189 | .pipe(jshint.reporter('default'));
190 | });
191 |
192 | gulp.task('watch', function () {
193 | gulp.watch(files.app_files.js, ['lint', 'build-src']);
194 | gulp.watch(files.app_files.atpl, ['html2js', 'index']);
195 | gulp.watch(files.app_files.html, ['index']);
196 | gulp.watch(files.app_files.styles, ['less', 'index']);
197 |
198 | gulp.watch('./src/config/**/*.json', ['config-build']);
199 | });
200 |
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "egghead-angularjs-eggly-build-automation",
3 | "version": "1.0.0",
4 | "description": "eggly =====",
5 | "main": "gulpfile.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "body-parser": "^1.11.0",
13 | "bootstrap": "^3.3.2",
14 | "cookie-parser": "^1.3.3",
15 | "del": "^2.2.0",
16 | "express": "^4.11.2",
17 | "fs": "0.0.2",
18 | "gulp": "^3.8.11",
19 | "gulp-concat": "^2.4.3",
20 | "gulp-inject": "^3.0.0",
21 | "gulp-jshint": "^2.0.0",
22 | "gulp-less": "^3.0.5",
23 | "gulp-ng-annotate": "^1.1.0",
24 | "gulp-ng-html2js": "^0.2.1",
25 | "gulp-nodemon": "^2.0.6",
26 | "gulp-rename": "^1.2.0",
27 | "gulp-uglify": "^1.1.0",
28 | "http": "0.0.0",
29 | "lodash": "^4.0.0",
30 | "run-sequence": "^1.0.2"
31 | },
32 | "dependencies": {
33 | "normalize.less": "^1.0.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/server/server-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | port: 3444,
3 | data_location: __dirname + '/../data/',
4 | rest_base_url: '/api',
5 | static_site_root: __dirname + '/../build' //up a dir and find build
6 | };
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | var config = require('./server-config'),
2 | express = require('express'),
3 | app = express(),
4 | server = require('http').createServer(app),
5 | mockFileRoot = config.data_location,
6 | fs = require('fs');
7 |
8 | var cookieParser = require('cookie-parser');
9 | var bodyParser = require('body-parser');
10 |
11 |
12 | // CONFIG SERVER
13 | //allows us to write cookies
14 | app.use(cookieParser());
15 |
16 | //allows server to run as proxy
17 | app.enable('trust proxy');
18 | app.use(bodyParser.json());
19 | app.use(express.static(config.static_site_root));
20 |
21 | var responseCache = {};
22 |
23 | function getMock(path, cacheResponse) {
24 | var mockResponse = responseCache[path];
25 |
26 | cacheResponse = cacheResponse || false;
27 |
28 | if (!mockResponse) {
29 | mockResponse = fs.readFileSync(path);
30 | mockResponse = JSON.parse(mockResponse);
31 | if(cacheResponse) {
32 | responseCache[path] = mockResponse;
33 | }
34 | }
35 |
36 | return mockResponse;
37 | }
38 |
39 | /**
40 | * Sends `default.json` that matches the path of the request
41 | * from the data dir. Assumes a rigid directory structure that
42 | * matches the route exactly.
43 | *
44 | * @param req
45 | * @param res
46 | */
47 | function sendDefault(req, res) {
48 | var endpoint,
49 | splitPath = req.params[0].split('?')[0].split("/"),
50 | mockPath = mockFileRoot + req.params[0] + '/' + 'default.json',
51 | mockResponse;
52 |
53 | if (splitPath.length > 2)
54 | endpoint = splitPath[splitPath.length - 2];
55 |
56 | try {
57 |
58 | res.json(getMock(mockPath))
59 | } catch (err) {
60 | console.log("something bad happened", err);
61 | res.status(500).send(JSON.parse(err));
62 | }
63 | }
64 |
65 | app.get(config.rest_base_url + '/*', sendDefault);
66 | app.post(config.rest_base_url + '/*', sendDefault);
67 |
68 | // FIRE IT UP
69 |
70 | server.listen(config.port, function () {
71 | console.log("Express server listening on port %d", config.port);
72 | });
73 |
--------------------------------------------------------------------------------
/src/app/categories/bookmarks/bookmarks.js:
--------------------------------------------------------------------------------
1 | angular.module('categories.bookmarks', [
2 | 'categories.bookmarks.create',
3 | 'categories.bookmarks.edit',
4 | 'eggly.models.categories',
5 | 'eggly.models.bookmarks'
6 | ])
7 | .config(function ($stateProvider) {
8 | $stateProvider
9 | .state('eggly.categories.bookmarks', {
10 | url: 'categories/:category',
11 | //target the named 'ui-view' in ROOT (eggly) state named 'bookmarks'
12 | //to show bookmarks for a specific category
13 | views: {
14 | 'bookmarks@': {
15 | templateUrl: 'categories/bookmarks/bookmarks.tmpl.html',
16 | controller: 'BookmarksListCtrl as bookmarksListCtrl'
17 | }
18 | }
19 | })
20 | ;
21 | })
22 | .controller('BookmarksListCtrl', function ($stateParams, CategoriesModel, BookmarksModel) {
23 | var bookmarksListCtrl = this;
24 |
25 | CategoriesModel.setCurrentCategory($stateParams.category);
26 |
27 | BookmarksModel.getBookmarks()
28 | .then(function (bookmarks) {
29 | bookmarksListCtrl.bookmarks = bookmarks;
30 | });
31 |
32 | bookmarksListCtrl.getCurrentCategory = CategoriesModel.getCurrentCategory;
33 | bookmarksListCtrl.getCurrentCategoryName = CategoriesModel.getCurrentCategoryName;
34 | bookmarksListCtrl.deleteBookmark = BookmarksModel.deleteBookmark;
35 | })
36 |
37 | ;
38 |
39 |
--------------------------------------------------------------------------------
/src/app/categories/bookmarks/bookmarks.tmpl.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/app/categories/bookmarks/create/bookmark-create.js:
--------------------------------------------------------------------------------
1 | angular.module('categories.bookmarks.create', [
2 |
3 | ])
4 | .config(function ($stateProvider) {
5 | $stateProvider
6 | .state('eggly.categories.bookmarks.create', {
7 | url: '/bookmarks/create',
8 | //target the un-named 'ui-view' in PARENT states template
9 | templateUrl: 'categories/bookmarks/create/bookmark-create.tmpl.html',
10 | controller: 'CreateBookMarkCtrl as createBookmarkCtrl'
11 | })
12 | ;
13 | })
14 | .controller('CreateBookMarkCtrl', function($state, $stateParams, BookmarksModel) {
15 | var createBookmarkCtrl = this;
16 |
17 | function returnToBookmarks() {
18 | $state.go('eggly.categories.bookmarks', {
19 | category: $stateParams.category
20 | });
21 | }
22 |
23 | function cancelCreating() {
24 | returnToBookmarks();
25 | }
26 |
27 | function createBookmark() {
28 | BookmarksModel.createBookmark(createBookmarkCtrl.newBookmark);
29 | returnToBookmarks();
30 | }
31 |
32 | function resetForm() {
33 | createBookmarkCtrl.newBookmark = {
34 | title: '',
35 | url: '',
36 | category: $stateParams.category
37 | };
38 | }
39 |
40 | createBookmarkCtrl.cancelCreating = cancelCreating;
41 | createBookmarkCtrl.createBookmark = createBookmark;
42 |
43 | resetForm();
44 | });
--------------------------------------------------------------------------------
/src/app/categories/bookmarks/create/bookmark-create.tmpl.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/categories/bookmarks/edit/bookmark-edit.js:
--------------------------------------------------------------------------------
1 | angular.module('categories.bookmarks.edit', [])
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('eggly.categories.bookmarks.edit', {
5 | url: '/bookmarks/:bookmarkId/edit',
6 | //target the un-named 'ui-view' in PARENT states template
7 | templateUrl: 'categories/bookmarks/edit/bookmark-edit.tmpl.html',
8 | controller: 'EditBookmarkCtrl as editBookmarkCtrl'
9 | })
10 | ;
11 | })
12 | .controller('EditBookmarkCtrl', function ($state, $stateParams, BookmarksModel) {
13 | var editBookmarkCtrl = this;
14 |
15 | function returnToBookmarks() {
16 | $state.go('eggly.categories.bookmarks', {
17 | category: $stateParams.category
18 | });
19 | }
20 |
21 | function updateBookmark() {
22 | editBookmarkCtrl.bookmark = angular.copy(editBookmarkCtrl.editedBookmark);
23 | BookmarksModel.updateBookmark(editBookmarkCtrl.editedBookmark);
24 | returnToBookmarks();
25 | }
26 |
27 | function cancelEditing() {
28 | returnToBookmarks();
29 | }
30 |
31 | BookmarksModel.getBookmarkById($stateParams.bookmarkId)
32 | .then(function (bookmark) {
33 | if (bookmark) {
34 | editBookmarkCtrl.bookmark = bookmark;
35 | editBookmarkCtrl.editedBookmark = angular.copy(editBookmarkCtrl.bookmark);
36 | } else {
37 | returnToBookmarks();
38 | }
39 | });
40 |
41 | editBookmarkCtrl.cancelEditing = cancelEditing;
42 | editBookmarkCtrl.updateBookmark = updateBookmark;
43 | })
44 | ;
45 |
--------------------------------------------------------------------------------
/src/app/categories/bookmarks/edit/bookmark-edit.tmpl.html:
--------------------------------------------------------------------------------
1 | Editing {{editBookmarkCtrl.bookmark.title}}
2 |
3 |
--------------------------------------------------------------------------------
/src/app/categories/categories.js:
--------------------------------------------------------------------------------
1 | angular.module('categories', [
2 | 'eggly.models.categories'
3 | ])
4 | .config(function ($stateProvider) {
5 | $stateProvider
6 | .state('eggly.categories', {
7 | url: '/',
8 | views: {
9 | //target the ui-view named 'categories' in ROOT state (eggly)
10 | 'categories@': {
11 | controller: 'CategoriesListCtrl as categoriesListCtrl',
12 | templateUrl: 'categories/categories.tmpl.html'
13 | },
14 | //target the ui-view named 'bookmarks' in ROOT state (eggly)
15 | //to show all bookmarks for all categories
16 | 'bookmarks@': {
17 | controller: 'BookmarksListCtrl as bookmarksListCtrl',
18 | templateUrl: 'categories/bookmarks/bookmarks.tmpl.html'
19 | }
20 | }
21 | })
22 | ;
23 | })
24 | .controller('CategoriesListCtrl', function CategoriesListCtrl(CategoriesModel) {
25 | var categoriesListCtrl = this;
26 |
27 | CategoriesModel.getCategories()
28 | .then(function (result) {
29 | categoriesListCtrl.categories = result;
30 | });
31 | })
32 | ;
33 |
--------------------------------------------------------------------------------
/src/app/categories/categories.tmpl.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/app/common/models/bookmarks-model.js:
--------------------------------------------------------------------------------
1 | angular.module('eggly.models.bookmarks', [])
2 | .service('BookmarksModel', function ($http, $q) {
3 | var model = this,
4 | URLS = {
5 | FETCH: '/api/bookmarks'
6 | },
7 | bookmarks;
8 |
9 | function extract(result) {
10 | return result.data;
11 | }
12 |
13 | function cacheBookmarks(result) {
14 | bookmarks = extract(result);
15 | return bookmarks;
16 | }
17 |
18 | function findBookmark(bookmarkId) {
19 | return _.find(bookmarks, function (bookmark) {
20 | return bookmark.id === parseInt(bookmarkId, 10);
21 | });
22 | }
23 |
24 | model.getBookmarks = function () {
25 | var deferred = $q.defer();
26 |
27 | if (bookmarks) {
28 | deferred.resolve(bookmarks);
29 | } else {
30 | $http.get(URLS.FETCH).then(function(bookmarks){
31 | deferred.resolve(cacheBookmarks(bookmarks));
32 | });
33 | }
34 |
35 | return deferred.promise;
36 | };
37 |
38 | model.getBookmarkById = function (bookmarkId) {
39 | var deferred = $q.defer();
40 | if (bookmarks) {
41 | deferred.resolve(findBookmark(bookmarkId));
42 | } else {
43 | model.getBookmarks().then(function () {
44 | deferred.resolve(findBookmark(bookmarkId));
45 | });
46 | }
47 | return deferred.promise;
48 | };
49 |
50 | model.createBookmark = function (bookmark) {
51 | bookmark.id = bookmarks.length;
52 | bookmarks.push(bookmark);
53 | };
54 |
55 | model.updateBookmark = function (bookmark) {
56 | var index = _.findIndex(bookmarks, function (b) {
57 | return b.id == bookmark.id;
58 | });
59 |
60 | bookmarks[index] = bookmark;
61 | };
62 |
63 | model.deleteBookmark = function (bookmark) {
64 | _.remove(bookmarks, function (b) {
65 | return b.id == bookmark.id;
66 | });
67 | };
68 | })
69 |
70 | ;
71 |
--------------------------------------------------------------------------------
/src/app/common/models/categories-model.js:
--------------------------------------------------------------------------------
1 | angular.module('eggly.models.categories', [
2 |
3 | ])
4 | .service('CategoriesModel', function ($http, $q) {
5 | var model = this,
6 | URLS = {
7 | FETCH: '/api/categories'
8 | },
9 | categories,
10 | currentCategory;
11 |
12 | function extract(result) {
13 | return result.data;
14 | }
15 |
16 | function cacheCategories(result) {
17 | categories = extract(result);
18 | return categories;
19 | }
20 |
21 | model.getCategories = function() {
22 | return (categories) ? $q.when(categories) : $http.get(URLS.FETCH).then(cacheCategories);
23 | };
24 |
25 | model.setCurrentCategory = function(category) {
26 | return model.getCategoryByName(category).then(function(category) {
27 | currentCategory = category;
28 | });
29 | };
30 |
31 | model.getCurrentCategory = function() {
32 | return currentCategory;
33 | };
34 |
35 | model.getCurrentCategoryName = function() {
36 | return currentCategory ? currentCategory.name : '';
37 | };
38 |
39 | model.getCategoryByName = function(categoryName) {
40 | var deferred = $q.defer();
41 |
42 | function findCategory(){
43 | return _.find(categories, function(c){
44 | return c.name == categoryName;
45 | });
46 | }
47 |
48 | if(categories) {
49 | deferred.resolve(findCategory());
50 | } else {
51 | model.getCategories()
52 | .then(function() {
53 | deferred.resolve(findCategory());
54 | });
55 | }
56 |
57 | return deferred.promise;
58 | };
59 |
60 |
61 | })
62 | ;
63 |
--------------------------------------------------------------------------------
/src/app/eggly-app.js:
--------------------------------------------------------------------------------
1 | angular.module('Eggly', [
2 | 'ui.router',
3 | 'categories',
4 | 'categories.bookmarks',
5 | 'templates-app'
6 | ])
7 | .config(function ($stateProvider, $urlRouterProvider) {
8 | $stateProvider
9 | //abstract state serves as a PLACEHOLDER or NAMESPACE for application states
10 | .state('eggly', {
11 | url: '',
12 | abstract: true
13 | })
14 | ;
15 |
16 | $urlRouterProvider.otherwise('/');
17 | })
18 | ;
--------------------------------------------------------------------------------
/src/assets/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio/egghead-angularjs-eggly-build-automation/c897ee1a274c883bc0f5c716176148e5a54115e2/src/assets/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/src/assets/fonts/glyphicons-halflings-regular.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio/egghead-angularjs-eggly-build-automation/c897ee1a274c883bc0f5c716176148e5a54115e2/src/assets/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio/egghead-angularjs-eggly-build-automation/c897ee1a274c883bc0f5c716176148e5a54115e2/src/assets/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/src/assets/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio/egghead-angularjs-eggly-build-automation/c897ee1a274c883bc0f5c716176148e5a54115e2/src/assets/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/src/assets/img/eggly-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio/egghead-angularjs-eggly-build-automation/c897ee1a274c883bc0f5c716176148e5a54115e2/src/assets/img/eggly-logo.png
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Eggly
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/less/animations.less:
--------------------------------------------------------------------------------
1 | [ui-view].ng-enter, [ui-view].ng-leave {
2 | position: absolute;
3 | left: 0;
4 | right: 0;
5 | -webkit-transition:all .5s ease-in-out;
6 | -moz-transition:all .5s ease-in-out;
7 | -o-transition:all .5s ease-in-out;
8 | transition:all .5s ease-in-out;
9 | }
10 |
11 | [ui-view].ng-enter {
12 | opacity: 0;
13 | }
14 |
15 | [ui-view].ng-enter-active {
16 | opacity: 1;
17 | }
18 |
19 | [ui-view].ng-leave {
20 | opacity: 1;
21 | }
22 |
23 | [ui-view].ng-leave-active {
24 | opacity: 0;
25 | }
--------------------------------------------------------------------------------
/src/less/eggly.less:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | background-color: #D5DBD8;
4 | width: 100%;
5 | height: 100%;
6 | color: #4F534E;
7 | }
8 |
9 | a {
10 | color: #373A36;
11 | font-size: 24px;
12 | text-decoration: none;
13 | }
14 |
15 | a:hover {
16 | color: #5bc0de;
17 | }
18 |
19 | .btn, .btn:focus {
20 | outline: none !important;
21 | }
22 |
23 | .btn-link {
24 | color: #373A36;
25 | font-size: 24px;
26 | text-decoration: none !important;
27 | }
28 |
29 | .btn-link:hover {
30 | color: #5bc0de;
31 | }
32 |
33 | .sidebar a {
34 | color: #5bc0de;
35 | font-size: 30px;
36 | text-decoration: none;
37 | }
38 |
39 | .sub-header {
40 | padding-bottom: 10px;
41 | border-bottom: 1px solid #EEE;
42 | }
43 |
44 | .logo {
45 | padding: 20px;
46 | }
47 |
48 | .sidebar {
49 | display: none;
50 | padding-left: 0px;
51 | padding-right: 0px;
52 | }
53 |
54 | .sidebar > ul {
55 | margin: 0px;
56 | padding: 0px;
57 | }
58 |
59 | .sidebar .active {
60 | background-color: #D5DBD8;
61 | }
62 |
63 | .sidebar .active > a {
64 | text-decoration: none;
65 | color: #2B2828;
66 | }
67 |
68 | .main .active span,
69 | .main .active > a {
70 | color: #5bc0de;
71 | }
72 |
73 | .editing > button {
74 | color: #5bc0de !important;
75 | }
76 | .editing > a {
77 | color: #5bc0de !important;
78 | }
79 |
80 | .nav > li > a:hover, .nav > li > a:focus {
81 | text-decoration: none;
82 | background-color: #D5DBD8;
83 | }
84 |
85 | @media (min-width: 768px) {
86 | .sidebar {
87 | position: fixed;
88 | top: 0;
89 | bottom: 0;
90 | left: 0;
91 | z-index: 1000;
92 | display: block;
93 | overflow-x: hidden;
94 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
95 | background-color: #2B2828;
96 | border-right: 1px solid #7B807E;
97 | }
98 | }
99 |
100 | .main {
101 | padding-top: 96px;
102 | padding-left: 24px;
103 | }
104 |
105 | .createBookmark {
106 | padding-left: 5px;
107 | padding-right: 5px;
108 | }
109 |
110 | .create-form, .edit-form {
111 | padding: 20px;
112 | }
113 |
--------------------------------------------------------------------------------
/src/less/main.less:
--------------------------------------------------------------------------------
1 | @import "../../node_modules/normalize.less/normalize.less";
2 | @import '../../node_modules/bootstrap/less/bootstrap';
3 |
4 | @import "eggly";
5 | @import "animations";
--------------------------------------------------------------------------------
/vendor/angular-ui-router.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * State-based routing for AngularJS
3 | * @version v0.2.10
4 | * @link http://angular-ui.github.com/
5 | * @license MIT License, http://www.opensource.org/licenses/MIT
6 | */
7 | "undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ui.router"),function(a,b,c){"use strict";function d(a,b){return I(new(I(function(){},{prototype:a})),b)}function e(a){return H(arguments,function(b){b!==a&&H(b,function(b,c){a.hasOwnProperty(c)||(a[c]=b)})}),a}function f(a,b){var c=[];for(var d in a.path){if(a.path[d]!==b.path[d])break;c.push(a.path[d])}return c}function g(a,b){if(Array.prototype.indexOf)return a.indexOf(b,Number(arguments[2])||0);var c=a.length>>>0,d=Number(arguments[2])||0;for(d=0>d?Math.ceil(d):Math.floor(d),0>d&&(d+=c);c>d;d++)if(d in a&&a[d]===b)return d;return-1}function h(a,b,c,d){var e,h=f(c,d),i={},j=[];for(var k in h)if(h[k].params&&h[k].params.length){e=h[k].params;for(var l in e)g(j,e[l])>=0||(j.push(e[l]),i[e[l]]=a[e[l]])}return I({},i,b)}function i(a,b){var c={};return H(a,function(a){var d=b[a];c[a]=null!=d?String(d):null}),c}function j(a,b,c){if(!c){c=[];for(var d in a)c.push(d)}for(var e=0;e "));if(o[c]=d,E(a))m.push(c,[function(){return b.get(a)}],h);else{var e=b.annotate(a);H(e,function(a){a!==c&&g.hasOwnProperty(a)&&k(g[a],a)}),m.push(c,a,e)}n.pop(),o[c]=f}}function l(a){return F(a)&&a.then&&a.$$promises}if(!F(g))throw new Error("'invocables' must be an object");var m=[],n=[],o={};return H(g,k),g=n=o=null,function(d,f,g){function h(){--s||(t||e(r,f.$$values),p.$$values=r,p.$$promises=!0,o.resolve(r))}function k(a){p.$$failure=a,o.reject(a)}function n(c,e,f){function i(a){l.reject(a),k(a)}function j(){if(!C(p.$$failure))try{l.resolve(b.invoke(e,g,r)),l.promise.then(function(a){r[c]=a,h()},i)}catch(a){i(a)}}var l=a.defer(),m=0;H(f,function(a){q.hasOwnProperty(a)&&!d.hasOwnProperty(a)&&(m++,q[a].then(function(b){r[a]=b,--m||j()},i))}),m||j(),q[c]=l.promise}if(l(d)&&g===c&&(g=f,f=d,d=null),d){if(!F(d))throw new Error("'locals' must be an object")}else d=i;if(f){if(!l(f))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else f=j;var o=a.defer(),p=o.promise,q=p.$$promises={},r=I({},d),s=1+m.length/3,t=!1;if(C(f.$$failure))return k(f.$$failure),p;f.$$values?(t=e(r,f.$$values),h()):(I(q,f.$$promises),f.then(h,k));for(var u=0,v=m.length;v>u;u+=3)d.hasOwnProperty(m[u])?h():n(m[u],m[u+1],m[u+2]);return p}},this.resolve=function(a,b,c,d){return this.study(a)(b,c,d)}}function m(a,b,c){this.fromConfig=function(a,b,c){return C(a.template)?this.fromString(a.template,b):C(a.templateUrl)?this.fromUrl(a.templateUrl,b):C(a.templateProvider)?this.fromProvider(a.templateProvider,b,c):null},this.fromString=function(a,b){return D(a)?a(b):a},this.fromUrl=function(c,d){return D(c)&&(c=c(d)),null==c?null:a.get(c,{cache:b}).then(function(a){return a.data})},this.fromProvider=function(a,b,d){return c.invoke(a,null,d||{params:b})}}function n(a){function b(b){if(!/^\w+(-+\w+)*$/.test(b))throw new Error("Invalid parameter name '"+b+"' in pattern '"+a+"'");if(f[b])throw new Error("Duplicate parameter name '"+b+"' in pattern '"+a+"'");f[b]=!0,j.push(b)}function c(a){return a.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&")}var d,e=/([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,f={},g="^",h=0,i=this.segments=[],j=this.params=[];this.source=a;for(var k,l,m;(d=e.exec(a))&&(k=d[2]||d[3],l=d[4]||("*"==d[1]?".*":"[^/]*"),m=a.substring(h,d.index),!(m.indexOf("?")>=0));)g+=c(m)+"("+l+")",b(k),i.push(m),h=e.lastIndex;m=a.substring(h);var n=m.indexOf("?");if(n>=0){var o=this.sourceSearch=m.substring(n);m=m.substring(0,n),this.sourcePath=a.substring(0,h+n),H(o.substring(1).split(/[&?]/),b)}else this.sourcePath=a,this.sourceSearch="";g+=c(m)+"$",i.push(m),this.regexp=new RegExp(g),this.prefix=i[0]}function o(){this.compile=function(a){return new n(a)},this.isMatcher=function(a){return F(a)&&D(a.exec)&&D(a.format)&&D(a.concat)},this.$get=function(){return this}}function p(a){function b(a){var b=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(a.source);return null!=b?b[1].replace(/\\(.)/g,"$1"):""}function c(a,b){return a.replace(/\$(\$|\d{1,2})/,function(a,c){return b["$"===c?0:Number(c)]})}function d(a,b,c){if(!c)return!1;var d=a.invoke(b,b,{$match:c});return C(d)?d:!0}var e=[],f=null;this.rule=function(a){if(!D(a))throw new Error("'rule' must be a function");return e.push(a),this},this.otherwise=function(a){if(E(a)){var b=a;a=function(){return b}}else if(!D(a))throw new Error("'rule' must be a function");return f=a,this},this.when=function(e,f){var g,h=E(f);if(E(e)&&(e=a.compile(e)),!h&&!D(f)&&!G(f))throw new Error("invalid 'handler' in when()");var i={matcher:function(b,c){return h&&(g=a.compile(c),c=["$match",function(a){return g.format(a)}]),I(function(a,e){return d(a,c,b.exec(e.path(),e.search()))},{prefix:E(b.prefix)?b.prefix:""})},regex:function(a,e){if(a.global||a.sticky)throw new Error("when() RegExp must not be global or sticky");return h&&(g=e,e=["$match",function(a){return c(g,a)}]),I(function(b,c){return d(b,e,a.exec(c.path()))},{prefix:b(a)})}},j={matcher:a.isMatcher(e),regex:e instanceof RegExp};for(var k in j)if(j[k])return this.rule(i[k](e,f));throw new Error("invalid 'what' in when()")},this.$get=["$location","$rootScope","$injector",function(a,b,c){function d(b){function d(b){var d=b(c,a);return d?(E(d)&&a.replace().url(d),!0):!1}if(!b||!b.defaultPrevented){var g,h=e.length;for(g=0;h>g;g++)if(d(e[g]))return;f&&d(f)}}return b.$on("$locationChangeSuccess",d),{sync:function(){d()}}}]}function q(a,e,f){function g(a){return 0===a.indexOf(".")||0===a.indexOf("^")}function l(a,b){var d=E(a),e=d?a:a.name,f=g(e);if(f){if(!b)throw new Error("No reference point given for path '"+e+"'");for(var h=e.split("."),i=0,j=h.length,k=b;j>i;i++)if(""!==h[i]||0!==i){if("^"!==h[i])break;if(!k.parent)throw new Error("Path '"+e+"' not valid for state '"+b.name+"'");k=k.parent}else k=b;h=h.slice(i).join("."),e=k.name+(k.name&&h?".":"")+h}var l=w[e];return!l||!d&&(d||l!==a&&l.self!==a)?c:l}function m(a,b){x[a]||(x[a]=[]),x[a].push(b)}function n(b){b=d(b,{self:b,resolve:b.resolve||{},toString:function(){return this.name}});var c=b.name;if(!E(c)||c.indexOf("@")>=0)throw new Error("State must have a valid name");if(w.hasOwnProperty(c))throw new Error("State '"+c+"'' is already defined");var e=-1!==c.indexOf(".")?c.substring(0,c.lastIndexOf(".")):E(b.parent)?b.parent:"";if(e&&!w[e])return m(e,b.self);for(var f in z)D(z[f])&&(b[f]=z[f](b,z.$delegates[f]));if(w[c]=b,!b[y]&&b.url&&a.when(b.url,["$match","$stateParams",function(a,c){v.$current.navigable==b&&j(a,c)||v.transitionTo(b,a,{location:!1})}]),x[c])for(var g=0;g-1}function p(a){var b=a.split("."),c=v.$current.name.split(".");if("**"===b[0]&&(c=c.slice(c.indexOf(b[1])),c.unshift("**")),"**"===b[b.length-1]&&(c.splice(c.indexOf(b[b.length-2])+1,Number.MAX_VALUE),c.push("**")),b.length!=c.length)return!1;for(var d=0,e=b.length;e>d;d++)"*"===b[d]&&(c[d]="*");return c.join("")===b.join("")}function q(a,b){return E(a)&&!C(b)?z[a]:D(b)&&E(a)?(z[a]&&!z.$delegates[a]&&(z.$delegates[a]=z[a]),z[a]=b,this):this}function r(a,b){return F(a)?b=a:b.name=a,n(b),this}function s(a,e,g,m,n,q,r,s,x){function z(){r.url()!==M&&(r.url(M),r.replace())}function A(a,c,d,f,h){var i=d?c:k(a.params,c),j={$stateParams:i};h.resolve=n.resolve(a.resolve,j,h.resolve,a);var l=[h.resolve.then(function(a){h.globals=a})];return f&&l.push(f),H(a.views,function(c,d){var e=c.resolve&&c.resolve!==a.resolve?c.resolve:{};e.$template=[function(){return g.load(d,{view:c,locals:j,params:i,notify:!1})||""}],l.push(n.resolve(e,j,h.resolve,a).then(function(f){if(D(c.controllerProvider)||G(c.controllerProvider)){var g=b.extend({},e,j);f.$$controller=m.invoke(c.controllerProvider,null,g)}else f.$$controller=c.controller;f.$$state=a,f.$$controllerAs=c.controllerAs,h[d]=f}))}),e.all(l).then(function(){return h})}var B=e.reject(new Error("transition superseded")),F=e.reject(new Error("transition prevented")),K=e.reject(new Error("transition aborted")),L=e.reject(new Error("transition failed")),M=r.url(),N=x.baseHref();return u.locals={resolve:null,globals:{$stateParams:{}}},v={params:{},current:u.self,$current:u,transition:null},v.reload=function(){v.transitionTo(v.current,q,{reload:!0,inherit:!1,notify:!1})},v.go=function(a,b,c){return this.transitionTo(a,b,I({inherit:!0,relative:v.$current},c))},v.transitionTo=function(b,c,f){c=c||{},f=I({location:!0,inherit:!1,relative:null,notify:!0,reload:!1,$retry:!1},f||{});var g,k=v.$current,n=v.params,o=k.path,p=l(b,f.relative);if(!C(p)){var s={to:b,toParams:c,options:f};if(g=a.$broadcast("$stateNotFound",s,k.self,n),g.defaultPrevented)return z(),K;if(g.retry){if(f.$retry)return z(),L;var w=v.transition=e.when(g.retry);return w.then(function(){return w!==v.transition?B:(s.options.$retry=!0,v.transitionTo(s.to,s.toParams,s.options))},function(){return K}),z(),w}if(b=s.to,c=s.toParams,f=s.options,p=l(b,f.relative),!C(p)){if(f.relative)throw new Error("Could not resolve '"+b+"' from state '"+f.relative+"'");throw new Error("No such state '"+b+"'")}}if(p[y])throw new Error("Cannot transition to abstract state '"+b+"'");f.inherit&&(c=h(q,c||{},v.$current,p)),b=p;var x,D,E=b.path,G=u.locals,H=[];for(x=0,D=E[x];D&&D===o[x]&&j(c,n,D.ownParams)&&!f.reload;x++,D=E[x])G=H[x]=D.locals;if(t(b,k,G,f))return b.self.reloadOnSearch!==!1&&z(),v.transition=null,e.when(v.current);if(c=i(b.params,c||{}),f.notify&&(g=a.$broadcast("$stateChangeStart",b.self,c,k.self,n),g.defaultPrevented))return z(),F;for(var N=e.when(G),O=x;O=x;d--)g=o[d],g.self.onExit&&m.invoke(g.self.onExit,g.self,g.locals.globals),g.locals=null;for(d=x;d1||b.ctrlKey||b.metaKey||b.shiftKey||f.attr("target")||(c(function(){a.go(i.state,j,o)}),b.preventDefault())})}}}function y(a,b,c){return{restrict:"A",controller:["$scope","$element","$attrs",function(d,e,f){function g(){a.$current.self===i&&h()?e.addClass(l):e.removeClass(l)}function h(){return!k||j(k,b)}var i,k,l;l=c(f.uiSrefActive||"",!1)(d),this.$$setStateInfo=function(b,c){i=a.get(b,w(e)),k=c,g()},d.$on("$stateChangeSuccess",g)}]}}function z(a){return function(b){return a.is(b)}}function A(a){return function(b){return a.includes(b)}}function B(a,b){function e(a){this.locals=a.locals.globals,this.params=this.locals.$stateParams}function f(){this.locals=null,this.params=null}function g(c,g){if(null!=g.redirectTo){var h,j=g.redirectTo;if(E(j))h=j;else{if(!D(j))throw new Error("Invalid 'redirectTo' in when()");h=function(a,b){return j(a,b.path(),b.search())}}b.when(c,h)}else a.state(d(g,{parent:null,name:"route:"+encodeURIComponent(c),url:c,onEnter:e,onExit:f}));return i.push(g),this}function h(a,b,d){function e(a){return""!==a.name?a:c}var f={routes:i,params:d,current:c};return b.$on("$stateChangeStart",function(a,c,d,f){b.$broadcast("$routeChangeStart",e(c),e(f))}),b.$on("$stateChangeSuccess",function(a,c,d,g){f.current=e(c),b.$broadcast("$routeChangeSuccess",e(c),e(g)),J(d,f.params)}),b.$on("$stateChangeError",function(a,c,d,f,g,h){b.$broadcast("$routeChangeError",e(c),e(f),h)}),f}var i=[];e.$inject=["$$state"],this.when=g,this.$get=h,h.$inject=["$state","$rootScope","$routeParams"]}var C=b.isDefined,D=b.isFunction,E=b.isString,F=b.isObject,G=b.isArray,H=b.forEach,I=b.extend,J=b.copy;b.module("ui.router.util",["ng"]),b.module("ui.router.router",["ui.router.util"]),b.module("ui.router.state",["ui.router.router","ui.router.util"]),b.module("ui.router",["ui.router.state"]),b.module("ui.router.compat",["ui.router"]),l.$inject=["$q","$injector"],b.module("ui.router.util").service("$resolve",l),m.$inject=["$http","$templateCache","$injector"],b.module("ui.router.util").service("$templateFactory",m),n.prototype.concat=function(a){return new n(this.sourcePath+a+this.sourceSearch)},n.prototype.toString=function(){return this.source},n.prototype.exec=function(a,b){var c=this.regexp.exec(a);if(!c)return null;var d,e=this.params,f=e.length,g=this.segments.length-1,h={};if(g!==c.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(d=0;g>d;d++)h[e[d]]=c[d+1];for(;f>d;d++)h[e[d]]=b[e[d]];return h},n.prototype.parameters=function(){return this.params},n.prototype.format=function(a){var b=this.segments,c=this.params;if(!a)return b.join("");var d,e,f,g=b.length-1,h=c.length,i=b[0];for(d=0;g>d;d++)f=a[c[d]],null!=f&&(i+=encodeURIComponent(f)),i+=b[d+1];for(;h>d;d++)f=a[c[d]],null!=f&&(i+=(e?"&":"?")+c[d]+"="+encodeURIComponent(f),e=!0);return i},b.module("ui.router.util").provider("$urlMatcherFactory",o),p.$inject=["$urlMatcherFactoryProvider"],b.module("ui.router.router").provider("$urlRouter",p),q.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider","$locationProvider"],b.module("ui.router.state").value("$stateParams",{}).provider("$state",q),r.$inject=[],b.module("ui.router.state").provider("$view",r),b.module("ui.router.state").provider("$uiViewScroll",s),t.$inject=["$state","$injector","$uiViewScroll"],u.$inject=["$compile","$controller","$state"],b.module("ui.router.state").directive("uiView",t),b.module("ui.router.state").directive("uiView",u),x.$inject=["$state","$timeout"],y.$inject=["$state","$stateParams","$interpolate"],b.module("ui.router.state").directive("uiSref",x).directive("uiSrefActive",y),z.$inject=["$state"],A.$inject=["$state"],b.module("ui.router.state").filter("isState",z).filter("includedByState",A),B.$inject=["$stateProvider","$urlRouterProvider"],b.module("ui.router.compat").provider("$route",B).directive("ngView",t)}(window,window.angular);
--------------------------------------------------------------------------------