<commit_before>/**
 * Backbone Firebase Adapter.
 */

(function() {

var _ = this._;
var Backbone = this.Backbone;

Backbone.Firebase = function(ref) {
  this._fbref = ref;
  this._children = [];
  if (typeof ref == "string") {
    this._fbref = new Firebase(ref);
  }
  _.bindAll(this);
  this._fbref.on("child_added", this._childAdded);
  this._fbref.on("child_moved", this._childMoved);
  this._fbref.on("child_changed", this._childChanged);
  this._fbref.on("child_removed", this._childRemoved);
};

_.extend(Backbone.Firebase.prototype, {

  _childAdded: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    if (prevChild) {
      var item = _.find(this._children, function(child) {
        return child.id == prevChild
      });
      this._children.splice(this._children.indexOf(item) + 1, 0, model);
    } else {
      this._children.unshift(model);
    }
  },
  _childMoved: function(childSnap, prevChild) {
    var model = childSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id;
    });
    this._childAdded(childSnap, prevChild);
  },
  _childChanged: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    var item = _.find(this._children, function(child) {
      return child.id == model.id
    });
    this._children[this._children.indexOf(item)] = model;
  },
  _childRemoved: function(oldChildSnap) {
    var model = oldChildSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id
    });
  },

  create: function(model, cb) {
    if (!model.id) {
      model.id = this._fbref.ref().push().name();
    }
    var val = model.toJSON();
    this._fbref.ref().child(model.id).set(val, _.bind(function(err) {
      if (!err) {
        cb(null, val);
      } else {
        cb("Could not create model " + model.id);
      }
    }, this));
  },

  read: function(model, cb) {
    if (!model.id) {
      _.defer(cb, "Invalid model ID provided to read");
      return;
    }
    var index = _.find(this._children, function(child) {
      return child.id == model.id
    });
    _.defer(cb, null, this._children[index]);
  },

  readAll: function(model, cb) {
    _.defer(cb, null, this._children);
  },

  update: function(model, cb) {
    var val = model.toJSON();
    this._fbref.ref().child(model.id).update(val, function(err) {
      if (!err) {
        cb(null, val);
      } else {
        cb("Could not update model " + model.id, null);
      }
    });
  },

  'delete': function(model, cb) {
    this._fbref.ref().child(model.id).remove(function(err) {
      if (!err) {
        cb(null, model);
      } else {
        cb("Could not delete model " + model.id);
      }
    });
  }
});

Backbone.Firebase.sync = function(method, model, options, error) {
  var store = model.firebase || model.collection.firebase;

  // Backwards compatibility with Backbone <= 0.3.3
  if (typeof options == 'function') {
    options = {
      success: options,
      error: error
    };
  }

  if (method == "read" && model.id == undefined) {
    method = "readAll";
  }

  store[method].apply(this, [model, function(err, val) {
    if (err) {
      model.trigger("error", model, err, options);
      if (Backbone.VERSION === "0.9.10") {
        options.error(model, err, options);
      } else {
        options.error(err);
      }
    } else {
      model.trigger("sync", model, val, options);
      if (Backbone.VERSION === "0.9.10") {
        options.success(model, val, options);
      } else {
        options.success(val);
      }
    }
  }]);
};

Backbone.oldSync = Backbone.sync;

// Override 'Backbone.sync' to default to Firebase sync.
// the original 'Backbone.sync' is still available in 'Backbone.oldSync'
Backbone.sync = function(method, model, options, error) {
  var syncMethod = Backbone.oldSync;
  if (model.firebase || (model.collection && model.collection.firebase)) {
    syncMethod = Backbone.Firebase.sync;
  }
  return syncMethod.apply(this, [method, model, options, error]);
};

// Custom Firebase Collection.
Backbone.Firebase.Collection = Backbone.Collection.extend({
  sync: function() {
    this._log("Sync called on a Firebase collection, ignoring.");
  },

  fetch: function() {
    this._log("Fetch called on a Firebase collection, ignoring.");
  },

  constructor: function(models, options) {

    // Apply parent constructor (this will also call initialize).
    Backbone.Collection.apply(this, arguments);

    if (options && options.firebase) {
      this.firebase = options.firebase;
    }
    switch (typeof this.firebase) {
      case "object": break;
      case "string": this.firebase = new Firebase(this.firebase); break;
      case "function": this.firebase = this.firebase(); break;
      default: throw new Error("Invalid firebase reference created");
    }

    // Add handlers for remote events.
    this.firebase.on("child_added", _.bind(this._childAdded, this));
    this.firebase.on("child_moved", _.bind(this._childMoved, this));
    this.firebase.on("child_changed", _.bind(this._childChanged, this));
    this.firebase.on("child_removed", _.bind(this._childRemoved, this));

    // Add handlers for all models in this collection, and any future ones
    // that may be added.
    function _updateModel(model, options) {
      this.firebase.ref().child(model.id).update(model.toJSON());
    }
    function _unUpdateModel(model) {
      model.off("change", _updateModel, this);
    }

    for (var i = 0; i < this.models.length; i++) {
      this.models[i].on("change", _updateModel, this);
      this.models[i].once("remove", _unUpdateModel, this);
    }
    this.on("add", function(model) {
      model.on("change", _updateModel, this);
      model.once("remove", _unUpdateModel, this);
    }, this);
  },

  comparator: function(model) {
    return model.id;
  },

  add: function(models, options) {
    var parsed = this._parseModels(models);
    options = options ? _.clone(options) : {};
    options.success = _.isFunction(options.success) ? options.success : function() {};

    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.ref().child(model.id).set(model, _.bind(options.success, model));
    }
  },

  remove: function(models, options) {
    var parsed = this._parseModels(models);
    options = options ? _.clone(options) : {};
    options.success = _.isFunction(options.success) ? options.success : function() {};

    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.ref().child(model.id).set(null, _.bind(options.success, model));
    }
  },

  create: function(model, options) {
    this._log("Create called, aliasing to add. Consider using Collection.add!");
    options = options ? _.clone(options) : {};
    if (options.wait) {
      this._log("Wait option provided to create, ignoring.");
    }
    model = Backbone.Collection.prototype._prepareModel.apply(
      this, [model, options]
    );
    if (!model) {
      return false;
    }
    this.add([model], options);
    return model;
  },

  _log: function(msg) {
    if (console && console.log) {
      console.log(msg);
    }
  },

  // TODO: Options will be ignored for add & remove, document this!
  _parseModels: function(models) {
    var ret = [];
    models = _.isArray(models) ? models.slice() : [models];
    for (var i = 0; i < models.length; i++) {
      var model = models[i];
      if (model.toJSON && typeof model.toJSON == "function") {
        model = model.toJSON();
      }
      if (!model.id) {
        model.id = this.firebase.ref().push().name();
      }
      ret.push(model);
    }
    return ret;
  },

  _childAdded: function(snap) {
    var model = snap.val()
    if (!model.id) model.id = snap.name()
    Backbone.Collection.prototype.add.apply(this, [model]);
  },

  _childMoved: function(snap) {
    // TODO: Investigate: can this occur without the ID changing?
    this._log("_childMoved called with " + snap.val());
  },

  _childChanged: function(snap) {
    var model = snap.val();
    if (!model.id) model.id = snap.name()
    var item = _.find(this.models, function(child) {
      return child.id == model.id
    });
    if (!item) {
      // TODO: Investigate: what is the right way to handle this case?
      throw new Error("Could not find model with ID " + model.id);
    }

    var diff = _.difference(_.keys(item.attributes), _.keys(model));
    _.each(diff, function(key) {
      item.unset(key);
    });

    item.set(model);
  },

  _childRemoved: function(snap) {
    var model = snap.val()
    if (!model.id) model.id = snap.name()
    Backbone.Collection.prototype.remove.apply(this, [model]);
  }
});

// Custom Firebase Model.
Backbone.Firebase.Model = Backbone.Model.extend({
  save: function() {
    this._log("Save called on a Firebase model, ignoring.");
  },

  destroy: function(options) {
    // TODO: Fix naive success callback. Add error callback.
    this.firebase.ref().set(null, this._log);
    this.trigger('destroy', this, this.collection, options);
    if (options.success) {
      options.success(this,null,options);
    }
  },

  constructor: function(model, options) {

    // Apply parent constructor (this will also call initialize).
    Backbone.Model.apply(this, arguments);

    if (options && options.firebase) {
      this.firebase = options.firebase;
    }
    switch (typeof this.firebase) {
      case "object": break;
      case "string": this.firebase = new Firebase(this.firebase); break;
      case "function": this.firebase = this.firebase(); break;
      default: throw new Error("Invalid firebase reference created");
    }

    // Add handlers for remote events.
    this.firebase.on("value", this._modelChanged.bind(this));

    this._listenLocalChange(true);
  },

  _listenLocalChange: function(state) {
    if (state)
      this.on("change", this._updateModel, this);
    else
      this.off("change", this._updateModel, this);
  },

  _updateModel: function(model, options) {
    // Find the deleted keys and set their values to null
    // so Firebase properly deletes them.
    var modelObj = model.toJSON();
    _.each(model.changed, function(value, key) {
      if (typeof value === "undefined" || value === null)
        if (key == "id")
          delete modelObj[key];
        else
          modelObj[key] = null;
    });
    if (_.size(modelObj))
      this.firebase.ref().update(modelObj, this._log);
  },

  _modelChanged: function(snap) {
    // Unset attributes that have been deleted from the server
    // by comparing the keys that have been removed.
    var newModel = snap.val();
    if (typeof newModel === "object" && newModel !== null) {
      var diff = _.difference(_.keys(this.attributes), _.keys(newModel));
      var _this = this;
      _.each(diff, function(key) {
          _this.unset(key);
      });
    }
    this._listenLocalChange(false);
    this.set(newModel);
    this.trigger('sync', this, null, null);
    this._listenLocalChange(true);
  },

  _log: function(msg) {
    if (typeof msg === "undefined" || msg === null) return;
    if (console && console.log) {
      console.log(msg);
    }
  }

});

})();
<commit_msg>Fixed Echo on Collections<commit_after>/**
 * Backbone Firebase Adapter.
 */

