vendor: 26,722 bytes, lines 1-830
1/* 2 * angucomplete-alt 3 * Autocomplete directive for AngularJS 4 * This is a fork of Daryl Rowland's angucomplete with some extra features. 5 * By Hidenari Nozaki 6 */ 7 8/*! Copyright (c) 2014 Hidenari Nozaki and contributors | Licensed under the MIT license */ 9 10(function (root, factory) { 11 'use strict'; 12 if (typeof module !== 'undefined' && module.exports) { 13 // CommonJS 14 module.exports = factory(require('angular')); 15 } else if (typeof define === 'function' && define.amd) { 16 // AMD 17 define(['angular'], factory); 18 } else { 19 // Global Variables 20 factory(root.angular); 21 } 22}(window, function (angular) { 23 'use strict'; 24 25 angular.module('angucomplete-alt', []).directive('angucompleteAlt', ['$q', '$parse', '$http', '$sce', '$timeout', '$templateCache', '$interpolate', '$rootScope', function ($q, $parse, $http, $sce, $timeout, $templateCache, $interpolate, $rootScope) { 26 // keyboard events 27 var KEY_DW = 40; 28 var KEY_RT = 39; 29 var KEY_UP = 38; 30 var KEY_LF = 37; 31 var KEY_ES = 27; 32 var KEY_EN = 13; 33 var KEY_TAB = 9; 34 35 var MIN_LENGTH = 3; 36 var MAX_LENGTH = 524288; // the default max length per the html maxlength attribute 37 var PAUSE = 500; 38 var BLUR_TIMEOUT = 200; 39 40 // string constants 41 var REQUIRED_CLASS = 'autocomplete-required'; 42 var TEXT_SEARCHING = 'Searching...'; 43 var TEXT_NORESULTS = 'No results found'; 44 var TEMPLATE_URL = '/angucomplete-alt/index.html'; 45 46 // Set the default template for this directive 47 $templateCache.put(TEMPLATE_URL, 48 '<div class="angucomplete-holder" ng-class="{\'angucomplete-dropdown-visible\': showDropdown}">' + 49 ' <input id="{{id}}_value" name="{{inputName}}" tabindex="{{fieldTabindex}}" ng-class="{\'angucomplete-input-not-empty\': notEmpty}" ng-model="searchStr" ng-disabled="disableInput" type="{{inputType}}" placeholder="{{placeholder}}" maxlength="{{maxlength}}" ng-focus="onFocusHandler()" class="{{inputClass}}" ng-focus="resetHideResults()" ng-blur="hideResults($event)" autocapitalize="off" autocorrect="off" autocomplete="off" ng-change="inputChangeHandler(searchStr)"/>' + 50 ' <div id="{{id}}_dropdown" class="angucomplete-dropdown" ng-show="showDropdown">' + 51 ' <div class="angucomplete-searching" ng-show="searching" ng-bind="textSearching"></div>' + 52 ' <div class="angucomplete-searching" ng-show="!searching && (!results || results.length == 0)" ng-bind="textNoResults"></div>' + 53 ' <div class="angucomplete-row" ng-repeat="result in results" ng-click="selectResult(result)" ng-mouseenter="hoverRow($index)" ng-class="{\'angucomplete-selected-row\': $index == currentIndex}">' + 54 ' <div ng-if="imageField" class="angucomplete-image-holder">' + 55 ' <img ng-if="result.image && result.image != \'\'" ng-src="{{result.image}}" class="angucomplete-image"/>' + 56 ' <div ng-if="!result.image && result.image != \'\'" class="angucomplete-image-default"></div>' + 57 ' </div>' + 58 ' <div class="angucomplete-title" ng-if="matchClass" ng-bind-html="result.title"></div>' + 59 ' <div class="angucomplete-title" ng-if="!matchClass">{{ result.title }}</div>' + 60 ' <div ng-if="matchClass && result.description && result.description != \'\'" class="angucomplete-description" ng-bind-html="result.description"></div>' + 61 ' <div ng-if="!matchClass && result.description && result.description != \'\'" class="angucomplete-description">{{result.description}}</div>' + 62 ' </div>' + 63 ' </div>' + 64 '</div>' 65 ); 66 67 function link(scope, elem, attrs, ctrl) { 68 var inputField = elem.find('input'); 69 var minlength = MIN_LENGTH; 70 var searchTimer = null; 71 var hideTimer; 72 var requiredClassName = REQUIRED_CLASS; 73 var responseFormatter; 74 var validState = null; 75 var httpCanceller = null; 76 var httpCallInProgress = false; 77 var dd = elem[0].querySelector('.angucomplete-dropdown'); 78 var isScrollOn = false; 79 var mousedownOn = null; 80 var unbindInitialValue; 81 var displaySearching; 82 var displayNoResults; 83 84 elem.on('mousedown', function(event) { 85 if (event.target.id) { 86 mousedownOn = event.target.id; 87 if (mousedownOn === scope.id + '_dropdown') { 88 document.body.addEventListener('click', clickoutHandlerForDropdown); 89 } 90 } 91 else { 92 mousedownOn = event.target.className; 93 } 94 }); 95 96 scope.currentIndex = scope.focusFirst ? 0 : null; 97 scope.searching = false; 98 unbindInitialValue = scope.$watch('initialValue', function(newval) { 99 if (newval) { 100 // remove scope listener 101 unbindInitialValue(); 102 // change input 103 handleInputChange(newval, true); 104 } 105 }); 106 107 scope.$watch('fieldRequired', function(newval, oldval) { 108 if (newval !== oldval) { 109 if (!newval) { 110 ctrl[scope.inputName].$setValidity(requiredClassName, true); 111 } 112 else if (!validState || scope.currentIndex === -1) { 113 handleRequired(false); 114 } 115 else { 116 handleRequired(true); 117 } 118 } 119 }); 120 121 scope.$on('angucomplete-alt:clearInput', function (event, elementId) { 122 if (!elementId || elementId === scope.id) { 123 scope.searchStr = null; 124 callOrAssign(); 125 handleRequired(false); 126 clearResults(); 127 } 128 }); 129 130 scope.$on('angucomplete-alt:changeInput', function (event, elementId, newval) { 131 if (!!elementId && elementId === scope.id) { 132 handleInputChange(newval); 133 } 134 }); 135 136 function handleInputChange(newval, initial) { 137 if (newval) { 138 if (typeof newval === 'object') { 139 scope.searchStr = extractTitle(newval); 140 callOrAssign({originalObject: newval}); 141 } else if (typeof newval === 'string' && newval.length > 0) { 142 scope.searchStr = newval; 143 } else { 144 if (console && console.error) { 145 console.error('Tried to set ' + (!!initial ? 'initial' : '') + ' value of angucomplete to', newval, 'which is an invalid value'); 146 } 147 } 148 149 handleRequired(true); 150 } 151 } 152 153 // #194 dropdown list not consistent in collapsing (bug). 154 function clickoutHandlerForDropdown(event) { 155 mousedownOn = null; 156 scope.hideResults(event); 157 document.body.removeEventListener('click', clickoutHandlerForDropdown); 158 } 159 160 // for IE8 quirkiness about event.which 161 function ie8EventNormalizer(event) { 162 return event.which ? event.which : event.keyCode; 163 } 164 165 function callOrAssign(value) { 166 if (typeof scope.selectedObject === 'function') { 167 scope.selectedObject(value, scope.selectedObjectData); 168 } 169 else { 170 scope.selectedObject = value; 171 } 172 173 if (value) { 174 handleRequired(true); 175 } 176 else { 177 handleRequired(false); 178 } 179 } 180 181 function callFunctionOrIdentity(fn) { 182 return function(data) { 183 return scope[fn] ? scope[fn](data) : data; 184 }; 185 } 186 187 function setInputString(str) { 188 callOrAssign({originalObject: str}); 189 190 if (scope.clearSelected) { 191 scope.searchStr = null; 192 } 193 clearResults(); 194 } 195 196 function extractTitle(data) { 197 // split title fields and run extractValue for each and join with ' ' 198 return scope.titleField.split(',') 199 .map(function(field) { 200 return extractValue(data, field); 201 }) 202 .join(' '); 203 } 204 205 function extractValue(obj, key) { 206 var keys, result; 207 if (key) { 208 keys= key.split('.'); 209 result = obj; 210 for (var i = 0; i < keys.length; i++) { 211 result = result[keys[i]]; 212 } 213 } 214 else { 215 result = obj; 216 } 217 return result; 218 } 219 220 function findMatchString(target, str) { 221 var result, matches, re; 222 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions 223 // Escape user input to be treated as a literal string within a regular expression 224 re = new RegExp(str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'); 225 if (!target) { return; } 226 if (!target.match || !target.replace) { target = target.toString(); } 227 matches = target.match(re); 228 if (matches) { 229 result = target.replace(re, 230 '<span class="'+ scope.matchClass +'">'+ matches[0] +'</span>'); 231 } 232 else { 233 result = target; 234 } 235 return $sce.trustAsHtml(result); 236 } 237 238 function handleRequired(valid) { 239 scope.notEmpty = valid; 240 validState = scope.searchStr; 241 if (scope.fieldRequired && ctrl && scope.inputName) { 242 ctrl[scope.inputName].$setValidity(requiredClassName, valid); 243 } 244 } 245 246 function keyupHandler(event) { 247 var which = ie8EventNormalizer(event); 248 if (which === KEY_LF || which === KEY_RT) { 249 // do nothing 250 return; 251 } 252 253 if (which === KEY_UP) { 254 event.preventDefault(); 255 } 256 else if (which === KEY_EN){ 257 scope.keyEnter(); 258 } 259 else if (which === KEY_DW) { 260 event.preventDefault(); 261 if (!scope.showDropdown && scope.searchStr && scope.searchStr.length >= minlength) { 262 initResults(); 263 scope.searching = true; 264 searchTimerComplete(scope.searchStr); 265 } 266 } 267 else if (which === KEY_ES) { 268 clearResults(); 269 scope.$apply(function() { 270 inputField.val(scope.searchStr); 271 }); 272 } 273 else { 274 if (minlength === 0 && !scope.searchStr) { 275 return; 276 } 277 278 if (!scope.searchStr || scope.searchStr === '') { 279 scope.showDropdown = false; 280 } else if (scope.searchStr.length >= minlength) { 281 initResults(); 282 283 if (searchTimer) { 284 $timeout.cancel(searchTimer); 285 } 286 287 scope.searching = true; 288 289 searchTimer = $timeout(function() { 290 searchTimerComplete(scope.searchStr); 291 }, scope.pause); 292 } 293 294 if (validState && validState !== scope.searchStr && !scope.clearSelected) { 295 scope.$apply(function() { 296 callOrAssign(); 297 }); 298 } 299 } 300 } 301 302 function handleOverrideSuggestions(event) { 303 if (scope.overrideSuggestions && 304 !(scope.selectedObject && scope.selectedObject.originalObject === scope.searchStr)) { 305 if (event) { 306 event.preventDefault(); 307 } 308 309 // cancel search timer 310 $timeout.cancel(searchTimer); 311 // cancel http request 312 cancelHttpRequest(); 313 314 setInputString(scope.searchStr); 315 } 316 } 317 318 function dropdownRowOffsetHeight(row) { 319 var css = getComputedStyle(row); 320 return row.offsetHeight + 321 parseInt(css.marginTop, 10) + parseInt(css.marginBottom, 10); 322 } 323 324 function dropdownHeight() { 325 return dd.getBoundingClientRect().top + 326 parseInt(getComputedStyle(dd).maxHeight, 10); 327 } 328 329 function dropdownRow() { 330 return elem[0].querySelectorAll('.angucomplete-row')[scope.currentIndex]; 331 } 332 333 function dropdownRowTop() { 334 return dropdownRow().getBoundingClientRect().top - 335 (dd.getBoundingClientRect().top + 336 parseInt(getComputedStyle(dd).paddingTop, 10)); 337 } 338 339 function dropdownScrollTopTo(offset) { 340 dd.scrollTop = dd.scrollTop + offset; 341 } 342 343 function updateInputField(){ 344 var current = scope.results[scope.currentIndex]; 345 if (scope.matchClass) { 346 inputField.val(extractTitle(current.originalObject)); 347 } 348 else { 349 inputField.val(current.title); 350 } 351 } 352 353 function keydownHandler(event) { 354 var which = ie8EventNormalizer(event); 355 var row = null; 356 var rowTop = null; 357 358 if (which === KEY_EN && scope.results) { 359 if (scope.currentIndex >= 0 && scope.currentIndex < scope.results.length) { 360 event.preventDefault(); 361 scope.selectResult(scope.results[scope.currentIndex]); 362 } else { 363 handleOverrideSuggestions(event); 364 clearResults(); 365 } 366 scope.$apply(); 367 } else if (which === KEY_DW && scope.results) { 368 event.preventDefault(); 369 if ((scope.currentIndex + 1) < scope.results.length && scope.showDropdown) { 370 scope.$apply(function() { 371 scope.currentIndex ++; 372 updateInputField(); 373 }); 374 375 if (isScrollOn) { 376 row = dropdownRow(); 377 if (dropdownHeight() < row.getBoundingClientRect().bottom) { 378 dropdownScrollTopTo(dropdownRowOffsetHeight(row)); 379 } 380 } 381 } 382 } else if (which === KEY_UP && scope.results) { 383 event.preventDefault(); 384 if (scope.currentIndex >= 1) { 385 scope.$apply(function() { 386 scope.currentIndex --; 387 updateInputField(); 388 }); 389 390 if (isScrollOn) { 391 rowTop = dropdownRowTop(); 392 if (rowTop < 0) { 393 dropdownScrollTopTo(rowTop - 1); 394 } 395 } 396 } 397 else if (scope.currentIndex === 0) { 398 scope.$apply(function() { 399 scope.currentIndex = -1; 400 inputField.val(scope.searchStr); 401 }); 402 } 403 } else if (which === KEY_TAB) { 404 if (scope.results && scope.results.length > 0 && scope.showDropdown) { 405 if (scope.currentIndex === -1 && scope.overrideSuggestions) { 406 // intentionally not sending event so that it does not 407 // prevent default tab behavior 408 handleOverrideSuggestions(); 409 } 410 else { 411 if (scope.currentIndex === -1) { 412 scope.currentIndex = 0; 413 } 414 scope.selectResult(scope.results[scope.currentIndex]); 415 scope.$digest(); 416 } 417 } 418 else { 419 // no results 420 // intentionally not sending event so that it does not 421 // prevent default tab behavior 422 if (scope.searchStr && scope.searchStr.length > 0) { 423 handleOverrideSuggestions(); 424 } 425 } 426 } else if (which === KEY_ES) { 427 // This is very specific to IE10/11 #272 428 // without this, IE clears the input text 429 event.preventDefault(); 430 } 431 } 432 433 function httpSuccessCallbackGen(str) { 434 return function(responseData, status, headers, config) { 435 // normalize return obejct from promise 436 if (!status && !headers && !config && responseData.data) { 437 responseData = responseData.data; 438 } 439 scope.searching = false; 440 processResults( 441 extractValue(responseFormatter(responseData), scope.remoteUrlDataField), 442 str); 443 }; 444 } 445 446 function httpErrorCallback(errorRes, status, headers, config) { 447 scope.searching = httpCallInProgress; 448 449 // normalize return obejct from promise 450 if (!status && !headers && !config) { 451 status = errorRes.status; 452 } 453 454 // cancelled/aborted 455 if (status === 0 || status === -1) { return; } 456 if (scope.remoteUrlErrorCallback) { 457 scope.remoteUrlErrorCallback(errorRes, status, headers, config); 458 } 459 else { 460 if (console && console.error) { 461 console.error('http error'); 462 } 463 } 464 } 465 466 function cancelHttpRequest() { 467 if (httpCanceller) { 468 httpCanceller.resolve(); 469 } 470 } 471 472 function getRemoteResults(str) { 473 var params = {}, 474 url = scope.remoteUrl + encodeURIComponent(str); 475 if (scope.remoteUrlRequestFormatter) { 476 params = {params: scope.remoteUrlRequestFormatter(str)}; 477 url = scope.remoteUrl; 478 } 479 if (!!scope.remoteUrlRequestWithCredentials) { 480 params.withCredentials = true; 481 } 482 cancelHttpRequest(); 483 httpCanceller = $q.defer(); 484 params.timeout = httpCanceller.promise; 485 httpCallInProgress = true; 486 $http.get(url, params) 487 .then(httpSuccessCallbackGen(str)) 488 .catch(httpErrorCallback) 489 .finally(function(){httpCallInProgress=false;}); 490 } 491 492 function getRemoteResultsWithCustomHandler(str) { 493 cancelHttpRequest(); 494 495 httpCanceller = $q.defer(); 496 497 scope.remoteApiHandler(str, httpCanceller.promise) 498 .then(httpSuccessCallbackGen(str)) 499 .catch(httpErrorCallback); 500 501 /* IE8 compatible 502 scope.remoteApiHandler(str, httpCanceller.promise) 503 ['then'](httpSuccessCallbackGen(str)) 504 ['catch'](httpErrorCallback); 505 */ 506 } 507 508 function clearResults() { 509 scope.showDropdown = false; 510 scope.results = []; 511 if (dd) { 512 dd.scrollTop = 0; 513 } 514 } 515 516 function initResults() { 517 scope.showDropdown = displaySearching; 518 scope.currentIndex = scope.focusFirst ? 0 : -1; 519 scope.results = []; 520 } 521 522 function getLocalResults(str) { 523 var i, match, s, value, 524 searchFields = scope.searchFields.split(','), 525 matches = []; 526 if (typeof scope.parseInput() !== 'undefined') { 527 str = scope.parseInput()(str); 528 } 529 for (i = 0; i < scope.localData.length; i++) { 530 match = false; 531 532 for (s = 0; s < searchFields.length; s++) { 533 value = extractValue(scope.localData[i], searchFields[s]) || ''; 534 match = match || (value.toString().toLowerCase().indexOf(str.toString().toLowerCase()) >= 0); 535 } 536 537 if (match) { 538 matches[matches.length] = scope.localData[i]; 539 } 540 } 541 return matches; 542 } 543 544 function checkExactMatch(result, obj, str){ 545 if (!str) { return false; } 546 for(var key in obj){ 547 if(obj[key].toLowerCase() === str.toLowerCase()){ 548 scope.selectResult(result); 549 return true; 550 } 551 } 552 return false; 553 } 554 555 function searchTimerComplete(str) { 556 // Begin the search 557 if (!str || str.length < minlength) { 558 return; 559 } 560 if (scope.localData) { 561 scope.$apply(function() { 562 var matches; 563 if (typeof scope.localSearch() !== 'undefined') { 564 matches = scope.localSearch()(str, scope.localData); 565 } else { 566 matches = getLocalResults(str); 567 } 568 scope.searching = false; 569 processResults(matches, str); 570 }); 571 } 572 else if (scope.remoteApiHandler) { 573 getRemoteResultsWithCustomHandler(str); 574 } else { 575 getRemoteResults(str); 576 } 577 } 578 579 function processResults(responseData, str) { 580 var i, description, image, text, formattedText, formattedDesc; 581 582 if (responseData && responseData.length > 0) { 583 scope.results = []; 584 585 for (i = 0; i < responseData.length; i++) { 586 if (scope.titleField && scope.titleField !== '') { 587 text = formattedText = extractTitle(responseData[i]); 588 } 589 590 description = ''; 591 if (scope.descriptionField) { 592 description = formattedDesc = extractValue(responseData[i], scope.descriptionField); 593 } 594 595 image = ''; 596 if (scope.imageField) { 597 image = extractValue(responseData[i], scope.imageField); 598 } 599 600 if (scope.matchClass) { 601 formattedText = findMatchString(text, str); 602 formattedDesc = findMatchString(description, str); 603 } 604 605 scope.results[scope.results.length] = { 606 title: formattedText, 607 description: formattedDesc, 608 image: image, 609 originalObject: responseData[i] 610 }; 611 } 612 613 } else { 614 scope.results = []; 615 } 616 617 if (scope.autoMatch && scope.results.length === 1 && 618 checkExactMatch(scope.results[0], 619 {title: text, desc: description || ''}, scope.searchStr)) { 620 scope.showDropdown = false; 621 } else if (scope.results.length === 0 && !displayNoResults) { 622 scope.showDropdown = false; 623 } else { 624 scope.showDropdown = true; 625 } 626 } 627 628 function showAll() { 629 if (scope.localData) { 630 scope.searching = false; 631 processResults(scope.localData, ''); 632 } 633 else if (scope.remoteApiHandler) { 634 scope.searching = true; 635 getRemoteResultsWithCustomHandler(''); 636 } 637 else { 638 scope.searching = true; 639 getRemoteResults(''); 640 } 641 } 642 643 scope.onFocusHandler = function() { 644 if (scope.focusIn) { 645 scope.focusIn(); 646 } 647 if (minlength === 0 && (!scope.searchStr || scope.searchStr.length === 0)) { 648 scope.currentIndex = scope.focusFirst ? 0 : scope.currentIndex; 649 scope.showDropdown = true; 650 showAll(); 651 } 652 }; 653 654 scope.hideResults = function() { 655 if (mousedownOn && 656 (mousedownOn === scope.id + '_dropdown' || 657 mousedownOn.indexOf('angucomplete') >= 0)) { 658 mousedownOn = null; 659 } 660 else { 661 hideTimer = $timeout(function() { 662 clearResults(); 663 scope.$apply(function() { 664 if (scope.searchStr && scope.searchStr.length > 0) { 665 inputField.val(scope.searchStr); 666 } 667 }); 668 }, BLUR_TIMEOUT); 669 cancelHttpRequest(); 670 671 if (scope.focusOut) { 672 scope.focusOut(); 673 } 674 675 if (scope.overrideSuggestions) { 676 if (scope.searchStr && scope.searchStr.length > 0 && scope.currentIndex === -1) { 677 handleOverrideSuggestions(); 678 } 679 } 680 } 681 }; 682 683 scope.resetHideResults = function() { 684 if (hideTimer) { 685 $timeout.cancel(hideTimer); 686 } 687 }; 688 689 scope.hoverRow = function(index) { 690 scope.currentIndex = index; 691 }; 692 693 scope.selectResult = function(result) { 694 // Restore original values 695 if (scope.matchClass) { 696 result.title = extractTitle(result.originalObject); 697 result.description = extractValue(result.originalObject, scope.descriptionField); 698 } 699 700 if (scope.clearSelected) { 701 scope.searchStr = null; 702 } 703 else { 704 scope.searchStr = result.title; 705 } 706 callOrAssign(result); 707 clearResults(); 708 }; 709 710 scope.inputChangeHandler = function(str) { 711 if (str.length < minlength) { 712 cancelHttpRequest(); 713 clearResults(); 714 } 715 else if (str.length === 0 && minlength === 0) { 716 showAll(); 717 } 718 719 if (scope.inputChanged) { 720 str = scope.inputChanged(str); 721 } 722 return str; 723 }; 724 725 // check required 726 if (scope.fieldRequiredClass && scope.fieldRequiredClass !== '') { 727 requiredClassName = scope.fieldRequiredClass; 728 } 729 730 // check min length 731 if (scope.minlength && scope.minlength !== '') { 732 minlength = parseInt(scope.minlength, 10); 733 } 734 735 // check pause time 736 if (!scope.pause) { 737 scope.pause = PAUSE; 738 } 739 740 // check clearSelected 741 if (!scope.clearSelected) { 742 scope.clearSelected = false; 743 } 744 745 // check override suggestions 746 if (!scope.overrideSuggestions) { 747 scope.overrideSuggestions = false; 748 } 749 750 // check required field 751 if (scope.fieldRequired && ctrl) { 752 // check initial value, if given, set validitity to true 753 if (scope.initialValue) { 754 handleRequired(true); 755 } 756 else { 757 handleRequired(false); 758 } 759 } 760 761 scope.inputType = attrs.type ? attrs.type : 'text'; 762 763 // set strings for "Searching..." and "No results" 764 scope.textSearching = attrs.textSearching ? attrs.textSearching : TEXT_SEARCHING; 765 scope.textNoResults = attrs.textNoResults ? attrs.textNoResults : TEXT_NORESULTS; 766 displaySearching = scope.textSearching === 'false' ? false : true; 767 displayNoResults = scope.textNoResults === 'false' ? false : true; 768 769 // set max length (default to maxlength deault from html 770 scope.maxlength = attrs.maxlength ? attrs.maxlength : MAX_LENGTH; 771 772 // register events 773 inputField.on('keydown', keydownHandler); 774 inputField.on('keyup compositionend', keyupHandler); 775 776 // set response formatter 777 responseFormatter = callFunctionOrIdentity('remoteUrlResponseFormatter'); 778 779 // set isScrollOn 780 $timeout(function() { 781 var css = getComputedStyle(dd); 782 isScrollOn = css.maxHeight && css.overflowY === 'auto'; 783 }); 784 } 785 786 return { 787 restrict: 'EA', 788 require: '^?form', 789 scope: { 790 keyEnter : '&', 791 selectedObject: '=', 792 selectedObjectData: '=', 793 disableInput: '=', 794 initialValue: '=', 795 localData: '=', 796 localSearch: '&', 797 remoteUrlRequestFormatter: '=', 798 remoteUrlRequestWithCredentials: '@', 799 remoteUrlResponseFormatter: '=', 800 remoteUrlErrorCallback: '=', 801 remoteApiHandler: '=', 802 id: '@', 803 type: '@', 804 placeholder: '@', 805 textSearching: '@', 806 textNoResults: '@', 807 remoteUrl: '@', 808 remoteUrlDataField: '@', 809 titleField: '@', 810 descriptionField: '@', 811 imageField: '@', 812 inputClass: '@', 813 pause: '@', 814 searchFields: '@', 815 minlength: '@', 816 matchClass: '@', 817 clearSelected: '@', 818 overrideSuggestions: '@', 819 fieldRequired: '=', 820 fieldRequiredClass: '@', 821 inputChanged: '=', 822 autoMatch: '@', 823 focusOut: '&', 824 focusIn: '&', 825 fieldTabindex: '@', 826 inputName: '@', 827 focusFirst: '@', 828 parseInput: '&' 829 }, 830 templateUrl: function(element, attrs) {
831 return attrs.templateUrl || TEMPLATE_URL; 832 }, 833 compile: function(tElement) { 834 var startSym = $interpolate.startSymbol(); 835 var endSym = $interpolate.endSymbol(); 836 if (!(startSym === '{{' && endSym === '}}')) { 837 var interpolatedHtml = tElement.html() 838 .replace(/\{\{/g, startSym) 839 .replace(/\}\}/g, endSym); 840 tElement.html(interpolatedHtml); 841 } 842 return link; 843 } 844 }; 845 }]); 846 847}));
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.