Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(614)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js

Issue 2805593002: DevTools: Navigate TabbedPane with arrow keys (Closed)
Patch Set: nextTabElement Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved. 2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 25 matching lines...) Expand all
36 super(true); 36 super(true);
37 this.registerRequiredCSS('ui/tabbedPane.css'); 37 this.registerRequiredCSS('ui/tabbedPane.css');
38 this.element.classList.add('tabbed-pane'); 38 this.element.classList.add('tabbed-pane');
39 this.contentElement.classList.add('tabbed-pane-shadow'); 39 this.contentElement.classList.add('tabbed-pane-shadow');
40 this.contentElement.tabIndex = -1; 40 this.contentElement.tabIndex = -1;
41 this._headerElement = this.contentElement.createChild('div', 'tabbed-pane-he ader'); 41 this._headerElement = this.contentElement.createChild('div', 'tabbed-pane-he ader');
42 this._headerContentsElement = this._headerElement.createChild('div', 'tabbed -pane-header-contents'); 42 this._headerContentsElement = this._headerElement.createChild('div', 'tabbed -pane-header-contents');
43 this._tabSlider = createElementWithClass('div', 'tabbed-pane-tab-slider'); 43 this._tabSlider = createElementWithClass('div', 'tabbed-pane-tab-slider');
44 this._tabsElement = this._headerContentsElement.createChild('div', 'tabbed-p ane-header-tabs'); 44 this._tabsElement = this._headerContentsElement.createChild('div', 'tabbed-p ane-header-tabs');
45 this._tabsElement.setAttribute('role', 'tablist'); 45 this._tabsElement.setAttribute('role', 'tablist');
46 this._tabsElement.addEventListener('keydown', this._keyDown.bind(this), fals e);
46 this._contentElement = this.contentElement.createChild('div', 'tabbed-pane-c ontent'); 47 this._contentElement = this.contentElement.createChild('div', 'tabbed-pane-c ontent');
47 this._contentElement.setAttribute('role', 'tabpanel'); 48 this._contentElement.setAttribute('role', 'tabpanel');
48 this._contentElement.createChild('content'); 49 this._contentElement.createChild('content');
49 /** @type {!Array.<!UI.TabbedPaneTab>} */ 50 /** @type {!Array.<!UI.TabbedPaneTab>} */
50 this._tabs = []; 51 this._tabs = [];
51 /** @type {!Array.<!UI.TabbedPaneTab>} */ 52 /** @type {!Array.<!UI.TabbedPaneTab>} */
52 this._tabsHistory = []; 53 this._tabsHistory = [];
53 /** @type {!Map<string, !UI.TabbedPaneTab>} */ 54 /** @type {!Map<string, !UI.TabbedPaneTab>} */
54 this._tabsById = new Map(); 55 this._tabsById = new Map();
55 this._currentTabLocked = false; 56 this._currentTabLocked = false;
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 } 211 }
211 212
212 /** 213 /**
213 * @param {string} id 214 * @param {string} id
214 * @param {boolean=} userGesture 215 * @param {boolean=} userGesture
215 */ 216 */
216 closeTab(id, userGesture) { 217 closeTab(id, userGesture) {
217 this.closeTabs([id], userGesture); 218 this.closeTabs([id], userGesture);
218 } 219 }
219 220
221
220 /** 222 /**
221 * @param {!Array.<string>} ids 223 * @param {!Array.<string>} ids
222 * @param {boolean=} userGesture 224 * @param {boolean=} userGesture
223 */ 225 */
224 closeTabs(ids, userGesture) { 226 closeTabs(ids, userGesture) {
225 var focused = this.hasFocus(); 227 var focused = this.hasFocus();
226 for (var i = 0; i < ids.length; ++i) 228 for (var i = 0; i < ids.length; ++i)
227 this._innerCloseTab(ids[i], userGesture); 229 this._innerCloseTab(ids[i], userGesture);
228 this._updateTabElements(); 230 this._updateTabElements();
229 if (this._tabsHistory.length) 231 if (this._tabsHistory.length)
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 break; 301 break;
300 } 302 }
301 } 303 }
302 if (index === -1) 304 if (index === -1)
303 return []; 305 return [];
304 return this._tabs.slice(index + 1).map(function(tab) { 306 return this._tabs.slice(index + 1).map(function(tab) {
305 return tab.id; 307 return tab.id;
306 }); 308 });
307 } 309 }
308 310
311 _viewHasFocus() {
312 if (this.visibleView)
313 return this.visibleView.hasFocus();
314 return this.contentElement === this.contentElement.getComponentRoot().active Element;
315 }
316
309 /** 317 /**
310 * @param {string} id 318 * @param {string} id
311 * @param {boolean=} userGesture 319 * @param {boolean=} userGesture
312 * @return {boolean} 320 * @return {boolean}
313 */ 321 */
314 selectTab(id, userGesture) { 322 selectTab(id, userGesture) {
315 if (this._currentTabLocked) 323 if (this._currentTabLocked)
316 return false; 324 return false;
317 var focused = this.hasFocus(); 325 var focused = this._viewHasFocus();
318 var tab = this._tabsById.get(id); 326 var tab = this._tabsById.get(id);
319 if (!tab) 327 if (!tab)
320 return false; 328 return false;
321 if (this._currentTab && this._currentTab.id === id) 329 if (this._currentTab && this._currentTab.id === id)
322 return true; 330 return true;
323 331
324 this.suspendInvalidations(); 332 this.suspendInvalidations();
325 this._hideCurrentTab(); 333 this._hideCurrentTab();
326 this._showTab(tab); 334 this._showTab(tab);
327 this.resumeInvalidations(); 335 this.resumeInvalidations();
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 */ 544 */
537 _hideTabElement(tab) { 545 _hideTabElement(tab) {
538 this._tabsElement.removeChild(tab.tabElement); 546 this._tabsElement.removeChild(tab.tabElement);
539 tab._shown = false; 547 tab._shown = false;
540 } 548 }
541 549
542 _createDropDownButton() { 550 _createDropDownButton() {
543 var dropDownContainer = createElementWithClass('div', 'tabbed-pane-header-ta bs-drop-down-container'); 551 var dropDownContainer = createElementWithClass('div', 'tabbed-pane-header-ta bs-drop-down-container');
544 var chevronIcon = UI.Icon.create('largeicon-chevron', 'chevron-icon'); 552 var chevronIcon = UI.Icon.create('largeicon-chevron', 'chevron-icon');
545 dropDownContainer.appendChild(chevronIcon); 553 dropDownContainer.appendChild(chevronIcon);
554 dropDownContainer.addEventListener('click', this._onDropDownMouseDown.bind(t his));
546 dropDownContainer.addEventListener('mousedown', this._onDropDownMouseDown.bi nd(this)); 555 dropDownContainer.addEventListener('mousedown', this._onDropDownMouseDown.bi nd(this));
547 return dropDownContainer; 556 return dropDownContainer;
548 } 557 }
549 558
550 /** 559 /**
551 * @param {!Event} event 560 * @param {!Event} event
552 */ 561 */
553 _onDropDownMouseDown(event) { 562 _onDropDownMouseDown(event) {
554 if (event.which !== 1) 563 if (event.which !== 1)
555 return; 564 return;
556 var menu = new UI.ContextMenu(event); 565 var rect = this._dropDownButton.getBoundingClientRect();
566 var menu = new UI.ContextMenu(event, false, rect.left, rect.bottom);
557 for (var i = 0; i < this._tabs.length; ++i) { 567 for (var i = 0; i < this._tabs.length; ++i) {
558 var tab = this._tabs[i]; 568 var tab = this._tabs[i];
559 if (tab._shown) 569 if (tab._shown)
560 continue; 570 continue;
561 menu.appendCheckboxItem(tab.title, this._dropDownMenuItemSelected.bind(thi s, tab), this._tabsHistory[0] === tab); 571 menu.appendCheckboxItem(tab.title, this._dropDownMenuItemSelected.bind(thi s, tab), this._tabsHistory[0] === tab);
562 } 572 }
563 menu.show(); 573 menu.show();
564 } 574 }
565 575
566 /** 576 /**
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 return; 759 return;
750 760
751 this._hideTab(this._currentTab); 761 this._hideTab(this._currentTab);
752 delete this._currentTab; 762 delete this._currentTab;
753 } 763 }
754 764
755 /** 765 /**
756 * @param {!UI.TabbedPaneTab} tab 766 * @param {!UI.TabbedPaneTab} tab
757 */ 767 */
758 _showTab(tab) { 768 _showTab(tab) {
769 tab.tabElement.tabIndex = 0;
759 tab.tabElement.classList.add('selected'); 770 tab.tabElement.classList.add('selected');
760 UI.ARIAUtils.setSelected(tab.tabElement, true); 771 UI.ARIAUtils.setSelected(tab.tabElement, true);
761 tab.view.show(this.element); 772 tab.view.show(this.element);
762 this._updateTabSlider(); 773 this._updateTabSlider();
763 } 774 }
764 775
765 _updateTabSlider() { 776 _updateTabSlider() {
766 if (!this._currentTab || !this._sliderEnabled) 777 if (!this._currentTab || !this._sliderEnabled)
767 return; 778 return;
768 var left = 0; 779 var left = 0;
769 for (var i = 0; i < this._tabs.length && this._currentTab !== this._tabs[i] && this._tabs[i]._shown; i++) 780 for (var i = 0; i < this._tabs.length && this._currentTab !== this._tabs[i] && this._tabs[i]._shown; i++)
770 left += this._tabs[i]._measuredWidth; 781 left += this._tabs[i]._measuredWidth;
771 var sliderWidth = this._currentTab._shown ? this._currentTab._measuredWidth : this._dropDownButton.offsetWidth; 782 var sliderWidth = this._currentTab._shown ? this._currentTab._measuredWidth : this._dropDownButton.offsetWidth;
772 var scaleFactor = window.devicePixelRatio >= 1.5 ? ' scaleY(0.75)' : ''; 783 var scaleFactor = window.devicePixelRatio >= 1.5 ? ' scaleY(0.75)' : '';
773 this._tabSlider.style.transform = 'translateX(' + left + 'px)' + scaleFactor ; 784 this._tabSlider.style.transform = 'translateX(' + left + 'px)' + scaleFactor ;
774 this._tabSlider.style.width = sliderWidth + 'px'; 785 this._tabSlider.style.width = sliderWidth + 'px';
775 786
776 if (this._tabSlider.parentElement !== this._headerContentsElement) 787 if (this._tabSlider.parentElement !== this._headerContentsElement)
777 this._headerContentsElement.appendChild(this._tabSlider); 788 this._headerContentsElement.appendChild(this._tabSlider);
778 } 789 }
779 790
780 /** 791 /**
781 * @param {!UI.TabbedPaneTab} tab 792 * @param {!UI.TabbedPaneTab} tab
782 */ 793 */
783 _hideTab(tab) { 794 _hideTab(tab) {
795 tab.tabElement.removeAttribute('tabIndex');
784 tab.tabElement.classList.remove('selected'); 796 tab.tabElement.classList.remove('selected');
785 tab.tabElement.setAttribute('aria-selected', 'false'); 797 tab.tabElement.setAttribute('aria-selected', 'false');
786 tab.view.detach(); 798 tab.view.detach();
787 } 799 }
788 800
789 /** 801 /**
790 * @override 802 * @override
791 * @return {!Array.<!Element>} 803 * @return {!Array.<!Element>}
792 */ 804 */
793 elementsToRestoreScrollPositionsFor() { 805 elementsToRestoreScrollPositionsFor() {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 } 847 }
836 848
837 /** 849 /**
838 * @param {boolean} allow 850 * @param {boolean} allow
839 * @param {boolean=} automatic 851 * @param {boolean=} automatic
840 */ 852 */
841 setAllowTabReorder(allow, automatic) { 853 setAllowTabReorder(allow, automatic) {
842 this._allowTabReorder = allow; 854 this._allowTabReorder = allow;
843 this._automaticReorder = automatic; 855 this._automaticReorder = automatic;
844 } 856 }
857
858 /**
859 * @param {!Event} event
860 */
861 _keyDown(event) {
862 if (!this._currentTab)
863 return;
864 var nextTabElement = null;
865 switch (event.keyCode) {
866 case UI.KeyboardShortcut.Keys.Up.code:
867 case UI.KeyboardShortcut.Keys.Left.code:
868 nextTabElement = this._currentTab.tabElement.previousElementSibling;
aboxhall 2017/04/17 23:03:36 Sorry for not noticing this the first time around,
einbinder 2017/04/18 18:45:22 It would be nicer to use this._tabs, but this._tab
869 if (!nextTabElement && !this._dropDownButton.parentElement)
870 nextTabElement = this._currentTab.tabElement.parentElement.lastElement Child;
871 break;
872 case UI.KeyboardShortcut.Keys.Down.code:
873 case UI.KeyboardShortcut.Keys.Right.code:
874 nextTabElement = this._currentTab.tabElement.nextElementSibling;
875 if (!nextTabElement && !this._dropDownButton.parentElement)
876 nextTabElement = this._currentTab.tabElement.parentElement.firstElemen tChild;
877 break;
878 case UI.KeyboardShortcut.Keys.Enter.code:
879 case UI.KeyboardShortcut.Keys.Space.code:
880 this._currentTab.view.focus();
881 return;
882 default:
883 return;
884 }
885 if (!nextTabElement) {
886 this._dropDownButton.click();
887 return;
888 }
889 var tab = this._tabs.find(tab => tab.tabElement === nextTabElement);
890 this.selectTab(tab.id, true);
891 nextTabElement.focus();
aboxhall 2017/04/17 23:03:36 Why not make focusing the tab part of selectTab()?
einbinder 2017/04/18 18:45:21 selectTab is also called for things like Ctrl+] sh
892 }
845 }; 893 };
846 894
847 /** @enum {symbol} */ 895 /** @enum {symbol} */
848 UI.TabbedPane.Events = { 896 UI.TabbedPane.Events = {
849 TabSelected: Symbol('TabSelected'), 897 TabSelected: Symbol('TabSelected'),
850 TabClosed: Symbol('TabClosed'), 898 TabClosed: Symbol('TabClosed'),
851 TabOrderChanged: Symbol('TabOrderChanged') 899 TabOrderChanged: Symbol('TabOrderChanged')
852 }; 900 };
853 901
854 /** 902 /**
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1019 tabElement.__iconElement = iconContainer; 1067 tabElement.__iconElement = iconContainer;
1020 } 1068 }
1021 1069
1022 /** 1070 /**
1023 * @param {boolean} measuring 1071 * @param {boolean} measuring
1024 * @return {!Element} 1072 * @return {!Element}
1025 */ 1073 */
1026 _createTabElement(measuring) { 1074 _createTabElement(measuring) {
1027 var tabElement = createElementWithClass('div', 'tabbed-pane-header-tab'); 1075 var tabElement = createElementWithClass('div', 'tabbed-pane-header-tab');
1028 tabElement.id = 'tab-' + this._id; 1076 tabElement.id = 'tab-' + this._id;
1029 tabElement.tabIndex = -1;
1030 UI.ARIAUtils.markAsTab(tabElement); 1077 UI.ARIAUtils.markAsTab(tabElement);
1031 UI.ARIAUtils.setSelected(tabElement, false); 1078 UI.ARIAUtils.setSelected(tabElement, false);
1032 tabElement.selectTabForTest = this._tabbedPane.selectTab.bind(this._tabbedPa ne, this.id, true); 1079 tabElement.selectTabForTest = this._tabbedPane.selectTab.bind(this._tabbedPa ne, this.id, true);
1033 1080
1034 var titleElement = tabElement.createChild('span', 'tabbed-pane-header-tab-ti tle'); 1081 var titleElement = tabElement.createChild('span', 'tabbed-pane-header-tab-ti tle');
1035 titleElement.textContent = this.title; 1082 titleElement.textContent = this.title;
1036 titleElement.title = this.tooltip || ''; 1083 titleElement.title = this.tooltip || '';
1037 this._createIconElement(tabElement, titleElement, measuring); 1084 this._createIconElement(tabElement, titleElement, measuring);
1038 if (!measuring) 1085 if (!measuring)
1039 this._titleElement = titleElement; 1086 this._titleElement = titleElement;
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
1220 * @param {!Array.<string>} ids 1267 * @param {!Array.<string>} ids
1221 */ 1268 */
1222 closeTabs(tabbedPane, ids) {}, 1269 closeTabs(tabbedPane, ids) {},
1223 1270
1224 /** 1271 /**
1225 * @param {string} tabId 1272 * @param {string} tabId
1226 * @param {!UI.ContextMenu} contextMenu 1273 * @param {!UI.ContextMenu} contextMenu
1227 */ 1274 */
1228 onContextMenu(tabId, contextMenu) {} 1275 onContextMenu(tabId, contextMenu) {}
1229 }; 1276 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698