1/* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31/** 32 * @constructor 33 * @extends {WebInspector.DialogDelegate} 34 * @implements {WebInspector.ViewportControl.Provider} 35 * @param {!WebInspector.SelectionDialogContentProvider} delegate 36 */ 37WebInspector.FilteredItemSelectionDialog = function(delegate) 38{ 39 WebInspector.DialogDelegate.call(this); 40 41 var xhr = new XMLHttpRequest(); 42 xhr.open("GET", "filteredItemSelectionDialog.css", false); 43 xhr.send(null); 44 45 this.element = document.createElement("div"); 46 this.element.className = "filtered-item-list-dialog"; 47 this.element.addEventListener("keydown", this._onKeyDown.bind(this), false); 48 var styleElement = this.element.createChild("style"); 49 styleElement.type = "text/css"; 50 styleElement.textContent = xhr.responseText; 51 52 this._promptElement = this.element.createChild("input", "monospace"); 53 this._promptElement.addEventListener("input", this._onInput.bind(this), false); 54 this._promptElement.type = "text"; 55 this._promptElement.setAttribute("spellcheck", "false"); 56 57 this._filteredItems = []; 58 this._viewportControl = new WebInspector.ViewportControl(this); 59 this._itemElementsContainer = this._viewportControl.element; 60 this._itemElementsContainer.classList.add("container"); 61 this._itemElementsContainer.classList.add("monospace"); 62 this._itemElementsContainer.addEventListener("click", this._onClick.bind(this), false); 63 this.element.appendChild(this._itemElementsContainer); 64 65 this._delegate = delegate; 66 this._delegate.setRefreshCallback(this._itemsLoaded.bind(this)); 67 this._itemsLoaded(); 68 69 this._shouldShowMatchingItems = true; 70} 71 72WebInspector.FilteredItemSelectionDialog.prototype = { 73 /** 74 * @param {!Element} element 75 * @param {!Element} relativeToElement 76 */ 77 position: function(element, relativeToElement) 78 { 79 const minWidth = 500; 80 const minHeight = 204; 81 var width = Math.max(relativeToElement.offsetWidth * 2 / 3, minWidth); 82 var height = Math.max(relativeToElement.offsetHeight * 2 / 3, minHeight); 83 84 this.element.style.width = width + "px"; 85 86 const shadowPadding = 20; // shadow + padding 87 element.positionAt( 88 relativeToElement.totalOffsetLeft() + Math.max((relativeToElement.offsetWidth - width - 2 * shadowPadding) / 2, shadowPadding), 89 relativeToElement.totalOffsetTop() + Math.max((relativeToElement.offsetHeight - height - 2 * shadowPadding) / 2, shadowPadding)); 90 this._dialogHeight = height; 91 92 this._updateShowMatchingItems(); 93 }, 94 95 focus: function() 96 { 97 WebInspector.setCurrentFocusElement(this._promptElement); 98 if (this._filteredItems.length && this._viewportControl.lastVisibleIndex() === -1) 99 this._viewportControl.refresh(); 100 }, 101 102 willHide: function() 103 { 104 if (this._isHiding) 105 return; 106 this._isHiding = true; 107 this._delegate.dispose(); 108 if (this._filterTimer) 109 clearTimeout(this._filterTimer); 110 }, 111 112 renderAsTwoRows: function() 113 { 114 this._renderAsTwoRows = true; 115 }, 116 117 onEnter: function() 118 { 119 if (!this._delegate.itemCount()) 120 return; 121 this._delegate.selectItem(this._filteredItems[this._selectedIndexInFiltered], this._promptElement.value.trim()); 122 }, 123 124 _itemsLoaded: function() 125 { 126 127 if (this._loadTimeout) 128 return; 129 this._loadTimeout = setTimeout(this._updateAfterItemsLoaded.bind(this), 0); 130 }, 131 132 _updateAfterItemsLoaded: function() 133 { 134 delete this._loadTimeout; 135 this._filterItems(); 136 }, 137 138 /** 139 * @param {number} index 140 * @return {!Element} 141 */ 142 _createItemElement: function(index) 143 { 144 var itemElement = document.createElement("div"); 145 itemElement.className = "filtered-item-list-dialog-item " + (this._renderAsTwoRows ? "two-rows" : "one-row"); 146 itemElement._titleElement = itemElement.createChild("span"); 147 itemElement._titleSuffixElement = itemElement.createChild("span"); 148 itemElement._subtitleElement = itemElement.createChild("div", "filtered-item-list-dialog-subtitle"); 149 itemElement._subtitleElement.textContent = "\u200B"; 150 itemElement._index = index; 151 this._delegate.renderItem(index, this._promptElement.value.trim(), itemElement._titleElement, itemElement._subtitleElement); 152 return itemElement; 153 }, 154 155 /** 156 * @param {string} query 157 */ 158 setQuery: function(query) 159 { 160 this._promptElement.value = query; 161 this._scheduleFilter(); 162 }, 163 164 _filterItems: function() 165 { 166 delete this._filterTimer; 167 if (this._scoringTimer) { 168 clearTimeout(this._scoringTimer); 169 delete this._scoringTimer; 170 } 171 172 var query = this._delegate.rewriteQuery(this._promptElement.value.trim()); 173 this._query = query; 174 var queryLength = query.length; 175 var filterRegex = query ? WebInspector.FilePathScoreFunction.filterRegex(query) : null; 176 177 var oldSelectedAbsoluteIndex = this._selectedIndexInFiltered ? this._filteredItems[this._selectedIndexInFiltered] : null; 178 var filteredItems = []; 179 this._selectedIndexInFiltered = 0; 180 181 var bestScores = []; 182 var bestItems = []; 183 var bestItemsToCollect = 100; 184 var minBestScore = 0; 185 var overflowItems = []; 186 187 scoreItems.call(this, 0); 188 189 /** 190 * @param {number} a 191 * @param {number} b 192 * @return {number} 193 */ 194 function compareIntegers(a, b) 195 { 196 return b - a; 197 } 198 199 /** 200 * @param {number} fromIndex 201 * @this {WebInspector.FilteredItemSelectionDialog} 202 */ 203 function scoreItems(fromIndex) 204 { 205 var maxWorkItems = 1000; 206 var workDone = 0; 207 for (var i = fromIndex; i < this._delegate.itemCount() && workDone < maxWorkItems; ++i) { 208 // Filter out non-matching items quickly. 209 if (filterRegex && !filterRegex.test(this._delegate.itemKeyAt(i))) 210 continue; 211 212 // Score item. 213 var score = this._delegate.itemScoreAt(i, query); 214 if (query) 215 workDone++; 216 217 // Find its index in the scores array (earlier elements have bigger scores). 218 if (score > minBestScore || bestScores.length < bestItemsToCollect) { 219 var index = insertionIndexForObjectInListSortedByFunction(score, bestScores, compareIntegers, true); 220 bestScores.splice(index, 0, score); 221 bestItems.splice(index, 0, i); 222 if (bestScores.length > bestItemsToCollect) { 223 // Best list is too large -> drop last elements. 224 overflowItems.push(bestItems.peekLast()); 225 bestScores.length = bestItemsToCollect; 226 bestItems.length = bestItemsToCollect; 227 } 228 minBestScore = bestScores.peekLast(); 229 } else 230 filteredItems.push(i); 231 } 232 233 // Process everything in chunks. 234 if (i < this._delegate.itemCount()) { 235 this._scoringTimer = setTimeout(scoreItems.bind(this, i), 0); 236 return; 237 } 238 delete this._scoringTimer; 239 240 this._filteredItems = bestItems.concat(overflowItems).concat(filteredItems); 241 for (var i = 0; i < this._filteredItems.length; ++i) { 242 if (this._filteredItems[i] === oldSelectedAbsoluteIndex) { 243 this._selectedIndexInFiltered = i; 244 break; 245 } 246 } 247 this._viewportControl.refresh(); 248 if (!query) 249 this._selectedIndexInFiltered = 0; 250 this._updateSelection(this._selectedIndexInFiltered, false); 251 } 252 }, 253 254 _onInput: function(event) 255 { 256 this._shouldShowMatchingItems = this._delegate.shouldShowMatchingItems(this._promptElement.value); 257 this._updateShowMatchingItems(); 258 this._scheduleFilter(); 259 }, 260 261 _updateShowMatchingItems: function() 262 { 263 this._itemElementsContainer.enableStyleClass("hidden", !this._shouldShowMatchingItems); 264 this.element.style.height = this._shouldShowMatchingItems ? this._dialogHeight + "px" : "auto"; 265 }, 266 267 _onKeyDown: function(event) 268 { 269 var newSelectedIndex = this._selectedIndexInFiltered; 270 271 switch (event.keyCode) { 272 case WebInspector.KeyboardShortcut.Keys.Down.code: 273 if (++newSelectedIndex >= this._filteredItems.length) 274 newSelectedIndex = this._filteredItems.length - 1; 275 this._updateSelection(newSelectedIndex, true); 276 event.consume(true); 277 break; 278 case WebInspector.KeyboardShortcut.Keys.Up.code: 279 if (--newSelectedIndex < 0) 280 newSelectedIndex = 0; 281 this._updateSelection(newSelectedIndex, false); 282 event.consume(true); 283 break; 284 case WebInspector.KeyboardShortcut.Keys.PageDown.code: 285 newSelectedIndex = Math.min(newSelectedIndex + this._viewportControl.rowsPerViewport(), this._filteredItems.length - 1); 286 this._updateSelection(newSelectedIndex, true); 287 event.consume(true); 288 break; 289 case WebInspector.KeyboardShortcut.Keys.PageUp.code: 290 newSelectedIndex = Math.max(newSelectedIndex - this._viewportControl.rowsPerViewport(), 0); 291 this._updateSelection(newSelectedIndex, false); 292 event.consume(true); 293 break; 294 default: 295 } 296 }, 297 298 _scheduleFilter: function() 299 { 300 if (this._filterTimer) 301 return; 302 this._filterTimer = setTimeout(this._filterItems.bind(this), 0); 303 }, 304 305 /** 306 * @param {number} index 307 * @param {boolean} makeLast 308 */ 309 _updateSelection: function(index, makeLast) 310 { 311 var element = this._viewportControl.renderedElementAt(this._selectedIndexInFiltered); 312 if (element) 313 element.classList.remove("selected"); 314 this._viewportControl.scrollItemIntoView(index, makeLast); 315 this._selectedIndexInFiltered = index; 316 element = this._viewportControl.renderedElementAt(index); 317 if (element) 318 element.classList.add("selected"); 319 }, 320 321 _onClick: function(event) 322 { 323 var itemElement = event.target.enclosingNodeOrSelfWithClass("filtered-item-list-dialog-item"); 324 if (!itemElement) 325 return; 326 this._delegate.selectItem(itemElement._index, this._promptElement.value.trim()); 327 WebInspector.Dialog.hide(); 328 }, 329 330 /** 331 * @return {number} 332 */ 333 itemCount: function() 334 { 335 return this._filteredItems.length; 336 }, 337 338 /** 339 * @param {number} index 340 * @return {!Element} 341 */ 342 itemElement: function(index) 343 { 344 var delegateIndex = this._filteredItems[index]; 345 var element = this._createItemElement(delegateIndex); 346 if (index === this._selectedIndexInFiltered) 347 element.classList.add("selected"); 348 return element; 349 }, 350 351 __proto__: WebInspector.DialogDelegate.prototype 352} 353 354/** 355 * @constructor 356 */ 357WebInspector.SelectionDialogContentProvider = function() 358{ 359} 360 361WebInspector.SelectionDialogContentProvider.prototype = { 362 /** 363 * @param {function():void} refreshCallback 364 */ 365 setRefreshCallback: function(refreshCallback) 366 { 367 this._refreshCallback = refreshCallback; 368 }, 369 370 /** 371 * @param {string} query 372 * @return {boolean} 373 */ 374 shouldShowMatchingItems: function(query) 375 { 376 return true; 377 }, 378 379 /** 380 * @return {number} 381 */ 382 itemCount: function() 383 { 384 return 0; 385 }, 386 387 /** 388 * @param {number} itemIndex 389 * @return {string} 390 */ 391 itemKeyAt: function(itemIndex) 392 { 393 return ""; 394 }, 395 396 /** 397 * @param {number} itemIndex 398 * @param {string} query 399 * @return {number} 400 */ 401 itemScoreAt: function(itemIndex, query) 402 { 403 return 1; 404 }, 405 406 /** 407 * @param {number} itemIndex 408 * @param {string} query 409 * @param {!Element} titleElement 410 * @param {!Element} subtitleElement 411 */ 412 renderItem: function(itemIndex, query, titleElement, subtitleElement) 413 { 414 }, 415 416 /** 417 * @param {!Element} element 418 * @param {string} query 419 * @return {boolean} 420 */ 421 highlightRanges: function(element, query) 422 { 423 if (!query) 424 return false; 425 426 /** 427 * @param {string} text 428 * @param {string} query 429 * @return {?Array.<!WebInspector.SourceRange>} 430 */ 431 function rangesForMatch(text, query) 432 { 433 var sm = new difflib.SequenceMatcher(query, text); 434 var opcodes = sm.get_opcodes(); 435 var ranges = []; 436 437 for (var i = 0; i < opcodes.length; ++i) { 438 var opcode = opcodes[i]; 439 if (opcode[0] === "equal") 440 ranges.push(new WebInspector.SourceRange(opcode[3], opcode[4] - opcode[3])); 441 else if (opcode[0] !== "insert") 442 return null; 443 } 444 return ranges; 445 } 446 447 var text = element.textContent; 448 var ranges = rangesForMatch(text, query); 449 if (!ranges) 450 ranges = rangesForMatch(text.toUpperCase(), query.toUpperCase()); 451 if (ranges) { 452 WebInspector.highlightRangesWithStyleClass(element, ranges, "highlight"); 453 return true; 454 } 455 return false; 456 }, 457 458 /** 459 * @param {number} itemIndex 460 * @param {string} promptValue 461 */ 462 selectItem: function(itemIndex, promptValue) 463 { 464 }, 465 466 refresh: function() 467 { 468 this._refreshCallback(); 469 }, 470 471 /** 472 * @param {string} query 473 * @return {string} 474 */ 475 rewriteQuery: function(query) 476 { 477 return query; 478 }, 479 480 dispose: function() 481 { 482 } 483} 484 485/** 486 * @constructor 487 * @extends {WebInspector.SelectionDialogContentProvider} 488 * @param {!WebInspector.View} view 489 * @param {!WebInspector.ContentProvider} contentProvider 490 * @param {function(number, number)} selectItemCallback 491 */ 492WebInspector.JavaScriptOutlineDialog = function(view, contentProvider, selectItemCallback) 493{ 494 WebInspector.SelectionDialogContentProvider.call(this); 495 496 this._functionItems = []; 497 this._view = view; 498 this._selectItemCallback = selectItemCallback; 499 contentProvider.requestContent(this._contentAvailable.bind(this)); 500} 501 502/** 503 * @param {!WebInspector.View} view 504 * @param {!WebInspector.ContentProvider} contentProvider 505 * @param {function(number, number)} selectItemCallback 506 */ 507WebInspector.JavaScriptOutlineDialog.show = function(view, contentProvider, selectItemCallback) 508{ 509 if (WebInspector.Dialog.currentInstance()) 510 return null; 511 var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.JavaScriptOutlineDialog(view, contentProvider, selectItemCallback)); 512 WebInspector.Dialog.show(view.element, filteredItemSelectionDialog); 513} 514 515WebInspector.JavaScriptOutlineDialog.prototype = { 516 /** 517 * @param {?string} content 518 */ 519 _contentAvailable: function(content) 520 { 521 this._outlineWorker = new Worker("ScriptFormatterWorker.js"); 522 this._outlineWorker.onmessage = this._didBuildOutlineChunk.bind(this); 523 const method = "outline"; 524 this._outlineWorker.postMessage({ method: method, params: { content: content } }); 525 }, 526 527 _didBuildOutlineChunk: function(event) 528 { 529 var data = event.data; 530 var chunk = data["chunk"]; 531 for (var i = 0; i < chunk.length; ++i) 532 this._functionItems.push(chunk[i]); 533 534 if (data.total === data.index) 535 this.dispose(); 536 537 this.refresh(); 538 }, 539 540 /** 541 * @return {number} 542 */ 543 itemCount: function() 544 { 545 return this._functionItems.length; 546 }, 547 548 /** 549 * @param {number} itemIndex 550 * @return {string} 551 */ 552 itemKeyAt: function(itemIndex) 553 { 554 return this._functionItems[itemIndex].name; 555 }, 556 557 /** 558 * @param {number} itemIndex 559 * @param {string} query 560 * @return {number} 561 */ 562 itemScoreAt: function(itemIndex, query) 563 { 564 var item = this._functionItems[itemIndex]; 565 return -item.line; 566 }, 567 568 /** 569 * @param {number} itemIndex 570 * @param {string} query 571 * @param {!Element} titleElement 572 * @param {!Element} subtitleElement 573 */ 574 renderItem: function(itemIndex, query, titleElement, subtitleElement) 575 { 576 var item = this._functionItems[itemIndex]; 577 titleElement.textContent = item.name + (item.arguments ? item.arguments : ""); 578 this.highlightRanges(titleElement, query); 579 subtitleElement.textContent = ":" + (item.line + 1); 580 }, 581 582 /** 583 * @param {number} itemIndex 584 * @param {string} promptValue 585 */ 586 selectItem: function(itemIndex, promptValue) 587 { 588 var lineNumber = this._functionItems[itemIndex].line; 589 if (!isNaN(lineNumber) && lineNumber >= 0) 590 this._selectItemCallback(lineNumber, this._functionItems[itemIndex].column); 591 }, 592 593 dispose: function() 594 { 595 if (this._outlineWorker) { 596 this._outlineWorker.terminate(); 597 delete this._outlineWorker; 598 } 599 }, 600 601 __proto__: WebInspector.SelectionDialogContentProvider.prototype 602} 603 604/** 605 * @constructor 606 * @extends {WebInspector.SelectionDialogContentProvider} 607 * @param {!Map.<!WebInspector.UISourceCode, number>=} defaultScores 608 */ 609WebInspector.SelectUISourceCodeDialog = function(defaultScores) 610{ 611 WebInspector.SelectionDialogContentProvider.call(this); 612 613 /** @type {!Array.<!WebInspector.UISourceCode>} */ 614 this._uiSourceCodes = []; 615 var projects = WebInspector.workspace.projects().filter(this.filterProject.bind(this)); 616 for (var i = 0; i < projects.length; ++i) 617 this._uiSourceCodes = this._uiSourceCodes.concat(projects[i].uiSourceCodes()); 618 this._defaultScores = defaultScores; 619 this._scorer = new WebInspector.FilePathScoreFunction(""); 620 WebInspector.workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); 621} 622 623WebInspector.SelectUISourceCodeDialog.prototype = { 624 /** 625 * @param {?WebInspector.UISourceCode} uiSourceCode 626 * @param {number=} lineNumber 627 */ 628 uiSourceCodeSelected: function(uiSourceCode, lineNumber) 629 { 630 // Overridden by subclasses 631 }, 632 633 /** 634 * @param {!WebInspector.Project} project 635 */ 636 filterProject: function(project) 637 { 638 return true; 639 // Overridden by subclasses 640 }, 641 642 /** 643 * @return {number} 644 */ 645 itemCount: function() 646 { 647 return this._uiSourceCodes.length; 648 }, 649 650 /** 651 * @param {number} itemIndex 652 * @return {string} 653 */ 654 itemKeyAt: function(itemIndex) 655 { 656 return this._uiSourceCodes[itemIndex].fullDisplayName(); 657 }, 658 659 /** 660 * @param {number} itemIndex 661 * @param {string} query 662 * @return {number} 663 */ 664 itemScoreAt: function(itemIndex, query) 665 { 666 var uiSourceCode = this._uiSourceCodes[itemIndex]; 667 var score = this._defaultScores ? (this._defaultScores.get(uiSourceCode) || 0) : 0; 668 if (!query || query.length < 2) 669 return score; 670 671 if (this._query !== query) { 672 this._query = query; 673 this._scorer = new WebInspector.FilePathScoreFunction(query); 674 } 675 676 var path = uiSourceCode.fullDisplayName(); 677 return score + 10 * this._scorer.score(path, null); 678 }, 679 680 /** 681 * @param {number} itemIndex 682 * @param {string} query 683 * @param {!Element} titleElement 684 * @param {!Element} subtitleElement 685 */ 686 renderItem: function(itemIndex, query, titleElement, subtitleElement) 687 { 688 query = this.rewriteQuery(query); 689 var uiSourceCode = this._uiSourceCodes[itemIndex]; 690 titleElement.textContent = uiSourceCode.displayName() + (this._queryLineNumber ? this._queryLineNumber : ""); 691 subtitleElement.textContent = uiSourceCode.fullDisplayName().trimEnd(100); 692 693 var indexes = []; 694 var score = new WebInspector.FilePathScoreFunction(query).score(subtitleElement.textContent, indexes); 695 var fileNameIndex = subtitleElement.textContent.lastIndexOf("/"); 696 var ranges = []; 697 for (var i = 0; i < indexes.length; ++i) 698 ranges.push({offset: indexes[i], length: 1}); 699 if (indexes[0] > fileNameIndex) { 700 for (var i = 0; i < ranges.length; ++i) 701 ranges[i].offset -= fileNameIndex + 1; 702 return WebInspector.highlightRangesWithStyleClass(titleElement, ranges, "highlight"); 703 } else { 704 return WebInspector.highlightRangesWithStyleClass(subtitleElement, ranges, "highlight"); 705 } 706 }, 707 708 /** 709 * @param {number} itemIndex 710 * @param {string} promptValue 711 */ 712 selectItem: function(itemIndex, promptValue) 713 { 714 if (/^:\d+$/.test(promptValue.trimRight())) { 715 var lineNumber = parseInt(promptValue.trimRight().substring(1), 10) - 1; 716 if (!isNaN(lineNumber) && lineNumber >= 0) 717 this.uiSourceCodeSelected(null, lineNumber); 718 return; 719 } 720 var lineNumberMatch = promptValue.match(/[^:]+\:([\d]*)$/); 721 var lineNumber = lineNumberMatch ? Math.max(parseInt(lineNumberMatch[1], 10) - 1, 0) : undefined; 722 this.uiSourceCodeSelected(this._uiSourceCodes[itemIndex], lineNumber); 723 }, 724 725 /** 726 * @param {string} query 727 * @return {string} 728 */ 729 rewriteQuery: function(query) 730 { 731 if (!query) 732 return query; 733 query = query.trim(); 734 var lineNumberMatch = query.match(/([^:]+)(\:[\d]*)$/); 735 this._queryLineNumber = lineNumberMatch ? lineNumberMatch[2] : ""; 736 return lineNumberMatch ? lineNumberMatch[1] : query; 737 }, 738 739 /** 740 * @param {!WebInspector.Event} event 741 */ 742 _uiSourceCodeAdded: function(event) 743 { 744 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 745 if (!this.filterProject(uiSourceCode.project())) 746 return; 747 this._uiSourceCodes.push(uiSourceCode) 748 this.refresh(); 749 }, 750 751 dispose: function() 752 { 753 WebInspector.workspace.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); 754 }, 755 756 __proto__: WebInspector.SelectionDialogContentProvider.prototype 757} 758 759/** 760 * @constructor 761 * @extends {WebInspector.SelectUISourceCodeDialog} 762 * @param {!WebInspector.SourcesPanel} panel 763 * @param {!Map.<!WebInspector.UISourceCode, number>=} defaultScores 764 */ 765WebInspector.OpenResourceDialog = function(panel, defaultScores) 766{ 767 WebInspector.SelectUISourceCodeDialog.call(this, defaultScores); 768 this._panel = panel; 769} 770 771WebInspector.OpenResourceDialog.prototype = { 772 773 /** 774 * @param {?WebInspector.UISourceCode} uiSourceCode 775 * @param {number=} lineNumber 776 */ 777 uiSourceCodeSelected: function(uiSourceCode, lineNumber) 778 { 779 if (!uiSourceCode) 780 uiSourceCode = this._panel.currentUISourceCode(); 781 if (!uiSourceCode) 782 return; 783 this._panel.showUISourceCode(uiSourceCode, lineNumber); 784 }, 785 786 /** 787 * @param {string} query 788 * @return {boolean} 789 */ 790 shouldShowMatchingItems: function(query) 791 { 792 return !query.startsWith(":"); 793 }, 794 795 /** 796 * @param {!WebInspector.Project} project 797 */ 798 filterProject: function(project) 799 { 800 return !project.isServiceProject(); 801 }, 802 803 __proto__: WebInspector.SelectUISourceCodeDialog.prototype 804} 805 806/** 807 * @param {!WebInspector.SourcesPanel} panel 808 * @param {!Element} relativeToElement 809 * @param {string=} name 810 * @param {!Map.<!WebInspector.UISourceCode, number>=} defaultScores 811 */ 812WebInspector.OpenResourceDialog.show = function(panel, relativeToElement, name, defaultScores) 813{ 814 if (WebInspector.Dialog.currentInstance()) 815 return; 816 817 var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.OpenResourceDialog(panel, defaultScores)); 818 filteredItemSelectionDialog.renderAsTwoRows(); 819 if (name) 820 filteredItemSelectionDialog.setQuery(name); 821 WebInspector.Dialog.show(relativeToElement, filteredItemSelectionDialog); 822} 823 824/** 825 * @constructor 826 * @extends {WebInspector.SelectUISourceCodeDialog} 827 * @param {string} type 828 * @param {function(!WebInspector.UISourceCode)} callback 829 */ 830WebInspector.SelectUISourceCodeForProjectTypeDialog = function(type, callback) 831{ 832 this._type = type; 833 WebInspector.SelectUISourceCodeDialog.call(this); 834 this._callback = callback; 835} 836 837WebInspector.SelectUISourceCodeForProjectTypeDialog.prototype = { 838 /** 839 * @param {!WebInspector.UISourceCode} uiSourceCode 840 * @param {number=} lineNumber 841 */ 842 uiSourceCodeSelected: function(uiSourceCode, lineNumber) 843 { 844 this._callback(uiSourceCode); 845 }, 846 847 /** 848 * @param {!WebInspector.Project} project 849 */ 850 filterProject: function(project) 851 { 852 return project.type() === this._type; 853 }, 854 855 __proto__: WebInspector.SelectUISourceCodeDialog.prototype 856} 857 858/** 859 * @param {string} type 860 * @param {function(!WebInspector.UISourceCode)} callback 861 * @param {!Element} relativeToElement 862 */ 863WebInspector.SelectUISourceCodeForProjectTypeDialog.show = function(name, type, callback, relativeToElement) 864{ 865 if (WebInspector.Dialog.currentInstance()) 866 return; 867 868 var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.SelectUISourceCodeForProjectTypeDialog(type, callback)); 869 filteredItemSelectionDialog.setQuery(name); 870 filteredItemSelectionDialog.renderAsTwoRows(); 871 WebInspector.Dialog.show(relativeToElement, filteredItemSelectionDialog); 872} 873