Refactor keyboard shortcut handling into a behavior
Change-Id: I25687959ba7dab846236af28cdb13786e87dc38e
This commit is contained in:
		
							
								
								
									
										63
									
								
								polygerrit-ui/app/behaviors/keyboard-shortcut-behavior.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								polygerrit-ui/app/behaviors/keyboard-shortcut-behavior.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | <!-- | ||||||
|  | Copyright (C) 2016 The Android Open Source Project | ||||||
|  |  | ||||||
|  | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | you may not use this file except in compliance with the License. | ||||||
|  | You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  | http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  | Unless required by applicable law or agreed to in writing, software | ||||||
|  | distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | See the License for the specific language governing permissions and | ||||||
|  | limitations under the License. | ||||||
|  | --> | ||||||
|  | <link rel="import" href="../bower_components/polymer/polymer.html"> | ||||||
|  | <script> | ||||||
|  | (function(window) { | ||||||
|  |   'use strict'; | ||||||
|  |  | ||||||
|  |   var KeyboardShortcutBehavior = { | ||||||
|  |     properties: { | ||||||
|  |       keyEventTarget: { | ||||||
|  |         type: Object, | ||||||
|  |         value: function() { return this; }, | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       _boundKeyHandler: { | ||||||
|  |         type: Function, | ||||||
|  |         readonly: true, | ||||||
|  |         value: function() { return this._handleKey.bind(this); }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     attached: function() { | ||||||
|  |       this.keyEventTarget.addEventListener('keydown', this._boundKeyHandler); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     detached: function() { | ||||||
|  |       this.keyEventTarget.removeEventListener('keydown', this._boundKeyHandler); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     shouldSupressKeyboardShortcut: function(e) { | ||||||
|  |       var getModifierState = e.getModifierState ? | ||||||
|  |           e.getModifierState.bind(e) : | ||||||
|  |           function() { return false; }; | ||||||
|  |       var target = e.detail ? e.detail.keyboardEvent : e.target; | ||||||
|  |       return getModifierState('Control') || | ||||||
|  |              getModifierState('Alt') || | ||||||
|  |              getModifierState('Meta') || | ||||||
|  |              getModifierState('Fn') || | ||||||
|  |              target.tagName == 'INPUT' || | ||||||
|  |              target.tagName == 'TEXTAREA' || | ||||||
|  |              target.tagName == 'SELECT' || | ||||||
|  |              target.tagName == 'BUTTON' || | ||||||
|  |              target.tagName == 'A'; | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   window.Gerrit = window.Gerrit || {}; | ||||||
|  |   window.Gerrit.KeyboardShortcutBehavior = KeyboardShortcutBehavior; | ||||||
|  | })(window); | ||||||
|  | </script> | ||||||
| @@ -15,6 +15,7 @@ limitations under the License. | |||||||
| --> | --> | ||||||
|  |  | ||||||
| <link rel="import" href="../bower_components/polymer/polymer.html"> | <link rel="import" href="../bower_components/polymer/polymer.html"> | ||||||
|  | <link rel="import" href="../behaviors/keyboard-shortcut-behavior.html"> | ||||||
| <link rel="import" href="../styles/gr-change-list-styles.html"> | <link rel="import" href="../styles/gr-change-list-styles.html"> | ||||||
| <link rel="import" href="gr-change-list-item.html"> | <link rel="import" href="gr-change-list-item.html"> | ||||||
|  |  | ||||||
| @@ -114,19 +115,13 @@ limitations under the License. | |||||||
|           type: Boolean, |           type: Boolean, | ||||||
|           value: false, |           value: false, | ||||||
|         }, |         }, | ||||||
|         _boundKeyHandler: { |         keyEventTarget: { | ||||||
|           type: Function, |           type: Object, | ||||||
|           value: function() { return this._handleKey.bind(this); }, |           value: function() { return document.body; }, | ||||||
|         } |         }, | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       attached: function() { |       behaviors: [ Gerrit.KeyboardShortcutBehavior ], | ||||||
|         document.body.addEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       detached: function() { |  | ||||||
|         document.body.removeEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       _computeLabelNames: function(groups) { |       _computeLabelNames: function(groups) { | ||||||
|         var labels = []; |         var labels = []; | ||||||
| @@ -168,7 +163,7 @@ limitations under the License. | |||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       _handleKey: function(e) { |       _handleKey: function(e) { | ||||||
|         if (util.shouldSupressKeyboardShortcut(e)) { return; } |         if (this.shouldSupressKeyboardShortcut(e)) { return; } | ||||||
|  |  | ||||||
|         if (this.groups == null) { return; } |         if (this.groups == null) { return; } | ||||||
|         var len = 0; |         var len = 0; | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ limitations under the License. | |||||||
| --> | --> | ||||||
|  |  | ||||||
| <link rel="import" href="../bower_components/polymer/polymer.html"> | <link rel="import" href="../bower_components/polymer/polymer.html"> | ||||||
|  | <link rel="import" href="../behaviors/keyboard-shortcut-behavior.html"> | ||||||
| <link rel="import" href="../behaviors/rest-client-behavior.html"> | <link rel="import" href="../behaviors/rest-client-behavior.html"> | ||||||
| <link rel="import" href="gr-account-link.html"> | <link rel="import" href="gr-account-link.html"> | ||||||
| <link rel="import" href="gr-ajax.html"> | <link rel="import" href="gr-ajax.html"> | ||||||
| @@ -292,6 +293,10 @@ limitations under the License. | |||||||
|           value: function() { return {}; }, |           value: function() { return {}; }, | ||||||
|         }, |         }, | ||||||
|         serverConfig: Object, |         serverConfig: Object, | ||||||
|  |         keyEventTarget: { | ||||||
|  |           type: Object, | ||||||
|  |           value: function() { return document.body; }, | ||||||
|  |         }, | ||||||
|  |  | ||||||
|         _comments: Object, |         _comments: Object, | ||||||
|         _change: { |         _change: { | ||||||
| @@ -317,13 +322,12 @@ limitations under the License. | |||||||
|           type: Function, |           type: Function, | ||||||
|           value: function() { return this._handleBodyScroll.bind(this); }, |           value: function() { return this._handleBodyScroll.bind(this); }, | ||||||
|         }, |         }, | ||||||
|         _boundKeyHandler: { |  | ||||||
|           type: Function, |  | ||||||
|           value: function() { return this._handleKey.bind(this); }, |  | ||||||
|         } |  | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       behaviors: [ Gerrit.RESTClientBehavior ], |       behaviors: [ | ||||||
|  |         Gerrit.KeyboardShortcutBehavior, | ||||||
|  |         Gerrit.RESTClientBehavior, | ||||||
|  |       ], | ||||||
|  |  | ||||||
|       ready: function() { |       ready: function() { | ||||||
|         app.accountReady.then(function() { |         app.accountReady.then(function() { | ||||||
| @@ -334,12 +338,10 @@ limitations under the License. | |||||||
|  |  | ||||||
|       attached: function() { |       attached: function() { | ||||||
|         window.addEventListener('scroll', this._boundScrollHandler); |         window.addEventListener('scroll', this._boundScrollHandler); | ||||||
|         document.body.addEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       detached: function() { |       detached: function() { | ||||||
|         window.removeEventListener('scroll', this._boundScrollHandler); |         window.removeEventListener('scroll', this._boundScrollHandler); | ||||||
|         document.body.removeEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       _handleBodyScroll: function(e) { |       _handleBodyScroll: function(e) { | ||||||
| @@ -515,7 +517,7 @@ limitations under the License. | |||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       _handleKey: function(e) { |       _handleKey: function(e) { | ||||||
|         if (util.shouldSupressKeyboardShortcut(e)) { return; } |         if (this.shouldSupressKeyboardShortcut(e)) { return; } | ||||||
|  |  | ||||||
|         switch(e.keyCode) { |         switch(e.keyCode) { | ||||||
|           case 65:  // 'a' |           case 65:  // 'a' | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ limitations under the License. | |||||||
|  |  | ||||||
| <link rel="import" href="../bower_components/polymer/polymer.html"> | <link rel="import" href="../bower_components/polymer/polymer.html"> | ||||||
| <link rel="import" href="../bower_components/iron-dropdown/iron-dropdown.html"> | <link rel="import" href="../bower_components/iron-dropdown/iron-dropdown.html"> | ||||||
|  | <link rel="import" href="../behaviors/keyboard-shortcut-behavior.html"> | ||||||
| <link rel="import" href="../behaviors/rest-client-behavior.html"> | <link rel="import" href="../behaviors/rest-client-behavior.html"> | ||||||
| <link rel="import" href="gr-ajax.html"> | <link rel="import" href="gr-ajax.html"> | ||||||
| <link rel="import" href="gr-diff.html"> | <link rel="import" href="gr-diff.html"> | ||||||
| @@ -156,6 +157,11 @@ limitations under the License. | |||||||
|           type: Object, |           type: Object, | ||||||
|           observer: '_paramsChanged', |           observer: '_paramsChanged', | ||||||
|         }, |         }, | ||||||
|  |         keyEventTarget: { | ||||||
|  |           type: Object, | ||||||
|  |           value: function() { return document.body; }, | ||||||
|  |         }, | ||||||
|  |  | ||||||
|         _patchRange: Object, |         _patchRange: Object, | ||||||
|         _change: Object, |         _change: Object, | ||||||
|         _changeNum: String, |         _changeNum: String, | ||||||
| @@ -165,37 +171,31 @@ limitations under the License. | |||||||
|           value: function() { return []; }, |           value: function() { return []; }, | ||||||
|         }, |         }, | ||||||
|         _path: String, |         _path: String, | ||||||
|         _boundKeyHandler: { |  | ||||||
|           type: Function, |  | ||||||
|           value: function() { return this._handleKey.bind(this); }, |  | ||||||
|         }, |  | ||||||
|         _loggedIn: { |         _loggedIn: { | ||||||
|           type: Boolean, |           type: Boolean, | ||||||
|           value: false, |           value: false, | ||||||
|         }, |         }, | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|  |       behaviors: [ | ||||||
|  |         Gerrit.KeyboardShortcutBehavior, | ||||||
|  |         Gerrit.RESTClientBehavior, | ||||||
|  |       ], | ||||||
|  |  | ||||||
|       ready: function() { |       ready: function() { | ||||||
|         app.accountReady.then(function() { |         app.accountReady.then(function() { | ||||||
|           this._loggedIn = app.loggedIn; |           this._loggedIn = app.loggedIn; | ||||||
|         }.bind(this)); |         }.bind(this)); | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       behaviors: [ Gerrit.RESTClientBehavior ], |  | ||||||
|  |  | ||||||
|       attached: function() { |       attached: function() { | ||||||
|         if (this._path) { |         if (this._path) { | ||||||
|           this.fire('title-change', {title: this._path}); |           this.fire('title-change', {title: this._path}); | ||||||
|         } |         } | ||||||
|         document.body.addEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       detached: function() { |  | ||||||
|         document.body.removeEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       _handleKey: function(e) { |       _handleKey: function(e) { | ||||||
|         if (util.shouldSupressKeyboardShortcut(e)) { return; } |         if (this.shouldSupressKeyboardShortcut(e)) { return; } | ||||||
|  |  | ||||||
|         switch(e.keyCode) { |         switch(e.keyCode) { | ||||||
|           case 219:  // '[' |           case 219:  // '[' | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ limitations under the License. | |||||||
| --> | --> | ||||||
|  |  | ||||||
| <link rel="import" href="../bower_components/polymer/polymer.html"> | <link rel="import" href="../bower_components/polymer/polymer.html"> | ||||||
|  | <link rel="import" href="../behaviors/keyboard-shortcut-behavior.html"> | ||||||
| <link rel="import" href="../behaviors/rest-client-behavior.html"> | <link rel="import" href="../behaviors/rest-client-behavior.html"> | ||||||
| <link rel="import" href="gr-ajax.html"> | <link rel="import" href="gr-ajax.html"> | ||||||
|  |  | ||||||
| @@ -112,23 +113,18 @@ limitations under the License. | |||||||
|           type: Number, |           type: Number, | ||||||
|           notify: true, |           notify: true, | ||||||
|         }, |         }, | ||||||
|  |         keyEventTarget: { | ||||||
|  |           type: Object, | ||||||
|  |           value: function() { return document.body; }, | ||||||
|  |         }, | ||||||
|  |  | ||||||
|         _drafts: Object, |         _drafts: Object, | ||||||
|         _boundKeyHandler: { |  | ||||||
|           type: Function, |  | ||||||
|           value: function() { return this._handleKey.bind(this); }, |  | ||||||
|         } |  | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       behaviors: [ Gerrit.RESTClientBehavior ], |       behaviors: [ | ||||||
|  |         Gerrit.KeyboardShortcutBehavior, | ||||||
|       attached: function() { |         Gerrit.RESTClientBehavior, | ||||||
|         document.body.addEventListener('keydown', this._boundKeyHandler); |       ], | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       detached: function() { |  | ||||||
|         document.body.removeEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       reload: function() { |       reload: function() { | ||||||
|         if (!this.changeNum || !this.patchNum) { |         if (!this.changeNum || !this.patchNum) { | ||||||
| @@ -183,7 +179,7 @@ limitations under the License. | |||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       _handleKey: function(e) { |       _handleKey: function(e) { | ||||||
|         if (util.shouldSupressKeyboardShortcut(e)) { return; } |         if (this.shouldSupressKeyboardShortcut(e)) { return; } | ||||||
|  |  | ||||||
|         switch(e.keyCode) { |         switch(e.keyCode) { | ||||||
|           case 74:  // 'j' |           case 74:  // 'j' | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ limitations under the License. | |||||||
|  |  | ||||||
| <link rel="import" href="../bower_components/polymer/polymer.html"> | <link rel="import" href="../bower_components/polymer/polymer.html"> | ||||||
| <link rel="import" href="../bower_components/iron-input/iron-input.html"> | <link rel="import" href="../bower_components/iron-input/iron-input.html"> | ||||||
|  | <link rel="import" href="../behaviors/keyboard-shortcut-behavior.html"> | ||||||
| <link rel="import" href="gr-ajax.html"> | <link rel="import" href="gr-ajax.html"> | ||||||
| <link rel="import" href="gr-request.html"> | <link rel="import" href="gr-request.html"> | ||||||
|  |  | ||||||
| @@ -173,26 +174,19 @@ limitations under the License. | |||||||
|             return this._handleBodyClick.bind(this); |             return this._handleBodyClick.bind(this); | ||||||
|           }, |           }, | ||||||
|         }, |         }, | ||||||
|         _boundKeyHandler: { |  | ||||||
|           type: Function, |  | ||||||
|           value: function() { return this._handleKey.bind(this); }, |  | ||||||
|         }, |  | ||||||
|  |  | ||||||
|         // Used for testing. |         // Used for testing. | ||||||
|         _lastAutocompleteRequest: Object, |         _lastAutocompleteRequest: Object, | ||||||
|         _xhrPromise: Object, |         _xhrPromise: Object, | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|  |       behaviors: [ Gerrit.KeyboardShortcutBehavior ], | ||||||
|  |  | ||||||
|       observers: [ |       observers: [ | ||||||
|         '_reviewersChanged(change.reviewers.*, change.owner)', |         '_reviewersChanged(change.reviewers.*, change.owner)', | ||||||
|       ], |       ], | ||||||
|  |  | ||||||
|       attached: function() { |  | ||||||
|         this.addEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       detached: function() { |       detached: function() { | ||||||
|         this.removeEventListener('keydown', this._boundKeyHandler); |  | ||||||
|         this._clearInputRequestHandle(); |         this._clearInputRequestHandle(); | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ limitations under the License. | |||||||
|  |  | ||||||
| <link rel="import" href="../bower_components/polymer/polymer.html"> | <link rel="import" href="../bower_components/polymer/polymer.html"> | ||||||
| <link rel="import" href="../bower_components/iron-input/iron-input.html"> | <link rel="import" href="../bower_components/iron-input/iron-input.html"> | ||||||
|  | <link rel="import" href="../behaviors/keyboard-shortcut-behavior.html"> | ||||||
|  |  | ||||||
| <dom-module id="gr-search-bar"> | <dom-module id="gr-search-bar"> | ||||||
|   <template> |   <template> | ||||||
| @@ -55,6 +56,8 @@ limitations under the License. | |||||||
|     Polymer({ |     Polymer({ | ||||||
|       is: 'gr-search-bar', |       is: 'gr-search-bar', | ||||||
|  |  | ||||||
|  |       behaviors: [ Gerrit.KeyboardShortcutBehavior ], | ||||||
|  |  | ||||||
|       listeners: { |       listeners: { | ||||||
|         'searchInput.keydown': '_inputKeyDownHandler', |         'searchInput.keydown': '_inputKeyDownHandler', | ||||||
|         'searchButton.tap': '_preventDefaultAndNavigateToInputVal', |         'searchButton.tap': '_preventDefaultAndNavigateToInputVal', | ||||||
| @@ -67,20 +70,12 @@ limitations under the License. | |||||||
|           notify: true, |           notify: true, | ||||||
|           observer: '_valueChanged', |           observer: '_valueChanged', | ||||||
|         }, |         }, | ||||||
|  |         keyEventTarget: { | ||||||
|  |           type: Object, | ||||||
|  |           value: function() { return document.body; }, | ||||||
|  |         }, | ||||||
|  |  | ||||||
|         _inputVal: String, |         _inputVal: String, | ||||||
|         _boundKeyHandler: { |  | ||||||
|           type: Function, |  | ||||||
|           value: function() { return this._handleKey.bind(this); }, |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       attached: function() { |  | ||||||
|         document.body.addEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       detached: function() { |  | ||||||
|         document.body.removeEventListener('keydown', this._boundKeyHandler); |  | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       _valueChanged: function(value) { |       _valueChanged: function(value) { | ||||||
| @@ -100,7 +95,7 @@ limitations under the License. | |||||||
|       }, |       }, | ||||||
|  |  | ||||||
|       _handleKey: function(e) { |       _handleKey: function(e) { | ||||||
|         if (util.shouldSupressKeyboardShortcut(e)) { return; } |         if (this.shouldSupressKeyboardShortcut(e)) { return; } | ||||||
|         switch(e.keyCode) { |         switch(e.keyCode) { | ||||||
|           case 191:  // '/' |           case 191:  // '/' | ||||||
|             e.preventDefault(); |             e.preventDefault(); | ||||||
|   | |||||||
| @@ -39,22 +39,6 @@ util.escapeHTML = function(str) { | |||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| util.shouldSupressKeyboardShortcut = function(e) { |  | ||||||
|   var getModifierState = e.getModifierState ? |  | ||||||
|       e.getModifierState.bind(e) : |  | ||||||
|       function() { return false; }; |  | ||||||
|   var target = e.detail ? e.detail.keyboardEvent : e.target; |  | ||||||
|   return getModifierState('Control') || |  | ||||||
|          getModifierState('Alt') || |  | ||||||
|          getModifierState('Meta') || |  | ||||||
|          getModifierState('Fn') || |  | ||||||
|          target.tagName == 'INPUT' || |  | ||||||
|          target.tagName == 'TEXTAREA' || |  | ||||||
|          target.tagName == 'SELECT' || |  | ||||||
|          target.tagName == 'BUTTON' || |  | ||||||
|          target.tagName == 'A'; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| util.getCookie = function(name) { | util.getCookie = function(name) { | ||||||
|   var key = name + '='; |   var key = name + '='; | ||||||
|   var cookies = document.cookie.split(';'); |   var cookies = document.cookie.split(';'); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andrew Bonventre
					Andrew Bonventre