Mechanical rename of base::debug -> base::trace_event [final pass]
[chromium-blink-merge.git] / third_party / polymer / components-chromium / core-collapse / core-collapse-extracted.js
blob344e2eedb3933e8c626fbc72f4407d685845db1e
3   Polymer('core-collapse', {
5     /**
6      * Fired when the `core-collapse`'s `opened` property changes.
7      * 
8      * @event core-collapse-open
9      */
11     /**
12      * Fired when the target element has been resized as a result of the opened
13      * state changing.
14      * 
15      * @event core-resize
16      */
18     /**
19      * The target element that will be opened when the `core-collapse` is 
20      * opened. If unspecified, the `core-collapse` itself is the target.
21      *
22      * @attribute target
23      * @type object
24      * @default null
25      */
26     target: null,
28     /**
29      * If true, the orientation is horizontal; otherwise is vertical.
30      *
31      * @attribute horizontal
32      * @type boolean
33      * @default false
34      */
35     horizontal: false,
37     /**
38      * Set opened to true to show the collapse element and to false to hide it.
39      *
40      * @attribute opened
41      * @type boolean
42      * @default false
43      */
44     opened: false,
46     /**
47      * Collapsing/expanding animation duration in second.
48      *
49      * @attribute duration
50      * @type number
51      * @default 0.33
52      */
53     duration: 0.33,
55     /**
56      * If true, the size of the target element is fixed and is set
57      * on the element.  Otherwise it will try to 
58      * use auto to determine the natural size to use
59      * for collapsing/expanding.
60      *
61      * @attribute fixedSize
62      * @type boolean
63      * @default false
64      */
65     fixedSize: false,
66     
67     /**
68      * By default the collapsible element is set to overflow hidden. This helps
69      * avoid element bleeding outside the region and provides consistent overflow
70      * style across opened and closed states. Set this property to true to allow 
71      * the collapsible element to overflow when it's opened.
72      *
73      * @attribute allowOverflow
74      * @type boolean
75      * @default false
76      */
77     allowOverflow: false,
79     created: function() {
80       this.transitionEndListener = this.transitionEnd.bind(this);
81     },
82     
83     ready: function() {
84       this.target = this.target || this;
85     },
87     domReady: function() {
88       this.async(function() {
89         this.afterInitialUpdate = true;
90       });
91     },
93     detached: function() {
94       if (this.target) {
95         this.removeListeners(this.target);
96       }
97     },
99     targetChanged: function(old) {
100       if (old) {
101         this.removeListeners(old);
102       }
103       if (!this.target) {
104         return;
105       }
106       this.isTargetReady = !!this.target;
107       this.classList.toggle('core-collapse-closed', this.target !== this);
108       this.toggleOpenedStyle(false);
109       this.horizontalChanged();
110       this.addListeners(this.target);
111       // set core-collapse-closed class initially to hide the target
112       this.toggleClosedClass(true);
113       this.update();
114     },
116     addListeners: function(node) {
117       node.addEventListener('transitionend', this.transitionEndListener);
118     },
120     removeListeners: function(node) {
121       node.removeEventListener('transitionend', this.transitionEndListener);
122     },
124     horizontalChanged: function() {
125       this.dimension = this.horizontal ? 'width' : 'height';
126     },
128     openedChanged: function() {
129       this.update();
130       this.fire('core-collapse-open', this.opened);
131     },
133     /**
134      * Toggle the opened state.
135      *
136      * @method toggle
137      */
138     toggle: function() {
139       this.opened = !this.opened;
140     },
142     setTransitionDuration: function(duration) {
143       var s = this.target.style;
144       s.transition = duration ? (this.dimension + ' ' + duration + 's') : null;
145       if (duration === 0) {
146         this.async('transitionEnd');
147       }
148     },
150     transitionEnd: function() {
151       if (this.opened && !this.fixedSize) {
152         this.updateSize('auto', null);
153       }
154       this.setTransitionDuration(null);
155       this.toggleOpenedStyle(this.opened);
156       this.toggleClosedClass(!this.opened);
157       this.asyncFire('core-resize', null, this.target);
158     },
160     toggleClosedClass: function(closed) {
161       this.hasClosedClass = closed;
162       this.target.classList.toggle('core-collapse-closed', closed);
163     },
164     
165     toggleOpenedStyle: function(opened) {
166       this.target.style.overflow = this.allowOverflow && opened ? '' : 'hidden';
167     },
169     updateSize: function(size, duration, forceEnd) {
170       this.setTransitionDuration(duration);
171       this.calcSize();
172       var s = this.target.style;
173       var nochange = s[this.dimension] === size;
174       s[this.dimension] = size;
175       // transitonEnd will not be called if the size has not changed
176       if (forceEnd && nochange) {
177         this.transitionEnd();
178       }
179     },
181     update: function() {
182       if (!this.target) {
183         return;
184       }
185       if (!this.isTargetReady) {
186         this.targetChanged(); 
187       }
188       this.horizontalChanged();
189       this[this.opened ? 'show' : 'hide']();
190     },
192     calcSize: function() {
193       return this.target.getBoundingClientRect()[this.dimension] + 'px';
194     },
196     getComputedSize: function() {
197       return getComputedStyle(this.target)[this.dimension];
198     },
200     show: function() {
201       this.toggleClosedClass(false);
202       // for initial update, skip the expanding animation to optimize
203       // performance e.g. skip calcSize
204       if (!this.afterInitialUpdate) {
205         this.transitionEnd();
206         return;
207       }
208       if (!this.fixedSize) {
209         this.updateSize('auto', null);
210         var s = this.calcSize();
211         if (s == '0px') {
212           this.transitionEnd();
213           return;
214         }
215         this.updateSize(0, null);
216       }
217       this.async(function() {
218         this.updateSize(this.size || s, this.duration, true);
219       });
220     },
222     hide: function() {
223       this.toggleOpenedStyle(false);
224       // don't need to do anything if it's already hidden
225       if (this.hasClosedClass && !this.fixedSize) {
226         return;
227       }
228       if (this.fixedSize) {
229         // save the size before hiding it
230         this.size = this.getComputedSize();
231       } else {
232         this.updateSize(this.calcSize(), null);
233       }
234       this.async(function() {
235         this.updateSize(0, this.duration);
236       });
237     }
239   });