<commit_before>var config = require('../config');
var mongo = require('mongoskin');
var params = require("../node_modules/swagger-node-express/lib/paramTypes");
var errorHandling = require('../node_modules/swagger-node-express/lib/errorHandling').error;
var async = require('async');
var BSON = mongo.BSONPure;

var io = require('socket.io-client')(config.routes.api);
var channel = '/subsystem'
var emit = function(data) {
  io.emit(channel, data);
}
emit({title: 'connect'});
//GET
exports.getAll = {
  'spec': {
    "description" : "Operations about subsystems",
    "path" : "/subsystems/all",
    "notes" : "Returns all subsystems",
    "summary" : "Fetch all subsystems",
    "method": "GET",
    "nickname" : "getAllSubsystem"
  },
  'action': function (req,res) {
    console.log(req.db);
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});
    db.collection('subsystemcollection').find().toArray(function (err, items) {
      if (items!=[]) {
        res.json(items);
      } else {
        res.send(errorHandling.error(404, 'not found'));
      }
    });
  }
};

exports.getOneById = {
  'spec': {
    "path" : "/subsystems/id/{subsystem_id}",
    "notes" : "Returns one subsystem",
    "summary" : "Returns one subsystem by ID",
    "method": "GET",
    "parameters" : [
      params.path("subsystem_id", "subsystem ID to get", "string")
      ],
    "nickname" : "getOneByIdSubsystem"
  },
  'action': function (req,res) {
    var home_id = req.params.subsystem_id || req.query.subsystem_id;
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});
    var homeRes;
    async.series([
      function (callback) {
      // check if string is ObjectID
        if (/^[0-9a-f]{24}$/.test(subsystem_id)) {
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
        db.collection('subsystemcollection').find({_id:BSON.ObjectID(subsystem_id)}).toArray(function (err, items) {
          if (!err) {
            subsystemRes = items;
            callback(null);
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
        if (subsystemRes.length <= 0) {
          callback(404);
        } else {
          if (subsystemRes.length > 1) {
            callback(400);
          } else {
            callback(null);
          }
        }
      }
    ],
    // optional callback
    function (err, results) {
      // io.emit('getone',{content: 'get one by id called', timestamp: Date.now()});

      if (err) {
        switch(err) {
          case 400:
            message = errorHandling(err, "Bad request.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          case 404:
            message = errorHandling(err, "Not found.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          default:
            message = errorHandling(err, "Unknown error.");
            res.status(500).send(JSON.stringify(message, null, 3));
            break;
        }
      } else {
        // io.emit('getonecall', { content: 'get one by id called.', timestamp: Date.now(), home_id: homeRes[0]._id});
        res.status(200).send(JSON.stringify(homeRes[0], null, 3));
      }
    });
  }
};

//GET
exports.changeState = {
  'spec': {
    "description" : "Operations about subsystems",
    "path" : "/subsystems/state",
    "notes" : "changeState",
    "summary" : "changeState",
    "method": "GET",
    "nickname" : "changeStateSubsystem"
  },
  'action': function (req,res) {
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});
    db.collection('subsystemcollection').find().toArray(function (err, items) {
      if (items!=[]) {
        emit({title: 'changeState', ip: req.ip, cookies: req.cookies, timestamp: Date.now()});
        //console.log(req.ip);
        res.json(items);
      } else {
        res.send(errorHandling.error(404, 'not found'));
      }
    });
  }
};
//PUT

//POST
exports.addOne = {
  'spec': {
    "path" : "/subsystems/add",
    "notes" : "Add one subsystem",
    "summary" : "Add one subsystem",
    "method": "POST",
    "parameters" : [
      params.query("name", "name of NEW subsystem", "string", true),
      params.query("interface", "interface of NEW subsystem", "string", true),
      params.query("system_id", "system ID of NEW subsystem", "string", true)
      ],
    "responseClass": "",
    "errorResponses": [],
    "nickname" : "addOneSubsystem"
  },
  'action': function (req,res) {
    var newName = req.query.name || req.body.name || '';
    var newInterface = req.query.interface || req.body.interface || '';
    var newSystemID = req.query.system_id || req.body.system_id || '';
    var subsystemToAdd;
    var systemRes;
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});

    async.series([
      function (callback) {
      // check if string is ObjectID
        if (/^[0-9A-Fa-f]{24}$/.test(newSystemID)) {
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
        db.collection('systemcollection').find({_id:BSON.ObjectID(newSystemID)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            systemRes = items;
            console.log(systemRes);
            if (systemRes.length <= 0) {
              callback(404);
            } else {
              if (systemRes.length > 1) {
                callback(400);
              } else {
                //only 1 system found
                callback(null);
              }
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
        if (newName!=null && newName!=null) {
          subsystemToAdd = {
            "identity": {
              "name": newName
            },
            "interface": newInterface,
            "system_id": systemRes[0]._id,
            "system_identity": systemRes[0].identity,
            "state": {},
            "desired_state": {},
            "created": Date.now(),
            "updated": Date.now()
          }
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
      //INCEPTION
        db.collection('subsystemcollection').insert(subsystemToAdd, function(err, result) {
          if (!err) {
            db.collection('systemcollection').update({_id:BSON.ObjectID(newSystemID)}, {$push: {subsystems: {subsystem_id: result[0]._id, subsystem_name:result[0].identity.name}}, $set: {updated: Date.now()}}, function (err) {
              if (!err) {
                callback(null);
              } else {
                callback(400);
              }
            });
          } else {
            callback(400);
          }
        });
      }
    ],
    // optional callback
    function (err, results) {
      if (err) {
        switch(err) {
          case 400:
            res.status(err).send(errorHandling(err, "Bad request."));
            break;
          case 404:
            res.status(err).send(errorHandling(err, "Not found."));
            break;
          default:
            res.status(500).send(JSON.stringify("Unknown error."));
            break;
        }
      } else {
        res.status(200).send(JSON.stringify("OK"));
      }
    });
  }
};

//DELETE
exports.deleteOneById = {
  'spec': {
    "path" : "/subsystems/id/{subsystem_id}",
    "notes" : "Deletes one subsystem",
    "summary" : "Deletes one subsystem by ID",
    "method": "DELETE",
    "parameters" : [
      params.path("subsystem_id", "subsystem ID to delete", "string"),
      params.query("owner_id", "owner ID of subsystem", "string", true)
      ],
    "nickname" : "deleteOneByIdSubsystem"
  },
  'action': function (req,res) {
    var subsystem_id = req.params.subsystem_id || req.query.subsystem_id;
    var owner_id = req.params.owner_id || req.query.owner_id;
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});

    var system_id;
    var subsystemRes;
    var systemRes;
    var homeRes;
    var userRes;
    var subsystemsArray;

    async.series([
      function (callback) {
      // check if string is ObjectID
      console.log('1.ObjectID Testing');
        if (/^[0-9a-f]{24}$/.test(subsystem_id) && /^[0-9a-f]{24}$/.test(owner_id)) {
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
      console.log('2.Fetching User');
        db.collection('usercollection').find({_id:BSON.ObjectID(owner_id)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            userRes = items;
            console.log(userRes);
            if (userRes.length<=0) {
              callback(404);
            } else if (userRes.length > 1) {
              callback(400);
            } else {
              callback(null);
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
      console.log('3.Fetching Subsystem');
        db.collection('subsystemcollection').find({_id:BSON.ObjectID(subsystem_id)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            subsystemRes = items;
            console.log(subsystemRes);
            if (subsystemRes.length<=0) {
              callback(404);
            } else if (subsystemRes.length > 1) {
              callback(400);
            } else {
              system_id = subsystemRes[0].system_id;
              callback(null);
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
      console.log('3.Fetching System');
        db.collection('systemcollection').find({_id:BSON.ObjectID(system_id)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            systemRes = items;
            console.log(systemRes);
            if (systemRes.length<=0) {
              callback(404);
            } else if (systemRes.length > 1) {
              callback(400);
            } else {
              callback(null);
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
      console.log('4.Testing Home');
        if (userRes[0].homes.length <= 0) {
          callback(404);
        } else {
          console.log(userRes[0].homes);
          for (var i = 0; i < userRes[0].homes.length; i++) {
            if (String(userRes[0].homes[i].home_id) == String(systemRes[0].home_id)) {
              console.log('same');
              callback(null);
            } else if (i >= userRes[0].homes.length) {
              callback(404);
            }
          }
        }
      },
      function (callback) {
      console.log('6.Splicing System');
        if (systemRes[0].subsystems.length <= 0) {
          callback(404);
        } else {
          for (var i = 0; i < systemRes[0].subsystems.length; i++) {
            if (systemRes[0].subsystems[i].subsystem_id == subsystem_id) {
              systemRes[0].subsystems.splice(i,1);
              subsystemsArray = systemRes[0].subsystems;
              console.log(subsystemsArray);
              callback(null);
            } else if (i >= systemRes[0].subsystems.length) {
              callback(404);
            }
          }
        }
      },
      function (callback) {
      console.log('7.System Removal');
        db.collection('subsystemcollection').remove({_id:BSON.ObjectID(subsystem_id)}, function (err, items) {
          if (!err) {
            db.collection('systemcollection').update({_id:BSON.ObjectID(system_id)}, {$set: {subsystems: subsystemsArray, updated:Date.now()}}, function (err) {
              if (!err) {
                callback(null);
              } else {
                callback(400);
              }
            });
          } else {
            callback(400);
          }
        });
      }

    ],
    // optional callback
    function (err, results) {
      if (err) {
        switch(err) {
          case 400:
            message = errorHandling(err, "Bad request.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          case 404:
            message = errorHandling(err, "Not found.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          default:
            message = errorHandling(err, "Unknown error.");
            res.status(500).send(JSON.stringify(message, null, 3));
            break;
        }
      } else {
        res.status(200).send(JSON.stringify("Subsystem has been successfully deleted.", null, 3));
      }
    });
  }
};
<commit_msg>add headers to request<commit_after>var config = require('../config');
var mongo = require('mongoskin');
var params = require("../node_modules/swagger-node-express/lib/paramTypes");
var errorHandling = require('../node_modules/swagger-node-express/lib/errorHandling').error;
var async = require('async');
var BSON = mongo.BSONPure;

var io = require('socket.io-client')(config.routes.api);
var channel = '/subsystem'
var emit = function(data) {
  io.emit(channel, data);
}
emit({title: 'connect'});
//GET
exports.getAll = {
  'spec': {
    "description" : "Operations about subsystems",
    "path" : "/subsystems/all",
    "notes" : "Returns all subsystems",
    "summary" : "Fetch all subsystems",
    "method": "GET",
    "nickname" : "getAllSubsystem"
  },
  'action': function (req,res) {
    console.log(req.db);
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});
    db.collection('subsystemcollection').find().toArray(function (err, items) {
      if (items!=[]) {
        res.json(items);
      } else {
        res.send(errorHandling.error(404, 'not found'));
      }
    });
  }
};

exports.getOneById = {
  'spec': {
    "path" : "/subsystems/id/{subsystem_id}",
    "notes" : "Returns one subsystem",
    "summary" : "Returns one subsystem by ID",
    "method": "GET",
    "parameters" : [
      params.path("subsystem_id", "subsystem ID to get", "string")
      ],
    "nickname" : "getOneByIdSubsystem"
  },
  'action': function (req,res) {
    var home_id = req.params.subsystem_id || req.query.subsystem_id;
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});
    var homeRes;
    async.series([
      function (callback) {
      // check if string is ObjectID
        if (/^[0-9a-f]{24}$/.test(subsystem_id)) {
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
        db.collection('subsystemcollection').find({_id:BSON.ObjectID(subsystem_id)}).toArray(function (err, items) {
          if (!err) {
            subsystemRes = items;
            callback(null);
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
        if (subsystemRes.length <= 0) {
          callback(404);
        } else {
          if (subsystemRes.length > 1) {
            callback(400);
          } else {
            callback(null);
          }
        }
      }
    ],
    // optional callback
    function (err, results) {
      // io.emit('getone',{content: 'get one by id called', timestamp: Date.now()});

      if (err) {
        switch(err) {
          case 400:
            message = errorHandling(err, "Bad request.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          case 404:
            message = errorHandling(err, "Not found.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          default:
            message = errorHandling(err, "Unknown error.");
            res.status(500).send(JSON.stringify(message, null, 3));
            break;
        }
      } else {
        // io.emit('getonecall', { content: 'get one by id called.', timestamp: Date.now(), home_id: homeRes[0]._id});
        res.status(200).send(JSON.stringify(homeRes[0], null, 3));
      }
    });
  }
};

//GET
exports.changeState = {
  'spec': {
    "description" : "Operations about subsystems",
    "path" : "/subsystems/state",
    "notes" : "changeState",
    "summary" : "changeState",
    "method": "GET",
    "nickname" : "changeStateSubsystem"
  },
  'action': function (req,res) {
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});
    db.collection('subsystemcollection').find().toArray(function (err, items) {
      if (items!=[]) {
        emit({title: 'changeState', headers: req.headers, ip: req.ip, cookies: req.cookies, timestamp: Date.now()});
        //console.log(req);
        res.json(items);
      } else {
        res.send(errorHandling.error(404, 'not found'));
      }
    });
  }
};
//PUT

//POST
exports.addOne = {
  'spec': {
    "path" : "/subsystems/add",
    "notes" : "Add one subsystem",
    "summary" : "Add one subsystem",
    "method": "POST",
    "parameters" : [
      params.query("name", "name of NEW subsystem", "string", true),
      params.query("interface", "interface of NEW subsystem", "string", true),
      params.query("system_id", "system ID of NEW subsystem", "string", true)
      ],
    "responseClass": "",
    "errorResponses": [],
    "nickname" : "addOneSubsystem"
  },
  'action': function (req,res) {
    var newName = req.query.name || req.body.name || '';
    var newInterface = req.query.interface || req.body.interface || '';
    var newSystemID = req.query.system_id || req.body.system_id || '';
    var subsystemToAdd;
    var systemRes;
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});

    async.series([
      function (callback) {
      // check if string is ObjectID
        if (/^[0-9A-Fa-f]{24}$/.test(newSystemID)) {
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
        db.collection('systemcollection').find({_id:BSON.ObjectID(newSystemID)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            systemRes = items;
            console.log(systemRes);
            if (systemRes.length <= 0) {
              callback(404);
            } else {
              if (systemRes.length > 1) {
                callback(400);
              } else {
                //only 1 system found
                callback(null);
              }
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
        if (newName!=null && newName!=null) {
          subsystemToAdd = {
            "identity": {
              "name": newName
            },
            "interface": newInterface,
            "system_id": systemRes[0]._id,
            "system_identity": systemRes[0].identity,
            "state": {},
            "desired_state": {},
            "created": Date.now(),
            "updated": Date.now()
          }
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
      //INCEPTION
        db.collection('subsystemcollection').insert(subsystemToAdd, function(err, result) {
          if (!err) {
            db.collection('systemcollection').update({_id:BSON.ObjectID(newSystemID)}, {$push: {subsystems: {subsystem_id: result[0]._id, subsystem_name:result[0].identity.name}}, $set: {updated: Date.now()}}, function (err) {
              if (!err) {
                callback(null);
              } else {
                callback(400);
              }
            });
          } else {
            callback(400);
          }
        });
      }
    ],
    // optional callback
    function (err, results) {
      if (err) {
        switch(err) {
          case 400:
            res.status(err).send(errorHandling(err, "Bad request."));
            break;
          case 404:
            res.status(err).send(errorHandling(err, "Not found."));
            break;
          default:
            res.status(500).send(JSON.stringify("Unknown error."));
            break;
        }
      } else {
        res.status(200).send(JSON.stringify("OK"));
      }
    });
  }
};

//DELETE
exports.deleteOneById = {
  'spec': {
    "path" : "/subsystems/id/{subsystem_id}",
    "notes" : "Deletes one subsystem",
    "summary" : "Deletes one subsystem by ID",
    "method": "DELETE",
    "parameters" : [
      params.path("subsystem_id", "subsystem ID to delete", "string"),
      params.query("owner_id", "owner ID of subsystem", "string", true)
      ],
    "nickname" : "deleteOneByIdSubsystem"
  },
  'action': function (req,res) {
    var subsystem_id = req.params.subsystem_id || req.query.subsystem_id;
    var owner_id = req.params.owner_id || req.query.owner_id;
    var db = mongo.db("mongodb://localhost:27017/scratch-test", {native_parser:true});

    var system_id;
    var subsystemRes;
    var systemRes;
    var homeRes;
    var userRes;
    var subsystemsArray;

    async.series([
      function (callback) {
      // check if string is ObjectID
      console.log('1.ObjectID Testing');
        if (/^[0-9a-f]{24}$/.test(subsystem_id) && /^[0-9a-f]{24}$/.test(owner_id)) {
          callback(null);
        } else {
          callback(400);
        }
      },
      function (callback) {
      console.log('2.Fetching User');
        db.collection('usercollection').find({_id:BSON.ObjectID(owner_id)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            userRes = items;
            console.log(userRes);
            if (userRes.length<=0) {
              callback(404);
            } else if (userRes.length > 1) {
              callback(400);
            } else {
              callback(null);
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
      console.log('3.Fetching Subsystem');
        db.collection('subsystemcollection').find({_id:BSON.ObjectID(subsystem_id)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            subsystemRes = items;
            console.log(subsystemRes);
            if (subsystemRes.length<=0) {
              callback(404);
            } else if (subsystemRes.length > 1) {
              callback(400);
            } else {
              system_id = subsystemRes[0].system_id;
              callback(null);
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
      console.log('3.Fetching System');
        db.collection('systemcollection').find({_id:BSON.ObjectID(system_id)}).toArray(function (err, items) {
          if (!err) {
            // console.log(items);
            systemRes = items;
            console.log(systemRes);
            if (systemRes.length<=0) {
              callback(404);
            } else if (systemRes.length > 1) {
              callback(400);
            } else {
              callback(null);
            }
          } else {
            callback(400);
          }
        });
      },
      function (callback) {
      console.log('4.Testing Home');
        if (userRes[0].homes.length <= 0) {
          callback(404);
        } else {
          console.log(userRes[0].homes);
          for (var i = 0; i < userRes[0].homes.length; i++) {
            if (String(userRes[0].homes[i].home_id) == String(systemRes[0].home_id)) {
              console.log('same');
              callback(null);
            } else if (i >= userRes[0].homes.length) {
              callback(404);
            }
          }
        }
      },
      function (callback) {
      console.log('6.Splicing System');
        if (systemRes[0].subsystems.length <= 0) {
          callback(404);
        } else {
          for (var i = 0; i < systemRes[0].subsystems.length; i++) {
            if (systemRes[0].subsystems[i].subsystem_id == subsystem_id) {
              systemRes[0].subsystems.splice(i,1);
              subsystemsArray = systemRes[0].subsystems;
              console.log(subsystemsArray);
              callback(null);
            } else if (i >= systemRes[0].subsystems.length) {
              callback(404);
            }
          }
        }
      },
      function (callback) {
      console.log('7.System Removal');
        db.collection('subsystemcollection').remove({_id:BSON.ObjectID(subsystem_id)}, function (err, items) {
          if (!err) {
            db.collection('systemcollection').update({_id:BSON.ObjectID(system_id)}, {$set: {subsystems: subsystemsArray, updated:Date.now()}}, function (err) {
              if (!err) {
                callback(null);
              } else {
                callback(400);
              }
            });
          } else {
            callback(400);
          }
        });
      }

    ],
    // optional callback
    function (err, results) {
      if (err) {
        switch(err) {
          case 400:
            message = errorHandling(err, "Bad request.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          case 404:
            message = errorHandling(err, "Not found.");
            res.status(err).send(JSON.stringify(message, null, 3));
            break;
          default:
            message = errorHandling(err, "Unknown error.");
            res.status(500).send(JSON.stringify(message, null, 3));
            break;
        }
      } else {
        res.status(200).send(JSON.stringify("Subsystem has been successfully deleted.", null, 3));
      }
    });
  }
};
<|endoftext|>


<commit_before>var locastyle = locastyle || {};
locastyle.modal = (function() {
  'use strict';

  var config = {
    open: {
      trigger: '[data-ls-module="modal"]'
    },
    close: {
      classes: '.ls-modal-overlay',
      trigger: '[data-dismiss="modal"]'
    }
  }

  function init() {
    unbind();
    bindOpen();
  }

  function unbind() {
    $(config.open.trigger).off('click.ls');
    $(config.close.classes + ", " + config.close.trigger).off('click.ls');
  }

  function bindOpen() {
    $(config.open.trigger).on('click.ls', function() {
      locastyle.modal.open($(this).data());
      bindKeypress();
    });
  }

  function bindKeypress(){
    $(document).keyup(function(e) {
      if(e.keyCode == 27){
        locastyle.modal.close()
      }
    });
  }

  function bindClose(){
    $(config.close.classes + ", " + config.close.trigger).on('click.ls', function() {
      locastyle.modal.close();
    });
  }

  function open($element) {
    if (!$element.target) {
      $('body').addClass('modal-opened').append(locastyle.templates.modal($element));
    } else {
      $($element.target)
        .show()
        .addClass('opened')
        .append('

')
        .appendTo('body');
        $('body').addClass('modal-opened');
    }
    bindClose();
  }

  function close() {
    $('.ls-modal').hide().removeClass("opened");
    $(".ls-modal-overlay, .ls-modal-template").remove();
    $('body').removeClass('modal-opened');
    locastyle.popover.destroyPopover();
  }

  return {
    init: init,
    open: open,
    close: close,
    unbind: unbind
  };

}());
<commit_msg>jshint modal<commit_after>var locastyle = locastyle || {};
locastyle.modal = (function() {
  'use strict';

  var config = {
    open: {
      trigger: '[data-ls-module="modal"]'
    },
    close: {
      classes: '.ls-modal-overlay',
      trigger: '[data-dismiss="modal"]'
    }
  };

  function init() {
    unbind();
    bindOpen();
  }

  function unbind() {
    $(config.open.trigger).off('click.ls');
    $(config.close.classes + ", " + config.close.trigger).off('click.ls');
  }

  function bindOpen() {
    $(config.open.trigger).on('click.ls', function() {
      locastyle.modal.open($(this).data());
      bindKeypress();
    });
  }

  function bindKeypress(){
    $(document).keyup(function(e) {
      if(e.keyCode == 27){
        locastyle.modal.close();
      }
    });
  }

  function bindClose(){
    $(config.close.classes + ", " + config.close.trigger).on('click.ls', function() {
      locastyle.modal.close();
    });
  }

  function open($element) {
    if (!$element.target) {
      $('body').addClass('modal-opened').append(locastyle.templates.modal($element));
    } else {
      $($element.target)
        .show()
        .addClass('opened')
        .append('

')
        .appendTo('body');
        $('body').addClass('modal-opened');
    }
    bindClose();
  }

  function close() {
    $('.ls-modal').hide().removeClass("opened");
    $(".ls-modal-overlay, .ls-modal-template").remove();
    $('body').removeClass('modal-opened');
    locastyle.popover.destroyPopover();
  }

  return {
    init: init,
    open: open,
    close: close,
    unbind: unbind
  };

}());
<|endoftext|>


<commit_before>/*
 * Copyright 2014 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @constructor
 * @extends {Protocol.Agents}
 * @param {string} name
 * @param {!InspectorBackendClass.Connection} connection
 * @param {function(?WebInspector.Target)=} callback
 */
WebInspector.Target = function(name, connection, callback)
{
    Protocol.Agents.call(this, connection.agentsMap());
    this._name = name;
    this._connection = connection;
    connection.addEventListener(InspectorBackendClass.Connection.Events.Disconnected, this._onDisconnect, this);
    this._id = WebInspector.Target._nextId++;

    /** @type {!Map.<!Function, !WebInspector.SDKModel>} */
    this._modelByConstructor = new Map();

    /** @type {!Object.<string, boolean>} */
    this._capabilities = {};
    this.pageAgent().canScreencast(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanScreencast, null));
    this.pageAgent().canEmulate(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanEmulate, null));
    if (Runtime.experiments.isEnabled("timelinePowerProfiler"))
        this.powerAgent().canProfilePower(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanProfilePower, null));
    this.workerAgent().canInspectWorkers(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanInspectWorkers, this._loadedWithCapabilities.bind(this, callback)));
    this.consoleAgent().setTracingBasedTimeline(true);
}

/**
 * @enum {string}
 */
WebInspector.Target.Capabilities = {
    CanScreencast: "CanScreencast",
    HasTouchInputs: "HasTouchInputs",
    CanProfilePower: "CanProfilePower",
    CanInspectWorkers: "CanInspectWorkers",
    CanEmulate: "CanEmulate"
}

WebInspector.Target._nextId = 1;

WebInspector.Target.prototype = {
    suspend: function()
    {
        if (!Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
            this.debuggerModel.asyncStackTracesStateChanged();
            return;
        }
        this.debuggerModel.suspendModel();
        this.cssModel.suspendModel();
        this.domModel.suspendModel();
    },

    resume: function()
    {
        if (Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
            this.domModel.resumeModel();
            this.cssModel.resumeModel();
            this.debuggerModel.resumeModel();
        } else {
            this.debuggerModel.asyncStackTracesStateChanged();
        }
    },

    /**
     * @return {number}
     */
    id: function()
    {
        return this._id;
    },

    /**
     *
     * @return {string}
     */
    name: function()
    {
        return this._name;
    },

    /**
     * @param {string} name
     * @param {function()|null} callback
     * @param {?Protocol.Error} error
     * @param {boolean} result
     */
    _initializeCapability: function(name, callback, error, result)
    {
        this._capabilities[name] = result;
        if (callback)
            callback();
    },

    /**
     * @param {string} capability
     * @return {boolean}
     */
    hasCapability: function(capability)
    {
        return !!this._capabilities[capability];
    },

    /**
     * @param {function(?WebInspector.Target)=} callback
     */
    _loadedWithCapabilities: function(callback)
    {
        if (this._connection.isClosed()) {
            callback(null);
            return;
        }

        /** @type {!WebInspector.ConsoleModel} */
        this.consoleModel = new WebInspector.ConsoleModel(this);

        /** @type {!WebInspector.NetworkManager} */
        this.networkManager = new WebInspector.NetworkManager(this);

        /** @type {!WebInspector.ResourceTreeModel} */
        this.resourceTreeModel = new WebInspector.ResourceTreeModel(this);
        if (!WebInspector.resourceTreeModel)
            WebInspector.resourceTreeModel = this.resourceTreeModel;

        /** @type {!WebInspector.NetworkLog} */
        this.networkLog = new WebInspector.NetworkLog(this);
        if (!WebInspector.networkLog)
            WebInspector.networkLog = this.networkLog;

        /** @type {!WebInspector.DebuggerModel} */
        this.debuggerModel = new WebInspector.DebuggerModel(this);
        if (!WebInspector.debuggerModel)
            WebInspector.debuggerModel = this.debuggerModel;

        /** @type {!WebInspector.RuntimeModel} */
        this.runtimeModel = new WebInspector.RuntimeModel(this);
        if (!WebInspector.runtimeModel)
            WebInspector.runtimeModel = this.runtimeModel;

        /** @type {!WebInspector.DOMModel} */
        this.domModel = new WebInspector.DOMModel(this);

        /** @type {!WebInspector.CSSStyleModel} */
        this.cssModel = new WebInspector.CSSStyleModel(this);
        if (!WebInspector.cssModel)
            WebInspector.cssModel = this.cssModel;

        /** @type {!WebInspector.WorkerManager} */
        this.workerManager = new WebInspector.WorkerManager(this, this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers));
        if (!WebInspector.workerManager)
            WebInspector.workerManager = this.workerManager;

        if (this.hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
            WebInspector.powerProfiler = new WebInspector.PowerProfiler(this);

        /** @type {!WebInspector.DatabaseModel} */
        this.databaseModel = new WebInspector.DatabaseModel(this);
        if (!WebInspector.databaseModel)
            WebInspector.databaseModel = this.databaseModel;

        /** @type {!WebInspector.DOMStorageModel} */
        this.domStorageModel = new WebInspector.DOMStorageModel(this);
        if (!WebInspector.domStorageModel)
            WebInspector.domStorageModel = this.domStorageModel;

        /** @type {!WebInspector.CPUProfilerModel} */
        this.cpuProfilerModel = new WebInspector.CPUProfilerModel(this);
        if (!WebInspector.cpuProfilerModel)
            WebInspector.cpuProfilerModel = this.cpuProfilerModel;

        /** @type {!WebInspector.HeapProfilerModel} */
        this.heapProfilerModel = new WebInspector.HeapProfilerModel(this);

        /** @type {!WebInspector.IndexedDBModel} */
        this.indexedDBModel = new WebInspector.IndexedDBModel(this);

        /** @type {!WebInspector.LayerTreeModel} */
        this.layerTreeModel = new WebInspector.LayerTreeModel(this);

        /** @type {!WebInspector.AnimationModel} */
        this.animationModel = new WebInspector.AnimationModel(this);

        if (callback)
            callback(this);
    },

    /**
     * @override
     * @param {string} domain
     * @param {!Object} dispatcher
     */
    registerDispatcher: function(domain, dispatcher)
    {
        this._connection.registerDispatcher(domain, dispatcher);
    },

    /**
     * @return {boolean}
     */
    isWorkerTarget: function()
    {
        return !this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers);
    },

    /**
     * @return {boolean}
     */
    canEmulate: function()
    {
        return this.hasCapability(WebInspector.Target.Capabilities.CanEmulate);
    },

    _onDisconnect: function()
    {
        WebInspector.targetManager.removeTarget(this);
        this._dispose();
    },

    _dispose: function()
    {
        this.debuggerModel.dispose();
        this.networkManager.dispose();
        this.cpuProfilerModel.dispose();
    },

    /**
     * @return {boolean}
     */
    isDetached: function()
    {
        return this._connection.isClosed();
    },

    __proto__: Protocol.Agents.prototype
}

/**
 * @constructor
 * @extends {WebInspector.Object}
 * @param {!WebInspector.Target} target
 */
WebInspector.SDKObject = function(target)
{
    WebInspector.Object.call(this);
    this._target = target;
}

WebInspector.SDKObject.prototype = {
    /**
     * @return {!WebInspector.Target}
     */
    target: function()
    {
        return this._target;
    },

    __proto__: WebInspector.Object.prototype
}

/**
 * @constructor
 * @extends {WebInspector.SDKObject}
 * @param {!Function} modelClass
 * @param {!WebInspector.Target} target
 */
WebInspector.SDKModel = function(modelClass, target)
{
    WebInspector.SDKObject.call(this, target);
    target._modelByConstructor.set(modelClass, this);
}

WebInspector.SDKModel.prototype = {
    __proto__: WebInspector.SDKObject.prototype
}

/**
 * @constructor
 * @extends {WebInspector.Object}
 */
WebInspector.TargetManager = function()
{
    WebInspector.Object.call(this);
    /** @type {!Array.<!WebInspector.Target>} */
    this._targets = [];
    /** @type {!Array.<!WebInspector.TargetManager.Observer>} */
    this._observers = [];
    /** @type {!Object.<string, !Array.<{modelClass: !Function, thisObject: (!Object|undefined), listener: function(!WebInspector.Event)}>>} */
    this._modelListeners = {};
    /** @type {boolean} */
    this._allTargetsSuspended = false;
}

WebInspector.TargetManager.Events = {
    InspectedURLChanged: "InspectedURLChanged",
    MainFrameNavigated: "MainFrameNavigated",
    Load: "Load",
    WillReloadPage: "WillReloadPage",
    SuspendStateChanged: "SuspendStateChanged"
}

WebInspector.TargetManager.prototype = {
    suspendAllTargets: function()
    {
        console.assert(!this._allTargetsSuspended);
        if (this._allTargetsSuspended)
            return;
        this._allTargetsSuspended = true;
        this._targets.forEach(function(target)
        {
            target.suspend();
        });
        this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
    },

    resumeAllTargets: function()
    {
        console.assert(this._allTargetsSuspended);
        if (!this._allTargetsSuspended)
            return;
        this._allTargetsSuspended = false;
        this._targets.forEach(function(target)
        {
            target.resume();
        });
        this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
    },

    /**
     * @return {boolean}
     */
    allTargetsSuspended: function()
    {
        return this._allTargetsSuspended;
    },

    /**
     * @return {string}
     */
    inspectedPageURL: function()
    {
        if (!this._targets.length)
            return "";

        return this._targets[0].resourceTreeModel.inspectedPageURL();
    },

    /**
     * @return {string}
     */
    inspectedPageDomain: function()
    {
        if (!this._targets.length)
            return "";

        return this._targets[0].resourceTreeModel.inspectedPageDomain();
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _redispatchEvent: function(event)
    {
        this.dispatchEventToListeners(event.type, event.data);
    },

    /**
     * @param {boolean=} ignoreCache
     */
    reloadPage: function(ignoreCache)
    {
        if (this._targets.length)
            this._targets[0].resourceTreeModel.reloadPage(ignoreCache);
    },

    /**
     * @param {!Function} modelClass
     * @param {string} eventType
     * @param {function(!WebInspector.Event)} listener
     * @param {!Object=} thisObject
     */
    addModelListener: function(modelClass, eventType, listener, thisObject)
    {
        for (var i = 0; i < this._targets.length; ++i) {
            var model = this._targets[i]._modelByConstructor.get(modelClass);
            model.addEventListener(eventType, listener, thisObject);
        }
        if (!this._modelListeners[eventType])
            this._modelListeners[eventType] = [];
        this._modelListeners[eventType].push({ modelClass: modelClass, thisObject: thisObject, listener: listener });
    },

    /**
     * @param {!Function} modelClass
     * @param {string} eventType
     * @param {function(!WebInspector.Event)} listener
     * @param {!Object=} thisObject
     */
    removeModelListener: function(modelClass, eventType, listener, thisObject)
    {
        if (!this._modelListeners[eventType])
            return;

        for (var i = 0; i < this._targets.length; ++i) {
            var model = this._targets[i]._modelByConstructor.get(modelClass);
            model.removeEventListener(eventType, listener, thisObject);
        }

        var listeners = this._modelListeners[eventType];
        for (var i = 0; i < listeners.length; ++i) {
            if (listeners[i].modelClass === modelClass && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
                listeners.splice(i--, 1);
        }
        if (!listeners.length)
            delete this._modelListeners[eventType];
    },

    /**
     * @param {!WebInspector.TargetManager.Observer} targetObserver
     */
    observeTargets: function(targetObserver)
    {
        this.targets().forEach(targetObserver.targetAdded.bind(targetObserver));
        this._observers.push(targetObserver);
    },

    /**
     * @param {!WebInspector.TargetManager.Observer} targetObserver
     */
    unobserveTargets: function(targetObserver)
    {
        this._observers.remove(targetObserver);
    },

    /**
     * @param {string} name
     * @param {!InspectorBackendClass.Connection} connection
     * @param {function(?WebInspector.Target)=} callback
     */
    createTarget: function(name, connection, callback)
    {
        var target = new WebInspector.Target(name, connection, callbackWrapper.bind(this));

        /**
         * @this {WebInspector.TargetManager}
         * @param {?WebInspector.Target} newTarget
         */
        function callbackWrapper(newTarget)
        {
            if (newTarget)
                this.addTarget(newTarget);
            if (callback)
                callback(newTarget);
        }
    },

    /**
     * @param {!WebInspector.Target} target
     */
    addTarget: function(target)
    {
        this._targets.push(target);
        if (this._targets.length === 1) {
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
        }
        var copy = this._observers.slice();
        for (var i = 0; i < copy.length; ++i)
            copy[i].targetAdded(target);

        for (var eventType in this._modelListeners) {
            var listeners = this._modelListeners[eventType];
            for (var i = 0; i < listeners.length; ++i) {
                var model = target._modelByConstructor.get(listeners[i].modelClass);
                model.addEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
            }
        }
    },

    /**
     * @param {!WebInspector.Target} target
     */
    removeTarget: function(target)
    {
        this._targets.remove(target);
        if (this._targets.length === 0) {
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
        }
        var copy = this._observers.slice();
        for (var i = 0; i < copy.length; ++i)
            copy[i].targetRemoved(target);

        for (var eventType in this._modelListeners) {
            var listeners = this._modelListeners[eventType];
            for (var i = 0; i < listeners.length; ++i) {
                var model = target._modelByConstructor.get(listeners[i].modelClass);
                model.removeEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
            }
        }
    },

    /**
     * @return {boolean}
     */
    hasTargets: function()
    {
        return !!this._targets.length;
    },

    /**
     * @return {!Array.<!WebInspector.Target>}
     */
    targets: function()
    {
        return this._targets.slice();
    },

    /**
     * @return {?WebInspector.Target}
     */
    mainTarget: function()
    {
        return this._targets[0] || null;
    },

    __proto__: WebInspector.Object.prototype
}

/**
 * @interface
 */
WebInspector.TargetManager.Observer = function()
{
}

WebInspector.TargetManager.Observer.prototype = {
    /**
     * @param {!WebInspector.Target} target
     */
    targetAdded: function(target) { },

    /**
     * @param {!WebInspector.Target} target
     */
    targetRemoved: function(target) { },
}

/**
 * @type {!WebInspector.TargetManager}
 */
WebInspector.targetManager = new WebInspector.TargetManager();
<commit_msg>Check existance of models on targets before event work<commit_after>/*
 * Copyright 2014 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @constructor
 * @extends {Protocol.Agents}
 * @param {string} name
 * @param {!InspectorBackendClass.Connection} connection
 * @param {function(?WebInspector.Target)=} callback
 */
WebInspector.Target = function(name, connection, callback)
{
    Protocol.Agents.call(this, connection.agentsMap());
    this._name = name;
    this._connection = connection;
    connection.addEventListener(InspectorBackendClass.Connection.Events.Disconnected, this._onDisconnect, this);
    this._id = WebInspector.Target._nextId++;

    /** @type {!Map.<!Function, !WebInspector.SDKModel>} */
    this._modelByConstructor = new Map();

    /** @type {!Object.<string, boolean>} */
    this._capabilities = {};
    this.pageAgent().canScreencast(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanScreencast, null));
    this.pageAgent().canEmulate(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanEmulate, null));
    if (Runtime.experiments.isEnabled("timelinePowerProfiler"))
        this.powerAgent().canProfilePower(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanProfilePower, null));
    this.workerAgent().canInspectWorkers(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanInspectWorkers, this._loadedWithCapabilities.bind(this, callback)));
    this.consoleAgent().setTracingBasedTimeline(true);
}

/**
 * @enum {string}
 */
WebInspector.Target.Capabilities = {
    CanScreencast: "CanScreencast",
    HasTouchInputs: "HasTouchInputs",
    CanProfilePower: "CanProfilePower",
    CanInspectWorkers: "CanInspectWorkers",
    CanEmulate: "CanEmulate"
}

WebInspector.Target._nextId = 1;

WebInspector.Target.prototype = {
    suspend: function()
    {
        if (!Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
            this.debuggerModel.asyncStackTracesStateChanged();
            return;
        }
        this.debuggerModel.suspendModel();
        this.cssModel.suspendModel();
        this.domModel.suspendModel();
    },

    resume: function()
    {
        if (Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
            this.domModel.resumeModel();
            this.cssModel.resumeModel();
            this.debuggerModel.resumeModel();
        } else {
            this.debuggerModel.asyncStackTracesStateChanged();
        }
    },

    /**
     * @return {number}
     */
    id: function()
    {
        return this._id;
    },

    /**
     *
     * @return {string}
     */
    name: function()
    {
        return this._name;
    },

    /**
     * @param {string} name
     * @param {function()|null} callback
     * @param {?Protocol.Error} error
     * @param {boolean} result
     */
    _initializeCapability: function(name, callback, error, result)
    {
        this._capabilities[name] = result;
        if (callback)
            callback();
    },

    /**
     * @param {string} capability
     * @return {boolean}
     */
    hasCapability: function(capability)
    {
        return !!this._capabilities[capability];
    },

    /**
     * @param {function(?WebInspector.Target)=} callback
     */
    _loadedWithCapabilities: function(callback)
    {
        if (this._connection.isClosed()) {
            callback(null);
            return;
        }

        /** @type {!WebInspector.ConsoleModel} */
        this.consoleModel = new WebInspector.ConsoleModel(this);

        /** @type {!WebInspector.NetworkManager} */
        this.networkManager = new WebInspector.NetworkManager(this);

        /** @type {!WebInspector.ResourceTreeModel} */
        this.resourceTreeModel = new WebInspector.ResourceTreeModel(this);
        if (!WebInspector.resourceTreeModel)
            WebInspector.resourceTreeModel = this.resourceTreeModel;

        /** @type {!WebInspector.NetworkLog} */
        this.networkLog = new WebInspector.NetworkLog(this);
        if (!WebInspector.networkLog)
            WebInspector.networkLog = this.networkLog;

        /** @type {!WebInspector.DebuggerModel} */
        this.debuggerModel = new WebInspector.DebuggerModel(this);
        if (!WebInspector.debuggerModel)
            WebInspector.debuggerModel = this.debuggerModel;

        /** @type {!WebInspector.RuntimeModel} */
        this.runtimeModel = new WebInspector.RuntimeModel(this);
        if (!WebInspector.runtimeModel)
            WebInspector.runtimeModel = this.runtimeModel;

        /** @type {!WebInspector.DOMModel} */
        this.domModel = new WebInspector.DOMModel(this);

        /** @type {!WebInspector.CSSStyleModel} */
        this.cssModel = new WebInspector.CSSStyleModel(this);
        if (!WebInspector.cssModel)
            WebInspector.cssModel = this.cssModel;

        /** @type {!WebInspector.WorkerManager} */
        this.workerManager = new WebInspector.WorkerManager(this, this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers));
        if (!WebInspector.workerManager)
            WebInspector.workerManager = this.workerManager;

        if (this.hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
            WebInspector.powerProfiler = new WebInspector.PowerProfiler(this);

        /** @type {!WebInspector.DatabaseModel} */
        this.databaseModel = new WebInspector.DatabaseModel(this);
        if (!WebInspector.databaseModel)
            WebInspector.databaseModel = this.databaseModel;

        /** @type {!WebInspector.DOMStorageModel} */
        this.domStorageModel = new WebInspector.DOMStorageModel(this);
        if (!WebInspector.domStorageModel)
            WebInspector.domStorageModel = this.domStorageModel;

        /** @type {!WebInspector.CPUProfilerModel} */
        this.cpuProfilerModel = new WebInspector.CPUProfilerModel(this);
        if (!WebInspector.cpuProfilerModel)
            WebInspector.cpuProfilerModel = this.cpuProfilerModel;

        /** @type {!WebInspector.HeapProfilerModel} */
        this.heapProfilerModel = new WebInspector.HeapProfilerModel(this);

        /** @type {!WebInspector.IndexedDBModel} */
        this.indexedDBModel = new WebInspector.IndexedDBModel(this);

        /** @type {!WebInspector.LayerTreeModel} */
        this.layerTreeModel = new WebInspector.LayerTreeModel(this);

        /** @type {!WebInspector.AnimationModel} */
        this.animationModel = new WebInspector.AnimationModel(this);

        if (callback)
            callback(this);
    },

    /**
     * @override
     * @param {string} domain
     * @param {!Object} dispatcher
     */
    registerDispatcher: function(domain, dispatcher)
    {
        this._connection.registerDispatcher(domain, dispatcher);
    },

    /**
     * @return {boolean}
     */
    isWorkerTarget: function()
    {
        return !this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers);
    },

    /**
     * @return {boolean}
     */
    canEmulate: function()
    {
        return this.hasCapability(WebInspector.Target.Capabilities.CanEmulate);
    },

    _onDisconnect: function()
    {
        WebInspector.targetManager.removeTarget(this);
        this._dispose();
    },

    _dispose: function()
    {
        this.debuggerModel.dispose();
        this.networkManager.dispose();
        this.cpuProfilerModel.dispose();
    },

    /**
     * @return {boolean}
     */
    isDetached: function()
    {
        return this._connection.isClosed();
    },

    __proto__: Protocol.Agents.prototype
}

/**
 * @constructor
 * @extends {WebInspector.Object}
 * @param {!WebInspector.Target} target
 */
WebInspector.SDKObject = function(target)
{
    WebInspector.Object.call(this);
    this._target = target;
}

WebInspector.SDKObject.prototype = {
    /**
     * @return {!WebInspector.Target}
     */
    target: function()
    {
        return this._target;
    },

    __proto__: WebInspector.Object.prototype
}

/**
 * @constructor
 * @extends {WebInspector.SDKObject}
 * @param {!Function} modelClass
 * @param {!WebInspector.Target} target
 */
WebInspector.SDKModel = function(modelClass, target)
{
    WebInspector.SDKObject.call(this, target);
    target._modelByConstructor.set(modelClass, this);
}

WebInspector.SDKModel.prototype = {
    __proto__: WebInspector.SDKObject.prototype
}

/**
 * @constructor
 * @extends {WebInspector.Object}
 */
WebInspector.TargetManager = function()
{
    WebInspector.Object.call(this);
    /** @type {!Array.<!WebInspector.Target>} */
    this._targets = [];
    /** @type {!Array.<!WebInspector.TargetManager.Observer>} */
    this._observers = [];
    /** @type {!Object.<string, !Array.<{modelClass: !Function, thisObject: (!Object|undefined), listener: function(!WebInspector.Event)}>>} */
    this._modelListeners = {};
    /** @type {boolean} */
    this._allTargetsSuspended = false;
}

WebInspector.TargetManager.Events = {
    InspectedURLChanged: "InspectedURLChanged",
    MainFrameNavigated: "MainFrameNavigated",
    Load: "Load",
    WillReloadPage: "WillReloadPage",
    SuspendStateChanged: "SuspendStateChanged"
}

WebInspector.TargetManager.prototype = {
    suspendAllTargets: function()
    {
        console.assert(!this._allTargetsSuspended);
        if (this._allTargetsSuspended)
            return;
        this._allTargetsSuspended = true;
        this._targets.forEach(function(target)
        {
            target.suspend();
        });
        this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
    },

    resumeAllTargets: function()
    {
        console.assert(this._allTargetsSuspended);
        if (!this._allTargetsSuspended)
            return;
        this._allTargetsSuspended = false;
        this._targets.forEach(function(target)
        {
            target.resume();
        });
        this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
    },

    /**
     * @return {boolean}
     */
    allTargetsSuspended: function()
    {
        return this._allTargetsSuspended;
    },

    /**
     * @return {string}
     */
    inspectedPageURL: function()
    {
        if (!this._targets.length)
            return "";

        return this._targets[0].resourceTreeModel.inspectedPageURL();
    },

    /**
     * @return {string}
     */
    inspectedPageDomain: function()
    {
        if (!this._targets.length)
            return "";

        return this._targets[0].resourceTreeModel.inspectedPageDomain();
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _redispatchEvent: function(event)
    {
        this.dispatchEventToListeners(event.type, event.data);
    },

    /**
     * @param {boolean=} ignoreCache
     */
    reloadPage: function(ignoreCache)
    {
        if (this._targets.length)
            this._targets[0].resourceTreeModel.reloadPage(ignoreCache);
    },

    /**
     * @param {!Function} modelClass
     * @param {string} eventType
     * @param {function(!WebInspector.Event)} listener
     * @param {!Object=} thisObject
     */
    addModelListener: function(modelClass, eventType, listener, thisObject)
    {
        for (var i = 0; i < this._targets.length; ++i) {
            var model = this._targets[i]._modelByConstructor.get(modelClass);
            if (model)
                model.addEventListener(eventType, listener, thisObject);
        }
        if (!this._modelListeners[eventType])
            this._modelListeners[eventType] = [];
        this._modelListeners[eventType].push({ modelClass: modelClass, thisObject: thisObject, listener: listener });
    },

    /**
     * @param {!Function} modelClass
     * @param {string} eventType
     * @param {function(!WebInspector.Event)} listener
     * @param {!Object=} thisObject
     */
    removeModelListener: function(modelClass, eventType, listener, thisObject)
    {
        if (!this._modelListeners[eventType])
            return;

        for (var i = 0; i < this._targets.length; ++i) {
            var model = this._targets[i]._modelByConstructor.get(modelClass);
            if (model)
                model.removeEventListener(eventType, listener, thisObject);
        }

        var listeners = this._modelListeners[eventType];
        for (var i = 0; i < listeners.length; ++i) {
            if (listeners[i].modelClass === modelClass && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
                listeners.splice(i--, 1);
        }
        if (!listeners.length)
            delete this._modelListeners[eventType];
    },

    /**
     * @param {!WebInspector.TargetManager.Observer} targetObserver
     */
    observeTargets: function(targetObserver)
    {
        this.targets().forEach(targetObserver.targetAdded.bind(targetObserver));
        this._observers.push(targetObserver);
    },

    /**
     * @param {!WebInspector.TargetManager.Observer} targetObserver
     */
    unobserveTargets: function(targetObserver)
    {
        this._observers.remove(targetObserver);
    },

    /**
     * @param {string} name
     * @param {!InspectorBackendClass.Connection} connection
     * @param {function(?WebInspector.Target)=} callback
     */
    createTarget: function(name, connection, callback)
    {
        var target = new WebInspector.Target(name, connection, callbackWrapper.bind(this));

        /**
         * @this {WebInspector.TargetManager}
         * @param {?WebInspector.Target} newTarget
         */
        function callbackWrapper(newTarget)
        {
            if (newTarget)
                this.addTarget(newTarget);
            if (callback)
                callback(newTarget);
        }
    },

    /**
     * @param {!WebInspector.Target} target
     */
    addTarget: function(target)
    {
        this._targets.push(target);
        if (this._targets.length === 1) {
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
            target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
        }
        var copy = this._observers.slice();
        for (var i = 0; i < copy.length; ++i)
            copy[i].targetAdded(target);

        for (var eventType in this._modelListeners) {
            var listeners = this._modelListeners[eventType];
            for (var i = 0; i < listeners.length; ++i) {
                var model = target._modelByConstructor.get(listeners[i].modelClass);
                if (model)
                    model.addEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
            }
        }
    },

    /**
     * @param {!WebInspector.Target} target
     */
    removeTarget: function(target)
    {
        this._targets.remove(target);
        if (this._targets.length === 0) {
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
            target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
        }
        var copy = this._observers.slice();
        for (var i = 0; i < copy.length; ++i)
            copy[i].targetRemoved(target);

        for (var eventType in this._modelListeners) {
            var listeners = this._modelListeners[eventType];
            for (var i = 0; i < listeners.length; ++i) {
                var model = target._modelByConstructor.get(listeners[i].modelClass);
                if (model)
                    model.removeEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
            }
        }
    },

    /**
     * @return {boolean}
     */
    hasTargets: function()
    {
        return !!this._targets.length;
    },

    /**
     * @return {!Array.<!WebInspector.Target>}
     */
    targets: function()
    {
        return this._targets.slice();
    },

    /**
     * @return {?WebInspector.Target}
     */
    mainTarget: function()
    {
        return this._targets[0] || null;
    },

    __proto__: WebInspector.Object.prototype
}

/**
 * @interface
 */
WebInspector.TargetManager.Observer = function()
{
}

WebInspector.TargetManager.Observer.prototype = {
    /**
     * @param {!WebInspector.Target} target
     */
    targetAdded: function(target) { },

    /**
     * @param {!WebInspector.Target} target
     */
    targetRemoved: function(target) { },
}

/**
 * @type {!WebInspector.TargetManager}
 */
WebInspector.targetManager = new WebInspector.TargetManager();
<|endoftext|>


<commit_before>/*The MIT License (MIT)

Copyright (c) 2015 Jens Malmborg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/

var vec3 = require('/gl-matrix/vec3.js');
var utils = require('/utils.js');
var Component = require('/entity.js').Component;
var Entity = require('/entity.js').Entity;
var Vector3 = require('/matrix.js').Vector3;
var RigidBody = require('/physics.js').RigidBody;

function BoundingBox() {
    this._min = vec3.create();
    this._max = vec3.create();
}

BoundingBox.prototype.min = function(value) {
    if (!value) {
        return this._min;
    }
    vec3.copy(this._min, value);
};

BoundingBox.prototype.max = function(value) {
    if (!value) {
        return this._max;
    }
    vec3.copy(this._max, value);
};

BoundingBox.prototype.closestPointTo = function(p) {
    var r = vec3.create();
    if (p[0] < this._min[0]) {
        r[0] = this._min[0];
    } else if (p[0] > this._max[0]) {
        r[0] = this._max[0];
    } else {
        r[0] = p[0];
    }
    if (p[1] < this._min[1]) {
        r[1] = this._min[1];
    } else if (p[1] > this._max[1]) {
        r[1] = this._max[1];
    } else {
        r[1] = p[1];
    }
    if (p[2] < this._min[2]) {
        r[2] = this._min[2];
    } else if (p[2] > this._max[2]) {
        r[2] = this._max[2];
    } else {
        r[2] = p[2];
    }
    return r;
};

BoundingBox.prototype.contains = function(p) {
    return (p[0] >= this._min[0]) && (p[0] <= this._max[0]) &&
        (p[1] >= this._min[1]) && (p[1] <= this._max[1]) &&
        (p[2] >= this._min[2]) && (p[2] <= this._max[2]);
};

BoundingBox.prototype.intersectsBox = function(box, mtv) {
    if (this._min[0] > box._max[0]) {
        return false;
    }
    if (this._max[0] < box._min[0]) {
        return false;
    }
    if (this._min[1] > box._max[1]) {
        return false;
    }
    if (this._max[1] < box._min[1]) {
        return false;
    }
    if (this._min[2] > box._max[2]) {
        return false;
    }
    if (this._max[2] < box._min[2]) {
        return false;
    }
    if (mtv !== undefined) {
        var left = box._min[0] - this._max[0];
        var right = box._max[0] - this._min[0];
        var top = box._min[1] - this._max[1];
        var bottom = box._max[1] - this._min[1];
        var front = box._min[2] - this._max[2];
        var back = box._max[2] - this._min[2];

        if (Math.abs(left) < right) {
            mtv[0] = left;
        } else {
            mtv[0] = right;
        }
        if (Math.abs(top) < bottom) {
            mtv[1] = top;
        } else {
            mtv[1] = bottom;
        }
        if (Math.abs(front) < back) {
            mtv[2] = front;
        } else {
            mtv[2] = back;
        }
        if (Math.abs(mtv[0]) < Math.abs(mtv[1])) {
            if (Math.abs(mtv[0]) < Math.abs(mtv[2])) {
                mtv[2] = 0;
            } else {
                mtv[0] = 0;
            }
            mtv[1] = 0;
        } else {
            if (Math.abs(mtv[1]) < Math.abs(mtv[2])) {
                mtv[2] = 0;
            } else {
                mtv[0] = 0;
            }
            mtv[0] = 0;
        }
    }
    return true;
};

BoundingBox.prototype.intersectsSphere = function(sphere, mtv) {
    var closestPoint = this.closestPointTo(sphere.center());
    var squaredDistance = vec3.squaredDistance(sphere.center(), closestPoint);
    var collision = squaredDistance < sphere.radius*sphere.radius;
    if (collision) {
        vec3.copy(mtv, this.minTranslationDistanceSphere(sphere));
        return true;
    }
    return false;
};

BoundingBox.prototype.minTranslationDistanceSphere = (function() {
    var _direction = new Vector3();
    var _result = new Vector3();

    return function(sphere) {
        var closestPoint = this.closestPointTo(sphere.center());
        vec3.sub(_direction, closestPoint, sphere.center());
        vec3.normalize(_direction, _direction);
        var distance = vec3.distance(closestPoint, sphere.center());
        return vec3.scale(_result, _direction, sphere.radius - distance);
    }
})();

function BoundingSphere(radius) {
    this._center = vec3.create();
    this.radius = radius || 0;
}

BoundingSphere.prototype.center = function(value) {
    if (value === undefined) {
        return this._center;
    }
    vec3.copy(this._center, value);
};

BoundingSphere.prototype.intersectsBox = function(box, mtv) {
    var collision = box.intersectsSphere(this, mtv);
    if (collision) {
        mtv.negate(mtv);
    }
    return collision;
};

BoundingSphere.prototype.intersectsSphere = function(sphere, mtv) {
    var squaredRadius =
        (sphere.radius + this.radius) * (sphere.radius + this.radius);
    var squaredDistance = vec3.squaredDistance(this._center, sphere._center);
    var collision = squaredDistance < squaredRadius;
    if (collision) {
        vec3.copy(mtv, this.minTranslationDistanceSphere(sphere));
        return true;
    }
    return false;
};

BoundingSphere.prototype.minTranslationDistanceSphere = (function() {
    var _dir = new Vector3();
    var _mtv = new Vector3();

    return function(sphere) {
        _dir = vec3.sub(_dir, this._center, sphere._center);
        var length = vec3.length(_dir);
        return vec3.scale(
            _mtv, _dir, ((this.radius + sphere.radius)-length)/length);
    }
})();

function BoxColliderComponent(options) {
    Component.call(this);
    options = options || {};
    this.box = new BoundingBox();
    this.collisionHandler = options.collisionHandler || function() {};
    this.collisionResolver =
        options.collisionResolver || RigidBody.resolveCollision;
    var size = options.size || vec3.fromValues(1,1,1);
    this.min = vec3.fromValues(-size[0]/2, -size[1]/2, -size[2]/2);
    this.max = vec3.fromValues(size[0]/2, size[1]/2, size[2]/2);
}

utils.extend(BoxColliderComponent, Component);

BoxColliderComponent.prototype.update = function() {
    var transform = this.entity.getTransform();
    vec3.transformMat4(this.box._min, this.min, transform);
    vec3.transformMat4(this.box._max, this.max, transform);
};

BoxColliderComponent.prototype.detectCollision = (function() {
    var _mtv = new Vector3();

    return function(entity) {
        if (!this.enabled) {
            return;
        }
        var boxCollider = entity.components.boxcollider;
        if (boxCollider && boxCollider.enabled) {
            if (this.box.intersectsBox(boxCollider.box, _mtv)) {
                this.collisionHandler(entity);
                boxCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
                return;
            }
        }
        var sphereCollider = entity.components.spherecollider;
        if (sphereCollider && sphereCollider.enabled) {
            if (this.box.intersectsSphere(sphereCollider.sphere, _mtv)) {
                this.collisionHandler(entity);
                sphereCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
            }
        }
    }
})();

function SphereColliderComponent(options) {
    Component.call(this);
    this.center = vec3.create();
    this.sphere = new BoundingSphere(options.radius || 0.5);
    this.collisionHandler = options.collisionHandler || function() {};
    this.collisionResolver =
        options.collisionResolver || RigidBody.resolveCollision;
}

utils.extend(SphereColliderComponent, Component);

SphereColliderComponent.prototype.update = function() {
    vec3.transformMat4(this.sphere._center, this.center,
        this.entity.getTransform());
};

SphereColliderComponent.prototype.detectCollision = (function() {
    var _mtv = new Vector3();

    return function(entity) {
        if (!this.enabled) {
            return;
        }
        var boxCollider = entity.components.boxcollider;
        if (boxCollider && boxCollider.enabled) {
            if (this.sphere.intersectsBox(boxCollider.box, _mtv)) {
                this.collisionHandler(entity);
                boxCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
                return;
            }
        }
        var sphereCollider = entity.components.spherecollider;
        if (sphereCollider && sphereCollider.enabled) {
            if (this.sphere.intersectsSphere(sphereCollider.sphere, _mtv)) {
                this.collisionHandler(entity);
                sphereCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
            }
        }
    }
})();

function CollisionManager() {
    Entity.call(this);
}

utils.extend(CollisionManager, Entity);

CollisionManager.detectEntityCollisions =
    function(entity, entities, startIndex) {

    for (var i = startIndex || 0; i < entities.length; i++) {
        if (entity === entities[i]) {
            continue;
        }
        var sphereCollider = entity.components.spherecollider;
        if (sphereCollider) {
            sphereCollider.detectCollision(entities[i]);
            continue;
        }
        var boxCollider = entity.components.boxcollider;
        if (boxCollider) {
            boxCollider.detectCollision(entities[i]);
            continue;
        }
    }
};

CollisionManager.detectCollisions = function(entities) {
    for (var i=0; i<entities.length; i++) {
        CollisionManager.detectEntityCollisions(entities[i], entities, i + 1);
    }
};

CollisionManager.prototype.update = function(elapsed) {
    Entity.prototype.update.call(this, elapsed);
    CollisionManager.detectCollisions(this.children);
};

module.exports.BoundingBox = BoundingBox;
module.exports.BoxColliderComponent = BoxColliderComponent;
module.exports.BoundingSphere = BoundingSphere;
module.exports.SphereColliderComponent = SphereColliderComponent;
module.exports.CollisionManager = CollisionManager;<commit_msg>Added OBB collision detection with SAT.<commit_after>/*The MIT License (MIT)

Copyright (c) 2015 Jens Malmborg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/

var Utils = require('/utils.js').Utils;
var Component = require('/entity.js').Component;
var Entity = require('/entity.js').Entity;
var Vector3 = require('/matrix.js').Vector3;
var RigidBody = require('/physics.js').RigidBody;

var SAT = {};

SAT.Shape = function Shape(center, points, radius) {
    this.center = center;
    this.points = points;
    // Radius for the shape is really only used when shape is a circle/sphere.
    this.radius = radius || 0;
};

SAT.Shape.prototype.project = function(axis) {
    var dot = axis.dot(this.points[0]);
    var min = dot;
    var max = dot;
    for (var i=0; i<this.points.length; i++) {
        dot = axis.dot(this.points[i]);
        min = Math.min(dot, min);
        max = Math.max(dot, max);
    }
    return {
        min: min - this.radius,
        max: max + this.radius
    };
};

SAT.distance = function(a, b) {
    if (a.min < b.min) {
        return b.min - a.max;
    } else {
        return a.min - b.max;
    }
};

SAT.testAxes = function(axes, shapeA, shapeB) {
    var result = {
        isIntersecting: true,
        minPenetrationDepth: null,
        minPenetrationVector: null
    };
    for (var i=0; i<axes.length; i++) {
        var projA = shapeA.project(axes[i]);
        var projB = shapeB.project(axes[i]);
        var dist = SAT.distance(projA, projB);
        if (dist > 0) {
            result.isIntersecting = false;
            break;
        }
        dist = Math.abs(dist);
        if (!result.minPenetrationDepth || dist < result.minPenetrationDepth) {
            result.minPenetrationDepth = dist;
            result.minPenetrationVector = axes[i];

            var d = shapeA.center.sub(shapeB.center);
            if (d.dot(result.minPenetrationVector) < 0) {
                result.minPenetrationVector =
                    result.minPenetrationVector.negate();
            }
        }
    }
    return result;
};

function BoundingBox(extents) {
    this.center = new Vector3();
    this.extents = extents || new Vector3();
    this.edges = [];
    this.points = [];
    for (var i=0; i<8; i++) {
        this.points.push(new Vector3());
    }
    this.normals = [];
    for (var i=0; i<3; i++) {
        this.normals.push(new Vector3());
    }
}

BoundingBox.prototype.closestPointTo = (function() {
    var _d = new Vector3();

    return function(point, result) {
        if (result) {
            result.set(0,0,0);
        }
        _d = point.sub(this.center, _d);
        var q = result || new Vector3();
        for (var i=0; i<this.normals.length; i++) {
            var dist = _d.dot(this.normals[i]);
            if (dist > this.extents[i]) {
                dist = this.extents[i];
            }
            if (dist < -this.extents[i]) {
                dist = -this.extents[i];
            }
            q.add(this.normals[i].scale(dist), q);
        }
        return q;
    }
})();

BoundingBox.prototype.intersectsBox = function(box, mtv) {
    var normals = this.normals.
        concat(box.normals).
        concat(this.edges).
        concat(box.edges);

    var a = new SAT.Shape(this.center, this.points);
    var b = new SAT.Shape(box.center, box.points);
    var result = SAT.testAxes(normals, a, b);

    if (!result.isIntersecting) {
        return false;
    }

    var min = result.minPenetrationDepth;
    var axis = result.minPenetrationVector;

    mtv.set(axis.normalize().scale(min));

    return true;
};

BoundingBox.prototype.intersectsSphere = (function() {
    var _closestPoint = new Vector3();
    var _axis = new Vector3();

    return function(sphere, mtv) {
        // When testing box with sphere using SAT, the only axis that needs to
        // be tested goes from center of sphere to closest point on box.
        _closestPoint = this.closestPointTo(sphere.center, _closestPoint)
            .add(this.center, _closestPoint);
        _axis = _closestPoint.sub(sphere.center, _axis)
            .normalize(_axis);

        var a = new SAT.Shape(this.center, this.points);
        var b = new SAT.Shape(sphere.center, [sphere.center], sphere.radius);

        var result = SAT.testAxes([_axis], a, b);
        if (!result.isIntersecting) {
            return false;
        }

        mtv.set(result.minPenetrationVector.normalize()
            .scale(result.minPenetrationDepth));

        return true;
    }
})();

function BoundingSphere(radius) {
    this.center = new Vector3();
    this.radius = radius || 0;
}

BoundingSphere.prototype.intersectsBox = function(box, mtv) {
    if (box.intersectsSphere(this, mtv)) {
        mtv.negate(mtv);
        return true;
    }
    return false;
};

BoundingSphere.prototype.intersectsSphere = (function() {
    var _delta = new Vector3();

    return function(sphere, mtv) {
        var sum = sphere.radius + this.radius;
        var isIntersecting =
            this.center.squaredDistance(sphere.center) < sum * sum;
        if (isIntersecting) {
            this.center.sub(sphere.center, _delta);
            var length = _delta.len();
            _delta.scale((sum-length)/length, mtv);
            return true;
        }
        return false;
    }
})();

var emptyCollisionHandler = function() {};

function BoxColliderComponent(options) {
    Component.call(this);

    options = Utils.options(options, this);
    options.value('extents', new Vector3(0.5,0.5,0.5));
    options.value('center', new Vector3());
    options.value('collisionHandler', emptyCollisionHandler);
    options.value('collisionResolver', RigidBody.resolveCollision);

    this.box = new BoundingBox();
}

Utils.extend(BoxColliderComponent, Component);

BoxColliderComponent.prototype.update = (function() {
    var _normals = [
        new Vector3(1,0,0),
        new Vector3(0,1,0),
        new Vector3(0,0,1)
    ];

    return function() {
        var transform = this.entity.transform;
        var world = transform.world();

        this.extents.transform(transform.scaling, this.box.extents);
        this.center.transform(world, this.box.center);

        var x = this.extents.x();
        var y = this.extents.y();
        var z = this.extents.z();

        this.box.points[0].set(-x, y,-z);
        this.box.points[1].set( x, y,-z);
        this.box.points[2].set(-x,-y,-z);
        this.box.points[3].set( x,-y,-z);
        this.box.points[4].set(-x, y, z);
        this.box.points[5].set( x, y, z);
        this.box.points[6].set(-x,-y, z);
        this.box.points[7].set( x,-y, z);

        for (var i=0; i<this.box.points.length; i++) {
            this.box.points[i].transform(world, this.box.points[i]);
        }

        for (var i=0; i<_normals.length; i++) {
            _normals[i].transform(transform.rotation, this.box.normals[i])
                .normalize(this.box.normals[i]);
        }
    }
})();

BoxColliderComponent.prototype.detectCollision = (function() {
    var _mtv = new Vector3();

    return function(entity) {
        if (!this.enabled) {
            return;
        }
        var boxCollider = entity.components.boxcollider;
        if (boxCollider && boxCollider.enabled) {
            if (this.box.intersectsBox(boxCollider.box, _mtv)) {
                this.collisionHandler(entity);
                boxCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
                return;
            }
        }
        var sphereCollider = entity.components.spherecollider;
        if (sphereCollider && sphereCollider.enabled) {
            if (this.box.intersectsSphere(sphereCollider.sphere, _mtv)) {
                this.collisionHandler(entity);
                sphereCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
            }
        }
    }
})();

function SphereColliderComponent(options) {
    Component.call(this);

    options = Utils.options(options, this);
    options.value('radius', 0.5);
    options.value('collisionHandler', emptyCollisionHandler);
    options.value('collisionResolver', RigidBody.resolveCollision);

    this.center = new Vector3();
    this.sphere = new BoundingSphere(this.radius);
}

Utils.extend(SphereColliderComponent, Component);

SphereColliderComponent.prototype.update = function() {
    var transform = this.entity.transform;
    this.center.transform(transform.world(), this.sphere.center);
    // Use the x component from the scaling matrix and apply to radius.
    this.sphere.radius = this.radius * transform.scaling[0];
};

SphereColliderComponent.prototype.detectCollision = (function() {
    var _mtv = new Vector3();

    return function(entity) {
        if (!this.enabled) {
            return;
        }
        var boxCollider = entity.components.boxcollider;
        if (boxCollider && boxCollider.enabled) {
            if (this.sphere.intersectsBox(boxCollider.box, _mtv)) {
                this.collisionHandler(entity);
                boxCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
                return;
            }
        }
        var sphereCollider = entity.components.spherecollider;
        if (sphereCollider && sphereCollider.enabled) {
            if (this.sphere.intersectsSphere(sphereCollider.sphere, _mtv)) {
                this.collisionHandler(entity);
                sphereCollider.collisionHandler(this.entity);
                this.collisionResolver(this.entity, entity, _mtv);
            }
        }
    }
})();

function CollisionManager() {
    Entity.call(this);
}

Utils.extend(CollisionManager, Entity);

CollisionManager.detectEntityCollisions =
    function(entity, entities, startIndex) {

    for (var i = startIndex || 0; i < entities.length; i++) {
        if (entity === entities[i]) {
            continue;
        }
        var sphereCollider = entity.components.spherecollider;
        if (sphereCollider) {
            sphereCollider.detectCollision(entities[i]);
            continue;
        }
        var boxCollider = entity.components.boxcollider;
        if (boxCollider) {
            boxCollider.detectCollision(entities[i]);
            continue;
        }
    }
};

CollisionManager.detectCollisions = function(entities) {
    for (var i=0; i<entities.length; i++) {
        CollisionManager.detectEntityCollisions(entities[i], entities, i + 1);
    }
};

CollisionManager.prototype.update = function(elapsed) {
    Entity.prototype.update.call(this, elapsed);
    CollisionManager.detectCollisions(this.children);
};

module.exports.BoundingBox = BoundingBox;
module.exports.BoxColliderComponent = BoxColliderComponent;
module.exports.BoundingSphere = BoundingSphere;
module.exports.SphereColliderComponent = SphereColliderComponent;
module.exports.CollisionManager = CollisionManager;<|endoftext|>