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 onFullScrenevent 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 initmethod 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 .selectionwas set.
Here is my final snippet, to be included in my plugin initmethod :
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.
07 Dec 2010My computer was starting to get slower and slower for the past days. And I realized my automatic backup wasn't backing anything up for the past month.
And I realized I had different versions of the same files on my 2 laptops...
Well, it seems I have to do some cleaning up.
Synchronizing paperwork
I started by cleaning up my Dropboxfolder. I removed shared folders with past clients, and created a "Paperwork" folder where I put all my invoices, contracts and general paperwork.
I also added my private KeePassfile as well as other info I may need to access anywhere, anytime.
KeePass allow me to store all my login/password credentials in a secure way (protected by a master password). It is really useful to have this file on all my computers (and mobile phone).
Dropbox is excellent for storing simple files, that you need everywhere. Being able to access invoices and contracts even from my mobile phone proved quite valuable when meeting clients.
Hard backup of personal files
I've also changed my scheduled backups of personal files. I bought an Acronis True Image last year, and reconfigured it today.
I have a hard drive whose sole purpose is to save backups. I scheduled for the first of each month to save : my system state, my applications configuration, and my personal files (photos, saved gamed, writings, etc).
I manually started all this backups to have a clean start. I also forced the backup to restart a whole new file every 6 month (opposed to using the incremental backup).
Backing up my music and movies
I did not spent too much time figuring how to save my hundred of Go of music and movies. I rarely watch the same movies twice, so losing them won't affect me too much.
I occasionally re-watch series, though, but as most of my friends have the same tastes as I, I could very easily get them back from them, or download them (again).
Regarding music, well, I have quite a big collection, but most of it is already "backed up" on my portable mp3 player.
Automatic synchronizing with BitBucket
On my day work, I now always version my files using Mercurial. BitBucket offers unlimited storage, and unlimited public repositories. Private repo are limited to 5 users. As I'm mostly alone on projects that should stay private, this seems the best deal I could found.
Mercurial being a versionning system, I got all the benefits of a backup here, being able to revert to previous versions, update it whenever I want and access it from anywhere.
I wrote a custom Hg hook on commit to automatically push my repos to BitBucket at least once a day (I'll post the code in a future post).
MySQL Backup
I used to backup mysql databases on my work computer using a windows app. This was slowing down my computer on every boot as well and backup was thus only effective when I was working and not when I was on vacations.
Today, I wanted something a lot more flexible, so I set a cronjob on my main host coupled with a slightly edited autoMySQLBackupscript.
This will automatically run everyday at midnight and make a local save (with daily, weekly and monthly rotate) of all my clients databases. Logs are saved on disk and gzipped, and will also be sent to a special backup@pixelastic.com mail address (stored on GMail).
This way I am sure to have my mysql backups on two different hosts, with daily and automatic saves, that I can access from anywhere if anything goes wrong.
Conclusion
It took me almost two full days to get the right tools, configure them and write my custom scripts but now, it is seamlessly integrated with my daily workflow. This is a weight off my shoulders, I know I can safely work as usual and my files are saved and easily accessible.
02 Dec 2010In cakePHP, you can pass all sort of parameters to your urls by following the www.domain.com/controllers/view/foo:bar/foo2:baz syntax.
You could then access $this->params['foo'] and $this->params['foo2'] in your Controller::view() method.
Using Router::connectName()
This does not play nice with default routing. I mean, if you define a route to add a vanity url like www.domain.com/vanity is routed to Controller:view(), you'll write something like this :
Router::connect('/vanity', array('controller' => 'controllers', 'action' => 'view'));
This will work as long as you don't specify any additional parameters. Once you started to add any parameters, the Router won't be able to parse your url and instead of returning www.domain.com/vanity/foo:bar/foo2:baz it will return the default www.domain.com/controllers/view/foo:bar/foo2:baz
If you do want your custom parameters to be taken into account by your Router rules, you have to manually add them, usingRouter::connectNamed(array('foo', 'foo2')).
Custom connectNamed()
I'll let you browse the [connectNamed()](http://api.cakephp.org/class/router
method-RouterconnectNamed) documentation page for further details on how to
use it properly. But one important thing not to overlook is that if you ever have to define a custom Router::connectNamed(), do not forget to add a second parameter of array('default' => true), this will allow all your paginated links to keep working.
26 Nov 2010This <noscript> tag on IE7 is making me crazy. Here are some "interesting" facts about it :
No content through Javascript
You can't get its content though javascript. It can be targeted but neither .innerHTML nor .textContent is set. It does not have any .childNodes either.
Gets displayed even when scripts are enabled
If you set noscript { display:block; border:15px solid red;}, it will get displayed even if Javascript is enabled. But with no content inside, you'll only have borders and background...
Styling it anyway
If you want to style it, just add an inner element and style this one :
<noscript><p>Lorem ipsum</p></noscript>
noscript p { background:blue; }
Disabling Javascript on IE7
If you want to disable Javascript on IE7, you'll have to go to Tools > Internet Options > Security > Custom and setting the "Enable ASP scripts" to No.
Yes, this doesn't make any sense.