PageSourceSearch

https://dedecms.com/assets/pkg/captcha/captcha.js?v=1729060935

js dedecms.com collected 2026-10-03 21:45:08 UTC 8,629 bytes, 296 lines download raw bytes

1/**
2 * @Description: 封装Captcha
3 */
4const Captcha = (function () {
5    /**
6     * @Description: 唯一KEY值,用作验证使用
7     */
8    var captchaKey = ""
9    /**
10     * @Description: 用户鼠标点击的位置 x,y
11     */
12    var dots = []
13    /**
14     * @Description: 最大可点数
15     */
16    var maxDot = 8
17
18    const captchaThumbDom = document.querySelector("#wg-cap-thumb")
19    const captchaImageDom = document.querySelector("#wg-cap-image")
20    const captchaWrapDom = document.querySelector("#wg-cap-dots")
21    const captchaRefreshBtnDom = document.querySelector("#wg-cap-refresh-btn")
22    const captchaCheckBtnDom = document.querySelector("#wg-cap-check-btn")
23
24    /**
25     * @Description: 初始化
26     */
27    function __initialize() {
28        handleEvent()
29
30        // 禁用移动端缩放
31        document.addEventListener('touchstart', (event) => {
32            if (event.touches.length > 1) {
33                event.preventDefault()
34            }
35        })
36        document.addEventListener('gesturestart', (event) => {
37            event.preventDefault()
38        })
39        // touchstart  解决:hover伪类在移动端二次点击的问题
40        document.body.addEventListener('touchend', () => { })
41    }
42
43    /**
44     * @Description: 处理所有事件
45     */
46    function handleEvent() {
47        addEventListener(captchaImageDom, "click", handleClickPos)
48        addEventListener(captchaRefreshBtnDom, "click", handleClickRefresh)
49        addEventListener(captchaCheckBtnDom, "click", handleClickCheck)
50    }
51
52    /**
53     * @Description: 为任意元素.绑定任意的事件
54     * @param el    任意的元素
55     * @param type  事件的类型
56     * @param fn    事件处理函数
57     */
58    function addEventListener(el, type, fn) {
59        //判断浏览器是否支持这个方法
60        if (el.addEventListener) {
61            el.addEventListener(type, fn, false);
62        } else if (el.attachEvent) {
63            el.attachEvent("on" + type, fn);
64        } else {
65            el["on" + type] = fn;
66        }
67    }
68
69    /**
70     * @Description: 找到元素的屏幕位置
71     * @param el
72     */
73    function calcLocationLeft(el) {
74        var tmp = el.offsetLeft
75        var val = el.offsetParent
76        while (val != null) {
77            tmp += val.offsetLeft
78            val = val.offsetParent
79        }
80        return tmp
81    }
82
83    /**
84     * @Description: 找到元素的屏幕位置
85     * @param el
86     */
87    function calcLocationTop(el) {
88        var tmp = el.offsetTop
89        var val = el.offsetParent
90        while (val != null) {
91            tmp += val.offsetTop
92            val = val.offsetParent
93        }
94        return tmp
95    }
96
97    /**
98     * @Description: 找到元素的屏幕位置
99     * @param dom
100     */
101    function getDomXY(dom) {
102        var x = 0
103        var y = 0
104        if (dom.getBoundingClientRect) {
105            var box = dom.getBoundingClientRect();
106            var D = document.documentElement;
107            x = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft;
108            y = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop
109        }
110        else {
111            while (dom !== document.body) {
112                x += dom.offsetLeft
113                y += dom.offsetTop
114                dom = dom.offsetParent
115            }
116        }
117        return {
118            domX: x,
119            domY: y
120        }
121    }
122
123    /**
124     * @Description: 插入点击icon大小为22x22
125     * @param event
126     * @param x
127     * @param y
128     */
129    function appendDotIcon(event, x, y) {
130        // const icon = '<div class="wg-cap-wrap__dot" style="position:absolute; top:' + (y * 0.5) + 'px; left:' + (x * 0.5) + 'px;"><span>'+ (dots.length + 1) +'</span></div>'
131        const dot = document.createElement('div')
132        dot.setAttribute('class', 'wg-cap-wrap__dot')
133        dot.setAttribute('style', 'top:' + (y - 11) + 'px; left:' + (x - 11) + 'px;')
134        dot.innerHTML = '<span>' + (dots.length + 1) + '</span>'
135        captchaWrapDom.appendChild(dot)
136
137        dots.push([x, y])
138    }
139
140    /**
141     * @Description: 重置
142     */
143    function resetCaptcha() {
144        captchaKey = ""
145        dots = []
146        captchaWrapDom.innerHTML = ""
147    }
148
149    /**
150     * @Description: 清空验证图片
151     */
152    function clearImage() {
153        captchaThumbDom.setAttribute("src", "")
154        captchaImageDom.setAttribute("src", "")
155    }
156
157    /**
158     * @Description: 处理点击验证码图片位置
159     * @param ev
160     */
161    function handleClickPos(ev) {
162        if (dots.length >= maxDot || captchaKey === "") {
163            return
164        }
165
166        const e = ev || window.event;
167        e.preventDefault()
168        const dom = e.currentTarget
169
170        const xy = getDomXY(dom)
171        const domX = xy.domX
172        const domY = xy.domY
173        // ===============================================
174        // @notice 如 getDomXY 不准确可尝试使用 calcLocationLeft 或 calcLocationTop
175        // const domX = this.calcLocationLeft(dom)
176        // const domY = this.calcLocationTop(dom)
177        // ===============================================
178
179        const mouseX = (navigator.appName === 'Netscape') ? e.pageX : e.x + document.body.scrollLeft
180        const mouseY = (navigator.appName === 'Netscape') ? e.pageY : e.y + document.body.scrollTop
181
182        // 计算点击的相对位置
183        const xPos = mouseX - domX;
184        const yPos = mouseY - domY;
185
186        appendDotIcon(e, parseInt(xPos.toString()), parseInt(yPos.toString()))
187        // appendDotIcon(e, xPos, yPos)
188        e.cancelBubble = true
189        e.preventDefault()
190        return false
191    }
192
193    /**
194     * @Description: 点击刷新
195     */
196    function handleClickRefresh() {
197        requestCaptchaData()
198    }
199
200    /**
201     * @Description: 点击验证
202     */
203    function handleClickCheck() {
204        var dotsA = []
205        dots.forEach(function (value, key) {
206            dotsA.push(value.join(","))
207        })
208
209        if (dotsA.length <= 0) {
210            failInfo("请依次点击图案进行验证");
211            return
212        }
213
214        requestCheckCaptchaData({ 'dots': dotsA.join(','), 'key': captchaKey })
215    }
216
217    /**
218     * @Description: 请求验证码数据
219     */
220    function requestCaptchaData() {
221        resetCaptcha();
222        clearImage();
223
224        captchaThumbDom.classList.add("wg-cap-wrap__hidden");
225        captchaImageDom.classList.add("wg-cap-wrap__hidden");
226
227        $.ajax({
228            method: "GET",
229            url: "/captcha_plus/get",
230            data: "",
231            dataType: "json",
232        }).done(function (resp) {
233            if (resp.code == responseCodeFail) {
234                failInfo(resp.message);
235            }
236            if (resp.code == responseCodeSuccess) {
237                let thumb_base64 = resp.data.thumb_base64;
238                let image_base64 = resp.data.image_base64;
239                let captcha_key = resp.data.captcha_key;
240
241                captchaThumbDom.classList.remove("wg-cap-wrap__hidden");
242                captchaImageDom.classList.remove("wg-cap-wrap__hidden");
243
244                captchaThumbDom.setAttribute("src", thumb_base64);
245                captchaImageDom.setAttribute("src", image_base64);
246                captchaKey = captcha_key;
247            }
248        }).fail(function (jqXHR) {
249            if (!jqXHR.responseJSON) {
250                failInfo("连接服务器失败");
251            } else {
252                failInfo(jqXHR.responseJSON.message);
253            }
254        });
255    }
256
257    /**
258     * @Description: 请求验证数据
259     * @param dots
260     */
261    function requestCheckCaptchaData(dots) {
262        $.ajax({
263            method: "POST",
264            headers: {
265                "CSRFToken": $.cookie("CSRFToken"),
266            },
267            url: "/captcha_plus/check",
268            data: dots,
269            dataType: "json",
270        }).done(function (resp) {
271            if (resp.code == responseCodeFail) {
272                failInfo(resp.message);
273
274                requestCaptchaData();
275            }
276            if (resp.code == responseCodeSuccess) {
277                $("#captcha_id").val(captchaKey);
278                $("#modal_captcha").modal("hide");
279
280                requestCheckCaptchaDataSuccess();
281            }
282        }).fail(function (jqXHR) {
283            if (!jqXHR.responseJSON) {
284                failInfo("连接服务器失败");
285            } else {
286                failInfo(jqXHR.responseJSON.message);
287            }
288        });
289    }
290
291    __initialize()
292
293    return {
294        requestCaptchaData: requestCaptchaData,
295    }
296})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.