Widget feature

WARNING

I moved this feature under the Editor entry because what I talk about here are the widgets of the inline editor offered as the editor plugin. For this reason I marked this page as Details only.

Some of the content of this page needs to be duplicated somewhere else and then this page removed. There are many important points such as the security entry at the bottom.

Widgets versus HTML Code

We want a way to make it really easy to create the HTML output.

At first I was thinking about forms, however, to make it really easy for the entire output we want to support widgets. This means we can create output only widgets (i.e. a table of data, a blog feed, etc.) and we can create forms (i.e. user can enter data and send it to a server.)

So... here and there this page may still talk about Forms instead of Widgets.

XML supports a language called XSLT which is used to transform one type of tags into another. For example, we can easily transform a <textfield> tag with a set of attributes and maybe some default data into a set of HTML tags such as <label>, <input>, etc. as may be required. At this point we're thinking to use CppCMS (TBD, I think that CppCMS is not going to give us Widgets...) which generates the forms and parses the POST replies (TBD). However, there is an advanced server on SourceForge (name required) that has the ability to create Widgets1. That sounds like a much better plan than using fields. A widget includes many functions and is most often not just one <input> tag in a form.

The forms include fields that users can fill and a button to push to send the results to the server.

Server or JavaScript

Note that a form is generally created on the server and pushed to the website. However, we may want to think about this carefully since some users may want to dynamically create a form on the client side. This can happy in two main ways: (1) the JavaScript code generates the entire form; (2) the JavaScript code sends an AJAX request and the server returns the form. Solution (1) should be faster (assuming the user has a good computer) but it requires all the widgets to be available in a JavaScript file (so loading that could be taking forever!) Solution (2) is generally slower because it needs to access the network and connections can be very slow.

It seems to me that if we want to benefit from the XSLT processing, we cannot really make use of JavaScript, although many companies do things like that (i.e. Facebook used <fb:like/> for their button.) It looks as if a JavaScript programmer wants to use a given widget, we can load it at that time, instead of trying to load everything at once. (i.e. if we detect a widget such as <snap:date> then we could send an AJAX request to load the JavaScript that can handle the date widget; would that be faster, in the long run, than requesting the server to send us a ready made date widget already in HTML? Assuming we can use an IFRAME to load the widget script in the browser cache, then that would be a lot faster the 2nd time the date widget is requested since it's already in the browser's cache!)

Display

Forms need to be versatile enough to allow for:

  • Placement of the label on the line before;
  • Placement of the label on the same line (left or right);
  • Placement of the label on the line below;
  • Placement of different items in a table so we can format the form on a screen instead of an up/down scheme like in many CMS systems; this should not require someone to know how to write CSS code, instead it uses a table with rows and columns and you can just move things around;
  • Placement of a description for a field; this is like an inline help (always visible);
  • Placement of a help tooltip for a field (this can be a button, or as I have done before an help area that changes when you enter a field);
  • Placement of an error box when doing AJAX validation (the error box is like a red rectangle with an arrow pointing to the input widget that has invalid content);

Button Handling

On all forms, all the buttons must be hidden and replaced by a "please wait..." type of a message when clicked so end users cannot submit the data more than once. This is done in JavaScript. Possibly, darken the screen (or lighten when the background is dark) as we're at it.

This can be a problem if we don't also offer an escape (i.e. a link/button to "cancel") since the AJAX code could fail.

In some cases we may just want to hide the whole form (i.e. a form used as a survey and we want the user to answer just once...)

Double Confirmation

As a special button capability we want to support a double confirmation. So if someone asks to delete a page, he can click on the Delete button and that opens a pop-up that requires the user to confirm the feat: Do you really want to delete that content?

Also for pages the damage is minimal since they only get hidden (the Hidden state or category, opposed to Published, In Moderation, etc.) it would be a pain to allow easy deletion.

This should be applied to any button that does an action that's a bit harder than average to fix.

Functionality

As much as possible, what can be shown to the end users using a small JavaScript piece of code should be shown. Using systems like jQuery makes this a very easy task.

