client/js/paper-renderer.js
changeset 66 9b459e41e2df
parent 64 3a5a9421687b
child 67 d341117f9370
--- a/client/js/paper-renderer.js	Tue Feb 26 11:09:57 2013 +0100
+++ b/client/js/paper-renderer.js	Tue Feb 26 17:04:24 2013 +0100
@@ -21,6 +21,7 @@
     _CLICKMODE_ADDNODE : 1,
     _CLICKMODE_STARTEDGE : 2,
     _CLICKMODE_ENDEDGE : 3,
+    _IMAGE_MAX_KB : 500,
     _USER_PLACEHOLDER : {
         color: "#000000",
         title: "(unknown user)",
@@ -645,21 +646,23 @@
 }
 
 Rkns.Renderer.NodeEditor.prototype.template = Rkns._.template(
-    '<h2><span class="Rk-CloseX">&times;</span><%=l10n.edit_node%></span></h2>'
-    + '<p><label><%=l10n.edit_title%></label><input class="Rk-Edit-Title" type="text" value="<%=node.title%>"/></p>'
-    + '<p><label><%=l10n.edit_uri%></label><input class="Rk-Edit-URI" type="text" value="<%=node.uri%>"/><a class="Rk-Edit-Goto" href="<%=node.uri%>" target="_blank"></a></p>'
-    + '<p><label><%=l10n.edit_description%></label><textarea class="Rk-Edit-Description"><%=node.description%></textarea></p>'
-    + '<div class="Rk-Editor-p"><label>Node color</label><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-Edit-Color" style="background:<%=node.color%>;"><span class="Rk-Edit-ColorTip"></span></span><ul class="Rk-Edit-ColorPicker">'
+    '<h2><span class="Rk-CloseX">&times;</span><%-translate("Edit Node")%></span></h2>'
+    + '<p><label><%-translate("Title:")%></label><input class="Rk-Edit-Title" type="text" value="<%=node.title%>"/></p>'
+    + '<p><label><%-translate("URI:")%></label><input class="Rk-Edit-URI" type="text" value="<%=node.uri%>"/><a class="Rk-Edit-Goto" href="<%=node.uri%>" target="_blank"></a></p>'
+    + '<p><label><%-translate("Description:")%></label><textarea class="Rk-Edit-Description"><%=node.description%></textarea></p>'
+    + '<div class="Rk-Editor-p"><span class="Rk-Editor-Label"><%-translate("Node color:")%></span><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-Edit-Color" style="background:<%=node.color%>;"><span class="Rk-Edit-ColorTip"></span></span><ul class="Rk-Edit-ColorPicker">'
     + '<% print(Rkns.pickerColors.reduce(function(m,c) { return m + "<li data-color=\'" + c + "\' style=\'background: " + c + "\'></li>"},"")); %></ul><span class="Rk-Edit-ColorPicker-Text">Choose color</span></div></div>'
-    + '<p><label><%=l10n.edit_image%></label><input class="Rk-Edit-Image" type="text" value="<%=node.image%>"/><img class="Rk-Edit-ImgPreview" src="<%=node.image%>" /></p>'
-    + '<p><label><%=l10n.created_by%></label> <span class="Rk-UserColor" style="background:<%=node.created_by_color%>;"></span><%=node.created_by_title%></p>'
+    + '<img class="Rk-Edit-ImgPreview" src="<%=node.image || node.image_placeholder%>" />'
+    + '<p><label><%-translate("Image URL:")%></label><input class="Rk-Edit-Image" type="text" value="<%=node.image%>"/></p>'
+    + '<p><label><%-translate("Choose Image File:")%></label><input class="Rk-Edit-Image-File" type="file"/></p>'    
+    + '<p><span class="Rk-Editor-Label"><%-translate("Created by:")%></span> <span class="Rk-UserColor" style="background:<%=node.created_by_color%>;"></span><%=node.created_by_title%></p>'
 );
 
 Rkns.Renderer.NodeEditor.prototype.readOnlyTemplate = Rkns._.template(
     '<h2><span class="Rk-CloseX">&times;</span><span class="Rk-UserColor" style="background:<%=node.color%>;"></span><%-node.title%></span></h2>'
     + '<p><a href="<%-node.uri%>" target="_blank"><%-node.uri%></a></p>'
     + '<p><%-node.description%></p>'
-    + '<p><label><%=l10n.created_by%> </label><span class="Rk-UserColor" style="background:<%=node.created_by_color%>;"></span><%=node.created_by_title%></p>'
+    + '<p><span class="Rk-Editor-Label"><%-translate("Created by:")%> </span><span class="Rk-UserColor" style="background:<%=node.created_by_color%>;"></span><%=node.created_by_title%></p>'
 );
 
 Rkns.Renderer.NodeEditor.prototype.draw = function() {
@@ -673,11 +676,12 @@
                 uri: _model.get("uri"),
                 description: _model.get("description"),
                 image: _model.get("image") || "",
+                image_placeholder: this.renderer.renkan.static_url + "img/image-placeholder.png",
                 color: _model.get("color") || _created_by.get("color"),
                 created_by_color: _created_by.get("color"),
                 created_by_title: _created_by.get("title")
             },
