Skip to content

Commit 1eb0309

Browse files
committed
[firebase-release] Updated ReactFire to 0.6.0
1 parent 10f2aa6 commit 1eb0309

File tree

5 files changed

+378
-3
lines changed

5 files changed

+378
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ In order to use ReactFire in your project, you need to include the following fil
2828
<script src="https://cdn.firebase.com/js/client/2.3.0/firebase.js"></script>
2929

3030
<!-- ReactFire -->
31-
<script src="https://cdn.firebase.com/libs/reactfire/0.5.1/reactfire.min.js"></script>
31+
<script src="https://cdn.firebase.com/libs/reactfire/0.6.0/reactfire.min.js"></script>
3232
```
3333

3434
Use the URL above to download both the minified and non-minified versions of ReactFire from the

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "reactfire",
33
"description": "Firebase mixin for ReactJS",
4-
"version": "0.0.0",
4+
"version": "0.6.0",
55
"authors": [
66
"Firebase <support@firebase.com>"
77
],

dist/reactfire.js

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
/*!
2+
* ReactFire is an open-source JavaScript library that allows you to add a
3+
* realtime data source to your React apps by providing an easy way to let
4+
* Firebase populate the state of React components.
5+
*
6+
* ReactFire 0.6.0
7+
* https://github.com/firebase/reactfire/
8+
* License: MIT
9+
*/
10+
/* eslint "strict": [2, "function"] */
11+
(function(root, factory) {
12+
'use strict';
13+
14+
/* istanbul ignore next */
15+
if (typeof define === 'function' && define.amd) {
16+
// AMD
17+
define([], function() {
18+
return (root.ReactFireMixin = factory());
19+
});
20+
} else if (typeof exports === 'object') {
21+
// CommonJS
22+
module.exports = factory();
23+
} else {
24+
// Global variables
25+
root.ReactFireMixin = factory();
26+
}
27+
}(this, function() {
28+
'use strict';
29+
30+
/*************/
31+
/* HELPERS */
32+
/*************/
33+
/**
34+
* Returns the index of the key in the list. If an item with the key is not in the list, -1 is
35+
* returned.
36+
*
37+
* @param {Array<any>} list A list of items.
38+
* @param {string} key The key for which to search.
39+
* @return {number} The index of the item which has the provided key or -1 if no items have the
40+
* provided key.
41+
*/
42+
function _indexForKey(list, key) {
43+
for (var i = 0, length = list.length; i < length; ++i) {
44+
if (list[i]['.key'] === key) {
45+
return i;
46+
}
47+
}
48+
49+
/* istanbul ignore next */
50+
return -1;
51+
}
52+
53+
/**
54+
* Throws a formatted error message.
55+
*
56+
* @param {string} message The error message to throw.
57+
*/
58+
function _throwError(message) {
59+
throw new Error('ReactFire: ' + message);
60+
}
61+
62+
/**
63+
* Validates the name of the variable which is being bound.
64+
*
65+
* @param {string} bindVar The variable which is being bound.
66+
*/
67+
function _validateBindVar(bindVar) {
68+
var errorMessage;
69+
70+
if (typeof bindVar !== 'string') {
71+
errorMessage = 'Bind variable must be a string. Got: ' + bindVar;
72+
} else if (bindVar.length === 0) {
73+
errorMessage = 'Bind variable must be a non-empty string. Got: ""';
74+
} else if (bindVar.length > 768) {
75+
// Firebase can only stored child paths up to 768 characters
76+
errorMessage = 'Bind variable is too long to be stored in Firebase. Got: ' + bindVar;
77+
} else if (/[\[\].#$\/\u0000-\u001F\u007F]/.test(bindVar)) {
78+
// Firebase does not allow node keys to contain the following characters
79+
errorMessage = 'Bind variable cannot contain any of the following characters: . # $ ] [ /. Got: ' + bindVar;
80+
}
81+
82+
if (typeof errorMessage !== 'undefined') {
83+
_throwError(errorMessage);
84+
}
85+
}
86+
87+
/**
88+
* Creates a new record given a key-value pair.
89+
*
90+
* @param {string} key The new record's key.
91+
* @param {any} value The new record's value.
92+
* @return {Object} The new record.
93+
*/
94+
function _createRecord(key, value) {
95+
var record = {};
96+
if (typeof value === 'object' && value !== null) {
97+
record = value;
98+
} else {
99+
record['.value'] = value;
100+
}
101+
record['.key'] = key;
102+
103+
return record;
104+
}
105+
106+
107+
/******************************/
108+
/* BIND AS OBJECT LISTENERS */
109+
/******************************/
110+
/**
111+
* 'value' listener which updates the value of the bound state variable.
112+
*
113+
* @param {string} bindVar The state variable to which the data is being bound.
114+
* @param {Firebase.DataSnapshot} snapshot A snapshot of the data being bound.
115+
*/
116+
function _objectValue(bindVar, snapshot) {
117+
var key = snapshot.key();
118+
var value = snapshot.val();
119+
120+
this.data[bindVar] = _createRecord(key, value);
121+
122+
this.setState(this.data);
123+
}
124+
125+
126+
/*****************************/
127+
/* BIND AS ARRAY LISTENERS */
128+
/*****************************/
129+
/**
130+
* 'child_added' listener which adds a new record to the bound array.
131+
*
132+
* @param {string} bindVar The state variable to which the data is being bound.
133+
* @param {Firebase.DataSnapshot} snapshot A snapshot of the data being bound.
134+
* @param {string|null} previousChildKey The key of the child after which the provided snapshot
135+
* is positioned; null if the provided snapshot is in the first position.
136+
*/
137+
function _arrayChildAdded(bindVar, snapshot, previousChildKey) {
138+
var key = snapshot.key();
139+
var value = snapshot.val();
140+
var array = this.data[bindVar];
141+
142+
// Determine where to insert the new record
143+
var insertionIndex;
144+
if (previousChildKey === null) {
145+
insertionIndex = 0;
146+
} else {
147+
var previousChildIndex = _indexForKey(array, previousChildKey);
148+
insertionIndex = previousChildIndex + 1;
149+
}
150+
151+
// Add the new record to the array
152+
array.splice(insertionIndex, 0, _createRecord(key, value));
153+
154+
// Update state
155+
this.setState(this.data);
156+
}
157+
158+
/**
159+
* 'child_removed' listener which removes a record from the bound array.
160+
*
161+
* @param {string} bindVar The state variable to which the data is bound.
162+
* @param {Firebase.DataSnapshot} snapshot A snapshot of the bound data.
163+
*/
164+
function _arrayChildRemoved(bindVar, snapshot) {
165+
var array = this.data[bindVar];
166+
167+
// Look up the record's index in the array
168+
var index = _indexForKey(array, snapshot.key());
169+
170+
// Splice out the record from the array
171+
array.splice(index, 1);
172+
173+
// Update state
174+
this.setState(this.data);
175+
}
176+
177+
/**
178+
* 'child_changed' listener which updates a record's value in the bound array.
179+
*
180+
* @param {string} bindVar The state variable to which the data is bound.
181+
* @param {Firebase.DataSnapshot} snapshot A snapshot of the data to bind.
182+
*/
183+
function _arrayChildChanged(bindVar, snapshot) {
184+
var key = snapshot.key();
185+
var value = snapshot.val();
186+
var array = this.data[bindVar];
187+
188+
// Look up the record's index in the array
189+
var index = _indexForKey(array, key);
190+
191+
// Update the record's value in the array
192+
array[index] = _createRecord(key, value);
193+
194+
// Update state
195+
this.setState(this.data);
196+
}
197+
198+
/**
199+
* 'child_moved' listener which updates a record's position in the bound array.
200+
*
201+
* @param {string} bindVar The state variable to which the data is bound.
202+
* @param {Firebase.DataSnapshot} snapshot A snapshot of the bound data.
203+
* @param {string|null} previousChildKey The key of the child after which the provided snapshot
204+
* is positioned; null if the provided snapshot is in the first position.
205+
*/
206+
function _arrayChildMoved(bindVar, snapshot, previousChildKey) {
207+
var key = snapshot.key();
208+
var array = this.data[bindVar];
209+
210+
// Look up the record's index in the array
211+
var currentIndex = _indexForKey(array, key);
212+
213+
// Splice out the record from the array
214+
var record = array.splice(currentIndex, 1)[0];
215+
216+
// Determine where to re-insert the record
217+
var insertionIndex;
218+
if (previousChildKey === null) {
219+
insertionIndex = 0;
220+
} else {
221+
var previousChildIndex = _indexForKey(array, previousChildKey);
222+
insertionIndex = previousChildIndex + 1;
223+
}
224+
225+
// Re-insert the record into the array
226+
array.splice(insertionIndex, 0, record);
227+
228+
// Update state
229+
this.setState(this.data);
230+
}
231+
232+
233+
/*************/
234+
/* BINDING */
235+
/*************/
236+
/**
237+
* Creates a binding between Firebase and the inputted bind variable as either an array or
238+
* an object.
239+
*
240+
* @param {Firebase} firebaseRef The Firebase ref whose data to bind.
241+
* @param {string} bindVar The state variable to which to bind the data.
242+
* @param {function} cancelCallback The Firebase reference's cancel callback.
243+
* @param {boolean} bindAsArray Whether or not to bind as an array or object.
244+
*/
245+
function _bind(firebaseRef, bindVar, cancelCallback, bindAsArray) {
246+
if (Object.prototype.toString.call(firebaseRef) !== '[object Object]') {
247+
_throwError('Invalid Firebase reference');
248+
}
249+
250+
_validateBindVar(bindVar);
251+
252+
if (typeof this.firebaseRefs[bindVar] !== 'undefined') {
253+
_throwError('this.state.' + bindVar + ' is already bound to a Firebase reference');
254+
}
255+
256+
// Keep track of the Firebase reference we are setting up listeners on
257+
this.firebaseRefs[bindVar] = firebaseRef.ref();
258+
259+
if (bindAsArray) {
260+
// Set initial state to an empty array
261+
this.data[bindVar] = [];
262+
this.setState(this.data);
263+
264+
// Add listeners for all 'child_*' events
265+
this.firebaseListeners[bindVar] = {
266+
child_added: firebaseRef.on('child_added', _arrayChildAdded.bind(this, bindVar), cancelCallback),
267+
child_removed: firebaseRef.on('child_removed', _arrayChildRemoved.bind(this, bindVar), cancelCallback),
268+
child_changed: firebaseRef.on('child_changed', _arrayChildChanged.bind(this, bindVar), cancelCallback),
269+
child_moved: firebaseRef.on('child_moved', _arrayChildMoved.bind(this, bindVar), cancelCallback)
270+
};
271+
} else {
272+
// Add listener for 'value' event
273+
this.firebaseListeners[bindVar] = {
274+
value: firebaseRef.on('value', _objectValue.bind(this, bindVar), cancelCallback)
275+
};
276+
}
277+
}
278+
279+
280+
var ReactFireMixin = {
281+
/********************/
282+
/* MIXIN LIFETIME */
283+
/********************/
284+
/**
285+
* Initializes the Firebase refs and listeners arrays.
286+
**/
287+
componentWillMount: function() {
288+
this.data = {};
289+
this.firebaseRefs = {};
290+
this.firebaseListeners = {};
291+
},
292+
293+
/**
294+
* Unbinds any remaining Firebase listeners.
295+
*/
296+
componentWillUnmount: function() {
297+
for (var bindVar in this.firebaseRefs) {
298+
/* istanbul ignore else */
299+
if (this.firebaseRefs.hasOwnProperty(bindVar)) {
300+
this.unbind(bindVar);
301+
}
302+
}
303+
},
304+
305+
306+
/*************/
307+
/* BINDING */
308+
/*************/
309+
/**
310+
* Creates a binding between Firebase and the inputted bind variable as an array.
311+
*
312+
* @param {Firebase} firebaseRef The Firebase ref whose data to bind.
313+
* @param {string} bindVar The state variable to which to bind the data.
314+
* @param {function} cancelCallback The Firebase reference's cancel callback.
315+
*/
316+
bindAsArray: function(firebaseRef, bindVar, cancelCallback) {
317+
var bindPartial = _bind.bind(this);
318+
bindPartial(firebaseRef, bindVar, cancelCallback, /* bindAsArray */ true);
319+
},
320+
321+
/**
322+
* Creates a binding between Firebase and the inputted bind variable as an object.
323+
*
324+
* @param {Firebase} firebaseRef The Firebase ref whose data to bind.
325+
* @param {string} bindVar The state variable to which to bind the data.
326+
* @param {function} cancelCallback The Firebase reference's cancel callback.
327+
*/
328+
bindAsObject: function(firebaseRef, bindVar, cancelCallback) {
329+
var bindPartial = _bind.bind(this);
330+
bindPartial(firebaseRef, bindVar, cancelCallback, /* bindAsArray */ false);
331+
},
332+
333+
/**
334+
* Removes the binding between Firebase and the inputted bind variable.
335+
*
336+
* @param {string} bindVar The state variable to which the data is bound.
337+
* @param {function} callback Called when the data is unbound and the state has been updated.
338+
*/
339+
unbind: function(bindVar, callback) {
340+
_validateBindVar(bindVar);
341+
342+
if (typeof this.firebaseRefs[bindVar] === 'undefined') {
343+
_throwError('this.state.' + bindVar + ' is not bound to a Firebase reference');
344+
}
345+
346+
// Turn off all Firebase listeners
347+
for (var event in this.firebaseListeners[bindVar]) {
348+
/* istanbul ignore else */
349+
if (this.firebaseListeners[bindVar].hasOwnProperty(event)) {
350+
var offListener = this.firebaseListeners[bindVar][event];
351+
this.firebaseRefs[bindVar].off(event, offListener);
352+
}
353+
}
354+
delete this.firebaseRefs[bindVar];
355+
delete this.firebaseListeners[bindVar];
356+
357+
// Update state
358+
var newState = {};
359+
newState[bindVar] = undefined;
360+
this.setState(newState, callback);
361+
}
362+
};
363+
364+
return ReactFireMixin;
365+
}));

dist/reactfire.min.js

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)