An example of functionality is how the title of a page is used to generate the URL for that page. As the user types the page title, we want to show the user how the URL will look like once published (i.e. a la WordPress, but without the bugs found in WordPress...)

Types of Widgets

We want to support the following types:

  • Input Widgets

A Normal Widget shows up on the user screen and is expected to include all the normal functionality of a widget. This is certainly the most common in a standard form.

This can include complex widgets such a CAPTCHA or a Date Picker. It can also be a set of widgets (i.e. to enter a complete address.)

Widgets have many properties such as a description shown in the help area of the widget (maybe under the widget or as you enter the widget, it is displayed in the Help Box of the form) and when the widget allows free form data entry it could also include a regular expression used to check that the data entered is valid (i.e. a widget that only accepts digits could use /[0-9]*/ or /[0-9]+/.)

Note that in some forms data in one field depends on data in another field. For example, in an address widget, you could have one widget for the name of the country and depending on that selection, the state widget would display a specific list of states. This may require some AJAX since the list of states should be filled after a the country is selected. Other types of inter-widget specifications can require a test such as a limitation in the number of characters (say 140) between a select URL and a message that will use that URL. (i.e. imagine that someone is writing a twit about a page, we get a shorten URL for that page and know it's 20 characters, now the user can write a message of 119 characters maximum - URL is 20 + 1 space + 119 = 140.)

Finally, there are times when a form morphs as the user makes his selection. For example, if you have a choice between accepting comments or not on a page, when not accepting comments, that's it. When accepting comments, you may also let the user choose whether the comments should be displayed top to bottom or bottom to top or maybe you want to offer a limit on how long the users have to comment on a page (i.e. after 30 days, close the comments.)

  • Display Widgets

Display Widgets are used to display data on the screen. Display widgets do not allow users to enter data, it is only to offer an easy way to display the data.

For example, we want a way to display tables (rows and columns of data.) This is very much in link with layouts that define the location where data shall be displayed (i.e. attach table A to box X, text message B to box Y, and image C to box Z,) although the layouts themselves only know about ready to be displayed HTML data to fit in their different boxes.

See: Layout feature [core]

  • Hidden Widgets

A Hidden Widget includes public data, which means the data is sent to the client's browser that is expected to send it back with the exact same value.

Hidden widgets are used for:

  1. A session identifier that must match on return (see security section below)
  2. A value used by a complex widget and that needs to be sent back to us
  • Data Widgets

A Data Widget is something quite a bit peculiar. Data Widgets hold data on the server side, but do not send that data over to the client's browser. In other words, this can be private data.

It is used, for example, to hold the session identifier that the user is expected to post back to us when he's done filling out the form.

When getting a form ready, you can add data widgets that are saved in the session cache for that form. When the form is sent back, that data is available to the validation functions and the submit function which saves the data entered by the end user as required by that plug-in.

The "Normal Widgets" is a group of widgets including all the visible widgets (i.e. simple text fields, number fields, dropdowns, lists, etc.) The other two types are widgets by themselves.

User Forms

The form capability should give users a way to create forms. This means a page can be composed of form elements and a submit button. All the form elements will behave just the same in a user defined page as it would in a plugin defined page, only submissions are saved by the user forms plugin for later review by administrators.

This capability gives the end users a way to create specialized contact forms, surveys (a la Drupal webform,) questions (a la Facebook,) etc.

The form can be saved in a submission list and it can be sent to a list of email addresses. The email address can be determine dynamically (i.e. if submitted on a user's page, then the destination would be that user's email address.)

When the form is a plugin form, then the POST goes to the plugin instead.

JavaScript Validation

We want each widgets to be capable of validating itself before the user POSTs the form back to the server. A JavaScript validation saves a lot of transfer bandwidth, allows for very fast feedback, allows you to show the exact field that is not valid (instead of an error message at the top of the screen.)

This must be built in the widgets. Default widgets should be defined (such as a widget to only enter a number, an US zip code, a UK postal code, etc.)

Multilingual Widgets

To allow translations, we want to offer widgets that display one or more languages and give one input widget to write the corresponding translation.

For a translator who can write multiple language, we can also mark several of the entries as input widgets instead of all but one. This way, a person who can read English and translate to Spanish and Portuguese would be shown:

  • The content in English (display only)
  • The content in Spanish (text input)
  • The content in Portuguese (text input)

Also we want to clearly detect whether a change was made in a language or another to properly propagate the need for further translation. Not only that, we want a little more than just one "Save" (publish) button. We do want to be able to say whether the translation(s) are considered finished or whether it still needs work.

Auto-save feature

Computers that allow JavaScript to run must have an auto-save feature. Although not all forms need to automatically be saved, plus, for anonymous users, we may just save the data in a private cookie instead of the server. When the anonymous user returns using the same browser, that data can be used to fill out the form.

Methods of storage exist in HTML 5.x and Flash, however, with older versions the only way really is to send the data to the server (i.e. cookies cannot be used to save data only locally, it will be sent to the server in order to become available in JavaScript!)

Since IE8, Safari 4, and pretty old FireFox, we can make use of the DOM Storage facility as defined in Mozilla (for older versions of IE, we could make use of the userData object.) The Mozilla documentation actually includes a sample code with a fallback implementation so older browsers can revert to using cookies for that data. However, remember that Cookies are quite limited (about 64Kb per cookie, and a cookie lasts only for a small amount of time and may get deleted by the browsers to get the space for another cookie in another website.)

Security Considerations

Form Session

We want to have a way to tell whether we created the form or whether the user built a packet and sent a POST without us first creating said form (i.e. spammers do that big time.)

This is done by including a hidden field in the form that includes some random number. If that number is not found in our form sessions (or it got invalidated / out of date,) then the form either timed out or was sent by a spammer.

Considering caches, we want to make sure that the same session number can be reused multiple times. With AJAX we could get an extra authorization code too.

To Be Honest

Some forms will be posted just once (i.e. in most cases an edit form) those should prevent all other users from editing the same thing. Such a form offers ONE session. Once used up, that's gone. Other forms, such as the search form or a comment form, are for multi-uses. This means the same session could be reused multiple times since having multiple users using the same form is not a non-sense. (Of course, the distinction is really necessary only if you're caching forms since otherwise it doesn't really make sense: if always fully dynamic, you'd definitively get a session for each instance.)

