Add an Icon or Text next to hyperlinks similar to the globe icon on external hyperlinks
This How-to applies to:
Plone 2.0.x
This How-to is intended for:
Integrators, Customizers
By default, Plone has a very nice way of automatically adding icons next to documents and hyperlinks. It does this using a combination of CSS and JavaScript.
Sometimes we need to extend this feature to cover other document types. For e.g., I wanted to display an icon next to every PDF document to make the users aware that clicking on the link will actually download a PDF. Here's how I did it.
Assumptions:
A PDF file is recognized not by mime type or any other sophisticated method but by verifying that the last 4 characters in the file name are '.pdf'. If you use a different naming convention or use shortnames to refer to your files, you may have to tweak the logic.
- Note: While this how-to uses a PDF file as an example, it can be applied to any other extension as well.
So, say you want to display a small PDF icon next to your PDF files. Try this.
Step 1
The JavaScript file at /Plone/portal_skins/plone_ecmascript/plone_javascripts.js has the function defined to dynamically check every hyperlink in the content and apply the appropriate CSS classname to the hyperlink. The CSS property in turn uses the background image property to display the icon. You can check it in the plone.css file typically at /Plone/portal_skins/portal_styles/.
We want to customize the plone_javascripts.js. I copied the file to my custom skin folder and modified the scanforlinks() function as follows:
function scanforlinks() {
// securing against really old DOMs
if (! document.getElementsByTagName){return false};
if (! document.getElementById){return false};
// Quick utility function by Geir Bækholt
// Scan all links in the document and set classes on them dependant on
// whether they point to the current site or are external links
contentarea = getContentArea()
if (! contentarea){return false}
links = contentarea.getElementsByTagName('a');
for (i=0; i < links.length; i++) {
if ((links[i].getAttribute('href'))&&(links[i].className.indexOf('link-plain')==-1 )) {
var linkval = links[i].getAttribute('href')
// check if the link href is a relative link, or an absolute link to the current host.
if (linkval.toLowerCase().indexOf(window.location.protocol+'//'+window.location.host)==0) {
// we are here because the link is an absolute pointer internal to our host
// vps - show pdf icon if filename has .pdf in it
if (linkval.toLowerCase().substring((linkval.length-4), linkval.length).indexOf('.pdf') == 0) {
//pdf file, add the pdf class
wrapNode(links[i], 'span', 'link-pdf')
}
} else if (linkval.indexOf('http:') != 0) {
// not a http-link. Possibly an internal relative link, but also possibly a mailto ot other snacks
// add tests for all relevant protocols as you like.
protocols = ['mailto', 'ftp', 'news', 'irc', 'h323', 'sip', 'callto', 'https']
// h323, sip and callto are internet telephony VoIP protocols
for (p=0; p < protocols.length; p++) {
if (linkval.indexOf(protocols[p]+':') == 0) {
// this link matches the protocol . add a classname protocol+link
//links[i].className = 'link-'+protocols[p]
wrapNode(links[i], 'span', 'link-'+protocols[p])
break;
}
}
} else {
// we are in here if the link points to somewhere else than our site.
if ( links[i].getElementsByTagName('img').length == 0 ) {
// vps - in my case all my PDF files were internal to my site only.
// If you want to add an icon for external links also, add code similar to above here also
// we do not want to mess with those links that already have images in them
//links[i].className = 'link-external'
wrapNode(links[i], 'span', 'link-external')
//links[i].setAttribute('target','_blank')
}
}
}
}
}
Step 2
Now we need to add the CSS definition for 'link-pdf'. I added the following to the ploneCustom.css in my custom skin folder:
/* Display PDF icon next to links to PDF files (where href ends with .pdf) */
.link-pdf {
background: transparent url(/portal_skins/custom/pdf_icon) right no-repeat;
padding: 1px 17px 1px 0px;
}
- Note: You will have to modify your image url path according to your setup. Also, you will have to have uploaded an icon image to the path specified. In the above case, the icon has a shortname of pdf_icon.
That's it. You should now see the icon next to every internal hyperlink to PDF documents.
Add text instead of icon
Okay, sometimes you may not want to add an icon next to every PDF document hyperlink. Say you have a page full of PDF documents and you don't want a hundred icon images clutter your page and distract the user. All you want to do is add a piece of text, e.g., [PDF] next to every PDF file. Here's how to do it.
Customize the plone_javascripts.js file as follows:
function scanforlinks() {
// securing against really old DOMs
if (! document.getElementsByTagName){return false};
if (! document.getElementById){return false};
// Quick utility function by Geir Bækholt
// Scan all links in the document and set classes on them dependant on
// whether they point to the current site or are external links
contentarea = getContentArea()
if (! contentarea){return false}
links = contentarea.getElementsByTagName('a');
for (i=0; i < links.length; i++) {
if ((links[i].getAttribute('href'))&&(links[i].className.indexOf('link-plain')==-1 )) {
var linkval = links[i].getAttribute('href')
// check if the link href is a relative link, or an absolute link to the current host.
if (linkval.toLowerCase().indexOf(window.location.protocol+'//'+window.location.host)==0) {
// we are here because the link is an absolute pointer internal
// to our host do nothing
//vps - show pdf icon if filename has .pdf in it
if(linkval.toLowerCase().substring((linkval.length-4), linkval.length).indexOf('.pdf') == 0) {
//pdf file, add the pdf class
wrapPDFNode(links[i], 'span', '')
}
} else if (linkval.indexOf('http:') != 0) {
// not a http-link. Possibly an internal relative link, but also possibly a mailto ot other snacks
// add tests for all relevant protocols as you like.
protocols = ['mailto', 'ftp', 'news', 'irc', 'h323', 'sip', 'callto', 'https']
// h323, sip and callto are internet telephony VoIP protocols
for (p=0; p < protocols.length; p++) {
if (linkval.indexOf(protocols[p]+':') == 0) {
// this link matches the protocol . add a classname protocol+link
//links[i].className = 'link-'+protocols[p]
wrapNode(links[i], 'span', 'link-'+protocols[p])
break;
}
}
} else {
// we are in here if the link points to somewhere else than our site.
if ( links[i].getElementsByTagName('img').length == 0 ) {
// we do not want to mess with those links that already have images in them
//links[i].className = 'link-external'
wrapNode(links[i], 'span', 'link-external')
//links[i].setAttribute('target','_blank')
}
}
}
}
}
Also, add a new function wrapPDFNode() [modified form of wrapNode, which could also have been extended to add this functionality but I just chose to create a new function) as follows:
/* vps - Display text '[PDF]' next to a pdf document link. Alternative to using
PDF icon image (copyright issues with modifying size
*/
function wrapPDFNode(node, wrappertype, wrapperclass) {
// utility function to wrap a node "node" in an arbitrary element of type
// "wrappertype" , with a class of "wrapperclass"
wrapper = document.createElement(wrappertype)
wrapper.className = wrapperclass;
innerNode = node.parentNode.replaceChild(wrapper,node);
wrapper.appendChild(innerNode);
wrapper.innerHTML = wrapper.innerHTML + ' [PDF]';
}
That's it! That should display the text [PDF] next to every PDF hyperlink.
Found it in portal_skins/plone_ecmascript/mark_special_links.js
I found the same code in plone_ecmascript and the name is mark_special_links.js. I modified this file to remove the globe icon for the external link from my plone site
More generic version
(Let's see the spambots work though that!)
CSS
.link-external
{
background: #fff; /*Plain white background*/
padding-left: 0px; /*Get rid of the shift to the right*/
}
Plone/portal_skins/plone_ecmascript/plone_javascripts.js
What/where is this in 2.1.1? I cannot find this javascript function anywhere.