1(function () { 2 'use strict'; 3 4 var extend = function () { 5 var length = arguments.length; 6 var target = arguments[0] || {}; 7 if (typeof target != "object" && typeof target != "function") { 8 target = {}; 9 } 10 if (length == 1) { 11 target = this; 12 i--; 13 } 14 for (var i = 1; i < length; i++) { 15 var source = arguments[i]; 16 for (var key in source) { 17 // 使ç¨for inä¼éåæ°ç»ææç坿䏾屿§ï¼å æ¬ååã 18 if (Object.prototype.hasOwnProperty.call(source, key)) { 19 target[key] = source[key]; 20 } 21 } 22 } 23 return target; 24 } 25 26 var isFunction = function isFunction(obj) { 27 return typeof obj === "function" && typeof obj.nodeType !== "number"; 28 }; 29 30 var SliderCaptcha = function (element, options) { 31 this.$element = element; 32 this.options = extend({}, SliderCaptcha.DEFAULTS, options); 33 this.$element.style.position = 'relative'; 34 this.$element.style.width = this.options.width + 'px'; 35 this.$element.style.margin = '0 auto'; 36 this.init(); 37 }; 38 39 SliderCaptcha.VERSION = '1.0'; 40 SliderCaptcha.Author = '[email protected]'; 41 SliderCaptcha.DEFAULTS = { 42 width: 280, // canvas宽度 43 height: 155, // canvasé«åº¦ 44 PI: Math.PI, 45 sliderL: 42, // æ»åè¾¹é¿ 46 sliderR: 9, // æ»ååå¾ 47 offset: 5, // 容éåå·® 48 loadingText: 'Loading...', 49 failedText: 'Essayer de nouveau', 50 barText: 'Glisser pour valider', 51 repeatIcon: 'fa fa-repeat', 52 maxLoadCount: 3, 53 localImages: function () { 54 return 'images/Pic' + Math.round(Math.random() * 4) + '.jpg'; 55 }, 56 verify: function (arr, url) { 57 var ret = false;
58 $.ajax({ 59 url: url, 60 data: { 61 "datas": JSON.stringify(arr), 62 }, 63 dataType: "json", 64 type: "post", 65 async: false, 66 success: function (result) { 67 ret = JSON.stringify(result); 68 console.log("Result: " + ret) 69 } 70 }); 71 return ret; 72 }, 73 remoteUrl: null 74 }; 75 76 function Plugin(option) { 77 var $this = document.getElementById(option.id); 78 var options = typeof option === 'object' && option; 79 return new SliderCaptcha($this, options); 80 } 81 82 window.sliderCaptcha = Plugin; 83 window.sliderCaptcha.Constructor = SliderCaptcha; 84 85 var _proto = SliderCaptcha.prototype; 86 _proto.init = function () { 87 this.initDOM(); 88 this.initImg(); 89 this.bindEvents(); 90 }; 91 92 _proto.initDOM = function () { 93 var createElement = function (tagName, className) { 94 var elment = document.createElement(tagName); 95 elment.className = className; 96 return elment; 97 }; 98 99 var createCanvas = function (width, height) { 100 var canvas = document.createElement('canvas'); 101 canvas.width = width; 102 canvas.height = height; 103 return canvas; 104 }; 105 106 var canvas = createCanvas(this.options.width - 2, this.options.height); // ç»å¸ 107 var block = canvas.cloneNode(true); // æ»å 108 var sliderContainer = createElement('div', 'sliderContainer'); 109 var refreshIcon = createElement('i', 'refreshIcon ' + this.options.repeatIcon); 110 var sliderMask = createElement('div', 'sliderMask'); 111 var sliderbg = createElement('div', 'sliderbg'); 112 var slider = createElement('div', 'slider'); 113 var sliderIcon = createElement('i', 'fa fa-arrow-right sliderIcon'); 114 var text = createElement('span', 'sliderText'); 115 116 block.className = 'block'; 117 text.innerHTML = this.options.barText; 118 119 var el = this.$element; 120 el.appendChild(canvas); 121 el.appendChild(refreshIcon); 122 el.appendChild(block); 123 slider.appendChild(sliderIcon); 124 sliderMask.appendChild(slider); 125 sliderContainer.appendChild(sliderbg); 126 sliderContainer.appendChild(sliderMask); 127 sliderContainer.appendChild(text); 128 el.appendChild(sliderContainer); 129 130 var _canvas = { 131 canvas: canvas, 132 block: block, 133 sliderContainer: sliderContainer, 134 refreshIcon: refreshIcon, 135 slider: slider, 136 sliderMask: sliderMask, 137 sliderIcon: sliderIcon, 138 text: text, 139 canvasCtx: canvas.getContext('2d'), 140 blockCtx: block.getContext('2d') 141 }; 142 143 if (isFunction(Object.assign)) { 144 Object.assign(this, _canvas); 145 } 146 else { 147 extend(this, _canvas); 148 } 149 }; 150 151 _proto.initImg = function () { 152 var that = this; 153 var isIE = window.navigator.userAgent.indexOf('Trident') > -1; 154 var L = this.options.sliderL + this.options.sliderR * 2 + 3; // æ»åå®é è¾¹é¿ 155 var drawImg = function (ctx, operation) { 156 var l = that.options.sliderL; 157 var r = that.options.sliderR; 158 var PI = that.options.PI; 159 var x = that.x; 160 var y = that.y; 161 ctx.beginPath(); 162 ctx.moveTo(x, y); 163 ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI); 164 ctx.lineTo(x + l, y); 165 ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI); 166 ctx.lineTo(x + l, y + l); 167 ctx.lineTo(x, y + l); 168 ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true); 169 ctx.lineTo(x, y); 170 ctx.lineWidth = 2; 171 ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'; 172 ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)'; 173 ctx.stroke(); 174 ctx[operation](); 175 ctx.globalCompositeOperation = isIE ? 'xor' : 'destination-over'; 176 }; 177 178 var getRandomNumberByRange = function (start, end) { 179 return Math.round(Math.random() * (end - start) + start); 180 }; 181 var img = new Image(); 182 img.crossOrigin = "Anonymous"; 183 var loadCount = 0; 184 img.onload = function () { 185 // éæºå建æ»åçä½ç½® 186 that.x = getRandomNumberByRange(L + 10, that.options.width - (L + 10)); 187 that.y = getRandomNumberByRange(10 + that.options.sliderR * 2, that.options.height - (L + 10)); 188 drawImg(that.canvasCtx, 'fill'); 189 drawImg(that.blockCtx, 'clip'); 190 191 that.canvasCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height); 192 that.blockCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height); 193 var y = that.y - that.options.sliderR * 2 - 1; 194 var ImageData = that.blockCtx.getImageData(that.x - 3, y, L, L); 195 that.block.width = L; 196 that.blockCtx.putImageData(ImageData, 0, y + 1); 197 that.text.textContent = that.text.getAttribute('data-text'); 198 }; 199 img.onerror = function () { 200 loadCount++; 201 if (window.location.protocol === 'file:') { 202 loadCount = that.options.maxLoadCount; 203 console.error("can't load pic resource file from File protocal. Please try http or https"); 204 } 205 if (loadCount >= that.options.maxLoadCount) { 206 that.text.textContent = 'å 载失败'; 207 that.classList.add('text-danger'); 208 return; 209 } 210 img.src = that.options.localImages(); 211 }; 212 img.setSrc = function () { 213 var src = ''; 214 loadCount = 0; 215 that.text.classList.remove('text-danger'); 216 if (isFunction(that.options.setSrc)) src = that.options.setSrc(); 217 if (!src || src === '') src = 'https://picsum.photos/' + that.options.width + '/' + that.options.height + '/?image=' + Math.round(Math.random() * 20); 218 if (isIE) { // IEæµè§å¨æ æ³éè¿img.crossOriginè·¨åï¼ä½¿ç¨ajaxè·åå¾çblobç¶å转为dataURLæ¾ç¤º 219 var xhr = new XMLHttpRequest(); 220 xhr.onloadend = function (e) { 221 var file = new FileReader(); // FileReaderä» æ¯æIE10+
222 file.readAsDataURL(e.target.response); 223 file.onloadend = function (e) { 224 img.src = e.target.result; 225 }; 226 }; 227 xhr.open('GET', src); 228 xhr.responseType = 'blob'; 229 xhr.send(); 230 } else img.src = src; 231 }; 232 img.setSrc(); 233 this.text.setAttribute('data-text', this.options.barText); 234 this.text.textContent = this.options.loadingText; 235 this.img = img; 236 }; 237 238 _proto.clean = function () { 239 this.canvasCtx.clearRect(0, 0, this.options.width, this.options.height); 240 this.blockCtx.clearRect(0, 0, this.options.width, this.options.height); 241 this.block.width = this.options.width; 242 }; 243 244 _proto.bindEvents = function () { 245 var that = this; 246 this.$element.addEventListener('selectstart', function () { 247 return false; 248 }); 249 250 this.refreshIcon.addEventListener('click', function () { 251 that.text.textContent = that.options.barText; 252 that.reset(); 253 if (isFunction(that.options.onRefresh)) that.options.onRefresh.call(that.$element); 254 }); 255 256 var originX, originY, trail = [], 257 isMouseDown = false; 258 259 var handleDragStart = function (e) { 260 if (that.text.classList.contains('text-danger')) return; 261 originX = e.clientX || e.touches[0].clientX; 262 originY = e.clientY || e.touches[0].clientY; 263 isMouseDown = true; 264 }; 265 266 var handleDragMove = function (e) { 267 if (!isMouseDown) return false; 268 var eventX = e.clientX || e.touches[0].clientX; 269 var eventY = e.clientY || e.touches[0].clientY; 270 var moveX = eventX - originX; 271 var moveY = eventY - originY; 272 if (moveX < 0 || moveX + 40 > that.options.width) return false; 273 that.slider.style.left = (moveX - 1) + 'px'; 274 var blockLeft = (that.options.width - 40 - 20) / (that.options.width - 40) * moveX; 275 that.block.style.left = blockLeft + 'px'; 276 277 that.sliderContainer.classList.add('sliderContainer_active'); 278 that.sliderMask.style.width = (moveX + 4) + 'px'; 279 trail.push(Math.round(moveY)); 280 }; 281 282 var handleDragEnd = function (e) { 283 if (!isMouseDown) return false; 284 isMouseDown = false; 285 var eventX = e.clientX || e.changedTouches[0].clientX; 286 if (eventX === originX) return false; 287 that.sliderContainer.classList.remove('sliderContainer_active'); 288 that.trail = trail; 289 var data = that.verify(); 290 if (data.spliced && data.verified) { 291 that.sliderContainer.classList.add('sliderContainer_success'); 292 if (isFunction(that.options.onSuccess)) that.options.onSuccess.call(that.$element); 293 } else { 294 that.sliderContainer.classList.add('sliderContainer_fail'); 295 if (isFunction(that.options.onFail)) that.options.onFail.call(that.$element); 296 setTimeout(function () { 297 that.text.innerHTML = that.options.failedText; 298 that.reset(); 299 }, 1000); 300 } 301 }; 302 303 this.slider.addEventListener('mousedown', handleDragStart); 304 this.slider.addEventListener('touchstart', handleDragStart); 305 document.addEventListener('mousemove', handleDragMove); 306 document.addEventListener('touchmove', handleDragMove); 307 document.addEventListener('mouseup', handleDragEnd); 308 document.addEventListener('touchend', handleDragEnd); 309 310 document.addEventListener('mousedown', function () { return false; }); 311 document.addEventListener('touchstart', function () { return false; }); 312 document.addEventListener('swipe', function () { return false; }); 313 }; 314 315 _proto.verify = function () { 316 var arr = this.trail; // æå¨æ¶yè½´çç§»å¨è·ç¦» 317 var left = parseInt(this.block.style.left); 318 var verified = false;
319 if (this.options.remoteUrl !== null) { 320 verified = this.options.verify(arr, this.options.remoteUrl); 321 } 322 else { 323 var sum = function (x, y) { return x + y; }; 324 var square = function (x) { return x * x; }; 325 var average = arr.reduce(sum) / arr.length; 326 var deviations = arr.map(function (x) { return x - average; }); 327 var stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length); 328 verified = stddev !== 0; 329 } 330 return { 331 spliced: Math.abs(left - this.x) < this.options.offset, 332 verified: verified 333 }; 334 }; 335 336 _proto.reset = function () { 337 this.sliderContainer.classList.remove('sliderContainer_fail'); 338 this.sliderContainer.classList.remove('sliderContainer_success'); 339 this.slider.style.left = 0; 340 this.block.style.left = 0; 341 this.sliderMask.style.width = 0; 342 this.clean(); 343 this.text.setAttribute('data-text', this.text.textContent); 344 this.text.textContent = this.options.loadingText; 345 this.img.setSrc(); 346 }; 347})();
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.