| 
 | 1 | +/*!  | 
 | 2 | + * vuefire v1.4.2  | 
 | 3 | + * (c) 2017 Evan You  | 
 | 4 | + * Released under the MIT License.  | 
 | 5 | + */  | 
 | 6 | +'use strict';  | 
 | 7 | + | 
 | 8 | +Object.defineProperty(exports, '__esModule', { value: true });  | 
 | 9 | + | 
 | 10 | +var Vue; // late binding  | 
 | 11 | + | 
 | 12 | +/**  | 
 | 13 | + * Returns the key of a Firebase snapshot across SDK versions.  | 
 | 14 | + *  | 
 | 15 | + * @param {FirebaseSnapshot} snapshot  | 
 | 16 | + * @return {string|null}  | 
 | 17 | + */  | 
 | 18 | +function _getKey (snapshot) {  | 
 | 19 | +  return typeof snapshot.key === 'function'  | 
 | 20 | +    ? snapshot.key()  | 
 | 21 | +    : snapshot.key  | 
 | 22 | +}  | 
 | 23 | + | 
 | 24 | +/**  | 
 | 25 | + * Returns the original reference of a Firebase reference or query across SDK versions.  | 
 | 26 | + *  | 
 | 27 | + * @param {FirebaseReference|FirebaseQuery} refOrQuery  | 
 | 28 | + * @return {FirebaseReference}  | 
 | 29 | + */  | 
 | 30 | +function _getRef (refOrQuery) {  | 
 | 31 | +  if (typeof refOrQuery.ref === 'function') {  | 
 | 32 | +    refOrQuery = refOrQuery.ref();  | 
 | 33 | +  } else if (typeof refOrQuery.ref === 'object') {  | 
 | 34 | +    refOrQuery = refOrQuery.ref;  | 
 | 35 | +  }  | 
 | 36 | + | 
 | 37 | +  return refOrQuery  | 
 | 38 | +}  | 
 | 39 | + | 
 | 40 | +/**  | 
 | 41 | + * Check if a value is an object.  | 
 | 42 | + *  | 
 | 43 | + * @param {*} val  | 
 | 44 | + * @return {boolean}  | 
 | 45 | + */  | 
 | 46 | +function isObject (val) {  | 
 | 47 | +  return Object.prototype.toString.call(val) === '[object Object]'  | 
 | 48 | +}  | 
 | 49 | + | 
 | 50 | +/**  | 
 | 51 | + * Convert firebase snapshot into a bindable data record.  | 
 | 52 | + *  | 
 | 53 | + * @param {FirebaseSnapshot} snapshot  | 
 | 54 | + * @return {Object}  | 
 | 55 | + */  | 
 | 56 | +function createRecord (snapshot) {  | 
 | 57 | +  var value = snapshot.val();  | 
 | 58 | +  var res = isObject(value)  | 
 | 59 | +    ? value  | 
 | 60 | +    : { '.value': value };  | 
 | 61 | +  res['.key'] = _getKey(snapshot);  | 
 | 62 | +  return res  | 
 | 63 | +}  | 
 | 64 | + | 
 | 65 | +/**  | 
 | 66 | + * Find the index for an object with given key.  | 
 | 67 | + *  | 
 | 68 | + * @param {array} array  | 
 | 69 | + * @param {string} key  | 
 | 70 | + * @return {number}  | 
 | 71 | + */  | 
 | 72 | +function indexForKey (array, key) {  | 
 | 73 | +  for (var i = 0; i < array.length; i++) {  | 
 | 74 | +    if (array[i]['.key'] === key) {  | 
 | 75 | +      return i  | 
 | 76 | +    }  | 
 | 77 | +  }  | 
 | 78 | +  /* istanbul ignore next */  | 
 | 79 | +  return -1  | 
 | 80 | +}  | 
 | 81 | + | 
 | 82 | +/**  | 
 | 83 | + * Bind a firebase data source to a key on a vm.  | 
 | 84 | + *  | 
 | 85 | + * @param {Vue} vm  | 
 | 86 | + * @param {string} key  | 
 | 87 | + * @param {object} source  | 
 | 88 | + */  | 
 | 89 | +function bind (vm, key, source) {  | 
 | 90 | +  var asObject = false;  | 
 | 91 | +  var cancelCallback = null;  | 
 | 92 | +  var readyCallback = null;  | 
 | 93 | +  // check { source, asArray, cancelCallback } syntax  | 
 | 94 | +  if (isObject(source) && source.hasOwnProperty('source')) {  | 
 | 95 | +    asObject = source.asObject;  | 
 | 96 | +    cancelCallback = source.cancelCallback;  | 
 | 97 | +    readyCallback = source.readyCallback;  | 
 | 98 | +    source = source.source;  | 
 | 99 | +  }  | 
 | 100 | +  if (!isObject(source)) {  | 
 | 101 | +    throw new Error('VueFire: invalid Firebase binding source.')  | 
 | 102 | +  }  | 
 | 103 | +  var ref = _getRef(source);  | 
 | 104 | +  vm.$firebaseRefs[key] = ref;  | 
 | 105 | +  vm._firebaseSources[key] = source;  | 
 | 106 | +  // bind based on initial value type  | 
 | 107 | +  if (asObject) {  | 
 | 108 | +    bindAsObject(vm, key, source, cancelCallback);  | 
 | 109 | +  } else {  | 
 | 110 | +    bindAsArray(vm, key, source, cancelCallback);  | 
 | 111 | +  }  | 
 | 112 | +  if (readyCallback) {  | 
 | 113 | +    source.once('value', readyCallback.bind(vm));  | 
 | 114 | +  }  | 
 | 115 | +}  | 
 | 116 | + | 
 | 117 | +/**  | 
 | 118 | + * Define a reactive property in a given vm if it's not defined  | 
 | 119 | + * yet  | 
 | 120 | + *  | 
 | 121 | + * @param {Vue} vm  | 
 | 122 | + * @param {string} key  | 
 | 123 | + * @param {*} val  | 
 | 124 | + */  | 
 | 125 | +function defineReactive (vm, key, val) {  | 
 | 126 | +  if (key in vm) {  | 
 | 127 | +    vm[key] = val;  | 
 | 128 | +  } else {  | 
 | 129 | +    Vue.util.defineReactive(vm, key, val);  | 
 | 130 | +  }  | 
 | 131 | +}  | 
 | 132 | + | 
 | 133 | +/**  | 
 | 134 | + * Bind a firebase data source to a key on a vm as an Array.  | 
 | 135 | + *  | 
 | 136 | + * @param {Vue} vm  | 
 | 137 | + * @param {string} key  | 
 | 138 | + * @param {object} source  | 
 | 139 | + * @param {function|null} cancelCallback  | 
 | 140 | + */  | 
 | 141 | +function bindAsArray (vm, key, source, cancelCallback) {  | 
 | 142 | +  var array = [];  | 
 | 143 | +  defineReactive(vm, key, array);  | 
 | 144 | + | 
 | 145 | +  var onAdd = source.on('child_added', function (snapshot, prevKey) {  | 
 | 146 | +    var index = prevKey ? indexForKey(array, prevKey) + 1 : 0;  | 
 | 147 | +    array.splice(index, 0, createRecord(snapshot));  | 
 | 148 | +  }, cancelCallback);  | 
 | 149 | + | 
 | 150 | +  var onRemove = source.on('child_removed', function (snapshot) {  | 
 | 151 | +    var index = indexForKey(array, _getKey(snapshot));  | 
 | 152 | +    array.splice(index, 1);  | 
 | 153 | +  }, cancelCallback);  | 
 | 154 | + | 
 | 155 | +  var onChange = source.on('child_changed', function (snapshot) {  | 
 | 156 | +    var index = indexForKey(array, _getKey(snapshot));  | 
 | 157 | +    array.splice(index, 1, createRecord(snapshot));  | 
 | 158 | +  }, cancelCallback);  | 
 | 159 | + | 
 | 160 | +  var onMove = source.on('child_moved', function (snapshot, prevKey) {  | 
 | 161 | +    var index = indexForKey(array, _getKey(snapshot));  | 
 | 162 | +    var record = array.splice(index, 1)[0];  | 
 | 163 | +    var newIndex = prevKey ? indexForKey(array, prevKey) + 1 : 0;  | 
 | 164 | +    array.splice(newIndex, 0, record);  | 
 | 165 | +  }, cancelCallback);  | 
 | 166 | + | 
 | 167 | +  vm._firebaseListeners[key] = {  | 
 | 168 | +    child_added: onAdd,  | 
 | 169 | +    child_removed: onRemove,  | 
 | 170 | +    child_changed: onChange,  | 
 | 171 | +    child_moved: onMove  | 
 | 172 | +  };  | 
 | 173 | +}  | 
 | 174 | + | 
 | 175 | +/**  | 
 | 176 | + * Bind a firebase data source to a key on a vm as an Object.  | 
 | 177 | + *  | 
 | 178 | + * @param {Vue} vm  | 
 | 179 | + * @param {string} key  | 
 | 180 | + * @param {Object} source  | 
 | 181 | + * @param {function|null} cancelCallback  | 
 | 182 | + */  | 
 | 183 | +function bindAsObject (vm, key, source, cancelCallback) {  | 
 | 184 | +  defineReactive(vm, key, {});  | 
 | 185 | +  var cb = source.on('value', function (snapshot) {  | 
 | 186 | +    vm[key] = createRecord(snapshot);  | 
 | 187 | +  }, cancelCallback);  | 
 | 188 | +  vm._firebaseListeners[key] = { value: cb };  | 
 | 189 | +}  | 
 | 190 | + | 
 | 191 | +/**  | 
 | 192 | + * Unbind a firebase-bound key from a vm.  | 
 | 193 | + *  | 
 | 194 | + * @param {Vue} vm  | 
 | 195 | + * @param {string} key  | 
 | 196 | + */  | 
 | 197 | +function unbind (vm, key) {  | 
 | 198 | +  var source = vm._firebaseSources && vm._firebaseSources[key];  | 
 | 199 | +  if (!source) {  | 
 | 200 | +    throw new Error(  | 
 | 201 | +      'VueFire: unbind failed: "' + key + '" is not bound to ' +  | 
 | 202 | +      'a Firebase reference.'  | 
 | 203 | +    )  | 
 | 204 | +  }  | 
 | 205 | +  var listeners = vm._firebaseListeners[key];  | 
 | 206 | +  for (var event in listeners) {  | 
 | 207 | +    source.off(event, listeners[event]);  | 
 | 208 | +  }  | 
 | 209 | +  vm[key] = null;  | 
 | 210 | +  vm.$firebaseRefs[key] = null;  | 
 | 211 | +  vm._firebaseSources[key] = null;  | 
 | 212 | +  vm._firebaseListeners[key] = null;  | 
 | 213 | +}  | 
 | 214 | + | 
 | 215 | +/**  | 
 | 216 | + * Ensure the related bookkeeping variables on an instance.  | 
 | 217 | + *  | 
 | 218 | + * @param {Vue} vm  | 
 | 219 | + */  | 
 | 220 | +function ensureRefs (vm) {  | 
 | 221 | +  if (!vm.$firebaseRefs) {  | 
 | 222 | +    vm.$firebaseRefs = Object.create(null);  | 
 | 223 | +    vm._firebaseSources = Object.create(null);  | 
 | 224 | +    vm._firebaseListeners = Object.create(null);  | 
 | 225 | +  }  | 
 | 226 | +}  | 
 | 227 | + | 
 | 228 | +var init = function () {  | 
 | 229 | +  var this$1 = this;  | 
 | 230 | + | 
 | 231 | +  var bindings = this.$options.firebase;  | 
 | 232 | +  if (typeof bindings === 'function') { bindings = bindings.call(this); }  | 
 | 233 | +  if (!bindings) { return }  | 
 | 234 | +  ensureRefs(this);  | 
 | 235 | +  for (var key in bindings) {  | 
 | 236 | +    bind(this$1, key, bindings[key]);  | 
 | 237 | +  }  | 
 | 238 | +};  | 
 | 239 | + | 
 | 240 | +var VueFireMixin = {  | 
 | 241 | +  created: init, // 1.x and 2.x  | 
 | 242 | +  beforeDestroy: function () {  | 
 | 243 | +    var this$1 = this;  | 
 | 244 | + | 
 | 245 | +    if (!this.$firebaseRefs) { return }  | 
 | 246 | +    for (var key in this$1.$firebaseRefs) {  | 
 | 247 | +      if (this$1.$firebaseRefs[key]) {  | 
 | 248 | +        this$1.$unbind(key);  | 
 | 249 | +      }  | 
 | 250 | +    }  | 
 | 251 | +    this.$firebaseRefs = null;  | 
 | 252 | +    this._firebaseSources = null;  | 
 | 253 | +    this._firebaseListeners = null;  | 
 | 254 | +  }  | 
 | 255 | +};  | 
 | 256 | + | 
 | 257 | +/**  | 
 | 258 | + * Install function passed to Vue.use() in manual installation.  | 
 | 259 | + *  | 
 | 260 | + * @param {function} _Vue  | 
 | 261 | + */  | 
 | 262 | +function install (_Vue) {  | 
 | 263 | +  Vue = _Vue;  | 
 | 264 | +  Vue.mixin(VueFireMixin);  | 
 | 265 | + | 
 | 266 | +  // use object-based merge strategy  | 
 | 267 | +  // TODO This makes impossible to merge functions  | 
 | 268 | +  var mergeStrats = Vue.config.optionMergeStrategies;  | 
 | 269 | +  mergeStrats.firebase = mergeStrats.methods;  | 
 | 270 | + | 
 | 271 | +  // extend instance methods  | 
 | 272 | +  Vue.prototype.$bindAsObject = function (key, source, cancelCallback, readyCallback) {  | 
 | 273 | +    ensureRefs(this);  | 
 | 274 | +    bind(this, key, {  | 
 | 275 | +      source: source,  | 
 | 276 | +      asObject: true,  | 
 | 277 | +      cancelCallback: cancelCallback,  | 
 | 278 | +      readyCallback: readyCallback  | 
 | 279 | +    });  | 
 | 280 | +  };  | 
 | 281 | + | 
 | 282 | +  Vue.prototype.$bindAsArray = function (key, source, cancelCallback, readyCallback) {  | 
 | 283 | +    ensureRefs(this);  | 
 | 284 | +    bind(this, key, {  | 
 | 285 | +      source: source,  | 
 | 286 | +      cancelCallback: cancelCallback,  | 
 | 287 | +      readyCallback: readyCallback  | 
 | 288 | +    });  | 
 | 289 | +  };  | 
 | 290 | + | 
 | 291 | +  Vue.prototype.$unbind = function (key) {  | 
 | 292 | +    unbind(this, key);  | 
 | 293 | +  };  | 
 | 294 | +}  | 
 | 295 | + | 
 | 296 | +// auto install  | 
 | 297 | +/* istanbul ignore if */  | 
 | 298 | +if (typeof window !== 'undefined' && window.Vue) {  | 
 | 299 | +  install(window.Vue);  | 
 | 300 | +}  | 
 | 301 | + | 
 | 302 | +module.exports = install;  | 
0 commit comments