Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 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 23 matching lines...) Expand all Loading... | |
| 34 UI.Dialog = class extends UI.Widget { | 34 UI.Dialog = class extends UI.Widget { |
| 35 constructor() { | 35 constructor() { |
| 36 super(true); | 36 super(true); |
| 37 this.markAsRoot(); | 37 this.markAsRoot(); |
| 38 this.registerRequiredCSS('ui/dialog.css'); | 38 this.registerRequiredCSS('ui/dialog.css'); |
| 39 | 39 |
| 40 this.contentElement.createChild('content'); | 40 this.contentElement.createChild('content'); |
| 41 this.contentElement.tabIndex = 0; | 41 this.contentElement.tabIndex = 0; |
| 42 this.contentElement.addEventListener('focus', this._onFocus.bind(this), fals e); | 42 this.contentElement.addEventListener('focus', this._onFocus.bind(this), fals e); |
| 43 this._keyDownBound = this._onKeyDown.bind(this); | 43 this._keyDownBound = this._onKeyDown.bind(this); |
| 44 this._onClickBound = this._onGlassPaneClick.bind(this); | |
| 45 this._overlay = new UI.ModalOverlay(); | |
| 46 this._overlay.setBlockPointerEvents(true); | |
| 47 this._wrapsContent = false; | |
| 48 this._maxSize = null; | |
| 44 | 49 |
| 45 this._wrapsContent = false; | |
| 46 this._dimmed = false; | |
| 47 /** @type {!Map<!HTMLElement, number>} */ | 50 /** @type {!Map<!HTMLElement, number>} */ |
| 48 this._tabIndexMap = new Map(); | 51 this._tabIndexMap = new Map(); |
| 49 } | 52 } |
| 50 | 53 |
| 51 /** | 54 /** |
| 52 * @return {boolean} | 55 * @return {boolean} |
| 53 */ | 56 */ |
| 54 static hasInstance() { | 57 static hasInstance() { |
| 55 return !!UI.Dialog._instance; | 58 return !!UI.Dialog._instance; |
| 56 } | 59 } |
| 57 | 60 |
| 58 /** | 61 /** |
| 59 * @param {!UI.Widget} view | |
| 60 */ | |
| 61 static setModalHostView(view) { | |
| 62 UI.Dialog._modalHostView = view; | |
| 63 } | |
| 64 | |
| 65 /** | |
| 66 * FIXME: make utility method in Dialog, so clients use it instead of this get ter. | |
| 67 * Method should be like Dialog.showModalElement(position params, reposition c allback). | |
| 68 * @return {?UI.Widget} | |
| 69 */ | |
| 70 static modalHostView() { | |
| 71 return UI.Dialog._modalHostView; | |
| 72 } | |
| 73 | |
| 74 static modalHostRepositioned() { | |
| 75 if (UI.Dialog._instance) | |
| 76 UI.Dialog._instance._position(); | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * @override | 62 * @override |
| 81 */ | 63 */ |
| 82 show() { | 64 show() { |
| 83 if (UI.Dialog._instance) | 65 if (UI.Dialog._instance) |
| 84 UI.Dialog._instance.detach(); | 66 UI.Dialog._instance.detach(); |
| 85 UI.Dialog._instance = this; | 67 UI.Dialog._instance = this; |
| 86 | 68 |
| 87 var document = /** @type {!Document} */ (UI.Dialog._modalHostView.element.ow nerDocument); | 69 this._disableTabIndexOnElements(this._overlay.document()); |
| 88 this._disableTabIndexOnElements(document); | |
| 89 | 70 |
| 90 this._glassPane = new UI.GlassPane(document, this._dimmed); | 71 super.show(this._overlay.element); |
| 91 this._glassPane.element.addEventListener('click', this._onGlassPaneClick.bin d(this), false); | 72 this._overlay.show(); |
| 92 this.element.ownerDocument.body.addEventListener('keydown', this._keyDownBou nd, false); | 73 this._overlay.addGlassPaneEventListener('click', this._onClickBound, false); |
| 74 this._overlay.document().body.addEventListener('keydown', this._keyDownBound , false); | |
|
caseq
2017/01/31 21:27:19
I wonder if we can make it simpler by focusing to
dgozman
2017/01/31 23:39:49
Done.
| |
| 75 this._overlay.setMaxSize(this._effectiveMaxSize()); | |
| 76 this._overlay.position(); | |
| 93 | 77 |
| 94 super.show(this._glassPane.element); | |
| 95 | |
| 96 this._position(); | |
| 97 this._focusRestorer = new UI.WidgetFocusRestorer(this); | 78 this._focusRestorer = new UI.WidgetFocusRestorer(this); |
| 98 } | 79 } |
| 99 | 80 |
| 100 /** | 81 /** |
| 101 * @override | 82 * @override |
| 102 */ | 83 */ |
| 103 detach() { | 84 detach() { |
| 104 this._focusRestorer.restore(); | 85 this._focusRestorer.restore(); |
| 105 | 86 |
| 106 this.element.ownerDocument.body.removeEventListener('keydown', this._keyDown Bound, false); | 87 this._overlay.document().body.removeEventListener('keydown', this._keyDownBo und, false); |
| 88 this._overlay.removeGlassPaneEventListener('click', this._onClickBound, fals e); | |
| 107 super.detach(); | 89 super.detach(); |
| 108 | 90 this._overlay.hide(); |
| 109 this._glassPane.dispose(); | |
| 110 delete this._glassPane; | |
| 111 | 91 |
| 112 this._restoreTabIndexOnElements(); | 92 this._restoreTabIndexOnElements(); |
| 113 | 93 |
| 114 delete UI.Dialog._instance; | 94 delete UI.Dialog._instance; |
| 115 } | 95 } |
| 116 | 96 |
| 117 addCloseButton() { | 97 addCloseButton() { |
| 118 var closeButton = this.contentElement.createChild('div', 'dialog-close-butto n', 'dt-close-button'); | 98 var closeButton = this.contentElement.createChild('div', 'dialog-close-butto n', 'dt-close-button'); |
| 119 closeButton.gray = true; | 99 closeButton.gray = true; |
| 120 closeButton.addEventListener('click', () => this.detach(), false); | 100 closeButton.addEventListener('click', () => this.detach(), false); |
| 121 } | 101 } |
| 122 | 102 |
| 123 /** | 103 /** |
| 124 * @param {number=} positionX | 104 * @param {?number} positionX |
| 125 * @param {number=} positionY | 105 * @param {?number} positionY |
| 126 */ | 106 */ |
| 127 setPosition(positionX, positionY) { | 107 setPosition(positionX, positionY) { |
| 128 this._defaultPositionX = positionX; | 108 this._overlay.setPosition(positionX, positionY); |
| 129 this._defaultPositionY = positionY; | 109 if (this._overlay.visible()) |
|
caseq
2017/01/31 21:27:20
remove?
dgozman
2017/01/31 23:39:49
Done.
| |
| 110 this._overlay.position(); | |
| 130 } | 111 } |
| 131 | 112 |
| 132 /** | 113 /** |
| 133 * @param {!UI.Size} size | 114 * @param {!UI.Size} size |
| 134 */ | 115 */ |
| 135 setMaxSize(size) { | 116 setMaxSize(size) { |
| 136 this._maxSize = size; | 117 this._maxSize = size; |
| 118 this._overlay.setMaxSize(this._effectiveMaxSize()); | |
| 119 if (this._overlay.visible()) | |
|
caseq
2017/01/31 21:27:20
ditto
| |
| 120 this._overlay.position(); | |
| 121 } | |
| 122 | |
| 123 /** | |
| 124 * @return {?UI.Size} | |
| 125 */ | |
| 126 _effectiveMaxSize() { | |
| 127 if (!this._wrapsContent) | |
| 128 return this._maxSize; | |
| 129 | |
| 130 var size = new UI.Size(this.contentElement.offsetWidth, this.contentElement. offsetHeight); | |
| 131 size.sizeToMin(this._maxSize); | |
| 132 return size; | |
| 137 } | 133 } |
| 138 | 134 |
| 139 /** | 135 /** |
| 140 * @param {boolean} wraps | 136 * @param {boolean} wraps |
| 141 */ | 137 */ |
| 142 setWrapsContent(wraps) { | 138 setWrapsContent(wraps) { |
| 139 this._wrapsContent = wraps; | |
| 143 this.element.classList.toggle('wraps-content', wraps); | 140 this.element.classList.toggle('wraps-content', wraps); |
| 144 this._wrapsContent = wraps; | 141 this._overlay.setMaxSize(this._effectiveMaxSize()); |
| 142 if (this._overlay.visible()) | |
|
caseq
2017/01/31 21:27:19
ditto.
| |
| 143 this._overlay.position(); | |
| 145 } | 144 } |
| 146 | 145 |
| 147 /** | 146 /** |
| 148 * @param {boolean} dimmed | 147 * @param {boolean} dimmed |
| 149 */ | 148 */ |
| 150 setDimmed(dimmed) { | 149 setDimmed(dimmed) { |
| 151 this._dimmed = dimmed; | 150 this._overlay.setDimmed(dimmed); |
| 152 } | 151 } |
| 153 | 152 |
| 154 contentResized() { | 153 contentResized() { |
| 155 if (this._wrapsContent) | 154 if (!this._wrapsContent) |
| 156 this._position(); | 155 return; |
| 156 this._overlay.setMaxSize(this._effectiveMaxSize()); | |
| 157 if (this._overlay.visible()) | |
|
caseq
2017/01/31 21:27:19
ditto.
| |
| 158 this._overlay.position(); | |
| 157 } | 159 } |
| 158 | 160 |
| 159 /** | 161 /** |
| 160 * @param {!Document} document | 162 * @param {!Document} document |
| 161 */ | 163 */ |
| 162 _disableTabIndexOnElements(document) { | 164 _disableTabIndexOnElements(document) { |
| 163 this._tabIndexMap.clear(); | 165 this._tabIndexMap.clear(); |
| 164 for (var node = document; node; node = node.traverseNextNode(document)) { | 166 for (var node = document; node; node = node.traverseNextNode(document)) { |
| 165 if (node instanceof HTMLElement) { | 167 if (node instanceof HTMLElement) { |
| 166 var element = /** @type {!HTMLElement} */ (node); | 168 var element = /** @type {!HTMLElement} */ (node); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 187 } | 189 } |
| 188 | 190 |
| 189 /** | 191 /** |
| 190 * @param {!Event} event | 192 * @param {!Event} event |
| 191 */ | 193 */ |
| 192 _onGlassPaneClick(event) { | 194 _onGlassPaneClick(event) { |
| 193 if (!this.element.isSelfOrAncestor(/** @type {?Node} */ (event.target))) | 195 if (!this.element.isSelfOrAncestor(/** @type {?Node} */ (event.target))) |
| 194 this.detach(); | 196 this.detach(); |
| 195 } | 197 } |
| 196 | 198 |
| 197 _position() { | |
| 198 var container = UI.Dialog._modalHostView.element; | |
| 199 | |
| 200 var width = container.offsetWidth - 10; | |
| 201 var height = container.offsetHeight - 10; | |
| 202 | |
| 203 if (this._wrapsContent) { | |
| 204 width = Math.min(width, this.contentElement.offsetWidth); | |
| 205 height = Math.min(height, this.contentElement.offsetHeight); | |
| 206 } | |
| 207 | |
| 208 if (this._maxSize) { | |
| 209 width = Math.min(width, this._maxSize.width); | |
| 210 height = Math.min(height, this._maxSize.height); | |
| 211 } | |
| 212 | |
| 213 var positionX; | |
| 214 if (typeof this._defaultPositionX === 'number') { | |
| 215 positionX = this._defaultPositionX; | |
| 216 } else { | |
| 217 positionX = (container.offsetWidth - width) / 2; | |
| 218 positionX = Number.constrain(positionX, 0, container.offsetWidth - width); | |
| 219 } | |
| 220 | |
| 221 var positionY; | |
| 222 if (typeof this._defaultPositionY === 'number') { | |
| 223 positionY = this._defaultPositionY; | |
| 224 } else { | |
| 225 positionY = (container.offsetHeight - height) / 2; | |
| 226 positionY = Number.constrain(positionY, 0, container.offsetHeight - height ); | |
| 227 } | |
| 228 | |
| 229 this.element.style.width = width + 'px'; | |
| 230 this.element.style.height = height + 'px'; | |
| 231 this.element.positionAt(positionX, positionY, container); | |
| 232 } | |
| 233 | |
| 234 /** | 199 /** |
| 235 * @param {!Event} event | 200 * @param {!Event} event |
| 236 */ | 201 */ |
| 237 _onKeyDown(event) { | 202 _onKeyDown(event) { |
| 238 if (event.keyCode === UI.KeyboardShortcut.Keys.Esc.code) { | 203 if (event.keyCode === UI.KeyboardShortcut.Keys.Esc.code) { |
| 239 event.consume(true); | 204 event.consume(true); |
| 240 this.detach(); | 205 this.detach(); |
| 241 } | 206 } |
| 242 } | 207 } |
| 243 }; | 208 }; |
| 244 | |
| 245 | |
| 246 /** @type {?Element} */ | |
| 247 UI.Dialog._previousFocusedElement = null; | |
| 248 | |
| 249 /** @type {?UI.Widget} */ | |
| 250 UI.Dialog._modalHostView = null; | |
| OLD | NEW |