/** * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ RED.palette = (function() { var exclusion = ['config','unknown','deprecated']; var coreCategories = ['subflows', 'input', 'output', 'function', 'social', 'mobile', 'storage', 'analysis', 'advanced']; var categoryContainers = {}; function createCategory(originalCategory,rootCategory,category,ns) { if ($("#palette-base-category-"+rootCategory).length === 0) { createCategoryContainer(originalCategory,rootCategory, ns+":palette.label."+rootCategory); } $("#palette-container-"+rootCategory).show(); if ($("#palette-"+category).length === 0) { $("#palette-base-category-"+rootCategory).append('
'); } } function createCategoryContainer(originalCategory,category, labelId) { var label = RED._(labelId, {defaultValue:category}); label = (label || category).replace(/_/g, " "); var catDiv = $('
'+ '
'+label+'
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
').appendTo("#palette-container"); catDiv.data('category',originalCategory); catDiv.data('label',label); categoryContainers[category] = { container: catDiv, close: function() { catDiv.removeClass("palette-open"); catDiv.addClass("palette-closed"); $("#palette-base-category-"+category).slideUp(); $("#palette-header-"+category+" i").removeClass("expanded"); }, open: function() { catDiv.addClass("palette-open"); catDiv.removeClass("palette-closed"); $("#palette-base-category-"+category).slideDown(); $("#palette-header-"+category+" i").addClass("expanded"); }, toggle: function() { if (catDiv.hasClass("palette-open")) { categoryContainers[category].close(); } else { categoryContainers[category].open(); } } }; $("#palette-header-"+category).on('click', function(e) { categoryContainers[category].toggle(); }); } function setLabel(type, el,label, info) { var nodeWidth = 82; var nodeHeight = 25; var lineHeight = 20; var portHeight = 10; var words = label.split(/[ -]/); var displayLines = []; var currentLine = words[0]; var currentLineWidth = RED.view.calculateTextWidth(currentLine, "palette_label", 0); for (var i=1;i"); var multiLineNodeHeight = 8+(lineHeight*displayLines.length); el.css({height:multiLineNodeHeight+"px"}); var labelElement = el.find(".palette_label"); labelElement.html(lines).attr('dir', RED.text.bidi.resolveBaseTextDir(lines)); el.find(".palette_port_output").css({top:(multiLineNodeHeight-5)+"px"}); el.find(".palette_port_input").css({top: "-5px"}); var popOverContent; try { var l = "

"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"

"; if (label != type) { l = "

"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"
"+type+"

"; } popOverContent = $(l+(info?info:$("script[data-help-name='"+type+"']").html()||"

"+RED._("palette.noInfo")+"

").trim()) .filter(function(n) { return (this.nodeType == 1 && this.nodeName == "P") || (this.nodeType == 3 && this.textContent.trim().length > 0) }).slice(0,2); } catch(err) { // Malformed HTML may cause errors. TODO: need to understand what can break // NON-NLS: internal debug console.log("Error generating pop-over label for ",type); console.log(err.toString()); popOverContent = "

"+label+"

"+RED._("palette.noInfo")+"

"; } el.data('popover').setContent(popOverContent); } function setIcon(element,sf) { var iconElement = element.find(".palette_icon"); var icon_url = RED.utils.getNodeIcon(sf._def,sf); iconElement.attr("style", "background-image: url("+icon_url+")"); } function escapeNodeType(nt) { return nt.replace(" ","_").replace(".","_").replace(":","_"); } function addNodeType(nt,def) { var nodeTypeId = escapeNodeType(nt); if ($("#palette_node_"+nodeTypeId).length) { return; } if (exclusion.indexOf(def.category)===-1) { var originalCategory = def.category; var category = def.category.replace(/ /g,"_"); var rootCategory = category.split("-")[0]; var d = document.createElement("div"); d.id = "palette_node_"+nodeTypeId; d.type = nt; var label = /^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1]; if (typeof def.paletteLabel !== "undefined") { try { label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||""; } catch(err) { console.log("Definition error: "+nt+".paletteLabel",err); } } $('
',{class:"palette_label"+(def.align=="right"?" palette_label_right":"")}).appendTo(d); d.className="palette_node"; if (def.icon) { var icon_url = RED.utils.getNodeIcon(def); var iconContainer = $('
',{class:"palette_icon_container"+(def.align=="right"?" palette_icon_container_right":"")}).appendTo(d); $('
',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer); } d.style.backgroundColor = RED.utils.getNodeColor(nt,def); if (def.outputs > 0) { var portOut = document.createElement("div"); portOut.className = "palette_port palette_port_output"; d.appendChild(portOut); } if (def.inputs > 0) { var portIn = document.createElement("div"); portIn.className = "palette_port palette_port_input"; d.appendChild(portIn); } createCategory(def.category,rootCategory,category,(coreCategories.indexOf(rootCategory) !== -1)?"node-red":def.set.id); $("#palette-"+category).append(d); $(d).data('category',rootCategory); d.onmousedown = function(e) { e.preventDefault(); }; var popover = RED.popover.create({ target:$(d), trigger: "hover", width: "300px", content: "hi", delay: { show: 750, hide: 50 } }); $(d).data('popover',popover); // $(d).popover({ // title:d.type, // placement:"right", // trigger: "hover", // delay: { show: 750, hide: 50 }, // html: true, // container:'body' // }); $(d).click(function() { RED.view.focus(); var helpText; if (nt.indexOf("subflow:") === 0) { helpText = marked(RED.nodes.subflow(nt.substring(8)).info||"")||(''+RED._("sidebar.info.none")+''); } else { helpText = $("script[data-help-name='"+d.type+"']").html()||(''+RED._("sidebar.info.none")+''); } RED.sidebar.info.set(helpText,RED._("sidebar.info.nodeHelp")); }); var chart = $("#chart"); var chartOffset = chart.offset(); var chartSVG = $("#chart>svg").get(0); var activeSpliceLink; var mouseX; var mouseY; var spliceTimer; var paletteWidth; var paletteTop; $(d).draggable({ helper: 'clone', appendTo: 'body', revert: true, revertDuration: 50, containment:'#main-container', start: function() { paletteWidth = $("#palette").width(); paletteTop = $("#palette").parent().position().top + $("#palette-container").position().top; RED.view.focus(); }, stop: function() { d3.select('.link_splice').classed('link_splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}}, drag: function(e,ui) { // TODO: this is the margin-left of palette node. Hard coding // it here makes me sad //console.log(ui.helper.position()); ui.position.left += 17.5; if (def.inputs > 0 && def.outputs > 0) { mouseX = ui.position.left-paletteWidth+(ui.helper.width()/2) - chartOffset.left + chart.scrollLeft(); mouseY = ui.position.top-paletteTop+(ui.helper.height()/2) - chartOffset.top + chart.scrollTop(); if (!spliceTimer) { spliceTimer = setTimeout(function() { var nodes = []; var bestDistance = Infinity; var bestLink = null; if (chartSVG.getIntersectionList) { var svgRect = chartSVG.createSVGRect(); svgRect.x = mouseX; svgRect.y = mouseY; svgRect.width = 1; svgRect.height = 1; nodes = chartSVG.getIntersectionList(svgRect,chartSVG); mouseX /= RED.view.scale(); mouseY /= RED.view.scale(); } else { // Firefox doesn't do getIntersectionList and that // makes us sad mouseX /= RED.view.scale(); mouseY /= RED.view.scale(); nodes = RED.view.getLinksAtPoint(mouseX,mouseY); } for (var i=0;i 0) { var portIn = document.createElement("div"); portIn.className = "palette_port palette_port_input"; paletteNode.append(portIn); } else if (portInput.length !== 0 && sf.in.length === 0) { portInput.remove(); } if (portOutput.length === 0 && sf.out.length > 0) { var portOut = document.createElement("div"); portOut.className = "palette_port palette_port_output"; paletteNode.append(portOut); } else if (portOutput.length !== 0 && sf.out.length === 0) { portOutput.remove(); } setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||"")); setIcon(paletteNode,sf); var currentCategory = paletteNode.data('category'); var newCategory = (sf.category||"subflows"); if (currentCategory !== newCategory) { var category = newCategory.replace(/ /g,"_"); createCategory(newCategory,category,category,"node-red"); var currentCategoryNode = paletteNode.closest(".palette-category"); var newCategoryNode = $("#palette-"+category); newCategoryNode.append(paletteNode); if (newCategoryNode.find(".palette_node").length === 1) { categoryContainers[category].open(); } paletteNode.data('category',newCategory); if (currentCategoryNode.find(".palette_node").length === 0) { if (currentCategoryNode.find("i").hasClass("expanded")) { currentCategoryNode.find(".palette-content").slideToggle(); currentCategoryNode.find("i").toggleClass("expanded"); } } } }); } function filterChange(val) { var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i'); $("#palette-container .palette_node").each(function(i,el) { var currentLabel = $(el).find(".palette_label").text(); if (val === "" || re.test(el.id) || re.test(currentLabel)) { $(this).show(); } else { $(this).hide(); } }); for (var category in categoryContainers) { if (categoryContainers.hasOwnProperty(category)) { if (categoryContainers[category].container .find(".palette_node") .filter(function() { return $(this).css('display') !== 'none'}).length === 0) { categoryContainers[category].close(); } else { categoryContainers[category].open(); } } } } function init() { RED.events.on('registry:node-type-added', function(nodeType) { var def = RED.nodes.getType(nodeType); addNodeType(nodeType,def); if (def.onpaletteadd && typeof def.onpaletteadd === "function") { def.onpaletteadd.call(def); } }); RED.events.on('registry:node-type-removed', function(nodeType) { removeNodeType(nodeType); }); RED.events.on('registry:node-set-enabled', function(nodeSet) { for (var j=0;j .palette-spinner").show(); $("#palette-search input").searchBox({ delay: 100, change: function() { filterChange($(this).val()); } }) var categoryList = coreCategories; if (RED.settings.paletteCategories) { categoryList = RED.settings.paletteCategories; } else if (RED.settings.theme('palette.categories')) { categoryList = RED.settings.theme('palette.categories'); } if (!Array.isArray(categoryList)) { categoryList = coreCategories } categoryList.forEach(function(category){ createCategoryContainer(category, category, "palette.label."+category); }); $("#palette-collapse-all").on("click", function(e) { e.preventDefault(); for (var cat in categoryContainers) { if (categoryContainers.hasOwnProperty(cat)) { categoryContainers[cat].close(); } } }); $("#palette-expand-all").on("click", function(e) { e.preventDefault(); for (var cat in categoryContainers) { if (categoryContainers.hasOwnProperty(cat)) { categoryContainers[cat].open(); } } }); } function getCategories() { var categories = []; $("#palette-container .palette-category").each(function(i,d) { categories.push({id:$(d).data('category'),label:$(d).data('label')}); }) return categories; } return { init: init, add:addNodeType, remove:removeNodeType, hide:hideNodeType, show:showNodeType, refresh:refreshNodeTypes, getCategories: getCategories }; })();