Recently there have been a number of requests for adding a CAPTCHA to the Sitefinity Forms widgets. Since the standard CAPTCHA controls that work with postback are not suitable for the Forms control, I am going to walk you through the process of implementing a client-side CAPTCHA control which can be used on Sitefinity Forms. I've stumbled on this blog post: 8 jQuery CAPTCHA Plugin with Tutorial, listing different jQuery CAPTCHA libraries. For this article I chose to use the first plugin(QapTcha), however the same principle applies for the rest of the plugins and you can use any of them. Now let's proceed to the implementation part.
Implementing the CAPTCHA widget
We are going to implement our custom widget as a script control, so we need to inherit from SimpleScriptView. This will allow us to use our control not only for Forms, but also for other places where we need CAPTCHA. The process of implementation is the same as the one for Book Widget part of the Siteifnity SDK, minus the implementation of a Silverligh control.
Implementing the server-side class
The only logic that our server side class will hold are just a few properties that are used by the QapTcha plugin to set up the UI. We need to expose those properties, set up the layout template path for the widget and refer the scripts on which this plugin depends. You can find the class implementation bellow:
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Web.UI;
using
System.Web.UI.HtmlControls;
using
Telerik.Sitefinity.Modules.Pages;
using
Telerik.Sitefinity.Web.UI;
namespace
Telerik.Sitefinity.Samples.Forms
{
class
FormQapTchaControl: SimpleScriptView
{
#region Properties
protected
override
string
LayoutTemplateName
{
get
{
return
null
; }
}
public
override
string
LayoutTemplatePath
{
get
{
return
this
.layoutTemplatePath;
}
set
{
this
.layoutTemplatePath = value;
}
}
[Category(
"QapTcha properites"
)]
public
bool
AutoRevert
{
get
{
return
this
.autoRevert;
}
set
{
this
.autoRevert = value;
}
}
[Category(
"QapTcha properites"
)]
public
bool
DisabledSubmit
{
get
{
return
this
.disabledSubmit;
}
set
{
this
.disabledSubmit = value;
}
}
[Category(
"QapTcha properites"
)]
public
string
TxtLock
{
get
{
return
this
.txtLock;
}
set
{
this
.txtLock = value;
}
}
[Category(
"QapTcha properites"
)]
public
string
TxtUnlock
{
get
{
return
this
.txtUnlock;
}
set
{
this
.txtUnlock = value;
}
}
#endregion
[Browsable(
false
)]
public
HtmlGenericControl QapTchaDiv
{
get
{
return
this
.Container.GetControl<HtmlGenericControl>(
"QaptCha"
,
true
);
}
}
#region Methods
protected
override
void
OnPreRender(EventArgs e)
{
base
.OnPreRender(e);
PageManager.ConfigureScriptManager(
this
.Page, ScriptRef.JQueryUI);
}
public
override
IEnumerable<System.Web.UI.ScriptDescriptor> GetScriptDescriptors()
{
var descriptors =
new
List<ScriptDescriptor>();
var descriptor =
new
ScriptControlDescriptor(
typeof
(FormQapTchaControl).FullName,
this
.ClientID);
//pass property values to the script component
descriptor.AddProperty(
"qapTchaDiv"
,
this
.QapTchaDiv.ClientID);
descriptor.AddProperty(
"autoRevert"
,
this
.AutoRevert);
descriptor.AddProperty(
"disabledSubmit"
,
this
.DisabledSubmit);
descriptor.AddProperty(
"txtLock"
,
this
.TxtLock);
descriptor.AddProperty(
"txtUnlock"
,
this
.TxtUnlock);
descriptors.Add(descriptor);
return
descriptors;
}
public
override
IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
{
var scripts =
new
List<ScriptReference>()
{
new
ScriptReference(FormQapTchaControl.componentScriptPath,
typeof
(FormQapTchaControl).Assembly.FullName),
new
ScriptReference(FormQapTchaControl.qapTchaScript,
typeof
(FormQapTchaControl).Assembly.FullName),
new
ScriptReference(FormQapTchaControl.jqueryUITouchScript,
typeof
(FormQapTchaControl).Assembly.FullName)
};
return
scripts;
}
protected
override
void
InitializeControls(GenericContainer container)
{
}
#endregion
#region Private fields
public
string
layoutTemplatePath =
"~/SfControls/Telerik.Sitefinity.Samples.Forms.Resources.Views.FormQapTchaControl.ascx"
;
private
bool
autoRevert =
true
;
private
bool
disabledSubmit =
true
;
private
string
txtLock =
"Locked : form can't be submited"
;
private
string
txtUnlock =
"Unlocked : form can be submited"
;
private
static
string
componentScriptPath =
"Telerik.Sitefinity.Samples.Forms.Resources.Scripts.FormQapTchaControl.js"
;
private
static
string
jqueryUITouchScript =
"Telerik.Sitefinity.Samples.Forms.Resources.Scripts.jquery.ui.touch.js"
;
private
static
string
qapTchaScript =
"Telerik.Sitefinity.Samples.Forms.Resources.Scripts.QapTcha.jquery.js"
;
#endregion
}
}
Implement the client-side component
The purpose of the client side component is to simply initialize our QapTcha plugin. We need to provide getter and setter methods for our properties, and pass them to the plugin:
Type.registerNamespace(
"Telerik.Sitefinity.Samples.Forms"
);
Telerik.Sitefinity.Samples.Forms.FormQapTchaControl =
function
(element) {
Telerik.Sitefinity.Samples.Forms.FormQapTchaControl.initializeBase(
this
, [element]);
this
._qapTchaDiv =
null
;
this
._autoRevert =
null
;
this
._disabledSubmit =
null
;
this
._txtLock =
null
;
this
._txtUnlock =
null
;
}
Telerik.Sitefinity.Samples.Forms.FormQapTchaControl.prototype = {
initialize:
function
() {
Telerik.Sitefinity.Samples.Forms.FormQapTchaControl.callBaseMethod(
this
,
'initialize'
);
//set QapTcha settings
$(
'#'
+
this
.get_qapTchaDiv()).QapTcha(
{ disabledSubmit:
this
.get_disabledSubmit(),
autoRevert:
this
.get_autoRevert(),
txtLock:
this
.get_txtLock(),
txtUnlock:
this
.set_txtUnlock()
});
},
dispose:
function
() {
Telerik.Sitefinity.Samples.Forms.FormQapTchaControl.callBaseMethod(
this
,
'dispose'
);
},
// properties
get_qapTchaDiv:
function
() {
return
this
._qapTchaDiv; },
set_qapTchaDiv:
function
(value) {
this
._qapTchaDiv = value; },
get_autoRevert:
function
() {
return
this
._autoRevert; },
set_autoRevert:
function
(value) {
this
._autoRevert = value; },
get_disabledSubmit:
function
() {
return
this
._disabledSubmit; },
set_disabledSubmit:
function
(value) {
this
._disabledSubmit = value; },
get_txtLock:
function
() {
return
this
._txtLock; },
set_txtLock:
function
(value) {
this
._txtLock = value; },
get_txtUnlock:
function
() {
return
this
._txtUnlock; },
set_txtUnlock:
function
(value) {
this
._txtUnlock = value; }
}
Telerik.Sitefinity.Samples.Forms.FormQapTchaControl.registerClass(
'Telerik.Sitefinity.Samples.Forms.FormQapTchaControl'
, Sys.UI.Control);
Implementing the control template
The control template is used to refer the style sheet that defines the look an feel of the QapTcha plugin and define a placeholder div for the slider:
<%@ Control Language="C#" AutoEventWireup="true" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" Assembly="Telerik.Sitefinity" %>
<
sf:ResourceLinks
id
=
"resourcesLinks1"
runat
=
"server"
UseEmbeddedThemes
=
"true"
>
<
sf:ResourceFile
Name
=
"Telerik.Sitefinity.Samples.Forms.Resources.CSS.QapTcha.jquery.css"
AssemblyInfo
=
"Telerik.Sitefinity.Samples.Forms.FormQapTchaControl, Telerik.Sitefinity.Samples.Forms"
Static
=
"true"
/>
</
sf:ResourceLinks
>
<
div
id
=
"QaptCha"
class
=
"QapTcha"
runat
=
"server"
></
div
>
Project overview
After you have implemented your client-side and server-side components, the control template, and have added the dependent scripts, styles and images for the QapTcha plugin the project should look similar to the on the bellow image:
The last step in terms of the project is to register the embedded resources (CSS, image and script files) with our assembly. To do so edit the AssemblyInfo class:
[assembly: WebResource(
"Telerik.Sitefinity.Samples.Forms.Resources.Scripts.FormQapTchaControl.js"
,
"application/x-javascript"
)]
[assembly: WebResource(
"Telerik.Sitefinity.Samples.Forms.Resources.Scripts.jquery.ui.touch.js"
,
"application/x-javascript"
)]
[assembly: WebResource(
"Telerik.Sitefinity.Samples.Forms.Resources.Scripts.QapTcha.jquery.js"
,
"application/x-javascript"
)]
[assembly: WebResource(
"Telerik.Sitefinity.Samples.Forms.Resources.Images.bg_QapTcha.png"
,
"image/png"
)]
[assembly: WebResource(
"Telerik.Sitefinity.Samples.Forms.Resources.Images.sprites.png"
,
"image/png"
)]
[assembly: WebResource(
"Telerik.Sitefinity.Samples.Forms.Resources.CSS.QapTcha.jquery.css"
,
"text/css"
, PerformSubstitution = true)]
You can now build the code library project and add it to the bin folder of your Sitefinity project.
Registering the QapTcha widget
To be able to use the widget we must do two things:
- Register our assembly with the Virtual Path Provider so that Sitefinity can resolve the widget template. To do so go to Administration -> Settings -> Advanced -> VirtualPathSettings -> Virtual paths and add a new virtual path for the control, then restart the website. Sample bellow:
- Register the custom control in the Forms toolbox. To so go to Administration -> Settings -> Advanced -> Toolboxes -> FormControls -> Sections -> Common -> Tools and register the custom control.
Download sample project
You can download the project for the custom control from this location: Telerik.Sitefinity.Samples.Forms. Make sure that you resolve the references to Sitefinity and OpenAccess assemblies.