diff -r 4c7ab16e5845 -r 19f0b7803aed client/js/main.js --- a/client/js/main.js Mon May 25 01:18:12 2015 +0200 +++ b/client/js/main.js Fri May 29 14:57:37 2015 +0200 @@ -1,555 +1,568 @@ - /* Declaring the Renkan Namespace Rkns and Default values */ (function(root) { -"use strict"; + "use strict"; + + if (typeof root.Rkns !== "object") { + root.Rkns = {}; + } + + var Rkns = root.Rkns; + var $ = Rkns.$ = root.jQuery; + var _ = Rkns._ = root._; -if (typeof root.Rkns !== "object") { - root.Rkns = {}; -} + Rkns.pickerColors = ["#8f1919", "#a80000", "#d82626", "#ff0000", "#e87c7c", "#ff6565", "#f7d3d3", "#fecccc", + "#8f5419", "#a85400", "#d87f26", "#ff7f00", "#e8b27c", "#ffb265", "#f7e5d3", "#fee5cc", + "#8f8f19", "#a8a800", "#d8d826", "#feff00", "#e8e87c", "#feff65", "#f7f7d3", "#fefecc", + "#198f19", "#00a800", "#26d826", "#00ff00", "#7ce87c", "#65ff65", "#d3f7d3", "#ccfecc", + "#198f8f", "#00a8a8", "#26d8d8", "#00feff", "#7ce8e8", "#65feff", "#d3f7f7", "#ccfefe", + "#19198f", "#0000a8", "#2626d8", "#0000ff", "#7c7ce8", "#6565ff", "#d3d3f7", "#ccccfe", + "#8f198f", "#a800a8", "#d826d8", "#ff00fe", "#e87ce8", "#ff65fe", "#f7d3f7", "#feccfe", + "#000000", "#242424", "#484848", "#6d6d6d", "#919191", "#b6b6b6", "#dadada", "#ffffff" + ]; + + Rkns.__renkans = []; -var Rkns = root.Rkns; -var $ = Rkns.$ = root.jQuery; -var _ = Rkns._ = root._; + var _BaseBin = Rkns._BaseBin = function(_renkan, _opts) { + if (typeof _renkan !== "undefined") { + this.renkan = _renkan; + this.renkan.$.find(".Rk-Bin-Main").hide(); + this.$ = Rkns.$('
  • ') + .addClass("Rk-Bin") + .appendTo(_renkan.$.find(".Rk-Bin-List")); + this.title_icon_$ = Rkns.$('') + .addClass("Rk-Bin-Title-Icon") + .appendTo(this.$); + + var _this = this; -Rkns.pickerColors = ["#8f1919", "#a80000", "#d82626", "#ff0000", "#e87c7c", "#ff6565", "#f7d3d3", "#fecccc", - "#8f5419", "#a85400", "#d87f26", "#ff7f00", "#e8b27c", "#ffb265", "#f7e5d3", "#fee5cc", - "#8f8f19", "#a8a800", "#d8d826", "#feff00", "#e8e87c", "#feff65", "#f7f7d3", "#fefecc", - "#198f19", "#00a800", "#26d826", "#00ff00", "#7ce87c", "#65ff65", "#d3f7d3", "#ccfecc", - "#198f8f", "#00a8a8", "#26d8d8", "#00feff", "#7ce8e8", "#65feff", "#d3f7f7", "#ccfefe", - "#19198f", "#0000a8", "#2626d8", "#0000ff", "#7c7ce8", "#6565ff", "#d3d3f7", "#ccccfe", - "#8f198f", "#a800a8", "#d826d8", "#ff00fe", "#e87ce8", "#ff65fe", "#f7d3f7", "#feccfe", - "#000000", "#242424", "#484848", "#6d6d6d", "#919191", "#b6b6b6", "#dadada", "#ffffff"]; - -Rkns.__renkans = []; + Rkns.$('') + .attr({ + href: "#", + title: _renkan.translate("Close bin") + }) + .addClass("Rk-Bin-Close") + .html('×') + .appendTo(this.$) + .click(function() { + _this.destroy(); + if (!_renkan.$.find(".Rk-Bin-Main:visible").length) { + _renkan.$.find(".Rk-Bin-Main:last").slideDown(); + } + _renkan.resizeBins(); + return false; + }); + Rkns.$('') + .attr({ + href: "#", + title: _renkan.translate("Refresh bin") + }) + .addClass("Rk-Bin-Refresh") + .appendTo(this.$) + .click(function() { + _this.refresh(); + return false; + }); + this.count_$ = Rkns.$('
    ') + .addClass("Rk-Bin-Count") + .appendTo(this.$); + this.title_$ = Rkns.$('

    ') + .addClass("Rk-Bin-Title") + .appendTo(this.$); + this.main_$ = Rkns.$('
    ') + .addClass("Rk-Bin-Main") + .appendTo(this.$) + .html('

    ' + _renkan.translate("Loading, please wait") + '

    '); + this.title_$.html(_opts.title || '(new bin)'); + this.renkan.resizeBins(); -var _BaseBin = Rkns._BaseBin = function(_renkan, _opts) { - if (typeof _renkan !== "undefined") { - this.renkan = _renkan; - this.renkan.$.find(".Rk-Bin-Main").hide(); - this.$ = Rkns.$('
  • ') - .addClass("Rk-Bin") - .appendTo(_renkan.$.find(".Rk-Bin-List")); - this.title_icon_$ = Rkns.$('') - .addClass("Rk-Bin-Title-Icon") - .appendTo(this.$); + if (_opts.auto_refresh) { + window.setInterval(function() { + _this.refresh(); + }, _opts.auto_refresh); + } + } + }; + _BaseBin.prototype.destroy = function() { + this.$.detach(); + this.renkan.resizeBins(); + }; + + /* Point of entry */ + + var Renkan = Rkns.Renkan = function(_opts) { var _this = this; - Rkns.$('') - .attr({ - href: "#", - title: _renkan.translate("Close bin") - }) - .addClass("Rk-Bin-Close") - .html('×') - .appendTo(this.$) - .click(function() { - _this.destroy(); - if (!_renkan.$.find(".Rk-Bin-Main:visible").length) { - _renkan.$.find(".Rk-Bin-Main:last").slideDown(); - } - _renkan.resizeBins(); - return false; - }); - Rkns.$('') - .attr({ - href: "#", - title: _renkan.translate("Refresh bin") - }) - .addClass("Rk-Bin-Refresh") - .appendTo(this.$) - .click(function() { - _this.refresh(); - return false; - }); - this.count_$ = Rkns.$('
    ') - .addClass("Rk-Bin-Count") - .appendTo(this.$); - this.title_$ = Rkns.$('

    ') - .addClass("Rk-Bin-Title") - .appendTo(this.$); - this.main_$ = Rkns.$('
    ') - .addClass("Rk-Bin-Main") - .appendTo(this.$) - .html('

    ' + _renkan.translate("Loading, please wait") + '

    '); - this.title_$.html(_opts.title || '(new bin)'); - this.renkan.resizeBins(); + Rkns.__renkans.push(this); + + this.options = _.defaults(_opts, Rkns.defaults, { + templates: renkanJST + }); + this.template = renkanJST['templates/main.html']; - if (_opts.auto_refresh) { - window.setInterval(function() { - _this.refresh(); - },_opts.auto_refresh); - } - } -}; - -_BaseBin.prototype.destroy = function() { - this.$.detach(); - this.renkan.resizeBins(); -}; - -/* Point of entry */ - -var Renkan = Rkns.Renkan = function(_opts) { - var _this = this; - - Rkns.__renkans.push(this); + _.each(this.options.property_files, function(f) { + Rkns.$.getJSON(f, function(data) { + _this.options.properties = _this.options.properties.concat(data); + }); + }); - this.options = _.defaults(_opts, Rkns.defaults, {templates: renkanJST}); - this.template = renkanJST['templates/main.html']; - - _.each(this.options.property_files,function(f) { - Rkns.$.getJSON(f, function(data) { - _this.options.properties = _this.options.properties.concat(data); - }); - }); - - this.read_only = this.options.read_only || !this.options.editor_mode; + this.read_only = this.options.read_only || !this.options.editor_mode; - this.project = new Rkns.Models.Project(); - - this.setCurrentUser = function (user_id, user_name) { - this.project.addUser({ - _id:user_id, - title: user_name - }); - this.current_user = user_id; - this.renderer.redrawUsers(); - }; + this.project = new Rkns.Models.Project(); + this.dataloader = new Rkns.DataLoader.Loader(this.project, this.options); - if (typeof this.options.user_id !== "undefined") { - this.current_user = this.options.user_id; - } - this.$ = Rkns.$("#" + this.options.container); - this.$ - .addClass("Rk-Main") - .html(this.template(this)); - - this.tabs = []; - this.search_engines = []; - - this.current_user_list = new Rkns.Models.UsersList(); - - this.current_user_list.on("add remove", function() { - if (this.renderer) { + this.setCurrentUser = function(user_id, user_name) { + this.project.addUser({ + _id: user_id, + title: user_name + }); + this.current_user = user_id; this.renderer.redrawUsers(); - } - }); - - this.colorPicker = (function() { - var _tmpl = renkanJST['templates/colorpicker.html']; - return '
      ' + Rkns.pickerColors.map(function(c) { return _tmpl({c:c});}).join("") + '
    '; - })(); - - if (this.options.show_editor) { - this.renderer = new Rkns.Renderer.Scene(this); - } + }; - if (!this.options.search.length) { - this.$.find(".Rk-Web-Search-Form").detach(); - } else { - var _tmpl = renkanJST['templates/search.html'], - _select = this.$.find(".Rk-Search-List"), - _input = this.$.find(".Rk-Web-Search-Input"), - _form = this.$.find(".Rk-Web-Search-Form"); - _.each(this.options.search, function(_search, _key) { - if (Rkns[_search.type] && Rkns[_search.type].Search) { - _this.search_engines.push(new Rkns[_search.type].Search(_this, _search)); - } - }); - _select.html( - _(this.search_engines).map(function(_search, _key) { - return _tmpl({ - key: _key, - title: _search.getSearchTitle(), - className: _search.getBgClass() - }); - }).join("") - ); - _select.find("li").click(function() { - var _el = Rkns.$(this); - _this.setSearchEngine(_el.attr("data-key")); - _form.submit(); - }); - _form.submit(function() { - if (_input.val()) { - var _search = _this.search_engine; - _search.search(_input.val()); - } - return false; - }); - this.$.find(".Rk-Search-Current").mouseenter( - function() { _select.slideDown(); } - ); - this.$.find(".Rk-Search-Select").mouseleave( - function() { _select.hide(); } - ); - this.setSearchEngine(0); - } - _.each(this.options.bins, function(_bin) { - if (Rkns[_bin.type] && Rkns[_bin.type].Bin) { - _this.tabs.push(new Rkns[_bin.type].Bin(_this, _bin)); + if (typeof this.options.user_id !== "undefined") { + this.current_user = this.options.user_id; } - }); - - var elementDropped = false; + this.$ = Rkns.$("#" + this.options.container); + this.$ + .addClass("Rk-Main") + .html(this.template(this)); - this.$.find(".Rk-Bins") - .on("click",".Rk-Bin-Title,.Rk-Bin-Title-Icon", function() { - var _mainDiv = Rkns.$(this).siblings(".Rk-Bin-Main"); - if (_mainDiv.is(":hidden")) { - _this.$.find(".Rk-Bin-Main").slideUp(); - _mainDiv.slideDown(); + this.tabs = []; + this.search_engines = []; + + this.current_user_list = new Rkns.Models.UsersList(); + + this.current_user_list.on("add remove", function() { + if (this.renderer) { + this.renderer.redrawUsers(); } }); - if (this.options.show_editor) { - - this.$.find(".Rk-Bins").on("mouseover", ".Rk-Bin-Item", function(_e) { - var _t = Rkns.$(this); - if (_t && $(_t).attr("data-uri")) { - var _models = _this.project.get("nodes").where({ - uri: $(_t).attr("data-uri") - }); - _.each(_models, function(_model) { - _this.renderer.highlightModel(_model); + this.colorPicker = (function() { + var _tmpl = renkanJST['templates/colorpicker.html']; + return '
      ' + Rkns.pickerColors.map(function(c) { + return _tmpl({ + c: c }); - } - }).mouseout(function() { - _this.renderer.unhighlightAll(); - }).on("mousemove", ".Rk-Bin-Item", function(e) { - try { - this.dragDrop(); - } - catch(err) {} - }).on("touchstart", ".Rk-Bin-Item", function(e) { - elementDropped = false; - }).on("touchmove", ".Rk-Bin-Item", function(e) { - e.preventDefault(); - var touch = e.originalEvent.changedTouches[0], - off = _this.renderer.canvas_$.offset(), - w = _this.renderer.canvas_$.width(), - h = _this.renderer.canvas_$.height(); - if (touch.pageX >= off.left && touch.pageX < (off.left + w) && touch.pageY >= off.top && touch.pageY < (off.top + h)) { - if (elementDropped) { - _this.renderer.onMouseMove(touch, true); - } else { - elementDropped = true; - var div = document.createElement('div'); - div.appendChild(this.cloneNode(true)); - _this.renderer.dropData({"text/html": div.innerHTML}, touch); - _this.renderer.onMouseDown(touch, true); + }).join("") + '
    '; + })(); + + if (this.options.show_editor) { + this.renderer = new Rkns.Renderer.Scene(this); + } + + if (!this.options.search.length) { + this.$.find(".Rk-Web-Search-Form").detach(); + } else { + var _tmpl = renkanJST['templates/search.html'], + _select = this.$.find(".Rk-Search-List"), + _input = this.$.find(".Rk-Web-Search-Input"), + _form = this.$.find(".Rk-Web-Search-Form"); + _.each(this.options.search, function(_search, _key) { + if (Rkns[_search.type] && Rkns[_search.type].Search) { + _this.search_engines.push(new Rkns[_search.type].Search(_this, _search)); } - } - }).on("touchend", ".Rk-Bin-Item", function(e) { - if (elementDropped) { - _this.renderer.onMouseUp(e.originalEvent.changedTouches[0], true); - } - elementDropped = false; - }).on("dragstart", ".Rk-Bin-Item", function(e) { - var div = document.createElement('div'); - div.appendChild(this.cloneNode(true)); - try { - e.originalEvent.dataTransfer.setData("text/html",div.innerHTML); - } - catch(err) { - e.originalEvent.dataTransfer.setData("text",div.innerHTML); + }); + _select.html( + _(this.search_engines).map(function(_search, _key) { + return _tmpl({ + key: _key, + title: _search.getSearchTitle(), + className: _search.getBgClass() + }); + }).join("") + ); + _select.find("li").click(function() { + var _el = Rkns.$(this); + _this.setSearchEngine(_el.attr("data-key")); + _form.submit(); + }); + _form.submit(function() { + if (_input.val()) { + var _search = _this.search_engine; + _search.search(_input.val()); + } + return false; + }); + this.$.find(".Rk-Search-Current").mouseenter( + function() { + _select.slideDown(); + } + ); + this.$.find(".Rk-Search-Select").mouseleave( + function() { + _select.hide(); + } + ); + this.setSearchEngine(0); + } + _.each(this.options.bins, function(_bin) { + if (Rkns[_bin.type] && Rkns[_bin.type].Bin) { + _this.tabs.push(new Rkns[_bin.type].Bin(_this, _bin)); } }); - } + var elementDropped = false; - Rkns.$(window).resize(function() { - _this.resizeBins(); - }); + this.$.find(".Rk-Bins") + .on("click", ".Rk-Bin-Title,.Rk-Bin-Title-Icon", function() { + var _mainDiv = Rkns.$(this).siblings(".Rk-Bin-Main"); + if (_mainDiv.is(":hidden")) { + _this.$.find(".Rk-Bin-Main").slideUp(); + _mainDiv.slideDown(); + } + }); - var lastsearch = false, lastval = ''; + if (this.options.show_editor) { - this.$.find(".Rk-Bins-Search-Input").on("change keyup paste input", function() { - var val = Rkns.$(this).val(); - if (val === lastval) { - return; + this.$.find(".Rk-Bins").on("mouseover", ".Rk-Bin-Item", function(_e) { + var _t = Rkns.$(this); + if (_t && $(_t).attr("data-uri")) { + var _models = _this.project.get("nodes").where({ + uri: $(_t).attr("data-uri") + }); + _.each(_models, function(_model) { + _this.renderer.highlightModel(_model); + }); + } + }).mouseout(function() { + _this.renderer.unhighlightAll(); + }).on("mousemove", ".Rk-Bin-Item", function(e) { + try { + this.dragDrop(); + } catch (err) {} + }).on("touchstart", ".Rk-Bin-Item", function(e) { + elementDropped = false; + }).on("touchmove", ".Rk-Bin-Item", function(e) { + e.preventDefault(); + var touch = e.originalEvent.changedTouches[0], + off = _this.renderer.canvas_$.offset(), + w = _this.renderer.canvas_$.width(), + h = _this.renderer.canvas_$.height(); + if (touch.pageX >= off.left && touch.pageX < (off.left + w) && touch.pageY >= off.top && touch.pageY < (off.top + h)) { + if (elementDropped) { + _this.renderer.onMouseMove(touch, true); + } else { + elementDropped = true; + var div = document.createElement('div'); + div.appendChild(this.cloneNode(true)); + _this.renderer.dropData({ + "text/html": div.innerHTML + }, touch); + _this.renderer.onMouseDown(touch, true); + } + } + }).on("touchend", ".Rk-Bin-Item", function(e) { + if (elementDropped) { + _this.renderer.onMouseUp(e.originalEvent.changedTouches[0], true); + } + elementDropped = false; + }).on("dragstart", ".Rk-Bin-Item", function(e) { + var div = document.createElement('div'); + div.appendChild(this.cloneNode(true)); + try { + e.originalEvent.dataTransfer.setData("text/html", div.innerHTML); + } catch (err) { + e.originalEvent.dataTransfer.setData("text", div.innerHTML); + } + }); + } - var search = Rkns.Utils.regexpFromTextOrArray(val.length > 1 ? val: null); - if (search.source === lastsearch) { - return; - } - lastsearch = search.source; - _.each(_this.tabs, function(tab) { - tab.render(search); + + Rkns.$(window).resize(function() { + _this.resizeBins(); }); - }); - this.$.find(".Rk-Bins-Search-Form").submit(function() { - return false; - }); - -}; - -Renkan.prototype.translate = function(_text) { - if (Rkns.i18n[this.options.language] && Rkns.i18n[this.options.language][_text]) { - return Rkns.i18n[this.options.language][_text]; - } - if (this.options.language.length > 2 && Rkns.i18n[this.options.language.substr(0,2)] && Rkns.i18n[this.options.language.substr(0,2)][_text]) { - return Rkns.i18n[this.options.language.substr(0,2)][_text]; - } - return _text; -}; - -Renkan.prototype.onStatusChange = function() { - this.renderer.onStatusChange(); -}; - -Renkan.prototype.setSearchEngine = function(_key) { - this.search_engine = this.search_engines[_key]; - this.$.find(".Rk-Search-Current").attr("class","Rk-Search-Current " + this.search_engine.getBgClass()); - var listClasses = this.search_engine.getBgClass().split(" "); - var classes = ""; - for (var i= 0; i < listClasses.length; i++) { - classes += "." + listClasses[i]; - } - this.$.find(".Rk-Web-Search-Input.Rk-Search-Input").attr("placeholder", this.translate("Search in ") + this.$.find(".Rk-Search-List "+ classes).html()); -}; - -Renkan.prototype.resizeBins = function() { - var _d = + this.$.find(".Rk-Bins-Head").outerHeight(); - this.$.find(".Rk-Bin-Title:visible").each(function() { - _d += Rkns.$(this).outerHeight(); - }); - this.$.find(".Rk-Bin-Main").css({ - height: this.$.find(".Rk-Bins").height() - _d - }); -}; - -/* Utility functions */ -var getUUID4 = function() { - return '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 lastsearch = false, + lastval = ''; -Rkns.Utils = { - getUUID4 : getUUID4, - getUID : (function() { - function pad(n){ - return n<10 ? '0'+n : n; - } - var _d = new Date(), - ID_AUTO_INCREMENT = 0, - ID_BASE = _d.getUTCFullYear() + '-' + - pad(_d.getUTCMonth()+1) + '-' + - pad(_d.getUTCDate()) + '-' + - getUUID4(); - return function(_base) { - var _n = (++ID_AUTO_INCREMENT).toString(16), - _uidbase = (typeof _base === "undefined" ? "" : _base + "-" ); - while (_n.length < 4) { _n = '0' + _n; } - return _uidbase + ID_BASE + '-' + _n; - }; - })(), - getFullURL : function(url) { - - if(typeof(url) === 'undefined' || url == null ) { - return ""; - } - if(/https?:\/\//.test(url)) { - return url; - } - var img = new Image(); - img.src = url; - var res = img.src; - img.src = null; - return res; - - }, - inherit : function(_baseClass, _callbefore) { - - var _class = function(_arg) { - if (typeof _callbefore === "function") { - _callbefore.apply(this, Array.prototype.slice.call(arguments, 0)); + this.$.find(".Rk-Bins-Search-Input").on("change keyup paste input", function() { + var val = Rkns.$(this).val(); + if (val === lastval) { + return; } - _baseClass.apply(this, Array.prototype.slice.call(arguments, 0)); - if (typeof this._init === "function" && !this._initialized) { - this._init.apply(this, Array.prototype.slice.call(arguments, 0)); - this._initialized = true; + var search = Rkns.Utils.regexpFromTextOrArray(val.length > 1 ? val : null); + if (search.source === lastsearch) { + return; } - }; - _.extend(_class.prototype,_baseClass.prototype); - - return _class; - - }, - regexpFromTextOrArray: (function() { - var charsub = [ - '[aáàâä]', - '[cç]', - '[eéèêë]', - '[iíìîï]', - '[oóòôö]', - '[uùûü]' - ], - removeChars = [ - String.fromCharCode(768), String.fromCharCode(769), String.fromCharCode(770), String.fromCharCode(771), String.fromCharCode(807), - "{", "}", "(", ")", "[", "]", "【", "】", "、", "・", "‥", "。", "「", "」", "『", "』", "〜", ":", "!", "?", " ", - ",", " ", ";", "(", ")", ".", "*", "+", "\\", "?", "|", "{", "}", "[", "]", "^", "#", "/" - ], - remsrc = "[\\" + removeChars.join("\\") + "]", - remrx = new RegExp(remsrc, "gm"), - charsrx = _.map(charsub, function(c) { - return new RegExp(c); + lastsearch = search.source; + _.each(_this.tabs, function(tab) { + tab.render(search); }); - function replaceText(_text) { - var txt = _text.toLowerCase().replace(remrx,""), src = ""; - function makeReplaceFunc(l) { - return function(k,v) { - l = l.replace(charsrx[k], v); - }; - } - for (var j = 0; j < txt.length; j++) { - if (j) { - src += remsrc + "*"; - } - var l = txt[j]; - _.each(charsub, makeReplaceFunc(l)); - src += l; - } - return src; + }); + this.$.find(".Rk-Bins-Search-Form").submit(function() { + return false; + }); + + }; + + Renkan.prototype.translate = function(_text) { + if (Rkns.i18n[this.options.language] && Rkns.i18n[this.options.language][_text]) { + return Rkns.i18n[this.options.language][_text]; + } + if (this.options.language.length > 2 && Rkns.i18n[this.options.language.substr(0, 2)] && Rkns.i18n[this.options.language.substr(0, 2)][_text]) { + return Rkns.i18n[this.options.language.substr(0, 2)][_text]; } + return _text; + }; + + Renkan.prototype.onStatusChange = function() { + this.renderer.onStatusChange(); + }; + + Renkan.prototype.setSearchEngine = function(_key) { + this.search_engine = this.search_engines[_key]; + this.$.find(".Rk-Search-Current").attr("class", "Rk-Search-Current " + this.search_engine.getBgClass()); + var listClasses = this.search_engine.getBgClass().split(" "); + var classes = ""; + for (var i = 0; i < listClasses.length; i++) { + classes += "." + listClasses[i]; + } + this.$.find(".Rk-Web-Search-Input.Rk-Search-Input").attr("placeholder", this.translate("Search in ") + this.$.find(".Rk-Search-List " + classes).html()); + }; + + Renkan.prototype.resizeBins = function() { + var _d = +this.$.find(".Rk-Bins-Head").outerHeight(); + this.$.find(".Rk-Bin-Title:visible").each(function() { + _d += Rkns.$(this).outerHeight(); + }); + this.$.find(".Rk-Bin-Main").css({ + height: this.$.find(".Rk-Bins").height() - _d + }); + }; + + /* Utility functions */ + var getUUID4 = function() { + return '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); + }); + }; - function getSource(inp) { - switch (typeof inp) { - case "string": - return replaceText(inp); - case "object": - var src = ''; - _.each(inp, function(v) { - var res = getSource(v); - if (res) { - if (src) { - src += '|'; - } - src += res; - } - }); - return src; + Rkns.Utils = { + getUUID4: getUUID4, + getUID: (function() { + function pad(n) { + return n < 10 ? '0' + n : n; } - return ''; - } + var _d = new Date(), + ID_AUTO_INCREMENT = 0, + ID_BASE = _d.getUTCFullYear() + '-' + + pad(_d.getUTCMonth() + 1) + '-' + + pad(_d.getUTCDate()) + '-' + + getUUID4(); + return function(_base) { + var _n = (++ID_AUTO_INCREMENT).toString(16), + _uidbase = (typeof _base === "undefined" ? "" : _base + "-"); + while (_n.length < 4) { + _n = '0' + _n; + } + return _uidbase + ID_BASE + '-' + _n; + }; + })(), + getFullURL: function(url) { + + if (typeof(url) === 'undefined' || url == null) { + return ""; + } + if (/https?:\/\//.test(url)) { + return url; + } + var img = new Image(); + img.src = url; + var res = img.src; + img.src = null; + return res; + + }, + inherit: function(_baseClass, _callbefore) { - return function(_textOrArray) { - var source = getSource(_textOrArray); - if (source) { - var testrx = new RegExp( source, "im"), - replacerx = new RegExp( '(' + source + ')', "igm"); - return { - isempty: false, - source: source, - test: function(_t) { return testrx.test(_t); }, - replace: function(_text, _replace) { return _text.replace(replacerx, _replace); } - }; - } else { - return { - isempty: true, - source: '', - test: function() { return true; }, - replace: function(_text) { return text; } - }; - } - }; - })(), - /* 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 */ - _NODE_BUTTON_WIDTH: 40, + var _class = function(_arg) { + if (typeof _callbefore === "function") { + _callbefore.apply(this, Array.prototype.slice.call(arguments, 0)); + } + _baseClass.apply(this, Array.prototype.slice.call(arguments, 0)); + if (typeof this._init === "function" && !this._initialized) { + this._init.apply(this, Array.prototype.slice.call(arguments, 0)); + this._initialized = true; + } + }; + _.extend(_class.prototype, _baseClass.prototype); + + return _class; + + }, + regexpFromTextOrArray: (function() { + var charsub = [ + '[aáàâä]', + '[cç]', + '[eéèêë]', + '[iíìîï]', + '[oóòôö]', + '[uùûü]' + ], + removeChars = [ + String.fromCharCode(768), String.fromCharCode(769), String.fromCharCode(770), String.fromCharCode(771), String.fromCharCode(807), + "{", "}", "(", ")", "[", "]", "【", "】", "、", "・", "‥", "。", "「", "」", "『", "』", "〜", ":", "!", "?", " ", + ",", " ", ";", "(", ")", ".", "*", "+", "\\", "?", "|", "{", "}", "[", "]", "^", "#", "/" + ], + remsrc = "[\\" + removeChars.join("\\") + "]", + remrx = new RegExp(remsrc, "gm"), + charsrx = _.map(charsub, function(c) { + return new RegExp(c); + }); + + function replaceText(_text) { + var txt = _text.toLowerCase().replace(remrx, ""), + src = ""; - _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 */ - _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: 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 */ - _DOUBLETAP_DISTANCE: 20*20, - /* 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, - title: _renkan.translate("(unknown user)"), - get: function(attr) { - return this[attr] || false; + function makeReplaceFunc(l) { + return function(k, v) { + l = l.replace(charsrx[k], v); + }; + } + for (var j = 0; j < txt.length; j++) { + if (j) { + src += remsrc + "*"; + } + var l = txt[j]; + _.each(charsub, makeReplaceFunc(l)); + src += l; + } + return src; + } + + function getSource(inp) { + switch (typeof inp) { + case "string": + return replaceText(inp); + case "object": + var src = ''; + _.each(inp, function(v) { + var res = getSource(v); + if (res) { + if (src) { + src += '|'; + } + src += res; + } + }); + return src; + } + return ''; } - }; - }, - /* 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("Drag items from this website, drop them in Renkan").replace(/ /g,"_") + - "

    '.replace(/_/g,String.fromCharCode(32));b.appendChild(d);e=[{r:/https?:\\/\\/[^\\/]*twitter\\.com\\//,s:'.tweet',n:'twitter'},{r:/https?:\\/\\/[^\\/]*google\\.[^\\/]+\\//,s:'.g',n:'google'},{r:/https?:\\/\\/[^\\/]*lemonde\\.fr\\//,s:'[data-vr-contentbox]',n:'lemonde'}];f=false;e.forEach(function(g){if(g.r.test(c)){f=g;}});if(f){h=function(){Array.prototype.forEach.call(a.querySelectorAll(f.s),function(i){i[j]=true;k=i.style;k.borderWidth='2px';k.borderColor='#909';k.borderStyle='solid';k.backgroundColor='rgba(200,0,180,.1)';})};window.setInterval(h,500);h();};a.addEventListener('dragstart',function(k){l=k.dataTransfer;l.setData(m+'source-uri',c);l.setData(m+'source-title',a.title);n=k.target;if(f){o=n;while(!o.attributes[j]){o=o.parentNode;if(o==b){break;}}}if(f&&o.attributes[j]){p=o.cloneNode(true);l.setData(m+'specific-site',f.n)}else{q=a.getSelection();if(q.type==='Range'||!q.type){p=q.getRangeAt(0).cloneContents();}else{p=n.cloneNode();}}r=a.createElement('div');r.appendChild(p);l.setData('text/x-iri-selected-text',r.textContent.trim());l.setData('text/x-iri-selected-html',r.innerHTML);},false);})();"; - }, - /* Shortens text to the required length then adds ellipsis */ - shortenText: function(_text, _maxlength) { - return (_text.length > _maxlength ? (_text.substr(0,_maxlength) + '…') : _text); - }, - /* Drawing an edit box with an arrow and positioning the edit box according to the position of the node/edge being edited - * Called by Rkns.Renderer.NodeEditor and Rkns.Renderer.EdgeEditor */ - drawEditBox: function(_options, _coords, _path, _xmargin, _selector) { - _selector.css({ - width: ( _options.tooltip_width - 2* _options.tooltip_padding ) - }); - var _height = _selector.outerHeight() + 2* _options.tooltip_padding, - _isLeft = (_coords.x < paper.view.center.x ? 1 : -1), - _left = _coords.x + _isLeft * ( _xmargin + _options.tooltip_arrow_length ), - _right = _coords.x + _isLeft * ( _xmargin + _options.tooltip_arrow_length + _options.tooltip_width ), - _top = _coords.y - _height / 2; - if (_top + _height > (paper.view.size.height - _options.tooltip_margin)) { - _top = Math.max( paper.view.size.height - _options.tooltip_margin, _coords.y + _options.tooltip_arrow_width / 2 ) - _height; - } - if (_top < _options.tooltip_margin) { - _top = Math.min( _options.tooltip_margin, _coords.y - _options.tooltip_arrow_width / 2 ); + + return function(_textOrArray) { + var source = getSource(_textOrArray); + if (source) { + var testrx = new RegExp(source, "im"), + replacerx = new RegExp('(' + source + ')', "igm"); + return { + isempty: false, + source: source, + test: function(_t) { + return testrx.test(_t); + }, + replace: function(_text, _replace) { + return _text.replace(replacerx, _replace); + } + }; + } else { + return { + isempty: true, + source: '', + test: function() { + return true; + }, + replace: function(_text) { + return text; + } + }; + } + }; + })(), + /* 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 */ + _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 */ + _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: 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 */ + _DOUBLETAP_DISTANCE: 20 * 20, + /* 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, + title: _renkan.translate("(unknown user)"), + get: function(attr) { + return this[attr] || false; + } + }; + }, + /* 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("Drag items from this website, drop them in Renkan").replace(/ /g, "_") + + "

    '.replace(/_/g,String.fromCharCode(32));b.appendChild(d);e=[{r:/https?:\\/\\/[^\\/]*twitter\\.com\\//,s:'.tweet',n:'twitter'},{r:/https?:\\/\\/[^\\/]*google\\.[^\\/]+\\//,s:'.g',n:'google'},{r:/https?:\\/\\/[^\\/]*lemonde\\.fr\\//,s:'[data-vr-contentbox]',n:'lemonde'}];f=false;e.forEach(function(g){if(g.r.test(c)){f=g;}});if(f){h=function(){Array.prototype.forEach.call(a.querySelectorAll(f.s),function(i){i[j]=true;k=i.style;k.borderWidth='2px';k.borderColor='#909';k.borderStyle='solid';k.backgroundColor='rgba(200,0,180,.1)';})};window.setInterval(h,500);h();};a.addEventListener('dragstart',function(k){l=k.dataTransfer;l.setData(m+'source-uri',c);l.setData(m+'source-title',a.title);n=k.target;if(f){o=n;while(!o.attributes[j]){o=o.parentNode;if(o==b){break;}}}if(f&&o.attributes[j]){p=o.cloneNode(true);l.setData(m+'specific-site',f.n)}else{q=a.getSelection();if(q.type==='Range'||!q.type){p=q.getRangeAt(0).cloneContents();}else{p=n.cloneNode();}}r=a.createElement('div');r.appendChild(p);l.setData('text/x-iri-selected-text',r.textContent.trim());l.setData('text/x-iri-selected-html',r.innerHTML);},false);})();"; + }, + /* Shortens text to the required length then adds ellipsis */ + shortenText: function(_text, _maxlength) { + return (_text.length > _maxlength ? (_text.substr(0, _maxlength) + '…') : _text); + }, + /* Drawing an edit box with an arrow and positioning the edit box according to the position of the node/edge being edited + * Called by Rkns.Renderer.NodeEditor and Rkns.Renderer.EdgeEditor */ + drawEditBox: function(_options, _coords, _path, _xmargin, _selector) { + _selector.css({ + width: (_options.tooltip_width - 2 * _options.tooltip_padding) + }); + var _height = _selector.outerHeight() + 2 * _options.tooltip_padding, + _isLeft = (_coords.x < paper.view.center.x ? 1 : -1), + _left = _coords.x + _isLeft * (_xmargin + _options.tooltip_arrow_length), + _right = _coords.x + _isLeft * (_xmargin + _options.tooltip_arrow_length + _options.tooltip_width), + _top = _coords.y - _height / 2; + if (_top + _height > (paper.view.size.height - _options.tooltip_margin)) { + _top = Math.max(paper.view.size.height - _options.tooltip_margin, _coords.y + _options.tooltip_arrow_width / 2) - _height; + } + if (_top < _options.tooltip_margin) { + _top = Math.min(_options.tooltip_margin, _coords.y - _options.tooltip_arrow_width / 2); + } + var _bottom = _top + _height; + /* jshint laxbreak:true */ + _path.segments[0].point = _path.segments[7].point = _coords.add([_isLeft * _xmargin, 0]); + _path.segments[1].point.x = _path.segments[2].point.x = _path.segments[5].point.x = _path.segments[6].point.x = _left; + _path.segments[3].point.x = _path.segments[4].point.x = _right; + _path.segments[2].point.y = _path.segments[3].point.y = _top; + _path.segments[4].point.y = _path.segments[5].point.y = _bottom; + _path.segments[1].point.y = _coords.y - _options.tooltip_arrow_width / 2; + _path.segments[6].point.y = _coords.y + _options.tooltip_arrow_width / 2; + _path.closed = true; + _path.fillColor = new paper.GradientColor(new paper.Gradient([_options.tooltip_top_color, _options.tooltip_bottom_color]), [0, _top], [0, _bottom]); + _selector.css({ + left: (_options.tooltip_padding + Math.min(_left, _right)), + top: (_options.tooltip_padding + _top) + }); + return _path; } - var _bottom = _top + _height; - /* jshint laxbreak:true */ - _path.segments[0].point - = _path.segments[7].point - = _coords.add([_isLeft * _xmargin, 0]); - _path.segments[1].point.x - = _path.segments[2].point.x - = _path.segments[5].point.x - = _path.segments[6].point.x - = _left; - _path.segments[3].point.x - = _path.segments[4].point.x - = _right; - _path.segments[2].point.y - = _path.segments[3].point.y - = _top; - _path.segments[4].point.y - = _path.segments[5].point.y - = _bottom; - _path.segments[1].point.y = _coords.y - _options.tooltip_arrow_width / 2; - _path.segments[6].point.y = _coords.y + _options.tooltip_arrow_width / 2; - _path.closed = true; - _path.fillColor = new paper.GradientColor(new paper.Gradient([_options.tooltip_top_color, _options.tooltip_bottom_color]), [0,_top], [0, _bottom]); - _selector.css({ - left: (_options.tooltip_padding + Math.min(_left, _right)), - top: (_options.tooltip_padding + _top) - }); - return _path; - } -}; + }; })(window); /* END main.js */