(function() {

var _ = this._;
var Backbone = this.Backbone;

Backbone.Firebase = function(ref) {
  this._fbref = ref;
  this._children = [];
  if (typeof ref == "string") {
    this._fbref = new Firebase(ref);
  }
  _.bindAll(this);
  this._fbref.on("child_added", this._childAdded);
  this._fbref.on("child_moved", this._childMoved);
  this._fbref.on("child_changed", this._childChanged);
  this._fbref.on("child_removed", this._childRemoved);
};

_.extend(Backbone.Firebase.prototype, {

  _childAdded: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    if (prevChild) {
      var item = _.find(this._children, function(child) {
        return child.id == prevChild
      });
      this._children.splice(this._children.indexOf(item) + 1, 0, model);
    } else {
      this._children.unshift(model);
    }
  },
  _childMoved: function(childSnap, prevChild) {
    var model = childSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id;
    });
    this._childAdded(childSnap, prevChild);
  },
  _childChanged: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    var item = _.find(this._children, function(child) {
      return child.id == model.id
    });
    this._children[this._children.indexOf(item)] = model;
  },
  _childRemoved: function(oldChildSnap) {
    var model = oldChildSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id
    });
  },

  create: function(model, cb) {
    if (!model.id) {
      model.id = this._fbref.ref().push().name();
    }
    var val = model.toJSON();
    this._fbref.ref().child(model.id).set(val, _.bind(function(err) {
      if (!err) {
        cb(null, val);
      } else {
        cb("Could not create model " + model.id);
      }
    }, this));
  },

  read: function(model, cb) {
    if (!model.id) {
      _.defer(cb, "Invalid model ID provided to read");
      return;
    }
    var index = _.find(this._children, function(child) {
      return child.id == model.id
    });
    _.defer(cb, null, this._children[index]);
  },

  readAll: function(model, cb) {
    _.defer(cb, null, this._children);
  },

  update: function(model, cb) {
    var val = model.toJSON();
    this._fbref.ref().child(model.id).update(val, function(err) {
      if (!err) {
        cb(null, val);
      } else {
        cb("Could not update model " + model.id, null);
      }
    });
  },

  'delete': function(model, cb) {
    this._fbref.ref().child(model.id).remove(function(err) {
      if (!err) {
        cb(null, model);
      } else {
        cb("Could not delete model " + model.id);
      }
    });
  }
});

Backbone.Firebase.sync = function(method, model, options, error) {
  var store = model.firebase || model.collection.firebase;

  // Backwards compatibility with Backbone <= 0.3.3
  if (typeof options == 'function') {
    options = {
      success: options,
      error: error
    };
  }

  if (method == "read" && model.id == undefined) {
    method = "readAll";
  }

  store[method].apply(this, [model, function(err, val) {
    if (err) {
      model.trigger("error", model, err, options);
      if (Backbone.VERSION === "0.9.10") {
        options.error(model, err, options);
      } else {
        options.error(err);
      }
    } else {
      model.trigger("sync", model, val, options);
      if (Backbone.VERSION === "0.9.10") {
        options.success(model, val, options);
      } else {
        options.success(val);
      }
    }
  }]);
};

Backbone.oldSync = Backbone.sync;

// Override 'Backbone.sync' to default to Firebase sync.
// the original 'Backbone.sync' is still available in 'Backbone.oldSync'
Backbone.sync = function(method, model, options, error) {
  var syncMethod = Backbone.oldSync;
  if (model.firebase || (model.collection && model.collection.firebase)) {
    syncMethod = Backbone.Firebase.sync;
  }
  return syncMethod.apply(this, [method, model, options, error]);
};

// Custom Firebase Collection.
Backbone.Firebase.Collection = Backbone.Collection.extend({
  sync: function() {
    this._log("Sync called on a Firebase collection, ignoring.");
  },

  fetch: function() {
    this._log("Fetch called on a Firebase collection, ignoring.");
  },

  constructor: function(models, options) {

    // Apply parent constructor (this will also call initialize).
    Backbone.Collection.apply(this, arguments);

    if (options && options.firebase) {
      this.firebase = options.firebase;
    }
    switch (typeof this.firebase) {
      case "object": break;
      case "string": this.firebase = new Firebase(this.firebase); break;
      case "function": this.firebase = this.firebase(); break;
      default: throw new Error("Invalid firebase reference created");
    }

    // Add handlers for remote events.
    this.firebase.on("child_added", _.bind(this._childAdded, this));
    this.firebase.on("child_moved", _.bind(this._childMoved, this));
    this.firebase.on("child_changed", _.bind(this._childChanged, this));
    this.firebase.on("child_removed", _.bind(this._childRemoved, this));

    for (var i = 0; i < this.models.length; i++) {
      this.models[i].on("change", this._updateModel, this);
      this.models[i].once("remove", this._unUpdateModel, this);
    }
    this.on("add", function(model) {
      model.on("change", this._updateModel, this);
      model.once("remove", this._unUpdateModel, this);
    }, this);
  },

  comparator: function(model) {
    return model.id;
  },

  add: function(models, options) {
    var parsed = this._parseModels(models);
    options = options ? _.clone(options) : {};
    options.success = _.isFunction(options.success) ? options.success : function() {};

    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.ref().child(model.id).set(model, _.bind(options.success, model));
    }
  },

  remove: function(models, options) {
    var parsed = this._parseModels(models);
    options = options ? _.clone(options) : {};
    options.success = _.isFunction(options.success) ? options.success : function() {};

    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.ref().child(model.id).set(null, _.bind(options.success, model));
    }
  },

  create: function(model, options) {
    this._log("Create called, aliasing to add. Consider using Collection.add!");
    options = options ? _.clone(options) : {};
    if (options.wait) {
      this._log("Wait option provided to create, ignoring.");
    }
    model = Backbone.Collection.prototype._prepareModel.apply(
      this, [model, options]
    );
    if (!model) {
      return false;
    }
    this.add([model], options);
    return model;
  },

  _log: function(msg) {
    if (console && console.log) {
      console.log(msg);
    }
  },

  // TODO: Options will be ignored for add & remove, document this!
  _parseModels: function(models) {
    var ret = [];
    models = _.isArray(models) ? models.slice() : [models];
    for (var i = 0; i < models.length; i++) {
      var model = models[i];
      if (model.toJSON && typeof model.toJSON == "function") {
        model = model.toJSON();
      }
      if (!model.id) {
        model.id = this.firebase.ref().push().name();
      }
      ret.push(model);
    }
    return ret;
  },

  _childAdded: function(snap) {
    var model = snap.val()
    if (!model.id) model.id = snap.name()
    Backbone.Collection.prototype.add.apply(this, [model]);
  },

  _childMoved: function(snap) {
    // TODO: Investigate: can this occur without the ID changing?
    this._log("_childMoved called with " + snap.val());
  },

  _childChanged: function(snap) {
    var model = snap.val();
    if (!model.id) model.id = snap.name()
    var item = _.find(this.models, function(child) {
      return child.id == model.id
    });
    if (!item) {
      // TODO: Investigate: what is the right way to handle this case?
      throw new Error("Could not find model with ID " + model.id);
    }

    var diff = _.difference(_.keys(item.attributes), _.keys(model));
    _.each(diff, function(key) {
      item.unset(key);
    });

    this._listenLocalChange(item, false);
    item.set(model);
    this._listenLocalChange(item, true);
  },

  _childRemoved: function(snap) {
    var model = snap.val()
    if (!model.id) model.id = snap.name()
    Backbone.Collection.prototype.remove.apply(this, [model]);
  },

  // Add handlers for all models in this collection, and any future ones
  // that may be added.
  _updateModel: function(model, options) {
    this.firebase.ref().child(model.id).update(model.toJSON());
  },

  _unUpdateModel: function(model) {
    model.off("change", this._updateModel, this);
  },

  _listenLocalChange: function(model, state) {
    if (state)
      model.on("change", this._updateModel, this);
    else
      this._unUpdateModel(model);
  }
});

