1/// NG-DELAY by Brent Vane and others 2/// Used as an attribute to help add a delay from user input on ng-change events 3/// https://github.com/brentvatne/angular-delay/blob/master/src/angular-delay.js 4/// Sample ==> <input ng-model="search" ng-change="updateResults()" ng-delay="1500" /> 5(function (window, angular, undefined) { 6 'use strict'; 7 angular.module('ngDelay', []) 8 .directive('ngDelay', ['$timeout', function ($timeout) { 9 return { 10 restrict: 'A', 11 scope: true, 12 compile: function (element, attributes) { 13 var expression = attributes['ngChange']; 14 if (!expression) 15 return; 16 var ngModel = attributes['ngModel']; 17 if (ngModel) attributes['ngModel'] = '$parent.' + ngModel; 18 attributes['ngChange'] = '$$delay.execute()'; 19 return { 20 post: function (scope, element, attributes) { 21 scope.$$delay = { 22 expression: expression, 23 delay: scope.$eval(attributes['ngDelay']), 24 execute: function () { 25 var state = scope.$$delay; 26 state.then = Date.now(); 27 $timeout(function () { 28 if (Date.now() - state.then >= state.delay) 29 scope.$parent.$eval(expression); 30 }, state.delay); 31 } 32 }; 33 } 34 } 35 } 36 }; 37 }]); 38})(window, window.angular); 39/** 40 * @license AngularJS v1.8.2
vendor: 25,829 bytes, lines 40-730
40 41 * (c) 2010-2020 Google LLC. http://angularjs.org 42 * License: MIT 43 */ 44(function(window, angular) {'use strict'; 45 46/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 47 * Any commits to this file should be reviewed with security in mind. * 48 * Changes to this file can potentially create security vulnerabilities. * 49 * An approval from 2 Core members with history of modifying * 50 * this file is required. * 51 * * 52 * Does the change somehow allow for arbitrary javascript to be executed? * 53 * Or allows for someone to change the prototype of built-in objects? * 54 * Or gives undesired access to variables likes document or window? * 55 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 56 57var $sanitizeMinErr = angular.$$minErr('$sanitize'); 58var bind; 59var extend; 60var forEach; 61var isArray; 62var isDefined; 63var lowercase; 64var noop; 65var nodeContains; 66var htmlParser; 67var htmlSanitizeWriter; 68 69/** 70 * @ngdoc module 71 * @name ngSanitize 72 * @description 73 * 74 * The `ngSanitize` module provides functionality to sanitize HTML. 75 * 76 * See {@link ngSanitize.$sanitize `$sanitize`} for usage. 77 */ 78 79/** 80 * @ngdoc service 81 * @name $sanitize 82 * @kind function 83 * 84 * @description 85 * Sanitizes an html string by stripping all potentially dangerous tokens. 86 * 87 * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a trusted URI list) are 88 * then serialized back to a properly escaped HTML string. This means that no unsafe input can make 89 * it into the returned string. 90 * 91 * The trusted URIs for URL sanitization of attribute values is configured using the functions 92 * `aHrefSanitizationTrustedUrlList` and `imgSrcSanitizationTrustedUrlList` of {@link $compileProvider}. 93 * 94 * The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}. 95 * 96 * @param {string} html HTML input. 97 * @returns {string} Sanitized HTML. 98 * 99 * @example 100 <example module="sanitizeExample" deps="angular-sanitize.js" name="sanitize-service"> 101 <file name="index.html"> 102 <script> 103 angular.module('sanitizeExample', ['ngSanitize']) 104 .controller('ExampleController', ['$scope', '$sce', function($scope, $sce) { 105 $scope.snippet = 106 '<p style="color:blue">an html\n' + 107 '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' + 108 'snippet</p>'; 109 $scope.deliberatelyTrustDangerousSnippet = function() { 110 return $sce.trustAsHtml($scope.snippet); 111 }; 112 }]); 113 </script> 114 <div ng-controller="ExampleController"> 115 Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea> 116 <table> 117 <tr> 118 <td>Directive</td> 119 <td>How</td> 120 <td>Source</td> 121 <td>Rendered</td> 122 </tr> 123 <tr id="bind-html-with-sanitize"> 124 <td>ng-bind-html</td> 125 <td>Automatically uses $sanitize</td> 126 <td><pre><div ng-bind-html="snippet"><br/></div></pre></td> 127 <td><div ng-bind-html="snippet"></div></td> 128 </tr> 129 <tr id="bind-html-with-trust"> 130 <td>ng-bind-html</td> 131 <td>Bypass $sanitize by explicitly trusting the dangerous value</td> 132 <td> 133 <pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()"> 134</div></pre> 135 </td> 136 <td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td> 137 </tr> 138 <tr id="bind-default"> 139 <td>ng-bind</td> 140 <td>Automatically escapes</td> 141 <td><pre><div ng-bind="snippet"><br/></div></pre></td> 142 <td><div ng-bind="snippet"></div></td> 143 </tr> 144 </table> 145 </div> 146 </file> 147 <file name="protractor.js" type="protractor"> 148 it('should sanitize the html snippet by default', function() { 149 expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')). 150 toBe('<p>an html\n<em>click here</em>\nsnippet</p>'); 151 }); 152 153 it('should inline raw snippet if bound to a trusted value', function() { 154 expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')). 155 toBe("<p style=\"color:blue\">an html\n" + 156 "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + 157 "snippet</p>"); 158 }); 159 160 it('should escape snippet without any filter', function() { 161 expect(element(by.css('#bind-default div')).getAttribute('innerHTML')). 162 toBe("<p style=\"color:blue\">an html\n" + 163 "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + 164 "snippet</p>"); 165 }); 166 167 it('should update', function() { 168 element(by.model('snippet')).clear(); 169 element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>'); 170 expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')). 171 toBe('new <b>text</b>'); 172 expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe( 173 'new <b onclick="alert(1)">text</b>'); 174 expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe( 175 "new <b onclick=\"alert(1)\">text</b>"); 176 }); 177 </file> 178 </example> 179 */ 180 181 182/** 183 * @ngdoc provider 184 * @name $sanitizeProvider 185 * @this 186 * 187 * @description 188 * Creates and configures {@link $sanitize} instance. 189 */ 190function $SanitizeProvider() { 191 var hasBeenInstantiated = false; 192 var svgEnabled = false; 193 194 this.$get = ['$$sanitizeUri', function($$sanitizeUri) { 195 hasBeenInstantiated = true; 196 if (svgEnabled) { 197 extend(validElements, svgElements); 198 } 199 return function(html) { 200 var buf = []; 201 htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { 202 return !/^unsafe:/.test($$sanitizeUri(uri, isImage)); 203 })); 204 return buf.join(''); 205 }; 206 }]; 207 208 209 /** 210 * @ngdoc method 211 * @name $sanitizeProvider#enableSvg 212 * @kind function 213 * 214 * @description 215 * Enables a subset of svg to be supported by the sanitizer. 216 * 217 * <div class="alert alert-warning"> 218 * <p>By enabling this setting without taking other precautions, you might expose your 219 * application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned 220 * outside of the containing element and be rendered over other elements on the page (e.g. a login 221 * link). Such behavior can then result in phishing incidents.</p> 222 * 223 * <p>To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg 224 * tags within the sanitized content:</p> 225 * 226 * <br> 227 * 228 * <pre><code> 229 * .rootOfTheIncludedContent svg { 230 * overflow: hidden !important; 231 * } 232 * </code></pre> 233 * </div> 234 * 235 * @param {boolean=} flag Enable or disable SVG support in the sanitizer. 236 * @returns {boolean|$sanitizeProvider} Returns the currently configured value if called 237 * without an argument or self for chaining otherwise. 238 */ 239 this.enableSvg = function(enableSvg) { 240 if (isDefined(enableSvg)) { 241 svgEnabled = enableSvg; 242 return this; 243 } else { 244 return svgEnabled; 245 } 246 }; 247 248 249 /** 250 * @ngdoc method 251 * @name $sanitizeProvider#addValidElements 252 * @kind function 253 * 254 * @description 255 * Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe 256 * and are not stripped off during sanitization. You can extend the following lists of elements: 257 * 258 * - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML 259 * elements. HTML elements considered safe will not be removed during sanitization. All other 260 * elements will be stripped off. 261 * 262 * - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as 263 * "void elements" (similar to HTML 264 * [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These 265 * elements have no end tag and cannot have content. 266 * 267 * - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only 268 * taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for 269 * `$sanitize`. 270 * 271 * <div class="alert alert-info"> 272 * This method must be called during the {@link angular.Module#config config} phase. Once the 273 * `$sanitize` service has been instantiated, this method has no effect. 274 * </div> 275 * 276 * <div class="alert alert-warning"> 277 * Keep in mind that extending the built-in lists of elements may expose your app to XSS or 278 * other vulnerabilities. Be very mindful of the elements you add. 279 * </div> 280 * 281 * @param {Array<String>|Object} elements - A list of valid HTML elements or an object with one or 282 * more of the following properties: 283 * - **htmlElements** - `{Array<String>}` - A list of elements to extend the current list of 284 * HTML elements. 285 * - **htmlVoidElements** - `{Array<String>}` - A list of elements to extend the current list of 286 * void HTML elements; i.e. elements that do not have an end tag. 287 * - **svgElements** - `{Array<String>}` - A list of elements to extend the current list of SVG 288 * elements. The list of SVG elements is only taken into account if SVG is 289 * {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`. 290 * 291 * Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`. 292 * 293 * @return {$sanitizeProvider} Returns self for chaining. 294 */ 295 this.addValidElements = function(elements) { 296 if (!hasBeenInstantiated) { 297 if (isArray(elements)) { 298 elements = {htmlElements: elements}; 299 } 300 301 addElementsTo(svgElements, elements.svgElements); 302 addElementsTo(voidElements, elements.htmlVoidElements); 303 addElementsTo(validElements, elements.htmlVoidElements); 304 addElementsTo(validElements, elements.htmlElements); 305 } 306 307 return this; 308 }; 309 310 311 /** 312 * @ngdoc method 313 * @name $sanitizeProvider#addValidAttrs 314 * @kind function 315 * 316 * @description 317 * Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are 318 * not stripped off during sanitization. 319 * 320 * **Note**: 321 * The new attributes will not be treated as URI attributes, which means their values will not be 322 * sanitized as URIs using `$compileProvider`'s 323 * {@link ng.$compileProvider#aHrefSanitizationTrustedUrlList aHrefSanitizationTrustedUrlList} and 324 * {@link ng.$compileProvider#imgSrcSanitizationTrustedUrlList imgSrcSanitizationTrustedUrlList}. 325 * 326 * <div class="alert alert-info"> 327 * This method must be called during the {@link angular.Module#config config} phase. Once the 328 * `$sanitize` service has been instantiated, this method has no effect. 329 * </div> 330 * 331 * <div class="alert alert-warning"> 332 * Keep in mind that extending the built-in list of attributes may expose your app to XSS or 333 * other vulnerabilities. Be very mindful of the attributes you add. 334 * </div> 335 * 336 * @param {Array<String>} attrs - A list of valid attributes. 337 * 338 * @returns {$sanitizeProvider} Returns self for chaining. 339 */ 340 this.addValidAttrs = function(attrs) { 341 if (!hasBeenInstantiated) { 342 extend(validAttrs, arrayToMap(attrs, true)); 343 } 344 return this; 345 }; 346 347 ////////////////////////////////////////////////////////////////////////////////////////////////// 348 // Private stuff 349 ////////////////////////////////////////////////////////////////////////////////////////////////// 350 351 bind = angular.bind; 352 extend = angular.extend; 353 forEach = angular.forEach; 354 isArray = angular.isArray; 355 isDefined = angular.isDefined; 356 lowercase = angular.$$lowercase; 357 noop = angular.noop; 358 359 htmlParser = htmlParserImpl; 360 htmlSanitizeWriter = htmlSanitizeWriterImpl; 361 362 nodeContains = window.Node.prototype.contains || /** @this */ function(arg) { 363 // eslint-disable-next-line no-bitwise 364 return !!(this.compareDocumentPosition(arg) & 16); 365 }; 366 367 // Regular Expressions for parsing tags and attributes 368 var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 369 // Match everything outside of normal chars and " (quote character) 370 NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g; 371 372 373 // Good source of info about elements and attributes 374 // http://dev.w3.org/html5/spec/Overview.html#semantics 375 // http://simon.html5.org/html-elements 376 377 // Safe Void Elements - HTML5 378 // http://dev.w3.org/html5/spec/Overview.html#void-elements 379 var voidElements = stringToMap('area,br,col,hr,img,wbr'); 380 381 // Elements that you can, intentionally, leave open (and which close themselves) 382 // http://dev.w3.org/html5/spec/Overview.html#optional-tags 383 var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'), 384 optionalEndTagInlineElements = stringToMap('rp,rt'), 385 optionalEndTagElements = extend({}, 386 optionalEndTagInlineElements, 387 optionalEndTagBlockElements); 388 389 // Safe Block Elements - HTML5 390 var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('address,article,' + 391 'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' + 392 'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul')); 393 394 // Inline Elements - HTML5 395 var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('a,abbr,acronym,b,' + 396 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,' + 397 'samp,small,span,strike,strong,sub,sup,time,tt,u,var')); 398 399 // SVG Elements 400 // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements 401 // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted. 402 // They can potentially allow for arbitrary javascript to be executed. See #11290 403 var svgElements = stringToMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' + 404 'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,' + 405 'radialGradient,rect,stop,svg,switch,text,title,tspan'); 406 407 // Blocked Elements (will be stripped) 408 var blockedElements = stringToMap('script,style'); 409 410 var validElements = extend({}, 411 voidElements, 412 blockElements, 413 inlineElements, 414 optionalEndTagElements); 415 416 //Attributes that have href and hence need to be sanitized 417 var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base'); 418 419 var htmlAttrs = stringToMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + 420 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + 421 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + 422 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' + 423 'valign,value,vspace,width'); 424 425 // SVG attributes (without "id" and "name" attributes) 426 // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes 427 var svgAttrs = stringToMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + 428 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' + 429 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' + 430 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' + 431 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' + 432 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' + 433 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' + 434 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' + 435 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' + 436 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' + 437 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' + 438 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' + 439 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' + 440 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' + 441 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true); 442 443 var validAttrs = extend({}, 444 uriAttrs, 445 svgAttrs, 446 htmlAttrs); 447 448 function stringToMap(str, lowercaseKeys) { 449 return arrayToMap(str.split(','), lowercaseKeys); 450 } 451 452 function arrayToMap(items, lowercaseKeys) { 453 var obj = {}, i; 454 for (i = 0; i < items.length; i++) { 455 obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true; 456 } 457 return obj; 458 } 459 460 function addElementsTo(elementsMap, newElements) { 461 if (newElements && newElements.length) { 462 extend(elementsMap, arrayToMap(newElements)); 463 } 464 } 465 466 /** 467 * Create an inert document that contains the dirty HTML that needs sanitizing. 468 * We use the DOMParser API by default and fall back to createHTMLDocument if DOMParser is not 469 * available. 470 */ 471 var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) { 472 if (isDOMParserAvailable()) { 473 return getInertBodyElement_DOMParser; 474 } 475 476 if (!document || !document.implementation) { 477 throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document'); 478 } 479 var inertDocument = document.implementation.createHTMLDocument('inert'); 480 var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body'); 481 return getInertBodyElement_InertDocument; 482 483 function isDOMParserAvailable() { 484 try { 485 return !!getInertBodyElement_DOMParser(''); 486 } catch (e) { 487 return false; 488 } 489 } 490 491 function getInertBodyElement_DOMParser(html) { 492 // We add this dummy element to ensure that the rest of the content is parsed as expected 493 // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag. 494 html = '<remove></remove>' + html; 495 try { 496 var body = new window.DOMParser().parseFromString(html, 'text/html').body; 497 body.firstChild.remove(); 498 return body; 499 } catch (e) { 500 return undefined; 501 } 502 } 503 504 function getInertBodyElement_InertDocument(html) { 505 inertBodyElement.innerHTML = html; 506 507 // Support: IE 9-11 only 508 // strip custom-namespaced attributes on IE<=11 509 if (document.documentMode) { 510 stripCustomNsAttrs(inertBodyElement); 511 } 512 513 return inertBodyElement; 514 } 515 })(window, window.document); 516 517 /** 518 * @example 519 * htmlParser(htmlString, { 520 * start: function(tag, attrs) {}, 521 * end: function(tag) {}, 522 * chars: function(text) {}, 523 * comment: function(text) {} 524 * }); 525 * 526 * @param {string} html string 527 * @param {object} handler 528 */ 529 function htmlParserImpl(html, handler) { 530 if (html === null || html === undefined) { 531 html = ''; 532 } else if (typeof html !== 'string') { 533 html = '' + html; 534 } 535 536 var inertBodyElement = getInertBodyElement(html); 537 if (!inertBodyElement) return ''; 538 539 //mXSS protection 540 var mXSSAttempts = 5; 541 do { 542 if (mXSSAttempts === 0) { 543 throw $sanitizeMinErr('uinput', 'Failed to sanitize html because the input is unstable'); 544 } 545 mXSSAttempts--; 546 547 // trigger mXSS if it is going to happen by reading and writing the innerHTML 548 html = inertBodyElement.innerHTML; 549 inertBodyElement = getInertBodyElement(html); 550 } while (html !== inertBodyElement.innerHTML); 551 552 var node = inertBodyElement.firstChild; 553 while (node) { 554 switch (node.nodeType) { 555 case 1: // ELEMENT_NODE 556 handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes)); 557 break; 558 case 3: // TEXT NODE 559 handler.chars(node.textContent); 560 break; 561 } 562 563 var nextNode; 564 if (!(nextNode = node.firstChild)) { 565 if (node.nodeType === 1) { 566 handler.end(node.nodeName.toLowerCase()); 567 } 568 nextNode = getNonDescendant('nextSibling', node); 569 if (!nextNode) { 570 while (nextNode == null) { 571 node = getNonDescendant('parentNode', node); 572 if (node === inertBodyElement) break; 573 nextNode = getNonDescendant('nextSibling', node); 574 if (node.nodeType === 1) { 575 handler.end(node.nodeName.toLowerCase()); 576 } 577 } 578 } 579 } 580 node = nextNode; 581 } 582 583 while ((node = inertBodyElement.firstChild)) { 584 inertBodyElement.removeChild(node); 585 } 586 } 587 588 function attrToMap(attrs) { 589 var map = {}; 590 for (var i = 0, ii = attrs.length; i < ii; i++) { 591 var attr = attrs[i]; 592 map[attr.name] = attr.value; 593 } 594 return map; 595 } 596 597 598 /** 599 * Escapes all potentially dangerous characters, so that the 600 * resulting string can be safely inserted into attribute or 601 * element text. 602 * @param value 603 * @returns {string} escaped text 604 */ 605 function encodeEntities(value) { 606 return value. 607 replace(/&/g, '&'). 608 replace(SURROGATE_PAIR_REGEXP, function(value) { 609 var hi = value.charCodeAt(0); 610 var low = value.charCodeAt(1); 611 return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'; 612 }). 613 replace(NON_ALPHANUMERIC_REGEXP, function(value) { 614 return '&#' + value.charCodeAt(0) + ';'; 615 }). 616 replace(/</g, '<'). 617 replace(/>/g, '>'); 618 } 619 620 /** 621 * create an HTML/XML writer which writes to buffer 622 * @param {Array} buf use buf.join('') to get out sanitized html string 623 * @returns {object} in the form of { 624 * start: function(tag, attrs) {}, 625 * end: function(tag) {}, 626 * chars: function(text) {}, 627 * comment: function(text) {} 628 * } 629 */ 630 function htmlSanitizeWriterImpl(buf, uriValidator) { 631 var ignoreCurrentElement = false; 632 var out = bind(buf, buf.push); 633 return { 634 start: function(tag, attrs) { 635 tag = lowercase(tag); 636 if (!ignoreCurrentElement && blockedElements[tag]) { 637 ignoreCurrentElement = tag; 638 } 639 if (!ignoreCurrentElement && validElements[tag] === true) { 640 out('<'); 641 out(tag); 642 forEach(attrs, function(value, key) { 643 var lkey = lowercase(key); 644 var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); 645 if (validAttrs[lkey] === true && 646 (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { 647 out(' '); 648 out(key); 649 out('="'); 650 out(encodeEntities(value)); 651 out('"'); 652 } 653 }); 654 out('>'); 655 } 656 }, 657 end: function(tag) { 658 tag = lowercase(tag); 659 if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) { 660 out('</'); 661 out(tag); 662 out('>'); 663 } 664 // eslint-disable-next-line eqeqeq 665 if (tag == ignoreCurrentElement) { 666 ignoreCurrentElement = false; 667 } 668 }, 669 chars: function(chars) { 670 if (!ignoreCurrentElement) { 671 out(encodeEntities(chars)); 672 } 673 } 674 }; 675 } 676 677 678 /** 679 * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare 680 * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want 681 * to allow any of these custom attributes. This method strips them all. 682 * 683 * @param node Root element to process 684 */ 685 function stripCustomNsAttrs(node) { 686 while (node) { 687 if (node.nodeType === window.Node.ELEMENT_NODE) { 688 var attrs = node.attributes; 689 for (var i = 0, l = attrs.length; i < l; i++) { 690 var attrNode = attrs[i]; 691 var attrName = attrNode.name.toLowerCase(); 692 if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) { 693 node.removeAttributeNode(attrNode); 694 i--; 695 l--; 696 } 697 } 698 } 699 700 var nextNode = node.firstChild; 701 if (nextNode) { 702 stripCustomNsAttrs(nextNode); 703 } 704 705 node = getNonDescendant('nextSibling', node); 706 } 707 } 708 709 function getNonDescendant(propName, node) { 710 // An element is clobbered if its `propName` property points to one of its descendants 711 var nextNode = node[propName]; 712 if (nextNode && nodeContains.call(node, nextNode)) { 713 throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText); 714 } 715 return nextNode; 716 } 717} 718 719function sanitizeText(chars) { 720 var buf = []; 721 var writer = htmlSanitizeWriter(buf, noop); 722 writer.chars(chars); 723 return buf.join(''); 724} 725 726 727// define ngSanitize module and register $sanitize service 728angular.module('ngSanitize', []) 729 .provider('$sanitize', $SanitizeProvider) 730 .info({ angularVersion: '1.8.
7302
vendor: 7,335 bytes, lines 730-929
730' }); 731 732/** 733 * @ngdoc filter 734 * @name linky 735 * @kind function 736 * 737 * @description 738 * Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and 739 * plain email address links. 740 * 741 * Requires the {@link ngSanitize `ngSanitize`} module to be installed. 742 * 743 * @param {string} text Input text. 744 * @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in. 745 * @param {object|function(url)} [attributes] Add custom attributes to the link element. 746 * 747 * Can be one of: 748 * 749 * - `object`: A map of attributes 750 * - `function`: Takes the url as a parameter and returns a map of attributes 751 * 752 * If the map of attributes contains a value for `target`, it overrides the value of 753 * the target parameter. 754 * 755 * 756 * @returns {string} Html-linkified and {@link $sanitize sanitized} text. 757 * 758 * @usage 759 <span ng-bind-html="linky_expression | linky"></span> 760 * 761 * @example 762 <example module="linkyExample" deps="angular-sanitize.js" name="linky-filter"> 763 <file name="index.html"> 764 <div ng-controller="ExampleController"> 765 Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea> 766 <table> 767 <tr> 768 <th>Filter</th> 769 <th>Source</th> 770 <th>Rendered</th> 771 </tr> 772 <tr id="linky-filter"> 773 <td>linky filter</td> 774 <td> 775 <pre><div ng-bind-html="snippet | linky"><br></div></pre> 776 </td> 777 <td> 778 <div ng-bind-html="snippet | linky"></div> 779 </td> 780 </tr> 781 <tr id="linky-target"> 782 <td>linky target</td> 783 <td> 784 <pre><div ng-bind-html="snippetWithSingleURL | linky:'_blank'"><br></div></pre> 785 </td> 786 <td> 787 <div ng-bind-html="snippetWithSingleURL | linky:'_blank'"></div> 788 </td> 789 </tr> 790 <tr id="linky-custom-attributes"> 791 <td>linky custom attributes</td> 792 <td> 793 <pre><div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"><br></div></pre> 794 </td> 795 <td> 796 <div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"></div> 797 </td> 798 </tr> 799 <tr id="escaped-html"> 800 <td>no filter</td> 801 <td><pre><div ng-bind="snippet"><br></div></pre></td> 802 <td><div ng-bind="snippet"></div></td> 803 </tr> 804 </table> 805 </file> 806 <file name="script.js"> 807 angular.module('linkyExample', ['ngSanitize']) 808 .controller('ExampleController', ['$scope', function($scope) { 809 $scope.snippet = 810 'Pretty text with some links:\n' + 811 'http://angularjs.org/,\n' + 812 'mailto:[email protected],\n' + 813 '[email protected],\n' + 814 'and one more: ftp://127.0.0.1/.'; 815 $scope.snippetWithSingleURL = 'http://angularjs.org/'; 816 }]); 817 </file> 818 <file name="protractor.js" type="protractor"> 819 it('should linkify the snippet with urls', function() { 820 expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). 821 toBe('Pretty text with some links: http://angularjs.org/, [email protected], ' + 822 '[email protected], and one more: ftp://127.0.0.1/.'); 823 expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); 824 }); 825 826 it('should not linkify snippet without the linky filter', function() { 827 expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). 828 toBe('Pretty text with some links: http://angularjs.org/, mailto:[email protected], ' + 829 '[email protected], and one more: ftp://127.0.0.1/.'); 830 expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); 831 }); 832 833 it('should update', function() { 834 element(by.model('snippet')).clear(); 835 element(by.model('snippet')).sendKeys('new http://link.'); 836 expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). 837 toBe('new http://link.'); 838 expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); 839 expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) 840 .toBe('new http://link.'); 841 }); 842 843 it('should work with the target property', function() { 844 expect(element(by.id('linky-target')). 845 element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()). 846 toBe('http://angularjs.org/'); 847 expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); 848 }); 849 850 it('should optionally add custom attributes', function() { 851 expect(element(by.id('linky-custom-attributes')). 852 element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()). 853 toBe('http://angularjs.org/'); 854 expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow'); 855 }); 856 </file> 857 </example> 858 */ 859angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { 860 var LINKY_URL_REGEXP = 861 /((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, 862 MAILTO_REGEXP = /^mailto:/i; 863 864 var linkyMinErr = angular.$$minErr('linky'); 865 var isDefined = angular.isDefined; 866 var isFunction = angular.isFunction; 867 var isObject = angular.isObject; 868 var isString = angular.isString; 869 870 return function(text, target, attributes) { 871 if (text == null || text === '') return text; 872 if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text); 873 874 var attributesFn = 875 isFunction(attributes) ? attributes : 876 isObject(attributes) ? function getAttributesObject() {return attributes;} : 877 function getEmptyAttributesObject() {return {};}; 878 879 var match; 880 var raw = text; 881 var html = []; 882 var url; 883 var i; 884 while ((match = raw.match(LINKY_URL_REGEXP))) { 885 // We can not end in these as they are sometimes found at the end of the sentence 886 url = match[0]; 887 // if we did not match ftp/http/www/mailto then assume mailto 888 if (!match[2] && !match[4]) { 889 url = (match[3] ? 'http://' : 'mailto:') + url; 890 } 891 i = match.index; 892 addText(raw.substr(0, i)); 893 addLink(url, match[0].replace(MAILTO_REGEXP, '')); 894 raw = raw.substring(i + match[0].length); 895 } 896 addText(raw); 897 return $sanitize(html.join('')); 898 899 function addText(text) { 900 if (!text) { 901 return; 902 } 903 html.push(sanitizeText(text)); 904 } 905 906 function addLink(url, text) { 907 var key, linkAttributes = attributesFn(url); 908 html.push('<a '); 909 910 for (key in linkAttributes) { 911 html.push(key + '="' + linkAttributes[key] + '" '); 912 } 913 914 if (isDefined(target) && !('target' in linkAttributes)) { 915 html.push('target="', 916 target, 917 '" '); 918 } 919 html.push('href="', 920 url.replace(/"/g, '"'), 921 '">'); 922 addText(text); 923 html.push('</a>'); 924 } 925 }; 926}]); 927 928 929})(window, window.angular);
930 931/* 932 Webnames Error 933 ----------------------------- 934 Module is meant to handle server and client side errors. 935 936Scenarios: 9371.) Unexpected error 938 StatusCode = 500 939 940 Symptoms: 941 - threw out of controller action method 942 943 What should happen: 944 - gets logged as special critical error to investigate 945 - if Angular error handler is present, let that handle the user error 946 - if it's a production environment, allow them to log an error report 947 - if it's local host, display stack trace etc 948 949 Examples: 950 - developer forgets to handle an exception that can be thrown, fixable error occurs (null reference) 951 - the user should be able to report that an error occurred and the error should be investigated 952 - these prohibit the user from continuing their intended action on the site 953 954 Solution: 955 - the user should log an error 956 957 - inline form or link to oops page 958 959 9602.) Expected error 961 StatusCode = 422 962 963 Symptoms: 964 - it was caught in the controller, the StatusCode was manually set to 422 965 966 What should happen: 967 - should be handled in Angular controller, displaying a special message to the user (should/could use the WnErrorHandler) 968 - handle required view state on the promise rejection 969 970 Examples: 971 - server side validation of a domain name fails, return an error object and error message to display to the user 972 973 Author: Akos Sebestyen 974*/ 975(function () { 976 "use strict"; 977 978 angular.module('WebnamesError', ['ngSanitize']) 979 980 .config(['$httpProvider', function ($httpProvider) { 981 $httpProvider.interceptors.push('WnHttpInterceptor'); 982 }]) 983 984 .factory('WnHttpInterceptor', ['$log', '$q', '$sce', 'WnErrorHandler', function ($log, $q, $sce, WnErrorHandler) { 985 return { 986 'request': function (config) { 987 // Add a custom header so our BaseController.cs can recognize that the WebnamesError module is present. 988 return config; 989 }, 990 991 'responseError': function (response) { 992 // Convert the array buffer data into an object 993 if (response.data instanceof ArrayBuffer) { 994 response.data = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(response.data))); 995 } 996 997 // Push the error into the error handler directive 998 if (response.status === 500 && !!response.data.wnAngularError) { 999 WnErrorHandler.PushError(!!response.data.debugMode ? $sce.trustAsHtml(response.data.wnAngularError) : response.data.wnAngularError, true); 1000 } 1001 1002 return $q.reject(response); 1003 } 1004 } 1005 }]); 1006 1007})(); 1008 1009/* 1010 * Webnames Error 1011 * ---------------- 1012 * Directives for displaying errors to the user from Angular. 1013 * 1014 * Author: Akos Sebestyen 1015 */ 1016(function () { 1017 "use strict"; 1018 1019 angular.module('WebnamesError') 1020 1021 // you can specify the 'timeout-length' property to determine how long the notification should stay on screen 1022 .directive('wnNotifications', wnNotifications) 1023 1024 // errors for the user to see 1025 .directive('wnErrors', wnErrors) 1026 1027 .directive('helpdeskError', helpdeskError); 1028 1029 function wnNotifications() { 1030 return { 1031 restrict: 'EA', 1032 replace: true, 1033 template: '<div class="alert {{ notification.sCSSClass || \'alert-info\' }} alert-dismissible" data-ng-repeat="notification in wnn.notifications track by notification.id" role="alert">' + 1034 '<button class="close" data-dismiss="alert" aria-label="Close"><i class="fas fa-times"></i></button>' + 1035 '<p data-ng-bind-html="notification.message"></p>' + 1036 '</div>', 1037 controllerAs: 'wnn', 1038 link: function (scope, elem, attrs) { 1039 scope.$emit('wnNotifications loaded'); 1040 if (!!attrs.timeoutLength) { 1041 scope.timeoutLength = attrs.timeoutLength; 1042 } 1043 }, 1044 controller: ['$scope', '$timeout', 'WnErrorHandler', function ($scope, $timeout, WnErrorHandler) { 1045 var vm = this; 1046 1047 vm.notifications = WnErrorHandler.Notifications; 1048 1049 $scope.$on('WnNotificationPushed', function (event, id) { 1050 if (!!$scope.timeoutLength && $scope.timeoutLength > 0) { 1051 $timeout(function () { 1052 WnErrorHandler.RemoveById(id); 1053 }, $scope.timeoutLength * 1000); 1054 } 1055 }); 1056 1057 vm.clear = function (id) { 1058 WnErrorHandler.RemoveById(id); 1059 } 1060 }] 1061 } 1062 } 1063 1064 function wnErrors() { 1065 return { 1066 restrict: 'EA', 1067 replace: true, 1068 template: '<div id="webnames-error-directive" class="alert alert-danger alert-dismissible" data-ng-repeat="error in wne.errors track by error.id" role="alert">
1068' + 1069 '<button class="close" data-dismiss="alert" aria-label="Close" data-ng-if="!error.isCritical" data-ng-click="wne.clear(error.id)"><i class="fas fa-times"></i></button>' + 1070 '<p data-ng-bind-html="error.message"></p>' + 1071 '<p data-ng-if="error.isCritical">Timestamp: {{error.dtTimestamp | date: "yyyy-MM-dd H:mm:ss.sss"}}</p>' + 1072 '</div>', 1073 link: function (scope) { 1074 scope.$emit('wnErrors loaded'); 1075 }, 1076 controllerAs: 'wne', 1077 controller: ['$scope', '$timeout', 'WnErrorHandler', function ($scope, $timeout, WnErrorHandler) { 1078 var vm = this; 1079 1080 vm.errors = WnErrorHandler.Errors; 1081 1082 vm.clear = function (id) { 1083 WnErrorHandler.RemoveById(id); 1084 } 1085 }] 1086 } 1087 } 1088 1089 function helpdeskError() { 1090 return { 1091 restrict: 'EA', 1092 template: '<div class="red-tip">' + 1093 '<h1>Cart Errors</h1>' + 1094 '<h3>Message</h3>' + 1095 '<p>{{message}}</p>' + 1096 '<h3>StackTrace</h3>' + 1097 '<p>{{stackTrace}}</p>' + 1098 '<h3>Suggested Solution</h3>' + 1099 '<p>{{suggestedSolution}}</p>' + 1100 '<h3>Timestamp</h3>' + 1101 '<p>{{dtCreated}}</p>' + 1102 '</div>', 1103 scope: { 1104 error: '=' 1105 }, 1106 controller: [ 1107 '$scope', function ($scope) { 1108 // When the error object changes, make sure it has all attributes and then display the error 1109 $scope.$watch('error', function () { 1110 if ($scope.error && 1111 $scope.error.message && 1112 $scope.error.stackTrace && 1113 $scope.error.suggestedSolution && 1114 $scope.error.dtCreated) { 1115 $scope.message = $scope.error.message; 1116 $scope.stackTrace = $scope.error.stackTrace; 1117 $scope.suggestedSolution = $scope.error.suggestedSolution; 1118 $scope.dtCreated = $scope.error.dtCreated; 1119 } 1120 }); 1121 } 1122 ] 1123 } 1124 }; 1125})(); 1126 1127/* 1128 WebnamesError - WnErrorHandler 1129 ------------------ 1130 Service used to push messages to the directive which will display them to the user. 1131 1132 Author: Akos Sebestyen 1133 */ 1134(function () { 1135 "use strict"; 1136 1137 angular.module('WebnamesError') 1138 .service('WnErrorHandler', ['$rootScope', '$timeout', '$window', '$location', '$anchorScroll', 'WnMessage', '$log', function ($rootScope, $timeout, $window, $location, $anchorScroll, WnMessage, $log) { 1139 var service = this; 1140 var messageCount = 0; 1141 1142 var wnNotificationsPresent = false; 1143 var wnErrorsPresent = false; 1144 1145 service.scrollToError = true; 1146 service.Notifications = []; 1147 service.Errors = []; 1148 1149 service.ClearAll = function () { 1150 // Must clear array using length so that references aren't lost 1151 service.Notifications.length = 0; 1152 service.Errors.length = 0; 1153 } 1154 1155 // Use this to push notifications to the user 1156 service.PushNotification = function (errorString, sCSSClass) { 1157 var id = messageCount; 1158 service.Notifications.push(new WnMessage(id, errorString, false, sCSSClass)); 1159 $rootScope.$broadcast('WnNotificationPushed', id); 1160 messageCount++; 1161 1162 return service.Notifications[service.Notifications.length - 1]; 1163 } 1164 1165 // Use this to push errors to the user 1166 service.PushError = function (errorString, isCritical) { 1167 var id = messageCount; 1168 service.Errors.push(new WnMessage(id, errorString, !!isCritical)); 1169 $rootScope.$broadcast('WnErrorPushed', id); 1170 messageCount++; 1171 1172 if (service.scrollToError) { 1173 $location.hash("webnames-error-directive"); 1174 $anchorScroll(); 1175 } 1176 1177 return service.Errors[service.Errors.length - 1]; 1178 } 1179 1180 service.GetById = function (id) { 1181 return _.findWhere(service.Notifications, { id: id }); 1182 } 1183 1184 service.RemoveById = function (id) { 1185 var index = _.findIndex(service.Notifications, { id: id }); 1186 1187 if (index < 0) { 1188 index = _.findIndex(service.Errors, { id: id }); 1189 if (index > -1 && !service.Errors[index].isCritical) service.Errors.splice(index, 1); 1190 } else { 1191 service.Notifications.splice(index, 1); 1192 } 1193 } 1194 1195 // TODO: implement parameters 1196 /** 1197 * Redirects client to the robot page. 1198 * @returns {} 1199 */ 1200 service.KillNonRecoverable = function () { 1201 $window.location.href = $window._SmartURL + "error/oops/default.aspx"; 1202 } 1203 1204 // Save events from link function of directives for page validation 1205 $rootScope.$on('wnNotifications loaded', function () { 1206 wnNotificationsPresent = true; 1207 }); 1208 1209 $rootScope.$on('wnErrors loaded', function () { 1210 wnErrorsPresent = true; 1211 }); 1212 1213 // Used for validation of the Angular page 1214 $timeout(function () { 1215 if (!wnErrorsPresent) { 1216 throw "No 'wnErrors' directive found! You should not use this module without placing this directive on your page first!"; 1217 } 1218 if (!wnNotificationsPresent) { 1219 throw "No 'wnNotifications' directive found! You should not use this module without placing this directive on your page first!"; 1220 } 1221 }); 1222 }]) 1223 1224 .factory('WnMessage', [function () { 1225 function WnMessage(id, message, isCritical, sCSSClass) { 1226 var model = this; 1227 1228 model.id = id; 1229 model.dtTimestamp = new Date(); 1230 model.isCritical = isCritical; 1231 model.sCSSClass = sCSSClass || ""; 1232 1233 model.message = message; 1234 } 1235 1236 return WnMessage; 1237 }]); 1238})(); 1239 1240/* 1241 Webnames Common 1242 -------------------------------- 1243 Module to hold common Angular functions 1244 1245 Author: Akos Sebestyen 2015 1246*/ 1247(function () { 1248 "use strict"; 1249
1250 angular.module('WebnamesCommon', []); 1251 1252})(); 1253 1254 1255/* 1256 Generic Injector 1257 -------------------------------- 1258 Used to inject data into Angular on pageload. 1259 1260 The provider exposes a "InjectGenericProperty" method that can be used at config time to get JSON data into the service. 1261 1262 Then you can access the data from GenericInjector.PropBag.yourProperty 1263 1264 Author: Akos Sebestyen 2015 1265*/ 1266(function () { 1267 "use strict"; 1268 1269 angular.module('WebnamesCommon') 1270 .provider('GenericInjector', function () { 1271 var _propBag = {}; 1272 1273 // Assign the prop bag 1274 var GenericInjector = function () { 1275 this.PropBag = _propBag; 1276 }; 1277 1278 return { 1279 $get: ['$injector', function ($injector) { return $injector.instantiate(GenericInjector) }], 1280 InjectGenericProperty: function (propName, propValue) { _propBag[propName] = propValue} 1281 } 1282 }); 1283 1284})(); 1285 1286 1287(function () { 1288 "use strict"; 1289 1290 angular.module("WebnamesCommon") 1291 .factory("WnFocus", ['$timeout', '$document', function ($timeout, $document) { 1292 return function(id) { 1293 $timeout(function () { 1294 var element = $document.getElementById(id); 1295 if (element) 1296 element.focus(); 1297 }); 1298 } 1299 }]); 1300})(); 1301// Scrolls to the top of the given selector. Use offset to offset the value by pixels 1302 1303(function () { 1304 "use strict"; 1305 1306 angular.module("WebnamesCommon") 1307 .factory("WnScroll", ['$timeout', function ($timeout) { 1308 return function (selector, offset, animateTime) { 1309 if (!offset) offset = 0; 1310 if (!animateTime) animateTime = 500; 1311 $timeout(function () { 1312 $('html, body').animate({ scrollTop: ($(selector).offset().top + offset) }, animateTime); 1313 }); 1314 } 1315 }]); 1316})(); 1317// https://gist.github.com/tommaitland/7579618 1318(function () { 1319 angular.module('WebnamesCommon').directive('ngDebounce', ['$timeout', function ($timeout) { 1320 return { 1321 restrict: 'A', 1322 require: 'ngModel', 1323 priority: 99, 1324 link: function (scope, elm, attr, ngModelCtrl) { 1325 if (attr.type === 'radio' || attr.type === 'checkbox') return; 1326 1327 elm.unbind('input'); 1328 1329 var debounce; 1330 elm.bind('input', function () { 1331 $timeout.cancel(debounce); 1332 debounce = $timeout(function () { 1333 scope.$apply(function () { 1334 ngModelCtrl.$setViewValue(elm.val()); 1335 }); 1336 }, attr.ngDebounce || 1000); 1337 }); 1338 elm.bind('blur', function () { 1339 scope.$apply(function () { 1340 ngModelCtrl.$setViewValue(elm.val()); 1341 }); 1342 }); 1343 } 1344 1345 } 1346 }]); 1347})(); 1348 1349(function () { 1350 "use strict"; 1351 1352 angular.module('WebnamesCommon') 1353 .filter('startFrom', function () { 1354 1355 return function (input, start) { 1356 if (input !== undefined && angular.isArray(input)) { 1357 return input.slice(start); 1358 } else { 1359 return []; 1360 } 1361 } 1362 }) 1363 .filter("getActiveKeys", [function () { 1364 /** 1365 * Takes an object and returns an array of keys where the values are truthy 1366 * @param {Object} obj Flat object of key value pairs 1367 * @returns {Array} array of keys with truthy values 1368 */ 1369 return function(obj) { 1370 return _.chain(obj) 1371 .pairs() // Turn object into array of arrays as key value pairs 1372 .filter(function (kvp) { return !!kvp[1] }) // Return all Key-Value pairs where value is truthy 1373 .map(function (kvp) { return kvp[0] }) // Map into an array of just strings of keys 1374 .value(); 1375 } 1376 }]) 1377 .filter('nullToEnd', function () { 1378 return function (array, key) { 1379 if (!angular.isArray(array)) return; 1380 1381 var present = array.filter(function (item) { 1382 return item[key]; 1383 }); 1384 var empty = array.filter(function (item) { 1385 return !item[key]; 1386 }); 1387 1388 return present.concat(empty); 1389 } 1390 }) 1391 .run(["$http", function ($http) { 1392 $http.defaults.headers.common['X-XSRF-Token'] = 1393 angular.element(document.querySelector('input[name="__RequestVerificationToken"]')).attr('value'); 1394 }]); 1395})(); 1396 1397angular.module('homeApp', ['ui.bootstrap', 'WebnamesCommon']) 1398 .controller('homeController', ['$scope', 'GenericInjector', function ($scope, GenericInjector) { 1399 $scope.bWixPromoActive = GenericInjector.PropBag.bWixPromoActive; 1400 }]) 1401 .controller('ModalReferral', ['$scope', '$uibModal', '$log', '$http', function ($scope, $uibModal, $log, $http) { 1402 $scope.open = function (size) { 1403 var modalInstance = $uibModal.open({ 1404 templateUrl: 'Home/tmpl/referralModal', 1405 controller: ['$scope', '$uibModalInstance', '$log', function ($scope, $uibModalInstance, $log) { 1406 $log.debug('referralModal'); 1407 1408 $http.post(window._SmartURL + 'Home/CheckReferralValidResult') 1409 .then(function success(response) { 1410 $log.debug(response); 1411 if (response.data.ReferralName == "") {
1412 $scope.referralResult = "This account is ineligible for the referral credit or the referral ID is incorrect. Referral credits are available for new accounts that are linked to an unregistered email." 1413 } else { 1414 $scope.referralResult = "You will automatically receive " + response.data.ReferralCreditAmount + " off your first purchase of " + response.data.ReferralCreditThreshold + " or more (before taxes, and after discounts). With 500+ domain extensions, powerful Canadian hosting and email, SSL, DNS hosting and more, we've got all the tools you need to make a name for yourself online. Let us know if you need anything, we're standing by to help! "; 1415 } 1416 }, 1417 function error(response) { 1418 alert("Unknown error. Please refresh the page and try again, or contact Support."); 1419 }); 1420 1421 $scope.ok = function () { 1422 $log.debug('Close'); 1423 $uibModalInstance.close(); 1424 }; 1425 1426 $scope.cancel = function () { 1427 $uibModalInstance.dismiss('cancel'); 1428 }; 1429 }], 1430 size: size 1431 }); 1432 }; 1433 1434 $scope.$on('Modal.Referral', function (e) { 1435 $log.debug('Modal.Referral:Open'); 1436 $scope.open('lg'); 1437 }); 1438 //Open as soon as it's loaded. 1439 $scope.open('lg'); 1440}]);
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.