aboutsummaryrefslogtreecommitdiff
path: root/js/panels/Timeline/Collapser.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/panels/Timeline/Collapser.js')
-rw-r--r--js/panels/Timeline/Collapser.js326
1 files changed, 326 insertions, 0 deletions
diff --git a/js/panels/Timeline/Collapser.js b/js/panels/Timeline/Collapser.js
new file mode 100644
index 00000000..5de884a9
--- /dev/null
+++ b/js/panels/Timeline/Collapser.js
@@ -0,0 +1,326 @@
1/* <copyright>
2 This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
3 No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
4 (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
5 </copyright> */
6
7/*
8 * Collapser: Takes two elements and creates a visual "expando:" clicking on one element expands/collapses the other.
9 * Required properties:
10 * clicker: The element that will be clicked on.
11 * content: The element that will expand or collapse as the clicker is clicked on.
12 * Optional properties:
13 * isCollapsed: Is the content collapsed. Set to true on serialization (or initialization) to start content in collapsed state.
14 * Can be manually set as well.
15 * collapsibleClass: The CSS class to apply to the content and the clicker when collapsed. Defaults to "collapsible-collapsed".
16 * isAnimated: Set to true to apply a transition to expand/collapse (defaults to false).
17 * transitionClass: If isAnimated is set to true, the component will apply transitionClass to the content during the
18 * collapse process. You can then define transitionClass in your style sheet with the desired CSS transitions.
19 * Defaults to "collapsible-transition".
20 * contentHeight: If both isAnimated and isCollapsedAtStart are set to true, set contentHeight to the height of the content
21 * (in pixels, but without the "px") when not collapsed. If this value is not set, the first time the content is expanded
22 * the transition will not work. Subsequent collapses (and expansions) will transition as expected.
23 * isLabelClickable: Boolean that indicates whether or not the clicker should have listener events. Defaults to true; set to
24 * false for collapsers that will only be operated remotely.
25 * toggle(): Manually toggle the expand/collapse of the content.
26 *
27 */
28var Montage = require("montage/core/core").Montage,
29 Component = require("montage/ui/component").Component,
30 Collapser = exports.Collapser = Montage.create(Component, {
31
32 // This component has no template.
33 hasTemplate:{
34 value: false
35 },
36
37 /* === BEGIN: Models === */
38
39 // contentHeight: Stores the height of the content just before collapse.
40 _contentHeight: {
41 value: 0
42 },
43 contentHeight: {
44 get: function() {
45 return this._contentHeight;
46 },
47 set: function(newVal) {
48 this._contentHeight = newVal;
49 }
50 },
51
52 // isCollapsing: true if the collapser is collapsing (or expanding); used in the draw cycle.
53 _isCollapsing: {
54 value: false
55 },
56
57 // isAnimated: boolean to apply transition to expand/collapse
58 _isAnimated : {
59 value: false
60 },
61 isAnimated: {
62 get: function() {
63 return this._isAnimated;
64 },
65 set: function(newVal) {
66 this._isAnimated = newVal;
67 }
68 },
69
70 _bypassAnimation : {
71 value: false
72 },
73 bypassAnimation: {
74 get: function() {
75 return this._bypassAnimation;
76 },
77 set: function(newVal) {
78 this._bypassAnimation= newVal;
79 }
80 },
81
82 // transitionClass: The CSS class to apply to the content during collapse to provide CSS transition.
83 // Note that this CSS class must be defined in your style sheet with the desired transitions.
84 _transitionClass : {
85 value: "collapsible-transition"
86 },
87 transitionClass: {
88 get: function() {
89 return this._transitionClass;
90 },
91 set: function(newVal) {
92 this._transitionClass = newVal;
93 }
94 },
95
96 // isCollapsed: is the content actually collapsed at this moment
97 _isCollapsed: {
98 value: ""
99 },
100 isCollapsed : {
101 get: function() {
102 return this._isCollapsed;
103 },
104 set: function(newVal) {
105 if (newVal !== this._isCollapsed) {
106 this._isCollapsed = newVal;
107 this.needsDraw = true;
108 }
109
110 }
111 },
112
113 // collapsedClass: the class to apply to the clicker and content when the content is collapsed.
114 _collapsedClass : {
115 value: "collapsible-collapsed"
116 },
117 collapsedClass: {
118 get: function() {
119 return this._collapsedClass;
120 },
121 set: function(newVal) {
122 this._collapsedClass = newVal;
123 }
124 },
125
126 // _origOverflowValue: Stores the original overflow value of the collapsible element.
127 // Why store the value? While the collapsible element is collapsed, obviously we will need overflow: hidden.
128 // But when the collapsible element is open, we will need overflow to return to its original value.
129 _origOverflowValue : {
130 value: false
131 },
132
133 // isLabelClickable: Boolean for whether or not the label is clickable. If set to false,
134 // the label click listener is never applied. For collapsibles that will only be operated remotely.
135 // Defaults to true.
136 _isLabelClickable : {
137 value: true
138 },
139 isLabelClickable : {
140 get: function() {
141 return this._isLabelClickable;
142 },
143 set: function(newVal) {
144 this._isLabelClickable = newVal;
145 }
146 },
147
148 // labelClickEvent: an event to fire when the label is clicked.
149 _labelClickEvent: {
150 value: false
151 },
152 labelClickEvent: {
153 get: function() {
154 return this._labelClickEvent;
155 },
156 set: function(newVal) {
157 this._labelClickEvent = newVal;
158 }
159 },
160
161 // toggle: manually toggle the collapser.
162 toggle: {
163 value: function() {
164 if (this.bypassAnimation) {
165 this.isAnimated = false;
166 }
167 this.myContent.classList.remove(this.transitionClass);
168 this.handleCollapserLabelClick();
169 }
170 },
171
172 /* === END: Models === */
173
174 /* === BEGIN: Draw cycle === */
175
176 prepareForDraw: {
177 value: function() {
178 // Add a click listener to the label for expand/collapse
179 if (this.isLabelClickable) {
180 this.clicker.identifier = "collapserLabel";
181 this.clicker.addEventListener("click", this, false);
182 }
183
184 // Get the original value of the overflow property:
185 this._origOverflowValue = window.getComputedStyle(this.myContent, null).getPropertyValue("overflow");
186
187 // If the content area is supposed to start out collapsed:
188 if (this.isCollapsed) {
189 this.myContent.style.height = "0px";
190 // Set the overflow to hidden if it's not already
191 if (this._origOverflowValue !== "hidden") {
192 this.myContent.style.overflow = "hidden";
193 }
194 this.myContent.classList.add(this.collapsedClass);
195 this.clicker.classList.add(this.collapsedClass);
196 } else {
197 this.myContent.style.height = "auto";
198 this.myContent.classList.remove(this.collapsedClass);
199 this.clicker.classList.remove(this.collapsedClass);
200 }
201 }
202 },
203 draw: {
204 value: function() {
205 // Is the content area expanding/collapsing?
206 this.myContent.classList.remove(this.transitionClass);
207 if (this._isCollapsing) {
208
209 if (this.isAnimated) {
210 // Apply the transition class to the content.
211 this.myContent.classList.add(this.transitionClass);
212
213 // Add a handler for the end of the transition, so we can tidy things up after
214 // the transition completes
215 this.myContent.identifier = "myContent";
216 this.myContent.addEventListener("webkitTransitionEnd", this, false);
217
218 this.myContent.style.overflow = "hidden";
219 }
220
221 // Next, are we expanding or collapsing?
222 if (this.myContent.classList.contains(this.collapsedClass)) {
223 // It's already collapsed so we are expanding
224 this.myContent.style.height = this.contentHeight + "px";
225 this.isCollapsed = false;
226
227 } else {
228 // It's expanded so we are collapsing
229 this.myContent.style.height = "0px";