Created
November 14, 2017 11:47
-
-
Save Abdillah/1437fd3dfc0c3ee928a8fc049306188f to your computer and use it in GitHub Desktop.
Captcha slider for human
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <link href="css/slide-to-captcha.css" rel="stylesheet"> | |
| <script src="js/modernizr.custom.20910.js"></script> | |
| <script src="js/jquery.js"></script> | |
| <script src="js/slide-to-captcha.js" type="text/javascript"></script> | |
| <script> | |
| var captcha, captcha1, captcha2, captcha3; | |
| $(document).ready(function () { | |
| // One | |
| captcha = new SliderCaptcha('.captcha', {}); | |
| // Still not enough? | |
| captcha1 = new SliderCaptcha('.captcha1', { handle: '.handle1' }); | |
| captcha2 = new SliderCaptcha('.captcha2', { handle: '.handle2' }); | |
| captcha3 = new SliderCaptcha('.captcha3', { handle: '.handle3' }); | |
| }) | |
| </script> | |
| </head> | |
| <body> | |
| <form> | |
| <div class="captcha"> | |
| <input type="hidden" name="captcha" /> | |
| <div class="handle"></div> | |
| </div> | |
| <div class="captcha1"> | |
| <div class="handle1"></div> | |
| </div> | |
| <div class="captcha2"> | |
| <div class="handle2"></div> | |
| </div> | |
| <div class="captcha3"> | |
| <div class="handle3"></div> | |
| </div> | |
| <input type="submit" value="Submit This"></input> | |
| </form> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| *, *:before, *:after { | |
| box-sizing: border-box; | |
| } | |
| .slide-to-captcha { | |
| background-color: #ddd; | |
| background-color: #dddddd; | |
| -webkit-box-shadow: inset 0 0 7px rgba(0,0,0,.2), 1px 1px 7px rgba(0,0,0,.4); | |
| -moz-box-shadow: inset 0 0 7px rgba(0,0,0,.2), 1px 1px 7px rgba(0,0,0,.4); | |
| box-shadow: inset 0 0 7px rgba(0,0,0,.2), 1px 1px 7px rgba(0,0,0,.4); | |
| border: 2px solid #343434; | |
| color: #343434; | |
| font-size: 0.5em; | |
| height: 40px; | |
| overflow: hidden; | |
| padding: 5px 5px; | |
| position: relative; | |
| text-align: center; | |
| -webkit-transition: background-color 0.3s; | |
| -moz-transition: background-color 0.3s; | |
| -ms-transition: background-color 0.3s; | |
| -o-transition: background-color 0.3s; | |
| transition: background-color 0.3s; | |
| width: 200px; | |
| } | |
| .slide-to-captcha:after { | |
| color: #010101; | |
| content: attr(data-content); | |
| font-weight: bold; | |
| height: 100%; | |
| line-height: 34px; | |
| margin-left: 10px; | |
| display: block; | |
| font-size: 1.3em; | |
| position: absolute; | |
| text-align: center; | |
| top: 0; | |
| width: 100%; | |
| z-index: 1; | |
| } | |
| .slide-to-captcha-handle { | |
| background: #343434; | |
| /* border: 2px solid #aaa; */ | |
| height: 100%; | |
| position: relative; | |
| transition: 100ms; | |
| width: 30px; | |
| z-index: 2; | |
| } | |
| .slide-to-captcha-handle.active-handle { | |
| background: #b43b3b; | |
| } | |
| .slide-to-captcha-handle:after { | |
| left: 22px; | |
| } | |
| .slide-to-captcha.valid { | |
| background-color: #0a0; | |
| color: #0a0; | |
| } | |
| .slide-to-captcha.valid:after { | |
| color: #f0f0f0; | |
| content: attr(data-content); | |
| display: block; | |
| position: absolute; | |
| text-align: center; | |
| top: 0; | |
| z-index: 1; | |
| } | |
| .slide-to-captcha.valid .slide-to-captcha-handle { | |
| background-color: transparent; | |
| transform: translate(10px) rotate(45deg); | |
| height: 80%; | |
| border: unset; | |
| border-bottom: 3px solid #fff; | |
| border-right: 3px solid #fff; | |
| width: 10px; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Require jQuery | |
| */ | |
| var SliderCaptcha = function(element, options) { | |
| // Object Composition | |
| this.data = { | |
| options: $.extend({ | |
| authValue: 'Authenticated!', | |
| cursor: 'move', | |
| customValidation: true, | |
| direction: 'x', //x or y | |
| handle: '.handle', | |
| hintText: 'Grab and Slide', | |
| inputName: 'captcha', | |
| completeCallback: defaultCompleteCallback | |
| }, options), | |
| handle: { | |
| obj: 0, | |
| active: 0, | |
| oWidth: 0 | |
| }, | |
| slide: { | |
| obj: $(element), | |
| width: 0, | |
| oWidth: 0 | |
| }, | |
| form: { | |
| obj: 0, | |
| input: 0 | |
| } | |
| }; | |
| // Object data alias : It's a relics, maybe future removed | |
| this.options = this.data.options; | |
| this.handle = this.data.handle; | |
| this.slide = this.data.slide; | |
| this.form = this.data.form; | |
| this.init = function () { | |
| // Init data | |
| this.slide.obj = $(element); | |
| this.slide.obj.addClass('slide-to-captcha'); | |
| this.slide.width = this.slide.obj.width(); | |
| this.slide.oWidth = this.slide.obj.outerWidth(true); | |
| /* Slider Logic | |
| * -------------------- | |
| * | _ | | |
| * | |_|------------- | | |
| * | | | |
| * -------------------- | |
| * |--------------| | |
| * | |
| * start = slide.left + (slide.oWidth - slide.width) / 2; | |
| * end = (start + )slide.width - handle.width/2 | |
| * ^ this practically not necessary, I don't know | |
| * handleCenterPos = e.pageX - handle.width/2 | |
| */ | |
| this.slide.start = this.slide.obj.offset().left + (this.slide.oWidth - this.slide.width) / 2; | |
| this.slide.end = this.slide.start + this.slide.width; | |
| // Show hint | |
| $('.slide-to-captcha').attr('data-content', this.options.hintText); | |
| this.handle.obj = $(element).find(this.options.handle); | |
| this.handle.obj.addClass('slide-to-captcha-handle'); | |
| this.handle.obj.offset({ left: this.slide.start }); | |
| this.handle.width = this.handle.obj.width(); | |
| this.handle.oWidth = this.handle.obj.outerWidth(); | |
| // Substract half of the handle width from the track width | |
| this.slide.end = this.slide.end - (this.handle.width / 2); | |
| // console.log("start %i = %i + (%i - %i) / 2", this.slide.start, this.slide.obj.offset().left, this.slide.oWidth, this.slide.width); | |
| // console.log("end %i = %i - (%i / 2)", this.slide.end, this.slide.width, this.handle.width); | |
| this.form.obj = this.slide.obj.parents('form'); | |
| this.form.input = $(this.form.obj).find('input[name=' + this.options.inputName + ']'); | |
| if (this.options.customValidation === false) { | |
| this.form.obj.attr('data-valid', 'false'); | |
| this.form.obj.attr('onsubmit', "return $(this).attr('data-valid') === 'true';"); | |
| } | |
| this.handle.obj.css('cursor', this.options.cursor) | |
| .on('mousedown', this, this.onDrag); | |
| }; | |
| this.destroy = function () { | |
| this.form.obj.removeAttr('data-valid', 'false'); | |
| this.handle.obj.removeClass('slide-to-captcha-handle'); | |
| this.slide.obj.removeClass('slide-to-captcha'); | |
| this.slide.obj.removeClass('valid'); | |
| this.form.input.attr('value', ''); | |
| this.handle.obj.css('cursor', 'normal') | |
| .on('mousedown', null); | |
| this.handle.active.offset({left: 0}); | |
| }; | |
| this.reset = function () { | |
| this.destroy(); | |
| this.init(); | |
| }; | |
| this.onDrag = function (e) { | |
| var data = e.data; | |
| data.handle.active = $(this).addClass('active-handle'); | |
| data.handle.obj | |
| .on('mousemove', data, data.onMove) | |
| .on('mouseup', data, data.onRelease); | |
| // if(data.options.direction === 'y') { | |
| // yPos = handle.offset().top + handleHeight = e.pageY; | |
| // } | |
| // To avoid calculation error when style doesn't fully loaded, | |
| // recalc slider start and end here | |
| data.slide.start = data.slide.obj.offset().left + (data.slide.oWidth - data.slide.width) / 2; | |
| data.slide.end = data.slide.start + data.slide.width - data.handle.width; | |
| e.preventDefault(); | |
| }; | |
| this.onMove = function (e) { | |
| var data = e.data; | |
| var handleXPos = data.handle.obj.offset().left + (e.pageX - data.handle.obj.offset().left - (data.handle.width / 2)); | |
| console.log('pageX: %i . handle off: %i', e.pageX, data.handle.obj.offset().left); | |
| // console.log('%i > %i or < %i', handleXPos, data.slide.start, data.slide.end); | |
| if(handleXPos >= data.slide.start && handleXPos <= data.slide.end) { | |
| // console.log(handleXPos - data.slide.start); | |
| if (data.handle.obj.hasClass('active-handle')) { | |
| data.handle.active.offset({left: handleXPos}); | |
| } | |
| } else { | |
| // console.log('%i >= %i ?', handleXPos, data.slide.end); | |
| if(handleXPos >= data.slide.end) { | |
| var ev = { data: data }; | |
| data.onComplete(ev); | |
| } | |
| data.handle.active.mouseup(); | |
| } | |
| }; | |
| this.onComplete = function (e) { | |
| var data = e.data; | |
| data.handle.active.offset({ left: data.slide.end }); | |
| data.handle.active.off(); | |
| data.onRelease(e); | |
| data.form.obj.attr('data-valid', 'true'); | |
| data.slide.obj.addClass('valid'); | |
| data.options.completeCallback(data); | |
| data.form.input.attr('value', data.options.authValue); | |
| }; | |
| function defaultCompleteCallback(data) { | |
| console.log('Authenticated as human!'); | |
| data.slide.obj.attr('data-content', data.options.authValue); | |
| }; | |
| this.onRelease = function (e) { | |
| var data = e.data; | |
| data.handle.active.removeClass('active-handle'); | |
| }; | |
| // Solo function | |
| this.init(); | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment