# HG changeset patch # User ymh # Date 1466766441 -7200 # Node ID 02e3c464223f384acbfcdaaae9d1ddbdb671eed8 # Parent 192ce5938726814d24487ed65ae15f734e9b6ca2 Add click origin info to help action tracing diff -r 192ce5938726 -r 02e3c464223f .hgignore --- a/.hgignore Thu Jun 23 17:50:37 2016 +0200 +++ b/.hgignore Fri Jun 24 13:07:21 2016 +0200 @@ -1,5 +1,6 @@ syntax: regexp +\.tern-port$ ^\.project$ ^\.pydevproject$ ^server/java/target$ diff -r 192ce5938726 -r 02e3c464223f client/js/main.js --- a/client/js/main.js Thu Jun 23 17:50:37 2016 +0200 +++ b/client/js/main.js Fri Jun 24 13:07:21 2016 +0200 @@ -354,6 +354,17 @@ }; Rkns.Utils = { + + OriginEnum: (function(o) { return (Object.freeze && Object.freeze(o)) || o; }) ({ + NONE: 0, + NODE_BUTTON: 1, + NODE_DOUBLE_CLICK: 2, + NODE_DROP_EXT: 3, + NODE_DROP_BIN: 4, + EDGE_BUTTON_BAR: 256, + EDGE_BUTTON_CIRCLE: 512 + }), + getUUID4: getUUID4, getUID: (function() { function pad(n) { @@ -505,7 +516,7 @@ /* Constants used to know if a specific action is to be performed when clicking on the canvas */ _CLICKMODE_ADDNODE: 1, _CLICKMODE_STARTEDGE: 2, - _CLICKMODE_ENDEDGE: 3, + _CLICKMODE_ENDEDGE: 4, /* Node size step: Used to calculate the size change when clicking the +/- buttons */ _NODE_SIZE_STEP: Math.LN2 / 4, _MIN_SCALE: 1 / 20, diff -r 192ce5938726 -r 02e3c464223f client/js/models.js --- a/client/js/models.js Thu Jun 23 17:50:37 2016 +0200 +++ b/client/js/models.js Fri Jun 24 13:07:21 2016 +0200 @@ -1,19 +1,20 @@ (function(root) { - "use strict"; + 'use strict'; var Backbone = root.Backbone; var Models = root.Rkns.Models = {}; Models.getUID = function(obj) { - var guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, - function(c) { - var r = Math.random() * 16 | 0, v = c === 'x' ? r - : (r & 0x3 | 0x8); - return v.toString(16); - }); + var guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' + .replace(/[xy]/g, + function(c) { + var r = Math.random() * 16 | 0, v = c === 'x' ? r + : (r & 0x3 | 0x8); + return v.toString(16); + }); if (typeof obj !== 'undefined') { - return obj.type + "-" + guid; + return obj.type + '-' + guid; } else { return guid; @@ -21,16 +22,16 @@ }; var RenkanModel = Backbone.RelationalModel.extend({ - idAttribute : "_id", + idAttribute : '_id', constructor : function(options) { - if (typeof options !== "undefined") { + if (typeof options !== 'undefined') { options._id = options._id || options.id || Models.getUID(this); - options.title = options.title || ""; - options.description = options.description || ""; - options.uri = options.uri || ""; + options.title = options.title || ''; + options.description = options.description || ''; + options.uri = options.uri || ''; - if (typeof this.prepare === "function") { + if (typeof this.prepare === 'function') { options = this.prepare(options); } } @@ -38,13 +39,13 @@ }, validate : function() { if (!this.type) { - return "object has no type"; + return 'object has no type'; } }, addReference : function(_options, _propName, _list, _id, _default) { var _element = _list.get(_id); - if (typeof _element === "undefined" && - typeof _default !== "undefined") { + if (typeof _element === 'undefined' && + typeof _default !== 'undefined') { _options[_propName] = _default; } else { @@ -55,115 +56,115 @@ // USER var User = Models.User = RenkanModel.extend({ - type : "user", + type : 'user', prepare : function(options) { - options.color = options.color || "#666666"; + options.color = options.color || '#666666'; return options; }, toJSON : function() { return { - _id : this.get("_id"), - title : this.get("title"), - uri : this.get("uri"), - description : this.get("description"), - color : this.get("color") + _id : this.get('_id'), + title : this.get('title'), + uri : this.get('uri'), + description : this.get('description'), + color : this.get('color') }; } }); // NODE var Node = Models.Node = RenkanModel.extend({ - type : "node", + type : 'node', relations : [ { type : Backbone.HasOne, - key : "created_by", + key : 'created_by', relatedModel : User } ], prepare : function(options) { var project = options.project; - this.addReference(options, "created_by", project.get("users"), - options.created_by, project.current_user); - options.description = options.description || ""; + this.addReference(options, 'created_by', project.get('users'), + options.created_by, project.current_user); + options.description = options.description || ''; return options; }, toJSON : function() { return { - _id : this.get("_id"), - title : this.get("title"), - uri : this.get("uri"), - description : this.get("description"), - position : this.get("position"), - image : this.get("image"), - style : this.get("style"), - created_by : this.get("created_by") ? this.get("created_by") - .get("_id") : null, - size : this.get("size"), - clip_path : this.get("clip_path"), - shape : this.get("shape"), - type : this.get("type") + _id : this.get('_id'), + title : this.get('title'), + uri : this.get('uri'), + description : this.get('description'), + position : this.get('position'), + image : this.get('image'), + style : this.get('style'), + created_by : this.get('created_by') ? this.get('created_by') + .get('_id') : null, + size : this.get('size'), + clip_path : this.get('clip_path'), + shape : this.get('shape'), + type : this.get('type') }; } }); // EDGE var Edge = Models.Edge = RenkanModel.extend({ - type : "edge", + type : 'edge', relations : [ { type : Backbone.HasOne, - key : "created_by", + key : 'created_by', relatedModel : User }, { type : Backbone.HasOne, - key : "from", + key : 'from', relatedModel : Node }, { type : Backbone.HasOne, - key : "to", + key : 'to', relatedModel : Node } ], prepare : function(options) { var project = options.project; - this.addReference(options, "created_by", project.get("users"), - options.created_by, project.current_user); - this.addReference(options, "from", project.get("nodes"), - options.from); - this.addReference(options, "to", project.get("nodes"), options.to); + this.addReference(options, 'created_by', project.get('users'), + options.created_by, project.current_user); + this.addReference(options, 'from', project.get('nodes'), + options.from); + this.addReference(options, 'to', project.get('nodes'), options.to); return options; }, toJSON : function() { return { - _id : this.get("_id"), - title : this.get("title"), - uri : this.get("uri"), - description : this.get("description"), - from : this.get("from") ? this.get("from").get("_id") : null, - to : this.get("to") ? this.get("to").get("_id") : null, - style : this.get("style"), - created_by : this.get("created_by") ? this.get("created_by") - .get("_id") : null + _id : this.get('_id'), + title : this.get('title'), + uri : this.get('uri'), + description : this.get('description'), + from : this.get('from') ? this.get('from').get('_id') : null, + to : this.get('to') ? this.get('to').get('_id') : null, + style : this.get('style'), + created_by : this.get('created_by') ? this.get('created_by') + .get('_id') : null }; } }); // View var View = Models.View = RenkanModel.extend({ - type : "view", + type : 'view', relations : [ { type : Backbone.HasOne, - key : "created_by", + key : 'created_by', relatedModel : User } ], prepare : function(options) { var project = options.project; - this.addReference(options, "created_by", project.get("users"), - options.created_by, project.current_user); - options.description = options.description || ""; - if (typeof options.offset !== "undefined") { + this.addReference(options, 'created_by', project.get('users'), + options.created_by, project.current_user); + options.description = options.description || ''; + if (typeof options.offset !== 'undefined') { var offset = {}; if (Array.isArray(options.offset)) { offset.x = options.offset[0]; offset.y = options.offset.length > 1 ? options.offset[1] - : options.offset[0]; + : options.offset[0]; } else if (options.offset.x != null) { offset.x = options.offset.x; @@ -175,27 +176,27 @@ }, toJSON : function() { return { - _id : this.get("_id"), - zoom_level : this.get("zoom_level"), - offset : this.get("offset"), - title : this.get("title"), - description : this.get("description"), - created_by : this.get("created_by") ? this.get("created_by") - .get("_id") : null, - hidden_nodes: this.get("hidden_nodes") - // Don't need project id + _id : this.get('_id'), + zoom_level : this.get('zoom_level'), + offset : this.get('offset'), + title : this.get('title'), + description : this.get('description'), + created_by : this.get('created_by') ? this.get('created_by') + .get('_id') : null, + hidden_nodes: this.get('hidden_nodes') + // Don't need project id }; } }); // PROJECT var Project = Models.Project = RenkanModel.extend({ - schema_version : "2", - type : "project", + schema_version : '2', + type : 'project', blacklist : [ 'saveStatus', 'loadingStatus'], relations : [ { type : Backbone.HasMany, - key : "users", + key : 'users', relatedModel : User, reverseRelation : { key : 'project', @@ -203,7 +204,7 @@ } }, { type : Backbone.HasMany, - key : "nodes", + key : 'nodes', relatedModel : Node, reverseRelation : { key : 'project', @@ -211,7 +212,7 @@ } }, { type : Backbone.HasMany, - key : "edges", + key : 'edges', relatedModel : Edge, reverseRelation : { key : 'project', @@ -219,7 +220,7 @@ } }, { type : Backbone.HasMany, - key : "views", + key : 'views', relatedModel : View, reverseRelation : { key : 'project', @@ -229,19 +230,19 @@ addUser : function(_props, _options) { _props.project = this; var _user = User.findOrCreate(_props); - this.get("users").push(_user, _options); + this.get('users').push(_user, _options); return _user; }, addNode : function(_props, _options) { _props.project = this; var _node = Node.findOrCreate(_props); - this.get("nodes").push(_node, _options); + this.get('nodes').push(_node, _options); return _node; }, addEdge : function(_props, _options) { _props.project = this; var _edge = Edge.findOrCreate(_props); - this.get("edges").push(_edge, _options); + this.get('edges').push(_edge, _options); return _edge; }, addView : function(_props, _options) { @@ -249,57 +250,57 @@ // TODO: check if need to replace with create only var _view = View.findOrCreate(_props); // TODO: Should we remember only one view? - this.get("views").push(_view, _options); + this.get('views').push(_view, _options); return _view; }, removeNode : function(_model) { - this.get("nodes").remove(_model); + this.get('nodes').remove(_model); }, removeEdge : function(_model) { - this.get("edges").remove(_model); + this.get('edges').remove(_model); }, validate : function(options) { var _project = this; _.each( - [].concat(options.users, options.nodes, options.edges,options.views), - function(_item) { - if (_item) { - _item.project = _project; + [].concat(options.users, options.nodes, options.edges,options.views), + function(_item) { + if (_item) { + _item.project = _project; + } } - } ); }, getSchemaVersion : function(data) { - var t = data; - if(typeof(t) === "undefined") { - t = this; - } - var version = t.schema_version; - if(!version) { - return 1; - } - else { - return version; - } + var t = data; + if(typeof(t) === 'undefined') { + t = this; + } + var version = t.schema_version; + if(!version) { + return 1; + } + else { + return version; + } }, // Add event handler to remove edges when a node is removed initialize : function() { var _this = this; - this.on("remove:nodes", function(_node) { - _this.get("edges").remove( - _this.get("edges").filter( - function(_edge) { - return _edge.get("from") === _node || - _edge.get("to") === _node; - })); + this.on('remove:nodes', function(_node) { + _this.get('edges').remove( + _this.get('edges').filter( + function(_edge) { + return _edge.get('from') === _node || + _edge.get('to') === _node; + })); }); }, toJSON : function() { var json = _.clone(this.attributes); for ( var attr in json) { if ((json[attr] instanceof Backbone.Model) || - (json[attr] instanceof Backbone.Collection) || - (json[attr] instanceof RenkanModel)) { + (json[attr] instanceof Backbone.Collection) || + (json[attr] instanceof RenkanModel)) { json[attr] = json[attr].toJSON(); } } @@ -308,53 +309,53 @@ }); var RosterUser = Models.RosterUser = Backbone.Model - .extend({ - type : "roster_user", - idAttribute : "_id", + .extend({ + type : 'roster_user', + idAttribute : '_id', - constructor : function(options) { + constructor : function(options) { - if (typeof options !== "undefined") { - options._id = options._id || - options.id || - Models.getUID(this); - options.title = options.title || "(untitled " + this.type + ")"; - options.description = options.description || ""; - options.uri = options.uri || ""; - options.project = options.project || null; - options.site_id = options.site_id || 0; + if (typeof options !== 'undefined') { + options._id = options._id || + options.id || + Models.getUID(this); + options.title = options.title || '(untitled ' + this.type + ')'; + options.description = options.description || ''; + options.uri = options.uri || ''; + options.project = options.project || null; + options.site_id = options.site_id || 0; - if (typeof this.prepare === "function") { - options = this.prepare(options); - } + if (typeof this.prepare === 'function') { + options = this.prepare(options); } - Backbone.Model.prototype.constructor.call(this, options); - }, + } + Backbone.Model.prototype.constructor.call(this, options); + }, - validate : function() { - if (!this.type) { - return "object has no type"; - } - }, + validate : function() { + if (!this.type) { + return 'object has no type'; + } + }, - prepare : function(options) { - options.color = options.color || "#666666"; - return options; - }, + prepare : function(options) { + options.color = options.color || '#666666'; + return options; + }, - toJSON : function() { - return { - _id : this.get("_id"), - title : this.get("title"), - uri : this.get("uri"), - description : this.get("description"), - color : this.get("color"), - project : (this.get("project") != null) ? this.get( - "project").get("id") : null, - site_id : this.get("site_id") - }; - } - }); + toJSON : function() { + return { + _id : this.get('_id'), + title : this.get('title'), + uri : this.get('uri'), + description : this.get('description'), + color : this.get('color'), + project : (this.get('project') != null) ? this.get( + 'project').get('id') : null, + site_id : this.get('site_id') + }; + } + }); var UsersList = Models.UsersList = Backbone.Collection.extend({ model : RosterUser diff -r 192ce5938726 -r 02e3c464223f client/js/renderer/nodelinkbutton.js --- a/client/js/renderer/nodelinkbutton.js Thu Jun 23 17:50:37 2016 +0200 +++ b/client/js/renderer/nodelinkbutton.js Fri Jun 24 13:07:21 2016 +0200 @@ -22,12 +22,12 @@ if (this.renderer.isEditable()) { var _off = this.renderer.canvas_$.offset(), _point = new paper.Point([ - _event.pageX - _off.left, - _event.pageY - _off.top - ]); + _event.pageX - _off.left, + _event.pageY - _off.top + ]); this.renderer.click_target = null; this.renderer.removeRepresentationsOfType("editor"); - this.renderer.addTempEdge(this.source_representation, _point); + this.renderer.addTempEdge(this.source_representation, _point, Utils.OriginEnum.EDGE_BUTTON_CIRCLE); } } }).value(); diff -r 192ce5938726 -r 02e3c464223f client/js/renderer/scene.js --- a/client/js/renderer/scene.js Thu Jun 23 17:50:37 2016 +0200 +++ b/client/js/renderer/scene.js Fri Jun 24 13:07:21 2016 +0200 @@ -1,7 +1,7 @@ define(['jquery', 'underscore', 'filesaver', 'requtils', 'renderer/miniframe', 'screenfull'], function ($, _, filesaver, requtils, MiniFrame, Screenfull) { 'use strict'; - + var Utils = requtils.getUtils(); /* Scene Begin */ @@ -240,37 +240,37 @@ this.$.find(".Rk-Users").mouseleave( function() { _this.$.find(".Rk-UserList").slideUp(); } ); - + if (Screenfull.enabled){ bindClick(".Rk-FullScreen-Button", "fullScreen"); - + document.addEventListener(Screenfull.raw.fullscreenchange, function () { //the listener occur too randomly and sometimes before the fullscreen is fully set up //so we add 500 delay setTimeout(function(){ var widthAft = _this.$.width(); var heightAft = _this.$.height(); - + if (_this.renkan.options.show_top_bar) { heightAft -= _this.$.find(".Rk-TopBar").height(); } if (_this.renkan.options.show_bins && (this.renkan.$.find(".Rk-Bins").position().left > 0)) { widthAft -= this.renkan.$.find(".Rk-Bins").width(); } - + paper.view.viewSize = new paper.Size([widthAft, heightAft]); _this.resize(_this.currentWidth, widthAft, _this.currentHeight, heightAft); - + _this.currentWidth = widthAft; _this.currentHeight = heightAft; - + if (!Screenfull.isFullscreen) { paper.view.onResize = function(_event) { var newWidth = _event.size._width, newHeight = _event.size._height; var prevHeight = newHeight - _event.delta.height, prevWidth = newWidth - _event.delta.width; - + _this.resize(prevWidth, newWidth, prevHeight, newHeight); }; } @@ -280,7 +280,7 @@ this.$.find(".Rk-FullScreen-Button").addClass("disabled"); this.$.find(".Rk-FullScreen-Button .Rk-TopBar-Tooltip-Contents").html(this.renkan.translate("Fullscreen not supported by your browser")); } - + bindClick(".Rk-AddNode-Button", "addNodeBtn"); bindClick(".Rk-AddEdge-Button", "addEdgeBtn"); bindClick(".Rk-Save-Button", "save"); @@ -309,7 +309,7 @@ newHeight = _event.size._height; var prevHeight = newHeight - _event.delta.height, prevWidth = newWidth - _event.delta.width; - + _this.resize(prevWidth, newWidth, prevHeight, newHeight); }); @@ -353,22 +353,22 @@ break; } }); - + this.renkan.project.on("loaded", function(){ if (_this.renkan.options.url_parameters){ - Backbone.history.start(); + Backbone.history.start(); } else { _this.fixSize(); } _this.redrawActive = true; _thRedraw(); }); - + //register router events this.renkan.router.on("router", function(_params){ _this.setViewparameters(_params); }); - + this.renkan.project.on("change:loadingStatus", function(){ if (_this.renkan.project.get("loadingStatus")){ var animate = _this.$.find(".loader").addClass("run"); @@ -836,13 +836,13 @@ }, resize: function(prevWidth, newWidth, prevHeight, newHeight){ var _ratio; - + if (this.minimap) { this.minimap.topleft = paper.view.bounds.bottomRight.subtract(this.minimap.size); this.minimap.rectangle.fitBounds(this.minimap.topleft.subtract([2,2]), this.minimap.size.add([4,4])); this.minimap.cliprectangle.fitBounds(this.minimap.topleft, this.minimap.size); } - + var ratioH = newHeight/prevHeight, ratioW = newWidth/prevWidth; if (newHeight < newWidth) { @@ -851,13 +851,14 @@ _ratio = ratioW; } this.view.resizeZoom(newWidth - prevWidth, newHeight - prevHeight, _ratio); - + this.redraw(); }, - addTempEdge: function(_from, _point) { + addTempEdge: function(_from, _point, _origin) { var _tmpEdge = this.addRepresentation("TempEdge",null); _tmpEdge.end_pos = _point; _tmpEdge.from_representation = _from; + _tmpEdge.origin = _origin; _tmpEdge.redraw(); this.click_target = _tmpEdge; }, @@ -926,7 +927,8 @@ position: { x: _coords.x, y: _coords.y - } + }, + origin: Utils.OriginEnum.NODE_BUTTON }; var _node = this.renkan.project.addNode(_data); this.getRepresentationByModel(_node).openEditor(); @@ -936,7 +938,7 @@ if (this.click_mode) { if (this.isEditable() && this.click_mode === Utils._CLICKMODE_STARTEDGE && this.click_target && this.click_target.type === "Node") { this.removeRepresentationsOfType("editor"); - this.addTempEdge(this.click_target, _point); + this.addTempEdge(this.click_target, _point, Utils.OriginEnum.EDGE_BUTTON_BAR); this.click_mode = Utils._CLICKMODE_ENDEDGE; this.notif_$.fadeOut(function() { $(this).html(this.renkan.translate("Click on a second node to complete the edge")).fadeIn(); @@ -1011,7 +1013,8 @@ position: { x: _coords.x, y: _coords.y - } + }, + origin: Utils.OriginEnum.NODE_DOUBLE_CLICK }, _node = this.renkan.project.addNode(_data); this.getRepresentationByModel(_node).openEditor(); @@ -1122,25 +1125,27 @@ var newNode = (typeof this.renkan.options.drop_handler === "undefined")?this.defaultDropHandler(_data):this.renkan.options.drop_handler(_data); var _off = this.canvas_$.offset(), - _point = new paper.Point([ - _event.pageX - _off.left, - _event.pageY - _off.top - ]), - _coords = this.toModelCoords(_point), - _nodedata = { - id: Utils.getUID('node'), - created_by: this.renkan.current_user, - uri: newNode.uri || "", - title: newNode.title || "", - description: newNode.description || "", - image: newNode.image || "", - color: newNode.color || undefined, - clip_path: newNode.clipPath || undefined, - position: { - x: _coords.x, - y: _coords.y - } - }; + _point = new paper.Point([ + _event.pageX - _off.left, + _event.pageY - _off.top + ]), + _coords = this.toModelCoords(_point), + _nodedata = { + id: Utils.getUID('node'), + created_by: this.renkan.current_user, + uri: newNode.uri || "", + title: newNode.title || "", + description: newNode.description || "", + image: newNode.image || "", + color: newNode.color || undefined, + clip_path: newNode.clipPath || undefined, + position: { + x: _coords.x, + y: _coords.y + }, + //TODO: Determine if it comes from bin or ext + origin: Utils.OriginEnum.NODE_DROP_EXT + }; var _node = this.renkan.project.addNode(_nodedata), _repr = this.getRepresentationByModel(_node); if (_event.type === "drop") { @@ -1150,7 +1155,7 @@ fullScreen: function() { this.currentWidth = this.$.width(); this.currentHeight = this.$.height(); - + var _el = this.renkan.$[0]; paper.view.off("resize"); Screenfull.toggle(_el); diff -r 192ce5938726 -r 02e3c464223f client/js/renderer/tempedge.js --- a/client/js/renderer/tempedge.js Thu Jun 23 17:50:37 2016 +0200 +++ b/client/js/renderer/tempedge.js Fri Jun 24 13:07:21 2016 +0200 @@ -14,6 +14,7 @@ _init: function() { this.renderer.edge_layer.activate(); this.type = "Temp-edge"; + this.origin = Utils.OriginEnum.NONE; var _color = (this.project.get("users").get(this.renkan.current_user) || Utils._USER_PLACEHOLDER(this.renkan)).get("color"); this.line = new paper.Path(); @@ -56,18 +57,19 @@ }, mouseup: function(_event, _isTouch) { var _hitResult = paper.project.hitTest(_event.point), - _model = this.from_representation.model, - _endDrag = true; + _model = this.from_representation.model, + _endDrag = true; if (_hitResult && typeof _hitResult.item.__representation !== "undefined") { var _target = _hitResult.item.__representation; if (_target.type.substr(0,4) === "Node") { var _destmodel = _target.model || _target.source_representation.model; if (_model !== _destmodel) { var _data = { - id: Utils.getUID('edge'), - created_by: this.renkan.current_user, - from: _model, - to: _destmodel + id: Utils.getUID('edge'), + created_by: this.renkan.current_user, + from: _model, + to: _destmodel, + origin: this.origin }; if (this.renderer.isEditable()) { this.project.addEdge(_data);