2013/08/10

A basic upload script for CKEditor

A long time ago I published a basic example showing the skeleton of how an upload script for CKEditor should look like. Since the release of the imagepaste plugin I've received some requests to fill and explain all the details, and some people buy that plugin even before testing the free version and then they find that they don't know how to upload files.

So now I'm publishing that script with the missing part, a simple call to

move_uploaded_file($_FILES["upload"]["tmp_name"], $basePath . $name);

I've adjusted it a little so that the path to the upload folder and matching URL can be configured more easily, but it's still a very basic script. It doesn't perform any check on the uploaded files, you must take care of integrating it with your CMS (after all, that's something impossible for me to know how you're doing that part) and verify that the upload folder has the right permissions.

You can use it with CKEditor to enable the Upload tab in the Image and Link dialogs, and that way the user will be able to upload files (but not browse the existing ones). If you add the free version of the image paste plugin, then the user will be able to paste images from their clipboard into CKEditor, and the content will not be that huge mess of base64 encoded data, but a simple URL to your server with all the performance benefits that it means.

At this point, you can opt to buy the full version of the image paste plugin if you want to provide even more options for the users:

  • Drag and drop from the computer for every modern browser
  • Pasting images from the clipboard in Chrome (besides the basic pasting available in the free version for Firefox)
  • Copy and paste a file from your computer in Firefox
  • Two buttons to quickly upload a file or image for every browser. There's no way to make uploads simpler than this, other plugins still require the user to open a dialog, click browse, upload, etc... that's a huge mess and a big waste of time. Here you click and the file picker launches automatically, select the file that you want and then it's uploaded and inserted in a single step.

You can test all these features in the demo page for CKEditor 4 (the plugin also works with CKEditor 3)

Back to this upload script:

I've published it at GitHub so if other people wants to provide some suggestions for better compatibility or they take the time to improve it I will try to keep it updated, but I don't really want to spend too much time on it because if by a miracle it would be a success (in fact, I wouldn't like to see too many people using this because it's really basic) then attackers would love to exploit all the weakness that it has. Please, read the documentation, all the comments and try your best to secure it as much as you can. If you download it from GitHub, you can remove those extra .git* files that it has added automatically as well as the readme and the docs when you have read them.

You only need the upload.php file and to improve a little the security by obscurity you can opt to rename it anyway that you want, just put that same name and path in the configuration of your CKEditor.

The best option would be for you to take this script as a full example and then add your customizations, your own security options, make it unique so that a simple bot can't find and use it.

This is the link to download the current version from GitHub.

2013/08/02

Making the ImagePaste plugin compatible with IE11

Now that it's summer time and I have some free time I decided to take a look at the beta of IE 11 to check how well does it work with some of my CKEditor plugins.

The first thing to remember is that CKEditor itself isn't compatible with IE11 and if we are to base our guesses on previous history I don't think that they will really work on it until sometime after IE11 has been released and people start complaining seriously, but I prefer to look ahead and try to work now instead of having to rush later.

So I've focused my tests on the image paste plugin, specially because in their release notes they talk about the new ability to use the .files property in the clipboardData object as well as the base64 encoding performed by default (like Firefox).

Well, using base64 on the image is a nice little trick, but I think that it's really a bad option in the real world. I guess that if any performance guru would have been consulted they would have answered that this feature shouldn't have been added (at least not by default).

Testing IE nowadays it's much simpler than it used to be. Microsoft provides virtual machines ready to use with almost any combination of supported OS and IE as well as the virtual machine environment (at least I didn't miss anything). So after downloading the Win 8.1 preview and "installing" it, I was ready to test.

Ok, almost ready to test: no network connection. It turns out that the default network configuration is set up to work as a private network with the host. After changing it to my default bridged preference I had Internet again :-)

So I launched my demo with CKEditor 3 and... nothing. Nothing is pasted there. Not only the image is ignored from the clipboard, also any text can't be pasted. As the argument will be that CKEditor is "old" and it's not supported I moved then to the CKEditor 4 demo to check it, and yes, now it "works". The image is pasted but as base64 data. That means that neither my direct paste listener on the element is working to detect the files and the default CKEditor paste event is also failing to provide me the base64 so I could try to use the same Firefox trick.

A little debugging shows that the CKEditor paste isn't fired at all and my listener on the editable element works, but the event doesn't seem to include the .files property. Debugging that info isn't as easy as it seems, despite the claim that after pressing F12 the debugger is ready isn't true for me, breakpoints doesn't work, the files show up as a huge list of "plugin.js" files...

