/**
* TODO: add js header
*/
define([
"dojo",
"dojo/cookie",
"dojo/json",
"coweb/main",
"rcolor",
], function(dojo, cookie, json, coweb, RColor) {
var CoRenkan = function() {
};
var proto = CoRenkan.prototype;
proto.init = function() {
console.log("ready callback", dojo.config.corenkanConfig);
this.renkan = dojo.config.corenkanConfig.renkan;
this.project = dojo.config.corenkanConfig.renkan.project;
this.initCollab(dojo.config.corenkanConfig.projectId);
var sess = coweb.initSession();
this.session = sess;
var that = this;
sess.onStatusChange = function(status) {
console.log(status);
if(typeof that.onStatusChange === "function") {
that.onStatusChange(status);
}
};
sess.prepare({userDefined: {project_id:dojo.config.corenkanConfig.projectId}, collab: true}).then(function(data) {
console.log("Prepare ok : ", data);
that.setObjects();
});
};
proto.initCollab = function(id) {
this.users_collab = coweb.initCollab({id: "users_" + id});
this.users_collab.subscribeStateResponse(this, "onUsersStateResponse");
this.users_collab.subscribeReady(this, "onLocalJoin");
this.users_collab.subscribeSiteJoin(this, 'onRemoteJoin');
this.users_collab.subscribeSiteLeave(this, 'onRemoteLeave');
this.users_collab.subscribeSync("roster", this, "onRemoteRosterChange");
this.collab = coweb.initCollab({id : "renkan_" + id});
this.collab.subscribeStateResponse(this, "onStateResponse");
this.collab.subscribeSync("project", this, "onRemoteProjectChange");
this.collab.subscribeSync("user", this, "onRemoteUserChange");
this.collab.subscribeSync("node", this, "onRemoteNodeChange");
this.collab.subscribeSync("edge", this, "onRemoteEdgeChange");
};
proto.onLocalJoin = function(params) {
console.log("Local join", params);
this.current_site = params.site;
if(typeof this.renkan !== "undefined" && this.renkan != null && typeof this.renkan.current_user != "undefined") {
this.renkan.current_user.set("site_id", params.site);
}
};
proto.onRemoteJoin = function(params) {
console.log("Remote join", params);
// do nothing
};
proto.onRemoteLeave = function(params) {
console.log("Remote leave", params);
// remove remote site from current_user_list
if(typeof this.renkan === "undefined" || this.renkan == null || typeof this.renkan.current_user_list === "undefined" || this.renkan.current_user_list == null) {
return;
}
for ( var user in this.renkan.current_user_list.filter(function(u) { return u.get("site_id") == params.site; })) {
this.renkan.current_user_list.remove(user);
}
};
proto.onUsersStateResponse = function(state) {
user_list = json.parse(state);
console.log("Users State response", user_list);
_.each(user_list, function(user, i, l) {
user['_id'] = user['id'];
});
this.renkan.current_user_list.reset(user_list, {silent: true});
};
proto.onStateResponse = function(state) {
obj = json.parse(state);
console.log("State response", obj);
obj['_id'] = obj['id'];
this.project.set(obj);
};
function prepareValues(obj,c) {
values = {};
for(var fieldname in c.changes) {
if(c.changes[fieldname]) {
values[fieldname] = obj.get(fieldname);
}
}
return values;
}
proto.addObjectBind = function(type, obj, c, options, collab) {
console.log("add " + type,obj, c, options);
if(this.project == null) {
console.log("null project exiting");
return;
}
var values = obj.toJSON();
var new_values = {
id: obj.id,
_type: type,
_index: options.index,
_project_id : obj.get("project").get("_id"),
_user_id : (this.project.current_user!=null)?this.project.current_user.id:null
};
for(var k in new_values) {
values[k] = new_values[k];
}
console.log("add values : ", values);
collab.sendSync(type, values, "insert", options.index);
};
proto.removeObjectBind = function(type, obj, c, options, collab) {
console.log("delete " + type,obj, c, options);
var values = {
id: obj.id,
_type: type,
_index: options.index,
_project_id : obj.get("project").id,
_user_id : (this.project.current_user!=null)?this.project.current_user.id:null
};
collab.sendSync(type, values, "delete", options.index);
};
proto.updateObjectBind = function(type, obj, options, collab) {
console.log("change " + type,obj, options);
if(typeof obj != "undefined" && obj.hasChanged()) {
var values = {
id: obj.id,
_type: type,
_project_id : obj.get("project").id,
_user_id : (this.project.current_user!=null)?this.project.current_user.id:null
};
_.extend(values,obj.changed);
collab.sendSync(type, values);
}
};
/**
* Called when an abject is changed
*
*/
proto.objectChange = function(event, model, collection, options) {
console.log("project change all ", event, model, collection, options);
// check that current user is in user list of the project
if(this.project == null || this.project.current_user == null) {
return;
}
var current_user = this.project.current_user;
if(this.project.get("users").get(current_user.id) == null) {
var props = current_user.toJSON();
this.project.addUser(props);
}
};
proto.setObjects = function() {
console.log(cookie("BAYEUX_BROWSER"));
var renkan = this.renkan;
var project = renkan.project;
this.setProject(project);
this.setRenkan(renkan);
this.setUser(renkan);
};
proto.setRenkan = function(renkan) {
console.log("Set Renkan");
var that = this;
renkan.current_user_list.bind("add", function(obj, c, options) {
that.addObjectBind("roster", obj, c, options, that.users_collab);
});
//renkan.current_user_list.bind("remove", function(obj, c, options) {
// that.removeObjectBind("_roster", obj, c, options, that.users_collab);
//});
renkan.current_user_list.bind("change", function(obj, options) {
that.updateObjectBind("roster", obj, options, that.users_collab);
});
renkan.current_user_list.bind("change", function(obj, options) {
console.log("update roster",obj, options);
// get user in project
project = obj.get("project");
if(project == null) {
console.log("null project return");
return;
}
user = project.get("users").get(obj.id);
if(user == null) {
console.log("user " + obj.id + " not in project. return");
return;
}
for(att in obj.changed) {
new_val = obj.changed[att];
if(user.get("att") != new_val) {
user.set(att, new_val);
}
}
});
};
proto.setUser = function(renkan) {
console.log("set user : " + cookie("BAYEUX_BROWSER"));
if(typeof renkan === "undefined" || typeof renkan.project === "undefined" || renkan.project == null) {
return;
}
var user_id = cookie("BAYEUX_BROWSER");
var project = renkan.project;
var puser = project.get("users").get(user_id);
var puser_def = null;
if(puser == null) {
color = new RColor();
puser_def = {
id: user_id,
title: "anonymous",
project: project,
color: color.get(true, 0.3, 0.99),
site_id: this.current_site
};
}
else {
puser_def = puser.toJSON();
puser_def.project = project;
}
puser = renkan.current_user_list.push(puser_def);
project.current_user = puser;
renkan.current_user = puser.id;
var that = this;
project.once("all", function(event, model, collection, options){
that.objectChange(event, model, collection, options);
});
project.get("nodes").once("all", function(event, model, collection, options){
that.objectChange(event, model, collection, options);
});
project.get("edges").once("all", function(event, model, collection, options){
that.objectChange(event, model, collection, options);
});
};
proto.setProject = function(project) {
console.log("project", project);
var projectFields = ["title", "description", "uri"];
var that = this;
for(var fieldIndex in projectFields) {
(function(fi){
var field = projectFields[fi];
project.bind("change:"+field, function(obj, c) {
console.log(c);
values = {
id: obj.id,
_type: "project",
_project_id: obj.id,
_user_id : (this.project.current_user!=null)?this.project.current_user.id:null
};
values[field] = c;
that.collab.sendSync("project", values);
});
})(fieldIndex);
}
project.get("nodes").bind("add", function(obj, c, options) {
that.addObjectBind("node", obj, c, options, that.collab);
});
project.get("nodes").bind("remove", function(obj, c, options) {
that.removeObjectBind("node", obj, c, options, that.collab);
});
project.get("nodes").bind("change", function(obj, options) {
that.updateObjectBind("node", obj, options, that.collab);
});
project.get("users").bind("add", function(obj, c, options) {
that.addObjectBind("user", obj, c, options, that.collab);
});
project.get("users").bind("remove", function(obj, c, options) {
that.removeObjectBind("user", obj, c, options, that.collab);
});
project.get("users").bind("change", function(obj, options) {
that.updateObjectBind("user", obj, options, that.collab);
});
project.get("edges").bind("add", function(obj, c, options) {
that.addObjectBind("edge", obj, c, options, that.collab);
});
project.get("edges").bind("remove", function(obj, c, options) {
that.removeObjectBind("edge", obj, c, options, that.collab);
});
project.get("edges").bind("change", function(obj, options) {
that.updateObjectBind("edge", obj, options, that.collab);
});
};
/**
* Called when a remote data store for project changes in some manner. Dispatches to
* local methods for insert, update, delete handling.
* TODO: manage project list change on server
* @param args Cooperative web event
*/
proto.onRemoteProjectChange = function(args) {
console.log("Remote project change", args);
if (args.type === "update") {
this.onRemoteProjectUpdate(args.value, args.position);
}
};
/**
* Called when a remote data store for nodes changes in some manner. Dispatches to
* local methods for insert, update, delete handling.
* @param args Cooperative web event
*/
proto.onRemoteObjectChange = function(field, args) {
console.log("Remote "+ field +" change",args);
if (args.type === "insert") {
this.onRemoteObjectInsert(field, args.value, args.position);
} else if (args.type === "update") {
this.onRemoteObjectUpdate(field, args.value, args.position);
} else if (args.type === "delete") {
this.onRemoteObjectDelete(field, args.position);
}
};
/**
* Called when a remote data store for nodes changes in some manner. Dispatches to
* local methods for insert, update, delete handling.
* @param args Cooperative web event
*/
proto.onRemoteNodeChange = function(args) {
this.onRemoteObjectChange("nodes", args);
};
/**
* Called when a remote data store for nodes changes in some manner. Dispatches to
* local methods for insert, update, delete handling.
* @param args Cooperative web event
*/
proto.onRemoteUserChange = function(args) {
this.onRemoteObjectChange("users", args);
};
/**
* Called when a remote data store for nodes changes in some manner. Dispatches to
* local methods for insert, update, delete handling.
* @param args Cooperative web event
*/
proto.onRemoteEdgeChange = function(args) {
this.onRemoteObjectChange("edges", args);
};
/**
* Called when a remote data store for nodes changes in some manner. Dispatches to
* local methods for insert, update, delete handling.
* @param args Cooperative web event
*/
proto.onRemoteRosterChange = function(args) {
this.onRemoteObjectChange(this.renkan.current_user_list, args);
};
/**
* Called when a project attribute changes value in a remote data store.
* Updates the attribute value of the item with the same id in the local
* data store.
*
* @param value Item data sent by remote data store
* @param position Which item to update.
*/
proto.onRemoteProjectUpdate = function(values, position) {
var project_id = values['id'];
if(typeof(project_id) === "undefined") {
return;
}
if(this.project != null && project_id == this.project.id) {
for(var fieldname in values) {
if(fieldname != "id" && fieldname != "type") {
this.project.set(fieldname, values[fieldname]);
}
}
}
};
/**
* Called when an object is inserted in a remote data store.
*
* @param field_coll A collection or a string for one of the project collection
* @param value Item data sent by remote data store
* @param position Which item to update.
*/
proto.onRemoteObjectInsert = function(field_coll, values, position) {
console.log("Remote ", field_coll ," insert values ", values, "position", position);
var coll = null;
if(typeof field_coll === "string") {
coll = this.project.get(field_coll);
}
else {
coll = field_coll;
}
var object_id = values['id'];
var obj = coll.get(object_id);
if(obj != null) {
this.onRemoteObjectUpdate(field_coll, values, coll.indexOf(obj));
}
else {
var add_values = {};
for(var fieldname in values) {
if(fieldname == "_id" || fieldname[0] !== '_' ) {
add_values[fieldname] = values[fieldname];
}
}
switch(field_coll) {
case "nodes":
this.project.addNode(add_values, {at:position});
break;
case "edges":
this.project.addEdge(add_values, {at:position});
break;
case "users":
this.project.addUser(add_values, {at:position});
break;
default:
add_values.project = this.project;
coll.push(add_values, {at:position});
break;
}
}
};
/**
* Called when a object attribute changes value in a remote data store.
* Updates the attribute value of the item with the same id in the local
* data store.
*
* @param field_coll A collection or a string for one of the project collection
* @param value Item data sent by remote data store
* @param position Which item to update.
*/
proto.onRemoteObjectUpdate = function(field_coll, values, position) {
console.log("Remote ", field_coll ," update values ", values, "position", position);
var coll = null;
if(typeof field_coll === "string") {
coll = this.project.get(field_coll);
}
else {
coll = field_coll;
}
var object_id = values['id'];
if(this.project != null) {
var obj = coll.get(object_id);
if(obj != null) {
var changed_val = {};
for(var fieldname in values) {
if(fieldname != "id" && fieldname != "type") {
changed_val[fieldname] = values[fieldname];
}
}
obj.set(changed_val);
}
}
};
/**
* Called when a object is deleted in a remote data store.
*
* @param field_coll A collection or a string for one of the project collection
* @param position Which item to update.
*/
proto.onRemoteObjectDelete = function(field_coll, position) {
console.log("Remote ", field_coll," delete position", position);
var coll = null;
if(typeof field_coll === "string") {
coll = this.project.get(field);
}
else {
coll = field_coll;
}
coll.remove(coll.at(position));
};
var app = new CoRenkan();
dojo.ready(function() {
app.init();
});
return {
app: app
};
});