TabbedEditorContainer.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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. * @interface
  30. */
  31. WebInspector.TabbedEditorContainerDelegate = function() { }
  32. WebInspector.TabbedEditorContainerDelegate.prototype = {
  33. /**
  34. * @param {WebInspector.UISourceCode} uiSourceCode
  35. * @return {WebInspector.SourceFrame}
  36. */
  37. viewForFile: function(uiSourceCode) { }
  38. }
  39. /**
  40. * @constructor
  41. * @extends {WebInspector.Object}
  42. * @param {WebInspector.TabbedEditorContainerDelegate} delegate
  43. * @param {string} settingName
  44. */
  45. WebInspector.TabbedEditorContainer = function(delegate, settingName)
  46. {
  47. WebInspector.Object.call(this);
  48. this._delegate = delegate;
  49. this._tabbedPane = new WebInspector.TabbedPane();
  50. this._tabbedPane.setTabDelegate(new WebInspector.EditorContainerTabDelegate(this));
  51. this._tabbedPane.closeableTabs = true;
  52. this._tabbedPane.element.id = "scripts-editor-container-tabbed-pane";
  53. this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
  54. this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
  55. this._tabIds = new Map();
  56. this._files = {};
  57. this._loadedURIs = {};
  58. this._previouslyViewedFilesSetting = WebInspector.settings.createSetting(settingName, []);
  59. this._history = WebInspector.TabbedEditorContainer.History.fromObject(this._previouslyViewedFilesSetting.get());
  60. }
  61. WebInspector.TabbedEditorContainer.Events = {
  62. EditorSelected: "EditorSelected",
  63. EditorClosed: "EditorClosed"
  64. }
  65. WebInspector.TabbedEditorContainer._tabId = 0;
  66. WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount = 30;
  67. WebInspector.TabbedEditorContainer.prototype = {
  68. /**
  69. * @return {WebInspector.View}
  70. */
  71. get view()
  72. {
  73. return this._tabbedPane;
  74. },
  75. /**
  76. * @type {WebInspector.SourceFrame}
  77. */
  78. get visibleView()
  79. {
  80. return this._tabbedPane.visibleView;
  81. },
  82. /**
  83. * @param {Element} parentElement
  84. */
  85. show: function(parentElement)
  86. {
  87. this._tabbedPane.show(parentElement);
  88. },
  89. /**
  90. * @param {WebInspector.UISourceCode} uiSourceCode
  91. */
  92. showFile: function(uiSourceCode)
  93. {
  94. this._innerShowFile(uiSourceCode, true);
  95. },
  96. _addScrollAndSelectionListeners: function()
  97. {
  98. if (!this._currentView)
  99. return;
  100. this._currentView.addEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this);
  101. this._currentView.addEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this);
  102. },
  103. _removeScrollAndSelectionListeners: function()
  104. {
  105. if (!this._currentView)
  106. return;
  107. this._currentView.removeEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this);
  108. this._currentView.removeEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this);
  109. },
  110. _scrollChanged: function(event)
  111. {
  112. var lineNumber = /** @type {number} */ (event.data);
  113. this._history.updateScrollLineNumber(this._currentFile.uri(), lineNumber);
  114. this._history.save(this._previouslyViewedFilesSetting);
  115. },
  116. _selectionChanged: function(event)
  117. {
  118. var range = /** @type {WebInspector.TextRange} */ (event.data);
  119. this._history.updateSelectionRange(this._currentFile.uri(), range);
  120. this._history.save(this._previouslyViewedFilesSetting);
  121. },
  122. /**
  123. * @param {WebInspector.UISourceCode} uiSourceCode
  124. * @param {boolean=} userGesture
  125. */
  126. _innerShowFile: function(uiSourceCode, userGesture)
  127. {
  128. if (this._currentFile === uiSourceCode)
  129. return;
  130. this._removeScrollAndSelectionListeners();
  131. this._currentFile = uiSourceCode;
  132. var tabId = this._tabIds.get(uiSourceCode) || this._appendFileTab(uiSourceCode, userGesture);
  133. this._tabbedPane.selectTab(tabId, userGesture);
  134. if (userGesture)
  135. this._editorSelectedByUserAction();
  136. this._currentView = this.visibleView;
  137. this._addScrollAndSelectionListeners();
  138. this.dispatchEventToListeners(WebInspector.TabbedEditorContainer.Events.EditorSelected, this._currentFile);
  139. },
  140. /**
  141. * @param {WebInspector.UISourceCode} uiSourceCode
  142. * @return {string}
  143. */
  144. _titleForFile: function(uiSourceCode)
  145. {
  146. const maxDisplayNameLength = 30;
  147. const minDisplayQueryParamLength = 5;
  148. var title = uiSourceCode.name();
  149. title = title ? title.centerEllipsizedToLength(maxDisplayNameLength) : WebInspector.UIString("(program)");
  150. if (uiSourceCode.isDirty())
  151. title += "*";
  152. return title;
  153. },
  154. /**
  155. * @param {string} id
  156. * @param {string} nextTabId
  157. */
  158. _maybeCloseTab: function(id, nextTabId)
  159. {
  160. var uiSourceCode = this._files[id];
  161. var shouldPrompt = uiSourceCode.isDirty() && uiSourceCode.project().canSetFileContent();
  162. // FIXME: this should be replaced with common Save/Discard/Cancel dialog.
  163. if (!shouldPrompt || confirm(WebInspector.UIString("Are you sure you want to close unsaved file: %s?", uiSourceCode.name()))) {
  164. uiSourceCode.resetWorkingCopy();
  165. if (nextTabId)
  166. this._tabbedPane.selectTab(nextTabId, true);
  167. this._tabbedPane.closeTab(id, true);
  168. return true;
  169. }
  170. return false;
  171. },
  172. /**
  173. * @param {Array.<string>} ids
  174. */
  175. _closeTabs: function(ids)
  176. {
  177. var dirtyTabs = [];
  178. var cleanTabs = [];
  179. for (var i = 0; i < ids.length; ++i) {
  180. var id = ids[i];
  181. var uiSourceCode = this._files[id];
  182. if (uiSourceCode.isDirty())
  183. dirtyTabs.push(id);
  184. else
  185. cleanTabs.push(id);
  186. }
  187. if (dirtyTabs.length)
  188. this._tabbedPane.selectTab(dirtyTabs[0], true);
  189. this._tabbedPane.closeTabs(cleanTabs, true);
  190. for (var i = 0; i < dirtyTabs.length; ++i) {
  191. var nextTabId = i + 1 < dirtyTabs.length ? dirtyTabs[i + 1] : null;
  192. if (!this._maybeCloseTab(dirtyTabs[i], nextTabId))
  193. break;
  194. }
  195. },
  196. /**
  197. * @param {WebInspector.UISourceCode} uiSourceCode
  198. */
  199. addUISourceCode: function(uiSourceCode)
  200. {
  201. if (this._userSelectedFiles || this._loadedURIs[uiSourceCode.uri()])
  202. return;
  203. this._loadedURIs[uiSourceCode.uri()] = true;
  204. var index = this._history.index(uiSourceCode.uri())
  205. if (index === -1)
  206. return;
  207. var tabId = this._tabIds.get(uiSourceCode) || this._appendFileTab(uiSourceCode, false);
  208. if (!this._currentFile)
  209. return;
  210. // Select tab if this file was the last to be shown.
  211. if (!index) {
  212. this._innerShowFile(uiSourceCode, false);
  213. return;
  214. }
  215. var currentProjectType = this._currentFile.project().type();
  216. var addedProjectType = uiSourceCode.project().type();
  217. var snippetsProjectType = WebInspector.projectTypes.Snippets;
  218. if (this._history.index(this._currentFile.uri()) && currentProjectType === snippetsProjectType && addedProjectType !== snippetsProjectType)
  219. this._innerShowFile(uiSourceCode, false);
  220. },
  221. /**
  222. * @param {WebInspector.UISourceCode} uiSourceCode
  223. */
  224. removeUISourceCode: function(uiSourceCode)
  225. {
  226. this.removeUISourceCodes([uiSourceCode]);
  227. },
  228. /**
  229. * @param {Array.<WebInspector.UISourceCode>} uiSourceCodes
  230. */
  231. removeUISourceCodes: function(uiSourceCodes)
  232. {
  233. var tabIds = [];
  234. for (var i = 0; i < uiSourceCodes.length; ++i) {
  235. var uiSourceCode = uiSourceCodes[i];
  236. delete this._loadedURIs[uiSourceCode.uri()];
  237. var tabId = this._tabIds.get(uiSourceCode);
  238. if (tabId)
  239. tabIds.push(tabId);
  240. }
  241. this._tabbedPane.closeTabs(tabIds);
  242. },
  243. /**
  244. * @param {WebInspector.UISourceCode} uiSourceCode
  245. */
  246. _editorClosedByUserAction: function(uiSourceCode)
  247. {
  248. this._userSelectedFiles = true;
  249. this._history.remove(uiSourceCode.uri());
  250. this._updateHistory();
  251. },
  252. _editorSelectedByUserAction: function()
  253. {
  254. this._userSelectedFiles = true;
  255. this._updateHistory();
  256. },
  257. _updateHistory: function()
  258. {
  259. var tabIds = this._tabbedPane.lastOpenedTabIds(WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount);
  260. function tabIdToURI(tabId)
  261. {
  262. return this._files[tabId].uri();
  263. }
  264. this._history.update(tabIds.map(tabIdToURI.bind(this)));
  265. this._history.save(this._previouslyViewedFilesSetting);
  266. },
  267. /**
  268. * @param {WebInspector.UISourceCode} uiSourceCode
  269. * @return {string}
  270. */
  271. _tooltipForFile: function(uiSourceCode)
  272. {
  273. return uiSourceCode.originURL();
  274. },
  275. /**
  276. * @param {WebInspector.UISourceCode} uiSourceCode
  277. * @param {boolean=} userGesture
  278. */
  279. _appendFileTab: function(uiSourceCode, userGesture)
  280. {
  281. var view = this._delegate.viewForFile(uiSourceCode);
  282. var title = this._titleForFile(uiSourceCode);
  283. var tooltip = this._tooltipForFile(uiSourceCode);
  284. var tabId = this._generateTabId();
  285. this._tabIds.put(uiSourceCode, tabId);
  286. this._files[tabId] = uiSourceCode;
  287. var savedScrollLineNumber = this._history.scrollLineNumber(uiSourceCode.uri());
  288. if (savedScrollLineNumber)
  289. view.scrollToLine(savedScrollLineNumber);
  290. var savedSelectionRange = this._history.selectionRange(uiSourceCode.uri());
  291. if (savedSelectionRange)
  292. view.setSelection(savedSelectionRange);
  293. this._tabbedPane.appendTab(tabId, title, view, tooltip, userGesture);
  294. this._addUISourceCodeListeners(uiSourceCode);
  295. return tabId;
  296. },
  297. /**
  298. * @param {WebInspector.Event} event
  299. */
  300. _tabClosed: function(event)
  301. {
  302. var tabId = /** @type {string} */ (event.data.tabId);
  303. var userGesture = /** @type {boolean} */ (event.data.isUserGesture);
  304. var uiSourceCode = this._files[tabId];
  305. if (this._currentFile === uiSourceCode) {
  306. this._removeScrollAndSelectionListeners();
  307. delete this._currentView;
  308. delete this._currentFile;
  309. }
  310. this._tabIds.remove(uiSourceCode);
  311. delete this._files[tabId];
  312. this._removeUISourceCodeListeners(uiSourceCode);
  313. this.dispatchEventToListeners(WebInspector.TabbedEditorContainer.Events.EditorClosed, uiSourceCode);
  314. if (userGesture)
  315. this._editorClosedByUserAction(uiSourceCode);
  316. },
  317. /**
  318. * @param {WebInspector.Event} event
  319. */
  320. _tabSelected: function(event)
  321. {
  322. var tabId = /** @type {string} */ (event.data.tabId);
  323. var userGesture = /** @type {boolean} */ (event.data.isUserGesture);
  324. var uiSourceCode = this._files[tabId];
  325. this._innerShowFile(uiSourceCode, userGesture);
  326. },
  327. /**
  328. * @param {WebInspector.UISourceCode} uiSourceCode
  329. */
  330. _addUISourceCodeListeners: function(uiSourceCode)
  331. {
  332. uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this);
  333. uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this);
  334. uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._uiSourceCodeWorkingCopyCommitted, this);
  335. uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormattedChanged, this);
  336. },
  337. /**
  338. * @param {WebInspector.UISourceCode} uiSourceCode
  339. */
  340. _removeUISourceCodeListeners: function(uiSourceCode)
  341. {
  342. uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this);
  343. uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this);
  344. uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._uiSourceCodeWorkingCopyCommitted, this);
  345. uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormattedChanged, this);
  346. },
  347. /**
  348. * @param {WebInspector.UISourceCode} uiSourceCode
  349. */
  350. _updateFileTitle: function(uiSourceCode)
  351. {
  352. var tabId = this._tabIds.get(uiSourceCode);
  353. if (tabId) {
  354. var title = this._titleForFile(uiSourceCode);
  355. this._tabbedPane.changeTabTitle(tabId, title);
  356. }
  357. },
  358. _uiSourceCodeTitleChanged: function(event)
  359. {
  360. var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
  361. this._updateFileTitle(uiSourceCode);
  362. },
  363. _uiSourceCodeWorkingCopyChanged: function(event)
  364. {
  365. var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
  366. this._updateFileTitle(uiSourceCode);
  367. },
  368. _uiSourceCodeWorkingCopyCommitted: function(event)
  369. {
  370. var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
  371. this._updateFileTitle(uiSourceCode);
  372. },
  373. _uiSourceCodeFormattedChanged: function(event)
  374. {
  375. var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
  376. this._updateFileTitle(uiSourceCode);
  377. },
  378. reset: function()
  379. {
  380. delete this._userSelectedFiles;
  381. },
  382. /**
  383. * @return {string}
  384. */
  385. _generateTabId: function()
  386. {
  387. return "tab_" + (WebInspector.TabbedEditorContainer._tabId++);
  388. },
  389. /**
  390. * @return {WebInspector.UISourceCode} uiSourceCode
  391. */
  392. currentFile: function()
  393. {
  394. return this._currentFile;
  395. },
  396. __proto__: WebInspector.Object.prototype
  397. }
  398. /**
  399. * @constructor
  400. * @param {string} url
  401. * @param {WebInspector.TextRange=} selectionRange
  402. * @param {number=} scrollLineNumber
  403. */
  404. WebInspector.TabbedEditorContainer.HistoryItem = function(url, selectionRange, scrollLineNumber)
  405. {
  406. /** @const */ this.url = url;
  407. /** @const */ this._isSerializable = url.length < WebInspector.TabbedEditorContainer.HistoryItem.serializableUrlLengthLimit;
  408. this.selectionRange = selectionRange;
  409. this.scrollLineNumber = scrollLineNumber;
  410. }
  411. WebInspector.TabbedEditorContainer.HistoryItem.serializableUrlLengthLimit = 4096;
  412. /**
  413. * @param {Object} serializedHistoryItem
  414. * @return {WebInspector.TabbedEditorContainer.HistoryItem}
  415. */
  416. WebInspector.TabbedEditorContainer.HistoryItem.fromObject = function (serializedHistoryItem)
  417. {
  418. var selectionRange = serializedHistoryItem.selectionRange ? WebInspector.TextRange.fromObject(serializedHistoryItem.selectionRange) : null;
  419. return new WebInspector.TabbedEditorContainer.HistoryItem(serializedHistoryItem.url, selectionRange, serializedHistoryItem.scrollLineNumber);
  420. }
  421. WebInspector.TabbedEditorContainer.HistoryItem.prototype = {
  422. /**
  423. * @return {?Object}
  424. */
  425. serializeToObject: function()
  426. {
  427. if (!this._isSerializable)
  428. return null;
  429. var serializedHistoryItem = {};
  430. serializedHistoryItem.url = this.url;
  431. serializedHistoryItem.selectionRange = this.selectionRange;
  432. serializedHistoryItem.scrollLineNumber = this.scrollLineNumber;
  433. return serializedHistoryItem;
  434. },
  435. __proto__: WebInspector.Object.prototype
  436. }
  437. /**
  438. * @constructor
  439. * @param {Array.<WebInspector.TabbedEditorContainer.HistoryItem>} items
  440. */
  441. WebInspector.TabbedEditorContainer.History = function(items)
  442. {
  443. this._items = items;
  444. this._rebuildItemIndex();
  445. }
  446. /**
  447. * @param {!Array.<!Object>} serializedHistory
  448. * @return {WebInspector.TabbedEditorContainer.History}
  449. */
  450. WebInspector.TabbedEditorContainer.History.fromObject = function(serializedHistory)
  451. {
  452. var items = [];
  453. for (var i = 0; i < serializedHistory.length; ++i)
  454. items.push(WebInspector.TabbedEditorContainer.HistoryItem.fromObject(serializedHistory[i]));
  455. return new WebInspector.TabbedEditorContainer.History(items);
  456. }
  457. WebInspector.TabbedEditorContainer.History.prototype = {
  458. /**
  459. * @param {string} url
  460. * @return {number}
  461. */
  462. index: function(url)
  463. {
  464. var index = this._itemsIndex[url];
  465. if (typeof index === "number")
  466. return index;
  467. return -1;
  468. },
  469. _rebuildItemIndex: function()
  470. {
  471. this._itemsIndex = {};
  472. for (var i = 0; i < this._items.length; ++i) {
  473. console.assert(!this._itemsIndex.hasOwnProperty(this._items[i].url));
  474. this._itemsIndex[this._items[i].url] = i;
  475. }
  476. },
  477. /**
  478. * @param {string} url
  479. * @return {WebInspector.TextRange|undefined}
  480. */
  481. selectionRange: function(url)
  482. {
  483. var index = this.index(url);
  484. return index !== -1 ? this._items[index].selectionRange : undefined;
  485. },
  486. /**
  487. * @param {string} url
  488. * @param {WebInspector.TextRange} selectionRange
  489. */
  490. updateSelectionRange: function(url, selectionRange)
  491. {
  492. if (!selectionRange)
  493. return;
  494. var index = this.index(url);
  495. if (index === -1)
  496. return;
  497. this._items[index].selectionRange = selectionRange;
  498. },
  499. /**
  500. * @param {string} url
  501. * @return {number|undefined}
  502. */
  503. scrollLineNumber: function(url)
  504. {
  505. var index = this.index(url);
  506. return index !== -1 ? this._items[index].scrollLineNumber : undefined;
  507. },
  508. /**
  509. * @param {string} url
  510. * @param {number} scrollLineNumber
  511. */
  512. updateScrollLineNumber: function(url, scrollLineNumber)
  513. {
  514. var index = this.index(url);
  515. if (index === -1)
  516. return;
  517. this._items[index].scrollLineNumber = scrollLineNumber;
  518. },
  519. /**
  520. * @param {Array.<string>} urls
  521. */
  522. update: function(urls)
  523. {
  524. for (var i = urls.length - 1; i >= 0; --i) {
  525. var index = this.index(urls[i]);
  526. var item;
  527. if (index !== -1) {
  528. item = this._items[index];
  529. this._items.splice(index, 1);
  530. } else
  531. item = new WebInspector.TabbedEditorContainer.HistoryItem(urls[i]);
  532. this._items.unshift(item);
  533. this._rebuildItemIndex();
  534. }
  535. },
  536. /**
  537. * @param {string} url
  538. */
  539. remove: function(url)
  540. {
  541. var index = this.index(url);
  542. if (index !== -1) {
  543. this._items.splice(index, 1);
  544. this._rebuildItemIndex();
  545. }
  546. },
  547. /**
  548. * @param {WebInspector.Setting} setting
  549. */
  550. save: function(setting)
  551. {
  552. setting.set(this._serializeToObject());
  553. },
  554. /**
  555. * @return {!Array.<!Object>}
  556. */
  557. _serializeToObject: function()
  558. {
  559. var serializedHistory = [];
  560. for (var i = 0; i < this._items.length; ++i) {
  561. var serializedItem = this._items[i].serializeToObject();
  562. if (serializedItem)
  563. serializedHistory.push(serializedItem);
  564. if (serializedHistory.length === WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount)
  565. break;
  566. }
  567. return serializedHistory;
  568. },
  569. __proto__: WebInspector.Object.prototype
  570. }
  571. /**
  572. * @constructor
  573. * @implements {WebInspector.TabbedPaneTabDelegate}
  574. * @param {WebInspector.TabbedEditorContainer} editorContainer
  575. */
  576. WebInspector.EditorContainerTabDelegate = function(editorContainer)
  577. {
  578. this._editorContainer = editorContainer;
  579. }
  580. WebInspector.EditorContainerTabDelegate.prototype = {
  581. /**
  582. * @param {WebInspector.TabbedPane} tabbedPane
  583. * @param {Array.<string>} ids
  584. */
  585. closeTabs: function(tabbedPane, ids)
  586. {
  587. this._editorContainer._closeTabs(ids);
  588. }
  589. }