Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

Commit 6cecd43

Browse files
committed
Merge branch 'master' into storage
2 parents 01ea208 + c22ef72 commit 6cecd43

9 files changed

Lines changed: 163 additions & 52 deletions

File tree

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ script:
1717
- sh ./tests/travis.sh
1818
before_script:
1919
- grunt install
20-
- phantomjs --version
20+
script:
21+
- sh ./tests/travis.sh
2122
after_script:
2223
- cat ./tests/coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
2324
env:

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ In order to use AngularFire in your project, you need to include the following f
4141

4242
```html
4343
<!-- AngularJS -->
44-
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
44+
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
4545

4646
<!-- Firebase -->
47-
<script src="https://www.gstatic.com/firebasejs/3.4.1/firebase.js"></script>
47+
<script src="https://www.gstatic.com/firebasejs/3.6.4/firebase.js"></script>
4848

4949
<!-- AngularFire -->
50-
<script src="https://cdn.firebase.com/libs/angularfire/2.0.2/angularfire.min.js"></script>
50+
<script src="https://cdn.firebase.com/libs/angularfire/2.2.0/angularfire.min.js"></script>
5151
```
5252

5353
You can also install AngularFire via npm and Bower and its dependencies will be downloaded

docs/guide/introduction-to-angularfire.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ AngularFire bindings from our CDN:
5757

5858
```html
5959
<!-- Angular -->
60-
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
60+
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
6161

6262
<!-- Firebase -->
63-
<script src="https://www.gstatic.com/firebasejs/3.3.0/firebase.js"></script>
63+
<script src="https://www.gstatic.com/firebasejs/3.6.4/firebase.js"></script>
6464

6565
<!-- AngularFire -->
66-
<script src="https://cdn.firebase.com/libs/angularfire/2.0.1/angularfire.min.js"></script>
66+
<script src="https://cdn.firebase.com/libs/angularfire/2.2.0/angularfire.min.js"></script>
6767
```
6868

6969
Firebase and AngularFire are also available via npm and Bower as `firebase` and `angularfire`,
@@ -215,7 +215,7 @@ When working directly with the SDK, it's important to notify Angular's compiler
215215
been loaded:
216216

217217
```js
218-
var ref = firebase().database().ref();
218+
var ref = firebase.database().ref();
219219
ref.on("value", function(snapshot) {
220220
// This isn't going to show up in the DOM immediately, because
221221
// Angular does not know we have changed this in memory.

docs/quickstart.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ In order to use AngularFire in a project, include the following script tags:
1717

1818
```html
1919
<!-- Angular -->
20-
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
20+
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
2121

2222
<!-- Firebase -->
23-
<script src="https://www.gstatic.com/firebasejs/3.3.0/firebase.js"></script>
23+
<script src="https://www.gstatic.com/firebasejs/3.6.4/firebase.js"></script>
2424

