07 Jan 2011IE8 has a strange bug (what bugs aren't strange in IE ?) when dealing with :after
and :before
pseudo-elements.
I was adding a nice looking arrow after one of my elements using :after
. I wanted this arrow to only display when my element was hovered, so I wrote the following code :
a {
position:relative;
display:block;
height:30px;
}
a:after {
position:absolute;
content:"";
top:0px;
right:-15px;
width:15px;
height:30px;
background:url(arrow.gif) top left no-repeat;
display:none;
}
a:hover:after {
display:block;
}
As you can see, nothing too fancy. I positionned my arrow using an empty :after
element and a background
image. I defaulted the arrow to hidden, and only show it when hovering the element.
IE in action
It does work pretty well in moder browsers. It also seems to work on IE8. When you hover the element in IE8, the arrow gets displayed. But it does not gets hidden when you stop hovering it.
There's a kind of ghost element that keeps getting displayed. It gets removed if you directly mouse it, or scroll your page, or alt-tab, etc. This clearly is a display artefact.
To counter this I had to write it in an other fashion (less readable in my opinion). Removing the default a:after
rule and adding all properties to a:hover:after
:
a {
position:relative;
display:block;
height:30px;
}
a:hover:after {
position:absolute;
content:"";
top:0px;
right:-15px;
width:15px;
height:30px;
background:url(arrow.gif) top left no-repeat;
display:block;
}
Update
It should be noted that more generally, I gets confused and create ghost elements and styling when we try to update the :after
/:before
properties based on a rule selecting its parent.
There seems to have a little lag/delay before the properties gets applied, and most of the time they do not.
06 Jan 2011I often use $this->cakeError('error404')
in my controllers to stop processing the request (and return a 404 error) when the supplied parameters are buggy or incomplete.
A strange side effect
I recently spotted a strange side effect on the latest site I was developping. It used a pretty large html footer filled with links dynamically fetched from my database.
As all pages (no matter what model/controller they were refering to) were using the same footer, I created a component with a simple startup
method to fetch them all and return them to the view. I added this component to my AppController
so that every controller will inherit it.
This worked nicely until I spotted that on error pages, the footer was left mostly empty. I was because my Component
callback was never fired.
How's that ?
When detecting an error, cake starts using its ErrorHandler
and thus do not fire callbacks.
Fortunatly, you can create an AppError
class (in app/app_error.php
) and overwrite the ErrorHandler
method. Namely, the error404
. I rewrote mine to explicitly fire the initialize
and startup
methods.
class AppError extends ErrorHandler {
function error404($params) {
$this->controller->Component->initialize($this->controller);
$this->controller->Component->startup($this->controller);
parent::error404($params);
}
}
I only fired two of the callbacks, but maybe beforeRender
and shutdown
should be fired too.
04 Jan 2011As you may have heard, Yahoo! is closing Delicious. I had started to use Delicious a lot lately, to work as a decentralised save of all my bookmarks and being able to search through them easily.
In my recent attempt to save as much of my work online, losing Delicious would meant losing a large part of collective wisdom. So I search for an alternative.
I finally registered for Pinboarda few days ago. It allows an easy way to import Delicious bookmarks in a matter of seconds and has all the features of Delicious I wanted.
It is not free however, but the one-time fee depends on the number of people using the service. I payed mine 9.12$.
The website itself is not as good looking as Delicious (ahem), but it does provide a cleaner search experience (in my point of view). I really don't care about other people bookmark, I only search through mine.
03 Jan 2011I wanted one of my tinyMCE plugins to fire a certain set of actions whenever the full screen mode was activated.
I search for an onFullScren
event or somethin similar but to no avail. I finally discovered that the full screen actually creates a whole new tinymce editor instance.
So the only thing I had to do was writing my little piece of code in the init
method of my plugin and check to see if the fullscreen was enabled.
The initial fullscreen plugin exposes a fullscreen_is_enabled
param that can be checked.
All I had to do was a simple condition like : if (editor.getParam('fullscreen_is_enabled')) {}.
And once in the condition I tried to execute my custom code. I needed the editor.execCommand
method but all I got was an error because t.selection
was not set.
It appears that the execCommand can only be executed when the full editor instance is loaded (and thus a t.selection is created). So I wrap my little piece of code into a setInterval
checking for editor.selection
and finally executed my code when the .selection
was set.
Here is my final snippet, to be included in my plugin init
method :
if (editor.getParam('fullscreen_is_enabled')) {
var fullScreenInterval = setInterval(function() {
if (!editor.selection) return false;
clearInterval(fullScreenInterval);
editor.execCommand('anyTinyMCECommand');
}, 1000);
}
11 Dec 2010When using the default tinyMCE implementation to add an <hr>
element to the editor content, the <hr>
is added inside its parent <p>
element (when it should be an element on its own, without such a parent).
I've added my own plugin to resolve this small issue, here is the code :
(function() {
tinymce.create('tinymce.plugins.pixelastic_hrPlugin', {
init : function(editor, url) {
// Register the command
editor.addCommand('mcepixelastic_hr', function() {
// We get the parent node
var parentNode = editor.selection.getNode(),
uniqueId = editor.dom.uniqueId();
// We insert the hr (with a unique id to select it later)
editor.execCommand('mceInsertContent', false, '<hr id="'+uniqueId+'" />');
var hr = editor.dom.select('#'+uniqueId)[0];
// We split the parent element around the hr
editor.dom.split(parentNode, hr);
// We remove the temporary id
$(hr).attr('id', null);
});
// Adding a button
editor.addButton(pluginName, { title : 'pixelastic_hr.desc', cmd : 'mcepixelastic_hr' });
}
}
});
// Register plugin
tinymce.PluginManager.add('pixelastic_hr', tinymce.plugins['pixelastic_hrPlugin']);
})();
The trick to use the editor.dom.split
method to split the parent element around the <hr>
element.
The dirty hacks is that there is no way to get a direct reference to a DOM element added through mceInsertContent
, so we need to set a temporary unique id and then select it through this id.
I use jQuery in my example and I strongly suggest you to do the same, the selectors it provides are much sexier and helps writing these kind of plugins pretty fast.