// Custom Firebase Model.
Backbone.Firebase.Model = Backbone.Model.extend({
  save: function() {
    this._log("Save called on a Firebase model, ignoring.");
  },

  destroy: function(options) {
    // TODO: Fix naive success callback. Add error callback.
    this.firebase.ref().set(null, this._log);
    this.trigger('destroy', this, this.collection, options);
    if (options.success) {
      options.success(this,null,options);
    }
  },

  constructor: function(model, options) {

    // Apply parent constructor (this will also call initialize).
    Backbone.Model.apply(this, arguments);

    if (options && options.firebase) {
      this.firebase = options.firebase;
    }
    switch (typeof this.firebase) {
      case "object": break;
      case "string": this.firebase = new Firebase(this.firebase); break;
      case "function": this.firebase = this.firebase(); break;
      default: throw new Error("Invalid firebase reference created");
    }

    // Add handlers for remote events.
    this.firebase.on("value", this._modelChanged.bind(this));

    this._listenLocalChange(true);
  },

  _listenLocalChange: function(state) {
    if (state)
      this.on("change", this._updateModel, this);
    else
      this.off("change", this._updateModel, this);
  },

  _updateModel: function(model, options) {
    // Find the deleted keys and set their values to null
    // so Firebase properly deletes them.
    var modelObj = model.toJSON();
    _.each(model.changed, function(value, key) {
      if (typeof value === "undefined" || value === null)
        if (key == "id")
          delete modelObj[key];
        else
          modelObj[key] = null;
    });
    if (_.size(modelObj))
      this.firebase.ref().update(modelObj, this._log);
  },

  _modelChanged: function(snap) {
    // Unset attributes that have been deleted from the server
    // by comparing the keys that have been removed.
    var newModel = snap.val();
    if (typeof newModel === "object" && newModel !== null) {
      var diff = _.difference(_.keys(this.attributes), _.keys(newModel));
      var _this = this;
      _.each(diff, function(key) {
          _this.unset(key);
      });
    }
    this._listenLocalChange(false);
    this.set(newModel);
    this.trigger('sync', this, null, null);
    this._listenLocalChange(true);
  },

  _log: function(msg) {
    if (typeof msg === "undefined" || msg === null) return;
    if (console && console.log) {
      console.log(msg);
    }
  }

});

})();
<|endoftext|>