2525
<!-- AngularFire -->
26-
<script src="https://cdn.firebase.com/libs/angularfire/2.0.1/angularfire.min.js"></script>
26+
<script src="https://cdn.firebase.com/libs/angularfire/2.2.0/angularfire.min.js"></script>
2727
```
2828

2929
Firebase and AngularFire are also available via npm and Bower as `firebase` and `angularfire`,
@@ -76,7 +76,7 @@ In the example above, `$scope.data` is going to be populated from the remote ser
7676
asynchronous call, so it will take some time before the data becomes available in the controller.
7777
While it might be tempting to put a `console.log` on the next line to read the results, the data
7878
won't be downloaded yet, so the object will appear to be empty. Read the section on
79-
[Asynchronous Operations](guide/introduction-to-angularfire.html#handling-asynchronous-operations) for more details.
79+
[Asynchronous Operations](guide/introduction-to-angularfire.md#handling-asynchronous-operations) for more details.
8080

8181

8282
## 5. Add Three-Way, Object Bindings

docs/reference.md

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* [`$bindTo(scope, varName)`](#bindtoscope-varname)
1212
* [`$watch(callback, context)`](#watchcallback-context)
1313
* [`$destroy()`](#destroy)
14+
* [`$resolved`](#resolved)
1415
* [`$firebaseArray`](#firebasearray)
1516
* [`$add(newData)`](#addnewdata)
1617
* [`$remove(recordOrIndex)`](#removerecordorindex)
@@ -22,6 +23,7 @@
2223
* [`$ref()`](#ref-1)
2324
* [`$watch(cb[, context])`](#watchcb-context)
2425
* [`$destroy()`](#destroy-1)
26+
* [`$resolved`](#resolved-1)
2527
* [`$firebaseAuth`](#firebaseauth)
2628
* Authentication
2729
* [`$signInWithCustomToken(authToken)`](#signinwithcustomtokenauthtoken)
@@ -41,7 +43,7 @@
4143
* [`$sendPasswordResetEmail(email)`](#sendpasswordresetemailemail)
4244
* Router Helpers
4345
* [`$waitForSignIn()`](#waitforsignin)
44-
* [`$requireSignIn()`](#requiresignin)
46+
* [`$requireSignIn(requireEmailVerification)`](#requiresigninrequireemailverification)
4547
* [Extending the Services](#extending-the-services)
4648
* [Extending `$firebaseObject`](#extending-firebaseobject)
4749
* [Extending `$firebaseArray`](#extending-firebasearray)
@@ -174,8 +176,8 @@ obj.$save().then(function(ref) {
174176

175177
### $loaded()
176178

177-
Returns a promise which is resolved when the initial object data has been downloaded from the database.
178-
The promise resolves to the `$firebaseObject` itself.
179+
Returns a promise which is resolved asynchronously when the initial object data has been downloaded
180+
from the database. The promise resolves to the `$firebaseObject` itself.
179181

180182
```js
181183
var obj = $firebaseObject(ref);
@@ -288,6 +290,32 @@ unwatch();
288290
Calling this method cancels event listeners and frees memory used by this object (deletes the
289291
local data). Changes are no longer synchronized to or from the database.
290292

293+
### $resolved
294+
295+
Attribute which represents the loaded state for this object. Its value will be `true` if the initial
296+
object data has been downloaded from the database; otherwise, its value will be `false`. This
297+
attribute is complementary to the `$loaded()` method. If the `$loaded()` promise is completed
298+
(either with success or rejection), then `$resolved` will be `true`. `$resolved` will be
299+
`false` before that.
300+
301+
Knowing if the object has been resolved is useful to conditionally show certain parts of your view:
302+
303+
```js
304+
$scope.obj = $firebaseObject(ref);
305+
```
306+
307+
```html
308+
<!-- Loading state -->
309+
<div ng-if="!obj.$resolved">
310+
...
311+
</div>
312+
313+
<!-- Loaded state -->
314+
<div ng-if="obj.$resolved">
315+
...
316+
</div>
317+
```
318+
291319

292320
## $firebaseArray
293321

@@ -461,8 +489,8 @@ list.$indexFor("zulu"); // -1
461489

462490
### $loaded()
463491

464-
Returns a promise which is resolved when the initial array data has been downloaded from the
465-
database. The promise resolves to the `$firebaseArray`.
492+
Returns a promise which is resolved asynchronously when the initial array data has been downloaded
493+
from the database. The promise resolves to the `$firebaseArray`.
466494

