Add an exponential backoff to rechecking the app list doodle.
[chromium-blink-merge.git] / third_party / polymer / components-chromium / core-resizable / core-resizable-extracted.js
blobac70353c307d4ed6bd0c749fbc7c4c093a4436fc
3 (function(scope) {
5 /**
6   `Polymer.CoreResizable` and `Polymer.CoreResizer` are a set of mixins that can be used
7   in Polymer elements to coordinate the flow of resize events between "resizers" (elements
8   that control the size or hidden state of their children) and "resizables" (elements that
9   need to be notified when they are resized or un-hidden by their parents in order to take
10   action on their new measurements).
12   Elements that perform measurement should add the `Core.Resizable` mixin to their 
13   Polymer prototype definition and listen for the `core-resize` event on themselves.
14   This event will be fired when they become showing after having been hidden,
15   when they are resized explicitly by a `CoreResizer`, or when the window has been resized.
16   Note, the `core-resize` event is non-bubbling.
18   `CoreResizable`'s must manually call the `resizableAttachedHandler` from the element's
19   `attached` callback and `resizableDetachedHandler` from the element's `detached`
20   callback.
22     @element CoreResizable
23     @status beta
24     @homepage github.io
27   scope.CoreResizable = {
29     /**
30      * User must call from `attached` callback
31      *
32      * @method resizableAttachedHandler
33      */
34     resizableAttachedHandler: function(cb) {
35       cb = cb || this._notifyResizeSelf;
36       this.async(function() {
37         var detail = {callback: cb, hasParentResizer: false};
38         this.fire('core-request-resize', detail);
39         if (!detail.hasParentResizer) {
40           this._boundWindowResizeHandler = cb.bind(this);
41           // log('adding window resize handler', null, this);
42           window.addEventListener('resize', this._boundWindowResizeHandler);
43         }
44       }.bind(this));
45     },
47     /**
48      * User must call from `detached` callback
49      *
50      * @method resizableDetachedHandler
51      */
52     resizableDetachedHandler: function() {
53       this.fire('core-request-resize-cancel', null, this, false);
54       if (this._boundWindowResizeHandler) {
55         window.removeEventListener('resize', this._boundWindowResizeHandler);
56       }
57     },
59     // Private: fire non-bubbling resize event to self; returns whether
60     // preventDefault was called, indicating that children should not
61     // be resized
62     _notifyResizeSelf: function() {
63       return this.fire('core-resize', null, this, false).defaultPrevented;
64     }
66   };
68 /**
69   `Polymer.CoreResizable` and `Polymer.CoreResizer` are a set of mixins that can be used
70   in Polymer elements to coordinate the flow of resize events between "resizers" (elements
71   that control the size or hidden state of their children) and "resizables" (elements that
72   need to be notified when they are resized or un-hidden by their parents in order to take
73   action on their new measurements).
75   Elements that cause their children to be resized (e.g. a splitter control) or hide/show
76   their children (e.g. overlay) should add the `Core.CoreResizer` mixin to their 
77   Polymer prototype definition and then call `this.notifyResize()` any time the element
78   resizes or un-hides its children.
80   `CoreResizer`'s must manually call the `resizerAttachedHandler` from the element's
81   `attached` callback and `resizerDetachedHandler` from the element's `detached`
82   callback.
84   Note: `CoreResizer` extends `CoreResizable`, and can listen for the `core-resize` event
85   on itself if it needs to perform resize work on itself before notifying children.
86   In this case, returning `false` from the `core-resize` event handler (or calling
87   `preventDefault` on the event) will prevent notification of children if required.
89   @element CoreResizer
90   @extends CoreResizable
91   @status beta
92   @homepage github.io
95   scope.CoreResizer = Polymer.mixin({
97     /**
98      * User must call from `attached` callback
99      *
100      * @method resizerAttachedHandler
101      */
102     resizerAttachedHandler: function() {
103       this.resizableAttachedHandler(this.notifyResize);
104       this._boundResizeRequested = this._boundResizeRequested || this._handleResizeRequested.bind(this);
105       var listener;
106       if (this.resizerIsPeer) {
107         listener = this.parentElement || (this.parentNode && this.parentNode.host);
108         listener._resizerPeers = listener._resizerPeers || [];
109         listener._resizerPeers.push(this);
110       } else {
111         listener = this;
112       }
113       listener.addEventListener('core-request-resize', this._boundResizeRequested);
114       this._resizerListener = listener;
115     },
117     /**
118      * User must call from `detached` callback
119      *
120      * @method resizerDetachedHandler
121      */
122     resizerDetachedHandler: function() {
123       this.resizableDetachedHandler();
124       this._resizerListener.removeEventListener('core-request-resize', this._boundResizeRequested);
125     },
127     /**
128      * User should call when resizing or un-hiding children
129      *
130      * @method notifyResize
131      */
132     notifyResize: function() {
133       // Notify self
134       if (!this._notifyResizeSelf()) {
135         // Notify requestors if default was not prevented
136         var r = this.resizeRequestors;
137         if (r) {
138           for (var i=0; i<r.length; i++) {
139             var ri = r[i];
140             if (!this.resizerShouldNotify || this.resizerShouldNotify(ri.target)) {
141               // log('notifying resize', null, ri.target, true);
142               ri.callback.apply(ri.target);
143               // logEnd();
144             }
145           }
146         }
147       }
148     },
150     /**
151      * User should implement to introduce filtering when notifying children.
152      * Generally, children that are hidden by the CoreResizer (e.g. non-active
153      * pages) need not be notified during resize, since they will be notified
154      * again when becoming un-hidden.
155      *
156      * Return `true` if CoreResizable passed as argument should be notified of
157      * resize.
158      *
159      * @method resizeerShouldNotify
160      * @param {Element} el
161      */
162      // resizeerShouldNotify: function(el) { }  // User to implement if needed
164     /**
165      * Set to `true` if the resizer is actually a peer to the elements it
166      * resizes (e.g. splitter); in this case it will listen for resize requests
167      * events from its peers on its parent.
168      *
169      * @property resizerIsPeer
170      * @type Boolean
171      * @default false
172      */
174     // Private: Handle requests for resize
175     _handleResizeRequested: function(e) {
176       var target = e.path[0];
177       if ((target == this) || 
178           (target == this._resizerListener) || 
179           (this._resizerPeers && this._resizerPeers.indexOf(target) < 0)) {
180         return;
181       }
182       // log('resize requested', target, this);
183       if (!this.resizeRequestors) {
184         this.resizeRequestors = [];
185       }
186       this.resizeRequestors.push({target: target, callback: e.detail.callback});
187       target.addEventListener('core-request-resize-cancel', this._cancelResizeRequested.bind(this));
188       e.detail.hasParentResizer = true;
189       e.stopPropagation();
190     },
192     // Private: Handle cancellation requests for resize
193     _cancelResizeRequested: function(e) {
194       // Exit early if we're already out of the DOM (resizeRequestors will already be null)
195       if (this.resizeRequestors) {
196         for (var i=0; i<this.resizeRequestors.length; i++) {
197           if (this.resizeRequestors[i].target == e.target) {
198             // log('resizeCanceled', e.target, this);
199             this.resizeRequestors.splice(i, 1);
200             break;
201           }
202         }
203       }
204     }
206   }, Polymer.CoreResizable);
208   // function prettyName(el) {
209   //   return el.localName + (el.id ? '#' : '') + el.id;
210   // }
212   // function log(what, from, to, group) {
213   //   var args = [what];
214   //   if (from) {
215   //     args.push('from ' + prettyName(from));
216   //   }
217   //   if (to) {
218   //     args.push('to ' + prettyName(to));
219   //   }
220   //   if (group) {
221   //     console.group.apply(console, args);
222   //   } else {
223   //     console.log.apply(console, args);
224   //   }
225   // }
227   // function logEnd() {
228   //   console.groupEnd();
229   // }
231 })(Polymer);