| 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 10 matching lines...) Expand all Loading... |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 /** | 31 UI.Dialog = class extends UI.GlassPane { |
| 32 * @unrestricted | |
| 33 */ | |
| 34 UI.Dialog = class extends UI.Widget { | |
| 35 constructor() { | 32 constructor() { |
| 36 super(true); | 33 super(); |
| 37 this.markAsRoot(); | |
| 38 this.registerRequiredCSS('ui/dialog.css'); | 34 this.registerRequiredCSS('ui/dialog.css'); |
| 39 | |
| 40 this.contentElement.createChild('content'); | |
| 41 this.contentElement.tabIndex = 0; | 35 this.contentElement.tabIndex = 0; |
| 42 this.contentElement.addEventListener('focus', this.focus.bind(this), false); | 36 this.contentElement.addEventListener('focus', this.focus.bind(this), false); |
| 43 this.contentElement.addEventListener('keydown', this._onKeyDown.bind(this),
false); | 37 this.contentElement.addEventListener('keydown', this._onKeyDown.bind(this),
false); |
| 44 this._dimmed = false; | 38 this.setBlockPointerEvents(true); |
| 45 this._wrapsContent = false; | 39 this.setSetOutsideClickCallback(event => { |
| 46 this._maxSize = null; | 40 this.hideDialog(); |
| 47 /** @type {?number} */ | 41 event.consume(true); |
| 48 this._positionX = null; | 42 }); |
| 49 /** @type {?number} */ | |
| 50 this._positionY = null; | |
| 51 this._fixedHeight = true; | |
| 52 | |
| 53 /** @type {!Map<!HTMLElement, number>} */ | 43 /** @type {!Map<!HTMLElement, number>} */ |
| 54 this._tabIndexMap = new Map(); | 44 this._tabIndexMap = new Map(); |
| 45 /** @type {?UI.WidgetFocusRestorer} */ |
| 46 this._focusRestorer = null; |
| 55 } | 47 } |
| 56 | 48 |
| 57 /** | 49 /** |
| 58 * @return {boolean} | 50 * @return {boolean} |
| 59 */ | 51 */ |
| 60 static hasInstance() { | 52 static hasInstance() { |
| 61 return !!UI.Dialog._instance; | 53 return !!UI.Dialog._instance; |
| 62 } | 54 } |
| 63 | 55 |
| 64 /** | 56 /** |
| 65 * @override | 57 * @param {!Document|!Element=} where |
| 66 * @suppressGlobalPropertiesCheck | |
| 67 * TODO(dgozman): pass document in constructor. | |
| 68 */ | 58 */ |
| 69 show() { | 59 showDialog(where) { |
| 60 var document = /** @type {!Document} */ ( |
| 61 where instanceof Document ? where : (where || UI.inspectorView.element).
ownerDocument); |
| 70 if (UI.Dialog._instance) | 62 if (UI.Dialog._instance) |
| 71 UI.Dialog._instance.detach(); | 63 UI.Dialog._instance.detach(); |
| 72 UI.Dialog._instance = this; | 64 UI.Dialog._instance = this; |
| 73 | |
| 74 this._disableTabIndexOnElements(document); | 65 this._disableTabIndexOnElements(document); |
| 75 | 66 this.showGlassPane(document); |
| 76 this._glassPane = new UI.GlassPane(document, this._dimmed, true /* blockPoin
terEvents*/, event => { | |
| 77 this.detach(); | |
| 78 event.consume(true); | |
| 79 }); | |
| 80 this._glassPane.setFixedHeight(this._fixedHeight); | |
| 81 this._glassPane.show(); | |
| 82 super.show(this._glassPane.contentElement); | |
| 83 this._glassPane.setContentPosition(this._positionX, this._positionY); | |
| 84 this._glassPane.setMaxContentSize(this._effectiveMaxSize()); | |
| 85 this._focusRestorer = new UI.WidgetFocusRestorer(this); | 67 this._focusRestorer = new UI.WidgetFocusRestorer(this); |
| 86 } | 68 } |
| 87 | 69 |
| 88 /** | 70 hideDialog() { |
| 89 * @override | |
| 90 */ | |
| 91 detach() { | |
| 92 this._focusRestorer.restore(); | 71 this._focusRestorer.restore(); |
| 93 | 72 this.hideGlassPane(); |
| 94 super.detach(); | |
| 95 this._glassPane.hide(); | |
| 96 delete this._glassPane; | |
| 97 | |
| 98 this._restoreTabIndexOnElements(); | 73 this._restoreTabIndexOnElements(); |
| 99 | |
| 100 delete UI.Dialog._instance; | 74 delete UI.Dialog._instance; |
| 101 } | 75 } |
| 102 | 76 |
| 103 addCloseButton() { | 77 addCloseButton() { |
| 104 var closeButton = this.contentElement.createChild('div', 'dialog-close-butto
n', 'dt-close-button'); | 78 var closeButton = this.contentElement.createChild('div', 'dialog-close-butto
n', 'dt-close-button'); |
| 105 closeButton.gray = true; | 79 closeButton.gray = true; |
| 106 closeButton.addEventListener('click', () => this.detach(), false); | 80 closeButton.addEventListener('click', () => this.detach(), false); |
| 107 } | 81 } |
| 108 | 82 |
| 109 /** | 83 /** |
| 110 * @param {?number} positionX | |
| 111 * @param {?number} positionY | |
| 112 */ | |
| 113 setPosition(positionX, positionY) { | |
| 114 this._positionX = positionX; | |
| 115 this._positionY = positionY; | |
| 116 } | |
| 117 | |
| 118 /** | |
| 119 * @param {!UI.Size} size | |
| 120 */ | |
| 121 setMaxSize(size) { | |
| 122 this._maxSize = size; | |
| 123 } | |
| 124 | |
| 125 /** | |
| 126 * @param {boolean} fixedHeight | |
| 127 */ | |
| 128 setFixedHeight(fixedHeight) { | |
| 129 this._fixedHeight = fixedHeight; | |
| 130 } | |
| 131 | |
| 132 /** | |
| 133 * @return {?UI.Size} | |
| 134 */ | |
| 135 _effectiveMaxSize() { | |
| 136 if (!this._wrapsContent) | |
| 137 return this._maxSize; | |
| 138 return new UI.Size(this.contentElement.offsetWidth, this.contentElement.offs
etHeight).clipTo(this._maxSize); | |
| 139 } | |
| 140 | |
| 141 /** | |
| 142 * @param {boolean} wraps | |
| 143 */ | |
| 144 setWrapsContent(wraps) { | |
| 145 this._wrapsContent = wraps; | |
| 146 this.element.classList.toggle('wraps-content', wraps); | |
| 147 } | |
| 148 | |
| 149 /** | |
| 150 * @param {boolean} dimmed | |
| 151 */ | |
| 152 setDimmed(dimmed) { | |
| 153 this._dimmed = dimmed; | |
| 154 } | |
| 155 | |
| 156 contentResized() { | |
| 157 if (!this._wrapsContent || !this._glassPane) | |
| 158 return; | |
| 159 this._glassPane.setMaxContentSize(this._effectiveMaxSize()); | |
| 160 } | |
| 161 | |
| 162 /** | |
| 163 * @param {!Document} document | 84 * @param {!Document} document |
| 164 */ | 85 */ |
| 165 _disableTabIndexOnElements(document) { | 86 _disableTabIndexOnElements(document) { |
| 166 this._tabIndexMap.clear(); | 87 this._tabIndexMap.clear(); |
| 167 for (var node = document; node; node = node.traverseNextNode(document)) { | 88 for (var node = document; node; node = node.traverseNextNode(document)) { |
| 168 if (node instanceof HTMLElement) { | 89 if (node instanceof HTMLElement) { |
| 169 var element = /** @type {!HTMLElement} */ (node); | 90 var element = /** @type {!HTMLElement} */ (node); |
| 170 var tabIndex = element.tabIndex; | 91 var tabIndex = element.tabIndex; |
| 171 if (tabIndex >= 0) { | 92 if (tabIndex >= 0) { |
| 172 this._tabIndexMap.set(element, tabIndex); | 93 this._tabIndexMap.set(element, tabIndex); |
| 173 element.tabIndex = -1; | 94 element.tabIndex = -1; |
| 174 } | 95 } |
| 175 } | 96 } |
| 176 } | 97 } |
| 177 } | 98 } |
| 178 | 99 |
| 179 _restoreTabIndexOnElements() { | 100 _restoreTabIndexOnElements() { |
| 180 for (var element of this._tabIndexMap.keys()) | 101 for (var element of this._tabIndexMap.keys()) |
| 181 element.tabIndex = /** @type {number} */ (this._tabIndexMap.get(element)); | 102 element.tabIndex = /** @type {number} */ (this._tabIndexMap.get(element)); |
| 182 this._tabIndexMap.clear(); | 103 this._tabIndexMap.clear(); |
| 183 } | 104 } |
| 184 | 105 |
| 185 /** | 106 /** |
| 186 * @param {!Event} event | 107 * @param {!Event} event |
| 187 */ | 108 */ |
| 188 _onKeyDown(event) { | 109 _onKeyDown(event) { |
| 189 if (event.keyCode === UI.KeyboardShortcut.Keys.Esc.code) { | 110 if (event.keyCode === UI.KeyboardShortcut.Keys.Esc.code) { |
| 190 event.consume(true); | 111 event.consume(true); |
| 191 this.detach(); | 112 this.hideDialog(); |
| 192 } | 113 } |
| 193 } | 114 } |
| 194 }; | 115 }; |
| OLD | NEW |