<commit_before>(function (window, $, _, Backbone) {

  var LightboxView = Backbone.View.extend({

    tagName: 'div',
    className: 'lightbox',
    options: {
      closeButtonTitle: 'close'
    },
    content: '',
    _dfd: null,

    events: {
      'click .lightbox-close': 'hide',
    },

    initialize: function (options) {
      this.options = $.extend(this.options, options);
      this.$el.html('
<button class="lightbox-close" title="' + this.options.closeButtonTitle + '"></button>

');
      if (this.options.additionalClassName) {
        this.$el.addClass(this.options.additionalClassName);
      }
      $('body').append(this.$el);
      this.hide();
      this._setLocalScope();
      this._setListeners();
    },

    _setLocalScope: function () {
      this.$content = this.$('.lightbox-content');
      this.$wrapper = this.$('.lightbox-wrapper');
    },

    _setListeners: function () {
      _.bindAll(this, '_centerVertically', '_onElClicked', '_keyup');
      $(window).on('resize', this._onResize);
      this.$el.click(this._onElClicked);
      $(document).keyup(this._keyup);
    },

    _setContent: function (content) {
      // Backbone view
      if (typeof content.render === 'function') {
        content.render();
        this._content = content.$el;
      }
      // jQuery object
      else if (content.jquery) {
        this._content = content;
      }
      // DOM string
      else if (typeof content === 'string') {
        this._content = $(content);
      }
      else {
        return false;
      }
      return true;
    },

    _setWidth: function (width) {
      this.$wrapper.css('width', width);
    },

    _resolvePromise: function () {
      if (this._dfd) {
        this._dfd.resolve();
        this._dfd = null;
      }
    },

    _setPromise: function () {
      this._resolvePromise();
      this._dfd = new jQuery.Deferred();
    },

    render: function () {
      this.$content.empty();
      this.$content.append(this._content);
      return this;
    },

    show: function (content, width) {
      // try to set content
      if (content) {
        if (!this._setContent(content)) {
          return false;
        }
      }
      // set width
      width = width || this.options.width;
      if (width) {
        this._setWidth(width);
      }
      // show content
      this.render();
      this.$el.show();
      this._centerVertically();
      this._setPromise();
      return this._dfd.promise();
    },

    hide: function () {
      this.$el.hide();
      this._resolvePromise();
      return this;
    },

    _onElClicked: function (e) {
      if ($(e.target).hasClass('lightbox')) {
        this.hide();
      }
    },

    _keyup: function (e) {
      if (e.keyCode === 27) { // esc
        this.hide();
      }
    },

    _onResize: function (e) {
      if (this._centeredVertically) {
        this._centerVertically();
      }
    },

    _centerVertically: function () {
      this._centeredVertically = false;
      var windowHeight = $(window).height();
      var wrapperHeight = this.$wrapper.height();
      if (windowHeight > wrapperHeight) {
        this._centeredVertically = true;
        this.$wrapper.css('marginTop', Math.floor((windowHeight - wrapperHeight) / 2));
      }
    }
  });

  window.LightboxView = LightboxView;
}(window, jQuery, _, Backbone));
<commit_msg>Remove trailing ,<commit_after>(function (window, $, _, Backbone) {

  var LightboxView = Backbone.View.extend({

    tagName: 'div',
    className: 'lightbox',
    options: {
      closeButtonTitle: 'close'
    },
    content: '',
    _dfd: null,

    events: {
      'click .lightbox-close': 'hide'
    },

    initialize: function (options) {
      this.options = $.extend(this.options, options);
      this.$el.html('
<button class="lightbox-close" title="' + this.options.closeButtonTitle + '"></button>

');
      if (this.options.additionalClassName) {
        this.$el.addClass(this.options.additionalClassName);
      }
      $('body').append(this.$el);
      this.hide();
      this._setLocalScope();
      this._setListeners();
    },

    _setLocalScope: function () {
      this.$content = this.$('.lightbox-content');
      this.$wrapper = this.$('.lightbox-wrapper');
    },

    _setListeners: function () {
      _.bindAll(this, '_centerVertically', '_onElClicked', '_keyup');
      $(window).on('resize', this._onResize);
      this.$el.click(this._onElClicked);
      $(document).keyup(this._keyup);
    },

    _setContent: function (content) {
      // Backbone view
      if (typeof content.render === 'function') {
        content.render();
        this._content = content.$el;
      }
      // jQuery object
      else if (content.jquery) {
        this._content = content;
      }
      // DOM string
      else if (typeof content === 'string') {
        this._content = $(content);
      }
      else {
        return false;
      }
      return true;
    },

    _setWidth: function (width) {
      this.$wrapper.css('width', width);
    },

    _resolvePromise: function () {
      if (this._dfd) {
        this._dfd.resolve();
        this._dfd = null;
      }
    },

    _setPromise: function () {
      this._resolvePromise();
      this._dfd = new jQuery.Deferred();
    },

    render: function () {
      this.$content.empty();
      this.$content.append(this._content);
      return this;
    },

    show: function (content, width) {
      // try to set content
      if (content) {
        if (!this._setContent(content)) {
          return false;
        }
      }
      // set width
      width = width || this.options.width;
      if (width) {
        this._setWidth(width);
      }
      // show content
      this.render();
      this.$el.show();
      this._centerVertically();
      this._setPromise();
      return this._dfd.promise();
    },

    hide: function () {
      this.$el.hide();
      this._resolvePromise();
      return this;
    },

    _onElClicked: function (e) {
      if ($(e.target).hasClass('lightbox')) {
        this.hide();
      }
    },

    _keyup: function (e) {
      if (e.keyCode === 27) { // esc
        this.hide();
      }
    },

    _onResize: function (e) {
      if (this._centeredVertically) {
        this._centerVertically();
      }
    },

    _centerVertically: function () {
      this._centeredVertically = false;
      var windowHeight = $(window).height();
      var wrapperHeight = this.$wrapper.height();
      if (windowHeight > wrapperHeight) {
        this._centeredVertically = true;
        this.$wrapper.css('marginTop', Math.floor((windowHeight - wrapperHeight) / 2));
      }
    }
  });

  window.LightboxView = LightboxView;
}(window, jQuery, _, Backbone));
<|endoftext|>


<commit_before>// backbone-subroute.js v0.4.1
//
// Copyright (C) 2012 Dave Cadwallader, Model N, Inc.
// Distributed under the MIT License
//
// Documentation and full license available at:
// https://github.com/ModelN/backbone.subroute

(function(factory) {
    if (typeof define === 'function' && define.amd) {
        // Register as an AMD module if available...
        define(['underscore', 'backbone'], factory);
    } else {
        // Browser globals for the unenlightened...
        factory(_, Backbone);
    }
}(function(_, Backbone) {

    Backbone.SubRoute = Backbone.Router.extend({
        constructor: function(prefix, options) {

            // each subroute instance should have its own routes hash
            this.routes = _.clone(this.routes) || {};

            // Prefix is optional, set to empty string if not passed
            this.prefix = prefix = prefix || "";

            // SubRoute instances may be instantiated using a prefix with or without a trailing slash.
            // If the prefix does *not* have a trailing slash, we need to insert a slash as a separator
            // between the prefix and the sub-route path for each route that we register with Backbone.
            this.separator = (prefix.slice(-1) === "/") ? "" : "/";

            // if you want to match "books" and "books/" without creating separate routes, set this
            // option to "true" and the sub-router will automatically create those routes for you.
            this.createTrailingSlashRoutes = options && options.createTrailingSlashRoutes;

            // Required to have Backbone set up routes
            Backbone.Router.prototype.constructor.call(this, options);

            // grab the full URL
            var hash;
            if (Backbone.history.fragment) {
                hash = Backbone.history.getFragment();
            } else {
                hash = Backbone.history.getHash();
            }

            // Trigger the subroute immediately.  this supports the case where
            // a user directly navigates to a URL with a subroute on the first page load.
            // Check every element, if one matches, break. Prevent multiple matches
            _.every(this.routes, function(key, route) {
                // Use the Backbone parser to turn route into regex for matching
                if (hash.match(Backbone.Router.prototype._routeToRegExp(route))) {
                    Backbone.history.loadUrl(hash);
                    return false;
                }
                return true;
            }, this);

            if (this.postInitialize) {
                this.postInitialize(options);
            }
        },
        navigate: function(route, options) {
            if (route.substr(0, 1) != '/' &&
                route.indexOf(this.prefix.substr(0, this.prefix.length - 1)) !== 0) {

                route = this.prefix +
                    (route ? this.separator : "") +
                    route;
            }
            Backbone.Router.prototype.navigate.call(this, route, options);
        },
        route: function(route, name, callback) {
            // strip off any leading slashes in the sub-route path,
            // since we already handle inserting them when needed.
            if (route.substr(0) === "/") {
                route = route.substr(1, route.length);
            }

            var _route = this.prefix;
            if (route && route.length > 0)
                _route += (this.separator + route);

            if (this.createTrailingSlashRoutes) {
                this.routes[_route + '/'] = name;
                Backbone.Router.prototype.route.call(this, _route + '/', name, callback);
            }

            // remove the un-prefixed route from our routes hash
            delete this.routes[route];

            // add the prefixed-route.  note that this routes hash is just provided
            // for informational and debugging purposes and is not used by the actual routing code.
            this.routes[_route] = name;

            // delegate the creation of the properly-prefixed route to Backbone
            return Backbone.Router.prototype.route.call(this, _route, name, callback);
        }
    });
    return Backbone.SubRoute;
}));
<commit_msg>Added support for commonjs<commit_after>// backbone-subroute.js v0.4.1
//
// Copyright (C) 2012 Dave Cadwallader, Model N, Inc.
// Distributed under the MIT License
//
// Documentation and full license available at:
// https://github.com/ModelN/backbone.subroute

(function(factory) {
    if (typeof define === 'function' && define.amd) {
        // Register as an AMD module if available...
        define(['underscore', 'backbone'], factory);
    } else if (typeof exports === 'object') {
        // Next for Node.js, CommonJS, browserify...
        factory(require('underscore'), require('backbone'));
    } else {
        // Browser globals for the unenlightened...
        factory(_, Backbone);
    }
}(function(_, Backbone) {

    Backbone.SubRoute = Backbone.Router.extend({
        constructor: function(prefix, options) {

            // each subroute instance should have its own routes hash
            this.routes = _.clone(this.routes) || {};

            // Prefix is optional, set to empty string if not passed
            this.prefix = prefix = prefix || "";

            // SubRoute instances may be instantiated using a prefix with or without a trailing slash.
            // If the prefix does *not* have a trailing slash, we need to insert a slash as a separator
            // between the prefix and the sub-route path for each route that we register with Backbone.
            this.separator = (prefix.slice(-1) === "/") ? "" : "/";

            // if you want to match "books" and "books/" without creating separate routes, set this
            // option to "true" and the sub-router will automatically create those routes for you.
            this.createTrailingSlashRoutes = options && options.createTrailingSlashRoutes;

            // Required to have Backbone set up routes
            Backbone.Router.prototype.constructor.call(this, options);

            // grab the full URL
            var hash;
            if (Backbone.history.fragment) {
                hash = Backbone.history.getFragment();
            } else {
                hash = Backbone.history.getHash();
            }

            // Trigger the subroute immediately.  this supports the case where
            // a user directly navigates to a URL with a subroute on the first page load.
            // Check every element, if one matches, break. Prevent multiple matches
            _.every(this.routes, function(key, route) {
                // Use the Backbone parser to turn route into regex for matching
                if (hash.match(Backbone.Router.prototype._routeToRegExp(route))) {
                    Backbone.history.loadUrl(hash);
                    return false;
                }
                return true;
            }, this);

            if (this.postInitialize) {
                this.postInitialize(options);
            }
        },
        navigate: function(route, options) {
            if (route.substr(0, 1) != '/' &&
                route.indexOf(this.prefix.substr(0, this.prefix.length - 1)) !== 0) {

                route = this.prefix +
                    (route ? this.separator : "") +
                    route;
            }
            Backbone.Router.prototype.navigate.call(this, route, options);
        },
        route: function(route, name, callback) {
            // strip off any leading slashes in the sub-route path,
            // since we already handle inserting them when needed.
            if (route.substr(0) === "/") {
                route = route.substr(1, route.length);
            }

            var _route = this.prefix;
            if (route && route.length > 0)
                _route += (this.separator + route);

            if (this.createTrailingSlashRoutes) {
                this.routes[_route + '/'] = name;
                Backbone.Router.prototype.route.call(this, _route + '/', name, callback);
            }

            // remove the un-prefixed route from our routes hash
            delete this.routes[route];

            // add the prefixed-route.  note that this routes hash is just provided
            // for informational and debugging purposes and is not used by the actual routing code.
            this.routes[_route] = name;

            // delegate the creation of the properly-prefixed route to Backbone
            return Backbone.Router.prototype.route.call(this, _route, name, callback);
        }
    });
    return Backbone.SubRoute;
}));
<|endoftext|>


<commit_before>// backbone-subroute.js v0.2
//
// Copyright (C) 2012 Dave Cadwallader, Model N, Inc.
// Distributed under the MIT License
//
// Documentation and full license available at:
// https://github.com/ModelN/backbone.subroute

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // Register as an AMD module if available...
        define(['underscore', 'backbone'], factory);
    } else {
        // Browser globals for the unenlightened...
        factory(_, Backbone);
    }
}(function(_, Backbone){

    Backbone.SubRoute = Backbone.Router.extend( {
        constructor:function ( prefix, options ) {
            var routes = {};

            // Prefix is optional, set to empty string if not passed
            this.prefix = prefix = prefix || "";

            // SubRoute instances may be instantiated using a prefix with or without a trailing slash.
            // If the prefix does *not* have a trailing slash, we need to insert a slash as a separator
            // between the prefix and the sub-route path for each route that we register with Backbone.
            var separator =
                    ( prefix.substr( -1 ) === "/" )
                            ? ""
                            : "/";

            // if you want to match "books" and "books/" without creating separate routes, set this
            // option to "true" and the sub-router will automatically create those routes for you.
            var createTrailingSlashRoutes = options && options.createTrailingSlashRoutes;

            // Register each sub-route with Backbone by combining the prefix and the sub-route path
            _.each( this.routes, function ( callback, path ) {
                if ( path ) {

                    // strip off any leading slashes in the sub-route path,
                    // since we already handle inserting them when needed.
                    if (path.substr(0) === "/") {
                        path = path.substr(1, path.length);
                    }

                    routes[prefix + separator + path] = callback;

                    if (createTrailingSlashRoutes) {
                        routes[prefix + separator + path + "/"] = callback;
                    }

                } else {
                    // default routes (those with a path equal to the empty string)
                    // are simply registered using the prefix as the route path.
                    routes[prefix] = callback;

                    if (createTrailingSlashRoutes) {
                        routes[prefix + "/"] = callback;
                    }
                }
            } );

            // Override the local sub-routes with the fully-qualified routes that we just set up.
            this.routes = routes;

            // Required to have Backbone set up routes
            Backbone.Router.prototype.constructor.call( this, options );

            // grab the full URL
            var hash = Backbone.history.getHash();

            // Trigger the subroute immediately.  this supports the case where
            // a user directly navigates to a URL with a subroute on the first page load.
            Backbone.history.loadUrl( hash );
        },
        navigate:function ( route, options ) {
            if ( route.substr( 0, 1 ) != '/' && route.indexOf( this.prefix.substr( 0,
                    this.prefix.length - 1 ) ) != 0 ) {
                route = this.prefix + route;
            }
            Backbone.Router.prototype.navigate.call( this, route, options );
        }
    } );
}));
<commit_msg>Fixed issue where separator "/" was not getting applied between prefix and fragment when calling navigate()<commit_after>// backbone-subroute.js v0.3
//
// Copyright (C) 2012 Dave Cadwallader, Model N, Inc.
// Distributed under the MIT License
//
// Documentation and full license available at:
// https://github.com/ModelN/backbone.subroute

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // Register as an AMD module if available...
        define(['underscore', 'backbone'], factory);
    } else {
        // Browser globals for the unenlightened...
        factory(_, Backbone);
    }
}(function(_, Backbone){

    Backbone.SubRoute = Backbone.Router.extend( {
        constructor:function ( prefix, options ) {
            var routes = {};

            // Prefix is optional, set to empty string if not passed
            this.prefix = prefix = prefix || "";

            // SubRoute instances may be instantiated using a prefix with or without a trailing slash.
            // If the prefix does *not* have a trailing slash, we need to insert a slash as a separator
            // between the prefix and the sub-route path for each route that we register with Backbone.
            this.separator =
                    ( prefix.substr( -1 ) === "/" )
                            ? ""
                            : "/";

            // if you want to match "books" and "books/" without creating separate routes, set this
            // option to "true" and the sub-router will automatically create those routes for you.
            var createTrailingSlashRoutes = options && options.createTrailingSlashRoutes;

            // Register each sub-route with Backbone by combining the prefix and the sub-route path
            _.each( this.routes, function ( callback, path ) {
                if ( path ) {

                    // strip off any leading slashes in the sub-route path,
                    // since we already handle inserting them when needed.
                    if (path.substr(0) === "/") {
                        path = path.substr(1, path.length);
                    }

                    routes[prefix + this.separator + path] = callback;

                    if (createTrailingSlashRoutes) {
                        routes[prefix + this.separator + path + "/"] = callback;
                    }

                } else {
                    // default routes (those with a path equal to the empty string)
                    // are simply registered using the prefix as the route path.
                    routes[prefix] = callback;

                    if (createTrailingSlashRoutes) {
                        routes[prefix + "/"] = callback;
                    }
                }
            }, this );

            // Override the local sub-routes with the fully-qualified routes that we just set up.
            this.routes = routes;

            // Required to have Backbone set up routes
            Backbone.Router.prototype.constructor.call( this, options );

            // grab the full URL
            var hash = Backbone.history.getHash();

            // Trigger the subroute immediately.  this supports the case where
            // a user directly navigates to a URL with a subroute on the first page load.
            Backbone.history.loadUrl( hash );
        },
        navigate:function ( route, options ) {
            if ( route.substr( 0, 1 ) != '/' && route.indexOf( this.prefix.substr( 0,
                    this.prefix.length - 1 ) ) != 0 ) {

                route = this.prefix +
                        ( route ? this.separator : "") +
                        route;
            }
            Backbone.Router.prototype.navigate.call( this, route, options );
        }
    } );
}));
<|endoftext|>


