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

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...

Related

Reader view breaks Javascript protecting images from right-click

I know protecting images is far from foolproof. However, clients ask for it, so I have Javascript on a site which is designed to prevent right-click saving/downloading.
It appears that Reader View ignores both the Javascript and the site's CSS. I tried to add {display:none} based on a rule .moz-reader-content (Firefox). I've assumed this is the case in all browsers.
Searching hasn't turned up a means of detecting reader view either.
Does anyone have any suggestions or know of a solution for this problem?
As you know there are no full-proof solutions. No matter what you do, if it's visible it can be copied. (With a screenshot as a last resort).
With that being said, a simple and surprisingly effective solution is just to overlay each image a transparent .png file.
<div id="imagecontainer" style="position:relative;">
<img src="yourimage.png" style="position:absolute;top:0px;left:0px;">
<img src="transparent-overlay.png" style="position:absolute;top:0px;left:0px;">
</div>
Right-clicking on the image, would then click on the overlay and not the image itself. (Of course, you'll want to give the overlay a less obvious name).
Additionally, you should watermark the image itself.
For getting around Reader View issues (I'm not sure which Reader View you're talking about btw), you could try using javascript to actually fill the images themselves. (Assuming your reader view doesn't permit js).
eg:
var i = document.createElement('img');
var o = document.createElement('img');
i.src = 'yourimage.png';
o.src = 'transparent-overlay.png';
document.getElementById('imagecontainer').appendChild(i);
document.getElementById('imagecontainer').appendChild(o);
In the latter js example you'd also need to set your css styles to absolute position the two images within #imagecontainer.

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[*]

Stash : Conditional Content

First off, a caveat ... I am brand new to Stash. I've heard a lot about it but this is my first time actually playing with it. I get the concept, but am having a hard time figuring this one thing out.
I have a main "wrapper" file and everything within that wrapper stays the same. I would like the option however, to be able to toggle the sidebar on and off if I need to.
I wouldn't think I would need a totally separate layout wrapper would I?
Is there a way to use a boolean variable within stash? (e.g. 2col=TRUE) or am I thinking about it wrong?
Thanks in advance for your help!
Generally what I'd do here is setup multiple Stash gets within the wrapper. Then in your individual templates you can set both the sidebar and the main content area. For parts where you might be repeating content, like the opening and closing divs of a sidebar, you can always drop some snippets inside the stash.
You can also use exp:stash:not_empty [docs] to wrap around the div or container for your sidebar within the wrapper.
I usually use one wrapper for every template. It'll contain an {exp:stash:get name="content"} tag, like yours, which contains the only variable content within.
In my individual templates, I embed the wrapper at the beginning using a regular EE embed ie. {embed="includes/wrapper"}.
Then I stash the content to be inserted into the wrapper using the {exp:stash:set name="content"} tag.
This seems like what you're doing anyway.
If I want to conditionally show a sidebar, I might just pass a variable into the embed.
eg. {embed="includes/wrapper" show_sidebar="yes"}
In my wrapper I would do this:
{if embed:show_sidebar}
Sidebar stuff.
{/if}

How to #set a variable to make it available in an included velocity template

I'm creating a custom theme for Liferay, I wish to include the footer within each page layout individually. Unfortunately, I don't appear to have access to the $full_templates_path variable within the page layout files. I have had no luck manually storing the value with #set and then accessing that value within the included template.
In a vanilla theme, processing of files is something like this:
portal_normal.vm:
1) some init, doctype, etc.
2) #parse("$full_templates_path/header.vm")
3) $theme.include($content_include)
a) custom_layout_1.tpl
b) chat portlet
4) #parse("$full_templates_path/footer.vm")
For layout purposes, I need to deviate from this pattern, like so:
portal_normal.vm
1) some init, doctype, etc.
2) #parse("$full_templates_path/header.vm")
3) $theme.include($content_include)
a) custom_layout_1.tpl
i) #parse("$full_templates_path/footer.vm")
b) chat portlet
When I try this, tomcat errors out because $full_templates_path is not defined within custom_layout_1.tpl. I tried to fix this problem by doing the following within portal_normal.vm
#set($full_footer_path = "$full_templates_path/footer.vm")
$theme.include($content_include)
And then, within custom_layout_1.tpl, I do this where I'd like the footer markup emitted:
#parse("$full_footer_path")
However, tomcat still errors out, saying that $full_footer_path is not defined.
When I hard-code the value of $full_templates_path into #parse statement in custom_layout_1.tpl, everything works fine, but that seems like a hack to me.
Ideally, this should do the right thing for the right reasons, not just because I used a lot of duct tape.
Any suggestions for ways to implement the inclusion of a template file from within a custom page layout?
The issue could be due to your velocity configuration.
The following property should be false velocimacro.permissions.allow.inline.local.scope if you want to access variables set in one template to be accessible in another
You may have miss-typed your question but shouldn't #set($full_footer_path = "$full_templates_path/footer.vm" have a close bracket at the end...
#set( $full_footer_path = "$full_templates_path/footer.vm" )
It might also help to wrap $full_templates_path in curly braces to distinguish it from the rest of the text i.e ${full_templates_path}

