1/* 2 * Copyright (C) 2011 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. 20 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/** 30 * @interface 31 */ 32WebInspector.TabbedEditorContainerDelegate = function() { } 33 34WebInspector.TabbedEditorContainerDelegate.prototype = { 35 /** 36 * @param {!WebInspector.UISourceCode} uiSourceCode 37 * @return {!WebInspector.SourceFrame} 38 */ 39 viewForFile: function(uiSourceCode) { } 40} 41 42/** 43 * @constructor 44 * @extends {WebInspector.Object} 45 * @param {!WebInspector.TabbedEditorContainerDelegate} delegate 46 * @param {string} settingName 47 * @param {string} placeholderText 48 */ 49WebInspector.TabbedEditorContainer = function(delegate, settingName, placeholderText) 50{ 51 WebInspector.Object.call(this); 52 this._delegate = delegate; 53 54 this._tabbedPane = new WebInspector.TabbedPane(); 55 this._tabbedPane.setPlaceholderText(placeholderText); 56 this._tabbedPane.setTabDelegate(new WebInspector.EditorContainerTabDelegate(this)); 57 58 this._tabbedPane.closeableTabs = true; 59 this._tabbedPane.element.id = "sources-editor-container-tabbed-pane"; 60 61 this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this); 62 this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this); 63 64 this._tabIds = new Map(); 65 this._files = {}; 66 67 this._previouslyViewedFilesSetting = WebInspector.settings.createSetting(settingName, []); 68 this._history = WebInspector.TabbedEditorContainer.History.fromObject(this._previouslyViewedFilesSetting.get()); 69} 70 71WebInspector.TabbedEditorContainer.Events = { 72 EditorSelected: "EditorSelected", 73 EditorClosed: "EditorClosed" 74} 75 76WebInspector.TabbedEditorContainer._tabId = 0; 77 78WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount = 30; 79 80WebInspector.TabbedEditorContainer.prototype = { 81 /** 82 * @return {!WebInspector.View} 83 */ 84 get view() 85 { 86 return this._tabbedPane; 87 }, 88 89 /** 90 * @type {!WebInspector.SourceFrame} 91 */ 92 get visibleView() 93 { 94 return this._tabbedPane.visibleView; 95 }, 96 97 /** 98 * @param {!Element} parentElement 99 */ 100 show: function(parentElement) 101 { 102 this._tabbedPane.show(parentElement); 103 }, 104 105 /** 106 * @param {!WebInspector.UISourceCode} uiSourceCode 107 */ 108 showFile: function(uiSourceCode) 109 { 110 this._innerShowFile(uiSourceCode, true); 111 }, 112 113 /** 114 * @return {!Array.<!WebInspector.UISourceCode>} 115 */ 116 historyUISourceCodes: function() 117 { 118 // FIXME: there should be a way to fetch UISourceCode for its uri. 119 var uriToUISourceCode = {}; 120 for (var id in this._files) { 121 var uiSourceCode = this._files[id]; 122 uriToUISourceCode[uiSourceCode.uri()] = uiSourceCode; 123 } 124 125 var result = []; 126 var uris = this._history._urls(); 127 for (var i = 0; i < uris.length; ++i) { 128 var uiSourceCode = uriToUISourceCode[uris[i]]; 129 if (uiSourceCode) 130 result.push(uiSourceCode); 131 } 132 return result; 133 }, 134 135 _addScrollAndSelectionListeners: function() 136 { 137 if (!this._currentView) 138 return; 139 this._currentView.addEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this); 140 this._currentView.addEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this); 141 }, 142 143 _removeScrollAndSelectionListeners: function() 144 { 145 if (!this._currentView) 146 return; 147 this._currentView.removeEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this); 148 this._currentView.removeEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this); 149 }, 150 151 _scrollChanged: function(event) 152 { 153 var lineNumber = /** @type {number} */ (event.data); 154 this._history.updateScrollLineNumber(this._currentFile.uri(), lineNumber); 155 this._history.save(this._previouslyViewedFilesSetting); 156 }, 157 158 _selectionChanged: function(event) 159 { 160 var range = /** @type {!WebInspector.TextRange} */ (event.data); 161 this._history.updateSelectionRange(this._currentFile.uri(), range); 162 this._history.save(this._previouslyViewedFilesSetting); 163 }, 164 165 /** 166 * @param {!WebInspector.UISourceCode} uiSourceCode 167 * @param {boolean=} userGesture 168 */ 169 _innerShowFile: function(uiSourceCode, userGesture) 170 { 171 if (this._currentFile === uiSourceCode) 172 return; 173 174 this._removeScrollAndSelectionListeners(); 175 this._currentFile = uiSourceCode; 176 177 var tabId = this._tabIds.get(uiSourceCode) || this._appendFileTab(uiSourceCode, userGesture); 178 179 this._tabbedPane.selectTab(tabId, userGesture); 180 if (userGesture) 181 this._editorSelectedByUserAction(); 182 183 this._currentView = this.visibleView; 184 this._addScrollAndSelectionListeners(); 185 186 this.dispatchEventToListeners(WebInspector.TabbedEditorContainer.Events.EditorSelected, this._currentFile); 187 }, 188 189 /** 190 * @param {!WebInspector.UISourceCode} uiSourceCode 191 * @return {string} 192 */ 193 _titleForFile: function(uiSourceCode) 194 { 195 var maxDisplayNameLength = 30; 196 var title = uiSourceCode.displayName(true).trimMiddle(maxDisplayNameLength); 197 if (uiSourceCode.isDirty() || uiSourceCode.hasUnsavedCommittedChanges()) 198 title += "*"; 199 return title; 200 }, 201 202 /** 203 * @param {string} id 204 * @param {string} nextTabId 205 */ 206 _maybeCloseTab: function(id, nextTabId) 207 { 208 var uiSourceCode = this._files[id]; 209 var shouldPrompt = uiSourceCode.isDirty() && uiSourceCode.project().canSetFileContent(); 210 // FIXME: this should be replaced with common Save/Discard/Cancel dialog. 211 if (!shouldPrompt || confirm(WebInspector.UIString("Are you sure you want to close unsaved file: %s?", uiSourceCode.name()))) { 212 uiSourceCode.resetWorkingCopy(); 213 if (nextTabId) 214 this._tabbedPane.selectTab(nextTabId, true); 215 this._tabbedPane.closeTab(id, true); 216 return true; 217 } 218 return false; 219 }, 220 221 /** 222 * @param {!Array.<string>} ids 223 */ 224 _closeTabs: function(ids) 225 { 226 var dirtyTabs = []; 227 var cleanTabs = []; 228 for (var i = 0; i < ids.length; ++i) { 229 var id = ids[i]; 230 var uiSourceCode = this._files[id]; 231 if (uiSourceCode.isDirty()) 232 dirtyTabs.push(id); 233 else 234 cleanTabs.push(id); 235 } 236 if (dirtyTabs.length) 237 this._tabbedPane.selectTab(dirtyTabs[0], true); 238 this._tabbedPane.closeTabs(cleanTabs, true); 239 for (var i = 0; i < dirtyTabs.length; ++i) { 240 var nextTabId = i + 1 < dirtyTabs.length ? dirtyTabs[i + 1] : null; 241 if (!this._maybeCloseTab(dirtyTabs[i], nextTabId)) 242 break; 243 } 244 }, 245 246 /** 247 * @param {!WebInspector.UISourceCode} uiSourceCode 248 */ 249 addUISourceCode: function(uiSourceCode) 250 { 251 var uri = uiSourceCode.uri(); 252 if (this._userSelectedFiles) 253 return; 254 255 var index = this._history.index(uri) 256 if (index === -1) 257 return; 258 259 var tabId = this._tabIds.get(uiSourceCode) || this._appendFileTab(uiSourceCode, false); 260 261 if (!this._currentFile) 262 return; 263 264 // Select tab if this file was the last to be shown. 265 if (!index) { 266 this._innerShowFile(uiSourceCode, false); 267 return; 268 } 269 270 var currentProjectType = this._currentFile.project().type(); 271 var addedProjectType = uiSourceCode.project().type(); 272 var snippetsProjectType = WebInspector.projectTypes.Snippets; 273 if (this._history.index(this._currentFile.uri()) && currentProjectType === snippetsProjectType && addedProjectType !== snippetsProjectType) 274 this._innerShowFile(uiSourceCode, false); 275 }, 276 277 /** 278 * @param {!WebInspector.UISourceCode} uiSourceCode 279 */ 280 removeUISourceCode: function(uiSourceCode) 281 { 282 this.removeUISourceCodes([uiSourceCode]); 283 }, 284 285 /** 286 * @param {!Array.<!WebInspector.UISourceCode>} uiSourceCodes 287 */ 288 removeUISourceCodes: function(uiSourceCodes) 289 { 290 var tabIds = []; 291 for (var i = 0; i < uiSourceCodes.length; ++i) { 292 var uiSourceCode = uiSourceCodes[i]; 293 var tabId = this._tabIds.get(uiSourceCode); 294 if (tabId) 295 tabIds.push(tabId); 296 } 297 this._tabbedPane.closeTabs(tabIds); 298 }, 299 300 /** 301 * @param {!WebInspector.UISourceCode} uiSourceCode 302 */ 303 _editorClosedByUserAction: function(uiSourceCode) 304 { 305 this._userSelectedFiles = true; 306 this._history.remove(uiSourceCode.uri()); 307 this._updateHistory(); 308 }, 309 310 _editorSelectedByUserAction: function() 311 { 312 this._userSelectedFiles = true; 313 this._updateHistory(); 314 }, 315 316 _updateHistory: function() 317 { 318 var tabIds = this._tabbedPane.lastOpenedTabIds(WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount); 319 320 /** 321 * @param {string} tabId 322 * @this {WebInspector.TabbedEditorContainer} 323 */ 324 function tabIdToURI(tabId) 325 { 326 return this._files[tabId].uri(); 327 } 328 329 this._history.update(tabIds.map(tabIdToURI.bind(this))); 330 this._history.save(this._previouslyViewedFilesSetting); 331 }, 332 333 /** 334 * @param {!WebInspector.UISourceCode} uiSourceCode 335 * @return {string} 336 */ 337 _tooltipForFile: function(uiSourceCode) 338 { 339 return uiSourceCode.originURL(); 340 }, 341 342 /** 343 * @param {!WebInspector.UISourceCode} uiSourceCode 344 * @param {boolean=} userGesture 345 * @return {string} 346 */ 347 _appendFileTab: function(uiSourceCode, userGesture) 348 { 349 var view = this._delegate.viewForFile(uiSourceCode); 350 var title = this._titleForFile(uiSourceCode); 351 var tooltip = this._tooltipForFile(uiSourceCode); 352 353 var tabId = this._generateTabId(); 354 this._tabIds.put(uiSourceCode, tabId); 355 this._files[tabId] = uiSourceCode; 356 357 var savedSelectionRange = this._history.selectionRange(uiSourceCode.uri()); 358 if (savedSelectionRange) 359 view.setSelection(savedSelectionRange); 360 var savedScrollLineNumber = this._history.scrollLineNumber(uiSourceCode.uri()); 361 if (savedScrollLineNumber) 362 view.scrollToLine(savedScrollLineNumber); 363 364 this._tabbedPane.appendTab(tabId, title, view, tooltip, userGesture); 365 366 this._updateFileTitle(uiSourceCode); 367 this._addUISourceCodeListeners(uiSourceCode); 368 return tabId; 369 }, 370 371 /** 372 * @param {!WebInspector.Event} event 373 */ 374 _tabClosed: function(event) 375 { 376 var tabId = /** @type {string} */ (event.data.tabId); 377 var userGesture = /** @type {boolean} */ (event.data.isUserGesture); 378 379 var uiSourceCode = this._files[tabId]; 380 if (this._currentFile === uiSourceCode) { 381 this._removeScrollAndSelectionListeners(); 382 delete this._currentView; 383 delete this._currentFile; 384 } 385 this._tabIds.remove(uiSourceCode); 386 delete this._files[tabId]; 387 388 this._removeUISourceCodeListeners(uiSourceCode); 389 390 this.dispatchEventToListeners(WebInspector.TabbedEditorContainer.Events.EditorClosed, uiSourceCode); 391 392 if (userGesture) 393 this._editorClosedByUserAction(uiSourceCode); 394 }, 395 396 /** 397 * @param {!WebInspector.Event} event 398 */ 399 _tabSelected: function(event) 400 { 401 var tabId = /** @type {string} */ (event.data.tabId); 402 var userGesture = /** @type {boolean} */ (event.data.isUserGesture); 403 404 var uiSourceCode = this._files[tabId]; 405 this._innerShowFile(uiSourceCode, userGesture); 406 }, 407 408 /** 409 * @param {!WebInspector.UISourceCode} uiSourceCode 410 */ 411 _addUISourceCodeListeners: function(uiSourceCode) 412 { 413 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this); 414 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this); 415 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._uiSourceCodeWorkingCopyCommitted, this); 416 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SavedStateUpdated, this._uiSourceCodeSavedStateUpdated, this); 417 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormattedChanged, this); 418 }, 419 420 /** 421 * @param {!WebInspector.UISourceCode} uiSourceCode 422 */ 423 _removeUISourceCodeListeners: function(uiSourceCode) 424 { 425 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this); 426 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this); 427 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._uiSourceCodeWorkingCopyCommitted, this); 428 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SavedStateUpdated, this._uiSourceCodeSavedStateUpdated, this); 429 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormattedChanged, this); 430 }, 431 432 /** 433 * @param {!WebInspector.UISourceCode} uiSourceCode 434 */ 435 _updateFileTitle: function(uiSourceCode) 436 { 437 var tabId = this._tabIds.get(uiSourceCode); 438 if (tabId) { 439 var title = this._titleForFile(uiSourceCode); 440 this._tabbedPane.changeTabTitle(tabId, title); 441 if (uiSourceCode.hasUnsavedCommittedChanges()) 442 this._tabbedPane.setTabIcon(tabId, "editor-container-unsaved-committed-changes-icon", WebInspector.UIString("Changes to this file were not saved to file system.")); 443 else 444 this._tabbedPane.setTabIcon(tabId, ""); 445 } 446 }, 447 448 _uiSourceCodeTitleChanged: function(event) 449 { 450 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 451 this._updateFileTitle(uiSourceCode); 452 this._updateHistory(); 453 }, 454 455 _uiSourceCodeWorkingCopyChanged: function(event) 456 { 457 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 458 this._updateFileTitle(uiSourceCode); 459 }, 460 461 _uiSourceCodeWorkingCopyCommitted: function(event) 462 { 463 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 464 this._updateFileTitle(uiSourceCode); 465 }, 466 467 _uiSourceCodeSavedStateUpdated: function(event) 468 { 469 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 470 this._updateFileTitle(uiSourceCode); 471 }, 472 473 _uiSourceCodeFormattedChanged: function(event) 474 { 475 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 476 this._updateFileTitle(uiSourceCode); 477 }, 478 479 reset: function() 480 { 481 delete this._userSelectedFiles; 482 }, 483 484 /** 485 * @return {string} 486 */ 487 _generateTabId: function() 488 { 489 return "tab_" + (WebInspector.TabbedEditorContainer._tabId++); 490 }, 491 492 /** 493 * @return {!WebInspector.UISourceCode} uiSourceCode 494 */ 495 currentFile: function() 496 { 497 return this._currentFile; 498 }, 499 500 __proto__: WebInspector.Object.prototype 501} 502 503/** 504 * @constructor 505 * @param {string} url 506 * @param {!WebInspector.TextRange=} selectionRange 507 * @param {number=} scrollLineNumber 508 */ 509WebInspector.TabbedEditorContainer.HistoryItem = function(url, selectionRange, scrollLineNumber) 510{ 511 /** @const */ this.url = url; 512 /** @const */ this._isSerializable = url.length < WebInspector.TabbedEditorContainer.HistoryItem.serializableUrlLengthLimit; 513 this.selectionRange = selectionRange; 514 this.scrollLineNumber = scrollLineNumber; 515} 516 517WebInspector.TabbedEditorContainer.HistoryItem.serializableUrlLengthLimit = 4096; 518 519/** 520 * @param {!Object} serializedHistoryItem 521 * @return {!WebInspector.TabbedEditorContainer.HistoryItem} 522 */ 523WebInspector.TabbedEditorContainer.HistoryItem.fromObject = function (serializedHistoryItem) 524{ 525 var selectionRange = serializedHistoryItem.selectionRange ? WebInspector.TextRange.fromObject(serializedHistoryItem.selectionRange) : undefined; 526 return new WebInspector.TabbedEditorContainer.HistoryItem(serializedHistoryItem.url, selectionRange, serializedHistoryItem.scrollLineNumber); 527} 528 529WebInspector.TabbedEditorContainer.HistoryItem.prototype = { 530 /** 531 * @return {?Object} 532 */ 533 serializeToObject: function() 534 { 535 if (!this._isSerializable) 536 return null; 537 var serializedHistoryItem = {}; 538 serializedHistoryItem.url = this.url; 539 serializedHistoryItem.selectionRange = this.selectionRange; 540 serializedHistoryItem.scrollLineNumber = this.scrollLineNumber; 541 return serializedHistoryItem; 542 }, 543 544 __proto__: WebInspector.Object.prototype 545} 546 547/** 548 * @constructor 549 * @param {!Array.<!WebInspector.TabbedEditorContainer.HistoryItem>} items 550 */ 551WebInspector.TabbedEditorContainer.History = function(items) 552{ 553 this._items = items; 554 this._rebuildItemIndex(); 555} 556 557/** 558 * @param {!Array.<!Object>} serializedHistory 559 * @return {!WebInspector.TabbedEditorContainer.History} 560 */ 561WebInspector.TabbedEditorContainer.History.fromObject = function(serializedHistory) 562{ 563 var items = []; 564 for (var i = 0; i < serializedHistory.length; ++i) 565 items.push(WebInspector.TabbedEditorContainer.HistoryItem.fromObject(serializedHistory[i])); 566 return new WebInspector.TabbedEditorContainer.History(items); 567} 568 569WebInspector.TabbedEditorContainer.History.prototype = { 570 /** 571 * @param {string} url 572 * @return {number} 573 */ 574 index: function(url) 575 { 576 var index = this._itemsIndex[url]; 577 if (typeof index === "number") 578 return index; 579 return -1; 580 }, 581 582 _rebuildItemIndex: function() 583 { 584 this._itemsIndex = {}; 585 for (var i = 0; i < this._items.length; ++i) { 586 console.assert(!this._itemsIndex.hasOwnProperty(this._items[i].url)); 587 this._itemsIndex[this._items[i].url] = i; 588 } 589 }, 590 591 /** 592 * @param {string} url 593 * @return {!WebInspector.TextRange|undefined} 594 */ 595 selectionRange: function(url) 596 { 597 var index = this.index(url); 598 return index !== -1 ? this._items[index].selectionRange : undefined; 599 }, 600 601 /** 602 * @param {string} url 603 * @param {!WebInspector.TextRange=} selectionRange 604 */ 605 updateSelectionRange: function(url, selectionRange) 606 { 607 if (!selectionRange) 608 return; 609 var index = this.index(url); 610 if (index === -1) 611 return; 612 this._items[index].selectionRange = selectionRange; 613 }, 614 615 /** 616 * @param {string} url 617 * @return {number|undefined} 618 */ 619 scrollLineNumber: function(url) 620 { 621 var index = this.index(url); 622 return index !== -1 ? this._items[index].scrollLineNumber : undefined; 623 }, 624 625 /** 626 * @param {string} url 627 * @param {number} scrollLineNumber 628 */ 629 updateScrollLineNumber: function(url, scrollLineNumber) 630 { 631 var index = this.index(url); 632 if (index === -1) 633 return; 634 this._items[index].scrollLineNumber = scrollLineNumber; 635 }, 636 637 /** 638 * @param {!Array.<string>} urls 639 */ 640 update: function(urls) 641 { 642 for (var i = urls.length - 1; i >= 0; --i) { 643 var index = this.index(urls[i]); 644 var item; 645 if (index !== -1) { 646 item = this._items[index]; 647 this._items.splice(index, 1); 648 } else 649 item = new WebInspector.TabbedEditorContainer.HistoryItem(urls[i]); 650 this._items.unshift(item); 651 this._rebuildItemIndex(); 652 } 653 }, 654 655 /** 656 * @param {string} url 657 */ 658 remove: function(url) 659 { 660 var index = this.index(url); 661 if (index !== -1) { 662 this._items.splice(index, 1); 663 this._rebuildItemIndex(); 664 } 665 }, 666 667 /** 668 * @param {!WebInspector.Setting} setting 669 */ 670 save: function(setting) 671 { 672 setting.set(this._serializeToObject()); 673 }, 674 675 /** 676 * @return {!Array.<!Object>} 677 */ 678 _serializeToObject: function() 679 { 680 var serializedHistory = []; 681 for (var i = 0; i < this._items.length; ++i) { 682 var serializedItem = this._items[i].serializeToObject(); 683 if (serializedItem) 684 serializedHistory.push(serializedItem); 685 if (serializedHistory.length === WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount) 686 break; 687 } 688 return serializedHistory; 689 }, 690 691 692 /** 693 * @return {!Array.<string>} 694 */ 695 _urls: function() 696 { 697 var result = []; 698 for (var i = 0; i < this._items.length; ++i) 699 result.push(this._items[i].url); 700 return result; 701 }, 702 703 __proto__: WebInspector.Object.prototype 704} 705 706/** 707 * @constructor 708 * @implements {WebInspector.TabbedPaneTabDelegate} 709 * @param {!WebInspector.TabbedEditorContainer} editorContainer 710 */ 711WebInspector.EditorContainerTabDelegate = function(editorContainer) 712{ 713 this._editorContainer = editorContainer; 714} 715 716WebInspector.EditorContainerTabDelegate.prototype = { 717 /** 718 * @param {!WebInspector.TabbedPane} tabbedPane 719 * @param {!Array.<string>} ids 720 */ 721 closeTabs: function(tabbedPane, ids) 722 { 723 this._editorContainer._closeTabs(ids); 724 } 725} 726