2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
5 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
6 Code distributed by Google as part of the polymer project is also
7 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
11 * @group Polymer Mixins
14 <link rel=
"import" href=
"../polymer/polymer.html">
21 `Polymer.CoreResizable` and `Polymer.CoreResizer` are a set of mixins that can be used
22 in Polymer elements to coordinate the flow of resize events between "resizers" (elements
23 that control the size or hidden state of their children) and "resizables" (elements that
24 need to be notified when they are resized or un-hidden by their parents in order to take
25 action on their new measurements).
27 Elements that perform measurement should add the `Core.Resizable` mixin to their
28 Polymer prototype definition and listen for the `core-resize` event on themselves.
29 This event will be fired when they become showing after having been hidden,
30 when they are resized explicitly by a `CoreResizer`, or when the window has been resized.
31 Note, the `core-resize` event is non-bubbling.
33 `CoreResizable`'s must manually call the `resizableAttachedHandler` from the element's
34 `attached` callback and `resizableDetachedHandler` from the element's `detached`
37 @element CoreResizable
42 scope
.CoreResizable
= {
45 * User must call from `attached` callback
47 * @method resizableAttachedHandler
49 resizableAttachedHandler: function(cb
) {
50 cb
= cb
|| this._notifyResizeSelf
;
51 this.async(function() {
52 var detail
= {callback
: cb
, hasParentResizer
: false};
53 this.fire('core-request-resize', detail
);
54 if (!detail
.hasParentResizer
) {
55 this._boundWindowResizeHandler
= cb
.bind(this);
56 // log('adding window resize handler', null, this);
57 window
.addEventListener('resize', this._boundWindowResizeHandler
);
63 * User must call from `detached` callback
65 * @method resizableDetachedHandler
67 resizableDetachedHandler: function() {
68 this.fire('core-request-resize-cancel', null, this, false);
69 if (this._boundWindowResizeHandler
) {
70 window
.removeEventListener('resize', this._boundWindowResizeHandler
);
74 // Private: fire non-bubbling resize event to self; returns whether
75 // preventDefault was called, indicating that children should not
77 _notifyResizeSelf: function() {
78 return this.fire('core-resize', null, this, false).defaultPrevented
;
84 `Polymer.CoreResizable` and `Polymer.CoreResizer` are a set of mixins that can be used
85 in Polymer elements to coordinate the flow of resize events between "resizers" (elements
86 that control the size or hidden state of their children) and "resizables" (elements that
87 need to be notified when they are resized or un-hidden by their parents in order to take
88 action on their new measurements).
90 Elements that cause their children to be resized (e.g. a splitter control) or hide/show
91 their children (e.g. overlay) should add the `Core.CoreResizer` mixin to their
92 Polymer prototype definition and then call `this.notifyResize()` any time the element
93 resizes or un-hides its children.
95 `CoreResizer`'s must manually call the `resizerAttachedHandler` from the element's
96 `attached` callback and `resizerDetachedHandler` from the element's `detached`
99 Note: `CoreResizer` extends `CoreResizable`, and can listen for the `core-resize` event
100 on itself if it needs to perform resize work on itself before notifying children.
101 In this case, returning `false` from the `core-resize` event handler (or calling
102 `preventDefault` on the event) will prevent notification of children if required.
105 @extends CoreResizable
110 scope
.CoreResizer
= Polymer
.mixin({
113 * User must call from `attached` callback
115 * @method resizerAttachedHandler
117 resizerAttachedHandler: function() {
118 this.resizableAttachedHandler(this.notifyResize
);
119 this._boundResizeRequested
= this._boundResizeRequested
|| this._handleResizeRequested
.bind(this);
121 if (this.resizerIsPeer
) {
122 listener
= this.parentElement
|| (this.parentNode
&& this.parentNode
.host
);
123 listener
._resizerPeers
= listener
._resizerPeers
|| [];
124 listener
._resizerPeers
.push(this);
128 listener
.addEventListener('core-request-resize', this._boundResizeRequested
);
129 this._resizerListener
= listener
;
133 * User must call from `detached` callback
135 * @method resizerDetachedHandler
137 resizerDetachedHandler: function() {
138 this.resizableDetachedHandler();
139 this._resizerListener
.removeEventListener('core-request-resize', this._boundResizeRequested
);
143 * User should call when resizing or un-hiding children
145 * @method notifyResize
147 notifyResize: function() {
149 if (!this._notifyResizeSelf()) {
150 // Notify requestors if default was not prevented
151 var r
= this.resizeRequestors
;
153 for (var i
=0; i
<r
.length
; i
++) {
155 if (!this.resizerShouldNotify
|| this.resizerShouldNotify(ri
.target
)) {
156 // log('notifying resize', null, ri.target, true);
157 ri
.callback
.apply(ri
.target
);
166 * User should implement to introduce filtering when notifying children.
167 * Generally, children that are hidden by the CoreResizer (e.g. non-active
168 * pages) need not be notified during resize, since they will be notified
169 * again when becoming un-hidden.
171 * Return `true` if CoreResizable passed as argument should be notified of
174 * @method resizeerShouldNotify
175 * @param {Element} el
177 // resizeerShouldNotify: function(el) { } // User to implement if needed
180 * Set to `true` if the resizer is actually a peer to the elements it
181 * resizes (e.g. splitter); in this case it will listen for resize requests
182 * events from its peers on its parent.
184 * @property resizerIsPeer
189 // Private: Handle requests for resize
190 _handleResizeRequested: function(e
) {
191 var target
= e
.path
[0];
192 if ((target
== this) ||
193 (target
== this._resizerListener
) ||
194 (this._resizerPeers
&& this._resizerPeers
.indexOf(target
) < 0)) {
197 // log('resize requested', target, this);
198 if (!this.resizeRequestors
) {
199 this.resizeRequestors
= [];
201 this.resizeRequestors
.push({target
: target
, callback
: e
.detail
.callback
});
202 target
.addEventListener('core-request-resize-cancel', this._cancelResizeRequested
.bind(this));
203 e
.detail
.hasParentResizer
= true;
207 // Private: Handle cancellation requests for resize
208 _cancelResizeRequested: function(e
) {
209 // Exit early if we're already out of the DOM (resizeRequestors will already be null)
210 if (this.resizeRequestors
) {
211 for (var i
=0; i
<this.resizeRequestors
.length
; i
++) {
212 if (this.resizeRequestors
[i
].target
== e
.target
) {
213 // log('resizeCanceled', e.target, this);
214 this.resizeRequestors
.splice(i
, 1);
221 }, Polymer
.CoreResizable
);
223 // function prettyName(el) {
224 // return el.localName + (el.id ? '#' : '') + el.id;
227 // function log(what, from, to, group) {
228 // var args = [what];
230 // args.push('from ' + prettyName(from));
233 // args.push('to ' + prettyName(to));
236 // console.group.apply(console, args);
238 // console.log.apply(console, args);
242 // function logEnd() {
243 // console.groupEnd();