AddThis _atssh div causing issues

I’m using AddThis in the new CSlide site, and it seems to add a div (id=”_atssh”), immediately after the link to the AddThis JavaScript file. This happens even if you have the JS file in the <head> section of the page, resulting in a div in the head, which clearly isn’t right. A quick search on the AddThis site suggests I am not the first to come across this issue, but it would appear the promised fix has not happened yet.

This can be fixed by putting the link to the JS file in the body (ideally at the end, for the sake of performance/progressive rendering*). However, having this div inserted at the end results in the size of the page height being increased by 1 pixel. Since, in my site anyway, it comes after a container with height set to 100%, it results in the page having a scrollbar when it shouldn’t need it.

Again, this can be fixed relatively easily, by adding the CSS below to your stylesheet. The offending div is invisible, so making it absolutely positioned (it used to already have position: absolute, but this seems to have changed (as at 6/01/2015)) and setting “top” to 0 just sticks it at the top of the page where it can’t interfere any more.

#_atssh {
    position: absolute;
    top: 0;
}

*I should mention that my JS was already at the end, and I only found out about the “div in the head” issue when looking into the page height issue.

CakePHP: Getting the full URL of the current page

In a CakePHP (2.3) project, I needed to echo the full (i.e. including scheme (http, https etc) and hostname) current URL in a view. I assumed this would be easy, and it is, but it wasn’t immediately obvious and took a bit of searching. The following examples assume we are on localhost, the project is called ‘project’ and the current page is /controller/action/1, so we would expect the full URL to be: http://localhost/project/controller/action/1.

The way to do it:

All we need to do is to echo a null url, with the ‘full’ option set to true, which means the scheme, hostname and project path are included. As well as null, any “falsey” value seems to work, e.g. false, 0, “”, and even array().

echo $this->Html->url(null, true);

Produces: http://localhost/project/controller/action/1

The ways not to do it:

echo $this->here;

Produces: /project/controller/action/1. This is missing the scheme and hostname.

echo $this->Html->url();

Produces: /project/controller/action/1. Again, this is missing the scheme and hostname.

echo $this->Html->url( $this->here, true );

Produces: http://localhost/project/project/controller/action/1. Here ‘project’ appears twice, once from $this->here and once as we have set the ‘full’ option to true.

Google Maps need resizing after being “shown” with JavaScript/JQuery

If you have a Google Map on a page that, for example, starts off hidden and is shown using JavaScript (inc. JQuery or another library), it seems to only load the top left map tile. In order to fix this, you need to resize the map after showing it, using the following line:

google.maps.event.trigger(map, 'resize');    //map is your google.maps.Map object

This is mentioned in the resize event in the Map class documentation.

XML views in CakePHP 2.x

In a CakePHP project, I needed to extract an XML string from the database and display it as an XML page. The docs suggested this would be easy with the XmlView, but I struggled to get it to work. However,  after a fair amount of fiddling around, I found an easy way to display an XML view.

Here’s what I had to do:

  • Enable parsing of .xml extensions in routes.php:
    Router::parseExtensions('xml');
  • Set the viewClass to Xml in the controller:
    $this->viewClass = 'Xml';
  • Create a simple xml view in Views/YourController/xml/xml.ctp, and echo $xml in this view:
    <?php echo $xml; ?>
  • Back in the controller, set the XML string to the view:
    $this->set('xml', $xmlString);
  • Finally, render using the xml view you have just created (this must be after the ‘set’ line above):
    $this->render('xml');

Unfortunately, this does not take advantage of the _serialize key, which would mean you don’t need to create a view file at all, but I just couldn’t get this to work with an XML string, despite trying various combinations of CakePHP’s Xml Class functions.

Complete Idiots Guide to using Composer with CakePHP

I recently wanted to use Miles Johnson’s Forum Plugin for CakePHP in a project, and when I came to install it, saw that he recommends (insists on, in fact) using Composer to do this, to take care of ensuring all the dependencies are installed. Never having used Composer before, I took a look at his post on using Composer with CakePHP, which probably counts as an idiots guide for most people, but still wasn’t basic enough for me. Therefore, I thought I would write a complete idiots guide!

The steps I had to go through to get it working were as follows:

  • Install Composer – I am on Windows, so just downloaded and ran the Windows installer, which seemed to work fine
  • Ensure that the openssl extension is enabled in php.ini, i.e. uncomment this line: extension=php_openssl.dll
  • Create a composer.json file in your app directory and add the dependencies, e.g. for the Forum plugin:
    {
       "config": {
          "vendor-dir": "Vendor"
       },
       "require": {
          "mjohnson/forum": "5.*"
       }
    }
  • Run composer install in the app directory. This should install all of the dependencies (in the Vendor or Plugin directories of your app, as appropriate) and create an autoload.php file in the Vendor directory
  • Add the following at the start of your Config/core.php file to make use of Composer’s autoloading capabilities:
    require_once dirname(__DIR__) . '/Vendor/autoload.php';

