OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 }; |
OLD | NEW |