diff -r 5cb7bdc8b028 -r 900467290a0a client/js/paper-renderer.js
--- a/client/js/paper-renderer.js Fri Apr 25 17:03:31 2014 +0200
+++ b/client/js/paper-renderer.js Sat Apr 26 14:29:36 2014 +0200
@@ -1,39 +1,38 @@
/* paper-renderer.js */
+"use strict";
(function(root) {
-"use strict";
-
-var Rkns = root.Rkns,
+ var Rkns = root.Rkns,
_ = Rkns._,
$ = Rkns.$;
-/* Rkns.Renderer Object */
+ /* Rkns.Renderer Object */
-/* This object contains constants, utility functions and classes for Renkan's Graph Manipulation GUI */
+ /* This object contains constants, utility functions and classes for Renkan's Graph Manipulation GUI */
-var Renderer = Rkns.Renderer = {},
- /* The minimum distance (in pixels) the mouse has to move to consider an element was dragged */
+ var Renderer = Rkns.Renderer = {},
+ /* The minimum distance (in pixels) the mouse has to move to consider an element was dragged */
_MIN_DRAG_DISTANCE = 2,
- /* Distance between the inner and outer radius of buttons that appear when hovering on a node */
+ /* Distance between the inner and outer radius of buttons that appear when hovering on a node */
_NODE_BUTTON_WIDTH = 40,
-
+
_EDGE_BUTTON_INNER = 2,
_EDGE_BUTTON_OUTER = 40,
- /* Constants used to know if a specific action is to be performed when clicking on the canvas */
+ /* 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,
- /* Node size step: Used to calculate the size change when clicking the +/- buttons */
+ /* Node size step: Used to calculate the size change when clicking the +/- buttons */
_NODE_SIZE_STEP = Math.LN2/4,
_MIN_SCALE = 1/20,
_MAX_SCALE = 20,
_MOUSEMOVE_RATE = 80,
_DOUBLETAP_DELAY = 800,
- /* Maximum distance in pixels (squared, to reduce calculations)
- * between two taps when double-tapping on a touch terminal */
+ /* Maximum distance in pixels (squared, to reduce calculations)
+ * between two taps when double-tapping on a touch terminal */
_DOUBLETAP_DISTANCE = 20*20,
- /* A placeholder so a default colour is displayed when a node has a null value for its user property */
+ /* A placeholder so a default colour is displayed when a node has a null value for its user property */
_USER_PLACEHOLDER = function(_renkan) {
return {
color: _renkan.options.default_user_color,
@@ -43,29 +42,29 @@
}
};
},
- /* The code for the "Drag and Add Bookmarklet", slightly minified and with whitespaces removed, though
- * it doesn't seem that it's still a requirement in newer browsers (i.e. the ones compatibles with canvas drawing)
- */
+ /* The code for the "Drag and Add Bookmarklet", slightly minified and with whitespaces removed, though
+ * it doesn't seem that it's still a requirement in newer browsers (i.e. the ones compatibles with canvas drawing)
+ */
_BOOKMARKLET_CODE = function(_renkan) {
return "(function(a,b,c,d,e,f,h,i,j,k,l,m,n,o,p,q,r){a=document;b=a.body;c=a.location.href;j='draggable';m='text/x-iri-';d=a.createElement('div');d.innerHTML='
<%-renkan.translate("Size:")%>-<%-node.size%>+
<% } %>' + + '<% if (options.show_node_editor_color) { %><%-renkan.translate("Created by:")%> <%- shortenText(node.created_by_title, 25) %>
<% } %>' + ), + readOnlyTemplate: _.template( + '<%-node.description%>
<% } %>' + + '<% if (node.image && options.show_node_tooltip_image) { %><%-renkan.translate("Created by:")%><%- shortenText(node.created_by_title, 25) %>
<% } %>' + ), + draw: function() { + var _model = this.source_representation.model, + _created_by = _model.get("created_by") || _USER_PLACEHOLDER(this.renkan), + _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate ), + _image_placeholder = this.options.static_url + "img/image-placeholder.png", + _size = (_model.get("size") || 0); + this.editor_$ + .html(_template({ + node: { + has_creator: !!_model.get("created_by"), + title: _model.get("title"), + uri: _model.get("uri"), + short_uri: shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40), + description: _model.get("description"), + image: _model.get("image") || "", + image_placeholder: _image_placeholder, + color: _model.get("color") || _created_by.get("color"), + clip_path: _model.get("clip_path") || false, + created_by_color: _created_by.get("color"), + created_by_title: _created_by.get("title"), + size: (_size > 0 ? "+" : "") + _size + }, + renkan: this.renkan, + options: this.options, + shortenText: shortenText + })); + this.redraw(); + var _this = this, + closeEditor = function() { + _this.renderer.removeRepresentation(_this); + paper.view.draw(); + }; + + this.editor_$.find(".Rk-CloseX").click(closeEditor); + + this.editor_$.find(".Rk-Edit-Goto").click(function() { + if (!_model.get("uri")) { + return false; + } + }); + + if (this.renderer.isEditable()) { -/* */ + var onFieldChange = _(function() { + _(function() { + if (_this.renderer.isEditable()) { + var _data = { + title: _this.editor_$.find(".Rk-Edit-Title").val() + }; + if (_this.options.show_node_editor_uri) { + _data.uri = _this.editor_$.find(".Rk-Edit-URI").val(); + _this.editor_$.find(".Rk-Edit-Goto").attr("href",_data.uri || "#"); + } + if (_this.options.show_node_editor_image) { + _data.image = _this.editor_$.find(".Rk-Edit-Image").val(); + _this.editor_$.find(".Rk-Edit-ImgPreview").attr("src", _data.image || _image_placeholder); + } + if (_this.options.show_node_editor_description) { + _data.description = _this.editor_$.find(".Rk-Edit-Description").val(); + } + _model.set(_data); + _this.redraw(); + } else { + closeEditor(); + } + + }).defer(); + }).throttle(500); + + this.editor_$.on("keyup", function(_e) { + if (_e.keyCode === 27) { + closeEditor(); + } + }); + + this.editor_$.find("input, textarea").on("change keyup paste", onFieldChange); -var TempEdge = Renderer.TempEdge = Rkns.Utils.inherit(_BaseRepresentation); + this.editor_$.find(".Rk-Edit-Image-File").change(function() { + if (this.files.length) { + var f = this.files[0], + fr = new FileReader(); + if (f.type.substr(0,5) !== "image") { + alert(_this.renkan.translate("This file is not an image")); + return; + } + if (f.size > (_this.options.uploaded_image_max_kb * 1024)) { + alert(_this.renkan.translate("Image size must be under ") + _this.options.uploaded_image_max_kb + _this.renkan.translate("KB")); + return; + } + fr.onload = function(e) { + _this.editor_$.find(".Rk-Edit-Image").val(e.target.result); + onFieldChange(); + }; + fr.readAsDataURL(f); + } + }); + this.editor_$.find(".Rk-Edit-Title")[0].focus(); + + var _picker = _this.editor_$.find(".Rk-Edit-ColorPicker"); + + this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover( + function(_e) { + _e.preventDefault(); + _picker.show(); + }, + function(_e) { + _e.preventDefault(); + _picker.hide(); + } + ); + + _picker.find("li").hover( + function(_e) { + _e.preventDefault(); + _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color")); + }, + function(_e) { + _e.preventDefault(); + _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || _USER_PLACEHOLDER(_this.renkan)).get("color")); + } + ).click(function(_e) { + _e.preventDefault(); + if (_this.renderer.isEditable()) { + _model.set("color", $(this).attr("data-color")); + _picker.hide(); + paper.view.draw(); + } else { + closeEditor(); + } + }); -_(TempEdge.prototype).extend({ -_init: function() { - this.renderer.edge_layer.activate(); - this.type = "Temp-edge"; - - var _color = (this.project.get("users").get(this.renkan.current_user) || _USER_PLACEHOLDER(this.renkan)).get("color"); - this.line = new paper.Path(); - this.line.strokeColor = _color; - this.line.dashArray = [4, 2]; - this.line.strokeWidth = this.options.selected_edge_stroke_width; - this.line.add([0,0],[0,0]); - this.line.__representation = this; - this.arrow = new paper.Path(); - this.arrow.fillColor = _color; - this.arrow.add( - [ 0, 0 ], - [ this.options.edge_arrow_length, this.options.edge_arrow_width / 2 ], - [ 0, this.options.edge_arrow_width ] - ); - this.arrow.__representation = this; - this.arrow_angle = 0; -}, -redraw: function() { - var _p0 = this.from_representation.paper_coords, - _p1 = this.end_pos, - _a = _p1.subtract(_p0).angle, - _c = _p0.add(_p1).divide(2); - this.line.segments[0].point = _p0; - this.line.segments[1].point = _p1; - this.arrow.rotate(_a - this.arrow_angle); - this.arrow.position = _c; - this.arrow_angle = _a; -}, -paperShift: function(_delta) { - if (!this.renderer.isEditable()) { - this.renderer.removeRepresentation(_this); - paper.view.draw(); - return; - } - this.end_pos = this.end_pos.add(_delta); - var _hitResult = paper.project.hitTest(this.end_pos); - this.renderer.findTarget(_hitResult); - this.redraw(); -}, -mouseup: function(_event, _isTouch) { - var _hitResult = paper.project.hitTest(_event.point), - _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: Rkns.Utils.getUID('edge'), - created_by: this.renkan.current_user, - from: _model, - to: _destmodel + var shiftSize = function(n) { + if (_this.renderer.isEditable()) { + var _newsize = n+(_model.get("size") || 0); + _this.editor_$.find(".Rk-Edit-Size-Value").text((_newsize > 0 ? "+" : "") + _newsize); + _model.set("size", _newsize); + paper.view.draw(); + } else { + closeEditor(); + } }; - if (this.renderer.isEditable()) { - this.project.addEdge(_data); + + this.editor_$.find(".Rk-Edit-Size-Down").click(function() { + shiftSize(-1); + return false; + }); + this.editor_$.find(".Rk-Edit-Size-Up").click(function() { + shiftSize(1); + return false; + }); + } else { + if (typeof this.source_representation.highlighted === "object") { + var titlehtml = this.source_representation.highlighted.replace(_(_model.get("title")).escape(),'$1'); + this.editor_$.find(".Rk-Display-Title" + (_model.get("uri") ? " a" : "")).html(titlehtml); + if (this.options.show_node_tooltip_description) { + this.editor_$.find(".Rk-Display-Description").html(this.source_representation.highlighted.replace(_(_model.get("description")).escape(),'$1')); + } + } + } + this.editor_$.find("img").load(function() { + _this.redraw(); + }); + }, + redraw: function() { + var _coords = this.source_representation.paper_coords; + drawEditBox(this.options, _coords, this.editor_block, this.source_representation.circle_radius * .75, this.editor_$); + this.editor_$.show(); + paper.view.draw(); + } + }); + + /* */ + + var EdgeEditor = Renderer.EdgeEditor = Rkns.Utils.inherit(_BaseEditor); + + _(EdgeEditor.prototype).extend({ + template: _.template( + '<%- renkan.translate("Change edge direction") %>
<% } %>' + + '<% if (options.show_edge_editor_nodes) { %><%-renkan.translate("From:")%><%- shortenText(edge.from_title, 25) %>
' + + '<%-renkan.translate("To:")%><%- shortenText(edge.to_title, 25) %>
<% } %>' + + '<% if (options.show_edge_editor_creator && edge.has_creator) { %><%-renkan.translate("Created by:")%><%- shortenText(edge.created_by_title, 25) %>
<% } %>' + ), + readOnlyTemplate: _.template( + '<%-edge.description%>
' + + '<% if (options.show_edge_tooltip_nodes) { %><%-renkan.translate("From:")%><%- shortenText(edge.from_title, 25) %>
' + + '<%-renkan.translate("To:")%><%- shortenText(edge.to_title, 25) %>
<% } %>' + + '<% if (options.show_edge_tooltip_creator && edge.has_creator) { %><%-renkan.translate("Created by:")%><%- shortenText(edge.created_by_title, 25) %>
<% } %>' + ), + draw: function() { + var _model = this.source_representation.model, + _from_model = _model.get("from"), + _to_model = _model.get("to"), + _created_by = _model.get("created_by") || _USER_PLACEHOLDER(this.renkan), + _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate); + this.editor_$ + .html(_template({ + edge: { + has_creator: !!_model.get("created_by"), + title: _model.get("title"), + uri: _model.get("uri"), + short_uri: shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40), + description: _model.get("description"), + color: _model.get("color") || _created_by.get("color"), + from_title: _from_model.get("title"), + to_title: _to_model.get("title"), + from_color: _from_model.get("color") || (_from_model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color"), + to_color: _to_model.get("color") || (_to_model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color"), + created_by_color: _created_by.get("color"), + created_by_title: _created_by.get("title") + }, + renkan: this.renkan, + shortenText: shortenText, + options: this.options + })); + this.redraw(); + var _this = this, + closeEditor = function() { + _this.renderer.removeRepresentation(_this); + paper.view.draw(); + }; + this.editor_$.find(".Rk-CloseX").click(closeEditor); + this.editor_$.find(".Rk-Edit-Goto").click(function() { + if (!_model.get("uri")) { + return false; + } + }); + + if (this.renderer.isEditable()) { + + var onFieldChange = _(function() { + _(function() { + if (_this.renderer.isEditable()) { + var _data = { + title: _this.editor_$.find(".Rk-Edit-Title").val() + }; + if (_this.options.show_edge_editor_uri) { + _data.uri = _this.editor_$.find(".Rk-Edit-URI").val(); + } + _this.editor_$.find(".Rk-Edit-Goto").attr("href",_data.uri || "#"); + _model.set(_data); + paper.view.draw(); + } else { + closeEditor(); + } + }).defer(); + }).throttle(500); + + this.editor_$.on("keyup", function(_e) { + if (_e.keyCode === 27) { + closeEditor(); + } + }); + + this.editor_$.find("input").on("keyup change paste", onFieldChange); + + this.editor_$.find(".Rk-Edit-Vocabulary").change(function() { + var e = $(this), + v = e.val(); + if (v) { + _this.editor_$.find(".Rk-Edit-Title").val(e.find(":selected").text()); + _this.editor_$.find(".Rk-Edit-URI").val(v); + onFieldChange(); + } + }); + this.editor_$.find(".Rk-Edit-Direction").click(function() { + if (_this.renderer.isEditable()) { + _model.set({ + from: _model.get("to"), + to: _model.get("from") + }); + _this.draw(); + } else { + closeEditor(); + } + }); + + var _picker = _this.editor_$.find(".Rk-Edit-ColorPicker"); + + this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover( + function(_e) { + _e.preventDefault(); + _picker.show(); + }, + function(_e) { + _e.preventDefault(); + _picker.hide(); + } + ); + + _picker.find("li").hover( + function(_e) { + _e.preventDefault(); + _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color")); + }, + function(_e) { + _e.preventDefault(); + _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || _USER_PLACEHOLDER(_this.renkan)).get("color")); + } + ).click(function(_e) { + _e.preventDefault(); + if (_this.renderer.isEditable()) { + _model.set("color", $(this).attr("data-color")); + _picker.hide(); + paper.view.draw(); + } else { + closeEditor(); + } + }); + } + }, + redraw: function() { + var _coords = this.source_representation.paper_coords; + drawEditBox(this.options, _coords, this.editor_block, 5, this.editor_$); + this.editor_$.show(); + paper.view.draw(); + } + }); + + /* */ + + var _NodeButton = Renderer._NodeButton = Rkns.Utils.inherit(_BaseButton); + + _(_NodeButton.prototype).extend({ + setSectorSize: function() { + var sectorInner = this.source_representation.circle_radius; + if (sectorInner !== this.lastSectorInner) { + if (this.sector) { + this.sector.destroy(); + } + this.sector = this.renderer.drawSector( + this, 1 + sectorInner, + _NODE_BUTTON_WIDTH + sectorInner, + this.startAngle, + this.endAngle, + 1, + this.imageName, + this.renkan.translate(this.text) + ); + this.lastSectorInner = sectorInner; + } + } + }); + + /* */ + + var NodeEditButton = Renderer.NodeEditButton = Rkns.Utils.inherit(_NodeButton); + + _(NodeEditButton.prototype).extend({ + _init: function() { + this.type = "Node-edit-button"; + this.lastSectorInner = 0; + this.startAngle = -135; + this.endAngle = -45; + this.imageName = "edit"; + this.text = "Edit"; + }, + mouseup: function() { + if (!this.renderer.is_dragging) { + this.source_representation.openEditor(); + } + } + }); + + /* */ + + var NodeRemoveButton = Renderer.NodeRemoveButton = Rkns.Utils.inherit(_NodeButton); + + _(NodeRemoveButton.prototype).extend({ + _init: function() { + this.type = "Node-remove-button"; + this.lastSectorInner = 0; + this.startAngle = 0; + this.endAngle = 90; + this.imageName = "remove"; + this.text = "Remove"; + }, + mouseup: function() { + this.renderer.click_target = null; + this.renderer.is_dragging = false; + this.renderer.removeRepresentationsOfType("editor"); + if (this.renderer.isEditable()) { + if (this.options.element_delete_delay) { + var delid = Rkns.Utils.getUID("delete"); + this.renderer.delete_list.push({ + id: delid, + time: new Date().valueOf() + this.options.element_delete_delay + }); + this.source_representation.model.set("delete_scheduled", delid); + } else { + if (confirm(this.renkan.translate('Do you really wish to remove node ') + '"' + this.source_representation.model.get("title") + '"?')) { + this.project.removeNode(this.source_representation.model); + } } } } - - if (_model === _target.model || (_target.source_representation && _target.source_representation.model === _model)) { - _endDrag = false; - this.renderer.is_dragging = true; - } - } - if (_endDrag) { - this.renderer.click_target = null; - this.renderer.is_dragging = false; - this.renderer.removeRepresentation(this); - paper.view.draw(); - } -}, -destroy: function() { - this.arrow.remove(); - this.line.remove(); -} -}); + }); -/* */ + /* */ -var _BaseEditor = Renderer._BaseEditor = Rkns.Utils.inherit(_BaseRepresentation); + var NodeRevertButton = Renderer.NodeRevertButton = Rkns.Utils.inherit(_NodeButton); -_(_BaseEditor.prototype).extend({ -_init: function() { - this.renderer.buttons_layer.activate(); - this.type = "editor"; - this.editor_block = new paper.Path(); - var _pts = _(_.range(8)).map(function() {return [0,0];}); - this.editor_block.add.apply(this.editor_block, _pts); - this.editor_block.strokeWidth = this.options.tooltip_border_width; - this.editor_block.strokeColor = this.options.tooltip_border_color; - this.editor_block.opacity = .8; - this.editor_$ = $('<%-renkan.translate("Size:")%>-<%-node.size%>+
<% } %>' - + '<% if (options.show_node_editor_color) { %><%-renkan.translate("Created by:")%> <%- shortenText(node.created_by_title, 25) %>
<% } %>' -), -readOnlyTemplate: _.template( - '<%-node.description%>
<% } %>' - + '<% if (node.image && options.show_node_tooltip_image) { %><%-renkan.translate("Created by:")%><%- shortenText(node.created_by_title, 25) %>
<% } %>' -), -draw: function() { - var _model = this.source_representation.model, - _created_by = _model.get("created_by") || _USER_PLACEHOLDER(this.renkan), - _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate ), - _image_placeholder = this.options.static_url + "img/image-placeholder.png", - _size = (_model.get("size") || 0); - this.editor_$ - .html(_template({ - node: { - has_creator: !!_model.get("created_by"), - title: _model.get("title"), - uri: _model.get("uri"), - short_uri: shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40), - description: _model.get("description"), - image: _model.get("image") || "", - image_placeholder: _image_placeholder, - color: _model.get("color") || _created_by.get("color"), - clip_path: _model.get("clip_path") || false, - created_by_color: _created_by.get("color"), - created_by_title: _created_by.get("title"), - size: (_size > 0 ? "+" : "") + _size - }, - renkan: this.renkan, - options: this.options, - shortenText: shortenText - })); - this.redraw(); - var _this = this, - closeEditor = function() { - _this.renderer.removeRepresentation(_this); - paper.view.draw(); - }; - - this.editor_$.find(".Rk-CloseX").click(closeEditor); - - this.editor_$.find(".Rk-Edit-Goto").click(function() { - if (!_model.get("uri")) { - return false; + /* */ + + var NodeLinkButton = Renderer.NodeLinkButton = Rkns.Utils.inherit(_NodeButton); + + _(NodeLinkButton.prototype).extend({ + _init: function() { + this.type = "Node-link-button"; + this.lastSectorInner = 0; + this.startAngle = 90; + this.endAngle = 180; + this.imageName = "link"; + this.text = "Link to another node"; + }, + mousedown: function(_event, _isTouch) { + if (this.renderer.isEditable()) { + var _off = this.renderer.canvas_$.offset(), + _point = new paper.Point([ + _event.pageX - _off.left, + _event.pageY - _off.top + ]); + this.renderer.click_target = null; + this.renderer.removeRepresentationsOfType("editor"); + this.renderer.addTempEdge(this.source_representation, _point); + } } }); - - if (this.renderer.isEditable()) { - - var onFieldChange = _(function() { - _(function() { - if (_this.renderer.isEditable()) { - var _data = { - title: _this.editor_$.find(".Rk-Edit-Title").val() - }; - if (_this.options.show_node_editor_uri) { - _data.uri = _this.editor_$.find(".Rk-Edit-URI").val(); - _this.editor_$.find(".Rk-Edit-Goto").attr("href",_data.uri || "#"); - } - if (_this.options.show_node_editor_image) { - _data.image = _this.editor_$.find(".Rk-Edit-Image").val(); - _this.editor_$.find(".Rk-Edit-ImgPreview").attr("src", _data.image || _image_placeholder); - } - if (_this.options.show_node_editor_description) { - _data.description = _this.editor_$.find(".Rk-Edit-Description").val(); - } - _model.set(_data); - _this.redraw(); - } else { - closeEditor(); - } - - }).defer(); - }).throttle(500); - - this.editor_$.on("keyup", function(_e) { - if (_e.keyCode === 27) { - closeEditor(); - } - }); - - this.editor_$.find("input, textarea").on("change keyup paste", onFieldChange); - - this.editor_$.find(".Rk-Edit-Image-File").change(function() { - if (this.files.length) { - var f = this.files[0], - fr = new FileReader(); - if (f.type.substr(0,5) !== "image") { - alert(_this.renkan.translate("This file is not an image")); - return; - } - if (f.size > (_this.options.uploaded_image_max_kb * 1024)) { - alert(_this.renkan.translate("Image size must be under ") + _this.options.uploaded_image_max_kb + _this.renkan.translate("KB")); - return; - } - fr.onload = function(e) { - _this.editor_$.find(".Rk-Edit-Image").val(e.target.result); - onFieldChange(); - }; - fr.readAsDataURL(f); - } - }); - this.editor_$.find(".Rk-Edit-Title")[0].focus(); - - var _picker = _this.editor_$.find(".Rk-Edit-ColorPicker"); - - this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover( - function(_e) { - _e.preventDefault(); - _picker.show(); - }, - function(_e) { - _e.preventDefault(); - _picker.hide(); - } - ); - - _picker.find("li").hover( - function(_e) { - _e.preventDefault(); - _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color")); - }, - function(_e) { - _e.preventDefault(); - _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || _USER_PLACEHOLDER(_this.renkan)).get("color")); - } - ).click(function(_e) { - _e.preventDefault(); - if (_this.renderer.isEditable()) { - _model.set("color", $(this).attr("data-color")); - _picker.hide(); - paper.view.draw(); - } else { - closeEditor(); + + /* */ + + var NodeEnlargeButton = Renderer.NodeEnlargeButton = Rkns.Utils.inherit(_NodeButton); + + _(NodeEnlargeButton.prototype).extend({ + _init: function() { + this.type = "Node-enlarge-button"; + this.lastSectorInner = 0; + this.startAngle = -45; + this.endAngle = 0; + this.imageName = "enlarge"; + this.text = "Enlarge"; + }, + mouseup: function() { + var _newsize = 1 + (this.source_representation.model.get("size") || 0); + this.source_representation.model.set("size", _newsize); + this.source_representation.select(); + this.select(); + paper.view.draw(); + } + }); + + /* */ + + var NodeShrinkButton = Renderer.NodeShrinkButton = Rkns.Utils.inherit(_NodeButton); + + _(NodeShrinkButton.prototype).extend({ + _init: function() { + this.type = "Node-shrink-button"; + this.lastSectorInner = 0; + this.startAngle = -180; + this.endAngle = -135; + this.imageName = "shrink"; + this.text = "Shrink"; + }, + mouseup: function() { + var _newsize = -1 + (this.source_representation.model.get("size") || 0); + this.source_representation.model.set("size", _newsize); + this.source_representation.select(); + this.select(); + paper.view.draw(); + } + }); + + /* */ + + var EdgeEditButton = Renderer.EdgeEditButton = Rkns.Utils.inherit(_BaseButton); + + _(EdgeEditButton.prototype).extend({ + _init: function() { + this.type = "Edge-edit-button"; + this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -270, -90, 1, "edit", this.renkan.translate("Edit")); + }, + mouseup: function() { + if (!this.renderer.is_dragging) { + this.source_representation.openEditor(); } - }); - - var shiftSize = function(n) { - if (_this.renderer.isEditable()) { - var _newsize = n+(_model.get("size") || 0); - _this.editor_$.find(".Rk-Edit-Size-Value").text((_newsize > 0 ? "+" : "") + _newsize); - _model.set("size", _newsize); - paper.view.draw(); - } else { - closeEditor(); - } - }; - - this.editor_$.find(".Rk-Edit-Size-Down").click(function() { - shiftSize(-1); - return false; - }); - this.editor_$.find(".Rk-Edit-Size-Up").click(function() { - shiftSize(1); - return false; - }); - } else { - if (typeof this.source_representation.highlighted === "object") { - var titlehtml = this.source_representation.highlighted.replace(_(_model.get("title")).escape(),'$1'); - this.editor_$.find(".Rk-Display-Title" + (_model.get("uri") ? " a" : "")).html(titlehtml); - if (this.options.show_node_tooltip_description) { - this.editor_$.find(".Rk-Display-Description").html(this.source_representation.highlighted.replace(_(_model.get("description")).escape(),'$1')); - } - } - } - this.editor_$.find("img").load(function() { - _this.redraw(); - }); -}, -redraw: function() { - var _coords = this.source_representation.paper_coords; - drawEditBox(this.options, _coords, this.editor_block, this.source_representation.circle_radius * .75, this.editor_$); - this.editor_$.show(); - paper.view.draw(); -} -}); - -/* */ - -var EdgeEditor = Renderer.EdgeEditor = Rkns.Utils.inherit(_BaseEditor); - -_(EdgeEditor.prototype).extend({ -template: _.template( - '<%- renkan.translate("Change edge direction") %>
<% } %>' - + '<% if (options.show_edge_editor_nodes) { %><%-renkan.translate("From:")%><%- shortenText(edge.from_title, 25) %>
' - + '<%-renkan.translate("To:")%><%- shortenText(edge.to_title, 25) %>
<% } %>' - + '<% if (options.show_edge_editor_creator && edge.has_creator) { %><%-renkan.translate("Created by:")%><%- shortenText(edge.created_by_title, 25) %>
<% } %>' -), -readOnlyTemplate: _.template( - '<%-edge.description%>
' - + '<% if (options.show_edge_tooltip_nodes) { %><%-renkan.translate("From:")%><%- shortenText(edge.from_title, 25) %>
' - + '<%-renkan.translate("To:")%><%- shortenText(edge.to_title, 25) %>
<% } %>' - + '<% if (options.show_edge_tooltip_creator && edge.has_creator) { %><%-renkan.translate("Created by:")%><%- shortenText(edge.created_by_title, 25) %>
<% } %>' -), -draw: function() { - var _model = this.source_representation.model, - _from_model = _model.get("from"), - _to_model = _model.get("to"), - _created_by = _model.get("created_by") || _USER_PLACEHOLDER(this.renkan), - _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate); - this.editor_$ - .html(_template({ - edge: { - has_creator: !!_model.get("created_by"), - title: _model.get("title"), - uri: _model.get("uri"), - short_uri: shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40), - description: _model.get("description"), - color: _model.get("color") || _created_by.get("color"), - from_title: _from_model.get("title"), - to_title: _to_model.get("title"), - from_color: _from_model.get("color") || (_from_model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color"), - to_color: _to_model.get("color") || (_to_model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color"), - created_by_color: _created_by.get("color"), - created_by_title: _created_by.get("title") - }, - renkan: this.renkan, - shortenText: shortenText, - options: this.options - })); - this.redraw(); - var _this = this, - closeEditor = function() { - _this.renderer.removeRepresentation(_this); - paper.view.draw(); - }; - this.editor_$.find(".Rk-CloseX").click(closeEditor); - this.editor_$.find(".Rk-Edit-Goto").click(function() { - if (!_model.get("uri")) { - return false; } }); - - if (this.renderer.isEditable()) { - - var onFieldChange = _(function() { - _(function() { - if (_this.renderer.isEditable()) { - var _data = { - title: _this.editor_$.find(".Rk-Edit-Title").val() - }; - if (_this.options.show_edge_editor_uri) { - _data.uri = _this.editor_$.find(".Rk-Edit-URI").val(); + + /* */ + + var EdgeRemoveButton = Renderer.EdgeRemoveButton = Rkns.Utils.inherit(_BaseButton); + + _(EdgeRemoveButton.prototype).extend({ + _init: function() { + this.type = "Edge-remove-button"; + this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -90, 90, 1, "remove", this.renkan.translate("Remove")); + }, + mouseup: function() { + this.renderer.click_target = null; + this.renderer.is_dragging = false; + this.renderer.removeRepresentationsOfType("editor"); + if (this.renderer.isEditable()) { + if (this.options.element_delete_delay) { + var delid = Rkns.Utils.getUID("delete"); + this.renderer.delete_list.push({ + id: delid, + time: new Date().valueOf() + this.options.element_delete_delay + }); + this.source_representation.model.set("delete_scheduled", delid); + } else { + if (confirm(this.renkan.translate('Do you really wish to remove edge ') + '"' + this.source_representation.model.get("title") + '"?')) { + this.project.removeEdge(this.source_representation.model); } - _this.editor_$.find(".Rk-Edit-Goto").attr("href",_data.uri || "#"); - _model.set(_data); - paper.view.draw(); - } else { - closeEditor(); } - }).defer(); - }).throttle(500); - - this.editor_$.on("keyup", function(_e) { - if (_e.keyCode === 27) { - closeEditor(); - } - }); - - this.editor_$.find("input").on("keyup change paste", onFieldChange); - - this.editor_$.find(".Rk-Edit-Vocabulary").change(function() { - var e = $(this), - v = e.val(); - if (v) { - _this.editor_$.find(".Rk-Edit-Title").val(e.find(":selected").text()); - _this.editor_$.find(".Rk-Edit-URI").val(v); - onFieldChange(); - } - }); - this.editor_$.find(".Rk-Edit-Direction").click(function() { - if (_this.renderer.isEditable()) { - _model.set({ - from: _model.get("to"), - to: _model.get("from") - }); - _this.draw(); - } else { - closeEditor(); - } - }); - - var _picker = _this.editor_$.find(".Rk-Edit-ColorPicker"); - - this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover( - function(_e) { - _e.preventDefault(); - _picker.show(); - }, - function(_e) { - _e.preventDefault(); - _picker.hide(); - } - ); - - _picker.find("li").hover( - function(_e) { - _e.preventDefault(); - _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color")); - }, - function(_e) { - _e.preventDefault(); - _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || _USER_PLACEHOLDER(_this.renkan)).get("color")); - } - ).click(function(_e) { - _e.preventDefault(); - if (_this.renderer.isEditable()) { - _model.set("color", $(this).attr("data-color")); - _picker.hide(); - paper.view.draw(); - } else { - closeEditor(); } - }); - } -}, -redraw: function() { - var _coords = this.source_representation.paper_coords; - drawEditBox(this.options, _coords, this.editor_block, 5, this.editor_$); - this.editor_$.show(); - paper.view.draw(); -} -}); - -/* */ - -var _NodeButton = Renderer._NodeButton = Rkns.Utils.inherit(_BaseButton); + } + }); -_(_NodeButton.prototype).extend({ -setSectorSize: function() { - var sectorInner = this.source_representation.circle_radius; - if (sectorInner !== this.lastSectorInner) { - if (this.sector) { - this.sector.destroy(); - } - this.sector = this.renderer.drawSector( - this, 1 + sectorInner, - _NODE_BUTTON_WIDTH + sectorInner, - this.startAngle, - this.endAngle, - 1, - this.imageName, - this.renkan.translate(this.text) - ); - this.lastSectorInner = sectorInner; - } -} -}); + /* */ -/* */ - -var NodeEditButton = Renderer.NodeEditButton = Rkns.Utils.inherit(_NodeButton); + var EdgeRevertButton = Renderer.EdgeRevertButton = Rkns.Utils.inherit(_BaseButton); -_(NodeEditButton.prototype).extend({ -_init: function() { - this.type = "Node-edit-button"; - this.lastSectorInner = 0; - this.startAngle = -135; - this.endAngle = -45; - this.imageName = "edit"; - this.text = "Edit"; -}, -mouseup: function() { - if (!this.renderer.is_dragging) { - this.source_representation.openEditor(); - } -} -}); - -/* */ - -var NodeRemoveButton = Renderer.NodeRemoveButton = Rkns.Utils.inherit(_NodeButton); - -_(NodeRemoveButton.prototype).extend({ -_init: function() { - this.type = "Node-remove-button"; - this.lastSectorInner = 0; - this.startAngle = 0; - this.endAngle = 90; - this.imageName = "remove"; - this.text = "Remove"; -}, -mouseup: function() { - this.renderer.click_target = null; - this.renderer.is_dragging = false; - this.renderer.removeRepresentationsOfType("editor"); - if (this.renderer.isEditable()) { - if (this.options.element_delete_delay) { - var delid = Rkns.Utils.getUID("delete"); - this.renderer.delete_list.push({ - id: delid, - time: new Date().valueOf() + this.options.element_delete_delay - }); - this.source_representation.model.set("delete_scheduled", delid); - } else { - if (confirm(this.renkan.translate('Do you really wish to remove node ') + '"' + this.source_representation.model.get("title") + '"?')) { - this.project.removeNode(this.source_representation.model); + _(EdgeRevertButton.prototype).extend({ + _init: function() { + this.type = "Edge-revert-button"; + this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -135, 135, 1, "revert", this.renkan.translate("Cancel deletion")); + }, + mouseup: function() { + this.renderer.click_target = null; + this.renderer.is_dragging = false; + if (this.renderer.isEditable()) { + this.source_representation.model.unset("delete_scheduled"); } } - } -} -}); - -/* */ - -var NodeRevertButton = Renderer.NodeRevertButton = Rkns.Utils.inherit(_NodeButton); - -_(NodeRevertButton.prototype).extend({ -_init: function() { - this.type = "Node-revert-button"; - this.lastSectorInner = 0; - this.startAngle = -135; - this.endAngle = 135; - this.imageName = "revert"; - this.text = "Cancel deletion"; -}, -mouseup: function() { - this.renderer.click_target = null; - this.renderer.is_dragging = false; - if (this.renderer.isEditable()) { - this.source_representation.model.unset("delete_scheduled"); - } -} -}); - -/* */ + }); -var NodeLinkButton = Renderer.NodeLinkButton = Rkns.Utils.inherit(_NodeButton); + /* */ -_(NodeLinkButton.prototype).extend({ -_init: function() { - this.type = "Node-link-button"; - this.lastSectorInner = 0; - this.startAngle = 90; - this.endAngle = 180; - this.imageName = "link"; - this.text = "Link to another node"; -}, -mousedown: function(_event, _isTouch) { - if (this.renderer.isEditable()) { - var _off = this.renderer.canvas_$.offset(), - _point = new paper.Point([ - _event.pageX - _off.left, - _event.pageY - _off.top - ]); - this.renderer.click_target = null; - this.renderer.removeRepresentationsOfType("editor"); - this.renderer.addTempEdge(this.source_representation, _point); - } -} -}); - -/* */ - -var NodeEnlargeButton = Renderer.NodeEnlargeButton = Rkns.Utils.inherit(_NodeButton); + var MiniFrame = Renderer.MiniFrame = Rkns.Utils.inherit(_BaseRepresentation); -_(NodeEnlargeButton.prototype).extend({ -_init: function() { - this.type = "Node-enlarge-button"; - this.lastSectorInner = 0; - this.startAngle = -45; - this.endAngle = 0; - this.imageName = "enlarge"; - this.text = "Enlarge"; -}, -mouseup: function() { - var _newsize = 1 + (this.source_representation.model.get("size") || 0); - this.source_representation.model.set("size", _newsize); - this.source_representation.select(); - this.select(); - paper.view.draw(); -} -}); - -/* */ - -var NodeShrinkButton = Renderer.NodeShrinkButton = Rkns.Utils.inherit(_NodeButton); + _(MiniFrame.prototype).extend({ + paperShift: function(_delta) { + this.renderer.offset = this.renderer.offset.subtract(_delta.divide(this.renderer.minimap.scale).multiply(this.renderer.scale)); + this.renderer.redraw(); + }, + mouseup: function(_delta) { + this.renderer.click_target = null; + this.renderer.is_dragging = false; + } + }); -_(NodeShrinkButton.prototype).extend({ -_init: function() { - this.type = "Node-shrink-button"; - this.lastSectorInner = 0; - this.startAngle = -180; - this.endAngle = -135; - this.imageName = "shrink"; - this.text = "Shrink"; -}, -mouseup: function() { - var _newsize = -1 + (this.source_representation.model.get("size") || 0); - this.source_representation.model.set("size", _newsize); - this.source_representation.select(); - this.select(); - paper.view.draw(); -} -}); - -/* */ - -var EdgeEditButton = Renderer.EdgeEditButton = Rkns.Utils.inherit(_BaseButton); - -_(EdgeEditButton.prototype).extend({ -_init: function() { - this.type = "Edge-edit-button"; - this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -270, -90, 1, "edit", this.renkan.translate("Edit")); -}, -mouseup: function() { - if (!this.renderer.is_dragging) { - this.source_representation.openEditor(); - } -} -}); - -/* */ - -var EdgeRemoveButton = Renderer.EdgeRemoveButton = Rkns.Utils.inherit(_BaseButton); + /* */ -_(EdgeRemoveButton.prototype).extend({ -_init: function() { - this.type = "Edge-remove-button"; - this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -90, 90, 1, "remove", this.renkan.translate("Remove")); -}, -mouseup: function() { - this.renderer.click_target = null; - this.renderer.is_dragging = false; - this.renderer.removeRepresentationsOfType("editor"); - if (this.renderer.isEditable()) { - if (this.options.element_delete_delay) { - var delid = Rkns.Utils.getUID("delete"); - this.renderer.delete_list.push({ - id: delid, - time: new Date().valueOf() + this.options.element_delete_delay - }); - this.source_representation.model.set("delete_scheduled", delid); - } else { - if (confirm(this.renkan.translate('Do you really wish to remove edge ') + '"' + this.source_representation.model.get("title") + '"?')) { - this.project.removeEdge(this.source_representation.model); - } - } - } -} -}); - -/* */ - -var EdgeRevertButton = Renderer.EdgeRevertButton = Rkns.Utils.inherit(_BaseButton); - -_(EdgeRevertButton.prototype).extend({ -_init: function() { - this.type = "Edge-revert-button"; - this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -135, 135, 1, "revert", this.renkan.translate("Cancel deletion")); -}, -mouseup: function() { - this.renderer.click_target = null; - this.renderer.is_dragging = false; - if (this.renderer.isEditable()) { - this.source_representation.model.unset("delete_scheduled"); - } -} -}); - -/* */ - -var MiniFrame = Renderer.MiniFrame = Rkns.Utils.inherit(_BaseRepresentation); - -_(MiniFrame.prototype).extend({ -paperShift: function(_delta) { - this.renderer.offset = this.renderer.offset.subtract(_delta.divide(this.renderer.minimap.scale).multiply(this.renderer.scale)); - this.renderer.redraw(); -}, -mouseup: function(_delta) { - this.renderer.click_target = null; - this.renderer.is_dragging = false; -} -}); - -/* */ + var Scene = Renderer.Scene = function(_renkan) { + this.renkan = _renkan; + this.$ = $(".Rk-Render"); + this.representations = []; + this.$.html(this.template(_renkan)); + this.onStatusChange(); + this.canvas_$ = this.$.find(".Rk-Canvas"); + this.labels_$ = this.$.find(".Rk-Labels"); + this.editor_$ = this.$.find(".Rk-Editor"); + this.notif_$ = this.$.find(".Rk-Notifications"); + paper.setup(this.canvas_$[0]); + this.scale = 1; + this.initialScale = 1; + this.offset = paper.view.center; + this.totalScroll = 0; + this.mouse_down = false; + this.click_target = null; + this.selected_target = null; + this.edge_layer = new paper.Layer(); + this.node_layer = new paper.Layer(); + this.buttons_layer = new paper.Layer(); + this.delete_list = []; -var Scene = Renderer.Scene = function(_renkan) { - this.renkan = _renkan; - this.$ = $(".Rk-Render"); - this.representations = []; - this.$.html(this.template(_renkan)); - this.onStatusChange(); - this.canvas_$ = this.$.find(".Rk-Canvas"); - this.labels_$ = this.$.find(".Rk-Labels"); - this.editor_$ = this.$.find(".Rk-Editor"); - this.notif_$ = this.$.find(".Rk-Notifications"); - paper.setup(this.canvas_$[0]); - this.scale = 1; - this.initialScale = 1; - this.offset = paper.view.center; - this.totalScroll = 0; - this.mouse_down = false; - this.click_target = null; - this.selected_target = null; - this.edge_layer = new paper.Layer(); - this.node_layer = new paper.Layer(); - this.buttons_layer = new paper.Layer(); - this.delete_list = []; - - if (_renkan.options.show_minimap) { - this.minimap = { - background_layer: new paper.Layer(), - edge_layer: new paper.Layer(), - node_layer: new paper.Layer(), - node_group: new paper.Group(), - size: new paper.Size( _renkan.options.minimap_width, _renkan.options.minimap_height ) - }; - - this.minimap.background_layer.activate(); - this.minimap.topleft = paper.view.bounds.bottomRight.subtract(this.minimap.size); - this.minimap.rectangle = new paper.Path.Rectangle(this.minimap.topleft.subtract([2,2]), this.minimap.size.add([4,4])); - this.minimap.rectangle.fillColor = _renkan.options.minimap_background_color; - this.minimap.rectangle.strokeColor = _renkan.options.minimap_border_color; - this.minimap.rectangle.strokeWidth = 4; - this.minimap.offset = new paper.Point(this.minimap.size.divide(2)); - this.minimap.scale = .1; - - this.minimap.node_layer.activate(); - this.minimap.cliprectangle = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size); - this.minimap.node_group.addChild(this.minimap.cliprectangle); - this.minimap.node_group.clipped = true; - this.minimap.miniframe = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size); - this.minimap.node_group.addChild(this.minimap.miniframe); - this.minimap.miniframe.fillColor = '#c0c0ff'; - this.minimap.miniframe.opacity = .3; - this.minimap.miniframe.strokeColor = '#000080'; - this.minimap.miniframe.strokeWidth = 3; - this.minimap.miniframe.__representation = new MiniFrame(this, null); - } - - this.throttledPaperDraw = _(function() { - paper.view.draw(); - }).throttle(100); - - this.bundles = []; - this.click_mode = false; - - var _this = this, + if (_renkan.options.show_minimap) { + this.minimap = { + background_layer: new paper.Layer(), + edge_layer: new paper.Layer(), + node_layer: new paper.Layer(), + node_group: new paper.Group(), + size: new paper.Size( _renkan.options.minimap_width, _renkan.options.minimap_height ) + }; + + this.minimap.background_layer.activate(); + this.minimap.topleft = paper.view.bounds.bottomRight.subtract(this.minimap.size); + this.minimap.rectangle = new paper.Path.Rectangle(this.minimap.topleft.subtract([2,2]), this.minimap.size.add([4,4])); + this.minimap.rectangle.fillColor = _renkan.options.minimap_background_color; + this.minimap.rectangle.strokeColor = _renkan.options.minimap_border_color; + this.minimap.rectangle.strokeWidth = 4; + this.minimap.offset = new paper.Point(this.minimap.size.divide(2)); + this.minimap.scale = .1; + + this.minimap.node_layer.activate(); + this.minimap.cliprectangle = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size); + this.minimap.node_group.addChild(this.minimap.cliprectangle); + this.minimap.node_group.clipped = true; + this.minimap.miniframe = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size); + this.minimap.node_group.addChild(this.minimap.miniframe); + this.minimap.miniframe.fillColor = '#c0c0ff'; + this.minimap.miniframe.opacity = .3; + this.minimap.miniframe.strokeColor = '#000080'; + this.minimap.miniframe.strokeWidth = 3; + this.minimap.miniframe.__representation = new MiniFrame(this, null); + } + + this.throttledPaperDraw = _(function() { + paper.view.draw(); + }).throttle(100); + + this.bundles = []; + this.click_mode = false; + + var _this = this, _allowScroll = true, _originalScale, _zooming = false, _lastTapDate, _lastTapX, _lastTapY; - - this.image_cache = {}; - this.icon_cache = {}; - - ['edit', 'remove', 'link', 'enlarge', 'shrink', 'revert' ].forEach(function(imgname) { - var img = new Image(); - img.src = _renkan.options.static_url + 'img/' + imgname + '.png'; - _this.icon_cache[imgname] = img; - }); - - var throttledMouseMove = _.throttle(function(_event, _isTouch) { - _this.onMouseMove(_event, _isTouch); - }, _MOUSEMOVE_RATE); - - this.canvas_$.on({ - mousedown: function(_event) { - _event.preventDefault(); - _this.onMouseDown(_event, false); - }, - mousemove: function(_event) { - _event.preventDefault(); - throttledMouseMove(_event, false); - }, - mouseup: function(_event) { - _event.preventDefault(); - _this.onMouseUp(_event, false); - }, - mousewheel: function(_event, _delta) { - if(_renkan.options.zoom_on_scroll) { + + this.image_cache = {}; + this.icon_cache = {}; + + ['edit', 'remove', 'link', 'enlarge', 'shrink', 'revert' ].forEach(function(imgname) { + var img = new Image(); + img.src = _renkan.options.static_url + 'img/' + imgname + '.png'; + _this.icon_cache[imgname] = img; + }); + + var throttledMouseMove = _.throttle(function(_event, _isTouch) { + _this.onMouseMove(_event, _isTouch); + }, _MOUSEMOVE_RATE); + + this.canvas_$.on({ + mousedown: function(_event) { _event.preventDefault(); - if (_allowScroll) { - _this.onScroll(_event, _delta); + _this.onMouseDown(_event, false); + }, + mousemove: function(_event) { + _event.preventDefault(); + throttledMouseMove(_event, false); + }, + mouseup: function(_event) { + _event.preventDefault(); + _this.onMouseUp(_event, false); + }, + mousewheel: function(_event, _delta) { + if(_renkan.options.zoom_on_scroll) { + _event.preventDefault(); + if (_allowScroll) { + _this.onScroll(_event, _delta); + } } - } - }, - touchstart: function(_event) { - _event.preventDefault(); - var _touches = _event.originalEvent.touches[0]; - if ( - _renkan.options.allow_double_click - && new Date() - _lastTap < _DOUBLETAP_DELAY - && ( Math.pow(_lastTapX - _touches.pageX, 2) + Math.pow(_lastTapY - _touches.pageY, 2) < _DOUBLETAP_DISTANCE ) - ) { + }, + touchstart: function(_event) { + _event.preventDefault(); + var _touches = _event.originalEvent.touches[0]; + if ( + _renkan.options.allow_double_click + && new Date() - _lastTap < _DOUBLETAP_DELAY + && ( Math.pow(_lastTapX - _touches.pageX, 2) + Math.pow(_lastTapY - _touches.pageY, 2) < _DOUBLETAP_DISTANCE ) + ) { + _lastTap = 0; + _this.onDoubleClick(_touches); + } else { + _lastTap = new Date(); + _lastTapX = _touches.pageX; + _lastTapY = _touches.pageY; + _originalScale = _this.scale; + _zooming = false; + _this.onMouseDown(_touches, true); + } + }, + touchmove: function(_event) { + _event.preventDefault(); _lastTap = 0; - _this.onDoubleClick(_touches); - } else { - _lastTap = new Date(); - _lastTapX = _touches.pageX; - _lastTapY = _touches.pageY; - _originalScale = _this.scale; - _zooming = false; - _this.onMouseDown(_touches, true); - } - }, - touchmove: function(_event) { - _event.preventDefault(); - _lastTap = 0; - if (_event.originalEvent.touches.length == 1) { - _this.onMouseMove(_event.originalEvent.touches[0], true); - } else { - if (!_zooming) { - _this.onMouseUp(_event.originalEvent.touches[0], true); - _this.click_target = null; - _this.is_dragging = false; - _zooming = true; - } - if (_event.originalEvent.scale === "undefined") { - return; - } - var _newScale = _event.originalEvent.scale * _originalScale, + if (_event.originalEvent.touches.length == 1) { + _this.onMouseMove(_event.originalEvent.touches[0], true); + } else { + if (!_zooming) { + _this.onMouseUp(_event.originalEvent.touches[0], true); + _this.click_target = null; + _this.is_dragging = false; + _zooming = true; + } + if (_event.originalEvent.scale === "undefined") { + return; + } + var _newScale = _event.originalEvent.scale * _originalScale, _scaleRatio = _newScale / _this.scale, _newOffset = new paper.Point([ - _this.canvas_$.width(), - _this.canvas_$.height() - ]).multiply( .5 * ( 1 - _scaleRatio ) ).add(_this.offset.multiply( _scaleRatio )); - _this.setScale(_newScale, _this.offset); - } - }, - touchend: function(_event) { - _event.preventDefault(); - _this.onMouseUp(_event.originalEvent.changedTouches[0], true); - }, - dblclick: function(_event) { - _event.preventDefault(); - if (_renkan.options.allow_double_click) { - _this.onDoubleClick(_event); - } - }, - mouseleave: function(_event) { - _event.preventDefault(); - _this.onMouseUp(_event, false); - _this.click_target = null; - _this.is_dragging = false; - }, - dragover: function(_event) { - _event.preventDefault(); - }, - dragenter: function(_event) { - _event.preventDefault(); - _allowScroll = false; - }, - dragleave: function(_event) { - _event.preventDefault(); - _allowScroll = true; - }, - drop: function(_event) { - _event.preventDefault(); - _allowScroll = true; - var res = {}; - _(_event.originalEvent.dataTransfer.types).each(function(t) { - try { - res[t] = _event.originalEvent.dataTransfer.getData(t); - } catch(e) {} - }); - var text = _event.originalEvent.dataTransfer.getData("Text"); - if (typeof text === "string") { - switch(text[0]) { + _this.canvas_$.width(), + _this.canvas_$.height() + ]).multiply( .5 * ( 1 - _scaleRatio ) ).add(_this.offset.multiply( _scaleRatio )); + _this.setScale(_newScale, _this.offset); + } + }, + touchend: function(_event) { + _event.preventDefault(); + _this.onMouseUp(_event.originalEvent.changedTouches[0], true); + }, + dblclick: function(_event) { + _event.preventDefault(); + if (_renkan.options.allow_double_click) { + _this.onDoubleClick(_event); + } + }, + mouseleave: function(_event) { + _event.preventDefault(); + _this.onMouseUp(_event, false); + _this.click_target = null; + _this.is_dragging = false; + }, + dragover: function(_event) { + _event.preventDefault(); + }, + dragenter: function(_event) { + _event.preventDefault(); + _allowScroll = false; + }, + dragleave: function(_event) { + _event.preventDefault(); + _allowScroll = true; + }, + drop: function(_event) { + _event.preventDefault(); + _allowScroll = true; + var res = {}; + _(_event.originalEvent.dataTransfer.types).each(function(t) { + try { + res[t] = _event.originalEvent.dataTransfer.getData(t); + } catch(e) {} + }); + var text = _event.originalEvent.dataTransfer.getData("Text"); + if (typeof text === "string") { + switch(text[0]) { case "{": case "[": try { @@ -1763,995 +1762,991 @@ res["text/plain"] = text; } } - break; + break; case "<": if (!res["text/html"]) { res["text/html"] = text; } - break; + break; default: if (!res["text/plain"]) { res["text/plain"] = text; } + } } - } - var url = _event.originalEvent.dataTransfer.getData("URL"); - if (url && !res["text/uri-list"]) { - res["text/uri-list"] = url; + var url = _event.originalEvent.dataTransfer.getData("URL"); + if (url && !res["text/uri-list"]) { + res["text/uri-list"] = url; + } + _this.dropData(res, _event.originalEvent); } - _this.dropData(res, _event.originalEvent); - } - }); - - var bindClick = function(selector, fname) { - _this.$.find(selector).click(function(evt) { - _this[fname](evt); - return false; }); - }; - - bindClick(".Rk-ZoomOut", "zoomOut"); - bindClick(".Rk-ZoomIn", "zoomIn"); - bindClick(".Rk-ZoomFit", "autoScale"); - this.$.find(".Rk-ZoomSave").click( function() { - _this.renkan.project.set("views", [{id:Rkns.Utils.getUID('view'), zoom_level:_this.scale, offset_x:_this.offset.x, offset_y:_this.offset.y}]); // Save scale - _this.$.find(".Rk-ZoomSetSaved").show(); - }); - this.$.find(".Rk-ZoomSetSaved").click( function() { - var view = _this.renkan.project.get("views")[0]; - _this.setScale(view.zoom_level, new paper.Point(view.offset_x, view.offset_y)); - }); - if(this.renkan.read_only && !isNaN(parseInt(this.renkan.options.default_view))){ - this.$.find(".Rk-ZoomSetSaved").show(); - } - this.$.find(".Rk-CurrentUser").mouseenter( - function() { _this.$.find(".Rk-UserList").slideDown(); } - ); - this.$.find(".Rk-Users").mouseleave( - function() { _this.$.find(".Rk-UserList").slideUp(); } - ); - bindClick(".Rk-FullScreen-Button", "fullScreen"); - bindClick(".Rk-AddNode-Button", "addNodeBtn"); - bindClick(".Rk-AddEdge-Button", "addEdgeBtn"); - bindClick(".Rk-Save-Button", "save"); - bindClick(".Rk-Open-Button", "open"); - this.$.find(".Rk-Bookmarklet-Button") + + var bindClick = function(selector, fname) { + _this.$.find(selector).click(function(evt) { + _this[fname](evt); + return false; + }); + }; + + bindClick(".Rk-ZoomOut", "zoomOut"); + bindClick(".Rk-ZoomIn", "zoomIn"); + bindClick(".Rk-ZoomFit", "autoScale"); + this.$.find(".Rk-ZoomSave").click( function() { + _this.renkan.project.set("views", [{id:Rkns.Utils.getUID('view'), zoom_level:_this.scale, offset_x:_this.offset.x, offset_y:_this.offset.y}]); // Save scale + _this.$.find(".Rk-ZoomSetSaved").show(); + }); + this.$.find(".Rk-ZoomSetSaved").click( function() { + var view = _this.renkan.project.get("views")[0]; + _this.setScale(view.zoom_level, new paper.Point(view.offset_x, view.offset_y)); + }); + if(this.renkan.read_only && !isNaN(parseInt(this.renkan.options.default_view))){ + this.$.find(".Rk-ZoomSetSaved").show(); + } + this.$.find(".Rk-CurrentUser").mouseenter( + function() { _this.$.find(".Rk-UserList").slideDown(); } + ); + this.$.find(".Rk-Users").mouseleave( + function() { _this.$.find(".Rk-UserList").slideUp(); } + ); + bindClick(".Rk-FullScreen-Button", "fullScreen"); + bindClick(".Rk-AddNode-Button", "addNodeBtn"); + bindClick(".Rk-AddEdge-Button", "addEdgeBtn"); + bindClick(".Rk-Save-Button", "save"); + bindClick(".Rk-Open-Button", "open"); + this.$.find(".Rk-Bookmarklet-Button") .attr("href","javascript:" + _BOOKMARKLET_CODE(_renkan)) .click(function(){ _this.notif_$ - .text(_renkan.translate("Drag this button to your bookmark bar. When on a third-party website, click it to enable drag-and-drop from the website to Renkan.")) - .fadeIn() - .delay(5000) - .fadeOut(); + .text(_renkan.translate("Drag this button to your bookmark bar. When on a third-party website, click it to enable drag-and-drop from the website to Renkan.")) + .fadeIn() + .delay(5000) + .fadeOut(); return false; }); - this.$.find(".Rk-TopBar-Button").mouseover(function() { - $(this).find(".Rk-TopBar-Tooltip").show(); - }).mouseout(function() { - $(this).find(".Rk-TopBar-Tooltip").hide(); - }); - bindClick(".Rk-Fold-Bins", "foldBins"); - - paper.view.onResize = function(_event) { - // Because of paper bug which does not calculate the good height (and width a fortiori) - // We have to update manually the canvas's height - paper.view._viewSize.height = _event.size.height = _this.canvas_$.parent().height(); - - 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); - } - _this.redraw(); - }; - - var _thRedraw = _.throttle(function() { - _this.redraw(); - },50); - - this.addRepresentations("Node", this.renkan.project.get("nodes")); - this.addRepresentations("Edge", this.renkan.project.get("edges")); - this.renkan.project.on("change:title", function() { - _this.$.find(".Rk-PadTitle").val(_renkan.project.get("title")); - }); - - this.$.find(".Rk-PadTitle").on("keyup input paste", function() { - _renkan.project.set({"title": $(this).val()}); - }); - - var _thRedrawUsers = _.throttle(function() { - _this.redrawUsers(); - }, 100); - - _thRedrawUsers(); - - this.renkan.project.on("add:users remove:users", _thRedrawUsers); - - this.renkan.project.on("add:nodes", function(_node) { - _this.addRepresentation("Node", _node); - _thRedraw(); - }); - this.renkan.project.on("add:edges", function(_edge) { - _this.addRepresentation("Edge", _edge); - _thRedraw(); - }); - this.renkan.project.on("change:title", function(_model, _title) { - var el = _this.$.find(".Rk-PadTitle"); - if (el.is("input")) { - if (el.val() !== _title) { - el.val(_title); + this.$.find(".Rk-TopBar-Button").mouseover(function() { + $(this).find(".Rk-TopBar-Tooltip").show(); + }).mouseout(function() { + $(this).find(".Rk-TopBar-Tooltip").hide(); + }); + bindClick(".Rk-Fold-Bins", "foldBins"); + + paper.view.onResize = function(_event) { + // Because of paper bug which does not calculate the good height (and width a fortiori) + // We have to update manually the canvas's height + paper.view._viewSize.height = _event.size.height = _this.canvas_$.parent().height(); + + 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); } - } else { - el.text(_title); - } - }); - - if (_renkan.options.size_bug_fix) { - var _delay = ( - typeof _renkan.options.size_bug_fix === "number" - ? _renkan.options.size_bug_fix - : 500 - ); - window.setTimeout( - function() { - _this.fixSize(true); - }, - _delay - ); - } - - if (_renkan.options.force_resize) { - $(window).resize(function() { - _this.fixSize(false); + _this.redraw(); + }; + + var _thRedraw = _.throttle(function() { + _this.redraw(); + },50); + + this.addRepresentations("Node", this.renkan.project.get("nodes")); + this.addRepresentations("Edge", this.renkan.project.get("edges")); + this.renkan.project.on("change:title", function() { + _this.$.find(".Rk-PadTitle").val(_renkan.project.get("title")); + }); + + this.$.find(".Rk-PadTitle").on("keyup input paste", function() { + _renkan.project.set({"title": $(this).val()}); }); - } - - if (_renkan.options.show_user_list && _renkan.options.user_color_editable) { - var $cpwrapper = this.$.find(".Rk-Users .Rk-Edit-ColorPicker-Wrapper"), - $cplist = this.$.find(".Rk-Users .Rk-Edit-ColorPicker"); - - $cpwrapper.hover( - function(_e) { - if (_this.isEditable()) { - _e.preventDefault(); - $cplist.show(); + + var _thRedrawUsers = _.throttle(function() { + _this.redrawUsers(); + }, 100); + + _thRedrawUsers(); + + this.renkan.project.on("add:users remove:users", _thRedrawUsers); + + this.renkan.project.on("add:nodes", function(_node) { + _this.addRepresentation("Node", _node); + _thRedraw(); + }); + this.renkan.project.on("add:edges", function(_edge) { + _this.addRepresentation("Edge", _edge); + _thRedraw(); + }); + this.renkan.project.on("change:title", function(_model, _title) { + var el = _this.$.find(".Rk-PadTitle"); + if (el.is("input")) { + if (el.val() !== _title) { + el.val(_title); } - }, - function(_e) { - _e.preventDefault(); - $cplist.hide(); - } - ); - - $cplist.find("li").mouseenter( - function(_e) { - if (_this.isEditable()) { - _e.preventDefault(); - _this.$.find(".Rk-CurrentUser-Color").css("background", $(this).attr("data-color")); - } - } - ); - } - - if (_renkan.options.show_search_field) { - - var lastval = ''; - - this.$.find(".Rk-GraphSearch-Field").on("keyup change paste input", function() { - var $this = $(this), - val = $this.val(); - if (val === lastval) { - return; - } - lastval = val; - if (val.length < 2) { - _renkan.project.get("nodes").each(function(n) { - _this.getRepresentationByModel(n).unhighlight(); - }); } else { - var rxs = Rkns.Utils.regexpFromTextOrArray(val); - _renkan.project.get("nodes").each(function(n) { - if (rxs.test(n.get("title")) || rxs.test(n.get("description"))) { - _this.getRepresentationByModel(n).highlight(rxs); - } else { - _this.getRepresentationByModel(n).unhighlight(); - } - }); + el.text(_title); } }); - } - - this.redraw(); - - window.setInterval(function() { - var _now = new Date().valueOf(); - _this.delete_list.forEach(function(d) { - if (_now >= d.time) { - var el = _renkan.project.get("nodes").findWhere({"delete_scheduled":d.id}); - if (el) { - project.removeNode(el); + + if (_renkan.options.size_bug_fix) { + var _delay = ( + typeof _renkan.options.size_bug_fix === "number" + ? _renkan.options.size_bug_fix + : 500 + ); + window.setTimeout( + function() { + _this.fixSize(true); + }, + _delay + ); + } + + if (_renkan.options.force_resize) { + $(window).resize(function() { + _this.fixSize(false); + }); + } + + if (_renkan.options.show_user_list && _renkan.options.user_color_editable) { + var $cpwrapper = this.$.find(".Rk-Users .Rk-Edit-ColorPicker-Wrapper"), + $cplist = this.$.find(".Rk-Users .Rk-Edit-ColorPicker"); + + $cpwrapper.hover( + function(_e) { + if (_this.isEditable()) { + _e.preventDefault(); + $cplist.show(); + } + }, + function(_e) { + _e.preventDefault(); + $cplist.hide(); + } + ); + + $cplist.find("li").mouseenter( + function(_e) { + if (_this.isEditable()) { + _e.preventDefault(); + _this.$.find(".Rk-CurrentUser-Color").css("background", $(this).attr("data-color")); + } + } + ); + } + + if (_renkan.options.show_search_field) { + + var lastval = ''; + + this.$.find(".Rk-GraphSearch-Field").on("keyup change paste input", function() { + var $this = $(this), + val = $this.val(); + if (val === lastval) { + return; + } + lastval = val; + if (val.length < 2) { + _renkan.project.get("nodes").each(function(n) { + _this.getRepresentationByModel(n).unhighlight(); + }); + } else { + var rxs = Rkns.Utils.regexpFromTextOrArray(val); + _renkan.project.get("nodes").each(function(n) { + if (rxs.test(n.get("title")) || rxs.test(n.get("description"))) { + _this.getRepresentationByModel(n).highlight(rxs); + } else { + _this.getRepresentationByModel(n).unhighlight(); + } + }); } - el = _renkan.project.get("edges").findWhere({"delete_scheduled":d.id}); - if (el) { - project.removeEdge(el); + }); + } + + this.redraw(); + + window.setInterval(function() { + var _now = new Date().valueOf(); + _this.delete_list.forEach(function(d) { + if (_now >= d.time) { + var el = _renkan.project.get("nodes").findWhere({"delete_scheduled":d.id}); + if (el) { + project.removeNode(el); + } + el = _renkan.project.get("edges").findWhere({"delete_scheduled":d.id}); + if (el) { + project.removeEdge(el); + } + } + }); + _this.delete_list = _this.delete_list.filter(function(d) { + return _renkan.project.get("nodes").findWhere({"delete_scheduled":d.id}) || _renkan.project.get("edges").findWhere({"delete_scheduled":d.id}); + }); + }, 500); + + if (this.minimap) { + window.setInterval(function() { + _this.rescaleMinimap(); + }, 2000); + } + + }; + + _(Scene.prototype).extend({ + template: _.template( + '<% if (options.show_top_bar) { %>