Package: zest.emailhider
Zest emailhiderThis document describes the zest.emailhider package.DependenciesThis package depends on jquery.pyproxy to integrate python code with
jquery code.OverviewThis package provides a mechanism to hide email addresses with
JavaScript.  Or actually: with this package you can hide your email
addresses by default so they are never in the html; with javascript
the addresses are then fetched and displayed.For every content item in your site you can have exactly one email
address, as we look up the email address for an object by its UID.
For objects for which you want this you should register a simple
adapter to the IMailable interface, so we can ask this adapter for anemailattribute and aUIDmethod.   The ‘emailhider’ view is
provided to generate the placeholder link.Objects display a placeholder link with ahidden-emailclass, auidrel attribute and aemail-uid-<someuid>class set to the
UID of an object; when the page is loaded some jQuery is run to make a
request for all those links to replace them with a ‘mailto’ link for
that object.  Using this mechanism the email address isn’t visible in
the initial page load, and it requires JavaScript to be seen - so it
is much harder for spammers to harvest.Special case: when the uid contains ‘email’ or ‘address’ it is clearly
no real uid.  In that case we do nothing with the IMailable interface
but we try to get a property with this ‘uid’ from the property sheet
of the portal.  Main use case is of course the ‘email_from_address’,
but you can add other addresses as well, like ‘info_email’.  If you
want to display the email_from address in for example a static portlet
on any page in the site, use this html code:<a class="hidden-email email-uid-email_from_address"
   rel="email_from_address">
   Activate JavaScript to see this address.</a>You can load thetest_emailhiderpage to see if this works.Instructions for your own packageWhat do you need to do if you want to use this in your own package,
for your own content type?First you need to make your content type adaptable to the IMailable
interface, either directly or via an adapter.If your content type already has aUIDmethod (like all Archetypes
content types) and anemailattribute, you can use some zcml like
this:<class class=".content.MyContentType">
  <implements interface="zest.emailhider.interfaces.IMailable" />
</class>If not, then you need to register an adapter for your content type
that has this method and attribute.  For example something like this:from zope.component import adapts
from zope.interface import implements
from zest.emailhider.interfaces import IMailable
from your.package.interfaces import IMyContentType

class MailableAdapter(object):
    adapts(IMyContentType)
    implements(IMailable)

    def __init__(self, context):
        self.context = context

    def UID(self):
        return self.context.my_special_uid_attribute

    @property
    def email(self):
        return self.context.getSomeContactAddress()Second, in the page template of your content type you need to add code
