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]);
237 this.currentStep_ = step;
241 * Sets visibility of the background.
242 * @param {boolean} visibility Whether background should be visible.
243 * @param {function()=} opt_onCompletion Called after visibility has
246 setBackgroundVisible: function(visible, opt_onCompletion) {
247 changeVisibility(this.backgroundContainer_, visible,
248 this.getBackgroundTransitionDuration(), opt_onCompletion);
252 * Returns default duration of animated transitions, in ms.
254 getDefaultTransitionDuration: function() {
255 return this.transitionsEnabled_ ? DEFAULT_TRANSITION_DURATION_MS : 0;
259 * Returns duration of transitions of background shield, in ms.
261 getBackgroundTransitionDuration: function() {
262 return this.transitionsEnabled_ ? BG_TRANSITION_DURATION_MS : 0;
270 window.onload = function() {
271 cr.FirstRun.initialize();