At this point a very important suggestion for Microsoft: Show folder names in the pane with the loaded scripts, having around 30 or 50 files named "plugin.js" and no way to tell them apart is not fun.

In order to debug correctly I restart the machine (maybe it's usual for people to start debuggin on the first IE & OS launch, but I don't see any other reason to fire up that VM, Win8.1 still tries to force "metro" too much so it doesn't fit my tastes) and now things seem to work a little better. To find the place for my breakpoints I search the files for the some function name specific to that file and that way I can avoid the mess of "plugin.js" .

And now looking at their documentation I notice something interesting, instead of using a clipboardData object on the paste event data, they are using one one the window object (like old IEs), so now it's obvious why this detection wasn't working. I add a workaround to try to use it and now when I copy an image from Paint I can detect and upload it like it happens in Firefox and Chrome. Due to the way that they have written their documentation I think that this feature isn't complete, after all I haven't managed to get an event if I try to paste a file from the desktop (like Firefox does) and if I create a document in WordPad with an image only the text is copied and no image is inserted, although given the way that they have chosen to write the documentation I think that some other feature should be available in the final version besides pasting a simple image from the clipboard.

After noticing that issue and given that this is a problem that shouldn't exist (providing files in the clipboard data is a feature that currently only Firefox and Chrome support, so if Microsoft want existing code to work they should use exactly the same APIs and objects) I filed a bug in their tracker to check if they care about compatibility or not. To my surprise this morning I had a reply, stating that obviously they can't reproduce the bug and the best course of action is to close it. I've replied providing the test file as a live url instead of an attachment (they didn't allow .html attachments so finding a .txt page might have been too hard for them). Of course this probably means the end of my efforts to report any issue in IE11 to Microsoft, if they don't care about something so simple and basic according to their goal of treating IE11 as any other modern browser then I'm not gonna waste my time trying to explain more complex things.

Back to my testings on IE11 and image paste, I noticed that dropping a file doesn't upload it and instead tries to open it as if I hadn't added any drop listeners. In this case the problem is that CKEditor at the moment detects IE11 as a gecko, but in this case Microsoft is aligning their behavior to old Chrome and requires that the drag over event is prevented. This is the kind of bug that Microsoft should also fix, but I don't have hope on them so I just add a line to detect "IEmodern" and it works (yes, this is the kind of bug/browser behavior that can't be changed based on feature detection but instead it relies on hardcoding which are the buggy browsers)

