| OLD | NEW |
| 1 /** | 1 /** |
| 2 Use `Polymer.PaperDialogBehavior` and `paper-dialog-shared-styles.html` to imple
ment a Material Design | 2 Use `Polymer.PaperDialogBehavior` and `paper-dialog-shared-styles.html` to imple
ment a Material Design |
| 3 dialog. | 3 dialog. |
| 4 | 4 |
| 5 For example, if `<paper-dialog-impl>` implements this behavior: | 5 For example, if `<paper-dialog-impl>` implements this behavior: |
| 6 | 6 |
| 7 <paper-dialog-impl> | 7 <paper-dialog-impl> |
| 8 <h2>Header</h2> | 8 <h2>Header</h2> |
| 9 <div>Dialog body</div> | 9 <div>Dialog body</div> |
| 10 <div class="buttons"> | 10 <div class="buttons"> |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 Polymer.PaperDialogBehaviorImpl = { | 51 Polymer.PaperDialogBehaviorImpl = { |
| 52 | 52 |
| 53 hostAttributes: { | 53 hostAttributes: { |
| 54 'role': 'dialog', | 54 'role': 'dialog', |
| 55 'tabindex': '-1' | 55 'tabindex': '-1' |
| 56 }, | 56 }, |
| 57 | 57 |
| 58 properties: { | 58 properties: { |
| 59 | 59 |
| 60 /** | 60 /** |
| 61 * If `modal` is true, this implies `no-cancel-on-outside-click` and `with
-backdrop`. | 61 * If `modal` is true, this implies `no-cancel-on-outside-click`, `no-canc
el-on-esc-key` and `with-backdrop`. |
| 62 */ | 62 */ |
| 63 modal: { | 63 modal: { |
| 64 observer: '_modalChanged', | |
| 65 type: Boolean, | 64 type: Boolean, |
| 66 value: false | 65 value: false |
| 67 }, | |
| 68 | |
| 69 /** @type {?Node} */ | |
| 70 _lastFocusedElement: { | |
| 71 type: Object | |
| 72 }, | |
| 73 | |
| 74 _boundOnFocus: { | |
| 75 type: Function, | |
| 76 value: function() { | |
| 77 return this._onFocus.bind(this); | |
| 78 } | |
| 79 }, | |
| 80 | |
| 81 _boundOnBackdropClick: { | |
| 82 type: Function, | |
| 83 value: function() { | |
| 84 return this._onBackdropClick.bind(this); | |
| 85 } | |
| 86 } | 66 } |
| 87 | 67 |
| 88 }, | 68 }, |
| 89 | 69 |
| 70 observers: [ |
| 71 '_modalChanged(modal, _readied)' |
| 72 ], |
| 73 |
| 90 listeners: { | 74 listeners: { |
| 91 'tap': '_onDialogClick', | 75 'tap': '_onDialogClick' |
| 92 'iron-overlay-opened': '_onIronOverlayOpened', | 76 }, |
| 93 'iron-overlay-closed': '_onIronOverlayClosed' | 77 |
| 78 ready: function () { |
| 79 // Only now these properties can be read. |
| 80 this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick; |
| 81 this.__prevNoCancelOnEscKey = this.noCancelOnEscKey; |
| 82 this.__prevWithBackdrop = this.withBackdrop; |
| 94 }, | 83 }, |
| 95 | 84 |
| 96 attached: function() { | 85 attached: function() { |
| 97 // this._observer is used by iron-overlay-behavior | 86 // this._observer is used by iron-overlay-behavior |
| 98 this._ariaObserver = Polymer.dom(this).observeNodes(this._updateAriaLabell
edBy); | 87 this._ariaObserver = Polymer.dom(this).observeNodes(this._updateAriaLabell
edBy); |
| 99 this._updateAriaLabelledBy(); | 88 this._updateAriaLabelledBy(); |
| 100 }, | 89 }, |
| 101 | 90 |
| 102 detached: function() { | 91 detached: function() { |
| 103 Polymer.dom(this).unobserveNodes(this._ariaObserver); | 92 Polymer.dom(this).unobserveNodes(this._ariaObserver); |
| 104 }, | 93 }, |
| 105 | 94 |
| 106 _modalChanged: function() { | 95 _modalChanged: function(modal, readied) { |
| 107 if (this.modal) { | 96 if (modal) { |
| 108 this.setAttribute('aria-modal', 'true'); | 97 this.setAttribute('aria-modal', 'true'); |
| 109 } else { | 98 } else { |
| 110 this.setAttribute('aria-modal', 'false'); | 99 this.setAttribute('aria-modal', 'false'); |
| 111 } | 100 } |
| 112 // modal implies noCancelOnOutsideClick and withBackdrop if true, don't ov
erwrite | 101 |
| 113 // those properties otherwise. | 102 // modal implies noCancelOnOutsideClick, noCancelOnEscKey and withBackdrop
. |
| 114 if (this.modal) { | 103 // We need to wait for the element to be ready before we can read the |
| 104 // properties values. |
| 105 if (!readied) { |
| 106 return; |
| 107 } |
| 108 |
| 109 if (modal) { |
| 110 this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick; |
| 111 this.__prevNoCancelOnEscKey = this.noCancelOnEscKey; |
| 112 this.__prevWithBackdrop = this.withBackdrop; |
| 115 this.noCancelOnOutsideClick = true; | 113 this.noCancelOnOutsideClick = true; |
| 114 this.noCancelOnEscKey = true; |
| 116 this.withBackdrop = true; | 115 this.withBackdrop = true; |
| 116 } else { |
| 117 // If the value was changed to false, let it false. |
| 118 this.noCancelOnOutsideClick = this.noCancelOnOutsideClick && |
| 119 this.__prevNoCancelOnOutsideClick; |
| 120 this.noCancelOnEscKey = this.noCancelOnEscKey && |
| 121 this.__prevNoCancelOnEscKey; |
| 122 this.withBackdrop = this.withBackdrop && this.__prevWithBackdrop; |
| 117 } | 123 } |
| 118 }, | 124 }, |
| 119 | 125 |
| 120 _updateAriaLabelledBy: function() { | 126 _updateAriaLabelledBy: function() { |
| 121 var header = Polymer.dom(this).querySelector('h2'); | 127 var header = Polymer.dom(this).querySelector('h2'); |
| 122 if (!header) { | 128 if (!header) { |
| 123 this.removeAttribute('aria-labelledby'); | 129 this.removeAttribute('aria-labelledby'); |
| 124 return; | 130 return; |
| 125 } | 131 } |
| 126 var headerId = header.getAttribute('id'); | 132 var headerId = header.getAttribute('id'); |
| 127 if (headerId && this.getAttribute('aria-labelledby') === headerId) { | 133 if (headerId && this.getAttribute('aria-labelledby') === headerId) { |
| 128 return; | 134 return; |
| 129 } | 135 } |
| 130 // set aria-describedBy to the header element | 136 // set aria-describedBy to the header element |
| 131 var labelledById; | 137 var labelledById; |
| 132 if (headerId) { | 138 if (headerId) { |
| 133 labelledById = headerId; | 139 labelledById = headerId; |
| 134 } else { | 140 } else { |
| 135 labelledById = 'paper-dialog-header-' + new Date().getUTCMilliseconds(); | 141 labelledById = 'paper-dialog-header-' + new Date().getUTCMilliseconds(); |
| 136 header.setAttribute('id', labelledById); | 142 header.setAttribute('id', labelledById); |
| 137 } | 143 } |
| 138 this.setAttribute('aria-labelledby', labelledById); | 144 this.setAttribute('aria-labelledby', labelledById); |
| 139 }, | 145 }, |
| 140 | 146 |
| 141 _updateClosingReasonConfirmed: function(confirmed) { | 147 _updateClosingReasonConfirmed: function(confirmed) { |
| 142 this.closingReason = this.closingReason || {}; | 148 this.closingReason = this.closingReason || {}; |
| 143 this.closingReason.confirmed = confirmed; | 149 this.closingReason.confirmed = confirmed; |
| 144 }, | 150 }, |
| 145 | 151 |
| 152 /** |
| 153 * Will dismiss the dialog if user clicked on an element with dialog-dismiss |
| 154 * or dialog-confirm attribute. |
| 155 */ |
| 146 _onDialogClick: function(event) { | 156 _onDialogClick: function(event) { |
| 147 var target = Polymer.dom(event).rootTarget; | 157 // Search for the element with dialog-confirm or dialog-dismiss, |
| 148 while (target && target !== this) { | 158 // from the root target until this (excluded). |
| 149 if (target.hasAttribute) { | 159 var path = Polymer.dom(event).path; |
| 150 if (target.hasAttribute('dialog-dismiss')) { | 160 for (var i = 0; i < path.indexOf(this); i++) { |
| 151 this._updateClosingReasonConfirmed(false); | 161 var target = path[i]; |
| 152 this.close(); | 162 if (target.hasAttribute && (target.hasAttribute('dialog-dismiss') || tar
get.hasAttribute('dialog-confirm'))) { |
| 153 event.stopPropagation(); | 163 this._updateClosingReasonConfirmed(target.hasAttribute('dialog-confirm
')); |
| 154 break; | 164 this.close(); |
| 155 } else if (target.hasAttribute('dialog-confirm')) { | 165 event.stopPropagation(); |
| 156 this._updateClosingReasonConfirmed(true); | 166 break; |
| 157 this.close(); | |
| 158 event.stopPropagation(); | |
| 159 break; | |
| 160 } | |
| 161 } | |
| 162 target = Polymer.dom(target).parentNode; | |
| 163 } | |
| 164 }, | |
| 165 | |
| 166 _onIronOverlayOpened: function() { | |
| 167 if (this.modal) { | |
| 168 document.body.addEventListener('focus', this._boundOnFocus, true); | |
| 169 document.body.addEventListener('click', this._boundOnBackdropClick, true
); | |
| 170 } | |
| 171 }, | |
| 172 | |
| 173 _onIronOverlayClosed: function() { | |
| 174 this._lastFocusedElement = null; | |
| 175 document.body.removeEventListener('focus', this._boundOnFocus, true); | |
| 176 document.body.removeEventListener('click', this._boundOnBackdropClick, tru
e); | |
| 177 }, | |
| 178 | |
| 179 _onFocus: function(event) { | |
| 180 if (this.modal && this._manager.currentOverlay() === this) { | |
| 181 if (Polymer.dom(event).path.indexOf(this) !== -1) { | |
| 182 this._lastFocusedElement = event.target; | |
| 183 } else if (this._lastFocusedElement) { | |
| 184 this._lastFocusedElement.focus(); | |
| 185 } else { | |
| 186 this._focusNode.focus(); | |
| 187 } | |
| 188 } | |
| 189 }, | |
| 190 | |
| 191 _onBackdropClick: function(event) { | |
| 192 if (this.modal && this._manager.currentOverlay() === this && Polymer.dom(e
vent).path.indexOf(this) === -1) { | |
| 193 if (this._lastFocusedElement) { | |
| 194 this._lastFocusedElement.focus(); | |
| 195 } else { | |
| 196 this._focusNode.focus(); | |
| 197 } | 167 } |
| 198 } | 168 } |
| 199 } | 169 } |
| 200 | 170 |
| 201 }; | 171 }; |
| 202 | 172 |
| 203 /** @polymerBehavior */ | 173 /** @polymerBehavior */ |
| 204 Polymer.PaperDialogBehavior = [Polymer.IronOverlayBehavior, Polymer.PaperDialo
gBehaviorImpl]; | 174 Polymer.PaperDialogBehavior = [Polymer.IronOverlayBehavior, Polymer.PaperDialo
gBehaviorImpl]; |
| OLD | NEW |