Create a map with clickable provinces/states using SVG, HTML/CSS, ImageMap

I am trying to create an interactive map where users can click on different provinces in the map to get info specific to that province.
Example:
archived: http://www.todospelaeducacao.org.br/
archived: http://code.google.com/p/svg2imap/
So far I've only found solutions that have limited functionality. I've only really searched for this using an SVG file, but I would be open to other file types if it is possible.
If anyone knows of a fully functioning way to do this (jQuery plug-in, PHP script, vector images) or a tutorial on how to do it manually please do share.
jQuery plugin for decorating image maps (highlights, select areas, tooltips):
http://www.outsharked.com/imagemapster/
Disclosure: I wrote it.
Sounds like you want a simple imagemap, I'd recommend to not make it more complex than it needs to be. Here's an article on how to improve imagemaps with svg. It's very easy to do clickable regions in svg itself, just add some <a> elements around the shapes you want to have clickable.
A couple of options if you need something more advanced:
http://jqvmap.com/
http://jvectormap.com/
http://polymaps.org/
I think it's better to divide my answer to 2 parts:
A-Create everything from scratch (using SVG, JavaScript, and HTML5):
Create a new HTML5 page
Create a new SVG file, each clickable area (province) should be a separate SVG Polygon in your SVG file,
(I'm using Adobe Illustrator for creating SVG files but you can find many alternative software products too, for example Inkscape)
Add mouseover and click events to your polygons one by one
<polygon points="200,10 250,190 160,210" style="fill:lime;stroke:purple;stroke-width:1"
onmouseover="mouseOverHandler(evt)"
onclick="clickHandler(evt)" />
Add a handler for each event in your JavaScript code and add your desired code to the handler
function mouseOverHandler(evt) {};
function clickHandler(evt) {};
Add the SVG file to your HTML page (I prefer inline SVG but you can use linked SVG file too)
Upload the files to your server
B-Use a software like FLDraw Interactive Image Creator (only if you have a map image and want to make it interactive):
Create an empty project and choose your map image as your base image when creating the new project
Add a Polygon element (from the Shape menu) for each province
For each polygon double click it to open the Properties window where you can choose an event type for mouse-over and click,
also change the shape opacity to 0 to make it invisible
Save your project and Publish it to HTML5, FLDraw will create a new folder that contains all of the required files for your project that you can upload to your server.
Option (A) is very good if you are programmer or you have someone to create the required code and SVG file for you,
Option (B) is good if you don't want to hire someone or spend your own time for creating everything from scratch
You have some other options too, for example using HTML5 Canvas instead of SVG, but it's not very easy to create a Zoomable map using HTML5 Canvas,
maybe there are some other ways too that I'm not aware of.
Just in case anyone will search for it - I used it on several sites, always the customization and RD possibilities were a perfect fit for what I needed. Simple and it is free to use:
Clickable CSS Maps
One note for more scripts on a site: I had some annoying problems with getting to work a map (that worked as a graphic menu) in Drupal 7. There where many other script used, and after handling them, I got stuck with the map - it still didn't work, although the jquery.cssmap.js, CSS (both local) and the script in the where in the right place. Firebug showed me an error and I suddenly eureka - a simple oversight, I left the script code as it was in the example and there was a conflict. Just change the front function "$" to "jQuery" (or other handler) and it works perfect. :]
Here's what I ment (of course you can put it before instead of the ):
<script type="text/javascript">
jQuery(function($){
$('#map-country').cssMap({'size' : 810});
});
</script>
Go to SVG to Script
with your SVG the default output is the map in SVG
Code which adds events is also added but is easily identified and can be altered as required.
I have been using makeaclickablemap for my province maps for some time now and it turned out to be a really good fit.
I had the same requirements and finally this Map converter worked for me. It is the best plugin for any map generation.
Here is another image map plugin I wrote to enhance image maps: https://github.com/gestixi/pictarea
It makes it easy to highlight all the area and let you specify different styles depending on the state of the zone: normal, hover, active, disable.
You can also specify how many zones can be selected at the same time.
The following code may help you:
$("#svgEuropa [id='stallwanger.it.dev_shape_DEU']").on("click",function(){
alert($(this).attr("id"));
});
Source
You have quite a few options for this:
1 - If you can find an SVG file for the map you want, you can use something like RaphaelJS or SnapSVG to add click listeners for your states/regions, this solution is the most customizable...
2 - You can use dedicated tools such as clickablemapbuilder (free) or makeaclickablemap (i think free also).
[disclaimer] Im the author of clickablemapbuilder.com :)
<script type="text/javascript">
jQuery(function($){
$('#map-country').cssMap({'size' : 810});
});
</script>
strong text

Resources