So now I tested again the CKEditor 3 demo and everything related to my plugin works. Images can be pasted, dragged, uploaded with the toolbar button... CKEditor itself has its own set of bugs (like not being able to paste at all in 3.6 or that the paste event isn't fired in 4.2) but that's outside my control. I could try to debug and provide patches if I really cared, but given that some of the patches that I provided for CKEditor have been ignored for years I prefer to not waste the time that way.

BTW, soon I might replace all the CKEditor 4 demos with the "Moono color" skin, being forced to see those black and white icons is really depressing.

 

2013/04/27

Uploading files to CKEditor the easy way

It's been some time since I published an improved version of the original ImagePaste plugin for Firefox. In that version I included the option to upload files by drag&drop from the desktop and that feature was supported by the latest versions of all the browsers.

Since then I've been polishing the plugin, adding little details, fixing whatever bugs appear and recently I've added a major new feature that I had in my head for a very long time but I never took the time to write it.

Finally I thought that enough is enough and that it's better to get that idea out of my mind and so we have now version 3 of the ImagePaste plugin, with two toolbar buttons to upload files or images without any extra dialog, just a click on the button, select the file and it's uploaded and inserted into the content.

Features of the plugin

In all the browsers you can upload a file or an image by clicking the addFile or addImage buttons. All the browsers means that even IE8 is supported for this option and it's just the simplest way for everyone to add files without having to deal with all the options in the default image or link dialogs.

If you use a modern browser (current versions of Firefox, Chrome, Opera and Safari, as well as IE 10) you will be able to upload an image or file just by dropping it into the editor.

With Chrome and Firefox, you can copy an image or part of it to your clipboard in a program like Photoshop, Paint.Net, etc... and then paste it into the contents with Ctrl+V.

With Firefox, you can select a file in your desktop, copy it to the clipboard (Ctrl+C) and then paste it into the editor with Ctrl+V.

Demo

There is a demo with CKEditor 3 and there's another demo with just the same plugin but using CKEditor 4, including some zones in "inline editing"

Getting the plugin

All the details are available in its new home.

 

I'm testing now selling the plugin through FetchApp to avoid any delays between the moment that you pay the money and when you get the file, so I would like to know if you have any problems in order to change the seller to another one.

Of course, verify that the mail account that you use is correctly configured, In theory you should get the file right after the payment, but it's better if you receive any mail correctly because I'll use that for future updates (all updates are included as you can see)

2012/12/15

No more releases for the onChange plugin

I know that the current version doesn't work correctly with the inline mode of CKEditor 4, but after reading some long threads it seems that some people doesn't like to use a third party plugin for this behavior and CKSource might release their own version, so I don't see any reason to keep updating my own one, specially due to the time that it can take to do a full review of all the ways that v4 can work in all the browsers.

If someone provides patches, I'll release those versions, but I just won't bother to test them (at least until I start using CKEditor 4, but I can't be sure when it will be ready to replace CKEditor 3 for me)

2012/12/06

Updates for the GoogleMaps plugin

It seems that I haven't write here anything about the Google Maps plugin for a whole year, and so some people might think that this is a dead project but it's far from that! it's alive and under continuous little improvements.

A summary of the new features since 3.1 (one year ago):

  • 3.2:
    • It's possible to delete single points in lines and areas.
    • Enabled Traffic and Weather layers.
  • 3.2.x:
    • Option to use custom icons in the markers.
    • It's possible to edit lines and areas.
  • 3.3:
    • Button in the editor for markers to insert a "Destination" link.
  • 3.3.x
    • Compatibility with CKEditor 4.

Besides that list, there are other adjustments to improve performance, add new translations, and of course fixing all the reported bugs but that list is boring :-)

A quick review of those new features:

Editing of lines and areas

Version 3.1 finally brought back the option to create Lines and Areas but the options to edit them or remove some points wasn't possible at the moment. Fortunatelly after some time those features were available and I added them to the maps editor.

New Layers

Sometimes Google adds a new option in the map, the Traffic layer allows to show the state of the road traffic in the map and the Weather shows the the typical sun/clouds/storm... icons overlayed if the zoom isn't too close.

Directions

This as a common request: an option to set in the window of a marker a link that provides the driving directions to arrive to a place. Now there's an icon in the embedded editor that inserts such a link for the current marker and when clicked it will launch Google Maps with the requested data.

CKEditor 4

This is the latest "feature" that I've added. Although most of the code of v4 is backwards compatible with CKEditor 3.x there are some changes that required some debugging to find out a solution to understand the problem and also the excesive padding in the default skin for v4 means that the contents of many fields were not correctly displayed.

At the moment I think that everything is working correctly, but I still want to perform more tests before being confident that I've tested everything (and so far I'm already getting tired of the problems caused by the dialogs in v4).

Anyway, here's a new demo to test Google Maps in CKEditor 4.

 

2012/12/03

Installing a CKEditor plugin inside Drupal or Joomla

This post is meant to be a compilation of notes about how to install a "CKEditor plugin", in a CKEditor installed in Joomla or Drupal. That means: you have CKEditor already installed inside your Drupal or Joomla and now you want to add a new third party plugin, and trying to follow the normal guidelines don't work because the integration with those CMSs means that the usual config.js isn't used.
Let's pick just for example this one: HTML5 Video Plugin, these are part of the install instructions that includes:

1. Copying the files

Extract the contents of the zip in you plugins directory, so it ends up like this

2. Adding it to CKEditor

Now add the plugin in your config.js or custom js configuration file: config.extraPlugins='video';

3. Add it to your toolbar

In your toolbar configuration, add a new 'Video' item in the place where you want the button to show up.
So, name of the plugin: "video", toolbar button: "Video"

Drupal

Edit June 2016:
Let's try to provide some extra info for the SimpleUploads plugin:
The main difficulty for this plugin with regards to other plugins is that it requires a server side script to save files. By default you won't get that with Drupal in the way that it's required, you can use for example IMCE to upload, manage and browse your files, but it lacks a method to save files posted directly from the editor.

You can look at this guide for file uploads in CKEditor as it's the basis for the next instructions:
If you haven't configured the file uploads then the Image dialog won't have the Upload tab and it will be like this image:



