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 |