467495
```js
468496
var list = $firebaseArray(ref);
@@ -547,6 +575,32 @@ function compare(a, b) {
547575
Stop listening for events and free memory used by this array (empties the local copy).
548576
Changes are no longer synchronized to or from the database.
549577

578+
### $resolved
579+
580+
Attribute which represents the loaded state for this array. Its value will be `true` if the initial
581+
array data has been downloaded from the database; otherwise, its value will be `false`. This
582+
attribute is complementary to the `$loaded()` method. If the `$loaded()` promise is completed
583+
(either with success or rejection), then `$resolved` will be `true`. `$resolved` will be
584+
`false` before that.
585+
586+
Knowing if the array has been resolved is useful to conditionally show certain parts of your view:
587+
588+
```js
589+
$scope.list = $firebaseArray(ref);
590+
```
591+
592+
```html
593+
<!-- Loading state -->
594+
<div ng-if="!list.$resolved">
595+
...
596+
</div>
597+
598+
<!-- Loaded state -->
599+
<div ng-if="list.$resolved">
600+
...
601+
</div>
602+
```
603+
550604

551605
## $firebaseAuth
552606

@@ -840,16 +894,15 @@ intended to be used in the `resolve()` method of Angular routers. See the
840894
["Using Authentication with Routers"](/docs/guide/user-auth.md#authenticating-with-routers)
841895
section of our AngularFire guide for more information and a full example.
842896

843-
### $requireSignIn()
897+
### $requireSignIn(requireEmailVerification)
844898

845899
Helper method which returns a promise fulfilled with the current authentication state if the user
846-
is authenticated but otherwise rejects the promise. This is intended to be used in the `resolve()`
847-
method of Angular routers to prevented unauthenticated users from seeing authenticated pages
848-
momentarily during page load. See the
900+
is authenticated and, if specified, has a verified email address, but otherwise rejects the promise.
901+
This is intended to be used in the `resolve()` method of Angular routers to prevented unauthenticated
902+
users from seeing authenticated pages momentarily during page load. See the
849903
["Using Authentication with Routers"](/docs/guide/user-auth.md#authenticating-with-routers)
850904
section of our AngularFire guide for more information and a full example.
851905

852-
853906
## Extending the Services
854907

855908
There are several powerful techniques for transforming the data downloaded and saved

package.json

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,32 +38,31 @@
3838
},
3939
"devDependencies": {
4040
"angular": "^1.3.0",
41-
"angular-mocks": "~1.4.6",
41+
"angular-mocks": "^1.6.0",
4242
"coveralls": "^2.11.2",
43-
"grunt": "~0.4.5",
44-
"grunt-cli": "^0.1.13",
45-
"grunt-contrib-concat": "^0.5.0",
46-
"grunt-contrib-connect": "^0.9.0",
43+
"grunt": "^1.0.1",
44+
"grunt-cli": "^1.2.0",
45+
"grunt-contrib-concat": "^1.0.1",
46+
"grunt-contrib-connect": "^1.0.2",
4747
"grunt-contrib-jshint": "^0.11.0",
48-
"grunt-contrib-uglify": "^0.7.0",
49-
"grunt-contrib-watch": "^0.6.1",
50-
"grunt-karma": "^0.10.1",
48+
"grunt-contrib-uglify": "^2.0.0",
49+
"grunt-contrib-watch": "^1.0.0",
50+
"grunt-karma": "^2.0.0",
5151
"grunt-notify": "^0.4.1",
52-
"grunt-protractor-runner": "^1.2.1",
52+
"grunt-protractor-runner": "^4.0.0",
5353
"grunt-shell-spawn": "^0.3.1",
5454
"jasmine-core": "^2.2.0",
5555
"jasmine-spec-reporter": "^2.1.0",
56-
"karma": "~0.12.31",
57-
"karma-chrome-launcher": "^0.2.2",
58-
"karma-coverage": "^0.2.7",
56+
"karma": "^1.3.0",
57+
"karma-chrome-launcher": "^2.0.0",
58+
"karma-coverage": "^1.1.1",
5959
"karma-failed-reporter": "0.0.3",
60-
"karma-firefox-launcher": "^0.1.4",
61-
"karma-html2js-preprocessor": "~0.1.0",
62-
"karma-jasmine": "^0.3.5",
63-
"karma-phantomjs-launcher": "~0.1.4",
64-
"karma-sauce-launcher": "~0.2.10",
65-
"karma-spec-reporter": "0.0.16",
60+
"karma-firefox-launcher": "^1.0.0",
61+
"karma-html2js-preprocessor": "^1.1.0",
62+
"karma-jasmine": "^1.1.0",
63+
"karma-sauce-launcher": "^1.1.0",
64+
"karma-spec-reporter": "^0.0.26",
6665
"load-grunt-tasks": "^3.1.0",
67-
"protractor": "^1.6.1"
66+
"protractor": "^4.0.13"
6867
}
6968
}

src/auth/FirebaseAuth.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,12 @@
184184
*
185185
* @param {boolean} rejectIfAuthDataIsNull Determines if the returned promise should be
186186
* resolved or rejected upon an unauthenticated client.
187+
* @param {boolean} rejectIfEmailNotVerified Determines if the returned promise should be
188+
* resolved or rejected upon a client without a verified email address.
187189
* @return {Promise<Object>} A promise fulfilled with the client's authentication state or
188190
* rejected if the client is unauthenticated and rejectIfAuthDataIsNull is true.
189191
*/
190-
_routerMethodOnAuthPromise: function(rejectIfAuthDataIsNull) {
192+
_routerMethodOnAuthPromise: function(rejectIfAuthDataIsNull, rejectIfEmailNotVerified) {
191193
var self = this;
192194

193195
// wait for the initial auth state to resolve; on page load we have to request auth state
@@ -200,6 +202,9 @@
200202
if (rejectIfAuthDataIsNull && authData === null) {
201203
res = self._q.reject("AUTH_REQUIRED");
202204
}
205+
else if (rejectIfEmailNotVerified && !authData.emailVerified) {
206+
res = self._q.reject("EMAIL_VERIFICATION_REQUIRED");
207+
}
203208
else {
204209
res = self._q.when(authData);
205210
}
@@ -248,11 +253,13 @@
248253
* Utility method which can be used in a route's resolve() method to require that a route has
249254
* a logged in client.
250255
*
256+
* @param {boolean} requireEmailVerification Determines if the route requires a client with a
257+
* verified email address.
251258
* @returns {Promise<Object>} A promise fulfilled with the client's current authentication
252259
* state or rejected if the client is not authenticated.
253260
*/
254-
requireSignIn: function() {
255-
return this._routerMethodOnAuthPromise(true);
261+
requireSignIn: function(requireEmailVerification) {
262+
return this._routerMethodOnAuthPromise(true, requireEmailVerification);
256263
},
257264

258265
/**
@@ -263,10 +270,9 @@
263270
* state, which will be null if the client is not authenticated.
264271
*/
265272
waitForSignIn: function() {
266-
return this._routerMethodOnAuthPromise(false);
273+
return this._routerMethodOnAuthPromise(false, false);
267274
},
268-
269-
275+
270276
/*********************/
271277
/* User Management */
272278
/*********************/

src/database/FirebaseObject.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,13 @@
461461
var isResolved = false;
462462
var def = $q.defer();
463463
var applyUpdate = $firebaseUtils.batch(function(snap) {
464-
var changed = firebaseObject.$$updated(snap);
465-
if( changed ) {
466-
// notifies $watch listeners and
467-
// updates $scope if bound to a variable
468-
firebaseObject.$$notify();
464+
if (firebaseObject) {
465+
var changed = firebaseObject.$$updated(snap);
466+
if( changed ) {
467+
// notifies $watch listeners and
468+
// updates $scope if bound to a variable
469+
firebaseObject.$$notify();
470+
}
469471
}
470472
});
471473
var error = $firebaseUtils.batch(function(err) {

tests/unit/FirebaseAuth.spec.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,57 @@ describe('FirebaseAuth',function(){
384384
tick();
385385
});
386386
});
387+
388+
describe('$requireSignIn(requireEmailVerification)',function(){
389+
it('will be resolved if user is logged in and has a verified email address', function(done){
390+
var credentials = {provider: 'facebook', emailVerified: true};
391+
spyOn(authService._, 'getAuth').and.callFake(function () {
392+
return credentials;
393+
});
394+
395+
authService.$requireSignIn(true)
396+
.then(function (result) {
397+
expect(result).toEqual(credentials);
398+
done();
399+
});
387400

401+
fakePromiseResolve(credentials);
402+
tick();
403+
});
404+
405+
it('will be resolved if user is logged in and we ignore email verification', function(done){
406+
var credentials = {provider: 'facebook', emailVerified: false};
407+
spyOn(authService._, 'getAuth').and.callFake(function () {
408+
return credentials;
409+
});
410+
411+
authService.$requireSignIn(false)
412+
.then(function (result) {
413+
expect(result).toEqual(credentials);
414+
done();
415+
});
416+
417+
fakePromiseResolve(credentials);
418+
tick();
419+
});
420+
421+
it('will be rejected if user does not have a verified email address', function(done){
422+
var credentials = {provider: 'facebook', emailVerified: false};
423+
spyOn(authService._, 'getAuth').and.callFake(function () {
424+
return credentials;
425+
});
426+
427+
authService.$requireSignIn(true)
428+
.catch(function (error) {
429+
expect(error).toEqual('EMAIL_VERIFICATION_REQUIRED');
430+
done();
431+
});
432+
433+
fakePromiseResolve(credentials);
434+
tick();
435+
});
436+
});
437+
388438
describe('$waitForSignIn()',function(){
389439
it('will be resolved with authData if user is logged in', function(done){
390440
var credentials = {provider: 'facebook'};

0 commit comments

Comments
 (0)