2011/09/03

Toolbar buttons in Writearea

Since version 1.1 it's possible to configure which buttons do you want to use in the toolbar of Writearea. There are in fact two toolbars and you can switch between them with a custom button.

The way to define the buttons is to use the preferences pane of Writearea and put the array of buttons in the corresponding input fields. Note that to try to help a little, you don't need to put the outer [ and ], just the groups separated by commas and with a '/' if you want to start a new row.

These are the default values for each toolbar:

Full Toolbar:
['Save'], ['SaveFile','LoadFile'], ['Source'],['Cut','Copy','Paste','PasteText','PasteFromWord'],['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],['ShowBlocks','Maximize'],['Image','Flash','Table','HorizontalRule','SpecialChar','Iframe'],['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],['BidiLtr', 'BidiRtl' ],'/',['Styles','Format','Font','FontSize'],['Bold','Italic','Underline','Strike'],['TextColor','BGColor'],['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv','Code'],['Link','Unlink','Anchor'],['SwitchToolbar']

BasicToolbar:
['Undo','Redo'], ['Bold', 'Italic', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink'],['SwitchToolbar']

Most of the commands are the ones available on the default CKEditor install, I don't know if there's any listing of the meaning of all of them, the best thing that I can think of is the user's guide, but it doesn't clearly link the button names with its action.

But beyond those common buttons, there are a few ones with special meaning here:

Custom buttons

'Save': It's available only while in the dialog popup, it will save the content of the editor to the original element. When the editor is integrated into the page you should use the existing save button provided by the page, that way there won't be any problem due to extra event handlers or differences between Save draft, Publish and Preview buttons of the page.

'SaveFile', 'LoadFile': These two options allows you to save/load the content of the editor to a file in your computer, just in case the page doesn't have any auto-save feature or you want to use something more than once.

'SwitchToolbar': These button allows you to switch between the basic and the full toolbar. I would suggest you to use the basic toolbar by default and only switch to full toolbar when there's something extra that you need at that moment. And of course, adjust each toolbar so the basic includes the commands that you usually need and the full toolbar doesn't includes buttons that you know you'll never use.

'Code': it's the SyntaxHighlight plugin available here. I made some little adjustments, but someday I might have to perform some bigger fixes to improve it and make it easier to use.


 

2011/08/22

ServerPreview plugin for CKEditor

Some years ago I created a plugin for FCKeditor to easily provide a preview of the contents that are being edited as they will look in the final site. That's specially important when you're using special markup in the editor that it's being replaced at the server by a widget or just some plain data.

The plugin is quite simple as the idea itself is simple: Get the current contents, and instead of opening a window with that HTML, post it to a custom page at the server and that page will be the one that can provide the proper context and show the HTML as  it will be rendered in the final page.

This weekend I was tasked by Flatbooster GmbH to upgrade it so it can be used with CKEditor, and also perform some additions like controlling the size of the preview window.

The usage is quite basic, you just have to add it to your extraPlugins, specify the serverPreview_Url with your server script and use the posted "htmlData" variable. You can read the install.html to learn about other little options.

The plugin replaces the normal 'Preview' button, so there's no need to do anything to your toolbar.

The plugin can be downloaded here: Server Preview plugin for CKEditor 1.4.

Update 15/10/2011

Version 1.4, allow to use other CKEditor instances in the serverPreview_AdditionalFields setting.

 

 

2011/08/21

Is your clock adjusted correctly?

FoxToPhone now uses OAuth

In July I changed the authentication routines in FoxToPhone to start using OAuth like the latest version of ChromeToPhone. Using OAuth in a Firefox extension was a little harder at the start because I couldn't find something easy to use like the snippet that it's available for Chrome extensions.

Finally I took that code and adapted it to be able to use it the way that I wanted, without the need of a "background page", and reusing most of the code to avoid introducing any unexpected error.

This weekend this version 1.2 of FoxToPhone has been approved and now it's being updated as Firefoxes check for updates of the extensions. And despite all our hopes on the beta testers it's clear that not everything is OK.

Some people have been experiencing login problems with ChromeToPhone getting a hardly useful "redirecting..." message, and it's not clear what's going on, so it should be expected that some people would get also strange errors in Firefox with the new authentication. We fixed one or two such issues during beta testing, and today I've found another reason.

Your clock settings

Other people have already commented about it in that ticket, and I didn't look at it, but today one user reported login issues and after a little testing I found that while starting the authentication, one request is done that includes the current time, and in this case the request showed that it was one hour ahead of the current time. And the Google server replied with an status 400 meaning that the request was wrong.

So the user just moved his clock one hour back and then he was able to login and start sending the requests. Great!, we're moving ahead.

So if you get a response status 400, then you should check the settings on your control panel about the time zone and daytime savings are correct. Even if you see that the clock matches the one in your wrist, the computer also has additional information like the zone/country where you are, so when it tries to convert that local time to a global timestamp it will generate the wrong data if some of your info is wrong.

Testing time

This is a little script that tries to request the current time to the Yahoo servers and then checks it with your local time, if you see an error message then you should review the time settings in your computer

 

Hey Google, can you improve that error page?

Certainly returning "400 (Bad Request)" when the problem is the timestamp seems a little rude. It's clear that it's possible to check that the parameter is out of the allowed bounds, so in order to be helpful the error message should give a clearer hint that the problem is just that parameter. No real attacker is gonna try to send a request with that parameter wrong, it's just too easy to do it right, so the only people that would pass wrong data there are those users that don't realize that there's a problem with their clock settings.

Just as I've been able to mock a little script that performs a simple test, I guess that you should be able to provide at the very least the same check in a dedicated page and working a little further it should be able to guess more exactly if the problem is the time zone, the DTS or just the clock itself, something that shows the user the correct screenshots to check their settings etc...

 

2011/08/15

Location aware password policy

This morning I waked up and I was thinking about the password on my phone. I've always found it annoying having to retype it every now and them, specially if I'm at a place like my home where no one else can grab it.

So I thought that the device should be smarter, and I think that currently it should be possible to bring a little intelligence to these "smartphones". When I'm at a place that I have to configured to be trusted, then once I unlock the phone it should remain unlocked as long as it remains there or I don't explicitly lock it.

One easy way to achieve this would be to enhance the wifi manager, whenever I connect to a protected wifi with a password one new option is available: "this is a trusted site", by checking it the phone (or any similar mobile device) will remain unlocked and it's also possible to specify if the unlock should last some minutes (5 or 10, like when you are doing something with 2 devices, leave one apart and when you pick it up again it's locked so you waste time unlocking it), one hour or remain unlocked as long as you're connected.

