Custom Captcha in javascript

by Faisal Khan Janjua

HTML

<style type="text/css">
  input, textarea {
      width: 200px;
  }
  textarea {
    min-height: 80px;
    max-height: 180px;
    min-width: 200px;
    max-width: 200px;
  }
  label {
      width: 96px;
      display: inline-block;
      vertical-align: top;
  }
</style>
<form>
  <div class="mainForm col-xs-12 col-sm-6">
    <label>Your Name</label>
    <input type="text">
  </div>

  <div class="mainForm col-xs-12 col-sm-6">
    <label>Email Address</label>
    <input type="email">
  </div>

  <div class="mainForm col-xs-12 col-sm-4">
    <label>Phone</label>
    <input type="text">
  </div>

  <div class="mainForm col-xs-12 col-sm-8">
    <label>Subject</label>
    <input type="text">
  </div>

  <div class="mainForm col-xs-12">
    <label>Your Message</label>
    <textarea></textarea>
  </div>

  <div class="mainForm col-xs-12">
    <div class="fcaptcha"></div>
  </div>

  <div class="mainForm col-xs-12">
    <button type="submit" disabled class="btn formBtnSend">Send Message</button>
    <p>We'll do our best to get back to you within 6-8 working hours.</p>
  </div>

</form>

CSS

.mainForm {
  margin-bottom: 20px;
}

@-webkit-keyframes rotateShow {
  0% {
    -webkit-transform: rotate(0);
  }

  50% {
    -webkit-transform: rotate(-20deg);
  }

  100% {
    -webkit-transform: rotate(0);
  }
}

@keyframes rotateShow {
  0% {
    transform: rotate(0);
  }

  50% {
    transform: rotate(-20deg);
  }

  100% {
    transform: rotate(0);
  }
}

.puzzleButton {
  margin: 0;
  width: 120px;
  height: 120px;
  padding: 14px;
  cursor: pointer;
  border-radius: 50%;
  background: #efefef;
  box-sizing: border-box;
}

.puzzleButton+p {
  display: inline-block;
  cursor: pointer;
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.puzzleContainer {
  width: 100%;
  height: 100%;
  padding: 15px;
  cursor: pointer;
  text-align: center;
  position: relative;
  border-radius: 50%;
  margin-bottom: 10px;
  box-sizing: border-box;
  -webkit-transition: all ease-in-out 0.1s;
  transition: all ease-in-out 0.1s;
  border-top: 3px solid #333;
  border-bottom: 3px solid #333;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
}

.puzzleContainer:active {
  transform: scale(0.9);
}

.puzzleButton.howto:hover .puzzleContainer,
.puzzleButton.howto.swing .puzzleContainer {
  -webkit-animation: rotateShow 0.55s;
  animation: rotateShow 0.55s;
}

.puzzleContainer:after,
.puzzleContainer:before {
  top: 11px;
  left: 1px;
  width: 0;
  height: 0;
  content: "";
  position: absolute;
  border-top: 12px solid #333;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  -webkit-transform: rotate(45deg);
  transform: rotate(45deg);
}

.puzzleContainer:after {
  right: 1px;
  top: auto;
  left: auto;
  bottom: 11px;
  -webkit-transform: rotate(-135deg);
  transform: rotate(-135deg);
}

.puzzleContainer span {
  position: absolute;
  width: 0;
  height: 0;
  top: 0;
  left: 0;
  right: 0;
  margin: auto;
  border-top: 8px solid #F00;
  border-left: 7px solid transparent;
  border-right: 7px solid...

JavaScript

function fcaptcha() {
  if (jQuery('.fcaptcha').length > 0) {
    //var pstyle = '<style type="text/css"></style>';
    var characters = 'ABCDEFGKLMPQRTUVWY123457';
    // var angles = [90, 180, 270];
    // var angles = [72, 144, 216, 288];
    var angles = [60, 120, 180, 240, 300];
    var gap = angles[1] - angles[0];
    var rotateAt = Math.floor(Math.random() * angles.length);
    var puzzleChar = characters.charAt(Math.floor(Math.random() * characters.length));
    var puzzlHtml = '<div class="puzzleButton howto"><div class="puzzleContainer"><span></span><div class="charRotator" style="transform:rotate(' + angles[rotateAt] + 'deg);" data-rotate="' + angles[rotateAt] + '">' + puzzleChar + '</div></div></div>';
    jQuery('.fcaptcha').append(puzzlHtml);
    //jQuery('head').append(pstyle);
    jQuery('.fcaptcha').css('text-align', 'left').append("<p><strong>Click here</strong> to solve above puzzle if you're human.</p>");
    jQuery(document).on('click', '.puzzleButton, .puzzleButton+p', function() {
      var its = jQuery(this);
      if (jQuery(this).find('.charRotator').length < 1) {
        its = jQuery(this).prev('.puzzleButton');
      }
      var rotateval = its.find('.charRotator').attr('data-rotate') - gap;
      var rotatedeg = its.find('.charRotator').attr('style').replace(/[^\d-]/g, '') - gap;
      its.find('.charRotator').css('transform', 'rotate(' + rotatedeg + 'deg)').attr('data-rotate', rotateval);
      if (rotateval < 0) {
        its.find('.charRotator').attr('data-rotate', 360 - gap);
      }
      if (its.find('.charRotator').attr('data-rotate') == 0) {
        its.removeClass('howto');
        its.closest('form').find('[type="submit"]').removeAttr('disabled');
      } else {
        its.addClass('howto');
        its.closest('form').find('[type="submit"]').attr('disabled', 'disabled');
      }
    });
    jQuery(document).on('mouseenter mouseleave', '.puzzleButton.howto+p', function(ev) {
      if (ev.type === 'mouseenter') {
       ...