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 and easy way to let
4+ * Firebase populate the state of React components.
5+ *
6+ * ReactFire 0.3.0
7+ * https://github.com/firebase/reactfire/
8+ * License: MIT
9+ */
10+
11+ ; ( function ( root , factory ) {
12+ "use strict" ;
13+ if ( typeof exports === "object" ) {
14+ // CommonJS
15+ module . exports = factory ( ) ;
16+ } else if ( typeof define === "function" && define . amd ) {
17+ // AMD
18+ define ( [ ] , function ( ) {
19+ return ( root . ReactFireMixin = factory ( ) ) ;
20+ } ) ;
21+ } else {
22+ // Global variables
23+ root . ReactFireMixin = factory ( ) ;
24+ }
25+ } ( this , function ( ) {
26+ "use strict" ;
27+
28+ var ReactFireMixin = {
29+ /********************/
30+ /* MIXIN LIFETIME */
31+ /********************/
32+ /* Initializes the Firebase binding refs array */
33+ componentWillMount : function ( ) {
34+ this . firebaseRefs = { } ;
35+ this . firebaseListeners = { } ;
36+ } ,
37+
38+ /* Removes any remaining Firebase bindings */
39+ componentWillUnmount : function ( ) {
40+ for ( var key in this . firebaseRefs ) {
41+ if ( this . firebaseRefs . hasOwnProperty ( key ) ) {
42+ this . unbind ( key ) ;
43+ }
44+ }
45+ } ,
46+
47+
48+ /*************/
49+ /* BINDING */
50+ /*************/
51+ /* Creates a binding between Firebase and the inputted bind variable as an array */
52+ bindAsArray : function ( firebaseRef , bindVar ) {
53+ this . _bind ( firebaseRef , bindVar , true ) ;
54+ } ,
55+
56+ /* Creates a binding between Firebase and the inputted bind variable as an object */
57+ bindAsObject : function ( firebaseRef , bindVar ) {
58+ this . _bind ( firebaseRef , bindVar , false ) ;
59+ } ,
60+
61+ /* Creates a binding between Firebase and the inputted bind variable as either an array or object */
62+ _bind : function ( firebaseRef , bindVar , bindAsArray ) {
63+ this . _validateBindVar ( bindVar ) ;
64+
65+ var errorMessage , errorCode ;
66+ if ( Object . prototype . toString . call ( firebaseRef ) !== "[object Object]" ) {
67+ errorMessage = "firebaseRef must be an instance of Firebase" ;
68+ errorCode = "INVALID_FIREBASE_REF" ;
69+ }
70+ else if ( typeof bindAsArray !== "boolean" ) {
71+ errorMessage = "bindAsArray must be a boolean. Got: " + bindAsArray ;
72+ errorCode = "INVALID_BIND_AS_ARRAY" ;
73+ }
74+
75+ if ( typeof errorMessage !== "undefined" ) {
76+ var error = new Error ( "ReactFire: " + errorMessage ) ;
77+ error . code = errorCode ;
78+ throw error ;
79+ }
80+
81+ this . firebaseRefs [ bindVar ] = firebaseRef . ref ( ) ;
82+ this . firebaseListeners [ bindVar ] = firebaseRef . on ( "value" , function ( dataSnapshot ) {
83+ var newState = { } ;
84+ if ( bindAsArray ) {
85+ newState [ bindVar ] = this . _toArray ( dataSnapshot . val ( ) ) ;
86+ }
87+ else {
88+ newState [ bindVar ] = dataSnapshot . val ( ) ;
89+ }
90+ this . setState ( newState ) ;
91+ } . bind ( this ) ) ;
92+ } ,
93+
94+ /* Removes the binding between Firebase and the inputted bind variable */
95+ unbind : function ( bindVar ) {
96+ this . _validateBindVar ( bindVar ) ;
97+
98+ if ( typeof this . firebaseRefs [ bindVar ] === "undefined" ) {
99+ var error = new Error ( "ReactFire: unexpected value for bindVar. \"" + bindVar + "\" was either never bound or has already been unbound" ) ;
100+ error . code = "UNBOUND_BIND_VARIABLE" ;
101+ throw error ;
102+ }
103+
104+ this . firebaseRefs [ bindVar ] . off ( "value" , this . firebaseListeners [ bindVar ] ) ;
105+ delete this . firebaseRefs [ bindVar ] ;
106+ delete this . firebaseListeners [ bindVar ] ;
107+ } ,
108+
109+
110+ /*************/
111+ /* HELPERS */
112+ /*************/
113+ /* Validates the name of the variable which is being bound */
114+ _validateBindVar : function ( bindVar ) {
115+ var errorMessage ;
116+
117+ if ( typeof bindVar !== "string" ) {
118+ errorMessage = "bindVar must be a string. Got: " + bindVar ;
119+ }
120+ else if ( bindVar . length === 0 ) {
121+ errorMessage = "bindVar must be a non-empty string. Got: \"\"" ;
122+ }
123+ else if ( bindVar . length > 768 ) {
124+ // Firebase can only stored child paths up to 768 characters
125+ errorMessage = "bindVar is too long to be stored in Firebase. Got: " + bindVar ;
126+ }
127+ else if ( / [ \[ \] . # $ \/ \u0000 - \u001F \u007F ] / . test ( bindVar ) ) {
128+ // Firebase does not allow node keys to contain the following characters
129+ errorMessage = "bindVar cannot contain any of the following characters: . # $ ] [ /. Got: " + bindVar ;
130+ }
131+
132+ if ( typeof errorMessage !== "undefined" ) {
133+ var error = new Error ( "ReactFire: " + errorMessage ) ;
134+ error . code = "INVALID_BIND_VARIABLE" ;
135+ throw error ;
136+ }
137+ } ,
138+
139+
140+ /* Returns true if the inputted object is a JavaScript array */
141+ _isArray : function ( obj ) {
142+ return ( Object . prototype . toString . call ( obj ) === "[object Array]" ) ;
143+ } ,
144+
145+ /* Converts a Firebase object to a JavaScript array */
146+ _toArray : function ( obj ) {
147+ var out = [ ] ;
148+ if ( obj ) {
149+ if ( this . _isArray ( obj ) ) {
150+ out = obj ;
151+ }
152+ else if ( typeof ( obj ) === "object" ) {
153+ for ( var key in obj ) {
154+ if ( obj . hasOwnProperty ( key ) ) {
155+ out . push ( obj [ key ] ) ;
156+ }
157+ }
158+ }
159+ }
160+ return out ;
161+ }
162+ } ;
163+
164+ return ReactFireMixin ;
165+ } ) ) ;
0 commit comments