优化了一些问题
@@ -5263,117 +5263,6 @@ body:has(.modal.in) .float-btn,
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
/*-----滑动验证码------*/
|
||||
.imagecaptcha > img {
|
||||
width: 92px;
|
||||
height: 35px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.line-form .imagecaptcha.abs-right {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.sign .line-form .imagecaptcha.abs-right {
|
||||
margin-top: -8px;
|
||||
margin-right: -8px;
|
||||
}
|
||||
|
||||
.slidercaptcha {
|
||||
min-height: 205px;
|
||||
}
|
||||
|
||||
.captcha-body-bg {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--muted-border-color);
|
||||
background: var(--main-shadow);
|
||||
}
|
||||
|
||||
.slidercaptcha .captcha-body-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.sliderContainer {
|
||||
text-align: center;
|
||||
background: var(--main-shadow);
|
||||
color: var(--muted-2-color);
|
||||
border-radius: 4px;
|
||||
margin-top: 0.5rem;
|
||||
position: relative;
|
||||
line-height: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.refreshIcon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
opacity: 0.6;
|
||||
top: 0;
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 5px #000;
|
||||
}
|
||||
|
||||
.sliderMask {
|
||||
position: absolute;
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.sliderContainer_active .sliderMask {
|
||||
background: rgba(5, 224, 96, 0.1);
|
||||
border: 1px solid rgba(94, 182, 89, 0.6);
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.sliderContainer_success .sliderMask {
|
||||
background: rgba(0, 153, 255, 0.2);
|
||||
border: 1px solid #43b5fc;
|
||||
}
|
||||
|
||||
.sliderContainer_fail .sliderMask {
|
||||
background: rgba(255, 0, 0, 0.2);
|
||||
border: 1px solid #ff4842;
|
||||
}
|
||||
|
||||
.captcha-slider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: var(--main-bg-color);
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.sliderContainer_active .captcha-slider {
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
.sliderContainer_success .captcha-slider {
|
||||
background: #3ca4f9;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.sliderContainer_fail .captcha-slider {
|
||||
background: #f7564a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.sliderContainer_success .sliderIcon:before {
|
||||
content: '\f00c';
|
||||
}
|
||||
|
||||
.sliderContainer_fail .sliderIcon:before {
|
||||
content: '\f00d';
|
||||
}
|
||||
|
||||
/*------登录框-------*/
|
||||
|
||||
.sign-content {
|
||||
|
||||
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
@@ -1,129 +0,0 @@
|
||||
function CaptchaInit() {
|
||||
var _mode = jQuery('[machine-verification]');
|
||||
var mode = _mode.attr('machine-verification');
|
||||
var _body = jQuery('body');
|
||||
window.captcha = {};
|
||||
|
||||
function get_img(_this) {
|
||||
jQuery.ajax({
|
||||
url: _win.uri + '/action/captcha.php',
|
||||
data: {
|
||||
type: 'image',
|
||||
id: _this.attr('imagecaptcha-id'),
|
||||
},
|
||||
}).done(function (data) {
|
||||
_this.html('<img alt="' + aksrt__('captcha_click_refresh') + '" src="' + data.img + '">');
|
||||
});
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case 'image':
|
||||
var _code = jQuery('.imagecaptcha');
|
||||
_code.each(function () {
|
||||
get_img(jQuery(this));
|
||||
});
|
||||
|
||||
_body.on('click', '.imagecaptcha', function () {
|
||||
get_img(jQuery(this));
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case 'slider':
|
||||
tbquire(['slidercaptcha']);
|
||||
|
||||
break;
|
||||
case 'tcaptcha':
|
||||
var $btn = jQuery('#TencentCaptcha.aksrt-tcaptcha');
|
||||
var appid = _mode.attr('tcaptcha-id');
|
||||
if (!$btn.length) {
|
||||
_body.append('<div class="hide aksrt-tcaptcha" id="TencentCaptcha" data-appid="' + appid + '" data-cbfn="TCaptchaOK" data-biz-state=""></div>');
|
||||
}
|
||||
tbquire(['tcaptcha-sdk']);
|
||||
|
||||
break;
|
||||
|
||||
case 'geetest':
|
||||
GeetestOpenInit(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CaptchaInit();
|
||||
|
||||
/*global SliderCaptchaModal, initGeetest4*/
|
||||
/**
|
||||
* 打开验证码弹窗
|
||||
* @param {object} _this - 当前对象
|
||||
* @param {string} mode - 模式,可选值为'slider'、'geetest'、'tcaptcha'
|
||||
* @returns {number} - 返回1表示打开失败
|
||||
*/
|
||||
function CaptchaOpen(_this, mode) {
|
||||
switch (mode) {
|
||||
case 'slider':
|
||||
tbquire(['slidercaptcha'], function () {
|
||||
SliderCaptchaModal('show', _this);
|
||||
});
|
||||
break;
|
||||
case 'geetest':
|
||||
window.captcha._this = _this;
|
||||
GeetestOpenInit(true);
|
||||
break;
|
||||
case 'tcaptcha':
|
||||
TCaptchaOpen(_this);
|
||||
break;
|
||||
}
|
||||
return !1;
|
||||
}
|
||||
|
||||
//腾讯验证码弹窗
|
||||
function TCaptchaOpen(_this) {
|
||||
window.captcha._this = _this;
|
||||
tbquire(['tcaptcha-sdk'], function () {
|
||||
jQuery('#TencentCaptcha.aksrt-tcaptcha').click();
|
||||
});
|
||||
}
|
||||
|
||||
function GeetestOpenInit(open) {
|
||||
var _mode = jQuery('[machine-verification]');
|
||||
if (window.GeetestCaptcha) {
|
||||
open && window.GeetestCaptcha.showCaptcha();
|
||||
return;
|
||||
}
|
||||
if (!_mode.length) {
|
||||
return;
|
||||
}
|
||||
tbquire(['https://static.geetest.com/v4/gt4.js'], function () {
|
||||
initGeetest4(
|
||||
{
|
||||
captchaId: _mode.attr('geetest-id'),
|
||||
product: 'bind',
|
||||
},
|
||||
function (captchaObj) {
|
||||
captchaObj
|
||||
.onReady(function () {
|
||||
window.GeetestCaptcha = captchaObj;
|
||||
open && captchaObj.showCaptcha();
|
||||
})
|
||||
.onSuccess(function () {
|
||||
var getValidate = captchaObj.getValidate();
|
||||
window.captcha.captcha_output = getValidate.captcha_output;
|
||||
window.captcha.gen_time = getValidate.gen_time;
|
||||
window.captcha.lot_number = getValidate.lot_number;
|
||||
window.captcha.ticket = getValidate.pass_token;
|
||||
window.captcha._this.click();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
//腾讯验证码回调
|
||||
function TCaptchaOK(res) {
|
||||
window.captcha.ticket = 0;
|
||||
window.captcha.randstr = 0;
|
||||
if (res.ret === 0) {
|
||||
window.captcha.ticket = res.ticket;
|
||||
window.captcha.randstr = res.randstr;
|
||||
window.captcha._this.click();
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
function CaptchaInit(){function t(t){jQuery.ajax({url:_win.uri+"/action/captcha.php",data:{type:"image",id:t.attr("imagecaptcha-id")}}).done(function(a){t.html('<img alt="'+aksrt__("captcha_click_refresh")+'" src="'+a.img+'">')})}var a=jQuery("[machine-verification]"),c=a.attr("machine-verification"),i=jQuery("body");switch(window.captcha={},c){case"image":var e=jQuery(".imagecaptcha");e.each(function(){t(jQuery(this))}),i.on("click",".imagecaptcha",function(){t(jQuery(this))});break;case"slider":tbquire(["slidercaptcha"]);break;case"tcaptcha":var n=jQuery("#TencentCaptcha.aksrt-tcaptcha"),h=a.attr("tcaptcha-id");n.length||i.append('<div class="hide aksrt-tcaptcha" id="TencentCaptcha" data-appid="'+h+'" data-cbfn="TCaptchaOK" data-biz-state=""></div>'),tbquire(["tcaptcha-sdk"]);break;case"geetest":GeetestOpenInit(!1)}}function CaptchaOpen(t,a){switch(a){case"slider":tbquire(["slidercaptcha"],function(){SliderCaptchaModal("show",t)});break;case"geetest":window.captcha._this=t,GeetestOpenInit(!0);break;case"tcaptcha":TCaptchaOpen(t)}return!1}function TCaptchaOpen(t){window.captcha._this=t,tbquire(["tcaptcha-sdk"],function(){jQuery("#TencentCaptcha.aksrt-tcaptcha").click()})}function GeetestOpenInit(t){var a=jQuery("[machine-verification]");window.GeetestCaptcha?t&&window.GeetestCaptcha.showCaptcha():a.length&&tbquire(["https://static.geetest.com/v4/gt4.js"],function(){initGeetest4({captchaId:a.attr("geetest-id"),product:"bind"},function(a){a.onReady(function(){window.GeetestCaptcha=a,t&&a.showCaptcha()}).onSuccess(function(){var t=a.getValidate();window.captcha.captcha_output=t.captcha_output,window.captcha.gen_time=t.gen_time,window.captcha.lot_number=t.lot_number,window.captcha.ticket=t.pass_token,window.captcha._this.click()})})})}function TCaptchaOK(t){window.captcha.ticket=0,window.captcha.randstr=0,0===t.ret&&(window.captcha.ticket=t.ticket,window.captcha.randstr=t.randstr,window.captcha._this.click())}CaptchaInit();
|
||||
@@ -231,8 +231,6 @@ _win.bd.on('click', '#commentform #submit', function () {
|
||||
auto_fun();
|
||||
wait_for(n.wait_time);
|
||||
jQuery('#comment').val('');
|
||||
jQuery('[name="canvas_yz"]').val('');
|
||||
jQuery('.imagecaptcha').click();
|
||||
jQuery('#respond').FixedInput('hide');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -62,7 +62,6 @@ tbquire.config({
|
||||
'imgbox' : 'imgbox.min',
|
||||
'section-navs' : 'section-navs.min',
|
||||
'poster-share' : 'poster-share.min',
|
||||
'slidercaptcha' : 'slidercaptcha.min',
|
||||
'comment' : 'comment.min',
|
||||
'page-template' : 'page-template.min',
|
||||
'page-edit' : 'page-edit.min',
|
||||
@@ -74,8 +73,6 @@ tbquire.config({
|
||||
'editextend' : 'editextend.min',
|
||||
'petite-vue' : 'libs/petite-vue.iife',
|
||||
'svg-icon' : 'svg-icon',
|
||||
'tcaptcha-sdk' : ['https://turing.captcha.qcloud.com/TJCaptcha'],
|
||||
'captcha' : 'captcha.min',
|
||||
'tilt' : '../../widgets/third-party/vanilla-tilt.min',
|
||||
'weixin-share' : 'weixin-share.min',
|
||||
'weixin-sdk' : ['//res.wx.qq.com/open/js/jweixin-1.6.0','//res2.wx.qq.com/open/js/jweixin-1.6.0'],
|
||||
|
||||
@@ -2453,9 +2453,6 @@ function z_auto_fun() {
|
||||
//海报分享
|
||||
jQuery('[poster-share]').length && tbquire(['poster-share']); //海报分享
|
||||
|
||||
//人机验证
|
||||
jQuery('[machine-verification]').length && tbquire(['captcha']); //人机验证
|
||||
|
||||
/* 提示工具*/
|
||||
jQuery("[data-toggle='tooltip']").tooltip({
|
||||
container: 'body',
|
||||
@@ -3844,10 +3841,6 @@ _win.bd.on('click', '.wp-ajax-submit,[zibajax="submit"]', function () {
|
||||
return aksrt_ajax(jQuery(this)), !1;
|
||||
});
|
||||
|
||||
function is_captcha() {
|
||||
return window.captcha && !window.captcha.ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: ajax请求封装
|
||||
* @param {*} _this 按钮的jquery对象
|
||||
@@ -3879,23 +3872,6 @@ function aksrt_ajax(_this, data, success, noty, no_loading) {
|
||||
data.action = _action;
|
||||
}
|
||||
|
||||
//人机验证
|
||||
if (data.captcha_mode && is_captcha(data.captcha_mode)) {
|
||||
tbquire(['captcha'], function () {
|
||||
CaptchaOpen(_this, data.captcha_mode);
|
||||
});
|
||||
return !1;
|
||||
}
|
||||
|
||||
if (window.captcha) {
|
||||
if (window.captcha._this) {
|
||||
delete window.captcha._this;
|
||||
}
|
||||
|
||||
data.captcha = JSON.parse(JSON.stringify(window.captcha));
|
||||
window.captcha = {}; //只能使用一次
|
||||
}
|
||||
|
||||
var _text = _this.html();
|
||||
var _loading = no_loading ? _text : '<i class="loading mr6"></i><text>' + aksrt__('please_wait') + '</text>';
|
||||
noty != 'stop' && notyf(noty || aksrt__('processing'), 'load', '', 'wp_ajax');
|
||||
@@ -3918,9 +3894,6 @@ function aksrt_ajax(_this, data, success, noty, no_loading) {
|
||||
},
|
||||
success: function (n) {
|
||||
var ys = n.ys ? n.ys : n.error ? 'danger' : '';
|
||||
if (n.error) {
|
||||
_win.slidercaptcha = false;
|
||||
}
|
||||
if (noty != 'stop') {
|
||||
notyf(n.msg || aksrt__('done'), ys, '', 'wp_ajax');
|
||||
} else if (n.msg) {
|
||||
|
||||
@@ -181,23 +181,6 @@ function miniupload() {
|
||||
}
|
||||
});
|
||||
|
||||
//人机验证
|
||||
if (formData.get('captcha_mode') && is_captcha(formData.get('captcha_mode'))) {
|
||||
tbquire(['captcha'], function () {
|
||||
CaptchaOpen(_this, formData.get('captcha_mode'));
|
||||
});
|
||||
return !1;
|
||||
}
|
||||
|
||||
if (window.captcha) {
|
||||
if (window.captcha._this) {
|
||||
delete window.captcha._this;
|
||||
}
|
||||
|
||||
formData.append('captcha', JSON.stringify(window.captcha));
|
||||
window.captcha = {}; //只能使用一次
|
||||
}
|
||||
|
||||
/**
|
||||
for (var [a, b] of formData.entries()) {
|
||||
console.log(a, b);
|
||||
@@ -250,9 +233,6 @@ function miniupload() {
|
||||
form.find('.progress .progress-bar').css('width', percent + '%');
|
||||
}),
|
||||
success: function (n) {
|
||||
if (n.error) {
|
||||
_win.slidercaptcha = false;
|
||||
}
|
||||
var ys = n.ys ? n.ys : n.error ? 'danger' : '';
|
||||
notyf(n.msg || aksrt__('operation_success'), ys, '', notyf_id);
|
||||
miniuploaded(n.no_preview_reset);
|
||||
|
||||
@@ -1,428 +0,0 @@
|
||||
(function ($) {
|
||||
'use strict';
|
||||
|
||||
var SliderCaptcha = function (element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, SliderCaptcha.DEFAULTS, options);
|
||||
this.$element.css({
|
||||
position: 'relative',
|
||||
width: this.options.width + 'px',
|
||||
margin: '0 auto',
|
||||
});
|
||||
this.init();
|
||||
};
|
||||
|
||||
SliderCaptcha.DEFAULTS = {
|
||||
width: 280, // canvas宽度
|
||||
height: 170, // canvas高度
|
||||
PI: Math.PI,
|
||||
sliderL: 42, // 滑块边长
|
||||
sliderR: 9, // 滑块半径
|
||||
offset: 8, // 容错偏差
|
||||
loadingText: '<i class="loading mr6"></i>' + aksrt__('loading'),
|
||||
failedText: aksrt__('captcha_retry'),
|
||||
barText: aksrt__('captcha_slide_hint'),
|
||||
repeatIcon: 'fa fas fa-sync-alt',
|
||||
maxLoadCount: 3,
|
||||
onFail: function () {
|
||||
//失败执行的函数
|
||||
},
|
||||
onSuccess: function () {
|
||||
//成功执行的函数
|
||||
},
|
||||
setSrc: function () {
|
||||
//图片获取函数
|
||||
return '';
|
||||
},
|
||||
getX: null,
|
||||
};
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('lgb.SliderCaptcha');
|
||||
var options = typeof option === 'object' && option;
|
||||
if (data && !/reset/.test(option)) $(data.refreshIcon).click();
|
||||
if (!data) $this.data('lgb.SliderCaptcha', (data = new SliderCaptcha(this, options)));
|
||||
if (typeof option === 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.sliderCaptcha = Plugin;
|
||||
$.fn.sliderCaptcha.Constructor = SliderCaptcha;
|
||||
|
||||
var _proto = SliderCaptcha.prototype;
|
||||
_proto.init = function () {
|
||||
this.initDOM();
|
||||
this.initImg();
|
||||
this.bindEvents();
|
||||
};
|
||||
|
||||
_proto.initDOM = function () {
|
||||
var createElement = function (tagName, className) {
|
||||
var elment = document.createElement(tagName);
|
||||
elment.className = className;
|
||||
return elment;
|
||||
};
|
||||
|
||||
var createCanvas = function (width, height) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
return canvas;
|
||||
};
|
||||
|
||||
var canvas = createCanvas(this.options.width - 2, this.options.height); // 画布
|
||||
var block = canvas.cloneNode(true); // 滑块
|
||||
var sliderContainer = createElement('div', 'sliderContainer');
|
||||
var refreshIcon = createElement('botton', 'refreshIcon ' + this.options.repeatIcon);
|
||||
var sliderMask = createElement('div', 'sliderMask');
|
||||
var slider = createElement('div', 'captcha-slider');
|
||||
var sliderIcon = createElement('i', 'fa fas fa-chevron-right sliderIcon');
|
||||
var text = createElement('span', 'sliderText');
|
||||
|
||||
canvas.className = 'captcha-body-bg placeholder';
|
||||
block.className = 'captcha-body-bar';
|
||||
text.innerHTML = this.options.barText;
|
||||
|
||||
var el = this.$element;
|
||||
el.html($(canvas));
|
||||
el.append($(refreshIcon));
|
||||
el.append($(block));
|
||||
slider.appendChild(sliderIcon);
|
||||
sliderContainer.appendChild(sliderMask);
|
||||
sliderContainer.appendChild(slider);
|
||||
sliderContainer.appendChild(text);
|
||||
el.append($(sliderContainer));
|
||||
|
||||
var _canvas = {
|
||||
canvas: canvas,
|
||||
block: block,
|
||||
sliderContainer: $(sliderContainer),
|
||||
refreshIcon: refreshIcon,
|
||||
slider: slider,
|
||||
sliderMask: sliderMask,
|
||||
sliderIcon: sliderIcon,
|
||||
text: $(text),
|
||||
canvasCtx: canvas.getContext('2d'),
|
||||
blockCtx: block.getContext('2d'),
|
||||
};
|
||||
|
||||
if ($.isFunction(Object.assign)) {
|
||||
Object.assign(this, _canvas);
|
||||
} else {
|
||||
$.extend(this, _canvas);
|
||||
}
|
||||
};
|
||||
|
||||
_proto.initImg = function () {
|
||||
var that = this;
|
||||
var isIE = window.navigator.userAgent.indexOf('Trident') > -1;
|
||||
var L = this.options.sliderL + this.options.sliderR * 2 + 3; // 滑块实际边长
|
||||
var drawImg = function (ctx, operation) {
|
||||
var l = that.options.sliderL;
|
||||
var r = that.options.sliderR;
|
||||
var PI = that.options.PI;
|
||||
var x = that.x;
|
||||
var y = that.y;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
|
||||
ctx.lineTo(x + l, y);
|
||||
ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
|
||||
ctx.lineTo(x + l, y + l);
|
||||
ctx.lineTo(x, y + l);
|
||||
ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
|
||||
ctx.lineTo(x, y);
|
||||
ctx.lineWidth = 2;
|
||||
ctx.fillStyle = 'rgba(100, 100, 100, 0.7)';
|
||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
||||
ctx.stroke();
|
||||
ctx[operation]();
|
||||
ctx.globalCompositeOperation = isIE ? 'xor' : 'destination-over';
|
||||
};
|
||||
|
||||
var getRandomNumberByRange = function (start, end) {
|
||||
return Math.round(Math.random() * (end - start) + start);
|
||||
};
|
||||
|
||||
var getRandomNumberByRangeToX = function (start, end) {
|
||||
if ($.isFunction(that.options.getX)) return that.options.getX(start, end);
|
||||
return getRandomNumberByRange(start, end);
|
||||
};
|
||||
|
||||
var img = new Image();
|
||||
img.crossOrigin = 'Anonymous';
|
||||
var loadCount = 0;
|
||||
|
||||
img.onload = function () {
|
||||
// 随机创建滑块的位置
|
||||
that.x = getRandomNumberByRangeToX(L + 10, that.options.width - (L + 10));
|
||||
that.y = getRandomNumberByRange(10 + that.options.sliderR * 2, that.options.height - (L + 10));
|
||||
drawImg(that.canvasCtx, 'fill');
|
||||
drawImg(that.blockCtx, 'clip');
|
||||
|
||||
that.canvasCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height);
|
||||
that.blockCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height);
|
||||
var y = that.y - that.options.sliderR * 2 - 1;
|
||||
var ImageData = that.blockCtx.getImageData(that.x - 3, y, L, L);
|
||||
that.block.width = L;
|
||||
that.blockCtx.putImageData(ImageData, 0, y + 1);
|
||||
that.text.text(that.text.attr('data-text'));
|
||||
};
|
||||
|
||||
img.onerror = function (e) {
|
||||
loadCount++;
|
||||
if (loadCount >= that.options.maxLoadCount) {
|
||||
that.text.text(aksrt__('captcha_load_failed')).addClass('text-danger c-red');
|
||||
that.canvas.removeClass('placeholder');
|
||||
return;
|
||||
}
|
||||
img.localImages();
|
||||
};
|
||||
img.setSrc = function () {
|
||||
loadCount = 0;
|
||||
that.text.removeClass('text-danger');
|
||||
if ($.isFunction(that.options.setSrc)) {
|
||||
var src = that.options.setSrc();
|
||||
src ? (img.src = that.options.setSrc()) : img.localImages();
|
||||
}
|
||||
};
|
||||
img.localImages = function () {
|
||||
that.text.removeClass('text-danger');
|
||||
var src = 'https://picsum.photos/' + that.options.width + '/' + that.options.height + '/?image=' + Math.round(Math.random() * 20);
|
||||
if (isIE) {
|
||||
// IE浏览器无法通过img.crossOrigin跨域,使用ajax获取图片blob然后转为dataURL显示
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onloadend = function (e) {
|
||||
var file = new FileReader(); // FileReader仅支持IE10+
|
||||
file.readAsDataURL(e.target.response);
|
||||
file.onloadend = function (e) {
|
||||
img.src = e.target.result;
|
||||
};
|
||||
};
|
||||
xhr.open('GET', src);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.send();
|
||||
} else img.src = src;
|
||||
};
|
||||
img.setSrc();
|
||||
this.text.attr('data-text', this.options.barText);
|
||||
this.text.html(this.options.loadingText);
|
||||
this.img = img;
|
||||
};
|
||||
|
||||
_proto.clean = function () {
|
||||
this.canvasCtx.clearRect(0, 0, this.options.width, this.options.height);
|
||||
this.blockCtx.clearRect(0, 0, this.options.width, this.options.height);
|
||||
this.block.width = this.options.width;
|
||||
};
|
||||
|
||||
_proto.bindEvents = function () {
|
||||
var that = this;
|
||||
this.$element.on('selectstart', function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
$(this.refreshIcon).on('click', function () {
|
||||
that.text.text(that.options.barText);
|
||||
that.reset();
|
||||
if ($.isFunction(that.options.onRefresh)) that.options.onRefresh.call(that.$element);
|
||||
});
|
||||
|
||||
var originX,
|
||||
originY,
|
||||
moveX,
|
||||
moveY,
|
||||
trail = [],
|
||||
isMouseDown = false;
|
||||
this.$element
|
||||
.on('touchstart pointerdown MSPointerDown', '.captcha-slider', function (e) {
|
||||
if (that.text.hasClass('text-danger')) return;
|
||||
originX = e.originalEvent.pageX || e.originalEvent.touches[0].pageX;
|
||||
originY = e.originalEvent.pageY || e.originalEvent.touches[0].pageY;
|
||||
isMouseDown = true;
|
||||
})
|
||||
.on('touchmove pointermove MSPointerMove', function (e) {
|
||||
if (isMouseDown) {
|
||||
var eventX = e.originalEvent.pageX || e.originalEvent.touches[0].pageX;
|
||||
var eventY = e.originalEvent.pageY || e.originalEvent.touches[0].pageY;
|
||||
moveX = eventX - originX;
|
||||
moveY = eventY - originY;
|
||||
if (moveX >= 0 && moveX + 40 <= that.options.width) {
|
||||
e.preventDefault ? e.preventDefault() : (e.returnValue = !1);
|
||||
that.slider.style.left = moveX - 1 + 'px';
|
||||
var blockLeft = ((that.options.width - 40 - 20) / (that.options.width - 40)) * moveX;
|
||||
that.block.style.left = blockLeft + 'px';
|
||||
that.sliderContainer.addClass('sliderContainer_active');
|
||||
that.sliderMask.style.width = moveX + 4 + 'px';
|
||||
trail.push(Math.round(moveY));
|
||||
}
|
||||
}
|
||||
})
|
||||
.on('touchend touchcancel pointerup MSPointerUp', function () {
|
||||
if (isMouseDown && moveX >= 0) {
|
||||
that.sliderContainer.removeClass('sliderContainer_active');
|
||||
that.trail = trail;
|
||||
var data = that.verify();
|
||||
if (data.spliced && data.verified) {
|
||||
that.sliderContainer.addClass('sliderContainer_success');
|
||||
setTimeout(function () {
|
||||
that.slider.style.left = 0;
|
||||
that.block.style.left = 0;
|
||||
that.sliderMask.style.width = 0;
|
||||
that.sliderContainer.removeClass('sliderContainer_fail sliderContainer_success');
|
||||
}, 500);
|
||||
if ($.isFunction(that.options.onSuccess)) that.options.onSuccess.call(that.$element, data);
|
||||
} else {
|
||||
that.sliderContainer.addClass('sliderContainer_fail');
|
||||
if ($.isFunction(that.options.onFail)) that.options.onFail.call(that.$element);
|
||||
setTimeout(function () {
|
||||
that.text.text(that.options.failedText);
|
||||
that.reset();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
moveX = 0;
|
||||
moveY = 0;
|
||||
isMouseDown = false;
|
||||
});
|
||||
};
|
||||
|
||||
_proto.verify = function () {
|
||||
var arr = this.trail; // 拖动时y轴的移动距离
|
||||
var left = parseInt(this.block.style.left);
|
||||
var verified = false;
|
||||
var sum = function (x, y) {
|
||||
return x + y;
|
||||
};
|
||||
var square = function (x) {
|
||||
return x * x;
|
||||
};
|
||||
var average = arr.reduce(sum) / arr.length;
|
||||
var deviations = arr.map(function (x) {
|
||||
return x - average;
|
||||
});
|
||||
var stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length);
|
||||
verified = stddev !== 0;
|
||||
return {
|
||||
spliced: Math.abs(left - this.x) < this.options.offset, //小于容差
|
||||
trail: arr,
|
||||
verified: verified, //距离
|
||||
distance: left,
|
||||
};
|
||||
};
|
||||
|
||||
_proto.reset = function () {
|
||||
this.sliderContainer.removeClass('sliderContainer_fail sliderContainer_success');
|
||||
this.slider.style.left = 0;
|
||||
this.block.style.left = 0;
|
||||
this.sliderMask.style.width = 0;
|
||||
this.clean();
|
||||
this.text.attr('data-text', this.text.text());
|
||||
this.text.html(this.options.loadingText);
|
||||
this.img.setSrc();
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
function SliderCaptchaModal(action, _btn) {
|
||||
var modal_id = 'SliderCaptcha';
|
||||
/*global captcha*/
|
||||
captcha._this = _btn;
|
||||
|
||||
if (!$('#' + modal_id).length) {
|
||||
var modal_html = '<div id="' + modal_id + '" class="modal flex jc fade" tabindex="-1" role="dialog" aria-hidden="false" style="display: none;user-select: none;z-index: 100000000;background:rgba(0,0,0,.5);"><div class="modal-mini modal-dialog" style="width: 340px;"> <div class="modal-content"><div class="modal-body"><div class="modal-colorful-header colorful-bg c-yellow" style="height: 100px;"><button class="close" data-dismiss="modal"><svg class="ic-close" aria-hidden="true"><use xlink:href="#icon-close"></use></svg></button><div class="colorful-make"></div><div class="text-center"><div class="em2x"><i class="fa fas fa-shield-alt"></i></div><div class="mt6 em12">' + aksrt__('captcha_verify_title') + '</div></div></div><div style="padding: 10px 0;margin-top: 100px;"><div class="slidercaptcha"></div></div></div></div></div></div>';
|
||||
$('body').append(modal_html);
|
||||
$('#' + modal_id + ' [data-dismiss="modal"]').on('click', hide);
|
||||
}
|
||||
|
||||
function str($str) {
|
||||
var a = get_random(11, 40);
|
||||
var b = get_random(11, 40);
|
||||
return a + '' + getPass(a) + $str + getPass(b) + b;
|
||||
}
|
||||
|
||||
function get_random(min, max) {
|
||||
return Math.round(Math.random() * (min - max) + max);
|
||||
}
|
||||
|
||||
function getPass(len) {
|
||||
var tmpCh = '';
|
||||
for (var i = 0; i < len; i++) {
|
||||
tmpCh += String.fromCharCode(Math.floor(Math.random() * 26) + 'a'.charCodeAt(0));
|
||||
}
|
||||
return tmpCh;
|
||||
}
|
||||
|
||||
function hide() {
|
||||
$('#' + modal_id).removeClass('in');
|
||||
setTimeout(function () {
|
||||
$('#' + modal_id).hide();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function show() {
|
||||
$('#' + modal_id).show();
|
||||
setTimeout(function () {
|
||||
$('#' + modal_id).addClass('in');
|
||||
$('#' + modal_id + ' .slidercaptcha').sliderCaptcha({
|
||||
onSuccess: function (res) {
|
||||
var token = captcha.token;
|
||||
var randstr = captcha.rand_str;
|
||||
delete captcha.rand_str;
|
||||
delete captcha.token;
|
||||
|
||||
if (!token || !randstr) {
|
||||
return notyf(aksrt__('captcha_data_failed'), 'danger');
|
||||
}
|
||||
|
||||
var randstr_a = get_random(1, 9);
|
||||
var randstr_b = get_random(15, 25);
|
||||
var _a = ~~token.substring(0, 2);
|
||||
var _b = ~~token.substring(token.length - 2, token.length);
|
||||
var _c = ~~token.substring(_a + 2, token.length - _b - 2);
|
||||
|
||||
//成功执行的函数
|
||||
captcha.ticket = str(res.distance);
|
||||
captcha.randstr = randstr_a + '' + randstr.substring(randstr_a, randstr_b) + randstr_b;
|
||||
captcha.spliced = res.spliced;
|
||||
captcha.trail = JSON.stringify(res.trail);
|
||||
|
||||
setTimeout(function () {
|
||||
hide();
|
||||
captcha._this.click();
|
||||
return false;
|
||||
}, 200);
|
||||
},
|
||||
setSrc: function () {
|
||||
//图片获取函数
|
||||
return _win.uri + '/img/captcha/' + Math.round(Math.random() * 20) + '.jpg';
|
||||
},
|
||||
getX: function (min, max) {
|
||||
//图片获取函数
|
||||
var $_x = get_random(min, max);
|
||||
captcha.ticket = 0;
|
||||
captcha.randstr = 0;
|
||||
captcha.spliced = 0;
|
||||
|
||||
$.ajax({
|
||||
url: _win.uri + '/action/captcha.php',
|
||||
data: {
|
||||
type: 'slider',
|
||||
randstr: str($_x),
|
||||
},
|
||||
}).done(function (data) {
|
||||
captcha.token = data.token;
|
||||
captcha.rand_str = data.rand_str;
|
||||
captcha.check = data.check;
|
||||
});
|
||||
|
||||
return $_x;
|
||||
},
|
||||
});
|
||||
}, 30);
|
||||
}
|
||||
|
||||
action === 'show' && show();
|
||||
action === 'hide' && hide();
|
||||
}
|
||||
@@ -1,406 +0,0 @@
|
||||
/**
|
||||
* AKSRT Slider CAPTCHA
|
||||
*
|
||||
* Canvas-based slider puzzle CAPTCHA verification.
|
||||
* No jQuery dependency — pure vanilla JS.
|
||||
*
|
||||
* Usage:
|
||||
* var captcha = new AksrtSliderCaptcha(container, {
|
||||
* onSuccess: function(token) { ... },
|
||||
* onFail: function() { ... },
|
||||
* setSrc: function(callback) { callback(imageUrl); }
|
||||
* });
|
||||
* captcha.reset();
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var DEFAULTS = {
|
||||
width: 280,
|
||||
height: 170,
|
||||
sliderL: 42,
|
||||
sliderR: 9,
|
||||
offset: 8,
|
||||
barText: '向右拖动滑块完成验证',
|
||||
successText: '验证成功',
|
||||
failText: '验证失败,请重试',
|
||||
loadingText: '加载中...',
|
||||
maxLoadCount: 3,
|
||||
onSuccess: function () {},
|
||||
onFail: function () {},
|
||||
setSrc: function (callback) { callback(''); },
|
||||
};
|
||||
|
||||
function AksrtSliderCaptcha(element, options) {
|
||||
this.el = typeof element === 'string' ? document.querySelector(element) : element;
|
||||
if (!this.el) return;
|
||||
this.options = {};
|
||||
for (var k in DEFAULTS) this.options[k] = DEFAULTS[k];
|
||||
if (options) { for (var k in options) this.options[k] = options[k]; }
|
||||
this.loadCount = 0;
|
||||
this.init();
|
||||
}
|
||||
|
||||
AksrtSliderCaptcha.prototype.init = function () {
|
||||
this.el.style.position = 'relative';
|
||||
this.el.style.width = this.options.width + 'px';
|
||||
this.el.style.margin = '0 auto';
|
||||
this.el.innerHTML = '';
|
||||
this.initDOM();
|
||||
this.initImg();
|
||||
};
|
||||
|
||||
AksrtSliderCaptcha.prototype.initDOM = function () {
|
||||
var o = this.options;
|
||||
|
||||
// Canvas container
|
||||
this.canvasWrap = document.createElement('div');
|
||||
this.canvasWrap.className = 'aksrt-captcha__canvas-wrap';
|
||||
this.canvasWrap.style.cssText = 'position:relative;overflow:hidden;border-radius:8px;background:#f0f0f0;';
|
||||
|
||||
this.canvas = document.createElement('canvas');
|
||||
this.canvas.width = o.width;
|
||||
this.canvas.height = o.height;
|
||||
this.canvasCtx = this.canvas.getContext('2d');
|
||||
|
||||
this.block = document.createElement('canvas');
|
||||
this.block.width = o.width;
|
||||
this.block.height = o.height;
|
||||
this.blockCtx = this.block.getContext('2d');
|
||||
|
||||
this.canvasWrap.appendChild(this.canvas);
|
||||
this.canvasWrap.appendChild(this.block);
|
||||
|
||||
// Refresh button
|
||||
this.refreshBtn = document.createElement('div');
|
||||
this.refreshBtn.className = 'aksrt-captcha__refresh';
|
||||
this.refreshBtn.innerHTML = '↻';
|
||||
this.refreshBtn.style.cssText = 'position:absolute;top:6px;right:6px;cursor:pointer;font-size:18px;color:#fff;background:rgba(0,0,0,0.3);border-radius:50%;width:28px;height:28px;display:flex;align-items:center;justify-content:center;z-index:5;';
|
||||
this.canvasWrap.appendChild(this.refreshBtn);
|
||||
|
||||
// Slider bar
|
||||
this.sliderBar = document.createElement('div');
|
||||
this.sliderBar.className = 'aksrt-captcha__bar';
|
||||
this.sliderBar.style.cssText = 'position:relative;height:40px;border-radius:20px;background:#e8e8e8;margin-top:10px;user-select:none;';
|
||||
|
||||
this.sliderMask = document.createElement('div');
|
||||
this.sliderMask.className = 'aksrt-captcha__mask';
|
||||
this.sliderMask.style.cssText = 'position:absolute;top:0;left:0;height:100%;border-radius:20px;background:linear-gradient(90deg,#1890ff,#36cfc9);width:0;transition:background 0.3s;';
|
||||
|
||||
this.slider = document.createElement('div');
|
||||
this.slider.className = 'aksrt-captcha__slider';
|
||||
this.slider.style.cssText = 'position:absolute;top:0;left:0;width:44px;height:40px;border-radius:20px;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,0.15);cursor:grab;display:flex;align-items:center;justify-content:center;font-size:18px;z-index:2;transition:box-shadow 0.2s;';
|
||||
this.slider.innerHTML = '❯';
|
||||
|
||||
this.text = document.createElement('div');
|
||||
this.text.className = 'aksrt-captcha__text';
|
||||
this.text.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:#999;font-size:14px;pointer-events:none;';
|
||||
this.text.textContent = o.barText;
|
||||
|
||||
this.sliderBar.appendChild(this.sliderMask);
|
||||
this.sliderBar.appendChild(this.slider);
|
||||
this.sliderBar.appendChild(this.text);
|
||||
|
||||
this.el.appendChild(this.canvasWrap);
|
||||
this.el.appendChild(this.sliderBar);
|
||||
|
||||
this.bindEvents();
|
||||
};
|
||||
|
||||
AksrtSliderCaptcha.prototype.initImg = function () {
|
||||
var self = this;
|
||||
this.loadCount++;
|
||||
if (this.loadCount > this.options.maxLoadCount) {
|
||||
this.text.textContent = '加载失败';
|
||||
return;
|
||||
}
|
||||
|
||||
this.text.textContent = this.options.loadingText;
|
||||
this.slider.style.display = 'none';
|
||||
|
||||
this.options.setSrc(function (src) {
|
||||
if (!src) {
|
||||
self.text.textContent = '验证服务不可用';
|
||||
return;
|
||||
}
|
||||
var img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.onload = function () {
|
||||
self.bgImg = img;
|
||||
self.drawBg();
|
||||
self.drawBlock();
|
||||
self.slider.style.display = '';
|
||||
self.text.textContent = self.options.barText;
|
||||
};
|
||||
img.onerror = function () {
|
||||
self.initImg();
|
||||
};
|
||||
img.src = src;
|
||||
});
|
||||
};
|
||||
|
||||
AksrtSliderCaptcha.prototype.drawBg = function () {
|
||||
var o = this.options;
|
||||
this.canvasCtx.drawImage(this.bgImg, 0, 0, o.width, o.height);
|
||||
this.canvasCtx.globalAlpha = 0.6;
|
||||
this.canvasCtx.fillStyle = '#000';
|
||||
this.canvasCtx.fillRect(0, 0, o.width, o.height);
|
||||
this.canvasCtx.globalAlpha = 1;
|
||||
};
|
||||
|
||||
AksrtSliderCaptcha.prototype.drawBlock = function () {
|
||||
var o = this.options;
|
||||
var x = o.sliderL + Math.random() * (o.width - o.sliderL * 2 - 20);
|
||||
var y = 10 + Math.random() * (o.height - o.sliderL - 20);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
var ctx = this.blockCtx;
|
||||
ctx.clearRect(0, 0, o.width, o.height);
|
||||
|
||||
// Draw the puzzle piece shape
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + o.sliderL / 2, y);
|
||||
ctx.arc(x + o.sliderL / 2, y - o.sliderR, o.sliderR, 0.5 * Math.PI, 2.5 * Math.PI, false);
|
||||
ctx.lineTo(x + o.sliderL, y);
|
||||
ctx.lineTo(x + o.sliderL, y + o.sliderL / 2);
|
||||
ctx.arc(x + o.sliderL + o.sliderR, y + o.sliderL / 2, o.sliderR, Math.PI, 0, false);
|
||||
ctx.lineTo(x + o.sliderL, y + o.sliderL);
|
||||
ctx.lineTo(x, y + o.sliderL);
|
||||
ctx.closePath();
|
||||
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.8)';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Clip and draw image portion
|
||||
ctx.save();
|
||||
ctx.clip();
|
||||
ctx.drawImage(this.bgImg, 0, 0, o.width, o.height);
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
AksrtSliderCaptcha.prototype.bindEvents = function () {
|
||||
var self = this;
|
||||
var o = this.options;
|
||||
var dragging = false;
|
||||
var startX = 0;
|
||||
var currentX = 0;
|
||||
var maxMove = o.width - o.sliderL - 10;
|
||||
var trail = []; // y-axis trail for behavior verification
|
||||
|
||||
function onStart(e) {
|
||||
e.preventDefault();
|
||||
dragging = true;
|
||||
trail = [];
|
||||
startX = (e.touches ? e.touches[0].clientX : e.clientX) || 0;
|
||||
self.slider.style.cursor = 'grabbing';
|
||||
self.slider.style.boxShadow = '0 4px 12px rgba(0,0,0,0.25)';
|
||||
}
|
||||
|
||||
function onMove(e) {
|
||||
if (!dragging) return;
|
||||
e.preventDefault();
|
||||
var clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||
var clientY = e.touches ? e.touches[0].clientY : e.clientY;
|
||||
currentX = Math.max(0, Math.min(maxMove, clientX - startX));
|
||||
trail.push(Math.round(clientY));
|
||||
self.slider.style.left = currentX + 'px';
|
||||
self.sliderMask.style.width = (currentX + 22) + 'px';
|
||||
self.block.style.left = currentX + 'px';
|
||||
}
|
||||
|
||||
function onEnd() {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
self.slider.style.cursor = 'grab';
|
||||
self.slider.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)';
|
||||
|
||||
var positionOk = Math.abs(currentX - self.x) < o.offset;
|
||||
var behaviorOk = verifyTrail(trail);
|
||||
|
||||
if (positionOk && behaviorOk) {
|
||||
self.onSuccess(trail, currentX);
|
||||
} else {
|
||||
self.onFail();
|
||||
}
|
||||
}
|
||||
|
||||
this.slider.addEventListener('mousedown', onStart);
|
||||
this.slider.addEventListener('touchstart', onStart, { passive: false });
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('touchmove', onMove, { passive: false });
|
||||
document.addEventListener('mouseup', onEnd);
|
||||
document.addEventListener('touchend', onEnd);
|
||||
|
||||
this.refreshBtn.addEventListener('click', function () {
|
||||
self.reset();
|
||||
});
|
||||
};
|
||||
|
||||
// Trail behavior verification: stddev of y-axis must be > 0 (not a robot straight line)
|
||||
function verifyTrail(trail) {
|
||||
if (!trail || trail.length < 5) return false;
|
||||
var sum = 0;
|
||||
for (var i = 0; i < trail.length; i++) sum += trail[i];
|
||||
var avg = sum / trail.length;
|
||||
var variance = 0;
|
||||
for (var j = 0; j < trail.length; j++) variance += (trail[j] - avg) * (trail[j] - avg);
|
||||
var stddev = Math.sqrt(variance / trail.length);
|
||||
return stddev > 0;
|
||||
}
|
||||
|
||||
// Encode trail + position for server verification
|
||||
function encodePayload(trail, spliced) {
|
||||
var str = JSON.stringify({ t: trail, s: Math.round(spliced), ts: Date.now() });
|
||||
try { return btoa(str); } catch (e) { return str; }
|
||||
}
|
||||
|
||||
AksrtSliderCaptcha.prototype.onSuccess = function (trail, spliced) {
|
||||
var self = this;
|
||||
var o = this.options;
|
||||
this.sliderBar.classList.add('sliderContainer_success');
|
||||
this.sliderMask.style.background = '#52c41a';
|
||||
this.text.textContent = o.successText;
|
||||
this.text.style.color = '#52c41a';
|
||||
this.slider.innerHTML = '✓';
|
||||
this.slider.style.color = '#52c41a';
|
||||
this.slider.style.cursor = 'default';
|
||||
|
||||
var payload = encodePayload(trail || [], spliced || 0);
|
||||
|
||||
// Server token verification if endpoint configured
|
||||
if (o.serverVerify) {
|
||||
var ajaxUrl = (window.aksrtData && aksrtData.ajaxUrl) || '/wp-admin/admin-ajax.php';
|
||||
var params = new URLSearchParams();
|
||||
params.set('action', 'aksrt_captcha_verify');
|
||||
if (window.aksrtData && aksrtData.nonce) params.set('nonce', aksrtData.nonce);
|
||||
params.set('payload', payload);
|
||||
if (o.scene) params.set('scene', o.scene);
|
||||
|
||||
fetch(ajaxUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||||
credentials: 'same-origin',
|
||||
body: params.toString()
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (json) {
|
||||
if (json && json.success && json.data && json.data.token) {
|
||||
if (typeof o.onSuccess === 'function') o.onSuccess(json.data.token);
|
||||
} else {
|
||||
self.onFail();
|
||||
}
|
||||
})
|
||||
.catch(function () { self.onFail(); });
|
||||
} else {
|
||||
if (typeof o.onSuccess === 'function') {
|
||||
setTimeout(function () { o.onSuccess(payload); }, 300);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AksrtSliderCaptcha.prototype.onFail = function () {
|
||||
var self = this;
|
||||
var o = this.options;
|
||||
this.sliderBar.classList.add('sliderContainer_fail');
|
||||
this.sliderMask.style.background = '#ff4d4f';
|
||||
this.text.textContent = o.failText;
|
||||
this.text.style.color = '#ff4d4f';
|
||||
this.slider.style.color = '#ff4d4f';
|
||||
|
||||
if (typeof o.onFail === 'function') o.onFail();
|
||||
|
||||
setTimeout(function () {
|
||||
self.sliderBar.classList.remove('sliderContainer_fail');
|
||||
self.reset();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
AksrtSliderCaptcha.prototype.reset = function () {
|
||||
this.slider.style.left = '0px';
|
||||
this.sliderMask.style.width = '0px';
|
||||
this.block.style.left = '0px';
|
||||
this.sliderMask.style.background = 'linear-gradient(90deg,#1890ff,#36cfc9)';
|
||||
this.text.style.color = '#999';
|
||||
this.text.textContent = this.options.loadingText;
|
||||
this.slider.innerHTML = '❯';
|
||||
this.slider.style.color = '';
|
||||
this.slider.style.cursor = 'grab';
|
||||
this.loadCount = 0;
|
||||
this.initImg();
|
||||
};
|
||||
|
||||
// ── Modal wrapper ──
|
||||
|
||||
function SliderCaptchaModal(options) {
|
||||
var overlay = document.createElement('div');
|
||||
overlay.className = 'aksrt-captcha-modal-overlay';
|
||||
var dialog = document.createElement('div');
|
||||
dialog.className = 'aksrt-captcha-modal-dialog';
|
||||
overlay.appendChild(dialog);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
var origSuccess = options.onSuccess;
|
||||
options.onSuccess = function (token) {
|
||||
overlay.classList.remove('is-open');
|
||||
setTimeout(function () { overlay.remove(); }, 300);
|
||||
if (typeof origSuccess === 'function') origSuccess(token);
|
||||
};
|
||||
|
||||
if (!options.setSrc) {
|
||||
options.setSrc = function (cb) {
|
||||
cb('https://picsum.photos/' + (options.width || 280) + '/' + (options.height || 170) + '?random=' + Date.now());
|
||||
};
|
||||
}
|
||||
|
||||
var captcha = new AksrtSliderCaptcha(dialog, options);
|
||||
|
||||
requestAnimationFrame(function () { overlay.classList.add('is-open'); });
|
||||
|
||||
overlay.addEventListener('click', function (e) {
|
||||
if (e.target === overlay) {
|
||||
overlay.classList.remove('is-open');
|
||||
setTimeout(function () { overlay.remove(); }, 300);
|
||||
}
|
||||
});
|
||||
|
||||
return { el: overlay, captcha: captcha };
|
||||
}
|
||||
|
||||
// ── Public API ──
|
||||
|
||||
window.AksrtSliderCaptcha = AksrtSliderCaptcha;
|
||||
window.SliderCaptchaModal = SliderCaptchaModal;
|
||||
|
||||
// ── CSS ──
|
||||
|
||||
var STYLE_ID = 'aksrt-slider-captcha-style';
|
||||
|
||||
function injectStyle() {
|
||||
if (document.getElementById(STYLE_ID)) return;
|
||||
var style = document.createElement('style');
|
||||
style.id = STYLE_ID;
|
||||
style.textContent =
|
||||
'.aksrt-captcha__canvas-wrap{position:relative;overflow:hidden;border-radius:8px;background:#f0f0f0;}' +
|
||||
'.aksrt-captcha__canvas-wrap canvas{display:block;}' +
|
||||
'.aksrt-captcha__canvas-wrap canvas:last-child{position:absolute;top:0;left:0;pointer-events:none;}' +
|
||||
'.aksrt-captcha__bar{position:relative;height:40px;border-radius:20px;background:#e8e8e8;margin-top:10px;user-select:none;}' +
|
||||
'.aksrt-captcha__mask{position:absolute;top:0;left:0;height:100%;border-radius:20px;background:linear-gradient(90deg,#1890ff,#36cfc9);width:0;transition:background 0.3s;}' +
|
||||
'.aksrt-captcha__slider{position:absolute;top:0;left:0;width:44px;height:40px;border-radius:20px;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,0.15);cursor:grab;display:flex;align-items:center;justify-content:center;font-size:18px;z-index:2;transition:box-shadow 0.2s;}' +
|
||||
'.aksrt-captcha__text{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:#999;font-size:14px;pointer-events:none;}';
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', injectStyle);
|
||||
} else {
|
||||
injectStyle();
|
||||
}
|
||||
})();
|
||||