<commit_before>import { MicroState } from 'ember-microstates';
import assign from '../utils/assign';
import { reduceObject } from '../utils/object-utils';

export default MicroState.extend({

  handlebarsValueFor(object, value) {
    return reduceObject(value, function(result, name, value) {
      return assign(result, {
        [name]: value
      });
    }, object);
  },

  actions: {
    recompute(current, params, options) {
      return options;
    },
    delete(current, target) {
      return reduceObject(current, function(result, name, value) {
        if (target === name) {
          return result;
        } else {
          return assign(result, {
            [name]: value
          });
        }
      });
    },
    assign(current, object={}) {
      return assign({}, current, object);
    },
    put(current, property, value) {
      return assign({}, current, {
        [property]: value
      });
    }
  }
});
<commit_msg>Ensure that a new object is used<commit_after>import { MicroState } from 'ember-microstates';
import assign from '../utils/assign';
import { reduceObject } from '../utils/object-utils';

export default MicroState.extend({

  prototypeFor(value) {
    return assign({}, value);
  },

  handlebarsValueFor(object, value) {
    return reduceObject(value, function(result, name, value) {
      return assign(result, {
        [name]: value
      });
    }, object);
  },

  actions: {
    recompute(current, params, options) {
      return options;
    },
    delete(current, target) {
      return reduceObject(current, function(result, name, value) {
        if (target === name) {
          return result;
        } else {
          return assign(result, {
            [name]: value
          });
        }
      });
    },
    assign(current, object={}) {
      return assign({}, current, object);
    },
    put(current, property, value) {
      return assign({}, current, {
        [property]: value
      });
    }
  }
});
<|endoftext|>


<commit_before>import Ember from 'ember';

/**
 * @module ember-dialog/mixins/context
 * @augments Ember.Mixin
 */
export default Ember.Mixin.create({

  /**
   * @property {Function} accept
   * @property {Function} decline
   */
  actions: {

    accept() {
      const acceptHandler = this.get("acceptHandler");
      const context = this.context.get("contextObject");
      if (context._actions && context._actions[acceptHandler]) {
        let args = Array.prototype.slice.apply(arguments);
            args.unshift(this);
        context._actions[acceptHandler].apply(context, args);
      } else {
        this.accept();
      }
    },

    decline() {
      const declineHandler = this.get("declineHandler");
      const context = this.context.get("contextObject");
      if (context._actions && context._actions[declineHandler]) {
        let args = Array.prototype.slice.apply(arguments);
            args.unshift(this);
        context._actions[declineHandler].apply(context, args);
      } else {
        this.decline();
      }
    }

  }

});
<commit_msg>Remove duplication<commit_after>import Ember from 'ember';

/**
 * @module ember-dialog/mixins/context
 * @augments Ember.Mixin
 */

const { run } = Ember;

function makeArgsArray(args, obj) {
  const argsArray = Array.prototype.slice.apply(args);
  argsArray.unshift(obj);
  return argsArray;
}

export function execAction(actionName, args) {
  const context = this.context.get("contextObject");
  actionName = this.get(actionName + "Handler");
  args = makeArgsArray(args, this);
  if (context._actions && context._actions[actionName]) {
    context._actions[actionName].apply(context, args);
  } else {
    this[actionName].apply(this);
  }
}

export default Ember.Mixin.create({

  /**
   * @property {Function} accept
   * @property {Function} decline
   */
  actions: {

    accept() {
      execAction.call(this, "accept", arguments);
    },

    decline() {
      execAction.call(this, "decline", arguments);
    }

  }

});
<|endoftext|>


<commit_before>const React = require('react');

const Columns = require('../columns');
const ListHeader = require('../components/ListHeader');
const ListControl = require('../components/ListControl');

const CurrentListStore = require('../stores/CurrentListStore');

const CONTROL_COLUMN_WIDTH = 26;  // icon + padding

const ListView = React.createClass({

	displayName: 'ListView',

	getInitialState () {
		return this.getStateFromStore();
	},

	componentDidMount () {
		CurrentListStore.addChangeListener(this.updateStateFromStore);
		if (!this.state.ready) {
			CurrentListStore.loadItems();
		}
	},

	componentWillUnmount () {
		CurrentListStore.removeChangeListener(this.updateStateFromStore);
	},

	updateStateFromStore () {
		this.setState(this.getStateFromStore());
	},

	getStateFromStore () {
		return {
			list: CurrentListStore.getList(),
			ready: CurrentListStore.isReady(),
			items: CurrentListStore.getItems(),
			columns: CurrentListStore.getActiveColumns()
		};
	},

	reorderItems: function() {
		alert('TODO: Add re-ordering of items');
	},

	removeItem: function() {
		confirm('Are you sure you want to remove this item?');
	},

	renderCols: function() {
		var cols = this.state.columns.map((col) => <col width={col.width} key={col.path} />);
		// add delete col when applicable
		if (!this.state.list.nodelete) {
			cols.unshift(<col width={CONTROL_COLUMN_WIDTH} key="delete" />);
		}
		// add sort col when applicable
		if (this.state.list.sortable) {
			cols.unshift(<col width={CONTROL_COLUMN_WIDTH} key="sortable" />);
		}
		return cols;
	},

	renderHeaders: function() {
		var cells = this.state.columns.map((col, i) => {
			// span first col for controls when present
			var span = 1;
			if (!i) {
				if (Keystone.list.sortable) span++;
				if (!Keystone.list.nodelete) span++;
			}
			return {col.label}	;
		});
		return

{cells}

;
	},

	renderRow: function(item) {
		var cells = this.state.columns.map((col) => {
			var ColumnType = Columns[col.field.type] || Columns.__unrecognised__;
			return <ColumnType key={col.path} list={Keystone.list} col={col} data={item} />;
		});
		// add sortable icon when applicable
		if (Keystone.list.sortable) {
			cells.unshift(<ListControl key="_sort" onClick={this.reorderItems} type="sortable" />);
		}
		// add delete icon when applicable
		if (!Keystone.list.nodelete) {
			cells.unshift(<ListControl key="_delete" onClick={this.removeItem} type="delete" />);
		}
		return
{cells}
;
	},

	render: function() {
		if (!this.state.ready) return null;
		var sortable = Keystone.list.sortable;
		var tableClass = sortable ? 'sortable ' : '';
		tableClass += 'Table ItemList';
		return (

				<ListHeader />

							{this.renderCols()}
							{this.renderHeaders()}

								{this.state.items.results.map(this.renderRow)}

		);
	}

});

var target = document.getElementById('list-view-table');
if (target) {
	React.render(<ListView />, target);
}
<commit_msg>Missing <colgroup> fixes the column removal issue<commit_after>const React = require('react');

const Columns = require('../columns');
const ListHeader = require('../components/ListHeader');
const ListControl = require('../components/ListControl');

const CurrentListStore = require('../stores/CurrentListStore');

const CONTROL_COLUMN_WIDTH = 26;  // icon + padding

