├── .gitignore ├── docs ├── html │ ├── favicon.ico │ └── nav.html ├── content │ ├── guide │ │ ├── templateProvider.ngdoc │ │ ├── 11-architecture.ngdoc │ │ ├── 05-conceptual.01-how-it-works.ngdoc │ │ ├── 05-conceptual.ngdoc │ │ ├── 21-lazy-loading-via-routing.ngdoc │ │ ├── index.ngdoc │ │ ├── 03-faq.ngdoc │ │ ├── 11-architecture.01-components.ngdoc │ │ └── 11-architecture.11-app-module-setup.ngdoc │ └── api │ │ └── index.ngdoc └── css │ └── style.css ├── dist ├── docs │ ├── font │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── css │ │ ├── style.css │ │ ├── animations.css │ │ ├── doc_widgets.css │ │ └── docs.css │ ├── partials │ │ ├── guide │ │ │ ├── templateProvider.html │ │ │ ├── 11-architecture.html │ │ │ ├── 05-conceptual.html │ │ │ ├── 05-conceptual.01-how-it-works.html │ │ │ ├── 21-lazy-loading-via-routing.html │ │ │ ├── 11-architecture.01-components.html │ │ │ ├── index.html │ │ │ ├── 03-faq.html │ │ │ └── 11-architecture.11-app-module-setup.html │ │ └── api │ │ │ ├── scs.couch-potato.$couchPotato.html │ │ │ ├── index.html │ │ │ ├── scs.couch-potato.$couchPotatoProvider.html │ │ │ └── scs.couch-potato.html │ ├── js │ │ ├── angular-bootstrap.min.js │ │ └── docs-setup.js │ └── index.html ├── samples │ ├── script-tags-ngroute │ │ ├── js │ │ │ ├── services │ │ │ │ ├── version.js │ │ │ │ └── myService2.js │ │ │ ├── controllers │ │ │ │ ├── myCtrl1.js │ │ │ │ └── myCtrl2.js │ │ │ ├── directives │ │ │ │ └── appVersion.js │ │ │ ├── filters │ │ │ │ └── interpolator.js │ │ │ └── app.js │ │ ├── partials │ │ │ ├── partial1.html │ │ │ └── partial2.html │ │ ├── css │ │ │ └── app.css │ │ └── index.html │ ├── requirejs-ui-router │ │ ├── partials │ │ │ ├── contacts.detail.item.html │ │ │ ├── contacts.detail.item.edit.html │ │ │ ├── contacts.list.html │ │ │ ├── contacts.detail.html │ │ │ └── contacts.html │ │ ├── app │ │ │ ├── services │ │ │ │ └── findById.js │ │ │ ├── app.js │ │ │ ├── controllers │ │ │ │ ├── contactsDetailController.js │ │ │ │ ├── contactsDetailItemController.js │ │ │ │ ├── contactsDetailItemEditController.js │ │ │ │ └── contactsController.js │ │ │ ├── config.js │ │ │ ├── run.js │ │ │ ├── app-init.js │ │ │ └── routeDefs.js │ │ ├── css │ │ │ └── styles.css │ │ └── index.html │ ├── README.md │ └── index.html ├── dependencies │ └── angular-ui-router.js └── angular-couch-potato.js ├── samples ├── script-tags-ngroute │ ├── js │ │ ├── services │ │ │ ├── version.js │ │ │ └── myService2.js │ │ ├── controllers │ │ │ ├── myCtrl1.js │ │ │ └── myCtrl2.js │ │ ├── directives │ │ │ └── appVersion.js │ │ ├── filters │ │ │ └── interpolator.js │ │ └── app.js │ ├── partials │ │ ├── partial1.html │ │ └── partial2.html │ ├── css │ │ └── app.css │ └── index.html ├── requirejs-ui-router │ ├── partials │ │ ├── contacts.detail.item.html │ │ ├── contacts.detail.item.edit.html │ │ ├── contacts.list.html │ │ ├── contacts.detail.html │ │ └── contacts.html │ ├── app │ │ ├── services │ │ │ └── findById.js │ │ ├── app.js │ │ ├── controllers │ │ │ ├── contactsDetailController.js │ │ │ ├── contactsDetailItemController.js │ │ │ ├── contactsDetailItemEditController.js │ │ │ └── contactsController.js │ │ ├── config.js │ │ ├── run.js │ │ ├── app-init.js │ │ └── routeDefs.js │ ├── css │ │ └── styles.css │ └── index.html ├── README.md └── index.html ├── server.js ├── .jshintrc ├── bower.json ├── package.json ├── LICENSE ├── README.md ├── Gruntfile.js └── src └── couchPotato.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.bak 4 | -------------------------------------------------------------------------------- /docs/html/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laurelnaiad/angular-couch-potato/HEAD/docs/html/favicon.ico -------------------------------------------------------------------------------- /dist/docs/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laurelnaiad/angular-couch-potato/HEAD/dist/docs/font/FontAwesome.otf -------------------------------------------------------------------------------- /docs/content/guide/templateProvider.ngdoc: -------------------------------------------------------------------------------- 1 | @ngdoc overview 2 | @name Use with templateProvider 3 | @description 4 | 5 | Testy 6 | -------------------------------------------------------------------------------- /samples/script-tags-ngroute/js/services/version.js: -------------------------------------------------------------------------------- 1 | define([], function () { 2 | app.registerValue('version', '0.2'); 3 | }); 4 | -------------------------------------------------------------------------------- /dist/samples/script-tags-ngroute/js/services/version.js: -------------------------------------------------------------------------------- 1 | define([], function () { 2 | app.registerValue('version', '0.2.3'); 3 | }); 4 | -------------------------------------------------------------------------------- /dist/docs/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laurelnaiad/angular-couch-potato/HEAD/dist/docs/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /dist/docs/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laurelnaiad/angular-couch-potato/HEAD/dist/docs/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/docs/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laurelnaiad/angular-couch-potato/HEAD/dist/docs/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/css/style.css: -------------------------------------------------------------------------------- 1 | div[role=main] div.row div.span3 { 2 | width: 240px; 3 | } 4 | div[role=main] div.row div.span9 { 5 | width: 680px; 6 | } 7 | -------------------------------------------------------------------------------- /dist/docs/css/style.css: -------------------------------------------------------------------------------- 1 | div[role=main] div.row div.span3 { 2 | width: 240px; 3 | } 4 | div[role=main] div.row div.span9 { 5 | width: 680px; 6 | } 7 | -------------------------------------------------------------------------------- /dist/docs/partials/guide/templateProvider.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Testy
This is the partial for view 1.
2 |3 | Getting version from the scope: {{ scopedAppVersion }} 4 |
5 | 6 |7 | And the version from the directive: 8 |
9 | -------------------------------------------------------------------------------- /dist/samples/script-tags-ngroute/partials/partial1.html: -------------------------------------------------------------------------------- 1 |This is the partial for view 1.
2 |3 | Getting version from the scope: {{ scopedAppVersion }} 4 |
5 | 6 |7 | And the version from the directive: 8 |
9 | -------------------------------------------------------------------------------- /docs/content/guide/11-architecture.ngdoc: -------------------------------------------------------------------------------- 1 | @ngdoc overview 2 | @name Architecture using Couch Potato 3 | @description 4 | 5 | You want to know about {@link 02.authoring.components Couch Potato Components} 6 | and {@link 02.authoring.app-module-setup App Module Setup}. 7 | -------------------------------------------------------------------------------- /samples/README.md: -------------------------------------------------------------------------------- 1 | To run the samples: 2 | 3 | * clone the repository 4 | * ```cd angular-couch-potato``` 5 | * ```npm install``` 6 | * ```node server.js``` 7 | * visit [http://localhost:3000/angular-couch-potato/samples/](http://localhost:3000/angular-couch-potato/samples/) 8 | -------------------------------------------------------------------------------- /dist/samples/README.md: -------------------------------------------------------------------------------- 1 | To run the samples: 2 | 3 | * clone the repository 4 | * ```cd angular-couch-potato``` 5 | * ```npm install``` 6 | * ```node server.js``` 7 | * visit [http://localhost:3000/angular-couch-potato/samples/](http://localhost:3006/angular-couch-potato/samples/) 8 | -------------------------------------------------------------------------------- /dist/docs/partials/guide/11-architecture.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | You want to know about Couch Potato Components 5 | and App Module Setup.
{{something}}
4 |This is the partial for view 2.
2 |3 | {{ welcomeMessage }} 4 |
5 |6 | Showing of 'interpolator' filter: 7 | 11 | 12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /dist/samples/script-tags-ngroute/partials/partial2.html: -------------------------------------------------------------------------------- 1 |This is the partial for view 2.
2 |3 | {{ welcomeMessage }} 4 |
5 |6 | Showing of 'interpolator' filter: 7 | 11 | 12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /samples/requirejs-ui-router/app/app.js: -------------------------------------------------------------------------------- 1 | define( 2 | 3 | ['angular','angular-couch-potato', 'angular-ui-router'], 4 | function(angular, couchPotato) { 5 | 6 | var app = angular.module('app', ['scs.couch-potato', 'ui.router']); 7 | 8 | // have Couch Potato set up the registerXXX functions on the app so that 9 | // registration of components is as easy as can be 10 | couchPotato.configureApp(app); 11 | 12 | return app; 13 | 14 | } 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /samples/requirejs-ui-router/app/controllers/contactsDetailController.js: -------------------------------------------------------------------------------- 1 | define(['app', 'services/findById'], function (app) { 2 | app.registerController( 3 | 'contactsDetailController', 4 | [ '$scope', '$stateParams', 'something', 'findById', 5 | function ($scope, $stateParams, something, findById) { 6 | $scope.something = something; 7 | $scope.contact = findById.find($scope.contacts, $stateParams.contactId); 8 | }] 9 | ); 10 | }); 11 | -------------------------------------------------------------------------------- /dist/samples/requirejs-ui-router/app/app.js: -------------------------------------------------------------------------------- 1 | define( 2 | 3 | ['angular','angular-couch-potato', 'angular-ui-router'], 4 | function(angular, couchPotato) { 5 | 6 | var app = angular.module('app', ['scs.couch-potato', 'ui.router']); 7 | 8 | // have Couch Potato set up the registerXXX functions on the app so that 9 | // registration of components is as easy as can be 10 | couchPotato.configureApp(app); 11 | 12 | return app; 13 | 14 | } 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /dist/samples/requirejs-ui-router/app/controllers/contactsDetailController.js: -------------------------------------------------------------------------------- 1 | define(['app', 'services/findById'], function (app) { 2 | app.registerController( 3 | 'contactsDetailController', 4 | [ '$scope', '$stateParams', 'something', 'findById', 5 | function ($scope, $stateParams, something, findById) { 6 | $scope.something = something; 7 | $scope.contact = findById.find($scope.contacts, $stateParams.contactId); 8 | }] 9 | ); 10 | }); 11 | -------------------------------------------------------------------------------- /dist/docs/partials/api/scs.couch-potato.$couchPotato.html: -------------------------------------------------------------------------------- 1 |$couchPotato
2 | (service in module scs.couch-potato
3 | )
4 | ==
7 | 8 |Important: you must inject the 9 | $couchPotatoProvider 10 | at config-time to use the service.
2 |
3 | You can use the navbar on the left to search (see footnote), or 7 | click an item from the table of contents.
8 | 9 |If you're looking for an overview of Couch Potato or want to know how to 10 | get started, try the guide.
11 | 12 |Footnote: Well, you should be able to use the search, but it's broken in this version of Angular docs -- you can't (usefully) click on the results it finds :(
The first sample is the "low end" of Couch Potato usage. It totally 13 | works but you leave some value on the table. It's meant to shadow angular-seed 14 | and to demonstrate the variety of components that *can* be lazy-loaded. It does 15 | not follow the recommended source code layout (semantic), instead it follows 16 | the angular-seed layout (directories for controllers, partials, etc.). 17 | 18 | If you're building a big 19 | app -- which, of course, is one of the reasons to use Couch Potato -- then 20 | you should consider following the techniques in the second sample. 21 |
22 | -------------------------------------------------------------------------------- /dist/samples/index.html: -------------------------------------------------------------------------------- 1 |The first sample is the "low end" of Couch Potato usage. It totally 13 | works but you leave some value on the table. It's meant to shadow angular-seed 14 | and to demonstrate the variety of components that *can* be lazy-loaded. It does 15 | not follow the recommended source code layout (semantic), instead it follows 16 | the angular-seed layout (directories for controllers, partials, etc.). 17 | 18 | If you're building a big 19 | app -- which, of course, is one of the reasons to use Couch Potato -- then 20 | you should consider following the techniques in the second sample. 21 |
22 | -------------------------------------------------------------------------------- /samples/requirejs-ui-router/partials/contacts.html: -------------------------------------------------------------------------------- 1 |$couchPotatoProvider
2 | (service in module scs.couch-potato
3 | )
4 | Injects and retains references to providers that will be used 7 | by the $couchPotato service 8 | at run-time.
9 | 10 |It is mandatory that you inject the provider before 11 | your app's module.run is called (e.g. in module.config).
$controllerProvider
14 | $compileProvider
16 | $filterProvider
18 | $provide
20 |
24 | myModule.config(
25 | [
26 | '$couchPotatoProvider', 'myOtherProvider',
27 | function($couchPotatoProvider, myOtherProvider) {
28 | myOtherProvider.config = { someParam: 'demo' };
29 | // $couchPotatoProvider needs no specific configuration
30 | }
31 | ]
32 | );
33 |
34 |
35 | See the couch-potato module documentation to learn 36 | how to load the module.
2 |
3 | In a traditional AngularJS application, you define and configure all components 7 | before the application runs. The seperation between "configuration time" and 8 | "run time", along with the dependency injection system, enables the programmer 9 | to define all components in any order and to know that they will all be 10 | configured prior to any of them being run. This might sound like a truism!
11 | 12 |There may be application where defining and configuring every component that the 13 | application will use is not optimal. A few reasons to delay are:
14 | 15 |In these cases, one may want to delay loading components. Couch Potato is 22 | intended to make the above cases possible.
23 | 24 |Additionally, you may have an application that, while developing it, you do 25 | not know which components will ultimately be used. For example, in a CMS 26 | (Content Management System), it is conceivable that components that did not 27 | even exist when the application was built are intended to be used within the 28 | application.
29 | 30 |In such a case, you most certainly need to delay loading the component!
31 | 32 |Couch Potato is intended to be part of a solution for this type of loose 33 | binding.
34 | 35 |How It Works provides a relatively high-level explanation 36 | of the methods that Couch Potato employs to allow for lazy loading and 37 | registration of components.
2 |
3 | Couch Potato works by preparing itself -- at configuration-time to do -- at 9 | run-time -- the work of registering components.
10 | 11 |In a normal AngularJS application, when run-time starts (which is typically 12 | when module.run happens or when the application is bootstrapped), all providers 13 | become "uninjectable." As such, you lose the ability to configure components.
14 | 15 |By storing references to the key registration "vehicles", Couch Potato can perform 16 | registrations during run-time. The components Couch Potato maintains references 17 | to are:
18 | 19 |Lazy-registration would be of little use if you couldn't lazily load script.
27 | 28 |This is where AMD (Asynchronous Module Definition) comes in. Couch Potato uses RequireJS. If you are unfamiliar with 29 | RequireJS, you'll want to read up a little. The general idea is that an AMD 30 | module definition states a list of dependencies and then specifies its 31 | definition.
32 | 33 |When a module is requested ("required" in AMD terms), all of it dependencies 34 | are fetched (or retrieved from the cache if they've already been required), and 35 | then passed to the module as function parameters. Continue by reading about 36 | Couch Potato Components.
37 | 38 |This guide is about to get heavy. If you haven't already done so, it's highly 39 | recommended that you stop and look at the samples 40 | before you proceed.
2 |
3 | Many applications will use Couch Potato exclusively within the context of their 7 | routing configurations, whether they use ngRoute, ui-router, or some other router 8 | (e.g. angular-detour or the inbuilt router in pre-2.0 versions of angular).
9 | 10 |The reasoning is that you are trying to lazy-load and register components that 11 | are used in the context of something must happen when the user visits a certain 12 | route/state of the application. This page describes such usage in general. See Ad Hoc Lazy Loading 13 | for alternative usage.
14 | 15 |When routes or states are invoked, an angular promise can resolved, and the $couchPotato service can invoke the $couchPotatoProvider to use RequireJS 18 | to download and register dependencies in the context of the promise.
19 | 20 |Since each component registers itself, indirect dependencies specified in AMD form are downloaded and registered along with the directly stated dependencies of the route.
21 | 22 |Couch Potato does not care which dependencies are resolved when the 23 | route is invoked. It is an application's responsibility to specify directly or indirectly all requirements.
24 | 25 |For example, if a route depends on a Couch Potato component named 26 | "base-state-components", and that component depends on another component named "base-Services", 27 | then all base services will be registered when the state "base", which depends 28 | on the component "base-state-components" is activated.
29 | 30 |The documented configurations for Couch Potato are:
31 | 32 |
2 |
3 | Couch Potato needs RequireJS in order to be useful. However, it is not 9 | necessary for your application to be bootstrapped using AMD. You have 10 | two options:
11 | 12 |If you use traditional script tags to load the module (i.e. you aren't 15 | using AMD to structure your the non-lazy portion of your application, 16 | you must load the following three scripts in this order (other 17 | modules can be loaded wherever it makes sense for you, but these three 18 | must follow the order):
19 | 20 |RequireJS
24 | 25 |26 | <!-- in index.html --> 27 | <script src="/js/angular.min.js"></script> 28 | <script src="/js/angular-couch-potato.min.js"></script> 29 | <script src="/js/require.min.js"></script> 30 |
If you use RequireJS, Couch Potato will first try to use an AMD module
36 | that is defined with the name 'angular'. If it does not find
37 | that, it will try to use an angular object defined as
38 | window.angular. This flexibility allows you to load angular
39 | from a script tag (if you do so before your require.js script tag)
40 | or from RequireJS -- the distinction will be critical if you are
41 | using multiple instances of angular (in which case I pity you for
42 | needing to, even though I understand that there are edge cases
43 | where it is necessary) -- it must be very painful.
Reference Couch Potato as a Dependency as follows: 48 |
49 | var myModule = angular.module('myApp', ['myOtherDep', 'scs.couch-potato']);
50 |
51 |
52 | See also the $couchPotatoProvider documentation.
9 | define(['app', 'lodash', 'myService', function(app, _) {
10 |
11 | app.registerController('myController', ['$scope', '$timeout', '$myService',
12 |
13 | function($scope, $timeout, $myService) {
14 |
15 | $scope.concattedAlphas = '';
16 | _.each(['a', 'b', 'c'], function(val) {
17 | $scope.concattedAlphas += val;
18 | });
19 |
20 | $timeout(
21 | function() {
22 | $scope.aValueFromMyService = $myService.aValue;
23 | },
24 | 1000
25 | );
26 | }
27 | ]);
28 | });
29 |
30 |
31 | That really silly controller depends on the AMD modules "lodash" and
32 | "myService".
33 |
34 | lodash is just the lodash utility library. It knows nothing
35 | about Couch Potato (or Angular) and doesn't need to. This is regular RequireJS here.
36 |
37 | On the other hand, "myService" is itself (or at least might be) a Couch Potato AMD module. It is
38 | defined similarly to the one we're defining here (i.e.
39 | app.registerService(...)). Note the use of the word "might". It's also
40 | entirely possible that myService was configured as a non-lazy component. In
41 | fact, when you use Couch Potato and you define components as modules like the
42 | one above, you are in control of whether they end up being loaded lazily or
43 | built into your application as part of a RequireJS compilation/minification
44 | build step (e.g in a grunt task).
45 |
46 | Both modules are required as part of requiring myController. In practical
47 | terms, this means that:
48 |
49 | * lodash can be used within the controller; and
50 | * myService will be registered before anyone tries to use myController, thus
51 | it can be injected into myController.
52 |
53 | In this way, Couch Potato components can depend on each other. This follows
54 | the "AMD way" of expressing dependencies, so that users of myController (e.g.
55 | routes or states) are not forced to know what components the controller requires
56 | -- the controller module is tracking that,
57 | and RequireJS is ensuring that everything it needs is prepped and ready to go.
58 |
59 | You may have noticed that we have not discussed the "app" dependency. It's the
60 | application module. It deserves some discussion.
61 |
62 | These AMD modules run outside the context of Angular. There needs to be a way
63 | to tie back into your app in order to register the component with Angular. The
64 | application module is the bridge.
65 |
66 | It turns out that in order to make it possible for Couch Potato to do its work,
67 | we've prepared the application module with some sugary functions that expose
68 | the Couch Potato services. Later, we'll see what those sugary functions look
69 | like. For now, just know that app.registerController is a function that's using
70 | Couch Potato to get the controller registered.
71 |
72 | The rest of the code in this module is just standard Angular stuff. The only
73 | real difference is the define function that wraps it and the call
74 | to app.registerController instead of app.controller.
75 |
76 | Ok, with components out of the way, let's loop back and look at the app module
77 | again to understand how it's enabling this app.registerController business.
78 | Read about {@link 19-app-module-setup setting up the app module}.
79 |
--------------------------------------------------------------------------------
/dist/docs/css/doc_widgets.css:
--------------------------------------------------------------------------------
1 | ul.doc-example {
2 | list-style-type: none;
3 | position: relative;
4 | font-size: 14px;
5 | }
6 |
7 | ul.doc-example > li {
8 | border: 2px solid gray;
9 | border-radius: 5px;
10 | -moz-border-radius: 5px;
11 | -webkit-border-radius: 5px;
12 | background-color: white;
13 | margin-bottom: 20px;
14 | }
15 |
16 | ul.doc-example > li.doc-example-heading {
17 | border: none;
18 | border-radius: none;
19 | margin-bottom: -10px;
20 | }
21 |
22 | span.nojsfiddle {
23 | float: right;
24 | font-size: 14px;
25 | margin-right:10px;
26 | margin-top: 10px;
27 | }
28 |
29 | form.jsfiddle {
30 | position: absolute;
31 | right: 0;
32 | z-index: 1;
33 | height: 14px;
34 | }
35 |
36 | form.jsfiddle button {
37 | cursor: pointer;
38 | padding: 4px 10px;
39 | margin: 10px;
40 | background-color: #FFF;
41 | font-weight: bold;
42 | color: #7989D6;
43 | border-color: #7989D6;
44 | -moz-border-radius: 8px;
45 | -webkit-border-radius:8px;
46 | border-radius: 8px;
47 | }
48 |
49 | form.jsfiddle textarea, form.jsfiddle input {
50 | display: none;
51 | }
52 |
53 | li.doc-example-live {
54 | padding: 10px;
55 | font-size: 1.2em;
56 | }
57 |
58 | div.syntaxhighlighter {
59 | padding-bottom: 1px !important; /* fix to remove unnecessary scrollbars http://is.gd/gSMgC */
60 | }
61 |
62 | /* TABS - tutorial environment navigation */
63 |
64 | div.tabs-nav {
65 | height: 25px;
66 | position: relative;
67 | }
68 |
69 | div.tabs-nav ul li {
70 | list-style: none;
71 | display: inline-block;
72 | padding: 5px 10px;
73 | }
74 |
75 | div.tabs-nav ul li.current a {
76 | color: white;
77 | text-decoration: none;
78 | }
79 |
80 | div.tabs-nav ul li.current {
81 | background: #7989D6;
82 | -moz-box-shadow: 4px 4px 6px #48577D;
83 | -moz-border-radius-topright: 8px;
84 | -moz-border-radius-topleft: 8px;
85 | box-shadow: 4px 4px 6px #48577D;
86 | border-radius-topright: 8px;
87 | border-radius-topleft: 8px;
88 | -webkit-box-shadow: 4px 4px 6px #48577D;
89 | -webkit-border-top-right-radius: 8px;
90 | -webkit-border-top-left-radius: 8px;
91 | border-top-right-radius: 8px;
92 | border-top-left-radius: 8px;
93 | }
94 |
95 | div.tabs-content {
96 | padding: 4px;
97 | position: relative;
98 | background: #7989D6;
99 | -moz-border-radius: 8px;
100 | border-radius: 8px;
101 | -webkit-border-radius: 8px;
102 | }
103 |
104 | div.tabs-content-inner {
105 | margin: 1px;
106 | padding: 10px;
107 | background: white;
108 | border-radius: 6px;
109 | -moz-border-radius: 6px;
110 | -webkit-border-radius: 6px;
111 | }
112 |
113 |
114 | /* Tutorial Nav Bar */
115 |
116 | #tutorial-nav {
117 | margin: 0.5em 0 1em 0;
118 | padding: 0;
119 | list-style-type: none;
120 | background: #7989D6;
121 |
122 | -moz-border-radius: 15px;
123 | -webkit-border-radius: 15px;
124 | border-radius: 15px;
125 |
126 | -moz-box-shadow: 4px 4px 6px #48577D;
127 | -webkit-box-shadow: 4px 4px 6px #48577D;
128 | box-shadow: 4px 4px 6px #48577D;
129 | }
130 |
131 |
132 | #tutorial-nav li {
133 | display: inline;
134 | }
135 |
136 |
137 | #tutorial-nav a:link, #tutorial-nav a:visited {
138 | font-size: 1.2em;
139 | color: #FFF;
140 | text-decoration: none;
141 | text-align: center;
142 | display: inline-block;
143 | width: 11em;
144 | padding: 0.2em 0;
145 | }
146 |
147 |
148 | #tutorial-nav a:hover {
149 | color: #000;
150 | }
151 |
--------------------------------------------------------------------------------
/dist/docs/partials/guide/11-architecture.01-components.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | A typical Couch Potato component might look something like this: 7 |
8 | define(['app', 'lodash', 'myService', function(app, _) {
9 |
10 | app.registerController('myController', ['$scope', '$timeout', '$myService',
11 |
12 | function($scope, $timeout, $myService) {
13 |
14 | $scope.concattedAlphas = '';
15 | _.each(['a', 'b', 'c'], function(val) {
16 | $scope.concattedAlphas += val;
17 | });
18 |
19 | $timeout(
20 | function() {
21 | $scope.aValueFromMyService = $myService.aValue;
22 | },
23 | 1000
24 | );
25 | }
26 | ]);
27 | });
28 |
29 |
30 | That really silly controller depends on the AMD modules "lodash" and 31 | "myService".
32 | 33 |lodash is just the lodash utility library. It knows nothing 34 | about Couch Potato (or Angular) and doesn't need to. This is regular RequireJS here.
35 | 36 |On the other hand, "myService" is itself (or at least might be) a Couch Potato AMD module. It is 37 | defined similarly to the one we're defining here (i.e. 38 | app.registerService(...)). Note the use of the word "might". It's also 39 | entirely possible that myService was configured as a non-lazy component. In 40 | fact, when you use Couch Potato and you define components as modules like the 41 | one above, you are in control of whether they end up being loaded lazily or 42 | built into your application as part of a RequireJS compilation/minification 43 | build step (e.g in a grunt task).
44 | 45 |Both modules are required as part of requiring myController. In practical 46 | terms, this means that:
47 | 48 |In this way, Couch Potato components can depend on each other. This follows 55 | the "AMD way" of expressing dependencies, so that users of myController (e.g. 56 | routes or states) are not forced to know what components the controller requires 57 | -- the controller module is tracking that, 58 | and RequireJS is ensuring that everything it needs is prepped and ready to go.
59 | 60 |You may have noticed that we have not discussed the "app" dependency. It's the 61 | application module. It deserves some discussion.
62 | 63 |These AMD modules run outside the context of Angular. There needs to be a way 64 | to tie back into your app in order to register the component with Angular. The 65 | application module is the bridge.
66 | 67 |It turns out that in order to make it possible for Couch Potato to do its work, 68 | we've prepared the application module with some sugary functions that expose 69 | the Couch Potato services. Later, we'll see what those sugary functions look 70 | like. For now, just know that app.registerController is a function that's using 71 | Couch Potato to get the controller registered.
72 | 73 |The rest of the code in this module is just standard Angular stuff. The only 74 | real difference is the define function that wraps it and the call 75 | to app.registerController instead of app.controller.
76 | 77 |Ok, with components out of the way, let's loop back and look at the app module 78 | again to understand how it's enabling this app.registerController business. 79 | Read about setting up the app module.
2 |
3 | Couch Potato aids in the lazy download and and run-time registration of:
7 | 8 |It supports hierarchies of dependencies within these components, expressed as 18 | RequireJS modules. Applications can use Couch Potato to download and register components when they are needed to satisfy the requirements of a given route, or can do so ad-hoc in response to other application events.
19 | 20 |For the impatient, the hasty and the quick, you can stop reading and take a look at the 21 | samples or check out their source code.
22 | 23 |For the reference learner, you can dive straight into the API.
24 | 25 |The Conceptual Overview section explains the purpose(s) for which 28 | Couch Potato is intended and how its usage differs from traditional AngularJS 29 | component definition and registration.
30 | 31 |Architecture using Couch Potato describes how applications and their components are organized and authored in a Couch Potato context.
32 | 33 |Lazy Loading Via Routing introduces the most common use case for Couch Potato -- loading and registering components in the context of route/state changes in the application.
34 | 35 |Ad Hoc Lazy Loading demonstrates how arbitrary application code can invoke the download and registration of Couch Potato components.
36 | 37 |Thoughts on Lazy Loading is a sort of postlude in which some challenges and ideas for the future are presented, hopefully in a manner that is somewhat more organized than a ramble.
38 | 39 |describes how applications and their components are organized and authored in a Couch Potato context.
44 | 45 |The various "use case" sections show how Couch Potato can be used in several 46 | contexts:
47 | 48 |Finally, some closing thoughts are presented with the 62 | hope of stimulating discussion and interest in participating in Couch Potato 63 | specifically and the development of tools and techniques for building big 64 | applications/sites with AngularJS in general.
2 |
3 | Couch Potato is useful if you want to delay a few, some or most of your Angular components for speed or scale reasons. It allows you to author all components in one framework, and choose through configuration which components are "compiled in" to your application and which ones are lazy loaded, and to have fine-grained control over when that lazy loading takes place. It can help you organize dependencies for your routes.
9 | 10 |No, Couch Potato isn't a router. It's meant to be used with a router. It is known to work with with current versions of angular-ui-router (recommended) and Angular's stock router (and ngRoute). It is built into angular-detour. It should work in any context where promises are resolved.
13 | 14 |It can also be used outside the context of routing.
15 | 16 |At this time, you cannot undefine or redefine components at run-time.
19 | 20 |No. At least one experiment is known to have established lazy-loading modules to be possible, but it involves hacking Angular.
23 | 24 |What does work: If you have a component that you want to lazy-load and it depends on 25 | a non-Angular-based script library, such as d3 or a jQuery plugin, you can depend on that 26 | library in the Couch Potato context and defer loading it until your component is loaded.
27 | 28 |What doesn't work: If you have a component that you want to lazy-load and it depends on an Angular-based module, e.g. angular-ui/bootstrap, then your application itself must depend on bootstrap at declaration time.
29 | 30 |No. At least one experiment is known to have established lazy-loading modules to be
33 | 34 |It's not.
37 | 38 |For one, Couch Potato doesn't operate at the module level by design. Operating at the component level within application components is the intent of Couch Potato. Module-level dependencies are at a higher-level.
39 | 40 |Two, run-time loading of modules isn't here, yet. Time will tell whether/how Couch Potato will fit into the future AnguarJS landscape.
41 | 42 |Couch Potato tests: the project does not have any tests, yet. It should have tests 46 | before version 1.0.0.
Testing components that are authored as Couch Potato components: guidelines/examples 48 | for testing apps built with Couch Potato. Will probably be based on protractor (new Angular testing framework).
Undefining/redefining components (for scale). RequireJS has an undef function 50 | that may enable this, but it may also be quite complicated. This is pie-in-the-sky stuff 51 | for now.
If the documentation isn't enough and/or you're having problems, use the issues list of the github repository.
57 | 58 |Absolutely. Pull requests are welcome.
Welcome to the ngStates sample
Use the menu above to navigate
' + 29 | 'Look at Alice or Bob to see a URL with a redirect in action.<' + '/p>' 30 | }) 31 | .state('contacts', { 32 | url: '/contacts', 33 | abstract: true, 34 | templateUrl: 'partials/contacts.html', 35 | controller: 'contactsController', 36 | resolve: { 37 | dummy: $couchPotatoProvider.resolveDependencies(['controllers/contactsController']) 38 | } 39 | }) 40 | .state('contacts.list', { 41 | // parent: 'contacts', 42 | url: '', 43 | templateUrl: 'partials/contacts.list.html' 44 | }) 45 | .state('contacts.detail', { 46 | // parent: 'contacts', 47 | url: '/{contactId}', 48 | resolve: { 49 | dummy: $couchPotatoProvider.resolveDependencies(['controllers/contactsDetailController']), 50 | something: 51 | [ '$timeout', 52 | function ($timeout) { 53 | return $timeout(function () { return 'Asynchronously resolved data'; }, 10); 54 | }] 55 | }, 56 | views: { 57 | '': { 58 | templateUrl: 'partials/contacts.detail.html', 59 | controller: 'contactsDetailController' 60 | }, 'hint@': { 61 | template: 'This is contacts.detail populating the view "hint@"' 62 | }, 63 | 'menu': { 64 | templateProvider: 65 | [ '$stateParams', 66 | function ($stateParams){ 67 | // This is just to demonstrate that $stateParams injection works for templateProvider 68 | // $stateParams are the parameters for the new state we're transitioning to, even 69 | // though the global '$stateParams' has not been updated yet. 70 | return '
Welcome to the ngStates sample
Use the menu above to navigate
' + 29 | 'Look at Alice or Bob to see a URL with a redirect in action.<' + '/p>' 30 | }) 31 | .state('contacts', { 32 | url: '/contacts', 33 | abstract: true, 34 | templateUrl: 'partials/contacts.html', 35 | controller: 'contactsController', 36 | resolve: { 37 | dummy: $couchPotatoProvider.resolveDependencies(['controllers/contactsController']) 38 | } 39 | }) 40 | .state('contacts.list', { 41 | // parent: 'contacts', 42 | url: '', 43 | templateUrl: 'partials/contacts.list.html' 44 | }) 45 | .state('contacts.detail', { 46 | // parent: 'contacts', 47 | url: '/{contactId}', 48 | resolve: { 49 | dummy: $couchPotatoProvider.resolveDependencies(['controllers/contactsDetailController']), 50 | something: 51 | [ '$timeout', 52 | function ($timeout) { 53 | return $timeout(function () { return 'Asynchronously resolved data'; }, 10); 54 | }] 55 | }, 56 | views: { 57 | '': { 58 | templateUrl: 'partials/contacts.detail.html', 59 | controller: 'contactsDetailController' 60 | }, 'hint@': { 61 | template: 'This is contacts.detail populating the view "hint@"' 62 | }, 63 | 'menu': { 64 | templateProvider: 65 | [ '$stateParams', 66 | function ($stateParams){ 67 | // This is just to demonstrate that $stateParams injection works for templateProvider 68 | // $stateParams are the parameters for the new state we're transitioning to, even 69 | // though the global '$stateParams' has not been updated yet. 70 | return '
61 |
62 | $state = {{$state.current.name}}
63 | $stateParams = {{$stateParams}}
64 | $state full url = {{ $state.$current.url.source }}
65 |
67 |
68 |
69 |
70 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/dist/samples/requirejs-ui-router/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
61 |
62 | $state = {{$state.current.name}}
63 | $stateParams = {{$stateParams}}
64 | $state full url = {{ $state.$current.url.source }}
65 |
67 |
68 |
69 |
70 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/dist/docs/css/docs.css:
--------------------------------------------------------------------------------
1 | img.AngularJS-small {
2 | width: 95px;
3 | height: 25px;
4 | }
5 |
6 | /* this is here to avoid the display=block shuffling of ngShow */
7 | .breadcrumb li > * {
8 | float:left;
9 | margin:0 2px 0 0;
10 | }
11 |
12 | .breadcrumb {
13 | padding-top: 6px;
14 | padding-bottom: 0;
15 | line-height: 18px
16 | }
17 |
18 | .header img {
19 | max-height: 40px;
20 | padding-right: 20px;
21 | }
22 |
23 | .header img+.brand {
24 | padding: 10px 20px 10px 10px;
25 | }
26 |
27 | .clear-navbar {
28 | margin-top: 60px;
29 | }
30 |
31 | .footer {
32 | padding-top: 2em;
33 | background-color: #333;
34 | color: white;
35 | padding-bottom: 2em;
36 | }
37 |
38 | .spacer {
39 | height: 1em;
40 | }
41 |
42 |
43 | .icon-cog {
44 | line-height: 13px;
45 | }
46 |
47 | /* =============================== */
48 |
49 | .form-search {
50 | margin-right: 10px;
51 | }
52 |
53 | .form-search .search-query {
54 | width: 180px;
55 | width: 200px \9;
56 | }
57 |
58 | .form-search .dropdown-menu {
59 | margin-left: 10px;
60 | }
61 |
62 | .form-search .code {
63 | font-family: monospace;
64 | font-weight: bold;
65 | font-size: 13px;
66 | color: black;
67 | }
68 |
69 | .form-search > ul.nav > li > a {
70 | margin: 0;
71 | }
72 |
73 | .form-search > ul.nav > li.module {
74 | background-color: #d3d3d3;
75 | }
76 |
77 | .form-search > ul.nav > li.section {
78 | background-color: #ebebeb;
79 | min-height: 14px;
80 | }
81 |
82 | .form-search > ul.nav > li.first {
83 | padding-top: 6px;
84 | }
85 |
86 | .form-search > ul.nav > li.last {
87 | padding-bottom: 6px;
88 | }
89 |
90 | .form-search > ul.nav > li.last + li.api-list-item {
91 | margin-top: -6px;
92 | padding-bottom: 6px;
93 | }
94 |
95 | .form-search .well {
96 | border-color: #d3d3d3;
97 | padding: 0;
98 | margin-bottom: 15px;
99 | }
100 |
101 | .form-search .well .nav-header {
102 | text-transform: none;
103 | padding: 3px 1px;
104 | margin: 0;
105 | }
106 |
107 | .form-search .well .nav-header a {
108 | text-transform: none;
109 | color: black;
110 | }
111 | .form-search .well .nav-header a:hover {
112 | background-color: inherit;
113 | }
114 |
115 | .form-search .well li {
116 | line-height: 14px;
117 | }
118 |
119 | .form-search .well li a:focus {
120 | outline: none;
121 | }
122 |
123 | .form-search .well .guide {
124 | float: right;
125 | padding-top: 0;
126 | color: gray;
127 | }
128 |
129 | .form-search .module .guide {
130 | line-height: 20px;
131 | }
132 |
133 | .match > a, .nav > .match > a:hover {
134 | background-color: #dbeaf4;
135 | }
136 |
137 | /* =============================== */
138 | /* Content */
139 | /* =============================== */
140 |
141 | .improve-docs {
142 | float: right;
143 | }
144 |
145 | .hint {
146 | font-size: .6em;
147 | color: #c0c0c0;
148 | }
149 |
150 | .content code {
151 | background-color: inherit;
152 | color: inherit;
153 | border: none;
154 | padding: 0;
155 | font-size: inherit;
156 | font-family: monospace;
157 | }
158 |
159 | .content h2,
160 | .content h3,
161 | .content h4,
162 | .content h5 {
163 | margin: 1em 0 5px;
164 | }
165 |
166 | .content h1 {
167 | font-size: 30px;
168 | line-height: 36px;
169 | }
170 |
171 | .content h2 {
172 | font-size: 24px;
173 | line-height: 36px;
174 | }
175 |
176 | .content h3 {
177 | line-height: 27px;
178 | font-size: 18px;
179 | }
180 |
181 | .content h4 {
182 | font-size: 15px;
183 | }
184 |
185 | ul.parameters > li > p,
186 | .returns > p {
187 | display: inline;
188 | }
189 |
190 | ul.methods > li,
191 | ul.properties > li,
192 | ul.events > li {
193 | list-style: none;
194 | min-height: 20px;
195 | padding: 19px;
196 | margin-bottom: 20px;
197 | background-color: #f5f5f5;
198 | border: 1px solid #eee;
199 | border: 1px solid rgba(0, 0, 0, 0.05);
200 | -webkit-border-radius: 4px;
201 | -moz-border-radius: 4px;
202 | border-radius: 4px;
203 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
204 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
205 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
206 | }
207 |
208 | .member.method > h2,
209 | .member.property > h2,
210 | .member.event > h2 {
211 | margin-bottom: .5em;
212 | }
213 |
214 | ul.methods > li > h3,
215 | ul.properties > li > h3,
216 | ul.events > li > h3 {
217 | margin: -19px -19px 1em -19px;
218 | padding: .25em 19px;
219 | background-color: #d3d3d3;
220 | font-family: monospace;
221 | }
222 |
223 | .center {
224 | display: block;
225 | margin: 2em auto;
226 | }
227 |
228 | .diagram {
229 | display: block;
230 | margin: 2em auto;
231 | padding: 1em;
232 | border: 1px solid black;
233 |
234 | -moz-box-shadow: 4px 4px 6px #48577D;
235 | -webkit-box-shadow: 4px 4px 6px #48577D;
236 | box-shadow: 4px 4px 6px #48577D;
237 |
238 | -moz-border-radius: 15px;
239 | -webkit-border-radius: 15px;
240 | border-radius: 15px;
241 | }
242 |
243 | .tutorial-nav {
244 | margin-left: 175px;
245 | color: black;
246 | margin-top: 2em;
247 | margin-bottom: 2em;
248 | }
249 |
250 | .tutorial-nav a {
251 | color: white;
252 | }
253 |
254 | .tutorial-nav a:hover {
255 | color: white;
256 | text-decoration: none;
257 | }
258 |
259 | .clear {
260 | clear: both;
261 | }
262 |
--------------------------------------------------------------------------------
/docs/content/guide/11-architecture.11-app-module-setup.ngdoc:
--------------------------------------------------------------------------------
1 | @ngdoc overview
2 | @name App Module Setup
3 | @description
4 |
5 | ## Couch Potato: Application Module Setup
6 |
7 | ### Stop, Breathe and Look at the Samples
8 |
9 | Yes, you were called impatient, hasty and quick if you wanted to look at the
10 | samples. Well it was a joke (perhaps a weak one). Or maybe it was deemed important
11 | to read the conceptual overview. In any case, the rest of this
12 | guide **assumes** you've looked at the samples. Using Couch Potato is actually
13 | pretty easy, and without seeing it in action it may feel more complicated
14 | and confusing than it needs to be or is.
15 |
16 | So have a look at the
17 | source and its readme
18 | and see them in action!
19 |
20 | Since Couch Potato component definitions run outside of the Angular context,
21 | there are two things we need to "do to" the app in order to be able to reach
22 | back into it to register components. Let's take them in order of when they
23 | occur in the lifecycle of the application.
24 |
25 | When the application module is declared, we want to define the registerXXX functions that Couch Potato components use.
26 |
27 | The easiest and best way is probably to let Couch Potato do it for us. When you
28 | declare your module and its dependencies, ask Couch Potato to configure the
29 | app.
30 |
31 | Two examples follow. The first assumes you've used <script> tags to
32 | load Angular and Couch Potato and the second uses the AMD-style. It's
33 | important to realize that the choice *does not* impact the way Couch Potato
34 | components are authored.
35 |
36 | Using <script> tags:
37 |
38 | var myApp = angular.module('myApp', ['scs.couch-potato']);
39 |
40 | couchPotato.configureApp(myApp);
41 |
42 |
43 | Using AMD:
44 |
45 | define(['angular','couch-potato'], function(angular, couchPotato) {
46 | var myApp = angular.module('myApp', ['scs.couch-potato']);
47 |
48 | couchPotato.configureApp(myApp);
49 | });
50 |
51 |
52 | Pretty easy.
53 |
54 | So what just happened? Couch Potato has assigned some functions as variables
55 | on the app. Specifically:
56 |
57 | * registerController(name, controller)
58 | * registerFactory(name, factory)
59 | * registerDirective(name, directive)
60 | * registerFilter(name, filter)
61 | * registerDecorator(name, decorator)
62 | * registerValue(name, value)
63 |
64 | It is these functions that the Couch Potato components call to accomplish
65 | registration. More on their inner workings below.
66 |
67 | The second thing we want to do occurs when the application enters run-time.
68 |
69 |
70 | myApp.run(['$couchPotato', function($couchPotato) {
71 | myApp.lazy = $couchPotato; //note that you need to use the name 'lazy'
72 | });
73 |
74 |
75 | This little assignment gives those register functions that were assigned above
76 | the capability of asking Couch Potato to do its work. Remember that the RequireJS AMD
77 | modules *do not* run in an Angular context -- hence we wouldn't be able to use
78 | dependency injection to grab the $couchPotato service. Latching onto it in
79 | module.run works around this.
80 |
81 | So back to those registerXXX functions. In fact, they contain branches.
82 | Each one looks something like this (we'll use registerController but they're
83 | all doing the same thing). Keep in mind you don't write these, Couch Potato
84 | assigns them to the app module for you when you call configureApp.
85 |
86 |
87 | function registerController(name, controller) {
88 | if (app.lazy) {
89 | app.lazy.registerController([name, controller]);
90 | }
91 | else {
92 | app.controller(name, controller);
93 | }
94 | }
95 |
96 |
97 | Why the branch? It enables calls to registerController (or registerDirective,
98 | etc.) to function at at configuration time **or** at run time. This is really
99 | handy. In practical terms, you can author *all* of your components as Couch
100 | Potato components, whether you want to compile them into your eventual app.js
101 | using r.js optimization or you want to load/register them lazily.
102 |
103 | ### Advanced Setup
104 |
105 | What follows assumes you're using RequireJS to load
106 | your app and is relatively advanced. It is likely to be confusing to those who
107 | do not know RequireJS well. (If you're using <script> tags then you're probably
108 | compiling certain components directly into your application module anyway.)
109 |
110 | You've been warned. If you want to skip this section you can move straight on
111 | to {@link 25-lazy-loading-via-routing Lazy Loading Via Routing}.
112 |
113 | The distinction between whether r.js will compile Couch Potato components
114 | or whether they will be lazy-loaded/registered is effected by whether or not you ```require``` (as in
115 | use the RequireJS require function on) them within your RequireJS ```main.js```
116 | file (or wherever it is that you have your RequireJS entry point). An example is probably necessary to flesh out this concept.
117 |
118 | Let's say your (over)simplified main.js looks like this -- relatively normal
119 | RequireJS configuration for an Angular app:
120 |
121 |
122 | require.config({
123 | paths: {
124 | 'angular': '//somecdn/angular.min.js',
125 | 'angular-ui-router': '//somecdn/angular-ui-router.min.js',
126 | 'couch-potato': '/js/angular-couch-potato.min.js'
127 | }
128 | });
129 |
130 | require(['app', 'run'], function(app) {
131 | angular.element(document).ready(function() {
132 | angular.bootstrap($('html'), [
133 | app['name'], function() {
134 | $('html').addClass('ng-app');
135 | }
136 | ]
137 | });
138 | });
139 |
140 |
141 | 'app' is your AMD module that defines the Angular app module.
142 |
143 | 'run' is your AMD module that causes the Angular app to be run.
144 |
145 | This main.js just initializes the app and runs it, then attaches the
146 | bootstrap function to the document ready event. As said, this is basic
147 | RequireJS/Angular stuff. Uses jQuery, but that's not important.
148 |
149 | Everything in main.js will be compiled by r.js -- **including the components
150 | that are required, and the ones they require, etc.**
151 |
152 | So anything that 'app' depends on, and anything that 'run' depends on -- those
153 | will be compiled into your output from r.js (if they are not prevented by being
154 | loaded from a CDN or otherwise exluded from the r.js compile process).
155 |
156 | Let's look at app.js:
157 |
158 | define(['angular', 'couch-potato', 'ui-router'],
159 | function(angular, couchPotato) {
160 | var app = angular.module('myApp', [
161 | 'ui.state'
162 | 'scs.couch-potato'
163 | ]);
164 |
165 | couchPotato.configureApp(app);
166 |
167 | // return app so you can access it using RequireJs
168 | return app;
169 | }
170 | );
171 |
172 |
173 | Aside from configuring the app for Couch Potato, this is all still normal
174 | RequireJS/Angular. Don't get bored -- we're getting toward the point here...
175 |
176 | Let's look at run.js:
177 |
178 | define(['app', 'config', 'someService'],
179 | function(app) {
180 | app.run(['$couchPotato', 'someService',
181 | function($couchPotato, someService) {
182 | app.lazy = $couchPotato;
183 | }
184 | ]);
185 | }
186 | );
187 |
188 |
189 | So this causes the app to go into run mode, and assigns $couchPotato to
190 | app.lazy. For the present exposition, what matters is that 'config' is
191 | required.
192 |
193 | Here's config.js:
194 |
195 | define(['app', 'couch-potato', 'compiled-components'], function(app) {
196 | app.config('$couchPotatoProvider', function($couchPotatoProvider) {
197 | // nothing really needed here except the rest of your app.config logic
198 | });
199 | });
200 |
201 |
202 | So, because it's necessary, $couchPotatoProvider is injected. But the point
203 | here is that 'compiled-components' is required. This is the module in which
204 | you specific which of your Couch Potato components will *not* be lazy loaded,
205 | and instead will be compiled into your app by r.js.
206 |
207 | One approach here is to bail on lazy loading filters and decorators. You may
208 | also have some directives that are used all over the place and not worth
209 | tracking as individual dependencies or lazy loading them.
210 |
211 | In which case, 'compiled-components.js' could look like:
212 |
213 | define(
214 | [
215 | 'filters',
216 | 'decorators',
217 | 'common-directives'
218 | ], function() {
219 | });
220 |
221 |
222 | Since all of the modules in this exposition are required down from main.js,
223 | r.js is going to build them into the compiled output.
224 |
225 | Components that are not required by this tree of dependencies will be lazy
226 | loaded as disussed in
227 | {@link 25-lazy-loading-via-routing Lazy Loading Via Routing}.
228 |
--------------------------------------------------------------------------------
/dist/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
2 |
3 | Yes, you were called impatient, hasty and quick if you wanted to look at the 9 | samples. Well it was a joke (perhaps a weak one). Or maybe it was deemed important 10 | to read the conceptual overview. In any case, the rest of this 11 | guide assumes you've looked at the samples. Using Couch Potato is actually 12 | pretty easy, and without seeing it in action it may feel more complicated 13 | and confusing than it needs to be or is.
14 | 15 |So have a look at the 16 | source and its readme 17 | and see them in action!
18 | 19 |Since Couch Potato component definitions run outside of the Angular context, 20 | there are two things we need to "do to" the app in order to be able to reach 21 | back into it to register components. Let's take them in order of when they 22 | occur in the lifecycle of the application.
23 | 24 |When the application module is declared, we want to define the registerXXX functions that Couch Potato components use.
25 | 26 |The easiest and best way is probably to let Couch Potato do it for us. When you 27 | declare your module and its dependencies, ask Couch Potato to configure the 28 | app.
29 | 30 |Two examples follow. The first assumes you've used <script> tags to 31 | load Angular and Couch Potato and the second uses the AMD-style. It's 32 | important to realize that the choice does not impact the way Couch Potato 33 | components are authored.
34 | 35 |Using <script> tags: 36 |
37 | var myApp = angular.module('myApp', ['scs.couch-potato']);
38 |
39 | couchPotato.configureApp(myApp);
40 |
41 |
42 | Using AMD: 43 |
44 | define(['angular','couch-potato'], function(angular, couchPotato) {
45 | var myApp = angular.module('myApp', ['scs.couch-potato']);
46 |
47 | couchPotato.configureApp(myApp);
48 | });
49 |
50 |
51 | Pretty easy.
52 | 53 |So what just happened? Couch Potato has assigned some functions as variables 54 | on the app. Specifically:
55 | 56 |It is these functions that the Couch Potato components call to accomplish 66 | registration. More on their inner workings below.
67 | 68 |The second thing we want to do occurs when the application enters run-time.
69 | 70 |
71 | myApp.run(['$couchPotato', function($couchPotato) {
72 | myApp.lazy = $couchPotato; //note that you need to use the name 'lazy'
73 | });
74 |
75 |
76 | This little assignment gives those register functions that were assigned above 77 | the capability of asking Couch Potato to do its work. Remember that the RequireJS AMD 78 | modules do not run in an Angular context -- hence we wouldn't be able to use 79 | dependency injection to grab the $couchPotato service. Latching onto it in 80 | module.run works around this.
81 | 82 |So back to those registerXXX functions. In fact, they contain branches. 83 | Each one looks something like this (we'll use registerController but they're 84 | all doing the same thing). Keep in mind you don't write these, Couch Potato 85 | assigns them to the app module for you when you call configureApp.
86 | 87 |
88 | function registerController(name, controller) {
89 | if (app.lazy) {
90 | app.lazy.registerController([name, controller]);
91 | }
92 | else {
93 | app.controller(name, controller);
94 | }
95 | }
96 |
97 |
98 | Why the branch? It enables calls to registerController (or registerDirective, 99 | etc.) to function at at configuration time or at run time. This is really 100 | handy. In practical terms, you can author all of your components as Couch 101 | Potato components, whether you want to compile them into your eventual app.js 102 | using r.js optimization or you want to load/register them lazily.
103 | 104 |What follows assumes you're using RequireJS to load 107 | your app and is relatively advanced. It is likely to be confusing to those who 108 | do not know RequireJS well. (If you're using <script> tags then you're probably 109 | compiling certain components directly into your application module anyway.)
110 | 111 |You've been warned. If you want to skip this section you can move straight on 112 | to Lazy Loading Via Routing.
113 | 114 |The distinction between whether r.js will compile Couch Potato components
115 | or whether they will be lazy-loaded/registered is effected by whether or not you require (as in
116 | use the RequireJS require function on) them within your RequireJS main.js
117 | file (or wherever it is that you have your RequireJS entry point). An example is probably necessary to flesh out this concept.
Let's say your (over)simplified main.js looks like this -- relatively normal 120 | RequireJS configuration for an Angular app:
121 | 122 |
123 | require.config({
124 | paths: {
125 | 'angular': '//somecdn/angular.min.js',
126 | 'angular-ui-router': '//somecdn/angular-ui-router.min.js',
127 | 'couch-potato': '/js/angular-couch-potato.min.js'
128 | }
129 | });
130 |
131 | require(['app', 'run'], function(app) {
132 | angular.element(document).ready(function() {
133 | angular.bootstrap($('html'), [
134 | app['name'], function() {
135 | $('html').addClass('ng-app');
136 | }
137 | ]
138 | });
139 | });
140 |
141 |
142 | 'app' is your AMD module that defines the Angular app module.
143 | 144 |'run' is your AMD module that causes the Angular app to be run.
145 | 146 |This main.js just initializes the app and runs it, then attaches the 147 | bootstrap function to the document ready event. As said, this is basic 148 | RequireJS/Angular stuff. Uses jQuery, but that's not important.
149 | 150 |Everything in main.js will be compiled by r.js -- including the components 151 | that are required, and the ones they require, etc.
152 | 153 |So anything that 'app' depends on, and anything that 'run' depends on -- those 154 | will be compiled into your output from r.js (if they are not prevented by being 155 | loaded from a CDN or otherwise exluded from the r.js compile process).
156 | 157 |Let's look at app.js: 158 |
159 | define(['angular', 'couch-potato', 'ui-router'],
160 | function(angular, couchPotato) {
161 | var app = angular.module('myApp', [
162 | 'ui.state'
163 | 'scs.couch-potato'
164 | ]);
165 |
166 | couchPotato.configureApp(app);
167 |
168 | // return app so you can access it using RequireJs
169 | return app;
170 | }
171 | );
172 |
173 |
174 | Aside from configuring the app for Couch Potato, this is all still normal 175 | RequireJS/Angular. Don't get bored -- we're getting toward the point here...
176 | 177 |Let's look at run.js: 178 |
179 | define(['app', 'config', 'someService'],
180 | function(app) {
181 | app.run(['$couchPotato', 'someService',
182 | function($couchPotato, someService) {
183 | app.lazy = $couchPotato;
184 | }
185 | ]);
186 | }
187 | );
188 |
189 |
190 | So this causes the app to go into run mode, and assigns $couchPotato to 191 | app.lazy. For the present exposition, what matters is that 'config' is 192 | required.
193 | 194 |Here's config.js: 195 |
196 | define(['app', 'couch-potato', 'compiled-components'], function(app) {
197 | app.config('$couchPotatoProvider', function($couchPotatoProvider) {
198 | // nothing really needed here except the rest of your app.config logic
199 | });
200 | });
201 |
202 |
203 | So, because it's necessary, $couchPotatoProvider is injected. But the point 204 | here is that 'compiled-components' is required. This is the module in which 205 | you specific which of your Couch Potato components will not be lazy loaded, 206 | and instead will be compiled into your app by r.js.
207 | 208 |One approach here is to bail on lazy loading filters and decorators. You may 209 | also have some directives that are used all over the place and not worth 210 | tracking as individual dependencies or lazy loading them.
211 | 212 |In which case, 'compiled-components.js' could look like: 213 |
214 | define(
215 | [
216 | 'filters',
217 | 'decorators',
218 | 'common-directives'
219 | ], function() {
220 | });
221 |
222 |
223 | Since all of the modules in this exposition are required down from main.js, 224 | r.js is going to build them into the compiled output.
225 | 226 |Components that are not required by this tree of dependencies will be lazy 227 | loaded as disussed in 228 | Lazy Loading Via Routing.
44 | * 45 | * 46 | * 47 | * 48 | *49 | * 50 | * #### B. Use RequireJS 51 | * 52 | * If you use RequireJS, Couch Potato will first try to use an AMD module 53 | * that is defined with the name ```'angular'```. If it does not find 54 | * that, it will try to use an angular object defined as 55 | * ```window.angular```. This flexibility allows you to load angular 56 | * from a script tag (if you do so before your require.js script tag) 57 | * or from RequireJS -- the distinction will be critical if you are 58 | * using multiple instances of angular (in which case I pity you for 59 | * needing to, even though I understand that there are edge cases 60 | * where it is necessary) -- it must be very painful. 61 | * 62 | * ### Adding Couch Potato as a Dependency 63 | * 64 | * Reference Couch Potato as a Dependency as follows: 65 | *
66 | * var myModule = angular.module('myApp', ['myOtherDep', 'scs.couch-potato']);
67 | *
68 | *
69 | * See also the {@link scs.couch-potato.$couchPotatoProvider
70 | * $couchPotatoProvider} documentation.
71 | */
72 | var module = angular.module('scs.couch-potato', ['ng']);
73 |
74 | function CouchPotatoProvider(
75 | $controllerProvider,
76 | $compileProvider,
77 | $provide,
78 | $filterProvider
79 | ) {
80 |
81 | var rootScope = null;
82 |
83 | //Expose each provider's functionality as single-argument functions.
84 | //The component-definining functions that are passed as parameters
85 | //should bear their own names. If apply is true, call apply on the
86 | //root scope. This allows clients that are manually registering
87 | //components (outside of the promise-based methods) to force registration
88 | //to be applied, even if they are not doing so in an angular context.
89 |
90 | function registerValue(value, apply) {
91 | $provide.value.apply(null, value);
92 | if (apply) {
93 | rootScope.$apply();
94 | }
95 | }
96 |
97 | function registerConstant(value, apply) {
98 | $provide.value.apply(null, value);
99 | if (apply) {
100 | rootScope.$apply();
101 | }
102 | }
103 |
104 | function registerFactory(factory, apply) {
105 | $provide.factory.apply(null, factory);
106 | if (apply) {
107 | rootScope.$apply();
108 | }
109 | }
110 |
111 | function registerService(service, apply) {
112 | $provide.service.apply(null, service);
113 | if (apply) {
114 | rootScope.$apply();
115 | }
116 | }
117 |
118 | function registerFilter(filter, apply) {
119 | $filterProvider.register.apply(null, filter);
120 | if (apply) {
121 | rootScope.$apply();
122 | }
123 | }
124 |
125 | function registerDirective(directive, apply) {
126 | $compileProvider.directive.apply(null, directive);
127 | if (apply) {
128 | rootScope.$apply();
129 | }
130 | }
131 |
132 | function registerController(controller, apply) {
133 | $controllerProvider.register.apply(null, controller);
134 | if (apply) {
135 | rootScope.$apply();
136 | }
137 | }
138 |
139 | function registerDecorator(decorator, apply) {
140 | $provide.decorator.apply(null, decorator);
141 | if (apply) {
142 | rootScope.$apply();
143 | }
144 | }
145 |
146 | function registerProvider(service, apply) {
147 | $provide.provider.apply(null, service);
148 | if (apply) {
149 | rootScope.$apply();
150 | }
151 | }
152 |
153 | function resolve(dependencies, returnIndex, returnSubId) {
154 | if (dependencies.dependencies) {
155 | return resolveDependenciesProperty(
156 | dependencies,
157 | returnIndex,
158 | returnSubId
159 | );
160 | }
161 | else {
162 | return resolveDependencies(dependencies, returnIndex, returnSubId);
163 | }
164 | }
165 | this.resolve = resolve;
166 |
167 | function resolveDependencies(dependencies, returnIndex, returnSubId) {
168 | function delay($q, $rootScope) {
169 |
170 | var defer = $q.defer();
171 |
172 | require(dependencies, function() {
173 | var args = Array.prototype.slice(arguments);
174 |
175 | var out;
176 |
177 | if (returnIndex === undefined) {
178 | out = arguments[arguments.length - 1];
179 | }
180 | else {
181 | argForOut = arguments[returnIndex];
182 | if (returnSubId === undefined) {
183 | out = argForOut;
184 | }
185 | else {
186 | out = argForOut[returnSubId];
187 | }
188 | }
189 |
190 | defer.resolve(out);
191 | $rootScope.$apply();
192 |
193 | });
194 |
195 | return defer.promise;
196 | }
197 |
198 | delay.$inject = ['$q', '$rootScope'];
199 | return delay;
200 |
201 | }
202 | this.resolveDependencies = resolveDependencies;
203 |
204 | function resolveDependenciesProperty(configProperties) {
205 | if (configProperties.dependencies) {
206 | var resolveConfig = configProperties;
207 | var deps = configProperties.dependencies;
208 | delete resolveConfig['dependencies'];
209 |
210 | resolveConfig.resolve = {};
211 | resolveConfig.resolve.delay = resolveDependencies(deps);
212 | return resolveConfig;
213 | }
214 | else
215 | {
216 | return configProperties;
217 | }
218 |
219 | }
220 | this.resolveDependenciesProperty = resolveDependenciesProperty;
221 |
222 | /**
223 | *
224 | * @ngdoc object
225 | * @name scs.couch-potato.$couchPotato
226 | *
227 | * @description
228 | *
229 | * ==
230 | *
231 | * **Important:** you must inject the
232 | * {@link scs.couch-potato.$couchPotatoProvider $couchPotatoProvider}
233 | * at config-time to use the service.
234 | *
235 | */
236 | this.$get = function ($rootScope) {
237 | var svc = {};
238 |
239 | rootScope = $rootScope;
240 |
241 | svc.registerValue = registerValue;
242 | svc.registerConstant = registerConstant;
243 | svc.registerFactory = registerFactory;
244 | svc.registerService = registerService;
245 | svc.registerFilter = registerFilter;
246 | svc.registerDirective = registerDirective;
247 | svc.registerController = registerController;
248 | svc.registerDecorator = registerDecorator;
249 | svc.registerProvider = registerProvider;
250 |
251 | svc.resolveDependenciesProperty = resolveDependenciesProperty;
252 | svc.resolveDependencies = resolveDependencies;
253 | svc.resolve = resolve;
254 |
255 | return svc;
256 | };
257 | this.$get.$inject = ['$rootScope'];
258 |
259 | }
260 | CouchPotatoProvider.$inject = [
261 | '$controllerProvider',
262 | '$compileProvider',
263 | '$provide',
264 | '$filterProvider'
265 | ]; //inject the providers into CouchPotatoProvider
266 |
267 | /**
268 | *
269 | * @ngdoc object
270 | * @name scs.couch-potato.$couchPotatoProvider
271 | *
272 | * @description
273 | * Injects and retains references to providers that will be used
274 | * by the {@link scs.couch-potato.$couchPotato $couchPotato service}
275 | * at run-time.
276 | *
277 | * It is **mandatory** that you inject the provider before
278 | * your app's module.run is called (e.g. in module.config).
279 | *
280 | * @example
281 | *
282 | * myModule.config(
283 | * [
284 | * '$couchPotatoProvider', 'myOtherProvider',
285 | * function($couchPotatoProvider, myOtherProvider) {
286 | * myOtherProvider.config = { someParam: 'demo' };
287 | * // $couchPotatoProvider needs no specific configuration
288 | * }
289 | * ]
290 | * );
291 | *
292 | *
293 | * See the {@link scs.couch-potato couch-potato module documentation} to learn
294 | * how to load the module.
295 | *
296 | * @requires $controllerProvider
297 | * @requires $compileProvider
298 | * @requires $filterProvider
299 | * @requires $provide
300 | *
301 | */
302 | module.provider('$couchPotato', CouchPotatoProvider);
303 |
304 | this.configureApp = function(app) {
305 | app.registerController = function(name, controller) {
306 | if (app.lazy) {
307 | app.lazy.registerController([name, controller]);
308 | }
309 | else {
310 | app.controller(name, controller);
311 | }
312 | return app;
313 | };
314 |
315 | app.registerFactory = function(name, factory) {
316 | if (app.lazy) {
317 | app.lazy.registerFactory([name, factory]);
318 | }
319 | else {
320 | app.factory(name, factory);
321 | }
322 | return app;
323 | };
324 |
325 |
326 | app.registerService = function(name, service) {
327 | if (app.lazy) {
328 | app.lazy.registerService([name, service]);
329 | }
330 | else {
331 | app.service(name, service);
332 | }
333 | return app;
334 | };
335 |
336 | app.registerDirective = function(name, directive) {
337 | if (app.lazy) {
338 | app.lazy.registerDirective([name, directive]);
339 | }
340 | else {
341 | app.directive(name, directive);
342 | }
343 | return app;
344 | };
345 |
346 | app.registerDecorator = function(name, decorator) {
347 | if (app.lazy) {
348 | app.lazy.registerDecorator([name, decorator]);
349 | }
350 | else {
351 | app.decorator(name, decorator);
352 | }
353 | return app;
354 | };
355 |
356 | app.registerProvider = function(name, provider) {
357 | if (app.lazy) {
358 | app.lazy.registerProvider([name, provider]);
359 | }
360 | else {
361 | app.provider(name, provider);
362 | }
363 | return app;
364 | };
365 |
366 | app.registerValue = function(name, value) {
367 | if (app.lazy) {
368 | app.lazy.registerValue([name, value]);
369 | }
370 | else {
371 | app.value(name, value);
372 | }
373 | return app;
374 | };
375 |
376 | app.registerConstant = function(name, value) {
377 | if (app.lazy) {
378 | app.lazy.registerConstant([name, value]);
379 | }
380 | else {
381 | app.constant(name, value);
382 | }
383 | return app;
384 | };
385 |
386 |
387 | app.registerFilter = function(name, filter) {
388 | if (app.lazy) {
389 | app.lazy.registerFilter([name, filter]);
390 | }
391 | else {
392 | app.filter(name, filter);
393 | }
394 | return app;
395 | };
396 |
397 | /**
398 | * extendInjectable Prototypically extends an injectable object from
399 | * another injectable object. Supports $inject-property-style injections
400 | * (e.g. CtrlFunc.$inject = ['$scope'];) and array notation
401 | * (e.g. ['$scope', function($scope) {...}]).
402 | *
403 | * @param object parent Parent object from which to extend.
404 | * @param object child Child object to receive into.
405 | * @return object The prototypically extended object.
406 | */
407 | app.extendInjectable = function(parent, child) {
408 |
409 | // split up injections and constructor
410 | function disassembleInjected(object) {
411 | if (angular.isArray(object)) {
412 | var func = object.slice(object.length - 1)[0];
413 | return [func, object.slice(0, object.length - 1)];
414 | }
415 | else {
416 | var injections = object.$inject;
417 | return [object, injections || []];
418 | }
419 | }
420 |
421 | parentPieces = disassembleInjected(parent);
422 | childPieces = disassembleInjected(child);
423 |
424 | // combined constructor.
425 | function CombinedConstructor() {
426 | var args = Array.prototype.slice.call(arguments);
427 |
428 | parentPieces[0].apply(this, args.slice(0, parentPieces[1].length));
429 | childPieces[0].apply(this, args.slice(parentPieces[1].length));
430 | }
431 |
432 | // combined object target
433 | function Inherit() {}
434 | // child's prototype will already be present
435 | Inherit.prototype = parentPieces[0].prototype;
436 |
437 | // instantiate it without calling constructor
438 | CombinedConstructor.prototype = new Inherit();
439 |
440 | // ask for everything.
441 | CombinedConstructor.$inject =
442 | [].concat(parentPieces[1]).concat(childPieces[1]);
443 |
444 | return CombinedConstructor;
445 | };
446 |
447 |
448 | };
449 |
450 | };
451 |
452 |
453 | if ( typeof(define) === 'function' && define.amd) {
454 | // expose couch potato as an AMD module depending on 'angular'
455 | // since we use angular from window, apps are not required
456 | // to export the angular object from a shim.
457 | define(['angular'], function() { return new CouchPotato(window.angular); });
458 | }
459 | else {
460 | window.couchPotato = new CouchPotato(angular);
461 | }
462 | }());
463 |
--------------------------------------------------------------------------------
/dist/angular-couch-potato.js:
--------------------------------------------------------------------------------
1 | /*! angular-couch-potato - v0.2.3 - 2014-11-06
2 | * https://github.com/laurelnaiad/angular-couch-potato
3 | * Copyright (c) 2013 Daphne Maddox;
4 | * Uses software code originally found at https://github.com/szhanginrhythm/angular-require-lazyload
5 | * Licensed MIT
6 | */
7 | (function() {
8 |
9 | var CouchPotato = function(angular) {
10 | //Self-invoking anonymous function keeps global scope clean.
11 |
12 | //Register the module.
13 | //Getting angular onto the global scope is the client's responsibility.
14 |
15 | /**
16 | *
17 | * @ngdoc overview
18 | * @name scs.couch-potato
19 | *
20 | * @description
21 | *
22 | * ## scs.couch-potato module
23 | *
24 | * ### Loading the Script
25 | *
26 | * Couch Potato needs RequireJS in order to be useful. However, it is not
27 | * necessary for your application to be bootstrapped using AMD. You have
28 | * two options:
29 | *
30 | * #### A. Use Traditional <script> Tags
31 | *
32 | * If you use traditional script tags to load the module (i.e. you aren't
33 | * using AMD to structure your the non-lazy portion of your application,
34 | * you **must** load the following three scripts in this order (other
35 | * modules can be loaded wherever it makes sense for you, but these three
36 | * must follow the order):
37 | *
38 | * 1. Angular
39 | * 2. Couch Potato
40 | * 3. RequireJS
41 | *
42 | * 43 | * 44 | * 45 | * 46 | * 47 | *48 | * 49 | * #### B. Use RequireJS 50 | * 51 | * If you use RequireJS, Couch Potato will first try to use an AMD module 52 | * that is defined with the name ```'angular'```. If it does not find 53 | * that, it will try to use an angular object defined as 54 | * ```window.angular```. This flexibility allows you to load angular 55 | * from a script tag (if you do so before your require.js script tag) 56 | * or from RequireJS -- the distinction will be critical if you are 57 | * using multiple instances of angular (in which case I pity you for 58 | * needing to, even though I understand that there are edge cases 59 | * where it is necessary) -- it must be very painful. 60 | * 61 | * ### Adding Couch Potato as a Dependency 62 | * 63 | * Reference Couch Potato as a Dependency as follows: 64 | *
65 | * var myModule = angular.module('myApp', ['myOtherDep', 'scs.couch-potato']);
66 | *
67 | *
68 | * See also the {@link scs.couch-potato.$couchPotatoProvider
69 | * $couchPotatoProvider} documentation.
70 | */
71 | var module = angular.module('scs.couch-potato', ['ng']);
72 |
73 | function CouchPotatoProvider(
74 | $controllerProvider,
75 | $compileProvider,
76 | $provide,
77 | $filterProvider
78 | ) {
79 |
80 | var rootScope = null;
81 |
82 | //Expose each provider's functionality as single-argument functions.
83 | //The component-definining functions that are passed as parameters
84 | //should bear their own names. If apply is true, call apply on the
85 | //root scope. This allows clients that are manually registering
86 | //components (outside of the promise-based methods) to force registration
87 | //to be applied, even if they are not doing so in an angular context.
88 |
89 | function registerValue(value, apply) {
90 | $provide.value.apply(null, value);
91 | if (apply) {
92 | rootScope.$apply();
93 | }
94 | }
95 |
96 | function registerConstant(value, apply) {
97 | $provide.value.apply(null, value);
98 | if (apply) {
99 | rootScope.$apply();
100 | }
101 | }
102 |
103 | function registerFactory(factory, apply) {
104 | $provide.factory.apply(null, factory);
105 | if (apply) {
106 | rootScope.$apply();
107 | }
108 | }
109 |
110 | function registerService(service, apply) {
111 | $provide.service.apply(null, service);
112 | if (apply) {
113 | rootScope.$apply();
114 | }
115 | }
116 |
117 | function registerFilter(filter, apply) {
118 | $filterProvider.register.apply(null, filter);
119 | if (apply) {
120 | rootScope.$apply();
121 | }
122 | }
123 |
124 | function registerDirective(directive, apply) {
125 | $compileProvider.directive.apply(null, directive);
126 | if (apply) {
127 | rootScope.$apply();
128 | }
129 | }
130 |
131 | function registerController(controller, apply) {
132 | $controllerProvider.register.apply(null, controller);
133 | if (apply) {
134 | rootScope.$apply();
135 | }
136 | }
137 |
138 | function registerDecorator(decorator, apply) {
139 | $provide.decorator.apply(null, decorator);
140 | if (apply) {
141 | rootScope.$apply();
142 | }
143 | }
144 |
145 | function registerProvider(service, apply) {
146 | $provide.provider.apply(null, service);
147 | if (apply) {
148 | rootScope.$apply();
149 | }
150 | }
151 |
152 | function resolve(dependencies, returnIndex, returnSubId) {
153 | if (dependencies.dependencies) {
154 | return resolveDependenciesProperty(
155 | dependencies,
156 | returnIndex,
157 | returnSubId
158 | );
159 | }
160 | else {
161 | return resolveDependencies(dependencies, returnIndex, returnSubId);
162 | }
163 | }
164 | this.resolve = resolve;
165 |
166 | function resolveDependencies(dependencies, returnIndex, returnSubId) {
167 | function delay($q, $rootScope) {
168 |
169 | var defer = $q.defer();
170 |
171 | require(dependencies, function() {
172 | var args = Array.prototype.slice(arguments);
173 |
174 | var out;
175 |
176 | if (returnIndex === undefined) {
177 | out = arguments[arguments.length - 1];
178 | }
179 | else {
180 | argForOut = arguments[returnIndex];
181 | if (returnSubId === undefined) {
182 | out = argForOut;
183 | }
184 | else {
185 | out = argForOut[returnSubId];
186 | }
187 | }
188 |
189 | defer.resolve(out);
190 | $rootScope.$apply();
191 |
192 | });
193 |
194 | return defer.promise;
195 | }
196 |
197 | delay.$inject = ['$q', '$rootScope'];
198 | return delay;
199 |
200 | }
201 | this.resolveDependencies = resolveDependencies;
202 |
203 | function resolveDependenciesProperty(configProperties) {
204 | if (configProperties.dependencies) {
205 | var resolveConfig = configProperties;
206 | var deps = configProperties.dependencies;
207 | delete resolveConfig['dependencies'];
208 |
209 | resolveConfig.resolve = {};
210 | resolveConfig.resolve.delay = resolveDependencies(deps);
211 | return resolveConfig;
212 | }
213 | else
214 | {
215 | return configProperties;
216 | }
217 |
218 | }
219 | this.resolveDependenciesProperty = resolveDependenciesProperty;
220 |
221 | /**
222 | *
223 | * @ngdoc object
224 | * @name scs.couch-potato.$couchPotato
225 | *
226 | * @description
227 | *
228 | * ==
229 | *
230 | * **Important:** you must inject the
231 | * {@link scs.couch-potato.$couchPotatoProvider $couchPotatoProvider}
232 | * at config-time to use the service.
233 | *
234 | */
235 | this.$get = function ($rootScope) {
236 | var svc = {};
237 |
238 | rootScope = $rootScope;
239 |
240 | svc.registerValue = registerValue;
241 | svc.registerConstant = registerConstant;
242 | svc.registerFactory = registerFactory;
243 | svc.registerService = registerService;
244 | svc.registerFilter = registerFilter;
245 | svc.registerDirective = registerDirective;
246 | svc.registerController = registerController;
247 | svc.registerDecorator = registerDecorator;
248 | svc.registerProvider = registerProvider;
249 |
250 | svc.resolveDependenciesProperty = resolveDependenciesProperty;
251 | svc.resolveDependencies = resolveDependencies;
252 | svc.resolve = resolve;
253 |
254 | return svc;
255 | };
256 | this.$get.$inject = ['$rootScope'];
257 |
258 | }
259 | CouchPotatoProvider.$inject = [
260 | '$controllerProvider',
261 | '$compileProvider',
262 | '$provide',
263 | '$filterProvider'
264 | ]; //inject the providers into CouchPotatoProvider
265 |
266 | /**
267 | *
268 | * @ngdoc object
269 | * @name scs.couch-potato.$couchPotatoProvider
270 | *
271 | * @description
272 | * Injects and retains references to providers that will be used
273 | * by the {@link scs.couch-potato.$couchPotato $couchPotato service}
274 | * at run-time.
275 | *
276 | * It is **mandatory** that you inject the provider before
277 | * your app's module.run is called (e.g. in module.config).
278 | *
279 | * @example
280 | *
281 | * myModule.config(
282 | * [
283 | * '$couchPotatoProvider', 'myOtherProvider',
284 | * function($couchPotatoProvider, myOtherProvider) {
285 | * myOtherProvider.config = { someParam: 'demo' };
286 | * // $couchPotatoProvider needs no specific configuration
287 | * }
288 | * ]
289 | * );
290 | *
291 | *
292 | * See the {@link scs.couch-potato couch-potato module documentation} to learn
293 | * how to load the module.
294 | *
295 | * @requires $controllerProvider
296 | * @requires $compileProvider
297 | * @requires $filterProvider
298 | * @requires $provide
299 | *
300 | */
301 | module.provider('$couchPotato', CouchPotatoProvider);
302 |
303 | this.configureApp = function(app) {
304 | app.registerController = function(name, controller) {
305 | if (app.lazy) {
306 | app.lazy.registerController([name, controller]);
307 | }
308 | else {
309 | app.controller(name, controller);
310 | }
311 | return app;
312 | };
313 |
314 | app.registerFactory = function(name, factory) {
315 | if (app.lazy) {
316 | app.lazy.registerFactory([name, factory]);
317 | }
318 | else {
319 | app.factory(name, factory);
320 | }
321 | return app;
322 | };
323 |
324 |
325 | app.registerService = function(name, service) {
326 | if (app.lazy) {
327 | app.lazy.registerService([name, service]);
328 | }
329 | else {
330 | app.service(name, service);
331 | }
332 | return app;
333 | };
334 |
335 | app.registerDirective = function(name, directive) {
336 | if (app.lazy) {
337 | app.lazy.registerDirective([name, directive]);
338 | }
339 | else {
340 | app.directive(name, directive);
341 | }
342 | return app;
343 | };
344 |
345 | app.registerDecorator = function(name, decorator) {
346 | if (app.lazy) {
347 | app.lazy.registerDecorator([name, decorator]);
348 | }
349 | else {
350 | app.decorator(name, decorator);
351 | }
352 | return app;
353 | };
354 |
355 | app.registerProvider = function(name, provider) {
356 | if (app.lazy) {
357 | app.lazy.registerProvider([name, provider]);
358 | }
359 | else {
360 | app.provider(name, provider);
361 | }
362 | return app;
363 | };
364 |
365 | app.registerValue = function(name, value) {
366 | if (app.lazy) {
367 | app.lazy.registerValue([name, value]);
368 | }
369 | else {
370 | app.value(name, value);
371 | }
372 | return app;
373 | };
374 |
375 | app.registerConstant = function(name, value) {
376 | if (app.lazy) {
377 | app.lazy.registerConstant([name, value]);
378 | }
379 | else {
380 | app.constant(name, value);
381 | }
382 | return app;
383 | };
384 |
385 |
386 | app.registerFilter = function(name, filter) {
387 | if (app.lazy) {
388 | app.lazy.registerFilter([name, filter]);
389 | }
390 | else {
391 | app.filter(name, filter);
392 | }
393 | return app;
394 | };
395 |
396 | /**
397 | * extendInjectable Prototypically extends an injectable object from
398 | * another injectable object. Supports $inject-property-style injections
399 | * (e.g. CtrlFunc.$inject = ['$scope'];) and array notation
400 | * (e.g. ['$scope', function($scope) {...}]).
401 | *
402 | * @param object parent Parent object from which to extend.
403 | * @param object child Child object to receive into.
404 | * @return object The prototypically extended object.
405 | */
406 | app.extendInjectable = function(parent, child) {
407 |
408 | // split up injections and constructor
409 | function disassembleInjected(object) {
410 | if (angular.isArray(object)) {
411 | var func = object.slice(object.length - 1)[0];
412 | return [func, object.slice(0, object.length - 1)];
413 | }
414 | else {
415 | var injections = object.$inject;
416 | return [object, injections || []];
417 | }
418 | }
419 |
420 | parentPieces = disassembleInjected(parent);
421 | childPieces = disassembleInjected(child);
422 |
423 | // combined constructor.
424 | function CombinedConstructor() {
425 | var args = Array.prototype.slice.call(arguments);
426 |
427 | parentPieces[0].apply(this, args.slice(0, parentPieces[1].length));
428 | childPieces[0].apply(this, args.slice(parentPieces[1].length));
429 | }
430 |
431 | // combined object target
432 | function Inherit() {}
433 | // child's prototype will already be present
434 | Inherit.prototype = parentPieces[0].prototype;
435 |
436 | // instantiate it without calling constructor
437 | CombinedConstructor.prototype = new Inherit();
438 |
439 | // ask for everything.
440 | CombinedConstructor.$inject =
441 | [].concat(parentPieces[1]).concat(childPieces[1]);
442 |
443 | return CombinedConstructor;
444 | };
445 |
446 |
447 | };
448 |
449 | };
450 |
451 |
452 | if ( typeof(define) === 'function' && define.amd) {
453 | // expose couch potato as an AMD module depending on 'angular'
454 | // since we use angular from window, apps are not required
455 | // to export the angular object from a shim.
456 | define(['angular'], function() { return new CouchPotato(window.angular); });
457 | }
458 | else {
459 | window.couchPotato = new CouchPotato(angular);
460 | }
461 | }());
462 |
--------------------------------------------------------------------------------