1/** 2 * @license angular-recaptcha build:2018-05-03 3 * https://github.com/vividcortex/angular-recaptcha 4 * Copyright (c) 2018 VividCortex 5**/ 6 7/*global angular, Recaptcha */ 8(function (ng) { 9 'use strict'; 10 11 ng.module('vcRecaptcha', []); 12 13}(angular)); 14 15/*global angular */ 16(function (ng) { 17 'use strict'; 18 19 function throwNoKeyException() { 20 throw new Error('You need to set the "key" attribute to your public reCaptcha key. If you don\'t have a key, please get one from https://www.google.com/recaptcha/admin/create'); 21 } 22 23 var app = ng.module('vcRecaptcha'); 24 25 /** 26 * An angular service to wrap the reCaptcha API 27 */ 28 app.provider('vcRecaptchaService', function(){ 29 var provider = this; 30 var config = {}; 31 provider.onLoadFunctionName = 'vcRecaptchaApiLoaded'; 32 33 /** 34 * Sets the reCaptcha configuration values which will be used by default is not specified in a specific directive instance. 35 * 36 * @since 2.5.0 37 * @param defaults object which overrides the current defaults object. 38 */ 39 provider.setDefaults = function(defaults){ 40 ng.copy(defaults, config); 41 }; 42 43 /** 44 * Sets the reCaptcha key which will be used by default is not specified in a specific directive instance. 45 * 46 * @since 2.5.0 47 * @param siteKey the reCaptcha public key (refer to the README file if you don't know what this is). 48 */ 49 provider.setSiteKey = function(siteKey){ 50 config.key = siteKey; 51 }; 52 53 /** 54 * Sets the reCaptcha theme which will be used by default is not specified in a specific directive instance. 55 * 56 * @since 2.5.0 57 * @param theme The reCaptcha theme. 58 */ 59 provider.setTheme = function(theme){ 60 config.theme = theme; 61 }; 62 63 /** 64 * Sets the reCaptcha stoken which will be used by default is not specified in a specific directive instance. 65 * 66 * @since 2.5.0 67 * @param stoken The reCaptcha stoken. 68 */ 69 provider.setStoken = function(stoken){ 70 config.stoken = stoken; 71 }; 72 73 /** 74 * Sets the reCaptcha size which will be used by default is not specified in a specific directive instance. 75 * 76 * @since 2.5.0 77 * @param size The reCaptcha size. 78 */ 79 provider.setSize = function(size){ 80 config.size = size; 81 }; 82 83 /** 84 * Sets the reCaptcha type which will be used by default is not specified in a specific directive instance. 85 * 86 * @since 2.5.0 87 * @param type The reCaptcha type. 88 */ 89 provider.setType = function(type){ 90 config.type = type; 91 }; 92 93 /** 94 * Sets the reCaptcha language which will be used by default is not specified in a specific directive instance. 95 * 96 * @param lang The reCaptcha language. 97 */ 98 provider.setLang = function(lang){ 99 config.lang = lang; 100 }; 101 102 /** 103 * Sets the reCaptcha badge position which will be used by default if not specified in a specific directive instance. 104 * 105 * @param badge The reCaptcha badge position. 106 */ 107 provider.setBadge = function(badge){ 108 config.badge = badge; 109 }; 110 111 /** 112 * Sets the reCaptcha configuration values which will be used by default is not specified in a specific directive instance. 113 * 114 * @since 2.5.0 115 * @param onLoadFunctionName string name which overrides the name of the onload function. Should match what is in the recaptcha script querystring onload value. 116 */ 117 provider.setOnLoadFunctionName = function(onLoadFunctionName){ 118 provider.onLoadFunctionName = onLoadFunctionName; 119 }; 120 121 provider.$get = ['$rootScope','$window', '$q', '$document', '$interval', function ($rootScope, $window, $q, $document, $interval) { 122 var deferred = $q.defer(), promise = deferred.promise, instances = {}, recaptcha; 123 124 $window.vcRecaptchaApiLoadedCallback = $window.vcRecaptchaApiLoadedCallback || []; 125 126 var callback = function () { 127 recaptcha = $window.grecaptcha; 128 129 deferred.resolve(recaptcha); 130 }; 131 132 $window.vcRecaptchaApiLoadedCallback.push(callback); 133 134 $window[provider.onLoadFunctionName] = function () { 135 $window.vcRecaptchaApiLoadedCallback.forEach(function(callback) { 136 callback(); 137 }); 138 }; 139 140 141 function getRecaptcha() { 142 if (!!recaptcha) { 143 return $q.when(recaptcha); 144 } 145 146 return promise; 147 } 148 149 function validateRecaptchaInstance() { 150 if (!recaptcha) { 151 throw new Error('reCaptcha has not been loaded yet.'); 152 } 153 } 154 155 156 // Check if grecaptcha.render is not defined already. 157 if (ng.isFunction(($window.grecaptcha || {}).render)) { 158 callback(); 159 } else if ($window.document.querySelector('script[src^="https://www.google.com/recaptcha/api.js"]')) { 160 // wait for script to be loaded. 161 var intervalWait = $interval(function() { 162 if (ng.isDefined($window.grecaptcha)) { 163 $interval.cancel(intervalWait); 164 callback(); 165 } 166 }, 25); 167 } else { 168 // Generate link on demand 169 var script = $window.document.createElement('script'); 170 script.async = true; 171 script.defer = true; 172 script.src = 'https://www.google.com/recaptcha/api.js?onload='+provider.onLoadFunctionName+'&render=explicit'; 173 $document.find('body')[0].appendChild(script); 174 } 175 176 return { 177 178 /** 179 * Creates a new reCaptcha object 180 * 181 * @param elm the DOM element where to put the captcha
182 * @param conf the captcha object configuration 183 * @throws NoKeyException if no key is provided in the provider config or the directive instance (via attribute) 184 */ 185 create: function (elm, conf) { 186 187 conf.sitekey = conf.key || config.key; 188 conf.theme = conf.theme || config.theme; 189 conf.stoken = conf.stoken || config.stoken; 190 conf.size = conf.size || config.size; 191 conf.type = conf.type || config.type; 192 conf.hl = conf.lang || config.lang; 193 conf.badge = conf.badge || config.badge; 194 195 if (!conf.sitekey) { 196 throwNoKeyException(); 197 } 198 return getRecaptcha().then(function (recaptcha) { 199 var widgetId = recaptcha.render(elm, conf); 200 instances[widgetId] = elm; 201 return widgetId; 202 }); 203 }, 204 205 /** 206 * Reloads the reCaptcha 207 */ 208 reload: function (widgetId) { 209 validateRecaptchaInstance(); 210 211 recaptcha.reset(widgetId); 212 213 // Let everyone know this widget has been reset. 214 $rootScope.$broadcast('reCaptchaReset', widgetId); 215 }, 216 217 /** 218 * Executes the reCaptcha 219 */ 220 execute: function (widgetId) { 221 validateRecaptchaInstance(); 222 223 recaptcha.execute(widgetId); 224 }, 225 226 /** 227 * Get/Set reCaptcha language 228 */ 229 useLang: function (widgetId, lang) { 230 var instance = instances[widgetId]; 231 232 if (instance) { 233 var iframe = instance.querySelector('iframe'); 234 if (lang) { 235 // Setter 236 if (iframe && iframe.src) { 237 var s = iframe.src; 238 if (/[?&]hl=/.test(s)) { 239 s = s.replace(/([?&]hl=)\w+/, '$1' + lang); 240 } else { 241 s += ((s.indexOf('?') === -1) ? '?' : '&') + 'hl=' + lang; 242 } 243 244 iframe.src = s; 245 } 246 } else { 247 // Getter 248 if (iframe && iframe.src && /[?&]hl=\w+/.test(iframe.src)) { 249 return iframe.src.replace(/.+[?&]hl=(\w+)([^\w].+)?/, '$1'); 250 } else { 251 return null; 252 } 253 } 254 } else { 255 throw new Error('reCaptcha Widget ID not exists', widgetId); 256 } 257 }, 258 259 /** 260 * Gets the response from the reCaptcha widget. 261 * 262 * @see https://developers.google.com/recaptcha/docs/display#js_api 263 * 264 * @returns {String} 265 */ 266 getResponse: function (widgetId) { 267 validateRecaptchaInstance(); 268 269 return recaptcha.getResponse(widgetId); 270 }, 271 272 /** 273 * Gets reCaptcha instance and configuration 274 */ 275 getInstance: function (widgetId) { 276 return instances[widgetId]; 277 }, 278 279 /** 280 * Destroy reCaptcha instance. 281 */ 282 destroy: function (widgetId) { 283 delete instances[widgetId]; 284 } 285 }; 286 287 }]; 288 });
289 290}(angular)); 291 292/*global angular, Recaptcha */ 293(function (ng) { 294 'use strict'; 295 296 var app = ng.module('vcRecaptcha'); 297 298 app.directive('vcRecaptcha', ['$document', '$timeout', 'vcRecaptchaService', function ($document, $timeout, vcRecaptcha) { 299 300 return { 301 restrict: 'A', 302 require: "?^^form", 303 scope: { 304 response: '=?ngModel', 305 key: '=?', 306 stoken: '=?', 307 theme: '=?', 308 size: '=?', 309 type: '=?', 310 lang: '=?', 311 badge: '=?', 312 tabindex: '=?', 313 required: '=?', 314 onCreate: '&', 315 onSuccess: '&', 316 onExpire: '&' 317 }, 318 link: function (scope, elm, attrs, ctrl) { 319 scope.widgetId = null; 320 321 if(ctrl && ng.isDefined(attrs.required)){ 322 scope.$watch('required', validate); 323 } 324 325 var removeCreationListener = scope.$watch('key', function (key) { 326 var callback = function (gRecaptchaResponse) { 327 // Safe $apply 328 $timeout(function () { 329 scope.response = gRecaptchaResponse; 330 validate(); 331 332 // Notify about the response availability 333 scope.onSuccess({response: gRecaptchaResponse, widgetId: scope.widgetId}); 334 }); 335 }; 336 337 vcRecaptcha.create(elm[0], { 338 339 callback: callback, 340 key: key, 341 stoken: scope.stoken || attrs.stoken || null, 342 theme: scope.theme || attrs.theme || null, 343 type: scope.type || attrs.type || null, 344 lang: scope.lang || attrs.lang || null, 345 tabindex: scope.tabindex || attrs.tabindex || null, 346 size: scope.size || attrs.size || null, 347 badge: scope.badge || attrs.badge || null, 348 'expired-callback': expired 349 350 }).then(function (widgetId) { 351 // The widget has been created 352 validate(); 353 scope.widgetId = widgetId; 354 scope.onCreate({widgetId: widgetId}); 355 356 scope.$on('$destroy', destroy); 357 358 scope.$on('reCaptchaReset', function(event, resetWidgetId){ 359 if(ng.isUndefined(resetWidgetId) || widgetId === resetWidgetId){ 360 scope.response = ""; 361 validate(); 362 } 363 }) 364 365 }); 366 367 // Remove this listener to avoid creating the widget more than once. 368 removeCreationListener(); 369 }); 370 371 function destroy() { 372 if (ctrl) { 373 // reset the validity of the form if we were removed 374 ctrl.$setValidity('recaptcha', null); 375 } 376 377 cleanup(); 378 } 379 380 function expired(){ 381 // Safe $apply 382 $timeout(function () { 383 scope.response = ""; 384 validate(); 385 386 // Notify about the response availability 387 scope.onExpire({ widgetId: scope.widgetId }); 388 }); 389 } 390 391 function validate(){ 392 if(ctrl){ 393 ctrl.$setValidity('recaptcha', scope.required === false ? null : Boolean(scope.response)); 394 } 395 } 396 397 function cleanup(){ 398 vcRecaptcha.destroy(scope.widgetId); 399 400 // removes elements reCaptcha added. 401 ng.element($document[0].querySelectorAll('.pls-container')).parent().remove(); 402 } 403 } 404 }; 405 }]); 406 407}(angular));
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.