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

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: Fix stray space in test Created 3 years, 7 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 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 */ 549 */
542 _hideTabElement(tab) { 550 _hideTabElement(tab) {
543 this._tabsElement.removeChild(tab.tabElement); 551 this._tabsElement.removeChild(tab.tabElement);
544 tab._shown = false; 552 tab._shown = false;
545 } 553 }
546 554
547 _createDropDownButton() { 555 _createDropDownButton() {
548 var dropDownContainer = createElementWithClass('div', 'tabbed-pane-header-ta bs-drop-down-container'); 556 var dropDownContainer = createElementWithClass('div', 'tabbed-pane-header-ta bs-drop-down-container');
549 var chevronIcon = UI.Icon.create('largeicon-chevron', 'chevron-icon'); 557 var chevronIcon = UI.Icon.create('largeicon-chevron', 'chevron-icon');
550 dropDownContainer.appendChild(chevronIcon); 558 dropDownContainer.appendChild(chevronIcon);
559 dropDownContainer.addEventListener('click', this._onDropDownMouseDown.bind(t his));
551 dropDownContainer.addEventListener('mousedown', this._onDropDownMouseDown.bi nd(this)); 560 dropDownContainer.addEventListener('mousedown', this._onDropDownMouseDown.bi nd(this));
552 return dropDownContainer; 561 return dropDownContainer;
553 } 562 }
554 563
555 /** 564 /**
556 * @param {!Event} event 565 * @param {!Event} event
557 */ 566 */
558 _onDropDownMouseDown(event) { 567 _onDropDownMouseDown(event) {
559 if (event.which !== 1) 568 if (event.which !== 1)
560 return; 569 return;
561 var menu = new UI.ContextMenu(event); 570 var rect = this._dropDownButton.getBoundingClientRect();
571 var menu = new UI.ContextMenu(event, false, rect.left, rect.bottom);
562 for (var i = 0; i < this._tabs.length; ++i) { 572 for (var i = 0; i < this._tabs.length; ++i) {
563 var tab = this._tabs[i]; 573 var tab = this._tabs[i];
564 if (tab._shown) 574 if (tab._shown)
565 continue; 575 continue;
566 menu.appendCheckboxItem(tab.title, this._dropDownMenuItemSelected.bind(thi s, tab), this._tabsHistory[0] === tab); 576 menu.appendCheckboxItem(tab.title, this._dropDownMenuItemSelected.bind(thi s, tab), this._tabsHistory[0] === tab);
567 } 577 }
568 menu.show(); 578 menu.show();
569 } 579 }
570 580
571 /** 581 /**
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
754 return; 764 return;
755 765
756 this._hideTab(this._currentTab); 766 this._hideTab(this._currentTab);
757 delete this._currentTab; 767 delete this._currentTab;
758 } 768 }
759 769
760 /** 770 /**
761 * @param {!UI.TabbedPaneTab} tab 771 * @param {!UI.TabbedPaneTab} tab
762 */ 772 */
763 _showTab(tab) { 773 _showTab(tab) {
774 tab.tabElement.tabIndex = 0;
764 tab.tabElement.classList.add('selected'); 775 tab.tabElement.classList.add('selected');
765 UI.ARIAUtils.setSelected(tab.tabElement, true); 776 UI.ARIAUtils.setSelected(tab.tabElement, true);
766 tab.view.show(this.element); 777 tab.view.show(this.element);
767 this._updateTabSlider(); 778 this._updateTabSlider();
768 } 779 }
769 780
770 _updateTabSlider() { 781 _updateTabSlider() {
771 if (!this._currentTab || !this._sliderEnabled) 782 if (!this._currentTab || !this._sliderEnabled)
772 return; 783 return;
773 var left = 0; 784 var left = 0;
774 for (var i = 0; i < this._tabs.length && this._currentTab !== this._tabs[i] && this._tabs[i]._shown; i++) 785 for (var i = 0; i < this._tabs.length && this._currentTab !== this._tabs[i] && this._tabs[i]._shown; i++)
775 left += this._tabs[i]._measuredWidth; 786 left += this._tabs[i]._measuredWidth;
776 var sliderWidth = this._currentTab._shown ? this._currentTab._measuredWidth : this._dropDownButton.offsetWidth; 787 var sliderWidth = this._currentTab._shown ? this._currentTab._measuredWidth : this._dropDownButton.offsetWidth;
777 var scaleFactor = window.devicePixelRatio >= 1.5 ? ' scaleY(0.75)' : ''; 788 var scaleFactor = window.devicePixelRatio >= 1.5 ? ' scaleY(0.75)' : '';
778 this._tabSlider.style.transform = 'translateX(' + left + 'px)' + scaleFactor ; 789 this._tabSlider.style.transform = 'translateX(' + left + 'px)' + scaleFactor ;
779 this._tabSlider.style.width = sliderWidth + 'px'; 790 this._tabSlider.style.width = sliderWidth + 'px';
780 791
781 if (this._tabSlider.parentElement !== this._headerContentsElement) 792 if (this._tabSlider.parentElement !== this._headerContentsElement)
782 this._headerContentsElement.appendChild(this._tabSlider); 793 this._headerContentsElement.appendChild(this._tabSlider);
783 } 794 }
784 795
785 /** 796 /**
786 * @param {!UI.TabbedPaneTab} tab 797 * @param {!UI.TabbedPaneTab} tab
787 */ 798 */
788 _hideTab(tab) { 799 _hideTab(tab) {
800 tab.tabElement.removeAttribute('tabIndex');
789 tab.tabElement.classList.remove('selected'); 801 tab.tabElement.classList.remove('selected');
790 tab.tabElement.setAttribute('aria-selected', 'false'); 802 tab.tabElement.setAttribute('aria-selected', 'false');
791 tab.view.detach(); 803 tab.view.detach();
792 } 804 }
793 805
794 /** 806 /**
795 * @override 807 * @override
796 * @return {!Array.<!Element>} 808 * @return {!Array.<!Element>}
797 */ 809 */
798 elementsToRestoreScrollPositionsFor() { 810 elementsToRestoreScrollPositionsFor() {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 } 852 }
841 853
842 /** 854 /**
843 * @param {boolean} allow 855 * @param {boolean} allow
844 * @param {boolean=} automatic 856 * @param {boolean=} automatic
845 */ 857 */
846 setAllowTabReorder(allow, automatic) { 858 setAllowTabReorder(allow, automatic) {
847 this._allowTabReorder = allow; 859 this._allowTabReorder = allow;
848 this._automaticReorder = automatic; 860 this._automaticReorder = automatic;
849 } 861 }
862
863 /**
864 * @param {!Event} event
865 */
866 _keyDown(event) {
867 if (!this._currentTab)
868 return;
869 var nextTabElement = null;
870 switch (event.key) {
871 case 'ArrowUp':
872 case 'ArrowLeft':
873 nextTabElement = this._currentTab.tabElement.previousElementSibling;
874 if (!nextTabElement && !this._dropDownButton.parentElement)
875 nextTabElement = this._currentTab.tabElement.parentElement.lastElement Child;
876 break;
877 case 'ArrowDown':
878 case 'ArrowRight':
879 nextTabElement = this._currentTab.tabElement.nextElementSibling;
880 if (!nextTabElement && !this._dropDownButton.parentElement)
881 nextTabElement = this._currentTab.tabElement.parentElement.firstElemen tChild;
882 break;
883 case 'Enter':
884 case 'Space':
885 this._currentTab.view.focus();
886 return;
887 default:
888 return;
889 }
890 if (!nextTabElement) {
891 this._dropDownButton.click();
892 return;
893 }
894 var tab = this._tabs.find(tab => tab.tabElement === nextTabElement);
895 this.selectTab(tab.id, true);
896 nextTabElement.focus();
897 }
850 }; 898 };
851 899
852 /** @enum {symbol} */ 900 /** @enum {symbol} */
853 UI.TabbedPane.Events = { 901 UI.TabbedPane.Events = {
854 TabSelected: Symbol('TabSelected'), 902 TabSelected: Symbol('TabSelected'),
855 TabClosed: Symbol('TabClosed'), 903 TabClosed: Symbol('TabClosed'),
856 TabOrderChanged: Symbol('TabOrderChanged') 904 TabOrderChanged: Symbol('TabOrderChanged')
857 }; 905 };
858 906
859 /** 907 /**
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 tabElement.__iconElement = iconContainer; 1072 tabElement.__iconElement = iconContainer;
1025 } 1073 }
1026 1074
1027 /** 1075 /**
1028 * @param {boolean} measuring 1076 * @param {boolean} measuring
1029 * @return {!Element} 1077 * @return {!Element}
1030 */ 1078 */
1031 _createTabElement(measuring) { 1079 _createTabElement(measuring) {
1032 var tabElement = createElementWithClass('div', 'tabbed-pane-header-tab'); 1080 var tabElement = createElementWithClass('div', 'tabbed-pane-header-tab');
1033 tabElement.id = 'tab-' + this._id; 1081 tabElement.id = 'tab-' + this._id;
1034 tabElement.tabIndex = -1;
1035 UI.ARIAUtils.markAsTab(tabElement); 1082 UI.ARIAUtils.markAsTab(tabElement);
1036 UI.ARIAUtils.setSelected(tabElement, false); 1083 UI.ARIAUtils.setSelected(tabElement, false);
1037 tabElement.selectTabForTest = this._tabbedPane.selectTab.bind(this._tabbedPa ne, this.id, true); 1084 tabElement.selectTabForTest = this._tabbedPane.selectTab.bind(this._tabbedPa ne, this.id, true);
1038 1085
1039 var titleElement = tabElement.createChild('span', 'tabbed-pane-header-tab-ti tle'); 1086 var titleElement = tabElement.createChild('span', 'tabbed-pane-header-tab-ti tle');
1040 titleElement.textContent = this.title; 1087 titleElement.textContent = this.title;
1041 titleElement.title = this.tooltip || ''; 1088 titleElement.title = this.tooltip || '';
1042 this._createIconElement(tabElement, titleElement, measuring); 1089 this._createIconElement(tabElement, titleElement, measuring);
1043 if (!measuring) 1090 if (!measuring)
1044 this._titleElement = titleElement; 1091 this._titleElement = titleElement;
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
1225 * @param {!Array.<string>} ids 1272 * @param {!Array.<string>} ids
1226 */ 1273 */
1227 closeTabs(tabbedPane, ids) {}, 1274 closeTabs(tabbedPane, ids) {},
1228 1275
1229 /** 1276 /**
1230 * @param {string} tabId 1277 * @param {string} tabId
1231 * @param {!UI.ContextMenu} contextMenu 1278 * @param {!UI.ContextMenu} contextMenu
1232 */ 1279 */
1233 onContextMenu(tabId, contextMenu) {} 1280 onContextMenu(tabId, contextMenu) {}
1234 }; 1281 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698