That should deal with all of the dependencies, in this case for the Forum Plugin. It is still necessary to load the Plugins in the Config/bootstrap.php file. For the Forum Plugin, this is does as follows:

CakePlugin::load('Utility', array('bootstrap' => true, 'routes' => true));
CakePlugin::load('Admin', array('bootstrap' => true, 'routes' => true));
CakePlugin::load('Forum', array('bootstrap' => true, 'routes' => true));

CKEditor: Use config.allowedContent/extraAllowedContent to stop tags being stripped

I was having an issue with certain tags, e.g. span and div, being stripped out of html by CKEditor. Whether or not I should be using these tags is another issue – in this particular situation it was useful to use span tags to give a class to snippets of text that would be styled in different ways, to indicate different types of text (printed, handwritten or engraved) on historical slides in CSlide.

It turns out that CKEditor (4.1 onwards) has the Advanced Content Filter (ACF), which is a highly configurable filter that allows only certain types of content to be entered into the editor, and removes any html tags that are not allowed by the configuration. The default behaviour (Automatic mode) results in all of the enabled editor features, e.g. styling buttons, formats, etc, adding their rules (i.e. the html associated with the feature) to the filtering rules to allow that type of content. The alternative to this is Custom mode, where the allowed content is defined in the config, using config.allowedContent – see the CKEditor guide on defining allowed content rules.

Turning off the ACF

I wouldn’t advise this (it is much better to configure the ACF), but if you really don’t want CKEditor to do any filtering, you can turn it off by adding the following line to config.js:

config.allowedContent = true;

extraAllowedContent

As well as fully defining the ACF rules using config.allowedContent, it is also possible to extend the current rules using config.extraAllowedContent, and this was the most straightforward solution to my issue. extraAllowedContent allows you to add rules to the current config, which is an easy way to extend, for example, the automatic mode configuration. In my case, I was able to allow span tags, and define a set of classes that these span tags would be allowed to have:

config.extraAllowedContent = 'span(engraved,printed,manuscript,slide_text,label_text)';

This setting means that any other class associated with span tags will be removed (though the span tag will remain). Using ‘span(*)’ allows span tags with any class.

Google Maps Autocomplete in Bootstrap Modal

I’ve just spent a while struggling to get a Google Maps API v3 Places Autocomplete search text box working in a Bootstrap JS Modal. It seemed as though the autocomplete wasn’t working at all, which I initially thought meant that I had messed up my JQuery selectors. However, it turns out that it the autocomplete was working (I could use the down arrow to toggle through the results), but the results were being shown behind the modal box. The z-index of the modal box is 1040 by default, whereas that of the .pac-container div that shows the autocomplete results is 1000 (defined inline).

Therefore, the solution (easy when you know how) is to change the z-index of the .pac-container div to greater than 1040, so that it appears on top of the modal. Since the z-index of .pac-container is defined inline, it is necessary to use !important to override this inline style with from an internal/external stylesheet:

div.pac-container {
   z-index: 1050 !important;
}

CKEditor: Custom format options

I wanted to just allow a single “Heading” paragraph format in CKEditor, rather than having multiple heading options. I found that it was possible to change the available options in editing “config.format_tags” in ckeditor/config.js. For example, the following would show just the paragraph (Normal) and h1 (Heading 1) format options:

config.format_tags = 'p;h1';

However, having “Heading 1” as the only heading option isn’t particularly satisfactory, so I wanted to rename it to something else. This requires defining a custom format type, as follows:

config.format_tags = 'p;Heading';
config.format_Heading = { element : 'h1', name: 'Heading' };

Each of the format_tags needs a corresponding format_(tagName) entry and the default ones are predefined (http://docs.ckeditor.com/source/plugin28.html#CKEDITOR-config-cfg-format_tags). Overwrite these defaults in the config.js file does not seem to work, so I had to define a new format type, ‘Heading’, using the h1 element and named ‘Heading’.

Google Maps API v3: Capturing viewport change – use “idle” not “bounds_changed”

When wanting to capture a change in the viewport (e.g. zoom, pan), when using the Google Maps API v3, the obvious event to listen for seems to be “bounds_changed”. However, when dragging the map to pan, this event is fired repeatedly, which, in our case, meant that there hundreds of requests being sent when a user panned.

The solution is to listen for the “idle” event instead, which is only fired when the user has stopped panning/zooming:

google.maps.event.addListener(map, 'idle', function() {
   //Do something when the user has stopped zooming/panning
});