Adding bespoke Google maps to Plone
(Of course this tutorial assumes you already know how to set up Google maps in standard HTML pages. If you don't know how to embed Google maps, then follow over to their documentation.)
- First via the ZMI make a copy of the main_template page template, and rename it for use on our map page:
- Within your site in the ZMI, go to portal_skins/plone_templates and enter the main_template page template.
- Click the "Customise" button to create a copy in the portal_skins/custom folder.
- Now enter portal_skins/custom and rename main_template to something suitable (e.g. "map-template"). This ensures that the version in the custom folder doesn't override the main_template that all pages use!
- We can now edit our map-template page template and add the required
Google JavaScript into the <head> and add the onload function to
the <body> tag:
<metal:page define-macro="master"> <metal:block define-slot="top_slot" /> <tal:doctype tal:replace="structure string:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">" /> <metal:block use-macro="here/global_defines/macros/defines" /> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" tal:define="lang language" tal:attributes="lang lang; xml:lang lang"> ... ... ... <tal:comment replace="nothing"> A slot where you can insert elements in the header from a template </tal:comment> <metal:headslot define-slot="head_slot" /> <tal:comment replace="nothing"> A slot where you can insert CSS in the header from a template </tal:comment> <metal:styleslot define-slot="style_slot" /> <tal:comment replace="nothing"> This is deprecated, please use style_slot instead. </tal:comment> <metal:cssslot define-slot="css_slot" /> <tal:comment replace="nothing"> A slot where you can insert javascript in the header from a template </tal:comment> <metal:javascriptslot define-slot="javascript_head_slot" /> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"> </script> <script type="text/javascript"> function initialize() { var centerMap = new google.maps.LatLng(51.776337690506615, -1.2435150146484375); var mapOptions = { zoom: 11, center: centerMap, mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); // Thom building. var thomPosition = new google.maps.LatLng(51.760425, -1.259544); var thomMarker = new google.maps.Marker({ position: thomPosition, map: map, title:"Department of Engineering Science" }); // IBME building. var ibmePosition = new google.maps.LatLng(51.752212, -1.214013); var ibmeMarker = new google.maps.Marker({ position: ibmePosition, map: map, title:"Institute of Biomedical Engineering" }); // Southwell building. var southwellPosition = new google.maps.LatLng(51.74639, -1.27065); var southwellMarker = new google.maps.Marker({ position: southwellPosition, map: map, title:"Southwell Laboratory" }); // Begbroke. var begbrokePosition = new google.maps.LatLng(51.817791, -1.306250); var begbrokeMarker = new google.maps.Marker({ position: begbrokePosition, map: map, title:"Begbroke Science Park" }); } </script> </head> <body onload="initialize()" tal:define="template_id python:template.id or path('view/__name__'); class_expr string:${context/getSectionFromURL} template-${template_id};" tal:attributes="class python:class_expr.strip(); dir python:test(isRTL, 'rtl', 'ltr')"> <div id="visual-portal-wrapper"> ... ... ... </body> </html> </metal:page>Presumably one should use the javascript_head_slot, but this way is simpler.
(Note: if the template does not compile for any reason it will not work. You will have to remove any code within the Google JavaScript that Zope does not like). - Now we have the custom template, we have to create a page template view to use it (i.e. to fill the relevant slots in our map-template).
- Since the page to contain the map will be a standard Plone page, we will take a copy of the default document_view.
- Within the ZMI enter portal_skins/plone_content/document_view and hit "customize". This will create a copy within portal_skins/custom.
- Rename this view to something suitable (e.g. map-view).
- Modify this so that it uses the map-template page template rather than the default main_template by modifying the metal:use-macro line to metal:use-macro="here/map-template/macros/master":
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:i18n="http://xml.zope.org/namespaces/i18n" xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal" lang="en" metal:use-macro="here/map-template/macros/master" i18n:domain="plone"> <head> </head> <body> <metal:main fill-slot="main"> <tal:main-macro metal:define-macro="main" tal:define="kssClassesView context/@@kss_field_decorator_view; getKssClasses nocall:kssClassesView/getKssClassesInlineEditable; templateId template/getId; text here/getText;"> <div tal:replace="structure provider:plone.abovecontenttitle" /> <h1 class="documentFirstHeading"> <metal:field use-macro="python:here.widget('title', mode='view')"> Title </metal:field> </h1> <div tal:replace="structure provider:plone.belowcontenttitle" /> <p class="documentDescription"> <metal:field use-macro="python:here.widget('description', mode='view')"> Description </metal:field> </p> <div tal:replace="structure provider:plone.abovecontentbody" /> <p tal:condition="python: not text and is_editable" i18n:translate="no_body_text" class="discreet"> This item does not have any body text, click the edit tab to change it. </p> <metal:field use-macro="python:here.widget('text', mode='view')"> Body text </metal:field> <div metal:use-macro="here/document_relateditems/macros/relatedItems"> show related items if they exist </div> <div tal:replace="structure provider:plone.belowcontentbody" /> </tal:main-macro> </metal:main> </body> </html> - The final step is to modify the page to contain the map to use our map-view for its layout:
- Within the ZMI navigate to the page to contain the Google map (e.g. contact-us/travel).
- Click on the Properties tab.
- Add a new string property with a name of "layout" and value of "map-view".
- Save the changes.
- The page is now ready to contain the <div> code that Google maps use for their map_canvas:
<div id="map_canvas" style="width: 800px; height: 400px;"></div>
This may be added to the page via the editor (i.e. in HTML view), or the code can even be added to the map-view page template if you don't want users messing with it.
XDV
If you are running collective.xdv to theme your site, all will work except for the <body onload="initialize()"> code.
This is because if the onload body attribute is not in your theme.html, then it will not appear in the final page HTML, and the Google map will not work.
You have two options:
- Add <body onload="initialize()"> to the theme.html body tag. However, this will mean that every page will call the initialize() JavaScript function, when for most pages the function has not been defined. Not a good idea!
- Add a rule into rules.xml to add the onload attribute to our body tag when it appears:
<prepend content='/html/body/@onload' theme='/html/body' />
This, of course, works perfectly, adding the initialize() function only on the page using the map-template!