See: AJAX feature (Inline Editing) [core]

Safe Data

All the data in the form must be checked for security reasons (i.e. SQL command, PHP code, etc.) This means removing any data that does not satisfy a certain validity (i.e. this entry much be a number, only digits are accepted!)

Spam

The Spam module is used to check out data that is posted on the site. That can include names, URLs, and a CAPTCHA widget.

Also we want to add random fields that get hidden with CSS or JavaScript and need to be sent back to us with no data (empty) or the POST is refused. Such a field can be generated in a random manner (i.e. random name.)

See: Anti-Spam feature

SSL Encryption

We certainly want to offer a way for all forms to appear on secure pages (which is a problem with a log in block and / or search feature.)

We may also want to offer a way to send all forms over HTTPS, even if the user is currently on HTTP. This is 100% secure, although most people have no clue. I think that as long as we offer the feature, we're good.

See: Secure Pages feature

Auto-clear Forms

Because a form may include some sensitive data, we need an auto-clear feature for forms.

This could be defined on a per widget basis and can ripple to the entire form (i.e. if one or more field is marked as an auto-clear, so is the form.)

Examples:

  1. The password widget should get cleared if data is entered and not submitted for too long;
  2. The credit card widget and similar input widgets.

 

  • 1. For example, a text field can offer the capability to have a drop down list, the widget would just take the drop-down list data or a callback and make everything else automatic. A complex widget asking users their address would include multiple inputs: a street address, the province or state, the country, a postal code, etc. the widget would manage all those fields as one object.

Snap! Websites
An Open Source CMS System in C++

Contact Us Directly