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

Commit e584905

Browse files
committed
chore(refactor): , , and other comments from Jacob
1 parent da9a148 commit e584905

5 files changed

Lines changed: 157 additions & 69 deletions

File tree

src/storage/FirebaseStorage.js

Lines changed: 95 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,55 @@
11
(function() {
22
"use strict";
33

4-
function unwrapStorageSnapshot(storageSnapshot) {
4+
/**
5+
* Take an UploadTask and create an interface for the user to monitor the
6+
* file's upload. The $progress, $error, and $complete methods are provided
7+
* to work with the $digest cycle.
8+
*
9+
* @param task
10+
* @param $firebaseUtils
11+
* @returns A converted task, which contains methods for monitoring the
12+
* upload progress.
13+
*/
14+
function _convertTask(task, $firebaseUtils) {
15+
return {
16+
$progress: function $progress(callback) {
17+
task.on('state_changed', function () {
18+
$firebaseUtils.compile(function () {
19+
callback(_unwrapStorageSnapshot(task.snapshot));
20+
});
21+
});
22+
},
23+
$error: function $error(callback) {
24+
task.on('state_changed', null, function (err) {
25+
$firebaseUtils.compile(function () {
26+
callback(err);
27+
});
28+
});
29+
},
30+
$complete: function $complete(callback) {
31+
task.on('state_changed', null, null, function () {
32+
$firebaseUtils.compile(function () {
33+
callback(_unwrapStorageSnapshot(task.snapshot));
34+
});
35+
});
36+
},
37+
$cancel: task.cancel,
38+
$resume: task.resume,
39+
$pause: task.pause,
40+
then: task.then,
41+
catch: task.catch,
42+
$snapshot: task.snapshot
43+
};
44+
}
45+
46+
/**
47+
* Take an Firebase Storage snapshot and unwrap only the needed properties.
48+
*
49+
* @param snapshot
50+
* @returns An object containing the unwrapped values.
51+
*/
52+
function _unwrapStorageSnapshot(storageSnapshot) {
553
return {
654
bytesTransferred: storageSnapshot.bytesTransferred,
755
downloadURL: storageSnapshot.downloadURL,
@@ -13,54 +61,56 @@
1361
};
1462
}
1563

16-
function isStorageRef(value) {
64+
/**
65+
* Determines if the value passed in is a Firebase Storage Reference. The
66+
* put method is used for the check.
67+
*
68+
* @param value
69+
* @returns A boolean that indicates if the value is a Firebase Storage
70+
* Reference.
71+
*/
72+
function _isStorageRef(value) {
1773
value = value || {};
1874
return typeof value.put === 'function';
1975
}
2076

77+
/**
78+
* Checks if the parameter is a Firebase Storage Reference, and throws an
79+
* error if it is not.
80+
*
81+
* @param storageRef
82+
*/
2183
function _assertStorageRef(storageRef) {
22-
if (!isStorageRef(storageRef)) {
84+
if (!_isStorageRef(storageRef)) {
2385
throw new Error('$firebaseStorage expects a Storage reference');
2486
}
2587
}
2688

89+
/**
90+
* This constructor should probably never be called manually. It is setup
91+
* for dependecy injection of the $firebaseUtils and $q service.
92+
*
93+
* @param {Object} $firebaseUtils
94+
* @param {Object} $q
95+
* @returns {Object}
96+
* @constructor
97+
*/
2798
function FirebaseStorage($firebaseUtils, $q) {
2899

100+
/**
101+
* This inner constructor `Storage` allows for exporting of private methods
102+
* like _assertStorageRef, _isStorageRef, _convertTask, and _unwrapStorageSnapshot.
103+
*/
29104
var Storage = function Storage(storageRef) {
30105
_assertStorageRef(storageRef);
31106
return {
32-
$put: function $put(file) {
33-
var task = storageRef.put(file);
34-
35-
return {
36-
$progress: function $progress(callback) {
37-
task.on('state_changed', function () {
38-
$firebaseUtils.compile(function () {
39-
callback(unwrapStorageSnapshot(task.snapshot));
40-
});
41-
});
42-
},
43-
$error: function $error(callback) {
44-
task.on('state_changed', null, function (err) {
45-
$firebaseUtils.compile(function () {
46-
callback(err);
47-
});
48-
});
49-
},
50-
$complete: function $complete(callback) {
51-
task.on('state_changed', null, null, function () {
52-
$firebaseUtils.compile(function () {
53-
callback(unwrapStorageSnapshot(task.snapshot));
54-
});
55-
});
56-
},
57-
$cancel: task.cancel,
58-
$resume: task.resume,
59-
$pause: task.pause,
60-
then: task.then,
61-
catch: task.catch,
62-
_task: task
63-
};
107+
$put: function $put(file, metadata) {
108+
var task = storageRef.put(file, metadata);
109+
return _convertTask(task, $firebaseUtils);
110+
},
111+
$putString: function $putString(data, format, metadata) {
112+
var task = storageRef.putString(data, format, metadata);
113+
return _convertTask(task, $firebaseUtils);
64114
},
65115
$getDownloadURL: function $getDownloadURL() {
66116
return $q.when(storageRef.getDownloadURL());
@@ -73,19 +123,27 @@
73123
},
74124
$updateMetadata: function $updateMetadata(object) {
75125
return $q.when(storageRef.updateMetadata(object));
126+
},
127+
$toString: function $toString() {
128+
return storageRef.toString();
76129
}
77130
};
78131
};
79132

80133
Storage.utils = {
81-
_unwrapStorageSnapshot: unwrapStorageSnapshot,
82-
_isStorageRef: isStorageRef,
134+
_unwrapStorageSnapshot: _unwrapStorageSnapshot,
135+
_isStorageRef: _isStorageRef,
83136
_assertStorageRef: _assertStorageRef
84137
};
85138

86139
return Storage;
87140
}
88141

142+
/**
143+
* Creates a wrapper for the firebase.storage() object. This factory allows
144+
* you to upload files and monitor their progress and the callbacks are
145+
* wrapped in the $digest cycle.
146+
*/
89147
angular.module('firebase.storage')
90148
.factory('$firebaseStorage', ["$firebaseUtils", "$q", FirebaseStorage]);
91149

src/storage/FirebaseStorageDirective.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99
scope: {},
1010
link: function (scope, element, attrs) {
1111
// $observe is like $watch but it waits for interpolation
12+
// any value passed as an attribute is converted to a string
13+
// if null or undefined is passed, it is converted to an empty string
1214
// Ex: <img firebase-src="{{ myUrl }}"/>
1315
attrs.$observe('firebaseSrc', function (newFirebaseSrcVal) {
14-
if (newFirebaseSrcVal !== '' &&
15-
newFirebaseSrcVal !== null &&
16-
newFirebaseSrcVal !== undefined &&
17-
typeof newFirebaseSrcVal === 'string') {
16+
if (newFirebaseSrcVal !== '') {
1817
var storageRef = firebase.storage().ref(newFirebaseSrcVal);
1918
var storage = $firebaseStorage(storageRef);
2019
storage.$getDownloadURL().then(function getDownloadURL(url) {

tests/protractor/upload/upload.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929

3030
<br />
3131
<div ng-show="metadata.downloadURL" id="url">{{metadata.downloadURL}}</div>
32+
33+
<div ng-show="error">
34+
{{ error | json }}
35+
</div>
36+
3237
<!-- Custom JS -->
3338
<script src="upload.js" defer></script>
3439
</body>

tests/protractor/upload/upload.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var app = angular.module('upload', ['firebase.storage']);
22

33
app.controller('UploadCtrl', function Upload($scope, $firebaseStorage, $timeout) {
4-
// Create a reference (possible create a provider)
4+
// Create a reference
55
const storageRef = firebase.storage().ref('user/1.png');
66
// Create the storage binding
77
const storageFire = $firebaseStorage(storageRef);
@@ -15,7 +15,7 @@ app.controller('UploadCtrl', function Upload($scope, $firebaseStorage, $timeout)
1515
$scope.upload = function() {
1616
$scope.isUploading = true;
1717
$scope.metadata = {bytesTransferred: 0, totalBytes: 1};
18-
$scope.error = {};
18+
$scope.error = null;
1919

2020
// upload the file
2121
const task = storageFire.$put(file);

tests/unit/FirebaseStorage.spec.js

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,29 @@ describe('$firebaseStorage', function () {
2323
});
2424
});
2525

26+
function setupPutTests(file, mockTask, isPutString) {
27+
var ref = firebase.storage().ref('thing');
28+
var task = null;
29+
var storage = $firebaseStorage(ref);
30+
var putMethod = isPutString ? 'putString': 'put';
31+
// If a MockTask is provided use it as the
32+
// return value of the spy on put
33+
if (mockTask) {
34+
spyOn(ref, putMethod).and.returnValue(mockTask);
35+
} else {
36+
spyOn(ref, putMethod);
37+
}
38+
task = storage['$' + putMethod](file);
39+
return {
40+
ref: ref,
41+
task: task
42+
};
43+
}
44+
45+
function setupPutStringTests(file, mockTask) {
46+
return setupPutTests(file, mockTask, true);
47+
}
48+
2649
it('should exist', inject(function () {
2750
expect($firebaseStorage).not.toBe(null);
2851
}));
@@ -105,29 +128,11 @@ describe('$firebaseStorage', function () {
105128

106129
describe('$put', function() {
107130

108-
function setupPutTests(file, mockTask) {
109-
var ref = firebase.storage().ref('thing');
110-
var task = null;
111-
var storage = $firebaseStorage(ref);
112-
// If a MockTask is provided use it as the
113-
// return value of the spy on put
114-
if (mockTask) {
115-
spyOn(ref, 'put').and.returnValue(mockTask);
116-
} else {
117-
spyOn(ref, 'put');
118-
}
119-
task = storage.$put(file);
120-
return {
121-
ref: ref,
122-
task: task
123-
};
124-
}
125-
126131
it('should call a storage ref put', function () {
127132
var mockTask = new MockTask();
128133
var setup = setupPutTests('file', mockTask);
129134
var ref = setup.ref;
130-
expect(ref.put).toHaveBeenCalledWith('file');
135+
expect(ref.put).toHaveBeenCalledWith('file', undefined);
131136
});
132137

133138
it('should return the observer functions', function () {
@@ -147,13 +152,6 @@ describe('$firebaseStorage', function () {
147152
expect(task.catch).toEqual(jasmine.any(Function));
148153
});
149154

150-
it('should create a mock task', function() {
151-
var mockTask = new MockTask();
152-
var setup = setupPutTests('file', mockTask);
153-
var task = setup.task;
154-
expect(task._task).toEqual(mockTask);
155-
});
156-
157155
it('$cancel', function() {
158156
var mockTask = new MockTask();
159157
spyOn(mockTask, 'cancel');
@@ -201,6 +199,34 @@ describe('$firebaseStorage', function () {
201199

202200
});
203201

202+
describe('$putString', function() {
203+
it('should call a storage ref put', function () {
204+
var mockTask = new MockTask();
205+
var setup = setupPutStringTests('string data', mockTask);
206+
var ref = setup.ref;
207+
// The two undefineds are for the optional parameters that are still
208+
// passed under the hood.
209+
expect(ref.putString).toHaveBeenCalledWith('string data', undefined, undefined);
210+
});
211+
});
212+
213+
describe('$toString', function() {
214+
it('should call a storage ref to string', function() {
215+
var ref = firebase.storage().ref('myfile');
216+
var storage = $firebaseStorage(ref);
217+
spyOn(ref, 'toString');
218+
storage.$toString();
219+
expect(ref.toString).toHaveBeenCalled();
220+
});
221+
222+
it('should return the proper gs:// URL', function() {
223+
var ref = firebase.storage().ref('myfile');
224+
var storage = $firebaseStorage(ref);
225+
var stringValue = storage.$toString();
226+
expect(stringValue).toEqual(ref.toString());
227+
});
228+
});
229+
204230
describe('$getDownloadURL', function() {
205231
it('should call the ref getDownloadURL method', function() {
206232
var ref = firebase.storage().ref('thing');

0 commit comments

Comments
 (0)