Now open your ckeditor.config.js and add a URL for the uploads:
config.filebrowserUploadUrl = '/simpleupload';
Save the changes and load a page with the editor and now it should have the upload tab (but obviously it won't work correctly)
Now it's the time to add our file uploader for Drupal, you can use this simpleuploads module for Drupal and take a look at its install instructions (don't focus on the comments about how to install CKEditor because you should already have it running, or adding the simpleuploads plugin because it's better to do it once the uploads are working)

Follow the instructions, if you have problems don't forget to review the doc about how to configure the file uploads for CKEditor in a generic way.

When you can upload images using the Upload tab in CKEditor you're ready to use the SimpleUploads plugin, it's the proper time to buy it because you know that you have the server ready.

Now extract the SimpleUploads files in the plugins folder for your CKEditor, this depends on how you have installed and configured CKEditor, it can be /sites/all/libraries/ckeditor-plugins or /sites/all/modules/ckeditor/plugins it depends on how you have installed CKEditor, but you should be able to find out in your admin pane. Check this guide about how to install plugins for CKEditor in Drupal, you can read also this guide for Drupal 7  if you're still having troubles to find info

At this point everything should be ready, just save the changes and test. If there are problems look at the browser console for any kind of error

Joomla

In the ckeditor folder there's a config.ini and config_src.ini , edit them ( I guess that maybe the changes are required on only one of them) and add a new block, like this:
[Video]
pluginName = Video
image = video/images/icon.png
title = Html5 Video
Hopefully this shold be enough and now you should be able to handle the plugin from the Drupal administration.

As you can see these steps are quite rough and I might be wrong about some of them but I don't use those CMSs and I'm writing this down only to have something to refer to when someone asks how to install a plugin there.
If you have any suggestions (I'm quite sure that this should be explained quite better), then please add a comment, send me a mail, whatever and I'll be glad to improve the post.

2012/09/09

Adjusting a CKEditor plugin to be compatible with v3 and v4

Recently CKSource announced the first beta of the new CKEditor 4, and along the improvements, it also brings some changes of the API. You can read about those changes in the included API-CHANGES.md file (open it with any text editor, I don't know if there's an easier way to read it correctly)

I'm gonna record here the changes that I have to go through to update my plugins when I touch them (although I'm not gonna try to do full testing until it goes out of beta).

Translations

The first breaking change is that CKEDITOR.plugins.setLang has changed, so now when you pass the object with the translations it must not include the "parent" object, as the doc says:

So, in v3 we had:

    CKEDITOR.plugins.setLang( 'myplugin', 'en',
    {
        myplugin :
        {
            title : 'My Plugin'
        }
    });
In v4 it should be changed to:
    CKEDITOR.plugins.setLang( 'myplugin', 'en',
    {
        title : 'My Plugin'
    });

That's good if you want to release a plugin only for v4 or you plan to ignore it, but if you want to be ready to upgrade and try to make your code compatible with both v3 and v4 you now have a problem because the name of the function hasn't changed but the expected parameters have done so.

So my solution is to create a new helper function and call this one instead of CKEDITOR.plugins.setLang:

CKEDITOR.addPluginLang = function( plugin, lang, obj )
{
    // v3 using feature detection
    if (CKEDITOR.skins)
    {
        var newObj = {};
        newObj[ plugin ] = obj;
        obj = newObj;
    }
    CKEDITOR.plugins.setLang( plugin, lang, obj );
}

This way, we use the new format for the obj parameter, but if the function detects that it's running in v3 it adds the plugin name as the root of all the strings

CKEDITOR.addPluginLang( 'myplugin', 'en',
{
        title : 'My Plugin'
});

Spacer image

Another change is that they decided that leaving the images/spacer.gif file there was polluting the global scope, so now you just have to copy that image in every plugin to be sure that it's included in the install and then adjust the paths in your code to use this copy of the image. It's not a big deal, but certainly to me it doesn't seem a big problem to leave that simple image in a common place so it can be easily reused.

Adding CSS

The doc explain this about this change:

The "additional CSS" feature provided by `CKEDITOR.editor::addCss` is now moved
to a global `CKEDITOR.addCss`, with specified style rules applies **document wide**.

Thus the proper way for a plugin to style it's editable content is to call `CKEDITOR.addCss`
inside of the plugin's `onLoad` function, rather than it's `init` function in v3.

So in order to make your code work in both versions you have to use something like this:

...
    getPlaceholderCss : function()
    {
        return 'img.cke_video' +
                '{' +
                    'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/placeholder.png' ) + ');' +
                    'background-position: center center;' +
                    'background-repeat: no-repeat;' +
                    'background-color:gray;'+
                    'border: 1px solid #a9a9a9;' +
                    'width: 80px;' +
                    'height: 80px;' +
                '}';
    },

    onLoad : function()
    {
        // v4
        if (CKEDITOR.addCss)
            CKEDITOR.addCss( this.getPlaceholderCss() );
    },

    init : function( editor )
    {
....
        // v3
        if (editor.addCss)
            editor.addCss( this.getPlaceholderCss() );
...

 

 

So this is all for the moment. I'll keep editing this post in the future as I upgrade more code.