mirror of
https://github.com/wahyd4/cdnjs.git
synced 2026-08-09 21:06:39 +10:00
721 lines
24 KiB
JavaScript
721 lines
24 KiB
JavaScript
// AngularFire is an officially supported AngularJS binding for Firebase.
|
|
// The bindings let you associate a Firebase URL with a model (or set of
|
|
// models), and they will be transparently kept in sync across all clients
|
|
// currently using your app. The 2-way data binding offered by AngularJS works
|
|
// as normal, except that the changes are also sent to all other clients
|
|
// instead of just a server.
|
|
//
|
|
// AngularFire 0.3.2
|
|
// http://angularfire.com
|
|
// License: MIT
|
|
|
|
"use strict";
|
|
|
|
var AngularFire;
|
|
|
|
// Define the `firebase` module under which all AngularFire services will live.
|
|
angular.module("firebase", []).value("Firebase", Firebase);
|
|
|
|
// Define the `angularFire` service for implicit syncing. `angularFire` binds a
|
|
// model to $scope and keeps the data synchronized with a Firebase location
|
|
// both ways.
|
|
angular.module("firebase").factory("angularFire", ["$q", "$parse", "$timeout",
|
|
function($q, $parse, $timeout) {
|
|
// The factory returns a new instance of the `AngularFire` object, defined
|
|
// below, everytime it is called. The factory takes 3 arguments:
|
|
//
|
|
// * `ref`: A Firebase reference. Queries or limits may be applied.
|
|
// * `$scope`: The scope with which the bound model is associated.
|
|
// * `name`: The name of the model.
|
|
return function(ref, scope, name) {
|
|
var af = new AngularFire($q, $parse, $timeout, ref);
|
|
return af.associate(scope, name);
|
|
};
|
|
}
|
|
]);
|
|
|
|
// The `AngularFire` object that implements implicit synchronization.
|
|
AngularFire = function($q, $parse, $timeout, ref) {
|
|
this._q = $q;
|
|
this._parse = $parse;
|
|
this._timeout = $timeout;
|
|
this._initial = true;
|
|
this._remoteValue = false;
|
|
|
|
if (typeof ref == "string") {
|
|
throw new Error("Please provide a Firebase reference instead " +
|
|
"of a URL, eg: new Firebase(url)");
|
|
}
|
|
this._fRef = ref;
|
|
};
|
|
|
|
AngularFire.prototype = {
|
|
// This function is called by the factory to create a new 2-way binding
|
|
// between a particular model in a `$scope` and a particular Firebase
|
|
// location.
|
|
associate: function($scope, name) {
|
|
var self = this;
|
|
var deferred = this._q.defer();
|
|
var promise = deferred.promise;
|
|
// We're currently listening for value changes to implement synchronization.
|
|
// This needs to be optimized, see
|
|
// [Ticket #25](https://github.com/firebase/angularFire/issues/25).
|
|
this._fRef.on("value", function(snap) {
|
|
var remote = snap.val();
|
|
// We use toJson/fromJson to remove $$hashKey. Can be replaced by
|
|
// angular.copy, but only for later version of AngularJS.
|
|
var local = angular.fromJson(angular.toJson(self._parse(name)($scope)));
|
|
|
|
// If remote value matches local value, don't do anything.
|
|
if (angular.equals(remote, local)) {
|
|
return;
|
|
}
|
|
|
|
if (self._initial) {
|
|
// First value received from the server. We try and merge any local
|
|
// changes that may have been made with the server values.
|
|
var merged = false;
|
|
var check = Object.prototype.toString;
|
|
if (remote && check.call(local) == check.call(remote)) {
|
|
if (check.call(local) == "[object Array]") {
|
|
merged = local.concat(remote);
|
|
if (!angular.equals(merged, remote)) {
|
|
self._fRef.ref().set(merged);
|
|
remote = merged;
|
|
}
|
|
} else if (check.call(local) == "[object Object]") {
|
|
merged = local;
|
|
for (var key in remote) {
|
|
merged[key] = remote[key];
|
|
}
|
|
self._fRef.ref().update(merged);
|
|
remote = merged;
|
|
}
|
|
}
|
|
// If remote value is null, overwrite remote value with local
|
|
if (remote === null && local !== undefined) {
|
|
self._fRef.ref().set(local);
|
|
remote = local;
|
|
}
|
|
// If types don't match or the type is primitive, just overwrite the
|
|
// local value with the remote value.
|
|
self._initial = false;
|
|
}
|
|
|
|
var resolve = false;
|
|
if (deferred) {
|
|
resolve = deferred;
|
|
deferred = false;
|
|
}
|
|
|
|
// Update the local model to reflect remote changes.
|
|
self._timeout(function() {
|
|
self._resolve($scope, name, resolve, remote);
|
|
});
|
|
});
|
|
return promise;
|
|
},
|
|
|
|
// Disassociation added via
|
|
// [pull request #34](https://github.com/firebase/angularFire/pull/34).
|
|
// This function is provided to the promise returned by `angularFire`
|
|
// when it is fulfilled. Invoking it will stop the two-way synchronization.
|
|
disassociate: function() {
|
|
var self = this;
|
|
if (self._unregister) {
|
|
self._unregister();
|
|
}
|
|
this._fRef.off("value");
|
|
},
|
|
|
|
// If `deferred` is a valid promise, it will be resolved with `val`, and
|
|
// the model will be watched for future (local) changes. `$scope[name]`
|
|
// will also be updated to the provided value.
|
|
_resolve: function($scope, name, deferred, val) {
|
|
var self = this;
|
|
var localVal = angular.fromJson(angular.toJson(this._parse(name)($scope)));
|
|
if (val === null) {
|
|
// NULL values are special in Firebase. If received, set the local value
|
|
// to the initial state for Objects and Arrays.
|
|
if (typeof localVal == "object") {
|
|
var check = Object.prototype.toString;
|
|
if (check.call(localVal) == check.call([])) {
|
|
val = [];
|
|
} else {
|
|
val = {};
|
|
}
|
|
}
|
|
}
|
|
this._remoteValue = angular.copy(val);
|
|
this._parse(name).assign($scope, angular.copy(val));
|
|
if (deferred) {
|
|
deferred.resolve(function() {
|
|
self.disassociate();
|
|
});
|
|
this._watch($scope, name);
|
|
}
|
|
},
|
|
|
|
// Watch for local changes.
|
|
_watch: function($scope, name) {
|
|
var self = this;
|
|
self._unregister = $scope.$watch(name, function() {
|
|
// We ignore local value changes until the first value was received
|
|
// from the server.
|
|
if (self._initial) {
|
|
return;
|
|
}
|
|
// If the new local value matches the current remote value, we don't
|
|
// trigger a remote update.
|
|
var val = angular.fromJson(angular.toJson(self._parse(name)($scope)));
|
|
if (angular.equals(val, self._remoteValue)) {
|
|
return;
|
|
}
|
|
var check = Object.prototype.toString;
|
|
if (check.call(val) == "[object Object]") {
|
|
// Use update if limits are in effect, set if not.
|
|
if (self._fRef.set) {
|
|
self._fRef.set(val);
|
|
} else {
|
|
self._fRef.ref().update(val);
|
|
}
|
|
} else {
|
|
self._fRef.ref().set(val);
|
|
}
|
|
}, true);
|
|
// Also watch for scope destruction and unregister.
|
|
$scope.$on("$destroy", function() {
|
|
self.disassociate();
|
|
});
|
|
},
|
|
|
|
// Helper function to log messages.
|
|
_log: function(msg) {
|
|
if (console && console.log) {
|
|
console.log(msg);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Define the `angularFireCollection` service for explicit syncing.
|
|
// `angularFireCollection` provides a collection object that you can modify.
|
|
// [Original code](https://github.com/petebacondarwin/angular-firebase/blob/master/ng-firebase-collection.js)
|
|
// by @petebacondarwin.
|
|
angular.module("firebase").factory("angularFireCollection", ["$timeout",
|
|
function($timeout) {
|
|
// `angularFireCollection` takes a Firebase references as the first
|
|
// argument, and a function as an optional second argument. The callback
|
|
// (if provided in the 2nd argument) will be called with a Firebase
|
|
// snapshot when the initial data has been loaded.
|
|
return function(collectionRef, initialCb, onItemChangeCb) {
|
|
if (typeof collectionRef == "string") {
|
|
throw new Error("Please provide a Firebase reference instead " +
|
|
"of a URL, eg: new Firebase(url)");
|
|
}
|
|
|
|
// An internal representation of a model present in the collection.
|
|
var AngularFireItem = function(ref, index) {
|
|
this.$ref = ref.ref();
|
|
this.$id = ref.name();
|
|
this.$index = index;
|
|
angular.extend(this, {$priority: ref.getPriority()}, ref.val());
|
|
};
|
|
|
|
// Implementation of firebase priority ordering:
|
|
// https://www.firebase.com/docs/javascript/firebase/setpriority.html
|
|
var firebaseOrder = [
|
|
// Partition into [ no priority, number as priority, string as priority ]
|
|
function(item) {
|
|
if (item.$priority == null) {
|
|
return 0;
|
|
} else if (angular.isNumber(item.$priority)) {
|
|
return 1;
|
|
} else if (angular.isString(item.$priority)) {
|
|
return 2;
|
|
}
|
|
},
|
|
// Within partions, sort first by priority (lexical or numerical,
|
|
// no priority skips this level of sorting by returning Infinity)
|
|
function(item) {
|
|
return item.$priority ? item.$priority : Infinity;
|
|
},
|
|
// Finally, sort items of equal priority lexically by name
|
|
function(item) {
|
|
return item.$id;
|
|
}
|
|
];
|
|
|
|
var indexes = {};
|
|
var collection = [];
|
|
|
|
function broadcastChange(type, item) {
|
|
if (onItemChangeCb && typeof onItemChangeCb == "function") {
|
|
onItemChangeCb(type, item);
|
|
}
|
|
}
|
|
|
|
function getIndex(prevId) {
|
|
return prevId ? indexes[prevId] + 1 : 0;
|
|
}
|
|
|
|
// Add an item to the local collection.
|
|
function addChild(index, item) {
|
|
indexes[item.$id] = index;
|
|
collection.splice(index, 0, item);
|
|
}
|
|
|
|
// Remove an item from the local collection.
|
|
function removeChild(id) {
|
|
var index = indexes[id];
|
|
if (index !== undefined) {
|
|
collection.splice(index, 1);
|
|
indexes[id] = undefined;
|
|
}
|
|
}
|
|
|
|
// Update an existing child in the local collection.
|
|
function updateChild(index, item) {
|
|
collection[index] = item;
|
|
}
|
|
|
|
// Move an existing child to a new location in the collection (usually
|
|
// triggered by a priority change).
|
|
function moveChild(from, to, item) {
|
|
collection.splice(from, 1);
|
|
collection.splice(to, 0, item);
|
|
updateIndexes(from, to);
|
|
}
|
|
|
|
// Update the index table.
|
|
function updateIndexes(from, to) {
|
|
var length = collection.length;
|
|
to = to || length;
|
|
if (to > length) {
|
|
to = length;
|
|
}
|
|
for (var index = from; index < to; index++) {
|
|
var item = collection[index];
|
|
item.$index = indexes[item.$id] = index;
|
|
}
|
|
}
|
|
|
|
// Trigger the initial callback, if one was provided.
|
|
if (initialCb && typeof initialCb == "function") {
|
|
collectionRef.once("value", function() {
|
|
$timeout(initialCb);
|
|
});
|
|
}
|
|
|
|
// Attach handlers for remote child added, removed, changed and moved
|
|
// events.
|
|
|
|
collectionRef.on("child_added", function(data, prevId) {
|
|
$timeout(function() {
|
|
var index = getIndex(prevId);
|
|
var item = new AngularFireItem(data, index);
|
|
addChild(index, item);
|
|
updateIndexes(index);
|
|
broadcastChange("item_added", item);
|
|
});
|
|
});
|
|
|
|
collectionRef.on("child_removed", function(data) {
|
|
$timeout(function() {
|
|
var id = data.name();
|
|
var pos = indexes[id];
|
|
var item = collection[pos];
|
|
removeChild(id);
|
|
updateIndexes(pos);
|
|
broadcastChange("item_removed", item);
|
|
});
|
|
});
|
|
|
|
collectionRef.on("child_changed", function(data, prevId) {
|
|
$timeout(function() {
|
|
var index = indexes[data.name()];
|
|
var newIndex = getIndex(prevId);
|
|
var item = new AngularFireItem(data, index);
|
|
broadcastChange("item_removed", collection[index]);
|
|
updateChild(index, item);
|
|
if (newIndex !== index) {
|
|
moveChild(index, newIndex, item);
|
|
}
|
|
broadcastChange("item_added", item);
|
|
});
|
|
});
|
|
|
|
collectionRef.on("child_moved", function(ref, prevId) {
|
|
$timeout(function() {
|
|
var oldIndex = indexes[ref.name()];
|
|
var newIndex = getIndex(prevId);
|
|
var item = collection[oldIndex];
|
|
moveChild(oldIndex, newIndex, item);
|
|
broadcastChange("item_moved", item);
|
|
});
|
|
});
|
|
|
|
// `angularFireCollection` exposes four methods on the collection
|
|
// returned.
|
|
|
|
// Retrieve object by name.
|
|
collection.getByName = function(name) {
|
|
return collection[indexes[name]];
|
|
};
|
|
|
|
// Retrieve a collection of objects by names.
|
|
collection.getByNames = function(names) {
|
|
var objs = [];
|
|
for (var i = 0, len = names.length; i < len; i++) {
|
|
objs.push(collection[indexes[names[i]]]);
|
|
}
|
|
return objs;
|
|
};
|
|
|
|
// Add an object to the remote collection. Adding an object is the
|
|
// equivalent of calling `push()` on a Firebase reference.
|
|
collection.add = function(item, cb) {
|
|
var ref;
|
|
// Make sure to remove $$hashKey etc.
|
|
var newItem = angular.fromJson(angular.toJson(item));
|
|
if (!cb) {
|
|
ref = collectionRef.ref().push(newItem);
|
|
} else {
|
|
ref = collectionRef.ref().push(newItem, cb);
|
|
}
|
|
return ref;
|
|
};
|
|
|
|
// Remove an object from the remote collection.
|
|
collection.remove = function(itemOrId, cb) {
|
|
var item = angular.isString(itemOrId) ?
|
|
collection[indexes[itemOrId]] : itemOrId;
|
|
if (!cb) {
|
|
item.$ref.remove();
|
|
} else {
|
|
item.$ref.remove(cb);
|
|
}
|
|
};
|
|
|
|
// Incrementally update an object in the remote collection.
|
|
collection.update = function(itemOrId, cb) {
|
|
var item = angular.isString(itemOrId) ?
|
|
collection[indexes[itemOrId]] : itemOrId;
|
|
var copy = angular.fromJson(angular.toJson(item));
|
|
if (!cb) {
|
|
item.$ref.update(copy);
|
|
} else {
|
|
item.$ref.update(copy, cb);
|
|
}
|
|
};
|
|
|
|
// Update an object in its entirety in the remote collection.
|
|
collection.set = function(itemOrId, cb) {
|
|
var item = angular.isString(itemOrId) ?
|
|
collection[indexes[itemOrId]] : itemOrId;
|
|
var copy = angular.fromJson(angular.toJson(item));
|
|
if (!cb) {
|
|
item.$ref.set(copy);
|
|
} else {
|
|
item.$ref.set(copy, cb);
|
|
}
|
|
};
|
|
|
|
collection.order = firebaseOrder;
|
|
return collection;
|
|
};
|
|
}
|
|
]);
|
|
|
|
// Defines the `angularFireAuth` service that provides authentication support
|
|
// for AngularFire.
|
|
angular.module("firebase").factory("angularFireAuth", [
|
|
"$injector", "$rootScope", "$parse", "$timeout", "$location", "$q",
|
|
function($injector, $rootScope, $parse, $timeout, $location, $q) {
|
|
// Check if '$route' is present, use if available.
|
|
var $route = null;
|
|
if ($injector.has("$route")) {
|
|
$route = $injector.get("$route");
|
|
}
|
|
|
|
// Helper function to decode Base64 (polyfill for window.btoa on IE).
|
|
// From: https://github.com/mshang/base64-js/blob/master/base64.js
|
|
function decodeBase64(str) {
|
|
var char_set =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
var output = ""; // final output
|
|
var buf = ""; // binary buffer
|
|
var bits = 8;
|
|
for (var i = 0; i < str.length; ++i) {
|
|
if (str[i] == "=") {
|
|
break;
|
|
}
|
|
var c_num = char_set.indexOf(str.charAt(i));
|
|
if (c_num == -1) {
|
|
throw new Error("Not base64.");
|
|
}
|
|
var c_bin = c_num.toString(2);
|
|
while (c_bin.length < 6) {
|
|
c_bin = "0" + c_bin;
|
|
}
|
|
buf += c_bin;
|
|
|
|
while (buf.length >= bits) {
|
|
var octet = buf.slice(0, bits);
|
|
buf = buf.slice(bits);
|
|
output += String.fromCharCode(parseInt(octet, 2));
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
// Helper function to extract claims from a JWT. Does *not* verify the
|
|
// validity of the token.
|
|
function deconstructJWT(token) {
|
|
var segments = token.split(".");
|
|
if (!segments instanceof Array || segments.length !== 3) {
|
|
throw new Error("Invalid JWT");
|
|
}
|
|
var decoded = "";
|
|
var claims = segments[1];
|
|
if (window.atob) {
|
|
decoded = window.atob(claims);
|
|
} else {
|
|
decoded = decodeBase64(claims);
|
|
}
|
|
return JSON.parse(decodeURIComponent(escape(decoded)));
|
|
}
|
|
|
|
// Updates the provided model.
|
|
function updateExpression(scope, name, val, cb) {
|
|
if (name) {
|
|
$timeout(function() {
|
|
$parse(name).assign(scope, val);
|
|
cb();
|
|
});
|
|
}
|
|
}
|
|
|
|
// A function to check whether the current path requires authentication,
|
|
// and if so, whether a redirect to a login page is needed.
|
|
function authRequiredRedirect(route, path, self) {
|
|
if (route.authRequired && !self._authenticated){
|
|
if (route.pathTo === undefined) {
|
|
self._redirectTo = $location.path();
|
|
} else {
|
|
self._redirectTo = route.pathTo === path ? "/" : route.pathTo;
|
|
}
|
|
$location.replace();
|
|
$location.path(path);
|
|
}
|
|
}
|
|
|
|
return {
|
|
// Initializes the authentication service. Takes a Firebase reference and
|
|
// an options object, that may contain the following properties:
|
|
//
|
|
// * `scope`: The scope to which user authentication status will be
|
|
// bound to. Defaults to `$rootScope` if not provided.
|
|
// * `name`: Name of the model to which user auth state is bound.
|
|
// * `callback`: A function that will be called when there is a change
|
|
// in authentication state.
|
|
// * `path`: The path to which the user will be redirected if the
|
|
// `authRequired` property was set to true in the `$routeProvider`, and
|
|
// the user isn't logged in.
|
|
// * `simple`: AngularFireAuth requires inclusion of the
|
|
// `firebase-simple-login.js` file by default. If this value is set to
|
|
// false, this requirement is waived, but only custom login functionality
|
|
// will be enabled.
|
|
initialize: function(ref, options) {
|
|
var self = this;
|
|
|
|
if (typeof ref == "string") {
|
|
throw new Error("Please provide a Firebase reference instead " +
|
|
"of a URL, eg: new Firebase(url)");
|
|
}
|
|
|
|
options = options || {};
|
|
this._scope = $rootScope;
|
|
if (options.scope) {
|
|
this._scope = options.scope;
|
|
} else {
|
|
throw new Error("Scope not provided to angularFireAuth!");
|
|
}
|
|
if (options.name) {
|
|
this._name = options.name;
|
|
} else {
|
|
throw new Error("Model name not provided to angularFireAuth!");
|
|
}
|
|
|
|
this._cb = function(){};
|
|
if (options.callback && typeof options.callback === "function") {
|
|
this._cb = options.callback;
|
|
}
|
|
|
|
this._redirectTo = null;
|
|
this._authenticated = false;
|
|
if (options.path && $route !== null) {
|
|
// Check if the current page requires authentication.
|
|
if ($route.current) {
|
|
authRequiredRedirect($route.current, options.path, self);
|
|
}
|
|
// Set up a handler for all future route changes, so we can check
|
|
// if authentication is required.
|
|
$rootScope.$on("$routeChangeStart", function(e, next) {
|
|
authRequiredRedirect(next, options.path, self);
|
|
});
|
|
}
|
|
|
|
// Initialize user authentication state to `null`.
|
|
this._ref = ref;
|
|
if (options.simple === false) {
|
|
updateExpression(this._scope, this._name, null, function() {});
|
|
return;
|
|
}
|
|
|
|
// Initialize Simple Login.
|
|
if (!window.FirebaseSimpleLogin) {
|
|
var err = new Error("FirebaseSimpleLogin undefined, " +
|
|
"did you include firebase-simple-login.js?");
|
|
$rootScope.$broadcast("angularFireAuth:error", err);
|
|
return;
|
|
}
|
|
var client = new FirebaseSimpleLogin(this._ref, function(err, user) {
|
|
self._cb(err, user);
|
|
if (err) {
|
|
$rootScope.$broadcast("angularFireAuth:error", err);
|
|
} else if (user) {
|
|
self._loggedIn(user);
|
|
} else {
|
|
self._loggedOut();
|
|
}
|
|
});
|
|
this._authClient = client;
|
|
},
|
|
|
|
// The login method takes a provider (for Simple Login) or a token
|
|
// (for Custom Login) and authenticates the Firebase URL with which
|
|
// the service was initialized.
|
|
login: function(tokenOrProvider, options) {
|
|
var promise = this._watchForLogin();
|
|
switch (tokenOrProvider) {
|
|
case "github":
|
|
case "persona":
|
|
case "twitter":
|
|
case "facebook":
|
|
case "anonymous":
|
|
case "password":
|
|
if (!this._authClient) {
|
|
var err = new Error("Simple Login not initialized");
|
|
$rootScope.$broadcast("angularFireAuth:error", err);
|
|
} else {
|
|
this._authClient.login(tokenOrProvider, options);
|
|
}
|
|
break;
|
|
// A token was provided, so initialize custom login.
|
|
default:
|
|
var claims, self = this;
|
|
try {
|
|
// Extract claims and update user auth state to include them.
|
|
claims = deconstructJWT(tokenOrProvider);
|
|
this._ref.auth(tokenOrProvider, function(err) {
|
|
if (err) {
|
|
$rootScope.$broadcast("angularFireAuth:error", err);
|
|
} else {
|
|
self._loggedIn(claims);
|
|
}
|
|
});
|
|
} catch(e) {
|
|
$rootScope.$broadcast("angularFireAuth:error", e);
|
|
}
|
|
}
|
|
return promise;
|
|
},
|
|
|
|
// Function cb receives an error as the first argument and a
|
|
// Simple Login user object as the second argument. Pass noLogin=true
|
|
// if you don't want the newly created user to also be logged in.
|
|
createUser: function(email, password, cb, noLogin){
|
|
var self = this;
|
|
this._authClient.createUser(email, password, function(err, user){
|
|
try {
|
|
if (err) {
|
|
$rootScope.$broadcast("angularFireAuth:error", err);
|
|
} else {
|
|
if (!noLogin) {
|
|
self.login("password", {email: email, password: password});
|
|
}
|
|
}
|
|
} catch(e) {
|
|
$rootScope.$broadcast("angularFireAuth:error", e);
|
|
}
|
|
if (cb) {
|
|
$timeout(function(){
|
|
cb(err, user);
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// Unauthenticate the Firebase reference.
|
|
logout: function() {
|
|
if (this._authClient) {
|
|
this._authClient.logout();
|
|
} else {
|
|
this._ref.unauth();
|
|
this._loggedOut();
|
|
}
|
|
},
|
|
|
|
// Common function to trigger a login event on the root scope.
|
|
_loggedIn: function(user) {
|
|
var self = this;
|
|
this._authenticated = true;
|
|
updateExpression(this._scope, this._name, user, function() {
|
|
$rootScope.$broadcast("angularFireAuth:login", user);
|
|
if (self._redirectTo) {
|
|
$location.replace();
|
|
$location.path(self._redirectTo);
|
|
self._redirectTo = null;
|
|
}
|
|
});
|
|
},
|
|
|
|
// Common function to trigger a logout event on the root scope.
|
|
_loggedOut: function() {
|
|
this._authenticated = false;
|
|
updateExpression(this._scope, this._name, null, function() {
|
|
$rootScope.$broadcast("angularFireAuth:logout");
|
|
});
|
|
},
|
|
|
|
_watchForLogin: function() {
|
|
var subs = [], def = $q.defer();
|
|
function done(err, user) {
|
|
// timeout is necessary because it a) allows the auth callbacks to take
|
|
// effect (applying auth parms before this is invoked) and b) forces
|
|
// $scope.apply(), which is necessary to make the promise resolve()
|
|
// event actually get sent to the listeners
|
|
$timeout(function() {
|
|
if (err) {
|
|
def.reject(err);
|
|
} else {
|
|
def.resolve(user);
|
|
}
|
|
});
|
|
for (var i=0; i < subs.length; i++) {
|
|
subs[i]();
|
|
}
|
|
}
|
|
subs.push($rootScope.$on("angularFireAuth:login", function(evt, user) {
|
|
done(null, user);
|
|
}));
|
|
subs.push($rootScope.$on("angularFireAuth:error", function(evt, err) {
|
|
done(err, null);
|
|
}));
|
|
return def.promise;
|
|
}
|
|
};
|
|
}
|
|
]);
|
|
|