Get RaphaelJS parent from node - svg

Is it possible to get the parent of the RaphaelJS generated code? I use a converter to convert my SVG to Raphael code, which I don't want to change, as I would have to do that for every iteration of my SVG file. Inside Illustrator, I have a structure like this:
GroupName
<Path>
<Path>
<Path>
The group has a name, which gets set like this:
var GroupName = rsr.set();
var path_a = rsr.path("......").attr({parent: "GroupName"});
var path_b = rsr.path("......").attr({parent: "GroupName"});
So they're not nested in the code or on the object, but the path actually has an attribute called "parent". How do I access that variable? I have tried multiple things, such as element.node.data("parent"), element.getAttribute("parent"), element.node.getAttribute("parent"), and so on.
I want to be able to mouseover on multiple paths, which has the same parent, and then run some code.

Workaround hack here:
It's trying to add the parent attribute on the element, but it's not allowed by Raphael. Inside the Raphael source code, there's an availableAttrs property. By adding parent: "" to it, I could actually add the HTML property on the element, then simply grab it with getAttribute on my node.
Neat little workaround which I only have to apply everytime Raphael comes out with an update (which is never).

Related

Linking into SVG content: Is it possible to specify an id AND a viewBox in a single URL fragment?

I want to confirm my interpretation of the SVG spec:
You can refer to an ID of an SVG. e.g., MyDrawing.svg#MyView
You can refer to an SVG viewBox. e.g., MyDrawing.svg#svgView(viewBox(0,200,1000,1000))
(This is what I want to confirm) But you can't do both in the same url. These options are mutually exclusive.
Context: I have a desire to link to an id attribute nested inside an svg but I also want to dynamically specify the view box. Ideally, I wouldn't have to modify the SVG to do this, because I have to do it for a lot of files; when/if my designer makes a modification, I don't want to have to do all that work over again.

