|  | @@ -1,765 +0,0 @@
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File
 | 
	
		
			
				|  |  | - * @namespace FS.File
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @constructor
 | 
	
		
			
				|  |  | - * @param {object|FS.File|data to attach} [ref] Another FS.File instance, a filerecord, or some data to pass to attachData
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File = function(ref, createdByTransform) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  self.createdByTransform = !!createdByTransform;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (ref instanceof FS.File || isBasicObject(ref)) {
 | 
	
		
			
				|  |  | -    // Extend self with filerecord related data
 | 
	
		
			
				|  |  | -    FS.Utility.extend(self, FS.Utility.cloneFileRecord(ref, {full: true}));
 | 
	
		
			
				|  |  | -  } else if (ref) {
 | 
	
		
			
				|  |  | -    self.attachData(ref);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// An FS.File can emit events
 | 
	
		
			
				|  |  | -FS.File.prototype = new EventEmitter();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.attachData
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {File|Blob|Buffer|ArrayBuffer|Uint8Array|String} data The data that you want to attach to the file.
 | 
	
		
			
				|  |  | - * @param {Object} [options] Options
 | 
	
		
			
				|  |  | - * @param {String} [options.type] The data content (MIME) type, if known.
 | 
	
		
			
				|  |  | - * @param {String} [options.headers] When attaching a URL, headers to be used for the GET request (currently server only)
 | 
	
		
			
				|  |  | - * @param {String} [options.auth] When attaching a URL, "username:password" to be used for the GET request (currently server only)
 | 
	
		
			
				|  |  | - * @param {Function} [callback] Callback function, callback(error). On the client, a callback is required if data is a URL.
 | 
	
		
			
				|  |  | - * @returns {FS.File} This FS.File instance.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.attachData = function fsFileAttachData(data, options, callback) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!callback && typeof options === "function") {
 | 
	
		
			
				|  |  | -    callback = options;
 | 
	
		
			
				|  |  | -    options = {};
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  options = options || {};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!data) {
 | 
	
		
			
				|  |  | -    throw new Error('FS.File.attachData requires a data argument with some data');
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  var urlOpts;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Set any other properties we can determine from the source data
 | 
	
		
			
				|  |  | -  // File
 | 
	
		
			
				|  |  | -  if (typeof File !== "undefined" && data instanceof File) {
 | 
	
		
			
				|  |  | -    self.name(data.name);
 | 
	
		
			
				|  |  | -    self.updatedAt(data.lastModifiedDate);
 | 
	
		
			
				|  |  | -    self.size(data.size);
 | 
	
		
			
				|  |  | -    setData(data.type);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Blob
 | 
	
		
			
				|  |  | -  else if (typeof Blob !== "undefined" && data instanceof Blob) {
 | 
	
		
			
				|  |  | -    self.name(data.name);
 | 
	
		
			
				|  |  | -    self.updatedAt(new Date());
 | 
	
		
			
				|  |  | -    self.size(data.size);
 | 
	
		
			
				|  |  | -    setData(data.type);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // URL: we need to do a HEAD request to get the type because type
 | 
	
		
			
				|  |  | -  // is required for filtering to work.
 | 
	
		
			
				|  |  | -  else if (typeof data === "string" && (data.slice(0, 5) === "http:" || data.slice(0, 6) === "https:")) {
 | 
	
		
			
				|  |  | -    urlOpts = FS.Utility.extend({}, options);
 | 
	
		
			
				|  |  | -    if (urlOpts.type) {
 | 
	
		
			
				|  |  | -      delete urlOpts.type;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (!callback) {
 | 
	
		
			
				|  |  | -      if (Meteor.isClient) {
 | 
	
		
			
				|  |  | -        throw new Error('FS.File.attachData requires a callback when attaching a URL on the client');
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      var result = Meteor.call('_cfs_getUrlInfo', data, urlOpts);
 | 
	
		
			
				|  |  | -      FS.Utility.extend(self, {original: result});
 | 
	
		
			
				|  |  | -      setData(result.type);
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      Meteor.call('_cfs_getUrlInfo', data, urlOpts, function (error, result) {
 | 
	
		
			
				|  |  | -        FS.debug && console.log("URL HEAD RESULT:", result);
 | 
	
		
			
				|  |  | -        if (error) {
 | 
	
		
			
				|  |  | -          callback(error);
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          var type = result.type || options.type;
 | 
	
		
			
				|  |  | -          if (! type) {
 | 
	
		
			
				|  |  | -            throw new Error('FS.File.attachData got a URL for which it could not determine the MIME type and none was provided using options.type');
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          FS.Utility.extend(self, {original: result});
 | 
	
		
			
				|  |  | -          setData(type);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Everything else
 | 
	
		
			
				|  |  | -  else {
 | 
	
		
			
				|  |  | -    setData(options.type);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Set the data
 | 
	
		
			
				|  |  | -  function setData(type) {
 | 
	
		
			
				|  |  | -    self.data = new DataMan(data, type, urlOpts);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // Update the type to match what the data is
 | 
	
		
			
				|  |  | -    self.type(self.data.type());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // Update the size to match what the data is.
 | 
	
		
			
				|  |  | -    // It's always safe to call self.data.size() without supplying a callback
 | 
	
		
			
				|  |  | -    // because it requires a callback only for URLs on the client, and we
 | 
	
		
			
				|  |  | -    // already added size for URLs when we got the result from '_cfs_getUrlInfo' method.
 | 
	
		
			
				|  |  | -    if (!self.size()) {
 | 
	
		
			
				|  |  | -      if (callback) {
 | 
	
		
			
				|  |  | -        self.data.size(function (error, size) {
 | 
	
		
			
				|  |  | -          if (error) {
 | 
	
		
			
				|  |  | -            callback && callback(error);
 | 
	
		
			
				|  |  | -          } else {
 | 
	
		
			
				|  |  | -            self.size(size);
 | 
	
		
			
				|  |  | -            setName();
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        self.size(self.data.size());
 | 
	
		
			
				|  |  | -        setName();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      setName();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  function setName() {
 | 
	
		
			
				|  |  | -    // See if we can extract a file name from URL or filepath
 | 
	
		
			
				|  |  | -    if (!self.name() && typeof data === "string") {
 | 
	
		
			
				|  |  | -      // name from URL
 | 
	
		
			
				|  |  | -      if (data.slice(0, 5) === "http:" || data.slice(0, 6) === "https:") {
 | 
	
		
			
				|  |  | -        if (FS.Utility.getFileExtension(data).length) {
 | 
	
		
			
				|  |  | -          // for a URL we assume the end is a filename only if it has an extension
 | 
	
		
			
				|  |  | -          self.name(FS.Utility.getFileName(data));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      // name from filepath
 | 
	
		
			
				|  |  | -      else if (data.slice(0, 5) !== "data:") {
 | 
	
		
			
				|  |  | -        self.name(FS.Utility.getFileName(data));
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    callback && callback();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return self; //allow chaining
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.uploadProgress
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @returns {number} The server confirmed upload progress
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.uploadProgress = function() {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  // Make sure our file record is updated
 | 
	
		
			
				|  |  | -  self.getFileRecord();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // If fully uploaded, return 100
 | 
	
		
			
				|  |  | -  if (self.uploadedAt) {
 | 
	
		
			
				|  |  | -    return 100;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Otherwise return the confirmed progress or 0
 | 
	
		
			
				|  |  | -  else {
 | 
	
		
			
				|  |  | -    return Math.round((self.chunkCount || 0) / (self.chunkSum || 1) * 100);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.controlledByDeps
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @returns {FS.Collection} Returns true if this FS.File is reactive
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * > Note: Returns true if this FS.File object was created by a FS.Collection
 | 
	
		
			
				|  |  | - * > and we are in a reactive computations. What does this mean? Well it should
 | 
	
		
			
				|  |  | - * > mean that our fileRecord is fully updated by Meteor and we are mounted on
 | 
	
		
			
				|  |  | - * > a collection
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.controlledByDeps = function() {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  return self.createdByTransform && Deps.active;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.getCollection
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @returns {FS.Collection} Returns attached collection or undefined if not mounted
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.getCollection = function() {
 | 
	
		
			
				|  |  | -  // Get the collection reference
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // If we already made the link then do no more
 | 
	
		
			
				|  |  | -  if (self.collection) {
 | 
	
		
			
				|  |  | -    return self.collection;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // If we don't have a collectionName then there's not much to do, the file is
 | 
	
		
			
				|  |  | -  // not mounted yet
 | 
	
		
			
				|  |  | -  if (!self.collectionName) {
 | 
	
		
			
				|  |  | -    // Should not throw an error here - could be common that the file is not
 | 
	
		
			
				|  |  | -    // yet mounted into a collection
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Link the collection to the file
 | 
	
		
			
				|  |  | -  self.collection = FS._collections[self.collectionName];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return self.collection; //possibly undefined, but that's desired behavior
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.isMounted
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @returns {FS.Collection} Returns attached collection or undefined if not mounted
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.isMounted = FS.File.prototype.getCollection;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.getFileRecord Returns the fileRecord
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @returns {object} The filerecord
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.getFileRecord = function() {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  // Check if this file object fileRecord is kept updated by Meteor, if so
 | 
	
		
			
				|  |  | -  // return self
 | 
	
		
			
				|  |  | -  if (self.controlledByDeps()) {
 | 
	
		
			
				|  |  | -    return self;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Go for manually updating the file record
 | 
	
		
			
				|  |  | -  if (self.isMounted()) {
 | 
	
		
			
				|  |  | -    FS.debug && console.log('GET FILERECORD: ' + self._id);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // Return the fileRecord or an empty object
 | 
	
		
			
				|  |  | -    var fileRecord = self.collection.files.findOne({_id: self._id}) || {};
 | 
	
		
			
				|  |  | -    FS.Utility.extend(self, fileRecord);
 | 
	
		
			
				|  |  | -    return fileRecord;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    // We return an empty object, this way users can still do `getRecord().size`
 | 
	
		
			
				|  |  | -    // Without getting an error
 | 
	
		
			
				|  |  | -    return {};
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.update
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {modifier} modifier
 | 
	
		
			
				|  |  | - * @param {object} [options]
 | 
	
		
			
				|  |  | - * @param {function} [callback]
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Updates the fileRecord.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.update = function(modifier, options, callback) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  FS.debug && console.log('UPDATE: ' + JSON.stringify(modifier));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Make sure we have options and callback
 | 
	
		
			
				|  |  | -  if (!callback && typeof options === 'function') {
 | 
	
		
			
				|  |  | -    callback = options;
 | 
	
		
			
				|  |  | -    options = {};
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  callback = callback || FS.Utility.defaultCallback;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!self.isMounted()) {
 | 
	
		
			
				|  |  | -    callback(new Error("Cannot update a file that is not associated with a collection"));
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Call collection update - File record
 | 
	
		
			
				|  |  | -  return self.collection.files.update({_id: self._id}, modifier, options, function(err, count) {
 | 
	
		
			
				|  |  | -    // Update the fileRecord if it was changed and on the client
 | 
	
		
			
				|  |  | -    // The server-side methods will pull the fileRecord if needed
 | 
	
		
			
				|  |  | -    if (count > 0 && Meteor.isClient)
 | 
	
		
			
				|  |  | -      self.getFileRecord();
 | 
	
		
			
				|  |  | -    // Call callback
 | 
	
		
			
				|  |  | -    callback(err, count);
 | 
	
		
			
				|  |  | -  });
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype._saveChanges
 | 
	
		
			
				|  |  | - * @private
 | 
	
		
			
				|  |  | - * @param {String} [what] "_original" to save original info, or a store name to save info for that store, or saves everything
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Updates the fileRecord from values currently set on the FS.File instance.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype._saveChanges = function(what) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!self.isMounted()) {
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  FS.debug && console.log("FS.File._saveChanges:", what || "all");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  var mod = {$set: {}};
 | 
	
		
			
				|  |  | -  if (what === "_original") {
 | 
	
		
			
				|  |  | -    mod.$set.original = self.original;
 | 
	
		
			
				|  |  | -  } else if (typeof what === "string") {
 | 
	
		
			
				|  |  | -    var info = self.copies[what];
 | 
	
		
			
				|  |  | -    if (info) {
 | 
	
		
			
				|  |  | -      mod.$set["copies." + what] = info;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    mod.$set.original = self.original;
 | 
	
		
			
				|  |  | -    mod.$set.copies = self.copies;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  self.update(mod);
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.remove
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {Function} [callback]
 | 
	
		
			
				|  |  | - * @returns {number} Count
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Remove the current file from its FS.Collection
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.remove = function(callback) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  FS.debug && console.log('REMOVE: ' + self._id);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  callback = callback || FS.Utility.defaultCallback;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!self.isMounted()) {
 | 
	
		
			
				|  |  | -    callback(new Error("Cannot remove a file that is not associated with a collection"));
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return self.collection.files.remove({_id: self._id}, function(err, res) {
 | 
	
		
			
				|  |  | -    if (!err) {
 | 
	
		
			
				|  |  | -      delete self._id;
 | 
	
		
			
				|  |  | -      delete self.collection;
 | 
	
		
			
				|  |  | -      delete self.collectionName;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    callback(err, res);
 | 
	
		
			
				|  |  | -  });
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.moveTo
 | 
	
		
			
				|  |  | - * @param {FS.Collection} targetCollection
 | 
	
		
			
				|  |  | - * @private // Marked private until implemented
 | 
	
		
			
				|  |  | - * @todo Needs to be implemented
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Move the file from current collection to another collection
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * > Note: Not yet implemented
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.getExtension Returns the lowercase file extension
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @deprecated Use the `extension` getter/setter method instead.
 | 
	
		
			
				|  |  | - * @param {Object} [options]
 | 
	
		
			
				|  |  | - * @param {String} [options.store] - Store name. Default is the original extension.
 | 
	
		
			
				|  |  | - * @returns {string} The extension eg.: `jpg` or if not found then an empty string ''
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.getExtension = function(options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  return self.extension(options);
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -function checkContentType(fsFile, storeName, startOfType) {
 | 
	
		
			
				|  |  | -  var type;
 | 
	
		
			
				|  |  | -  if (storeName && fsFile.hasStored(storeName)) {
 | 
	
		
			
				|  |  | -    type = fsFile.type({store: storeName});
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    type = fsFile.type();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (typeof type === "string") {
 | 
	
		
			
				|  |  | -    return type.indexOf(startOfType) === 0;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return false;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.isImage Is it an image file?
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {object} [options]
 | 
	
		
			
				|  |  | - * @param {string} [options.store] The store we're interested in
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Returns true if the copy of this file in the specified store has an image
 | 
	
		
			
				|  |  | - * content type. If the file object is unmounted or doesn't have a copy for
 | 
	
		
			
				|  |  | - * the specified store, or if you don't specify a store, this method checks
 | 
	
		
			
				|  |  | - * the content type of the original file.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.isImage = function(options) {
 | 
	
		
			
				|  |  | -  return checkContentType(this, (options || {}).store, 'image/');
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.isVideo Is it a video file?
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {object} [options]
 | 
	
		
			
				|  |  | - * @param {string} [options.store] The store we're interested in
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Returns true if the copy of this file in the specified store has a video
 | 
	
		
			
				|  |  | - * content type. If the file object is unmounted or doesn't have a copy for
 | 
	
		
			
				|  |  | - * the specified store, or if you don't specify a store, this method checks
 | 
	
		
			
				|  |  | - * the content type of the original file.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.isVideo = function(options) {
 | 
	
		
			
				|  |  | -  return checkContentType(this, (options || {}).store, 'video/');
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.isAudio Is it an audio file?
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {object} [options]
 | 
	
		
			
				|  |  | - * @param {string} [options.store] The store we're interested in
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Returns true if the copy of this file in the specified store has an audio
 | 
	
		
			
				|  |  | - * content type. If the file object is unmounted or doesn't have a copy for
 | 
	
		
			
				|  |  | - * the specified store, or if you don't specify a store, this method checks
 | 
	
		
			
				|  |  | - * the content type of the original file.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.isAudio = function(options) {
 | 
	
		
			
				|  |  | -  return checkContentType(this, (options || {}).store, 'audio/');
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.formattedSize
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param  {Object} options
 | 
	
		
			
				|  |  | - * @param  {String} [options.store=none,display original file size] Which file do you want to get the size of?
 | 
	
		
			
				|  |  | - * @param  {String} [options.formatString='0.00 b'] The `numeral` format string to use.
 | 
	
		
			
				|  |  | - * @return {String} The file size formatted as a human readable string and reactively updated.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * * You must add the `numeral` package to your app before you can use this method.
 | 
	
		
			
				|  |  | - * * If info is not found or a size can't be determined, it will show 0.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.formattedSize = function fsFileFormattedSize(options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (typeof numeral !== "function")
 | 
	
		
			
				|  |  | -    throw new Error("You must add the numeral package if you call FS.File.formattedSize");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  options = options || {};
 | 
	
		
			
				|  |  | -  options = options.hash || options;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  var size = self.size(options) || 0;
 | 
	
		
			
				|  |  | -  return numeral(size).format(options.formatString || '0.00 b');
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.isUploaded Is this file completely uploaded?
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @returns {boolean} True if the number of uploaded bytes is equal to the file size.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.isUploaded = function() {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Make sure we use the updated file record
 | 
	
		
			
				|  |  | -  self.getFileRecord();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return !!self.uploadedAt;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.hasStored
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {string} storeName Name of the store
 | 
	
		
			
				|  |  | - * @param {boolean} [optimistic=false] In case that the file record is not found, read below
 | 
	
		
			
				|  |  | - * @returns {boolean} Is a version of this file stored in the given store?
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * > Note: If the file is not published to the client or simply not found:
 | 
	
		
			
				|  |  | - * this method cannot know for sure if it exists or not. The `optimistic`
 | 
	
		
			
				|  |  | - * param is the boolean value to return. Are we `optimistic` that the copy
 | 
	
		
			
				|  |  | - * could exist. This is the case in `FS.File.url` we are optimistic that the
 | 
	
		
			
				|  |  | - * copy supplied by the user exists.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.hasStored = function(storeName, optimistic) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  // Make sure we use the updated file record
 | 
	
		
			
				|  |  | -  self.getFileRecord();
 | 
	
		
			
				|  |  | -  // If we havent the published data then
 | 
	
		
			
				|  |  | -  if (FS.Utility.isEmpty(self.copies)) {
 | 
	
		
			
				|  |  | -    return !!optimistic;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (typeof storeName === "string") {
 | 
	
		
			
				|  |  | -    // Return true only if the `key` property is present, which is not set until
 | 
	
		
			
				|  |  | -    // storage is complete.
 | 
	
		
			
				|  |  | -    return !!(self.copies && self.copies[storeName] && self.copies[storeName].key);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return false;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// Backwards compatibility
 | 
	
		
			
				|  |  | -FS.File.prototype.hasCopy = FS.File.prototype.hasStored;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.getCopyInfo
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @deprecated Use individual methods with `store` option instead.
 | 
	
		
			
				|  |  | - * @param {string} storeName Name of the store for which to get copy info.
 | 
	
		
			
				|  |  | - * @returns {Object} The file details, e.g., name, size, key, etc., specific to the copy saved in this store.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.getCopyInfo = function(storeName) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  // Make sure we use the updated file record
 | 
	
		
			
				|  |  | -  self.getFileRecord();
 | 
	
		
			
				|  |  | -  return (self.copies && self.copies[storeName]) || null;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype._getInfo
 | 
	
		
			
				|  |  | - * @private
 | 
	
		
			
				|  |  | - * @param {String} [storeName] Name of the store for which to get file info. Omit for original file details.
 | 
	
		
			
				|  |  | - * @param {Object} [options]
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.updateFileRecordFirst=false] Update this instance with data from the DB first?
 | 
	
		
			
				|  |  | - * @returns {Object} The file details, e.g., name, size, key, etc. If not found, returns an empty object.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype._getInfo = function(storeName, options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  options = options || {};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (options.updateFileRecordFirst) {
 | 
	
		
			
				|  |  | -    // Make sure we use the updated file record
 | 
	
		
			
				|  |  | -    self.getFileRecord();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (storeName) {
 | 
	
		
			
				|  |  | -    return (self.copies && self.copies[storeName]) || {};
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    return self.original || {};
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype._setInfo
 | 
	
		
			
				|  |  | - * @private
 | 
	
		
			
				|  |  | - * @param {String} storeName - Name of the store for which to set file info. Non-string will set original file details.
 | 
	
		
			
				|  |  | - * @param {String} property - Property to set
 | 
	
		
			
				|  |  | - * @param {String} value - New value for property
 | 
	
		
			
				|  |  | - * @param {Boolean} save - Should the new value be saved to the DB, too, or just set in the FS.File properties?
 | 
	
		
			
				|  |  | - * @returns {undefined}
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype._setInfo = function(storeName, property, value, save) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -  if (typeof storeName === "string") {
 | 
	
		
			
				|  |  | -    self.copies = self.copies || {};
 | 
	
		
			
				|  |  | -    self.copies[storeName] = self.copies[storeName] || {};
 | 
	
		
			
				|  |  | -    self.copies[storeName][property] = value;
 | 
	
		
			
				|  |  | -    save && self._saveChanges(storeName);
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    self.original = self.original || {};
 | 
	
		
			
				|  |  | -    self.original[property] = value;
 | 
	
		
			
				|  |  | -    save && self._saveChanges("_original");
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.name
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {String|null} [value] - If setting the name, specify the new name as the first argument. Otherwise the options argument should be first.
 | 
	
		
			
				|  |  | - * @param {Object} [options]
 | 
	
		
			
				|  |  | - * @param {Object} [options.store=none,original] - Get or set the name of the version of the file that was saved in this store. Default is the original file name.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.updateFileRecordFirst=false] Update this instance with data from the DB first? Applies to getter usage only.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.save=true] Save change to database? Applies to setter usage only.
 | 
	
		
			
				|  |  | - * @returns {String|undefined} If setting, returns `undefined`. If getting, returns the file name.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.name = function(value, options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!options && ((typeof value === "object" && value !== null) || typeof value === "undefined")) {
 | 
	
		
			
				|  |  | -    // GET
 | 
	
		
			
				|  |  | -    options = value || {};
 | 
	
		
			
				|  |  | -    options = options.hash || options; // allow use as UI helper
 | 
	
		
			
				|  |  | -    return self._getInfo(options.store, options).name;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    // SET
 | 
	
		
			
				|  |  | -    options = options || {};
 | 
	
		
			
				|  |  | -    return self._setInfo(options.store, 'name', value, typeof options.save === "boolean" ? options.save : true);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.extension
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {String|null} [value] - If setting the extension, specify the new extension (without period) as the first argument. Otherwise the options argument should be first.
 | 
	
		
			
				|  |  | - * @param {Object} [options]
 | 
	
		
			
				|  |  | - * @param {Object} [options.store=none,original] - Get or set the extension of the version of the file that was saved in this store. Default is the original file extension.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.updateFileRecordFirst=false] Update this instance with data from the DB first? Applies to getter usage only.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.save=true] Save change to database? Applies to setter usage only.
 | 
	
		
			
				|  |  | - * @returns {String|undefined} If setting, returns `undefined`. If getting, returns the file extension or an empty string if there isn't one.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.extension = function(value, options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!options && ((typeof value === "object" && value !== null) || typeof value === "undefined")) {
 | 
	
		
			
				|  |  | -    // GET
 | 
	
		
			
				|  |  | -    options = value || {};
 | 
	
		
			
				|  |  | -    return FS.Utility.getFileExtension(self.name(options) || '');
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    // SET
 | 
	
		
			
				|  |  | -    options = options || {};
 | 
	
		
			
				|  |  | -    var newName = FS.Utility.setFileExtension(self.name(options) || '', value);
 | 
	
		
			
				|  |  | -    return self._setInfo(options.store, 'name', newName, typeof options.save === "boolean" ? options.save : true);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.size
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {Number} [value] - If setting the size, specify the new size in bytes as the first argument. Otherwise the options argument should be first.
 | 
	
		
			
				|  |  | - * @param {Object} [options]
 | 
	
		
			
				|  |  | - * @param {Object} [options.store=none,original] - Get or set the size of the version of the file that was saved in this store. Default is the original file size.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.updateFileRecordFirst=false] Update this instance with data from the DB first? Applies to getter usage only.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.save=true] Save change to database? Applies to setter usage only.
 | 
	
		
			
				|  |  | - * @returns {Number|undefined} If setting, returns `undefined`. If getting, returns the file size.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.size = function(value, options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!options && ((typeof value === "object" && value !== null) || typeof value === "undefined")) {
 | 
	
		
			
				|  |  | -    // GET
 | 
	
		
			
				|  |  | -    options = value || {};
 | 
	
		
			
				|  |  | -    options = options.hash || options; // allow use as UI helper
 | 
	
		
			
				|  |  | -    return self._getInfo(options.store, options).size;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    // SET
 | 
	
		
			
				|  |  | -    options = options || {};
 | 
	
		
			
				|  |  | -    return self._setInfo(options.store, 'size', value, typeof options.save === "boolean" ? options.save : true);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.type
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {String} [value] - If setting the type, specify the new type as the first argument. Otherwise the options argument should be first.
 | 
	
		
			
				|  |  | - * @param {Object} [options]
 | 
	
		
			
				|  |  | - * @param {Object} [options.store=none,original] - Get or set the type of the version of the file that was saved in this store. Default is the original file type.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.updateFileRecordFirst=false] Update this instance with data from the DB first? Applies to getter usage only.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.save=true] Save change to database? Applies to setter usage only.
 | 
	
		
			
				|  |  | - * @returns {String|undefined} If setting, returns `undefined`. If getting, returns the file type.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.type = function(value, options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!options && ((typeof value === "object" && value !== null) || typeof value === "undefined")) {
 | 
	
		
			
				|  |  | -    // GET
 | 
	
		
			
				|  |  | -    options = value || {};
 | 
	
		
			
				|  |  | -    options = options.hash || options; // allow use as UI helper
 | 
	
		
			
				|  |  | -    return self._getInfo(options.store, options).type;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    // SET
 | 
	
		
			
				|  |  | -    options = options || {};
 | 
	
		
			
				|  |  | -    return self._setInfo(options.store, 'type', value, typeof options.save === "boolean" ? options.save : true);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.prototype.updatedAt
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {String} [value] - If setting updatedAt, specify the new date as the first argument. Otherwise the options argument should be first.
 | 
	
		
			
				|  |  | - * @param {Object} [options]
 | 
	
		
			
				|  |  | - * @param {Object} [options.store=none,original] - Get or set the last updated date for the version of the file that was saved in this store. Default is the original last updated date.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.updateFileRecordFirst=false] Update this instance with data from the DB first? Applies to getter usage only.
 | 
	
		
			
				|  |  | - * @param {Boolean} [options.save=true] Save change to database? Applies to setter usage only.
 | 
	
		
			
				|  |  | - * @returns {String|undefined} If setting, returns `undefined`. If getting, returns the file's last updated date.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.updatedAt = function(value, options) {
 | 
	
		
			
				|  |  | -  var self = this;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!options && ((typeof value === "object" && value !== null && !(value instanceof Date)) || typeof value === "undefined")) {
 | 
	
		
			
				|  |  | -    // GET
 | 
	
		
			
				|  |  | -    options = value || {};
 | 
	
		
			
				|  |  | -    options = options.hash || options; // allow use as UI helper
 | 
	
		
			
				|  |  | -    return self._getInfo(options.store, options).updatedAt;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    // SET
 | 
	
		
			
				|  |  | -    options = options || {};
 | 
	
		
			
				|  |  | -    return self._setInfo(options.store, 'updatedAt', value, typeof options.save === "boolean" ? options.save : true);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.onStoredCallback
 | 
	
		
			
				|  |  | - * @summary Calls callback when the file is fully stored to the specify storeName
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {String} [storeName] - The name of the file store we want to get called when stored.
 | 
	
		
			
				|  |  | - * @param {function} [callback]
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.onStoredCallback = function (storeName, callback) {
 | 
	
		
			
				|  |  | -  // Check file is not already stored
 | 
	
		
			
				|  |  | -  if (this.hasStored(storeName)) {
 | 
	
		
			
				|  |  | -    callback();
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (Meteor.isServer) {
 | 
	
		
			
				|  |  | -    // Listen to file stored events
 | 
	
		
			
				|  |  | -    // TODO Require thinking whether it is better to use observer for case of using multiple application instances, Ask for same image url while upload is being done.
 | 
	
		
			
				|  |  | -    this.on('stored', function (newStoreName) {
 | 
	
		
			
				|  |  | -      // If stored is completed to the specified store call callback
 | 
	
		
			
				|  |  | -      if (storeName === newStoreName) {
 | 
	
		
			
				|  |  | -        // Remove the specified file stored listener
 | 
	
		
			
				|  |  | -        this.removeListener('stored', arguments.callee);
 | 
	
		
			
				|  |  | -        callback();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }.bind(this)
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    var fileId = this._id,
 | 
	
		
			
				|  |  | -        collectionName = this.collectionName;
 | 
	
		
			
				|  |  | -    // Wait for file to be fully uploaded
 | 
	
		
			
				|  |  | -    Tracker.autorun(function (c) {
 | 
	
		
			
				|  |  | -      Meteor.call('_cfs_returnWhenStored', collectionName, fileId, storeName, function (error, result) {
 | 
	
		
			
				|  |  | -        if (result && result === true) {
 | 
	
		
			
				|  |  | -          c.stop();
 | 
	
		
			
				|  |  | -          callback();
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          Meteor.setTimeout(function () {
 | 
	
		
			
				|  |  | -            c.invalidate();
 | 
	
		
			
				|  |  | -          }, 100);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @method FS.File.onStored
 | 
	
		
			
				|  |  | - * @summary Function that returns when the file is fully stored to the specify storeName
 | 
	
		
			
				|  |  | - * @public
 | 
	
		
			
				|  |  | - * @param {String} storeName - The name of the file store we want to get called when stored.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Function that returns when the file is fully stored to the specify storeName.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * For example needed if wanted to save the direct link to a file on s3 when fully uploaded.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -FS.File.prototype.onStored = function (arguments) {
 | 
	
		
			
				|  |  | -  var onStoredSync = Meteor.wrapAsync(this.onStoredCallback);
 | 
	
		
			
				|  |  | -  return onStoredSync.call(this, arguments);
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -function isBasicObject(obj) {
 | 
	
		
			
				|  |  | -  return (obj === Object(obj) && Object.getPrototypeOf(obj) === Object.prototype);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// getPrototypeOf polyfill
 | 
	
		
			
				|  |  | -if (typeof Object.getPrototypeOf !== "function") {
 | 
	
		
			
				|  |  | -  if (typeof "".__proto__ === "object") {
 | 
	
		
			
				|  |  | -    Object.getPrototypeOf = function(object) {
 | 
	
		
			
				|  |  | -      return object.__proto__;
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    Object.getPrototypeOf = function(object) {
 | 
	
		
			
				|  |  | -      // May break if the constructor has been tampered with
 | 
	
		
			
				|  |  | -      return object.constructor.prototype;
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 |