const ListView = React.createClass({

	displayName: 'ListView',

	getInitialState () {
		return this.getStateFromStore();
	},

	componentDidMount () {
		CurrentListStore.addChangeListener(this.updateStateFromStore);
		if (!this.state.ready) {
			CurrentListStore.loadItems();
		}
	},

	componentWillUnmount () {
		CurrentListStore.removeChangeListener(this.updateStateFromStore);
	},

	updateStateFromStore () {
		this.setState(this.getStateFromStore());
	},

	getStateFromStore () {
		return {
			list: CurrentListStore.getList(),
			ready: CurrentListStore.isReady(),
			items: CurrentListStore.getItems(),
			columns: CurrentListStore.getActiveColumns()
		};
	},

	reorderItems: function() {
		alert('TODO: Add re-ordering of items');
	},

	removeItem: function() {
		confirm('Are you sure you want to remove this item?');
	},

	renderCols: function() {
		var cols = this.state.columns.map((col) => <col width={col.width} key={col.path} />);
		// add delete col when applicable
		if (!this.state.list.nodelete) {
			cols.unshift(<col width={CONTROL_COLUMN_WIDTH} key="delete" />);
		}
		// add sort col when applicable
		if (this.state.list.sortable) {
			cols.unshift(<col width={CONTROL_COLUMN_WIDTH} key="sortable" />);
		}
		return <colgroup>{cols}</colgroup>;
	},

	renderHeaders: function() {
		var cells = this.state.columns.map((col, i) => {
			// span first col for controls when present
			var span = 1;
			if (!i) {
				if (Keystone.list.sortable) span++;
				if (!Keystone.list.nodelete) span++;
			}
			return {col.label}	;
		});
		return

{cells}

;
	},

	renderRow: function(item) {
		var cells = this.state.columns.map((col) => {
			var ColumnType = Columns[col.field.type] || Columns.__unrecognised__;
			return <ColumnType key={col.path} list={Keystone.list} col={col} data={item} />;
		});
		// add sortable icon when applicable
		if (Keystone.list.sortable) {
			cells.unshift(<ListControl key="_sort" onClick={this.reorderItems} type="sortable" />);
		}
		// add delete icon when applicable
		if (!Keystone.list.nodelete) {
			cells.unshift(<ListControl key="_delete" onClick={this.removeItem} type="delete" />);
		}
		return
{cells}
;
	},

	render: function() {
		if (!this.state.ready) return null;
		var sortable = Keystone.list.sortable;
		var tableClass = sortable ? 'sortable ' : '';
		tableClass += 'Table ItemList';
		return (

				<ListHeader />

							{this.renderCols()}
							{this.renderHeaders()}

								{this.state.items.results.map(this.renderRow)}

		);
	}

});

var target = document.getElementById('list-view-table');
if (target) {
	React.render(<ListView />, target);
}
<|endoftext|>


