OLD | NEW |
| (Empty) |
1 <!-- | |
2 @license | |
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | |
4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
7 Code distributed by Google as part of the polymer project is also | |
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
9 --> | |
10 | |
11 <link rel="import" href="../polymer/polymer.html"> | |
12 | |
13 <script> | |
14 /** | |
15 * `IronResizableBehavior` is a behavior that can be used in Polymer elements
to | |
16 * coordinate the flow of resize events between "resizers" (elements that cont
rol the | |
17 * size or hidden state of their children) and "resizables" (elements that nee
d to be | |
18 * notified when they are resized or un-hidden by their parents in order to ta
ke | |
19 * action on their new measurements). | |
20 * Elements that perform measurement should add the `IronResizableBehavior` be
havior to | |
21 * their element definition and listen for the `iron-resize` event on themselv
es. | |
22 * This event will be fired when they become showing after having been hidden, | |
23 * when they are resized explicitly by another resizable, or when the window h
as been | |
24 * resized. | |
25 * Note, the `iron-resize` event is non-bubbling. | |
26 * | |
27 * @polymerBehavior Polymer.IronResizableBehavior | |
28 * @demo demo/index.html | |
29 **/ | |
30 Polymer.IronResizableBehavior = { | |
31 properties: { | |
32 /** | |
33 * The closest ancestor element that implements `IronResizableBehavior`. | |
34 */ | |
35 _parentResizable: { | |
36 type: Object, | |
37 observer: '_parentResizableChanged' | |
38 }, | |
39 | |
40 /** | |
41 * True if this element is currently notifying its descedant elements of | |
42 * resize. | |
43 */ | |
44 _notifyingDescendant: { | |
45 type: Boolean, | |
46 value: false | |
47 } | |
48 }, | |
49 | |
50 listeners: { | |
51 'iron-request-resize-notifications': '_onIronRequestResizeNotifications' | |
52 }, | |
53 | |
54 created: function() { | |
55 // We don't really need property effects on these, and also we want them | |
56 // to be created before the `_parentResizable` observer fires: | |
57 this._interestedResizables = []; | |
58 this._boundNotifyResize = this.notifyResize.bind(this); | |
59 }, | |
60 | |
61 attached: function() { | |
62 this.fire('iron-request-resize-notifications', null, { | |
63 node: this, | |
64 bubbles: true, | |
65 cancelable: true | |
66 }); | |
67 | |
68 if (!this._parentResizable) { | |
69 window.addEventListener('resize', this._boundNotifyResize); | |
70 this.notifyResize(); | |
71 } | |
72 }, | |
73 | |
74 detached: function() { | |
75 if (this._parentResizable) { | |
76 this._parentResizable.stopResizeNotificationsFor(this); | |
77 } else { | |
78 window.removeEventListener('resize', this._boundNotifyResize); | |
79 } | |
80 | |
81 this._parentResizable = null; | |
82 }, | |
83 | |
84 /** | |
85 * Can be called to manually notify a resizable and its descendant | |
86 * resizables of a resize change. | |
87 */ | |
88 notifyResize: function() { | |
89 if (!this.isAttached) { | |
90 return; | |
91 } | |
92 | |
93 this._interestedResizables.forEach(function(resizable) { | |
94 if (this.resizerShouldNotify(resizable)) { | |
95 this._notifyDescendant(resizable); | |
96 } | |
97 }, this); | |
98 | |
99 this._fireResize(); | |
100 }, | |
101 | |
102 /** | |
103 * Used to assign the closest resizable ancestor to this resizable | |
104 * if the ancestor detects a request for notifications. | |
105 */ | |
106 assignParentResizable: function(parentResizable) { | |
107 this._parentResizable = parentResizable; | |
108 }, | |
109 | |
110 /** | |
111 * Used to remove a resizable descendant from the list of descendants | |
112 * that should be notified of a resize change. | |
113 */ | |
114 stopResizeNotificationsFor: function(target) { | |
115 var index = this._interestedResizables.indexOf(target); | |
116 | |
117 if (index > -1) { | |
118 this._interestedResizables.splice(index, 1); | |
119 this.unlisten(target, 'iron-resize', '_onDescendantIronResize'); | |
120 } | |
121 }, | |
122 | |
123 /** | |
124 * This method can be overridden to filter nested elements that should or | |
125 * should not be notified by the current element. Return true if an element | |
126 * should be notified, or false if it should not be notified. | |
127 * | |
128 * @param {HTMLElement} element A candidate descendant element that | |
129 * implements `IronResizableBehavior`. | |
130 * @return {boolean} True if the `element` should be notified of resize. | |
131 */ | |
132 resizerShouldNotify: function(element) { return true; }, | |
133 | |
134 _onDescendantIronResize: function(event) { | |
135 if (this._notifyingDescendant) { | |
136 event.stopPropagation(); | |
137 return; | |
138 } | |
139 | |
140 // NOTE(cdata): In ShadowDOM, event retargetting makes echoing of the | |
141 // otherwise non-bubbling event "just work." We do it manually here for | |
142 // the case where Polymer is not using shadow roots for whatever reason: | |
143 if (!Polymer.Settings.useShadow) { | |
144 this._fireResize(); | |
145 } | |
146 }, | |
147 | |
148 _fireResize: function() { | |
149 this.fire('iron-resize', null, { | |
150 node: this, | |
151 bubbles: false | |
152 }); | |
153 }, | |
154 | |
155 _onIronRequestResizeNotifications: function(event) { | |
156 var target = event.path ? event.path[0] : event.target; | |
157 | |
158 if (target === this) { | |
159 return; | |
160 } | |
161 | |
162 if (this._interestedResizables.indexOf(target) === -1) { | |
163 this._interestedResizables.push(target); | |
164 this.listen(target, 'iron-resize', '_onDescendantIronResize'); | |
165 } | |
166 | |
167 target.assignParentResizable(this); | |
168 this._notifyDescendant(target); | |
169 | |
170 event.stopPropagation(); | |
171 }, | |
172 | |
173 _parentResizableChanged: function(parentResizable) { | |
174 if (parentResizable) { | |
175 window.removeEventListener('resize', this._boundNotifyResize); | |
176 } | |
177 }, | |
178 | |
179 _notifyDescendant: function(descendant) { | |
180 // NOTE(cdata): In IE10, attached is fired on children first, so it's | |
181 // important not to notify them if the parent is not attached yet (or | |
182 // else they will get redundantly notified when the parent attaches). | |
183 if (!this.isAttached) { | |
184 return; | |
185 } | |
186 | |
187 this._notifyingDescendant = true; | |
188 descendant.notifyResize(); | |
189 this._notifyingDescendant = false; | |
190 } | |
191 }; | |
192 </script> | |
193 | |
OLD | NEW |