1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview First run UI.
9 <include src
="step.js">
11 // Transitions durations.
12 /** @const */ var DEFAULT_TRANSITION_DURATION_MS
= 400;
13 /** @const */ var BG_TRANSITION_DURATION_MS
= 800;
16 * Changes visibility of element with animated transition.
17 * @param {Element} element Element which visibility should be changed.
18 * @param {boolean} visible Whether element should be visible after transition.
19 * @param {number=} opt_transitionDuration Time length of transition in
20 * milliseconds. Default value is DEFAULT_TRANSITION_DURATION_MS.
21 * @param {function()=} opt_onFinished Called after transition has finished.
23 function changeVisibility(
24 element
, visible
, opt_transitionDuration
, opt_onFinished
) {
25 var classes
= element
.classList
;
26 // If target visibility is the same as current element visibility.
27 if (classes
.contains('transparent') === !visible
) {
32 var transitionDuration
= (opt_transitionDuration
=== undefined) ?
33 cr
.FirstRun
.getDefaultTransitionDuration() : opt_transitionDuration
;
34 var style
= element
.style
;
35 var oldDurationValue
= style
.getPropertyValue('transition-duration');
36 style
.setProperty('transition-duration', transitionDuration
+ 'ms');
37 var transition
= visible
? 'show-animated' : 'hide-animated';
38 classes
.add(transition
);
39 classes
.toggle('transparent');
40 element
.addEventListener('webkitTransitionEnd', function f() {
41 element
.removeEventListener('webkitTransitionEnd', f
);
42 classes
.remove(transition
);
44 style
.setProperty('transition-duration', oldDurationValue
);
46 style
.removeProperty('transition-duration');
50 ensureTransitionEndEvent(element
, transitionDuration
);
53 cr
.define('cr.FirstRun', function() {
55 // Whether animated transitions are enabled.
56 transitionsEnabled_
: false,
58 // SVG element representing UI background.
61 // Container for background.
62 backgroundContainer_
: null,
64 // Mask element describing transparent "holes" in background.
67 // Pattern used for creating rectangular holes.
68 rectangularHolePattern_
: null,
70 // Pattern used for creating round holes.
71 roundHolePattern_
: null,
73 // Dictionary keeping all available tutorial steps by their names.
76 // Element representing step currently shown for user.
80 * Initializes internal structures and preparing steps.
82 initialize: function() {
83 disableTextSelectAndDrag();
84 this.transitionsEnabled_
= loadTimeData
.getBoolean('transitionsEnabled');
85 this.background_
= $('background');
86 this.backgroundContainer_
= $('background-container');
87 this.mask_
= $('mask');
88 this.rectangularHolePattern_
= $('rectangular-hole-pattern');
89 this.rectangularHolePattern_
.removeAttribute('id');
90 this.roundHolePattern_
= $('round-hole-pattern');
91 this.roundHolePattern_
.removeAttribute('id');
92 var stepElements
= document
.getElementsByClassName('step');
93 for (var i
= 0; i
< stepElements
.length
; ++i
) {
94 var step
= stepElements
[i
];
95 cr
.FirstRun
.DecorateStep(step
);
96 this.steps_
[step
.getName()] = step
;
98 this.setBackgroundVisible(true, function() {
99 chrome
.send('initialized');
104 * Hides all elements and background.
106 finalize: function() {
107 // At first we hide holes (job 1) and current step (job 2) simultaneously,
110 var onJobDone = function() {
114 this.setBackgroundVisible(false, function() {
115 chrome
.send('finalized');
118 this.doHideCurrentStep_(function(name
) {
120 chrome
.send('stepHidden', [name
]);
123 this.removeHoles(onJobDone
);
127 * Adds transparent rectangular hole to background.
128 * @param {number} x X coordinate of top-left corner of hole.
129 * @param {number} y Y coordinate of top-left corner of hole.
130 * @param {number} widht Width of hole.
131 * @param {number} height Height of hole.
133 addRectangularHole: function(x
, y
, width
, height
) {
134 var hole
= this.rectangularHolePattern_
.cloneNode();
135 hole
.setAttribute('x', x
);
136 hole
.setAttribute('y', y
);
137 hole
.setAttribute('width', width
);
138 hole
.setAttribute('height', height
);
139 this.mask_
.appendChild(hole
);
140 setTimeout(function() {
141 changeVisibility(hole
, true);
146 * Adds transparent round hole to background.
147 * @param {number} x X coordinate of circle center.
148 * @param {number} y Y coordinate of circle center.
149 * @param {number} radius Radius of circle.
151 addRoundHole: function(x
, y
, radius
) {
152 var hole
= this.roundHolePattern_
.cloneNode();
153 hole
.setAttribute('cx', x
);
154 hole
.setAttribute('cy', y
);
155 hole
.setAttribute('r', radius
);
156 this.mask_
.appendChild(hole
);
157 setTimeout(function() {
158 changeVisibility(hole
, true);
163 * Removes all holes previously added by |addHole|.
164 * @param {function=} opt_onHolesRemoved Called after all holes have been
167 removeHoles: function(opt_onHolesRemoved
) {
168 var mask
= this.mask_
;
169 var holes
= Array
.prototype.slice
.call(
170 mask
.getElementsByClassName('hole'));
171 var holesLeft
= holes
.length
;
173 if (opt_onHolesRemoved
)
174 opt_onHolesRemoved();
177 holes
.forEach(function(hole
) {
178 changeVisibility(hole
, false, this.getDefaultTransitionDuration(),
180 mask
.removeChild(hole
);
182 if (!holesLeft
&& opt_onHolesRemoved
)
183 opt_onHolesRemoved();
189 * Hides currently active step and notifies chrome after step has been
192 hideCurrentStep: function() {
193 assert(this.currentStep_
);
194 this.doHideCurrentStep_(function(name
) {
195 chrome
.send('stepHidden', [name
]);
200 * Hides currently active step.
201 * @param {function(string)=} opt_onStepHidden Called after step has been
204 doHideCurrentStep_: function(opt_onStepHidden
) {
205 if (!this.currentStep_
) {
206 if (opt_onStepHidden
)
210 var name
= this.currentStep_
.getName();
211 this.currentStep_
.hide(true, function() {
212 this.currentStep_
= null;
213 if (opt_onStepHidden
)
214 opt_onStepHidden(name
);
219 * Shows step with given name in given position.
220 * @param {string} name Name of step.
221 * @param {object} position Optional parameter with optional fields |top|,
222 * |right|, |bottom|, |left| used for step positioning.
223 * @param {Array} pointWithOffset Optional parameter for positioning
224 * bubble. Contains [x, y, offset], where (x, y) - point to which bubble
225 * points, offset - distance between arrow and point.
227 showStep: function(name
, position
, pointWithOffset
) {
228 assert(!this.currentStep_
);
229 if (!this.steps_
.hasOwnProperty(name
))
230 throw Error('Step "' + name
+ '" not found.');
231 var step
= this.steps_
[name
];
233 step
.setPosition(position
);
235 step
.setPointsTo(pointWithOffset
.slice(0, 2), pointWithOffset
[2]);
236 step
.show(true, function(step
) {
237 step
.focusDefaultControl();
238 this.currentStep_
= step
;
239 chrome
.send('stepShown', [name
]);
244 * Sets visibility of the background.
245 * @param {boolean} visibility Whether background should be visible.
246 * @param {function()=} opt_onCompletion Called after visibility has
249 setBackgroundVisible: function(visible
, opt_onCompletion
) {
250 changeVisibility(this.backgroundContainer_
, visible
,
251 this.getBackgroundTransitionDuration(), opt_onCompletion
);
255 * Returns default duration of animated transitions, in ms.
257 getDefaultTransitionDuration: function() {
258 return this.transitionsEnabled_
? DEFAULT_TRANSITION_DURATION_MS
: 0;
262 * Returns duration of transitions of background shield, in ms.
264 getBackgroundTransitionDuration: function() {
265 return this.transitionsEnabled_
? BG_TRANSITION_DURATION_MS
: 0;
273 window
.onload = function() {
274 cr
.FirstRun
.initialize();