<commit_before>(function(window, angular, undefined) {
    'use strict';
    angular.module("restOffline", [
        "uuid",
        "LocalForageModule"
    ]);
})(window, window.angular);
(function(window, angular, undefined) {
    'use strict';
    angular.module("restOffline")
        .provider("OfflineService", function() {
            var config = {
                apiUrl: "/api/",
                apis: {},
            };

            this.setApis = function(apis) {
                apis.forEach(function(api) {
                    config.apis[api.ressource] = {
                        finder: api.finder || function(collection, id)  {
                            var res = false;
                            collection.some(function(e) {
                                if (e.id === id) {
                                    res = e;
                                    return true;
                                }
                                return false;
                            });
                            return res;
                        }
                    };
                });
            };

            this.setApiUrl = function(url) {
                config.apiUrl = url;
            };
            this.$get = function($localForage, $q, rfc4122, $rootScope) {
                var responsePromises = {};

                /**
                    décoder l'url pour récupérer la variable ressourceKey pour sauvegarder en localStorage
                    et uuid qui est le deuxième
                    Format api accepté
                    {{config.apiUrl}}/ressourcekey
                    {{config.apiUrl}}/ressourcekey/id
                */
                var getParamsForApiUrl = function(url) {
                    if (url.indexOf(config.apiUrl) !== 0) {
                        return false;
                    }

                    //ref astuce : https://gist.github.com/jlong/2428561
                    var parser = document.createElement("a");
                    parser.href = url;
                    var paramUrl = parser.pathname.slice(config.apiUrl.length).split('/');

                    if (!config.apis[paramUrl[0]] || paramUrl.length > 2) {
                        //On ne gère pas le cas des sous requetes pour le moment
                        return false;
                    }

                    return {
                        "ressourceKey": paramUrl[0],
                        "id": paramUrl[1] || false
                    };
                };

                var addHistoryRequest = function(requestConfig) {
                    if (!requestConfig.headers.requestUuid) {
                        //on rajoute un requestUuid pour repérer quel requete il faudra supprimer du historyRequest
                        requestConfig.headers.requestUuid = rfc4122.v4();
                    }
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        })
                        .then(function(historyRequest) {
                            //On n'ajoute pas 2 fois la même requête, dans le cas où on les rejoue

                            if (!historyRequest.some(function(e) {
                                return e.uuid === requestConfig.headers.requestUuid;
                            })) {
                                historyRequest.push({
                                    "uuid": requestConfig.headers.requestUuid,
                                    "url": requestConfig.url,
                                    "method": requestConfig.method,
                                    "data": requestConfig.data
                                });
                                return $localForage.setItem("historyRequest", historyRequest)
                                    .then(function() {
                                        //on prévient le reste du monde qu'il y a un besoin de synchro à faire
                                        // MAIS cela ne veut pas dire que l'on est déconnecté
                                        $rootScope.$broadcast("OfflineService:needSync", true);
                                        return requestConfig;
                                    });
                            }
                            return requestConfig;
                        });
                };

                var getHistoryRequest = function(requestUuid) {
                    if (!requestUuid) {
                        return;
                    }
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        })
                        .then(function(historyRequest) {
                            return historyRequest.filter(function(e) {
                                return e.uuid === requestUuid;
                            });

                        });
                };

                var removeHistoryRequest = function(requestUuid) {
                    if (!requestUuid) {
                        return;
                    }
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        })
                        .then(function(historyRequest) {
                            var oldLength = historyRequest.length;
                            historyRequest = historyRequest.filter(function(e) {
                                return e.uuid !== requestUuid;
                            });

                            if (oldLength === historyRequest.length) {
                                return historyRequest;
                            }

                            return $localForage.setItem("historyRequest", historyRequest)
                                .then(function() {
                                    if (!historyRequest.length) {
                                        //historique à vide, cela signifie que l'on a plus rien à synchroniser
                                        $rootScope.$broadcast("OfflineService:needSync", false);
                                    }
                                    return historyRequest;
                                });
                        });
                };

                var getDataFromLocalStorage = function(paramsUrl) {
                    if (paramsUrl.id) {
                        return $localForage.getItem(paramsUrl.ressourceKey)
                            .then(function(ressourceValue) {
                                var obj = config.apis[paramsUrl.ressourceKey].finder(ressourceValue, paramsUrl.id);
                                if (obj) {
                                    return obj;
                                } else {
                                    //La ressource n'a pas été trouvé car elle n'a pas été chargé précedémment quand on était online
                                    return $q.reject();
                                }
                            });
                    }

                    return $localForage.getItem(paramsUrl.ressourceKey);
                };

                var saveDataToLocalStorage = function(paramsUrl, data) {
                    if (paramsUrl.id) { //url du type /api/ressourcekey/uuid
                        return $localForage.getItem(paramsUrl.ressourceKey)
                            .then(function(ressourceValue) {
                                ressourceValue = ressourceValue || [];
                                var obj = config.apis[paramsUrl.ressourceKey].finder(ressourceValue, paramsUrl.id);
                                if (obj) {
                                    for (var i in data)  {
                                        obj[i] = data[i];
                                    }
                                } else {
                                    ressourceValue.push(obj);
                                }
                                return $localForage.setItem(paramsUrl.ressourceKey, ressourceValue);
                            });
                    }

                    return $localForage.setItem(paramsUrl.ressourceKey, data);
                };

                this.getDataFromRecentPromises = function(response) {
                    var requestUuid = response.config.headers.requestUuid;
                    if (responsePromises[requestUuid]) {
                        response.data = responsePromises[requestUuid]
                            .then(function(data) {
                                return data;
                            });

                        return response;
                    }
                    return response;
                };

                return {
                    response: function(response) {
                        var paramsForApiUrl = getParamsForApiUrl(response.config.url);
                        if (!paramsForApiUrl) {
                            return response;
                        }

                        //Traitement d'une URL de type API

                        if (response.config.method === 'GET') {
                            saveDataToLocalStorage(paramsForApiUrl, response.data);
                        } else {
                            //POST PUT et DELETE
                            removeHistoryRequest(response.config.headers.requestUuid);
                        }

                        return response;
                    },
                    responseError: function(response) {
                        // si statut == 0 cela signifie que l'on est sur un manifest fallback
                        if (getParamsForApiUrl(config.url) && !response.status) {

                            //dans le cas normal, hors syncUp,
                            if (response.config.method === 'GET') {
                                response.data = getDataFromLocalStorage(paramsForApiUrl);
                            } else {
                                response.data = getDataFromRecentPromises(response);
                            }
                        }
                        return $q.reject(response);
                    },
                    request: function(config) {
                        var paramsForApiUrl = getParamsForApiUrl(config.url);
                        if (!paramsForApiUrl ||  config.method === 'GET' || config.headers.requestUuid) {
                            //sort si on est dans le cas d'une methode GET ou la requete a déjà été enregistré (donc il existe déjà un requestUuid)
                            return config;
                        }

                        return addHistoryRequest(config)
                            .then(function(config) {
                                switch (config.method) {
                                    case 'POST':
                                        responsePromises[config.headers.requestUuid] = $localForage.getItem(paramsForApiUrl.ressourceKey)
                                            .then(function(ressourceValue) {
                                                ressourceValue.push(config.data);

                                                $localForage.setItem(paramsForApiUrl.ressourceKey, ressourceValue);
                                                return config.data;
                                            });
                                        break;
                                    case 'PUT':
                                        //TODO
                                        break;
                                    case 'DELETE':
                                        //TODO
                                        break;
                                }
                                return config;
                            });
                    }
                };
            };
        });
})(window, window.angular);
(function(window, angular, undefined) {
    'use strict';
    angular.module("restOffline")
        .factory("OfflineSyncUpService", function($localForage, $http, $q) {
            /**
            Second service pour éviter une dépendance cyclique avec $http
            */
            return {
                syncUp: function() {

                    var OfflineSyncUpService = this;
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        }).then(function(historyRequest) {
                            if (!historyRequest.length) {
                                return;
                            }
                            var request = historyRequest[0];
                            return $http({
                                method: request.method,
                                url: request.url,
                                data: request.data,
                                headers: {
                                    requestUuid: request.uuid
                                }
                            }).then(function() {
                                return OfflineSyncUpService.syncUp();
                            });
                        });
                }
            };
        });
})(window, window.angular);<commit_msg>built dist file<commit_after>(function(window, angular, undefined) {
    'use strict';
    angular.module("restOffline", [
        "uuid",
        "LocalForageModule"
    ]);
})(window, window.angular);
(function(window, angular, undefined) {
    'use strict';
    angular.module("restOffline")
        .provider("OfflineService", function() {
            var config = {
                apiUrl: "/api/",
                apis: {}
            };

            this.setApis = function(apis) {
                apis.forEach(function(api) {
                    config.apis[api.ressource] = {
                        finder: api.finder || function(collection, id) {
                            var res = false;
                            collection.some(function(e) {
                                if (e.id === id) {
                                    res = e;
                                    return true;
                                }
                                return false;
                            });
                            return res;
                        }
                    };
                });
            };

            this.setApiUrl = function(url) {
                config.apiUrl = url;
            };
            this.$get = function($localForage, $q, rfc4122, $rootScope) {
                var responsePromises = {};

                /**
                    décoder l'url pour récupérer la variable ressourceKey pour sauvegarder en localStorage
                    et uuid qui est le deuxième
                    Format api accepté
                    {{config.apiUrl}}/ressourcekey
                    {{config.apiUrl}}/ressourcekey/id
                */
                var getParamsForApiUrl = function(url) {
                    if (url.indexOf(config.apiUrl) !== 0) {
                        return false;
                    }

                    //ref astuce : https://gist.github.com/jlong/2428561
                    var parser = document.createElement("a");
                    parser.href = url;
                    var paramUrl = parser.pathname.slice(config.apiUrl.length).split('/');

                    if (!config.apis[paramUrl[0]] || paramUrl.length > 2) {
                        //On ne gère pas le cas des sous requetes pour le moment
                        return false;
                    }

                    return {
                        "ressourceKey": paramUrl[0],
                        "id": paramUrl[1] || false
                    };
                };

                var addHistoryRequest = function(requestConfig) {
                    if (!requestConfig.headers.requestUuid) {
                        //on rajoute un requestUuid pour repérer quel requete il faudra supprimer du historyRequest
                        requestConfig.headers.requestUuid = rfc4122.v4();
                    }
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        })
                        .then(function(historyRequest) {
                            //On n'ajoute pas 2 fois la même requête, dans le cas où on les rejoue

                            if (!historyRequest.some(function(e) {
                                return e.uuid === requestConfig.headers.requestUuid;
                            })) {
                                historyRequest.push({
                                    "uuid": requestConfig.headers.requestUuid,
                                    "url": requestConfig.url,
                                    "method": requestConfig.method,
                                    "data": requestConfig.data
                                });
                                return $localForage.setItem("historyRequest", historyRequest)
                                    .then(function() {
                                        //on prévient le reste du monde qu'il y a un besoin de synchro à faire
                                        // MAIS cela ne veut pas dire que l'on est déconnecté
                                        $rootScope.$broadcast("OfflineService:needSync", true);
                                        return requestConfig;
                                    });
                            }
                            return requestConfig;
                        });
                };

                var getHistoryRequest = function(requestUuid) {
                    if (!requestUuid) {
                        return;
                    }
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        })
                        .then(function(historyRequest) {
                            return historyRequest.filter(function(e) {
                                return e.uuid === requestUuid;
                            });

                        });
                };

                var removeHistoryRequest = function(requestUuid) {
                    if (!requestUuid) {
                        return;
                    }
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        })
                        .then(function(historyRequest) {
                            var oldLength = historyRequest.length;
                            historyRequest = historyRequest.filter(function(e) {
                                return e.uuid !== requestUuid;
                            });

                            if (oldLength === historyRequest.length) {
                                return historyRequest;
                            }

                            return $localForage.setItem("historyRequest", historyRequest)
                                .then(function() {
                                    if (!historyRequest.length) {
                                        //historique à vide, cela signifie que l'on a plus rien à synchroniser
                                        $rootScope.$broadcast("OfflineService:needSync", false);
                                    }
                                    return historyRequest;
                                });
                        });
                };

                var getDataFromLocalStorage = function(paramsUrl) {
                    if (paramsUrl.id) {
                        return $localForage.getItem(paramsUrl.ressourceKey)
                            .then(function(ressourceValue) {
                                var obj = config.apis[paramsUrl.ressourceKey].finder(ressourceValue, paramsUrl.id);
                                if (obj) {
                                    return obj;
                                } else {
                                    //La ressource n'a pas été trouvé car elle n'a pas été chargé précedémment quand on était online
                                    return $q.reject();
                                }
                            });
                    }

                    return $localForage.getItem(paramsUrl.ressourceKey);
                };

                var saveDataToLocalStorage = function(paramsUrl, data) {
                    if (paramsUrl.id) { //url du type /api/ressourcekey/uuid
                        return $localForage.getItem(paramsUrl.ressourceKey)
                            .then(function(ressourceValue) {
                                ressourceValue = ressourceValue || [];
                                var obj = config.apis[paramsUrl.ressourceKey].finder(ressourceValue, paramsUrl.id);
                                if (obj) {
                                    for (var i in data) {
                                        obj[i] = data[i];
                                    }
                                } else {
                                    ressourceValue.push(obj);
                                }
                                return $localForage.setItem(paramsUrl.ressourceKey, ressourceValue);
                            });
                    }

                    return $localForage.setItem(paramsUrl.ressourceKey, data);
                };

                this.getDataFromRecentPromises = function(response) {
                    var requestUuid = response.config.headers.requestUuid;
                    if (responsePromises[requestUuid]) {
                        response.data = responsePromises[requestUuid]
                            .then(function(data) {
                                return data;
                            });

                        return response;
                    }
                    return response;
                };

                return {
                    response: function(response) {
                        var paramsForApiUrl = getParamsForApiUrl(response.config.url);
                        if (!paramsForApiUrl) {
                            return response;
                        }

                        //Traitement d'une URL de type API

                        if (response.config.method === 'GET') {
                            saveDataToLocalStorage(paramsForApiUrl, response.data);
                        } else {
                            //POST PUT et DELETE
                            removeHistoryRequest(response.config.headers.requestUuid);
                        }

                        return response;
                    },
                    responseError: function(response) {
                        // si statut == 0 cela signifie que l'on est sur un manifest fallback
                        if (getParamsForApiUrl(config.url) && !response.status) {

                            //dans le cas normal, hors syncUp,
                            if (response.config.method === 'GET') {
                                response.data = getDataFromLocalStorage(paramsForApiUrl);
                            } else {
                                response.data = getDataFromRecentPromises(response);
                            }
                        }
                        return $q.reject(response);
                    },
                    request: function(config) {
                        var paramsForApiUrl = getParamsForApiUrl(config.url);
                        if (!paramsForApiUrl || config.method === 'GET' || config.headers.requestUuid) {
                            //sort si on est dans le cas d'une methode GET ou la requete a déjà été enregistré (donc il existe déjà un requestUuid)
                            return config;
                        }

                        return addHistoryRequest(config)
                            .then(function(config) {
                                switch (config.method) {
                                    case 'POST':
                                        responsePromises[config.headers.requestUuid] = $localForage.getItem(paramsForApiUrl.ressourceKey)
                                            .then(function(ressourceValue) {
                                                ressourceValue.push(config.data);

                                                $localForage.setItem(paramsForApiUrl.ressourceKey, ressourceValue);
                                                return config.data;
                                            });
                                        break;
                                    case 'PUT':
                                        //TODO
                                        break;
                                    case 'DELETE':
                                        //TODO
                                        break;
                                }
                                return config;
                            });
                    }
                };
            };
        });
})(window, window.angular);