That simple change could help lots of times, if we can use the devices at home without the need to retype the password (or whatever lock mechanism you've chosen), then we would be slightly happier and we could use slightly harder passwords for the moments when we're out of home.

Additional refinements could defined as an option to specify a coverage zone: instead of home, you're at work in your office, so you want the device to remain unlocked while you're there, but if you move out of the office then it should go back to the normal behavior.

I think that many people might not be using currently any password just to avoid the hassle of having to unlock his device every now and then, but if a system like the proposed in this post would be available then I would bet that they would be much happier to know that they have a secure device when they're walking down the streets while keeping the simplicity of an always available device at home without the need to retype the password at every moment.

 

2011/08/13

Upcoming changes for Write Area

It has been a long time, but these days I'm going to try to push a new stable release of Write Area. It will be mostly an upgrade to the current CKEditor 3.6.1, but at the same time I'm gonna try to finish some code that it's available in the betas and provide a simplified version.

The main change will be the removal of the option to select whether to open the editor in a bottom pane or in a dialog. My plan is to finish the behavior of the new "integrated" mode, so that whenever you select to use Write Area with a normal textarea then it will be replaced by a CKEditor instance integrated in the same page. This is similar to what the "bottom pane" provides, but with the advantage of being able to create more than one instance, and the rest of the scripts of the page can get direct access to the contents as if nothing had happened.

If you try to use instead an existing editor that isn't too compatible with the current Firefox or it's missing features, then the editor will be launched in dialog mode. The plan is to do this automatically without the need to select a preference.

Why?

First: Simplify options.
More options means more testing, harder for the user as he has to think about what's better. I can't claim that I know better than him what's better for him, but I know what's more job for me.

Second: Try to avoid future problems due to changes in Firefox.
The bottom pane is a "XUL overlay", that means that it's somehow quite integrated with Firefox, and in the future the plan is to try to move as much extensions as possible to the Addons-SDK. That means that such integrations might be harder or just impossible. If I start removing these blocks I can try to test if it's possible to port the extension to this new world. Anyway that goal is quite far away as I've stated previously that I won't start using the Addons SDK as long as they require to install Python or any other third party libreary/compiler/whatever.

Third: Other browsers.
By using a simpler approach it's possible to create a Write Area version for Chrome, and although I don't use it I understand that other people do, so if there are just a few differences then I can provide a port of the extension. It won't be as feature rich as the Firefox version, but at least is something that people can use.

Conclusion

If you have a strong reason to believe that I'm making a mistake the I would like to hear your concerns. Otherwise I'll go ahead and release the update when it's ready

2011/07/31

Third version for seamless replacement of textareas

Sometime ago I wrote a script that allows to use CKEditor, and at the same time keep using older scripts existing on the page that relied on reading the textarea.value (or even writing it), without having to modify them to use the CKEditor API.

The initial version worked with Firefox and Internet Explorer 8, and shortly after I added some adjustments so that Opera was also supported.

Recently a comment in that second post stated that the script gave errors in Chrome, although it tries to detect if the API that I was using is supported, but of course, webkit guys decided to implement the API but not make it available for native properties. Their statement is that treating native properties as overridable would have a negative effect on performance, and as we all know it's much more important to have a fast browser than a browser that allows the developers to do new things; unless you're in their team then you can write a new API for whatever you need and everyone else should use this API because it will change the world, you'll no longer have to use Flash because now you have this API to overcome other problems that we didn't want to fix. Besides the bug tickets commented previously, here's another one: bug 36423

Ok, enough ranting.

As I said, I've worked to find out the problems and the funny fact about this new version is that it works in Chrome but it still fails in Safari 5.1. So you can use it in your site if can restrict the browser used by your users to IE8+, Firefox 3.5+ , Opera 10+, and Chrome 12+ (I don't really know the oldest version of Firefox, Opera and Chrome where this will work, but I wouldn't expect anyone to use old versions of those browsers)


// Modify the default methods in CKEDITOR.dom.element to use .nativeValue if it's available
CKEDITOR.dom.element.prototype.getValue = function()
{
    if (typeof(this.$.nativeValue) == "undefined")
        return this.$.value;

    return this.$.nativeValue;
}

CKEDITOR.dom.element.prototype.setValue = function( value )
{
    if (typeof(this.$.nativeValue) == "undefined")
        this.$.value = value;
    else
        this.$.nativeValue = value;

    return this;
}

// Hook each textarea with its editor
CKEDITOR.on('instanceCreated', function(e) {
 if (e.editor.element.getName()=="textarea")
 {
  var node = e.editor.element.$;

  // If the .nativeValue hasn't been set for the textarea try to do it now
  if (typeof node.nativeValue == "undefined")
  {
   // for Opera & Firefox
   if (!DefineNativeValue(node))
   {
    // IE8 & Webkit
    if (!DefineValueProperty(node))
    {
     alert("Your browser is buggy. You should upgrade to something newer")
     return;
    }
   }
  }

  node.editor = e.editor;

  // House keeping.
  e.editor.on('destroy', function(e) {
   if (node.editor)
    delete node.editor;
  });
 }
});

// This function alters the behavior of the .value property to work with CKEditor
// It also provides a new property .nativeValue that reflects the original .value
// It can be used with HTMLTextAreaElement.prototype for Firefox, but Opera needs to call it on a textarea instance
function DefineNativeValue(node)
{
 if (!node.__lookupGetter__)
  return false;

    var originalGetter = node.__lookupGetter__("value");
    var originalSetter = node.__lookupSetter__("value");
    if (originalGetter && originalSetter)
    {
        node.__defineGetter__("value", function() {
                // if there's an editor, return its value
                if (this.editor)
                    return this.editor.getData();
                // else return the native value
                return originalGetter.call(this);
                }
            );
        node.__defineSetter__("value", function(data) {
                // If there's an editor, set its value
                if (this.editor) this.editor.setData(data);
                // always set the native value
                originalSetter.call(this, data)
                }
            );

        node.__defineGetter__("nativeValue", function() {
                return originalGetter.call(this);
                }
            );
        node.__defineSetter__("nativeValue", function(data) {
                originalSetter.call(this, data)
                }
            );
        return true
    }
    return false;
}

function DefineValueProperty(node)
{
    var originalValuepropDesc = Object.getOwnPropertyDescriptor(node, "value");

 if (!originalValuepropDesc)
  return false;

 // Safari doesn't allow to overwrite the property (but Chrome does)
 if (!originalValuepropDesc.configurable)
  return false;

    Object.defineProperty(node, "nativeValue",
            {
                get: function() {
                    return ( originalValuepropDesc.get ? originalValuepropDesc.get.call(this) : originalValuepropDesc.value );
                },
                set: function(data) {
                    originalValuepropDesc.set ? originalValuepropDesc.set.call(this, data) : originalValuepropDesc.value = data;
                }
   }
        );

    Object.defineProperty(node, "value",
            {
                get: function() {
                    // if there's an editor, return its value
                    if (this.editor)
                        return this.editor.getData();
                    // else return the native value
                    return this.nativeValue;
                },
                set: function(data) {
                    // If there's an editor, set its value
                    if (this.editor) this.editor.setData(data);
                    // always set the native value
                    this.nativeValue = data;
                }
            }
        );
 return true;
}

// Detection, not really needed, but it can help troubleshoting.
if (Object.defineProperty)
{
    // IE 8 and updated webkits
 // Detect Safari
 if (document.head)
 {
  var test = Object.getOwnPropertyDescriptor(document.head, "innerHTML");
  // IE9
  if (!test)
  {
   if (!DefineValueProperty(HTMLTextAreaElement.prototype))
    alert("Unable to define property override on the prototype");
  }
  else
   if (!test.configurable)
    alert("Safari doesn't allow to overwrite native properties");
 }
}
    else if (document.__defineGetter__)
{
    // FF 3.5 and Opera 10
 // We try to get the innerHTML getter for the body, if it works then getting the value for each textarea will work
 // Detect old webkits
 if (!document.body.__lookupGetter__("innerHTML"))
  alert("Old webkits don't allow to read the originalGetter and Setter for the textarea value");
}
    else
{
    // detect IE8 in compatibility mode...
    if (document.documentMode)
        alert("The page is running in Compatibility Mode (" + document.documentMode + "). Fix that")
    else
        alert("Your version of IE is too old");
}

 

2011/07/13

Too many permissions for simple apps

Yesterday I was badly surprised when Reto Meier added a post pointing to an Android game activated by the voice; that sounded fun (although it's clear that it can't be played in too many places), but I wanted to check it out.

The bad surprise came when the market showed me the required permissions for the App:

  • Record sound (obviously, it needs as that's the differential point)
  • Full internet access (ok, some ads as it's a free app)
  • Read and write the contents of the SD card. This isn't too nice, but some apps and games have extra downloads to keep the app itself smaller and they download the data to the SD. We have to accept it until Android provides a better option (check below for my proposal)
  • Read identity and state of my phone. No, this isn't OK. An app doesn't really require to know anything about my phone. Usually this is enough for me to not install an app.
  • Read SMS. What??? Read my SMS? for a game?, are you joking?. So this app requires full internet access, read all the content of my SD card as well as my identity and my SMS? They can ask for my bank account at the same time.
  • Send SMS. Ok, this is enough. What's the difference between this game and those trojans that have been found claiming to be legit Android Apps? How can a user be able to find out that the developer is really a good person and it's requiring those permissions really based on real requirements instead of being used to send premium SMSs and hide them as those trojans do?

Whenever such application with those huge permissions is mentioned by someone that it's otherwise respected, we can expect that people will download it, and by doing it people will be used to accept that apps might require extra permissions. This will lead to "permission blindness" just like people is now blind to the Ads that appear in some webs, people will get used very soon to the fact that any app might want to read your SMS, your contacts and anything else.

So this will destroy any effectivenes of the permissions system, the typical statement "be careful about what you install" and "it's easy to spot a trojan due to its permissions" will be void. Sum it with the lack of review system in the Android Market and you get a big problem just waiting to happen.

According to some comments in that post, the developers answered in Twitter claiming that the SMS is to upgrade the app to a paid version. So... what's wrong with the Android Market? why don't you offer the full version there instead of using SMSs? Does premium SMS work across countries? how much it's gonna cost some random user in Spain like me a premium SMS sent to the USA? If it's just an internal switch in the app, why isn't this done using the existing internet connection? People pay it in your site and then the app is upgraded to full version. Hell, it can even be done showing the user an unlock code and without internet on the phone app itself!

The requirement to read/write the SD card could be fixed if Android had a better system for apps to store their own data:
Currently those apps create random folders anywhere on the SD card and they remain there after the app has been removed. If instead of getting full access to the SD card they had access to just a custom unique folder, then this could be much better:

  1. Any app can read/write to his own folder in the SD, ex. /Android/data/com.google.android.apps.maps/
  2. That folder is only accessed by that app (or other apps like file managers that really request full SD access), there's no need to state it in the permission list
  3. When the app is removed, the uninstaller also cleans up that folder, so that the app has been really uninstalled and nothing remains. If the user wanted to keep the data he can do a backup of the folder before performing the removal.
  4. In summary: the app itself doesn't really need to know the location of that folder, it just knows that it can safely read and write there, and due to that safety it doesn't require an extra permission at install time. Better for the developer, better for the users.

The Android system really needs an improvement in the way that permissions are granted, the user shouldn't have to worry because an app is requesting weird permissions, also, the Android Market should be much more careful and force a review of any app that requires permissions like send SMS, or perform a combination of read SD and get internet access. When an app just requires internet to show ads it's OK, but if that app is also able to read all the data in your SD card (photos, Titanium backups, etc...) then it should be reviewed to provide a warranty that it's a good app and not something evil.

Enough of bad comments, do you want to know a nice game? (no, this post isn't sponsored and I'm not related to the developer)
Test Trap!, it ask for all the permissions that you can expect from a nice game: none, and it can keep you playing it for a while trying to beat yourself.