to show the placeholder text instead of the real email address:<span>For more information contact us via email:</span>
<span tal:replace="structure context/@@emailhider" />Note that if you want this to still work when zest.emailhider is not
installed, you can use this code instead:<span tal:replace="structure context/@@emailhider|context/email" />This shows the unprotected plain text email when zest.emailhider is is
not available.  When you are using zest.emailhider 2.6 or higher this
works a bit better, as we have introduced an own browser layer: the
@@emailhider page is only available when zest.emailhider is actually
installed in the Plone Site.  This also makes it safe to use
zest.emailhider when you have more than one Plone Site in a single
Zope instance and want emailhider to only be used in one them.Note that the generated code in the template is very small, so you
can also look at the page template in zest.emailhider and copy some
code from there and change it to your own needs.  As long as your
objects can be found by UID in the uid_catalog and your content type
can be adapted to IMailable to get the email attribute, it should all
work fine.Note on KSS usage in older releasesOlder releases (until and including 1.3) used KSS instead of jQuery.
As our functionality should of course also work for anonymous users,
we had to make KSS publicly accessible.  So all javascript that was
needed for KSS was loaded for anonymous users as well.We cannot undo that automatically, as the package has no way of
knowing if the same change was needed by some other package or was
done for other valid reasons by a Manager.  So you should check the
javascript registry in the ZMI and see if this needs to be undone so
anonymous users no longer get the kss javascripts as they no longer
need that.For reference, this is the normal line in the Condition field of++resource++kukit.js(all on one line):python: not
here.restrictedTraverse('@@plone_portal_state').anonymous() and
here.restrictedTraverse('@@kss_devel_mode').isoff()and this is the normal line in the Condition field of++resource++kukit-devel.js(all on one line):python: not
here.restrictedTraverse('@@plone_portal_state').anonymous() and
here.restrictedTraverse('@@kss_devel_mode').ison()CompatibilityVersion 3.0 should work on Plone 4.1, 4.2, 4.3, 5.0.For older Plone versions, please stick to the 2.x line.  Latest
release as of writing is 2.7.Note that on Plone 5.0 we are not completely modern: we register our
css and javascript in the old portal tools, not in the new resource
registry.  So it ends up in the Plone legacy bundle.History of zest.emailhider package3.1.3 (2018-02-20)Make ‘No uids found in request.’ a warning instead of an error.
I see bots requesting this url.  [maurits]3.1.2 (2017-03-08)Do not render our javascript inline.  It leads to display problems
when it is included on a 404 page or any other non 20x page:
an assertion inProducts.ResourceRegistriesfails, resulting in
the html being returned with mimetype javascript.
That seems a possible problem with any inline script.
Added upgrade step for this.
[maurits]3.1.1 (2017-02-24)Fixed javascript bug that caused a request even without any emails to reveal.
[maurits]3.1 (2016-11-02)Query and reveal all emails at once.  If you have an employee
content type that you have hooked up to zest.emailhider, and you
have a page showing fifty employees, previously we would fire fifty
ajax requests.  Now we gather everything into one request.
[maurits]3.0 (2015-10-03)Added Travis badge.
[maurits]Support Plone 5 by readingplone.email_from_addressfrom the
registry.  This loses compatibility with Plone 4.0.  We try reading
any email (also your own additional emails) from the registry first,
withplone.prepended, and then look for a property on the
portal root.
[maurits]Use$instead ofjqin our javascript.  Now it works without
needingjquery-integration.js.  This loses compatibility with
Plone 3.
[maurits]Addedtest_emailhiderpage that hides the portalemail_from_address, so you can easily test it.  When you disable
your javascript you should not see an email address.
[maurits]2.7 (2012-09-12)Moved to github.
[maurits]2.6 (2011-11-11)Added MANIFEST.in so our generated .mo files are added to the source
distribution.
[maurits]Register our browser views only for our own new browser layer.
Added an upgrade step for this.  This makes it easier for other
packages to have a conditional dependency on zest.emailhider.
[maurits]2.5 (2011-06-01)Updated call to ‘jq_reveal_email’ to use the one at the root of the
site to avoid security errors. [vincent]2.4 (2011-05-10)Updated jquery.pyproxy dependency to at least 0.3.1 and removed the
now no longer needed clean_string call.
[maurits]2.3 (2010-12-15)Not only look up a fake uid for email_from_address as portal
property, but do this for any fake uid that has ‘email’ or ‘address’
in it.  Log warnings when no email address can be found for a fake
or real uid.
[maurits]2.2 (2010-12-14)Added another upgrade step as we definitely need to apply our
javascript registry too when upgrading.  Really at this point a
plain reinstall in the portal_quickinstaller is actually fine, which
we could also define as upgrade step, but never mind that now.
[maurits]2.1 (2010-12-14)Added two upgrade steps to upgrade from 1.x by installing
jquery.pyproxy and running our kss step (which just removes our
no longer needed kss file).
[maurits]2.0 (2010-12-09)Use jquery.pyproxy instead of KSS.  This makes the page load much
less for anonymous users.
[vincent+maurits]1.3 (2009-12-28)Made reveal_email available always, as it should just work whenever
we want to hide the glocal ‘email_from_address’.  If we have a real
uid target, then try to adapt that target to the IMailable interface
and if that fails we just silently do nothing.
[maurits]1.2 (2008-11-19)Using kss.plugin.cacheability and added it as a dependency.  [jladage]Allow to set the uid to email_from_address.  [jladage]Changed the KSS to use the load event instead of the click event - it
now either works transparently, or asks the user to activate JS. [simon]1.1 (2008-10-24)Added translations and modified template to use them. [simon]Initial creation of project. [simon]1.0 (2008-10-20)Initial creation of project. [simon]