Workaround for url(#fragment) shadowTree bug in Safari?

In an SVG, url(#fragment) fails in Safari under some conditions when the ancestor SVG is in a shadowTree. This means filters and patterns in a custom element can just stop working sometimes.
Basically, when there are two instances of the SVG created from a template, and one instance is hidden, fragment references in the other instance stop working, e.g.
<template>
<svg>
...
<filter id="blur">
...
</>
...
(attach cloned template to new shadows etc... )
...
templateUsingInstance1.style.display = "none"
// And then the following doesn't work.
templateUsingInstance2.shadowRoot.querySelector("g").style.filter = "url(#blur)"
Full Example: https://jsfiddle.net/InBllm/dw4vhax0/2/
The bug has already been reported but I'm curious if anyone else has run into this and knows a work-around.
I've tried
Inlining an SVG with relevant patterns/filters in the main doc and referring to that.
Inlining another SVG in the shadow tree with relevant patterns/filters and referring to that.
Referring to filters/patterns in an external SVG with relative and absolute paths. (Looks like this is a separate bug itself.)
Changing the style attribute directly (opposed to in defs>style).
Adding a base tag in the root HTML document.
Create an extra instance from the template, hide it (without using display:none), keep it around forever. (If other instances are created and destroyed the problem comes back.)
Abandoning shadowDom avoids the issue but that is not an option.
Best I got is this hack:
Create an extra instance from the template, hide it (without using display:none), keep it around forever.
Whenever an instance built from the offending template is removed, flash the stick-around instance. el.style.display = "none"; setTimeout(()=>{ele.style.display = "initial"},0)
This prevents breaking fragment references from getting stuck, but it can result in a one frame flash of missing filters/patterns...

fabricJS - SVG parameters with toSVG

According to this link, it is possible to modify a SVG, depending on the parameters included in the URL used to access this SVG.
Is it possible to do so using the toSVG() method ?
Let's say I create a basic canvas with a few elements. Once I'm done, I export and save the result of my canvas.toSVG() on AWS.
I get this image
Is it possible to modify the way toSVG() behaves, so that adding ?color=red at the end of the URL would make my tshirt red ?
I tried using the example from the documentation, using replace() on my canvas objects, but this generates empty SVGs.

TinyMCE and SVG

I'm using the latest/current TinyMCE editor (<script type="text/javascript" src='https://cdn.tinymce.com/4/tinymce.min.js'></script>) and it doesn't seem capable of displaying <svg>. I have some HTML saved in a database which contains some <svg>. When loaded in TinyMCE, it doesn't display.
Is this a known issue (I've searched and haven't found much)? Any workarounds?
TinyMCE strips empty and invalid tags. You can solve it by
Adding '&nbsp' to each empty element:
svg.find('*').each(function() {
if (!$(this).html()) {
$(this).text(' ');
}
});
here svg is your jQuery wrapped svg element.
Extending the valid elements according to the svg element reference*
extended_valid_elements: "svg[*],defs[*],pattern[*],desc[*],metadata[*],g[*],mask[*],path[*],line[*],marker[*],rect[*],circle[*],ellipse[*],polygon[*],polyline[*],linearGradient[*],radialGradient[*],stop[*],image[*],view[*],text[*],textPath[*],title[*],tspan[*],glyph[*],symbol[*],switch[*],use[*]"
*Note I added only the elements relevant for my case.
I tried Koen's first suggestion and it worked for existing SVG content (I added this in the setup callback). However it still filtered the SVG tags out when pasting HTML into the source code editor and then confirming the dialog.
After digging a bit into TinyMCE's source code to see where those elements are actually removed (it's in the DomParser class) I found an undocumented editor setting for the Schema class that specifies tags that are allowed to be empty without being removed. The only annoying thing is that you can't use it to add to the existing list, you can only override it. So when setting it you have to list the tags it has in there by default as well. Use this in the settings that you provide to TinyMCE when initialising it:
// First the list of tags that it normally knows about by default:
non_empty_elements: "td,th,iframe,video,audio,object,script,pre,code,area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,source,wbr,track"
// Now we add tags related to SVGs that it doesn't normally know about:
+ "svg,defs,pattern,desc,metadata,g,mask,path,line,marker,rect,circle,ellipse,polygon,polyline,linearGradient,radialGradient,stop,image,view,text,textPath,title,tspan,glyph,symbol,switch,use",
This way these SVG tags should never be filtered out because they are empty - as long as they are also valid in general, e.g. by setting the extended_valid_elements as Koen suggested above or by allowing all elements (not recommended as it leaves you vulnerable to XSS attacks):
extended_valid_elements: "*[*]"
Please note that this worked for my version 4.5.8 of TinyMCE. Since this setting is undocumented it might not work anymore in current or future versions. Also they might've adjusted the default list that I'm overriding here in later versions. Find nonEmptyElementsMap and shortEndedElementsMap in Schema.js in their source code to find the default list in your version (the two lists get combined) and note that in there the tags are separated by spaces but when you supply a list yourself the list is separated by commas (for whatever reason).
Seams to be TinyMCE that removes it because it is an empty tag: http://world.episerver.com/forum/developer-forum/-EPiServer-75-CMS/Thread-Container/2015/1/tinymce-and-svgs/
You might be able to use this inside the init:
extended_valid_elements : "svg[*]",
It works with other empty tags etc, but have never tried with SVG.
From the forum post I linked to:
ok,I did some debugging into TinyMCE and the problem seems to be that
the svg element is detected as being empty and therefor removed.
Unfortunatley there is no config way to change this behavior but there
are some workarounds.
Always have a name attibute for the svg element: <svg name="something"
Always have a data-mce attribute for the svg element: <svg data-mce-something="something"
Include some text content within the svg element: <svg> </svg> Using these techniques i could succesfully store
inline svg in an xhtml property
I made it work by adding all valid SVG elements to the extended_valid_elements property of the settings object while initializing TinyMCE, no other action was needed
For your convenience here's the full list of SVG elements I used
a[*],altGlyph[*],altGlyphDef[*],altGlyphItem[*],animate[*],animateMotion[*],animateTransform[*],circle[*],clipPath[*],color-profile[*],cursor[*],defs[*],desc[*],ellipse[*],feBlend[*],feColorMatrix[*],feComponentTransfer[*],feComposite[*],feConvolveMatrix[*],feDiffuseLighting[*],feDisplacementMap[*],feDistantLight[*],feFlood[*],feFuncA[*],feFuncB[*],feFuncG[*],feFuncR[*],feGaussianBlur[*],feImage[*],feMerge[*],feMergeNode[*],feMorphology[*],feOffset[*],fePointLight[*],feSpecularLighting[*],feSpotLight[*],feTile[*],feTurbulence[*],filter[*],font[*],font-face[*],font-face-format[*],font-face-name[*],font-face-src[*],font-face-uri[*],foreignObject[*],g[*],glyph[*],glyphRef[*],hkern[*],image[*],line[*],linearGradient[*],marker[*],mask[*],metadata[*],missing-glyph[*],mpath[*],path[*],pattern[*],polygon[*],polyline[*],radialGradient[*],rect[*],script[*],set[*],stop[*],style[*],svg[*],switch[*],symbol[*],text[*],textPath[*],title[*],tref[*],tspan[*],use[*],view[*],vkern[*],a[*],animate[*],animateMotion[*],animateTransform[*],circle[*],clipPath[*],defs[*],desc[*],discard[*],ellipse[*],feBlend[*],feColorMatrix[*],feComponentTransfer[*],feComposite[*],feConvolveMatrix[*],feDiffuseLighting[*],feDisplacementMap[*],feDistantLight[*],feDropShadow[*],feFlood[*],feFuncA[*],feFuncB[*],feFuncG[*],feFuncR[*],feGaussianBlur[*],feImage[*],feMerge[*],feMergeNode[*],feMorphology[*],feOffset[*],fePointLight[*],feSpecularLighting[*],feSpotLight[*],feTile[*],feTurbulence[*],filter[*],foreignObject[*],g[*],hatch[*],hatchpath[*],image[*],line[*],linearGradient[*],marker[*],mask[*],metadata[*],mpath[*],path[*],pattern[*],polygon[*],polyline[*],radialGradient[*],rect[*],script[*],set[*],stop[*],style[*],svg[*],switch[*],symbol[*],text[*],textPath[*],title[*],tspan[*],use[*],view[*],g[*],animate[*],animateColor[*],animateMotion[*],animateTransform[*],discard[*],mpath[*],set[*],circle[*],ellipse[*],line[*],polygon[*],polyline[*],rect[*],a[*],defs[*],g[*],marker[*],mask[*],missing-glyph[*],pattern[*],svg[*],switch[*],symbol[*],desc[*],metadata[*],title[*],feBlend[*],feColorMatrix[*],feComponentTransfer[*],feComposite[*],feConvolveMatrix[*],feDiffuseLighting[*],feDisplacementMap[*],feDropShadow[*],feFlood[*],feFuncA[*],feFuncB[*],feFuncG[*],feFuncR[*],feGaussianBlur[*],feImage[*],feMerge[*],feMergeNode[*],feMorphology[*],feOffset[*],feSpecularLighting[*],feTile[*],feTurbulence[*],font[*],font-face[*],font-face-format[*],font-face-name[*],font-face-src[*],font-face-uri[*],hkern[*],vkern[*],linearGradient[*],radialGradient[*],stop[*],circle[*],ellipse[*],image[*],line[*],path[*],polygon[*],polyline[*],rect[*],text[*],use[*],use[*],feDistantLight[*],fePointLight[*],feSpotLight[*],clipPath[*],defs[*],hatch[*],linearGradient[*],marker[*],mask[*],metadata[*],pattern[*],radialGradient[*],script[*],style[*],symbol[*],title[*],hatch[*],linearGradient[*],pattern[*],radialGradient[*],solidcolor[*],a[*],circle[*],ellipse[*],foreignObject[*],g[*],image[*],line[*],path[*],polygon[*],polyline[*],rect[*],svg[*],switch[*],symbol[*],text[*],textPath[*],tspan[*],use[*],g[*],circle[*],ellipse[*],line[*],path[*],polygon[*],polyline[*],rect[*],defs[*],g[*],svg[*],symbol[*],use[*],altGlyph[*],altGlyphDef[*],altGlyphItem[*],glyph[*],glyphRef[*],textPath[*],text[*],tref[*],tspan[*],altGlyph[*],textPath[*],tref[*],tspan[*],clipPath[*],cursor[*],filter[*],foreignObject[*],hatchpath[*],script[*],style[*],view[*],altGlyph[*],altGlyphDef[*],altGlyphItem[*],animateColor[*],cursor[*],font[*],font-face[*],font-face-format[*],font-face-name[*],font-face-src[*],font-face-uri[*],glyph[*],glyphRef[*],hkern[*],missing-glyph[*],tref[*],vkern[*]

Add target property for dropdownnode in Widget Container

I would like to add a target (e.g. _blank) property for a basicLeafNode on the Widget Container from the extension library.
I do not see the property for this.
Instead I could use the onClick property and return an URL. But then I still would have no target defined.
I could add a postScript method
var target = url;
view.postScript("window.open('"+target+"','_blank')")
but this fires when the container is loaded.
Can I add a target property without using the onClick Property?
In case I use the onClick property what method should I use or how I prevent the postscript is executed when the container is loaded?
The basicLeafNode doesn't currently provide a target property. You have 2 courses of action:
implement your own custom node as Michael suggested (hard)
use a class on the link e.g. "newpageopen" and add an onPageReady script that selects all a elements with the calss newpageopen and add the target property to the resulted HTML.
Something like this:
require(["dojo/ready","dojo/query"], function(ready){
ready(function(){
dojo.query("a.newpageopen").attr("target", "_blank");
});
});
Hope that helps;
To make this list of solutions a bit longer here another on wich does not require dojo or jquery:
Instead of using your code as SSJS like:
var target = url;
view.postScript("window.open('"+target+"','_blank')")
You can use the Client Side Code and add SSJS code in #{javascript:}' wich i think is the shortest solution on this Problem. Here a hardcoded example:
<xe:basicLeafNode>
<xe:this.onClick><![CDATA[window.open('#{javascript: return "http://www.google.com";}','_blank');]]></xe:this.onClick>
</xe:basicLeafNode>
the above example will also work with viewScope variables or SSJS funktions:
<xe:basicLeafNode>
<xe:this.onClick><![CDATA[window.open('#{javascript: return viewScope.url;}','_blank');]]></xe:this.onClick>
</xe:basicLeafNode>
You can add the target attribute using JavaScript. It's kind of inconvenient way but would work.
You can use dojo.query to query the HTML output generated by basicLeafNode on the Widget Container. Once you get the node of <a> then you can add attribute using dojo.attr.
One problem you might face is that the ID generated by XPages contains the character :, which will not work so you would have to escape it.
function escapeColon(controlID) {
return controlID.replace(/:/g, "\\3A");
}
So your code would be something like:
dojo.addOnLoad(function() {
dojo.attr(dojo.query(escapeColon("#{id:ID_of_basicLeafNode}") + " > a")[0], "target", "_blank");
});
The code escapeColon("#{id:ID_of_basicLeafNode}") + " > a" would generate a CSS selector. Here I am assuming that basicLeafNode on the Widget Container would generate something like this <div id="_id1:basicLeafNode"><a href=".... So the CSS selector would search for a tag with that ID and inside it the <a> tag. You would have to modify this based on the output that is generated.
As I said its a bit inconvenient. Also I haven't tested this code.

Resources