TabbedEditorContainer.js 23 KB

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