cros: Remove default pinned apps trial.
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / first_run / step.js
blob86e56e1e423c77fe17e66a674b63f778dc0b47dd
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.
5 /**
6  * Prototype for first-run tutorial steps.
7  */
9 cr.define('cr.FirstRun', function() {
10   var Step = cr.ui.define('div');
12   Step.prototype = {
13     __proto__: HTMLDivElement.prototype,
15     // Name of step.
16     name_: null,
18     // Button leading to next tutorial step.
19     nextButton_: null,
21     decorate: function() {
22       this.name_ = this.getAttribute('id');
23       this.nextButton_ = this.getElementsByClassName('next-button')[0];
24       if (!this.nextButton_)
25         throw Error('Next button not found.');
26       this.nextButton_.addEventListener('click', (function(e) {
27         chrome.send('nextButtonClicked', [this.getName()]);
28         e.stopPropagation();
29       }).bind(this));
30     },
32     /**
33      * Returns name of the string.
34      */
35     getName: function() {
36       return this.name_;
37     },
39     /**
40      * Hides the step.
41      * @param {boolean} animated Whether transition should be animated.
42      * @param {function()=} opt_onHidden Called after step has been hidden.
43      */
44     hide: function(animated, opt_onHidden) {
45       var transitionDuration =
46           animated ? cr.FirstRun.getDefaultTransitionDuration() : 0;
47       changeVisibility(this,
48                        false,
49                        transitionDuration,
50                        function() {
51                          this.classList.add('hidden');
52                          if (opt_onHidden)
53                             opt_onHidden();
54                        }.bind(this));
55     },
57     /**
58      * Shows the step.
59      * @param {boolean} animated Whether transition should be animated.
60      * @param {function()=} opt_onShown Called after step has been shown.
61      */
62     show: function(animated, opt_onShown) {
63       var transitionDuration =
64           animated ? cr.FirstRun.getDefaultTransitionDuration() : 0;
65       this.classList.remove('hidden');
66       changeVisibility(this,
67                        true,
68                        transitionDuration,
69                        function() {
70                          if (opt_onShown)
71                            opt_onShown();
72                        }.bind(this));
73     },
75     /**
76      * Sets position of the step.
77      * @param {object} position Parameter with optional fields |top|,
78      *     |right|, |bottom|, |left| holding corresponding offsets.
79      */
80     setPosition: function(position) {
81       var style = this.style;
82       ['top', 'right', 'bottom', 'left'].forEach(function(property) {
83         if (position.hasOwnProperty(property))
84           style.setProperty(property, position[property] + 'px');
85       });
86     }
87   };
89   var Bubble = cr.ui.define('div');
91   // Styles of .step which are used for arrow styling.
92   var ARROW_STYLES = [
93     'points-up',
94     'points-left',
95     'points-down',
96     'points-right',
97     'top',
98     'left',
99     'bottom',
100     'right'
101   ];
103   var DISTANCE_TO_POINTEE = 10;
104   var MINIMAL_SCREEN_OFFSET = 10;
105   var ARROW_LENGTH = 6; // Keep synced with .arrow border-width.
107   Bubble.prototype = {
108     __proto__: Step.prototype,
110     // Element displaying arrow.
111     arrow_: null,
113     // Unit vector directed along the bubble arrow.
114     direction_: null,
116     /**
117      * In addition to base class 'decorate' this method creates arrow and
118      * sets some properties related to arrow.
119      */
120     decorate: function() {
121       Step.prototype.decorate.call(this);
122       this.arrow_ = document.createElement('div');
123       this.arrow_.classList.add('arrow');
124       this.appendChild(this.arrow_);
125       ARROW_STYLES.forEach(function(style) {
126         if (!this.classList.contains(style))
127           return;
128         // Changing right to left in RTL case.
129         if (document.documentElement.getAttribute('dir') == 'rtl') {
130           style = style.replace(/right|left/, function(match) {
131             return (match == 'right') ? 'left' : 'right';
132           });
133         }
134         this.arrow_.classList.add(style);
135       }.bind(this));
136       var list = this.arrow_.classList;
137       if (list.contains('points-up'))
138         this.direction_ = [0, -1];
139       else if (list.contains('points-right'))
140         this.direction_ = [1, 0];
141       else if (list.contains('points-down'))
142         this.direction_ = [0, 1];
143       else // list.contains('points-left')
144         this.direction_ = [-1, 0];
145     },
147     /**
148      * Sets position of bubble in such a maner that bubble's arrow points to
149      * given point.
150      * @param {Array} point Bubble arrow should point to this point after
151      *     positioning. |point| has format [x, y].
152      * @param {offset} number Additional offset from |point|.
153      */
154     setPointsTo: function(point, offset) {
155       var shouldShowBefore = this.hidden;
156       // "Showing" bubble in order to make offset* methods work.
157       if (shouldShowBefore) {
158         this.style.setProperty('opacity', '0');
159         this.show(false);
160       }
161       var arrow = [this.arrow_.offsetLeft + this.arrow_.offsetWidth / 2,
162                    this.arrow_.offsetTop + this.arrow_.offsetHeight / 2];
163       var totalOffset = DISTANCE_TO_POINTEE + offset;
164       var left = point[0] - totalOffset * this.direction_[0] - arrow[0];
165       var top = point[1] - totalOffset * this.direction_[1] - arrow[1];
166       // Force bubble to be inside screen.
167       if (this.arrow_.classList.contains('points-up') ||
168           this.arrow_.classList.contains('points-down')) {
169         left = Math.max(left, MINIMAL_SCREEN_OFFSET);
170         left = Math.min(left, document.body.offsetWidth - this.offsetWidth -
171             MINIMAL_SCREEN_OFFSET);
172       }
173       if (this.arrow_.classList.contains('points-left') ||
174           this.arrow_.classList.contains('points-right')) {
175         top = Math.max(top, MINIMAL_SCREEN_OFFSET);
176         top = Math.min(top, document.body.offsetHeight - this.offsetHeight -
177             MINIMAL_SCREEN_OFFSET);
178       }
179       this.style.setProperty('left', left + 'px');
180       this.style.setProperty('top', top + 'px');
181       if (shouldShowBefore) {
182         this.hide(false);
183         this.style.removeProperty('opacity');
184       }
185     },
187     /**
188      * Sets position of bubble. Overrides Step.setPosition to adjust offsets
189      * in case if its direction is the same as arrow's direction.
190      * @param {object} position Parameter with optional fields |top|,
191      *     |right|, |bottom|, |left| holding corresponding offsets.
192      */
193     setPosition: function(position) {
194       var arrow = this.arrow_;
195       // Increasing offset if it's from side where bubble points to.
196       [['top', 'points-up'],
197        ['right', 'points-right'],
198        ['bottom', 'points-down'],
199        ['left', 'points-left']].forEach(function(mapping) {
200           if (position.hasOwnProperty(mapping[0]) &&
201               arrow.classList.contains(mapping[1])) {
202             position[mapping[0]] += ARROW_LENGTH + DISTANCE_TO_POINTEE;
203           }
204         });
205       Step.prototype.setPosition.call(this, position);
206     }
207   };
209   var HelpStep = cr.ui.define('div');
211   HelpStep.prototype = {
212     __proto__: Bubble.prototype,
214     decorate: function() {
215       Bubble.prototype.decorate.call(this);
216       var helpButton = this.getElementsByClassName('help-button')[0];
217       helpButton.addEventListener('click', function(e) {
218         chrome.send('helpButtonClicked');
219         e.stopPropagation();
220       });
221     },
222   };
224   var DecorateStep = function(el) {
225     if (el.id == 'help')
226       HelpStep.decorate(el);
227     else if (el.classList.contains('bubble'))
228       Bubble.decorate(el);
229     else
230       Step.decorate(el);
231   };
233   return {DecorateStep: DecorateStep};