-            l10n: this.renderer.renkan.l10n
+            translate: this.renderer.renkan.translate
         }));
     this.redraw();
     var _this = this;
@@ -686,19 +690,44 @@
         paper.view.draw();
     });
     if (!this.renderer.renkan.read_only) {
-        this.editor_$.find("input, textarea").bind("keyup change", function() {
-            var _uri = _this.editor_$.find(".Rk-Edit-URI").val(),
-                _image = _this.editor_$.find(".Rk-Edit-Image").val();
-            _this.editor_$.find(".Rk-Edit-ImgPreview").attr("src", _image);
-            _this.editor_$.find(".Rk-Edit-Goto").attr("href",_uri);
-            var _data = {
-                title: _this.editor_$.find(".Rk-Edit-Title").val(),
-                description: _this.editor_$.find(".Rk-Edit-Description").val(),
-                uri: _uri,
-                image: _image
-            }
-            _model.set(_data);
-            _this.redraw();
+    	
+    	var onFieldChange = Rkns._(function() {
+    		Rkns._(function() {
+	            var _uri = _this.editor_$.find(".Rk-Edit-URI").val(),
+	                _image = _this.editor_$.find(".Rk-Edit-Image").val();
+	            _this.editor_$.find(".Rk-Edit-ImgPreview").attr("src", _image);
+	            _this.editor_$.find(".Rk-Edit-Goto").attr("href",_uri);
+	            var _data = {
+	                title: _this.editor_$.find(".Rk-Edit-Title").val(),
+	                description: _this.editor_$.find(".Rk-Edit-Description").val(),
+	                uri: _uri,
+	                image: _image
+	            }
+	            _model.set(_data);
+	            _this.redraw();
+    		}).defer();
+    	}).throttle(500);
+    	
+    	this.editor_$.find("input, textarea").bind("change keyup paste", onFieldChange);
+    	
+        this.editor_$.find(".Rk-Edit-Image-File").bind("change", function() {
+        	if (this.files.length) {
+        		var f = this.files[0],
+        			fr = new FileReader();
+    			if (f.type.substr(0,5) !== "image") {
+    				alert(_this.renderer.renkan.translate("This file is not an image"));
+    				return;
+    			}
+    			if (f.size > (Rkns.Renderer._IMAGE_MAX_KB * 1024)) {
+    				alert(_this.renderer.renkan.translate("Image size must be under ")+Rkns.Renderer._IMAGE_MAX_KB+_this.renderer.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();
         this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover(
@@ -754,23 +783,23 @@
 }
 
 Rkns.Renderer.EdgeEditor.prototype.template = Rkns._.template(
-    '<h2><span class="Rk-CloseX">&times;</span><%=l10n.edit_edge%></span></h2>'
-    + '<p><label><%=l10n.edit_title%></label><input class="Rk-Edit-Title" type="text" value="<%=edge.title%>"/></p>'
-    + '<p><label><%=l10n.edit_uri%></label><input class="Rk-Edit-URI" type="text" value="<%=edge.uri%>"/><a class="Rk-Edit-Goto" href="<%=edge.uri%>" target="_blank"></a></p>'
-    + '<div class="Rk-Editor-p"><label>Edge color:</label><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-Edit-Color" style="background:<%=edge.color%>;"><span class="Rk-Edit-ColorTip"></span></span><ul class="Rk-Edit-ColorPicker">'
+    '<h2><span class="Rk-CloseX">&times;</span><%-translate("Edit Edge")%></span></h2>'
+    + '<p><label><%-translate("Title:")%></label><input class="Rk-Edit-Title" type="text" value="<%=edge.title%>"/></p>'
+    + '<p><label><%-translate("URI:")%></label><input class="Rk-Edit-URI" type="text" value="<%=edge.uri%>"/><a class="Rk-Edit-Goto" href="<%=edge.uri%>" target="_blank"></a></p>'
+    + '<div class="Rk-Editor-p"><span class="Rk-Editor-Label"><%-translate("Edge color:")%></span><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-Edit-Color" style="background:<%=edge.color%>;"><span class="Rk-Edit-ColorTip"></span></span><ul class="Rk-Edit-ColorPicker">'
     + '<% print(Rkns.pickerColors.reduce(function(m,c) { return m + "<li data-color=\'" + c + "\' style=\'background: " + c + "\'></li>"},"")); %></ul><span class="Rk-Edit-ColorPicker-Text">Choose color</span></div></div>'
-    + '<p><label><%=l10n.edit_from%></label><span class="Rk-UserColor" style="background:<%=edge.from_color%>;"></span><%=edge.from_title%></p>'
-    + '<p><label><%=l10n.edit_to%></label><span class="Rk-UserColor" style="background:<%=edge.to_color%>;"></span><%=edge.to_title%></p>'
-    + '<p><label><%=l10n.created_by%> </label><span class="Rk-UserColor" style="background:<%=edge.created_by_color%>;"></span><%=edge.created_by_title%></p>'
+    + '<p><span class="Rk-Editor-Label"><%-translate("From:")%></span><span class="Rk-UserColor" style="background:<%=edge.from_color%>;"></span><%=edge.from_title%></p>'
+    + '<p><span class="Rk-Editor-Label"><%-translate("To:")%></span><span class="Rk-UserColor" style="background:<%=edge.to_color%>;"></span><%=edge.to_title%></p>'
+    + '<p><span class="Rk-Editor-Label"><%-translate("Created by:")%></span><span class="Rk-UserColor" style="background:<%=edge.created_by_color%>;"></span><%=edge.created_by_title%></p>'
 );
 
 Rkns.Renderer.EdgeEditor.prototype.readOnlyTemplate = Rkns._.template(
     '<h2><span class="Rk-CloseX">&times;</span><span class="Rk-UserColor" style="background:<%=edge.color%>;"></span><%- edge.title %></span></h2>'
     + '<p><a href="<%-edge.uri%>" target="_blank"><%-edge.uri%></a></p>'
     + '<p><%-edge.description%></p>'
-    + '<p><label><%=l10n.edit_from%></label><span class="Rk-UserColor" style="background:<%=edge.from_color%>;"></span><%=edge.from_title%></p>'
-    + '<p><label><%=l10n.edit_to%></label><span class="Rk-UserColor" style="background:<%=edge.to_color%>;"></span><%=edge.to_title%></p>'
-    + '<p><label><%=l10n.created_by%> </label><span class="Rk-UserColor" style="background:<%=edge.created_by_color%>;"></span><%=edge.created_by_title%></p>'
+    + '<p><span class="Rk-Editor-Label"><%-translate("From:")%></span><span class="Rk-UserColor" style="background:<%=edge.from_color%>;"></span><%=edge.from_title%></p>'
+    + '<p><span class="Rk-Editor-Label"><%-translate("To:")%></span><span class="Rk-UserColor" style="background:<%=edge.to_color%>;"></span><%=edge.to_title%></p>'
+    + '<p><span class="Rk-Editor-Label"><%-translate("Created by:")%></span><span class="Rk-UserColor" style="background:<%=edge.created_by_color%>;"></span><%=edge.created_by_title%></p>'
 );
 
 Rkns.Renderer.EdgeEditor.prototype.draw = function() {
@@ -793,7 +822,7 @@
                 created_by_color: _created_by.get("color"),
                 created_by_title: _created_by.get("title")
             },
-            l10n: this.renderer.renkan.l10n
+            translate: this.renderer.renkan.translate
         }));
     this.redraw();
     var _this = this;
@@ -802,15 +831,20 @@
         paper.view.draw();
     });
     if (!this.renderer.renkan.read_only) {
-        this.editor_$.find("input, textarea").bind("keyup change", function() {
-            _this.editor_$.find(".Rk-Edit-Goto").attr("href",_this.editor_$.find(".Rk-Edit-URI").val());
-            var _data = {
-                title: _this.editor_$.find(".Rk-Edit-Title").val(),
-                uri: _this.editor_$.find(".Rk-Edit-URI").val()
-            }
-            _model.set(_data);
-            _this.redraw();
-        });
+    	
+    	var onFieldChange = Rkns._(function() {
+    		Rkns._(function() {
+    			_this.editor_$.find(".Rk-Edit-Goto").attr("href",_this.editor_$.find(".Rk-Edit-URI").val());
+	            var _data = {
+	                title: _this.editor_$.find(".Rk-Edit-Title").val(),
+	                uri: _this.editor_$.find(".Rk-Edit-URI").val()
+	            }
+	            _model.set(_data);
+	            _this.redraw();
+    		}).defer();
+    	}).throttle(500);
+    	
+        this.editor_$.find("input, textarea").bind("keyup change paste", onFieldChange);
         this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover(
             function() { _this.editor_$.find(".Rk-Edit-ColorPicker").show(); },
             function() { _this.editor_$.find(".Rk-Edit-ColorPicker").hide(); }
@@ -844,7 +878,7 @@
 Rkns.Renderer.NodeEditButton.prototype._init = function() {
     this.renderer.overlay_layer.activate();
     this.type = "Node-edit-button";
-    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._NODE_BUTTON_INNER, Rkns.Renderer._NODE_BUTTON_OUTER, - 90, 30, 1, this.renderer.renkan.static_url+'img/edit.png', this.renderer.renkan.l10n.caption_edit);
+    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._NODE_BUTTON_INNER, Rkns.Renderer._NODE_BUTTON_OUTER, - 90, 30, 1, this.renderer.renkan.static_url+'img/edit.png', this.renderer.renkan.translate("Edit"));
 }
 
 Rkns.Renderer.NodeEditButton.prototype.moveTo = function(_pos) {
@@ -887,7 +921,7 @@
 Rkns.Renderer.NodeRemoveButton.prototype._init = function() {
     this.renderer.overlay_layer.activate();
     this.type = "Node-remove-button";
-    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._NODE_BUTTON_INNER, Rkns.Renderer._NODE_BUTTON_OUTER, -210, -90, 1, this.renderer.renkan.static_url+'img/remove.png', this.renderer.renkan.l10n.caption_remove);
+    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._NODE_BUTTON_INNER, Rkns.Renderer._NODE_BUTTON_OUTER, -210, -90, 1, this.renderer.renkan.static_url+'img/remove.png', this.renderer.renkan.translate("Remove"));
 }
 
 Rkns.Renderer.NodeRemoveButton.prototype.moveTo = function(_pos) {
@@ -915,7 +949,7 @@
 
 Rkns.Renderer.NodeRemoveButton.prototype.mouseup = function() {
     this.renderer.removeRepresentationsOfType("editor");
-    if (confirm('Do you really wish to remove node "' + this.node_representation.model.get("title") + '"?')) {
+    if (confirm(this.renderer.renkan.translate('Do you really wish to remove node ') + '"' + this.node_representation.model.get("title") + '"?')) {
         this.project.removeNode(this.node_representation.model);
     }
 }
@@ -931,7 +965,7 @@
 Rkns.Renderer.NodeLinkButton.prototype._init = function() {
     this.renderer.overlay_layer.activate();
     this.type = "Node-link-button";
-    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._NODE_BUTTON_INNER, Rkns.Renderer._NODE_BUTTON_OUTER, 30, 150, 1, this.renderer.renkan.static_url+'img/link.png', this.renderer.renkan.l10n.caption_link);
+    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._NODE_BUTTON_INNER, Rkns.Renderer._NODE_BUTTON_OUTER, 30, 150, 1, this.renderer.renkan.static_url+'img/link.png', this.renderer.renkan.translate("Link to another node"));
 }
 
 Rkns.Renderer.NodeLinkButton.prototype.moveTo = function(_pos) {
@@ -968,7 +1002,7 @@
 Rkns.Renderer.EdgeEditButton.prototype._init = function() {
     this.renderer.overlay_layer.activate();
     this.type = "Edge-edit-button";
-    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._EDGE_BUTTON_INNER, Rkns.Renderer._EDGE_BUTTON_OUTER, - 90, 90, 1, this.renderer.renkan.static_url+'img/edit.png', this.renderer.renkan.l10n.caption_edit);
+    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._EDGE_BUTTON_INNER, Rkns.Renderer._EDGE_BUTTON_OUTER, - 90, 90, 1, this.renderer.renkan.static_url+'img/edit.png', this.renderer.renkan.translate("Edit"));
 }
 
 Rkns.Renderer.EdgeEditButton.prototype.moveTo = function(_pos) {
@@ -1011,7 +1045,7 @@
 Rkns.Renderer.EdgeRemoveButton.prototype._init = function() {
     this.renderer.overlay_layer.activate();
     this.type = "Edge-remove-button";
-    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._EDGE_BUTTON_INNER, Rkns.Renderer._EDGE_BUTTON_OUTER, - 270, -90, 1, this.renderer.renkan.static_url+'img/remove.png', this.renderer.renkan.l10n.caption_remove);
+    this.sector = Rkns.Renderer.Utils.sector(this, Rkns.Renderer._EDGE_BUTTON_INNER, Rkns.Renderer._EDGE_BUTTON_OUTER, - 270, -90, 1, this.renderer.renkan.static_url+'img/remove.png', this.renderer.renkan.translate("Remove"));
 }
 Rkns.Renderer.EdgeRemoveButton.prototype.moveTo = function(_pos) {
     this.sector.moveTo(_pos);
@@ -1038,7 +1072,7 @@
 
 Rkns.Renderer.EdgeRemoveButton.prototype.mouseup = function() {
     this.renderer.removeRepresentationsOfType("editor");
-    if (confirm('Do you really wish to remove edge "' + this.edge_representation.model.get("title") + '"?')) {
+    if (confirm(this.renderer.renkan.translate('Do you really wish to remove edge ') + '"' + this.edge_representation.model.get("title") + '"?')) {
         this.project.removeEdge(this.edge_representation.model);
     }
 }
@@ -1092,6 +1126,59 @@
     this.canvas_$.mouseenter(function(_event) {
         _this.onMouseEnter(_event);
     });
+    this.canvas_$.on("dragover", function(_event) {
+    	_event.stopPropagation();
+    	_event.preventDefault();
+    })
+    this.canvas_$.on("drop", function(_event) {
+    	_event.stopPropagation();
+    	_event.preventDefault();
+    	var res = {}
+    	Rkns._(_event.originalEvent.dataTransfer.types).each(function(t) {
+    		return res[t] = _event.originalEvent.dataTransfer.getData(t);
+    	});
+    	var newNode = {};
+    	if (res["text/plain"]) {
+    		newNode.description = res["text/plain"].replace(/[\s\n]+/gm,' ').trim();
+    	}
+    	if (res["text/html"]) {
+    		var snippet = Rkns.$('<div>').html(res["text/html"]);
+    		newNode.image = snippet.find("img").attr("src") || '';
+    		newNode.uri = snippet.find("a").attr("href");
+    	}
+    	if (res["text/uri-list"]) {
+    		newNode.uri = res["text/uri-list"];
+    	}
+    	if (res["text/x-moz-url"]) {
+    		newNode.title = (res["text/x-moz-url"].split("\n")[1] || "").trim();
+    		if (newNode.title === newNode.uri) {
+    			newNode.title = "";
+    		}
+    	}
+    	if (newNode.title || newNode.description || newNode.uri) {
+    		console.log(newNode);
+    		var _off = _this.canvas_$.offset(),
+            _point = new paper.Point([
+                _event.originalEvent.pageX - _off.left,
+                _event.originalEvent.pageY - _off.top
+            ]),
+            _coords = _this.toModelCoords(_point),
+            _data = {
+                id: Rkns.Utils.getUID('node'),
+                created_by: _this.renkan.current_user,
+                uri: newNode.uri || "",
+                title: newNode.title || _this.renkan.translate("Dragged resource"),
+                description: newNode.description || "",
+                image: newNode.image || "",
+                position: {
+                    x: _coords.x,
+                    y: _coords.y
+                }
+            };
+        	var _node = _this.renkan.project.addNode(_data);
+            _this.getRepresentationByModel(_node).openEditor();
+    	}
+    })
     this.editor_$.find(".Rk-ZoomOut").click(function() {
         _this.offset = new paper.Point([
             _this.canvas_$.width(),
@@ -1141,7 +1228,7 @@
             _this.notif_$.hide();
         } else {
             _this.click_mode = Rkns.Renderer._CLICKMODE_ADDNODE;
-            _this.notif_$.html(_renkan.l10n.notif_add_node).fadeIn();
+            _this.notif_$.html(_renkan.translate("Click on the background canvas to add a node")).fadeIn();
         }
     });
     this.$.find(".Rk-AddEdge-Button").click(function() {
@@ -1150,7 +1237,7 @@
             _this.notif_$.hide();
         } else {
             _this.click_mode = Rkns.Renderer._CLICKMODE_STARTEDGE;
-            _this.notif_$.html(_renkan.l10n.notif_start_edge).fadeIn();
+            _this.notif_$.html(_renkan.translate("Click on a first node to start the edge")).fadeIn();
         }
     });
     this.$.find(".Rk-TopBar-Button").mouseover(function() {
@@ -1209,18 +1296,18 @@
 }
 
 Rkns.Renderer.Scene.prototype.template = Rkns._.template(
-    '<div class="Rk-TopBar"><% if (read_only) { %><h2 class="Rk-PadTitle"><%- project.get("title") || l10n.untitled_project%></h2>'
-    + '<% } else { %><input type="text" class="Rk-PadTitle" value="<%- project.get("title") || "" %>" placeholder="<%=l10n.untitled_project%>" /><% } %>'
+    '<div class="Rk-TopBar"><% if (read_only) { %><h2 class="Rk-PadTitle"><%- project.get("title") || translate("Untitled project")%></h2>'
+    + '<% } else { %><input type="text" class="Rk-PadTitle" value="<%- project.get("title") || "" %>" placeholder="<%-translate("Untitled project")%>" /><% } %>'
     + '<div class="Rk-Users"><div class="Rk-CurrentUser"><span class="Rk-CurrentUser-Color"></span><span class="Rk-CurrentUser-Name">&lt;unknown user&gt;</span></div><ul class="Rk-UserList"></ul></div>'
-    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-FullScreen-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%=l10n.full_screen%></div></div></div>'
+    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-FullScreen-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%-translate("Full Screen")%></div></div></div>'
     + '<% if (!read_only) { %>'
-    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-AddNode-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%=l10n.add_node%></div></div></div>'
-    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-AddEdge-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%=l10n.add_edge%></div></div></div>'
-    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-Save-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%=l10n.save_project%></div></div></div>'
+    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-AddNode-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%-translate("Add Node")%></div></div></div>'
+    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-AddEdge-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%-translate("Add Edge")%></div></div></div>'
+    + '<div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-Save-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Tip"></div><div class="Rk-TopBar-Tooltip-Contents"><%-translate("Archive Project")%></div></div></div>'
     + '<div class="Rk-TopBar-Separator"></div></div>'
     + '<% } %>'
     + '<canvas class="Rk-Canvas" resize></canvas><div class="Rk-Editor"><div class="Rk-Notifications"></div>'
-    + '<div class="Rk-ZoomButtons"><div class="Rk-ZoomIn" title="<%=l10n.zoom_in%>"></div><div class="Rk-ZoomOut" title="<%=l10n.zoom_out%>"></div></div>'
+    + '<div class="Rk-ZoomButtons"><div class="Rk-ZoomIn" title="<%-translate("Zoom In")%>"></div><div class="Rk-ZoomOut" title="<%-translate("Zoom Out")%>"></div></div>'
     + '</div>'
 );
 
@@ -1441,7 +1528,7 @@
             this.addTempEdge(this.click_target, _event.point);
             this.click_mode = Rkns.Renderer._CLICKMODE_ENDEDGE;
             this.notif_$.fadeOut(function() {
-                Rkns.$(this).html(_renkan.l10n.notif_end_edge).fadeIn();
+                Rkns.$(this).html(_renkan.translate("Click on a second node to complete the edge")).fadeIn();
             });
         } else {
             this.notif_$.hide();