(function(window, angular, undefined) {
    'use strict';
    angular.module("restOffline")
        .factory("OfflineSyncUpService", function($localForage, $http) {
            /**
            Second service pour éviter une dépendance cyclique avec $http
            */
            return {
                syncUp: function() {

                    var OfflineSyncUpService = this;
                    return $localForage.getItem("historyRequest")
                        .then(function(historyRequest) {
                            return historyRequest || [];
                        }).then(function(historyRequest) {
                            if (!historyRequest.length) {
                                return;
                            }
                            var request = historyRequest[0];
                            return $http({
                                method: request.method,
                                url: request.url,
                                data: request.data,
                                headers: {
                                    requestUuid: request.uuid
                                }
                            }).then(function() {
                                return OfflineSyncUpService.syncUp();
                            });
                        });
                }
            };
        });
})(window, window.angular);
<|endoftext|>


<commit_before>/*
	@license Angular Snackbar version 1.0.0
	ⓒ 2015 AHN JAE-HA http://github.com/eu81273/angular.snackbar
	License: MIT
*/

(function(a){var b=a.module("angular.snackbar",[]);b.factory("snackbar",["$rootScope",function(a){return{create:function(e,d){a.$broadcast("createSnackbar",{message:e,timeout:d})}}}]);b.directive("snackbar",["$rootScope","$compile","$timeout",function(b,e,d){var f=3E3,g=200;return function(k,l,c){f=c.snackbarDuration||3E3;g=c.snackbarRemoveDelay||200;b.$on("createSnackbar",function(b,c){var h=e('
'+c.message+"
")(k);a.element(l).append(h);
d(function(){return a.element(h).removeClass("snackbar-opened")},c.timeout||f).then(function(a){d(function(){a.remove()},g)})})}}])})(angular);<commit_msg>reduce extra digest loops when hide<commit_after>/*
	@license Angular Snackbar version 1.0.0
	ⓒ 2015 AHN JAE-HA http://github.com/eu81273/angular.snackbar
	License: MIT
*/

(function(a){var b=a.module("angular.snackbar",[]);b.factory("snackbar",["$rootScope",function(a){return{create:function(e,d){a.$broadcast("createSnackbar",{message:e,timeout:d})}}}]);b.directive("snackbar",["$rootScope","$compile","$timeout",function(b,e,d){var f=3E3,g=200;return function(k,l,c){f=c.snackbarDuration||3E3;g=c.snackbarRemoveDelay||200;b.$on("createSnackbar",function(b,c){var h=e('
'+c.message+"
")(k);a.element(l).append(h);
d(function(){return a.element(h).removeClass("snackbar-opened")},c.timeout||f,!1).then(function(a){d(function(){a.remove()},g,!1)})})}}])})(angular);
<|endoftext|>


<commit_before>var gulp = require('gulp');
var ts = require('gulp-typescript');
var sourcemaps = require('gulp-sourcemaps');
var cache = require('gulp-cache');
var imagemin = require('gulp-imagemin');
var less = require('gulp-less');
var preprocess = require('gulp-preprocess');
var merge = require('merge-stream');

var tsOptions = {
    target: "es5",
    module: "none",
    noImplicitAny: true,
    removeComments: false,
    preserveConstEnums: true,
    strictNullChecks: true,
};

gulp.task('scripts', function() {
    return gulp.src('src/**/*.ts')
        .pipe(sourcemaps.init())
        .pipe(ts(tsOptions))
        .pipe(sourcemaps.write('maps', { includeContent:  false,  sourceRoot: "file:///" + __dirname + '/src' }))
        .pipe(gulp.dest('build/chrome'))
        .pipe(gulp.dest('build/edge'));
});

gulp.task('styles', function() {
    return gulp.src('src/**/*.less')
        .pipe(sourcemaps.init())
        .pipe(less())
        .pipe(sourcemaps.write('maps', { includeContent:  false,  sourceRoot: "file:///" + __dirname + '/src' }))
        .pipe(gulp.dest('build/edge'))
        .pipe(gulp.dest('build/chrome'));
});

gulp.task('images', function() {
    return gulp.src('src/**/*.png')
        .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))
        .pipe(gulp.dest('build/edge'))
        .pipe(gulp.dest('build/chrome'));
});

gulp.task('pages', function() {
    var edge = gulp.src('src/**/*.html')
        .pipe(preprocess({ context:  {  BROWSER: 'Edge' } }))
        .pipe(gulp.dest('build/edge'));

    var chrome = gulp.src('src/**/*.html')
        .pipe(preprocess({ context:  {  BROWSER: 'Chrome' } }))
        .pipe(gulp.dest('build/chrome'));

    return merge(edge, chrome);
});

gulp.task('extras', function() {
    var edge = gulp.src('src/extras/edge/**/*')
        .pipe(gulp.dest('build/edge'));

    var chrome = gulp.src('src/extras/chrome/**/*')
        .pipe(gulp.dest('build/chrome'));

    return merge(edge, chrome);
});

gulp.task('libs', function() {
    return gulp.src('src/lib/**/*')
        .pipe(gulp.dest('build/edge/lib'))
        .pipe(gulp.dest('build/chrome/lib'));
});

gulp.task('json', function() {
    var edge = gulp.src('src/**/*.json')
        .pipe(preprocess({ context:  {  BROWSER: 'Edge' }, extension: 'js' }))
        .pipe(gulp.dest('build/edge'));

    var chrome = gulp.src('src/**/*.json')
        .pipe(preprocess({ context:  {  BROWSER: 'Chrome' }, extension: 'js' }))
        .pipe(gulp.dest('build/chrome'));

    return merge(edge, chrome);
});

gulp.task('watch', ['default'], function() {
    gulp.watch('src/**/*.ts', ['scripts']);
    gulp.watch('src/**/*.less', ['styles']);
    gulp.watch('src/**/*.png', ['images']);
    gulp.watch('src/**/*.html', ['pages']);
    gulp.watch('src/**/*.json', ['json']);
    gulp.watch('src/extras/**/*', ['extras']);
    gulp.watch('src/lib/**/*', ['libs']);
});

gulp.task('default', ['scripts', 'styles', 'images', 'pages', 'json', 'extras', 'libs']);<commit_msg>Changing source map generation<commit_after>var gulp = require('gulp');
var ts = require('gulp-typescript');
var sourcemaps = require('gulp-sourcemaps');
var cache = require('gulp-cache');
var imagemin = require('gulp-imagemin');
var less = require('gulp-less');
var preprocess = require('gulp-preprocess');
var merge = require('merge-stream');

var tsOptions = {
    target: "es5",
    module: "none",
    noImplicitAny: true,
    removeComments: false,
    preserveConstEnums: true,
    strictNullChecks: true,
};

gulp.task('scripts', function() {
    return gulp.src('src/**/*.ts')
        .pipe(sourcemaps.init())
        .pipe(ts(tsOptions))
        .pipe(sourcemaps.write('maps'))
        .pipe(gulp.dest('build/chrome'))
        .pipe(gulp.dest('build/edge'));
});

gulp.task('styles', function() {
    return gulp.src('src/**/*.less')
        .pipe(sourcemaps.init())
        .pipe(less())
        .pipe(sourcemaps.write('maps'))
        .pipe(gulp.dest('build/edge'))
        .pipe(gulp.dest('build/chrome'));
});

gulp.task('images', function() {
    return gulp.src('src/**/*.png')
        .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))
        .pipe(gulp.dest('build/edge'))
        .pipe(gulp.dest('build/chrome'));
});

gulp.task('pages', function() {
    var edge = gulp.src('src/**/*.html')
        .pipe(preprocess({ context:  {  BROWSER: 'Edge' } }))
        .pipe(gulp.dest('build/edge'));

    var chrome = gulp.src('src/**/*.html')
        .pipe(preprocess({ context:  {  BROWSER: 'Chrome' } }))
        .pipe(gulp.dest('build/chrome'));

    return merge(edge, chrome);
});

gulp.task('extras', function() {
    var edge = gulp.src('src/extras/edge/**/*')
        .pipe(gulp.dest('build/edge'));

    var chrome = gulp.src('src/extras/chrome/**/*')
        .pipe(gulp.dest('build/chrome'));

    return merge(edge, chrome);
});

gulp.task('libs', function() {
    return gulp.src('src/lib/**/*')
        .pipe(gulp.dest('build/edge/lib'))
        .pipe(gulp.dest('build/chrome/lib'));
});

gulp.task('json', function() {
    var edge = gulp.src('src/**/*.json')
        .pipe(preprocess({ context:  {  BROWSER: 'Edge' }, extension: 'js' }))
        .pipe(gulp.dest('build/edge'));

    var chrome = gulp.src('src/**/*.json')
        .pipe(preprocess({ context:  {  BROWSER: 'Chrome' }, extension: 'js' }))
        .pipe(gulp.dest('build/chrome'));

    return merge(edge, chrome);
});

gulp.task('watch', ['default'], function() {
    gulp.watch('src/**/*.ts', ['scripts']);
    gulp.watch('src/**/*.less', ['styles']);
    gulp.watch('src/**/*.png', ['images']);
    gulp.watch('src/**/*.html', ['pages']);
    gulp.watch('src/**/*.json', ['json']);
    gulp.watch('src/extras/**/*', ['extras']);
    gulp.watch('src/lib/**/*', ['libs']);
});

gulp.task('default', ['scripts', 'styles', 'images', 'pages', 'json', 'extras', 'libs']);<|endoftext|>