├── .editorconfig
├── .gitignore
├── .travis.yml
├── CNAME
├── LICENSE
├── README.md
├── _config.yml
├── bower.json
├── build
├── css
│ ├── bootstrap-tour-standalone.css
│ ├── bootstrap-tour-standalone.min.css
│ ├── bootstrap-tour.css
│ └── bootstrap-tour.min.css
└── js
│ ├── bootstrap-tour-standalone.js
│ ├── bootstrap-tour-standalone.min.js
│ ├── bootstrap-tour.js
│ └── bootstrap-tour.min.js
├── coffeelint.json
├── composer.json
├── gulpfile.js
├── karma.conf.js
├── package.js
├── package.json
├── smart.json
├── src
├── coffee
│ ├── bootstrap-tour.coffee
│ ├── bootstrap-tour.docs.coffee
│ └── bootstrap-tour.spec.coffee
├── docs
│ ├── CNAME
│ ├── _includes
│ │ ├── footer.html
│ │ ├── header.html
│ │ └── nav.html
│ ├── _layouts
│ │ └── default.html
│ ├── api.html
│ ├── assets
│ │ ├── css
│ │ │ ├── bootstrap-tour.css
│ │ │ └── bootstrap-tour.docs.css
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ └── glyphicons-halflings-regular.woff
│ │ ├── img
│ │ │ ├── apple-touch-icon-144-precomposed.png
│ │ │ ├── favicon.png
│ │ │ └── masthead-pattern.png
│ │ ├── js
│ │ │ └── bootstrap-tour.js
│ │ └── vendor
│ │ │ └── pygments-manni.css
│ └── index.html
└── scss
│ ├── bootstrap-tour-standalone.scss
│ └── bootstrap-tour.scss
├── test
└── bootstrap-tour.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | bower_components
3 | bootstrap-tour.sublime-project
4 | bootstrap-tour.sublime-workspace
5 | npm-debug.log
6 | test
7 | docs
8 | _SpecRunner.html
9 | *.DS_Store
10 | smart.lock
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: required
3 | language: node_js
4 | node_js:
5 | - 8
6 | addons:
7 | chrome: stable
8 | before_install:
9 | - "export CHROME_BIN=chromium-browser"
10 | - "export DISPLAY=:99.0"
11 | - "sh -e /etc/init.d/xvfb start"
12 | before_script:
13 | - "yarn global add gulp-cli"
14 | - "npm rebuild node-sass"
15 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | bootstraptour.com
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2015 The Bootstrap Tour community
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bootstrap Tour
2 | [](https://travis-ci.org/sorich87/bootstrap-tour)
3 | [](https://david-dm.org/sorich87/bootstrap-tour)
4 | [](https://david-dm.org/sorich87/bootstrap-tour#info=devDependencies)
5 | [](https://www.npmjs.org/)
6 | [](https://houndci.com)
7 |
8 | Quick and easy way to build your product tours with Bootstrap Popovers.
9 |
10 | *Compatible with Bootstrap >= 2.3.0*
11 |
12 | ## Demo and Documentation
13 | [http://bootstraptour.com](http://bootstraptour.com)
14 |
15 | ## Contributing
16 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Gulp](http://gulpjs.com/).
17 |
18 | Feel free to contribute with pull requests, bug reports or enhancement suggestions.
19 |
20 | We use [Gulp](http://gulpjs.com/) and [Jasmine](http://jasmine.github.io/). Both make your life easier ;)
21 |
22 | ### Develop
23 |
24 | Files to be developed are located under `./src/`.
25 | Compiled sources are then automatically put under `./build/`, `./test/` and `./docs/`.
26 |
27 | #### Requirements
28 |
29 | To begin, you need a few standard dependencies installed. These commands will install ruby, gem, node, yarn, and gulp's command line runner:
30 |
31 | ##### Debian/Ubuntu Linux
32 |
33 | ```bash
34 | $ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
35 | $ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
36 | $ sudo apt-get update && sudo apt-get install ruby-full yarn
37 | ```
38 |
39 | ##### Mac OS X
40 |
41 | ```bash
42 | $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
43 | $ brew install ruby yarn
44 | ```
45 |
46 | ##### Development requirements
47 |
48 | ```bash
49 | $ yarn global add gulp-cli
50 | $ yarn
51 | $ gem install jekyll
52 | ```
53 |
54 | For Mac OS X Mavericks (10.9) users: You will need to [jump through all these hoops](http://dean.io/setting-up-a-ruby-on-rails-development-environment-on-mavericks/) before you can install Jekyll.
55 |
56 | #### Gulp usage
57 |
58 | Run gulp and start to develop with ease:
59 |
60 | ```bash
61 | $ gulp
62 | $ gulp dist
63 | $ gulp test
64 | $ gulp docs
65 | $ gulp clean
66 | $ gulp server
67 | $ gulp bump --type minor (major.minor.patch)
68 | ```
69 |
70 | Check `gulpfile.coffee` to know more.
71 |
72 | ## License
73 |
74 | Code licensed under the [MIT license](https://opensource.org/licenses/MIT).
75 | Documentation licensed under [CC BY 3.0](http://creativecommons.org/licenses/by/3.0/).
76 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | markdown: rdiscount
2 | permalink: pretty
3 | source: ./src/docs
4 | destination: ./docs
5 | encoding: UTF-8
6 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | @$% Not a Bower package. Use a better package management tool instead. ^&*
2 |
--------------------------------------------------------------------------------
/build/css/bootstrap-tour-standalone.css:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-tour - v0.12.0
3 | * http://bootstraptour.com
4 | * ========================================================================
5 | * Copyright 2012-2017 Ulrich Sossou
6 | *
7 | * ========================================================================
8 | * Licensed under the MIT License (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * https://opensource.org/licenses/MIT
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | .btn {
23 | display: inline-block;
24 | font-weight: normal;
25 | text-align: center;
26 | white-space: nowrap;
27 | vertical-align: middle;
28 | user-select: none;
29 | border: 1px solid transparent;
30 | padding: 0.5rem 0.75rem;
31 | font-size: 1rem;
32 | line-height: 1.25;
33 | border-radius: 0.25rem;
34 | transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; }
35 | .btn:focus, .btn:hover {
36 | text-decoration: none; }
37 | .btn:focus, .btn.focus {
38 | outline: 0;
39 | box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25); }
40 | .btn.disabled, .btn:disabled {
41 | opacity: .65; }
42 | .btn:active, .btn.active {
43 | background-image: none; }
44 |
45 | a.btn.disabled,
46 | fieldset[disabled] a.btn {
47 | pointer-events: none; }
48 |
49 | .btn-primary {
50 | color: #fff;
51 | background-color: #007bff;
52 | border-color: #007bff; }
53 | .btn-primary:hover {
54 | color: #fff;
55 | background-color: #0069d9;
56 | border-color: #0062cc; }
57 | .btn-primary:focus, .btn-primary.focus {
58 | box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5); }
59 | .btn-primary.disabled, .btn-primary:disabled {
60 | background-color: #007bff;
61 | border-color: #007bff; }
62 | .btn-primary:active, .btn-primary.active,
63 | .show > .btn-primary.dropdown-toggle {
64 | background-color: #0069d9;
65 | background-image: none;
66 | border-color: #0062cc; }
67 |
68 | .btn-secondary {
69 | color: #fff;
70 | background-color: #868e96;
71 | border-color: #868e96; }
72 | .btn-secondary:hover {
73 | color: #fff;
74 | background-color: #727b84;
75 | border-color: #6c757d; }
76 | .btn-secondary:focus, .btn-secondary.focus {
77 | box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5); }
78 | .btn-secondary.disabled, .btn-secondary:disabled {
79 | background-color: #868e96;
80 | border-color: #868e96; }
81 | .btn-secondary:active, .btn-secondary.active,
82 | .show > .btn-secondary.dropdown-toggle {
83 | background-color: #727b84;
84 | background-image: none;
85 | border-color: #6c757d; }
86 |
87 | .btn-success {
88 | color: #fff;
89 | background-color: #28a745;
90 | border-color: #28a745; }
91 | .btn-success:hover {
92 | color: #fff;
93 | background-color: #218838;
94 | border-color: #1e7e34; }
95 | .btn-success:focus, .btn-success.focus {
96 | box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5); }
97 | .btn-success.disabled, .btn-success:disabled {
98 | background-color: #28a745;
99 | border-color: #28a745; }
100 | .btn-success:active, .btn-success.active,
101 | .show > .btn-success.dropdown-toggle {
102 | background-color: #218838;
103 | background-image: none;
104 | border-color: #1e7e34; }
105 |
106 | .btn-info {
107 | color: #fff;
108 | background-color: #17a2b8;
109 | border-color: #17a2b8; }
110 | .btn-info:hover {
111 | color: #fff;
112 | background-color: #138496;
113 | border-color: #117a8b; }
114 | .btn-info:focus, .btn-info.focus {
115 | box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5); }
116 | .btn-info.disabled, .btn-info:disabled {
117 | background-color: #17a2b8;
118 | border-color: #17a2b8; }
119 | .btn-info:active, .btn-info.active,
120 | .show > .btn-info.dropdown-toggle {
121 | background-color: #138496;
122 | background-image: none;
123 | border-color: #117a8b; }
124 |
125 | .btn-warning {
126 | color: #111;
127 | background-color: #ffc107;
128 | border-color: #ffc107; }
129 | .btn-warning:hover {
130 | color: #111;
131 | background-color: #e0a800;
132 | border-color: #d39e00; }
133 | .btn-warning:focus, .btn-warning.focus {
134 | box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5); }
135 | .btn-warning.disabled, .btn-warning:disabled {
136 | background-color: #ffc107;
137 | border-color: #ffc107; }
138 | .btn-warning:active, .btn-warning.active,
139 | .show > .btn-warning.dropdown-toggle {
140 | background-color: #e0a800;
141 | background-image: none;
142 | border-color: #d39e00; }
143 |
144 | .btn-danger {
145 | color: #fff;
146 | background-color: #dc3545;
147 | border-color: #dc3545; }
148 | .btn-danger:hover {
149 | color: #fff;
150 | background-color: #c82333;
151 | border-color: #bd2130; }
152 | .btn-danger:focus, .btn-danger.focus {
153 | box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5); }
154 | .btn-danger.disabled, .btn-danger:disabled {
155 | background-color: #dc3545;
156 | border-color: #dc3545; }
157 | .btn-danger:active, .btn-danger.active,
158 | .show > .btn-danger.dropdown-toggle {
159 | background-color: #c82333;
160 | background-image: none;
161 | border-color: #bd2130; }
162 |
163 | .btn-light {
164 | color: #111;
165 | background-color: #f8f9fa;
166 | border-color: #f8f9fa; }
167 | .btn-light:hover {
168 | color: #111;
169 | background-color: #e2e6ea;
170 | border-color: #dae0e5; }
171 | .btn-light:focus, .btn-light.focus {
172 | box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5); }
173 | .btn-light.disabled, .btn-light:disabled {
174 | background-color: #f8f9fa;
175 | border-color: #f8f9fa; }
176 | .btn-light:active, .btn-light.active,
177 | .show > .btn-light.dropdown-toggle {
178 | background-color: #e2e6ea;
179 | background-image: none;
180 | border-color: #dae0e5; }
181 |
182 | .btn-dark {
183 | color: #fff;
184 | background-color: #343a40;
185 | border-color: #343a40; }
186 | .btn-dark:hover {
187 | color: #fff;
188 | background-color: #23272b;
189 | border-color: #1d2124; }
190 | .btn-dark:focus, .btn-dark.focus {
191 | box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5); }
192 | .btn-dark.disabled, .btn-dark:disabled {
193 | background-color: #343a40;
194 | border-color: #343a40; }
195 | .btn-dark:active, .btn-dark.active,
196 | .show > .btn-dark.dropdown-toggle {
197 | background-color: #23272b;
198 | background-image: none;
199 | border-color: #1d2124; }
200 |
201 | .btn-outline-primary {
202 | color: #007bff;
203 | background-color: transparent;
204 | background-image: none;
205 | border-color: #007bff; }
206 | .btn-outline-primary:hover {
207 | color: #fff;
208 | background-color: #007bff;
209 | border-color: #007bff; }
210 | .btn-outline-primary:focus, .btn-outline-primary.focus {
211 | box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5); }
212 | .btn-outline-primary.disabled, .btn-outline-primary:disabled {
213 | color: #007bff;
214 | background-color: transparent; }
215 | .btn-outline-primary:active, .btn-outline-primary.active,
216 | .show > .btn-outline-primary.dropdown-toggle {
217 | color: #fff;
218 | background-color: #007bff;
219 | border-color: #007bff; }
220 |
221 | .btn-outline-secondary {
222 | color: #868e96;
223 | background-color: transparent;
224 | background-image: none;
225 | border-color: #868e96; }
226 | .btn-outline-secondary:hover {
227 | color: #fff;
228 | background-color: #868e96;
229 | border-color: #868e96; }
230 | .btn-outline-secondary:focus, .btn-outline-secondary.focus {
231 | box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5); }
232 | .btn-outline-secondary.disabled, .btn-outline-secondary:disabled {
233 | color: #868e96;
234 | background-color: transparent; }
235 | .btn-outline-secondary:active, .btn-outline-secondary.active,
236 | .show > .btn-outline-secondary.dropdown-toggle {
237 | color: #fff;
238 | background-color: #868e96;
239 | border-color: #868e96; }
240 |
241 | .btn-outline-success {
242 | color: #28a745;
243 | background-color: transparent;
244 | background-image: none;
245 | border-color: #28a745; }
246 | .btn-outline-success:hover {
247 | color: #fff;
248 | background-color: #28a745;
249 | border-color: #28a745; }
250 | .btn-outline-success:focus, .btn-outline-success.focus {
251 | box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5); }
252 | .btn-outline-success.disabled, .btn-outline-success:disabled {
253 | color: #28a745;
254 | background-color: transparent; }
255 | .btn-outline-success:active, .btn-outline-success.active,
256 | .show > .btn-outline-success.dropdown-toggle {
257 | color: #fff;
258 | background-color: #28a745;
259 | border-color: #28a745; }
260 |
261 | .btn-outline-info {
262 | color: #17a2b8;
263 | background-color: transparent;
264 | background-image: none;
265 | border-color: #17a2b8; }
266 | .btn-outline-info:hover {
267 | color: #fff;
268 | background-color: #17a2b8;
269 | border-color: #17a2b8; }
270 | .btn-outline-info:focus, .btn-outline-info.focus {
271 | box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5); }
272 | .btn-outline-info.disabled, .btn-outline-info:disabled {
273 | color: #17a2b8;
274 | background-color: transparent; }
275 | .btn-outline-info:active, .btn-outline-info.active,
276 | .show > .btn-outline-info.dropdown-toggle {
277 | color: #fff;
278 | background-color: #17a2b8;
279 | border-color: #17a2b8; }
280 |
281 | .btn-outline-warning {
282 | color: #ffc107;
283 | background-color: transparent;
284 | background-image: none;
285 | border-color: #ffc107; }
286 | .btn-outline-warning:hover {
287 | color: #fff;
288 | background-color: #ffc107;
289 | border-color: #ffc107; }
290 | .btn-outline-warning:focus, .btn-outline-warning.focus {
291 | box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5); }
292 | .btn-outline-warning.disabled, .btn-outline-warning:disabled {
293 | color: #ffc107;
294 | background-color: transparent; }
295 | .btn-outline-warning:active, .btn-outline-warning.active,
296 | .show > .btn-outline-warning.dropdown-toggle {
297 | color: #fff;
298 | background-color: #ffc107;
299 | border-color: #ffc107; }
300 |
301 | .btn-outline-danger {
302 | color: #dc3545;
303 | background-color: transparent;
304 | background-image: none;
305 | border-color: #dc3545; }
306 | .btn-outline-danger:hover {
307 | color: #fff;
308 | background-color: #dc3545;
309 | border-color: #dc3545; }
310 | .btn-outline-danger:focus, .btn-outline-danger.focus {
311 | box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5); }
312 | .btn-outline-danger.disabled, .btn-outline-danger:disabled {
313 | color: #dc3545;
314 | background-color: transparent; }
315 | .btn-outline-danger:active, .btn-outline-danger.active,
316 | .show > .btn-outline-danger.dropdown-toggle {
317 | color: #fff;
318 | background-color: #dc3545;
319 | border-color: #dc3545; }
320 |
321 | .btn-outline-light {
322 | color: #f8f9fa;
323 | background-color: transparent;
324 | background-image: none;
325 | border-color: #f8f9fa; }
326 | .btn-outline-light:hover {
327 | color: #fff;
328 | background-color: #f8f9fa;
329 | border-color: #f8f9fa; }
330 | .btn-outline-light:focus, .btn-outline-light.focus {
331 | box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5); }
332 | .btn-outline-light.disabled, .btn-outline-light:disabled {
333 | color: #f8f9fa;
334 | background-color: transparent; }
335 | .btn-outline-light:active, .btn-outline-light.active,
336 | .show > .btn-outline-light.dropdown-toggle {
337 | color: #fff;
338 | background-color: #f8f9fa;
339 | border-color: #f8f9fa; }
340 |
341 | .btn-outline-dark {
342 | color: #343a40;
343 | background-color: transparent;
344 | background-image: none;
345 | border-color: #343a40; }
346 | .btn-outline-dark:hover {
347 | color: #fff;
348 | background-color: #343a40;
349 | border-color: #343a40; }
350 | .btn-outline-dark:focus, .btn-outline-dark.focus {
351 | box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5); }
352 | .btn-outline-dark.disabled, .btn-outline-dark:disabled {
353 | color: #343a40;
354 | background-color: transparent; }
355 | .btn-outline-dark:active, .btn-outline-dark.active,
356 | .show > .btn-outline-dark.dropdown-toggle {
357 | color: #fff;
358 | background-color: #343a40;
359 | border-color: #343a40; }
360 |
361 | .btn-link {
362 | font-weight: normal;
363 | color: #007bff;
364 | border-radius: 0; }
365 | .btn-link, .btn-link:active, .btn-link.active, .btn-link:disabled {
366 | background-color: transparent; }
367 | .btn-link, .btn-link:focus, .btn-link:active {
368 | border-color: transparent;
369 | box-shadow: none; }
370 | .btn-link:hover {
371 | border-color: transparent; }
372 | .btn-link:focus, .btn-link:hover {
373 | color: #0056b3;
374 | text-decoration: underline;
375 | background-color: transparent; }
376 | .btn-link:disabled {
377 | color: #868e96; }
378 | .btn-link:disabled:focus, .btn-link:disabled:hover {
379 | text-decoration: none; }
380 |
381 | .btn-lg, .btn-group-lg > .btn {
382 | padding: 0.5rem 1rem;
383 | font-size: 1.25rem;
384 | line-height: 1.5;
385 | border-radius: 0.3rem; }
386 |
387 | .btn-sm, .btn-group-sm > .btn {
388 | padding: 0.25rem 0.5rem;
389 | font-size: 0.875rem;
390 | line-height: 1.5;
391 | border-radius: 0.2rem; }
392 |
393 | .btn-block {
394 | display: block;
395 | width: 100%; }
396 |
397 | .btn-block + .btn-block {
398 | margin-top: 0.5rem; }
399 |
400 | input[type="submit"].btn-block,
401 | input[type="reset"].btn-block,
402 | input[type="button"].btn-block {
403 | width: 100%; }
404 |
405 | .fade {
406 | opacity: 0;
407 | transition: opacity 0.15s linear; }
408 | .fade.show {
409 | opacity: 1; }
410 |
411 | .collapse {
412 | display: none; }
413 | .collapse.show {
414 | display: block; }
415 |
416 | tr.collapse.show {
417 | display: table-row; }
418 |
419 | tbody.collapse.show {
420 | display: table-row-group; }
421 |
422 | .collapsing {
423 | position: relative;
424 | height: 0;
425 | overflow: hidden;
426 | transition: height 0.35s ease; }
427 |
428 | .btn-group,
429 | .btn-group-vertical {
430 | position: relative;
431 | display: inline-flex;
432 | vertical-align: middle; }
433 | .btn-group > .btn,
434 | .btn-group-vertical > .btn {
435 | position: relative;
436 | flex: 0 1 auto;
437 | margin-bottom: 0; }
438 | .btn-group > .btn:hover,
439 | .btn-group-vertical > .btn:hover {
440 | z-index: 2; }
441 | .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,
442 | .btn-group-vertical > .btn:focus,
443 | .btn-group-vertical > .btn:active,
444 | .btn-group-vertical > .btn.active {
445 | z-index: 2; }
446 | .btn-group .btn + .btn,
447 | .btn-group .btn + .btn-group,
448 | .btn-group .btn-group + .btn,
449 | .btn-group .btn-group + .btn-group,
450 | .btn-group-vertical .btn + .btn,
451 | .btn-group-vertical .btn + .btn-group,
452 | .btn-group-vertical .btn-group + .btn,
453 | .btn-group-vertical .btn-group + .btn-group {
454 | margin-left: -1px; }
455 |
456 | .btn-toolbar {
457 | display: flex;
458 | flex-wrap: wrap;
459 | justify-content: flex-start; }
460 | .btn-toolbar .input-group {
461 | width: auto; }
462 |
463 | .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
464 | border-radius: 0; }
465 |
466 | .btn-group > .btn:first-child {
467 | margin-left: 0; }
468 | .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
469 | border-top-right-radius: 0;
470 | border-bottom-right-radius: 0; }
471 |
472 | .btn-group > .btn:last-child:not(:first-child),
473 | .btn-group > .dropdown-toggle:not(:first-child) {
474 | border-top-left-radius: 0;
475 | border-bottom-left-radius: 0; }
476 |
477 | .btn-group > .btn-group {
478 | float: left; }
479 |
480 | .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
481 | border-radius: 0; }
482 |
483 | .btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
484 | .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
485 | border-top-right-radius: 0;
486 | border-bottom-right-radius: 0; }
487 |
488 | .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
489 | border-top-left-radius: 0;
490 | border-bottom-left-radius: 0; }
491 |
492 | .btn + .dropdown-toggle-split {
493 | padding-right: 0.5625rem;
494 | padding-left: 0.5625rem; }
495 | .btn + .dropdown-toggle-split::after {
496 | margin-left: 0; }
497 |
498 | .btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {
499 | padding-right: 0.375rem;
500 | padding-left: 0.375rem; }
501 |
502 | .btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {
503 | padding-right: 0.75rem;
504 | padding-left: 0.75rem; }
505 |
506 | .btn-group-vertical {
507 | display: inline-flex;
508 | flex-direction: column;
509 | align-items: flex-start;
510 | justify-content: center; }
511 | .btn-group-vertical .btn,
512 | .btn-group-vertical .btn-group {
513 | width: 100%; }
514 | .btn-group-vertical > .btn + .btn,
515 | .btn-group-vertical > .btn + .btn-group,
516 | .btn-group-vertical > .btn-group + .btn,
517 | .btn-group-vertical > .btn-group + .btn-group {
518 | margin-top: -1px;
519 | margin-left: 0; }
520 |
521 | .btn-group-vertical > .btn:not(:first-child):not(:last-child) {
522 | border-radius: 0; }
523 |
524 | .btn-group-vertical > .btn:first-child:not(:last-child) {
525 | border-bottom-right-radius: 0;
526 | border-bottom-left-radius: 0; }
527 |
528 | .btn-group-vertical > .btn:last-child:not(:first-child) {
529 | border-top-left-radius: 0;
530 | border-top-right-radius: 0; }
531 |
532 | .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
533 | border-radius: 0; }
534 |
535 | .btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
536 | .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
537 | border-bottom-right-radius: 0;
538 | border-bottom-left-radius: 0; }
539 |
540 | .btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
541 | border-top-left-radius: 0;
542 | border-top-right-radius: 0; }
543 |
544 | [data-toggle="buttons"] > .btn input[type="radio"],
545 | [data-toggle="buttons"] > .btn input[type="checkbox"],
546 | [data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
547 | [data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
548 | position: absolute;
549 | clip: rect(0, 0, 0, 0);
550 | pointer-events: none; }
551 |
552 | .popover {
553 | position: absolute;
554 | top: 0;
555 | left: 0;
556 | z-index: 1060;
557 | display: block;
558 | max-width: 276px;
559 | padding: 1px;
560 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
561 | font-style: normal;
562 | font-weight: normal;
563 | line-height: 1.5;
564 | text-align: left;
565 | text-align: start;
566 | text-decoration: none;
567 | text-shadow: none;
568 | text-transform: none;
569 | letter-spacing: normal;
570 | word-break: normal;
571 | word-spacing: normal;
572 | white-space: normal;
573 | line-break: auto;
574 | font-size: 0.875rem;
575 | word-wrap: break-word;
576 | background-color: #fff;
577 | background-clip: padding-box;
578 | border: 1px solid rgba(0, 0, 0, 0.2);
579 | border-radius: 0.3rem; }
580 | .popover .arrow {
581 | position: absolute;
582 | display: block;
583 | width: 10px;
584 | height: 5px; }
585 | .popover .arrow::before,
586 | .popover .arrow::after {
587 | position: absolute;
588 | display: block;
589 | border-color: transparent;
590 | border-style: solid; }
591 | .popover .arrow::before {
592 | content: "";
593 | border-width: 11px; }
594 | .popover .arrow::after {
595 | content: "";
596 | border-width: 11px; }
597 | .popover.bs-popover-top, .popover.bs-popover-auto[x-placement^="top"] {
598 | margin-bottom: 10px; }
599 | .popover.bs-popover-top .arrow, .popover.bs-popover-auto[x-placement^="top"] .arrow {
600 | bottom: 0; }
601 | .popover.bs-popover-top .arrow::before, .popover.bs-popover-auto[x-placement^="top"] .arrow::before,
602 | .popover.bs-popover-top .arrow::after, .popover.bs-popover-auto[x-placement^="top"] .arrow::after {
603 | border-bottom-width: 0; }
604 | .popover.bs-popover-top .arrow::before, .popover.bs-popover-auto[x-placement^="top"] .arrow::before {
605 | bottom: -11px;
606 | margin-left: -6px;
607 | border-top-color: rgba(0, 0, 0, 0.25); }
608 | .popover.bs-popover-top .arrow::after, .popover.bs-popover-auto[x-placement^="top"] .arrow::after {
609 | bottom: -10px;
610 | margin-left: -6px;
611 | border-top-color: #fff; }
612 | .popover.bs-popover-right, .popover.bs-popover-auto[x-placement^="right"] {
613 | margin-left: 10px; }
614 | .popover.bs-popover-right .arrow, .popover.bs-popover-auto[x-placement^="right"] .arrow {
615 | left: 0; }
616 | .popover.bs-popover-right .arrow::before, .popover.bs-popover-auto[x-placement^="right"] .arrow::before,
617 | .popover.bs-popover-right .arrow::after, .popover.bs-popover-auto[x-placement^="right"] .arrow::after {
618 | margin-top: -8px;
619 | border-left-width: 0; }
620 | .popover.bs-popover-right .arrow::before, .popover.bs-popover-auto[x-placement^="right"] .arrow::before {
621 | left: -11px;
622 | border-right-color: rgba(0, 0, 0, 0.25); }
623 | .popover.bs-popover-right .arrow::after, .popover.bs-popover-auto[x-placement^="right"] .arrow::after {
624 | left: -10px;
625 | border-right-color: #fff; }
626 | .popover.bs-popover-bottom, .popover.bs-popover-auto[x-placement^="bottom"] {
627 | margin-top: 10px; }
628 | .popover.bs-popover-bottom .arrow, .popover.bs-popover-auto[x-placement^="bottom"] .arrow {
629 | top: 0; }
630 | .popover.bs-popover-bottom .arrow::before, .popover.bs-popover-auto[x-placement^="bottom"] .arrow::before,
631 | .popover.bs-popover-bottom .arrow::after, .popover.bs-popover-auto[x-placement^="bottom"] .arrow::after {
632 | margin-left: -7px;
633 | border-top-width: 0; }
634 | .popover.bs-popover-bottom .arrow::before, .popover.bs-popover-auto[x-placement^="bottom"] .arrow::before {
635 | top: -11px;
636 | border-bottom-color: rgba(0, 0, 0, 0.25); }
637 | .popover.bs-popover-bottom .arrow::after, .popover.bs-popover-auto[x-placement^="bottom"] .arrow::after {
638 | top: -10px;
639 | border-bottom-color: #fff; }
640 | .popover.bs-popover-bottom .popover-header::before, .popover.bs-popover-auto[x-placement^="bottom"] .popover-header::before {
641 | position: absolute;
642 | top: 0;
643 | left: 50%;
644 | display: block;
645 | width: 20px;
646 | margin-left: -10px;
647 | content: "";
648 | border-bottom: 1px solid #f7f7f7; }
649 | .popover.bs-popover-left, .popover.bs-popover-auto[x-placement^="left"] {
650 | margin-right: 10px; }
651 | .popover.bs-popover-left .arrow, .popover.bs-popover-auto[x-placement^="left"] .arrow {
652 | right: 0; }
653 | .popover.bs-popover-left .arrow::before, .popover.bs-popover-auto[x-placement^="left"] .arrow::before,
654 | .popover.bs-popover-left .arrow::after, .popover.bs-popover-auto[x-placement^="left"] .arrow::after {
655 | margin-top: -8px;
656 | border-right-width: 0; }
657 | .popover.bs-popover-left .arrow::before, .popover.bs-popover-auto[x-placement^="left"] .arrow::before {
658 | right: -11px;
659 | border-left-color: rgba(0, 0, 0, 0.25); }
660 | .popover.bs-popover-left .arrow::after, .popover.bs-popover-auto[x-placement^="left"] .arrow::after {
661 | right: -10px;
662 | border-left-color: #fff; }
663 |
664 | .popover-header {
665 | padding: 8px 14px;
666 | margin-bottom: 0;
667 | font-size: 1rem;
668 | color: inherit;
669 | background-color: #f7f7f7;
670 | border-bottom: 1px solid #ebebeb;
671 | border-top-left-radius: calc(0.3rem - 1px);
672 | border-top-right-radius: calc(0.3rem - 1px); }
673 | .popover-header:empty {
674 | display: none; }
675 |
676 | .popover-body {
677 | padding: 9px 14px;
678 | color: #212529; }
679 |
680 | .tour-backdrop {
681 | background-color: #000;
682 | filter: alpha(opacity=80);
683 | opacity: .8;
684 | position: absolute;
685 | z-index: 1100; }
686 |
687 | .popover[class*="tour-"] {
688 | z-index: 1102; }
689 | .popover[class*="tour-"] .popover-navigation {
690 | overflow: hidden;
691 | padding: 9px 14px; }
692 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] {
693 | float: right; }
694 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"],
695 | .popover[class*="tour-"] .popover-navigation *[data-role="next"],
696 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] {
697 | cursor: pointer; }
698 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled,
699 | .popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled,
700 | .popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled {
701 | cursor: default; }
702 | .popover[class*="tour-"].orphan {
703 | left: 50%;
704 | margin-top: 0;
705 | position: fixed;
706 | top: 50%;
707 | transform: translate(-50%, -50%); }
708 | .popover[class*="tour-"].orphan .arrow {
709 | display: none; }
710 |
--------------------------------------------------------------------------------
/build/css/bootstrap-tour-standalone.min.css:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-tour - v0.12.0
3 | * http://bootstraptour.com
4 | * ========================================================================
5 | * Copyright 2012-2017 Ulrich Sossou
6 | *
7 | * ========================================================================
8 | * Licensed under the MIT License (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * https://opensource.org/licenses/MIT
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | .btn{display:inline-block;font-weight:normal;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;border:1px solid transparent;padding:0.5rem 0.75rem;font-size:1rem;line-height:1.25;border-radius:0.25rem;transition:background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn:focus,.btn.focus{outline:0;box-shadow:0 0 0 3px rgba(0,123,255,0.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:active,.btn.active{background-image:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary:focus,.btn-primary.focus{box-shadow:0 0 0 3px rgba(0,123,255,0.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#007bff;border-color:#007bff}.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{background-color:#0069d9;background-image:none;border-color:#0062cc}.btn-secondary{color:#fff;background-color:#868e96;border-color:#868e96}.btn-secondary:hover{color:#fff;background-color:#727b84;border-color:#6c757d}.btn-secondary:focus,.btn-secondary.focus{box-shadow:0 0 0 3px rgba(134,142,150,0.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#868e96;border-color:#868e96}.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{background-color:#727b84;background-image:none;border-color:#6c757d}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success:focus,.btn-success.focus{box-shadow:0 0 0 3px rgba(40,167,69,0.5)}.btn-success.disabled,.btn-success:disabled{background-color:#28a745;border-color:#28a745}.btn-success:active,.btn-success.active,.show>.btn-success.dropdown-toggle{background-color:#218838;background-image:none;border-color:#1e7e34}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info:focus,.btn-info.focus{box-shadow:0 0 0 3px rgba(23,162,184,0.5)}.btn-info.disabled,.btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8}.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{background-color:#138496;background-image:none;border-color:#117a8b}.btn-warning{color:#111;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#111;background-color:#e0a800;border-color:#d39e00}.btn-warning:focus,.btn-warning.focus{box-shadow:0 0 0 3px rgba(255,193,7,0.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#ffc107;border-color:#ffc107}.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{background-color:#e0a800;background-image:none;border-color:#d39e00}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger:focus,.btn-danger.focus{box-shadow:0 0 0 3px rgba(220,53,69,0.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#dc3545;border-color:#dc3545}.btn-danger:active,.btn-danger.active,.show>.btn-danger.dropdown-toggle{background-color:#c82333;background-image:none;border-color:#bd2130}.btn-light{color:#111;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#111;background-color:#e2e6ea;border-color:#dae0e5}.btn-light:focus,.btn-light.focus{box-shadow:0 0 0 3px rgba(248,249,250,0.5)}.btn-light.disabled,.btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:active,.btn-light.active,.show>.btn-light.dropdown-toggle{background-color:#e2e6ea;background-image:none;border-color:#dae0e5}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark:focus,.btn-dark.focus{box-shadow:0 0 0 3px rgba(52,58,64,0.5)}.btn-dark.disabled,.btn-dark:disabled{background-color:#343a40;border-color:#343a40}.btn-dark:active,.btn-dark.active,.show>.btn-dark.dropdown-toggle{background-color:#23272b;background-image:none;border-color:#1d2124}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:focus,.btn-outline-primary.focus{box-shadow:0 0 0 3px rgba(0,123,255,0.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:active,.btn-outline-primary.active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-secondary{color:#868e96;background-color:transparent;background-image:none;border-color:#868e96}.btn-outline-secondary:hover{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-secondary:focus,.btn-outline-secondary.focus{box-shadow:0 0 0 3px rgba(134,142,150,0.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#868e96;background-color:transparent}.btn-outline-secondary:active,.btn-outline-secondary.active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:focus,.btn-outline-success.focus{box-shadow:0 0 0 3px rgba(40,167,69,0.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:active,.btn-outline-success.active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:focus,.btn-outline-info.focus{box-shadow:0 0 0 3px rgba(23,162,184,0.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:active,.btn-outline-info.active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:focus,.btn-outline-warning.focus{box-shadow:0 0 0 3px rgba(255,193,7,0.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:active,.btn-outline-warning.active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:focus,.btn-outline-danger.focus{box-shadow:0 0 0 3px rgba(220,53,69,0.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:active,.btn-outline-danger.active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:focus,.btn-outline-light.focus{box-shadow:0 0 0 3px rgba(248,249,250,0.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:active,.btn-outline-light.active,.show>.btn-outline-light.dropdown-toggle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:focus,.btn-outline-dark.focus{box-shadow:0 0 0 3px rgba(52,58,64,0.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:active,.btn-outline-dark.active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-link{font-weight:normal;color:#007bff;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:focus,.btn-link:active{border-color:transparent;box-shadow:none}.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent}.btn-link:disabled{color:#868e96}.btn-link:disabled:focus,.btn-link:disabled:hover{text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:0.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:0.3rem}.btn-sm,.btn-group-sm>.btn{padding:0.25rem 0.5rem;font-size:0.875rem;line-height:1.5;border-radius:0.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:0.5rem}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;transition:opacity 0.15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height 0.35s ease}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:0 1 auto;margin-bottom:0}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover{z-index:2}.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn+.dropdown-toggle-split{padding-right:0.5625rem;padding-left:0.5625rem}.btn+.dropdown-toggle-split::after{margin-left:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:0.375rem;padding-left:0.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:0.75rem;padding-left:0.75rem}.btn-group-vertical{display:inline-flex;flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-style:normal;font-weight:normal;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,0.2);border-radius:0.3rem}.popover .arrow{position:absolute;display:block;width:10px;height:5px}.popover .arrow::before,.popover .arrow::after{position:absolute;display:block;border-color:transparent;border-style:solid}.popover .arrow::before{content:"";border-width:11px}.popover .arrow::after{content:"";border-width:11px}.popover.bs-popover-top,.popover.bs-popover-auto[x-placement^="top"]{margin-bottom:10px}.popover.bs-popover-top .arrow,.popover.bs-popover-auto[x-placement^="top"] .arrow{bottom:0}.popover.bs-popover-top .arrow::before,.popover.bs-popover-auto[x-placement^="top"] .arrow::before,.popover.bs-popover-top .arrow::after,.popover.bs-popover-auto[x-placement^="top"] .arrow::after{border-bottom-width:0}.popover.bs-popover-top .arrow::before,.popover.bs-popover-auto[x-placement^="top"] .arrow::before{bottom:-11px;margin-left:-6px;border-top-color:rgba(0,0,0,0.25)}.popover.bs-popover-top .arrow::after,.popover.bs-popover-auto[x-placement^="top"] .arrow::after{bottom:-10px;margin-left:-6px;border-top-color:#fff}.popover.bs-popover-right,.popover.bs-popover-auto[x-placement^="right"]{margin-left:10px}.popover.bs-popover-right .arrow,.popover.bs-popover-auto[x-placement^="right"] .arrow{left:0}.popover.bs-popover-right .arrow::before,.popover.bs-popover-auto[x-placement^="right"] .arrow::before,.popover.bs-popover-right .arrow::after,.popover.bs-popover-auto[x-placement^="right"] .arrow::after{margin-top:-8px;border-left-width:0}.popover.bs-popover-right .arrow::before,.popover.bs-popover-auto[x-placement^="right"] .arrow::before{left:-11px;border-right-color:rgba(0,0,0,0.25)}.popover.bs-popover-right .arrow::after,.popover.bs-popover-auto[x-placement^="right"] .arrow::after{left:-10px;border-right-color:#fff}.popover.bs-popover-bottom,.popover.bs-popover-auto[x-placement^="bottom"]{margin-top:10px}.popover.bs-popover-bottom .arrow,.popover.bs-popover-auto[x-placement^="bottom"] .arrow{top:0}.popover.bs-popover-bottom .arrow::before,.popover.bs-popover-auto[x-placement^="bottom"] .arrow::before,.popover.bs-popover-bottom .arrow::after,.popover.bs-popover-auto[x-placement^="bottom"] .arrow::after{margin-left:-7px;border-top-width:0}.popover.bs-popover-bottom .arrow::before,.popover.bs-popover-auto[x-placement^="bottom"] .arrow::before{top:-11px;border-bottom-color:rgba(0,0,0,0.25)}.popover.bs-popover-bottom .arrow::after,.popover.bs-popover-auto[x-placement^="bottom"] .arrow::after{top:-10px;border-bottom-color:#fff}.popover.bs-popover-bottom .popover-header::before,.popover.bs-popover-auto[x-placement^="bottom"] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:20px;margin-left:-10px;content:"";border-bottom:1px solid #f7f7f7}.popover.bs-popover-left,.popover.bs-popover-auto[x-placement^="left"]{margin-right:10px}.popover.bs-popover-left .arrow,.popover.bs-popover-auto[x-placement^="left"] .arrow{right:0}.popover.bs-popover-left .arrow::before,.popover.bs-popover-auto[x-placement^="left"] .arrow::before,.popover.bs-popover-left .arrow::after,.popover.bs-popover-auto[x-placement^="left"] .arrow::after{margin-top:-8px;border-right-width:0}.popover.bs-popover-left .arrow::before,.popover.bs-popover-auto[x-placement^="left"] .arrow::before{right:-11px;border-left-color:rgba(0,0,0,0.25)}.popover.bs-popover-left .arrow::after,.popover.bs-popover-auto[x-placement^="left"] .arrow::after{right:-10px;border-left-color:#fff}.popover-header{padding:8px 14px;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(0.3rem - 1px);border-top-right-radius:calc(0.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:9px 14px;color:#212529}.tour-backdrop{background-color:#000;filter:alpha(opacity=80);opacity:.8;position:absolute;z-index:1100}.popover[class*="tour-"]{z-index:1102}.popover[class*="tour-"] .popover-navigation{overflow:hidden;padding:9px 14px}.popover[class*="tour-"] .popover-navigation *[data-role="end"]{float:right}.popover[class*="tour-"] .popover-navigation *[data-role="prev"],.popover[class*="tour-"] .popover-navigation *[data-role="next"],.popover[class*="tour-"] .popover-navigation *[data-role="end"]{cursor:pointer}.popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled,.popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled,.popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled{cursor:default}.popover[class*="tour-"].orphan{left:50%;margin-top:0;position:fixed;top:50%;transform:translate(-50%, -50%)}.popover[class*="tour-"].orphan .arrow{display:none}
23 |
--------------------------------------------------------------------------------
/build/css/bootstrap-tour.css:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-tour - v0.12.0
3 | * http://bootstraptour.com
4 | * ========================================================================
5 | * Copyright 2012-2017 Ulrich Sossou
6 | *
7 | * ========================================================================
8 | * Licensed under the MIT License (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * https://opensource.org/licenses/MIT
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | .tour-backdrop {
23 | background-color: #000;
24 | filter: alpha(opacity=80);
25 | opacity: .8;
26 | position: absolute;
27 | z-index: 1100; }
28 |
29 | .popover[class*="tour-"] {
30 | z-index: 1102; }
31 | .popover[class*="tour-"] .popover-navigation {
32 | overflow: hidden;
33 | padding: 9px 14px; }
34 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] {
35 | float: right; }
36 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"],
37 | .popover[class*="tour-"] .popover-navigation *[data-role="next"],
38 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] {
39 | cursor: pointer; }
40 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled,
41 | .popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled,
42 | .popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled {
43 | cursor: default; }
44 | .popover[class*="tour-"].orphan {
45 | left: 50%;
46 | margin-top: 0;
47 | position: fixed;
48 | top: 50%;
49 | transform: translate(-50%, -50%); }
50 | .popover[class*="tour-"].orphan .arrow {
51 | display: none; }
52 |
--------------------------------------------------------------------------------
/build/css/bootstrap-tour.min.css:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-tour - v0.12.0
3 | * http://bootstraptour.com
4 | * ========================================================================
5 | * Copyright 2012-2017 Ulrich Sossou
6 | *
7 | * ========================================================================
8 | * Licensed under the MIT License (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * https://opensource.org/licenses/MIT
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | .tour-backdrop{background-color:#000;filter:alpha(opacity=80);opacity:.8;position:absolute;z-index:1100}.popover[class*="tour-"]{z-index:1102}.popover[class*="tour-"] .popover-navigation{overflow:hidden;padding:9px 14px}.popover[class*="tour-"] .popover-navigation *[data-role="end"]{float:right}.popover[class*="tour-"] .popover-navigation *[data-role="prev"],.popover[class*="tour-"] .popover-navigation *[data-role="next"],.popover[class*="tour-"] .popover-navigation *[data-role="end"]{cursor:pointer}.popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled,.popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled,.popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled{cursor:default}.popover[class*="tour-"].orphan{left:50%;margin-top:0;position:fixed;top:50%;transform:translate(-50%, -50%)}.popover[class*="tour-"].orphan .arrow{display:none}
23 |
--------------------------------------------------------------------------------
/build/js/bootstrap-tour.min.js:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-tour - v0.12.0
3 | * http://bootstraptour.com
4 | * ========================================================================
5 | * Copyright 2012-2017 Ulrich Sossou
6 | *
7 | * ========================================================================
8 | * Licensed under the MIT License (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * https://opensource.org/licenses/MIT
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | var bind=function(t,e){return function(){return t.apply(e,arguments)}};!function(t,e){"function"==typeof define&&define.amd?define(["jquery"],function(o){return t.Tour=e(o)}):"object"==typeof exports?module.exports=e(require("jquery")):t.Tour=e(t.jQuery)}(window,function(t){var e;return e=window.document,function(){function o(e){this._showPopoverAndOverlay=bind(this._showPopoverAndOverlay,this);var o;try{o=window.localStorage}catch(t){o=!1}this._options=t.extend({name:"tour",steps:[],container:"body",autoscroll:!0,keyboard:!0,storage:o,debug:!1,backdrop:!1,backdropContainer:"body",backdropPadding:0,redirect:!0,orphan:!1,duration:!1,delay:!1,basePath:"",template:'
« Prev Next » Pause
End tour ',afterSetState:function(t,e){},afterGetState:function(t,e){},afterRemoveState:function(t){},onStart:function(t){},onEnd:function(t){},onShow:function(t){},onShown:function(t){},onHide:function(t){},onHidden:function(t){},onNext:function(t){},onPrev:function(t){},onPause:function(t,e){},onResume:function(t,e){},onRedirectError:function(t){}},e),this._force=!1,this._inited=!1,this._current=null,this.backdrops=[]}return o.prototype.addSteps=function(t){var e,o,n;for(e=0,o=t.length;e",next:e===this._options.steps.length-1?-1:e+1,prev:e-1,animation:!0,container:this._options.container,autoscroll:this._options.autoscroll,backdrop:this._options.backdrop,backdropContainer:this._options.backdropContainer,backdropPadding:this._options.backdropPadding,redirect:this._options.redirect,reflexElement:this._options.steps[e].element,backdropElement:this._options.steps[e].element,orphan:this._options.orphan,duration:this._options.duration,delay:this._options.delay,template:this._options.template,onShow:this._options.onShow,onShown:this._options.onShown,onHide:this._options.onHide,onHidden:this._options.onHidden,onNext:this._options.onNext,onPrev:this._options.onPrev,onPause:this._options.onPause,onResume:this._options.onResume,onRedirectError:this._options.onRedirectError},this._options.steps[e])},o.prototype.init=function(t){return this._force=t,this.ended()?(this._debug("Tour ended, init prevented."),this):(this.setCurrentStep(),this._initMouseNavigation(),this._initKeyboardNavigation(),null!==this._current&&this.showStep(this._current),this._inited=!0,this)},o.prototype.start=function(t){var e;return null==t&&(t=!1),this._inited||this.init(t),null===this._current&&(e=this._makePromise(null!=this._options.onStart?this._options.onStart(this):void 0),this._callOnPromiseDone(e,this.showStep,0)),this},o.prototype.next=function(){var t;return t=this.hideStep(this._current,this._current+1),this._callOnPromiseDone(t,this._showNextStep)},o.prototype.prev=function(){var t;return t=this.hideStep(this._current,this._current-1),this._callOnPromiseDone(t,this._showPrevStep)},o.prototype.goTo=function(t){var e;return e=this.hideStep(this._current,t),this._callOnPromiseDone(e,this.showStep,t)},o.prototype.end=function(){var o,n;return o=function(o){return function(n){if(t(e).off("click.tour-"+o._options.name),t(e).off("keyup.tour-"+o._options.name),o._setState("end","yes"),o._inited=!1,o._force=!1,o._clearTimer(),null!=o._options.onEnd)return o._options.onEnd(o)}}(this),n=this.hideStep(this._current),this._callOnPromiseDone(n,o)},o.prototype.ended=function(){return!this._force&&!!this._getState("end")},o.prototype.restart=function(){return this._removeState("current_step"),this._removeState("end"),this._removeState("redirect_to"),this.start()},o.prototype.pause=function(){var t;return(t=this.getStep(this._current))&&t.duration?(this._paused=!0,this._duration-=(new Date).getTime()-this._start,window.clearTimeout(this._timer),this._debug("Paused/Stopped step "+(this._current+1)+" timer ("+this._duration+" remaining)."),null!=t.onPause?t.onPause(this,this._duration):void 0):this},o.prototype.resume=function(){var t;return(t=this.getStep(this._current))&&t.duration?(this._paused=!1,this._start=(new Date).getTime(),this._duration=this._duration||t.duration,this._timer=window.setTimeout(function(t){return function(){return t._isLast()?t.next():t.end()}}(this),this._duration),this._debug("Started step "+(this._current+1)+" timer with duration "+this._duration),null!=t.onResume&&this._duration!==t.duration?t.onResume(this,this._duration):void 0):this},o.prototype.hideStep=function(e,o){var n,i,r,s;if(s=this.getStep(e))return this._clearTimer(),r=this._makePromise(null!=s.onHide?s.onHide(this,e):void 0),i=function(n){return function(i){var r,a;if((r=t(s.element)).data("bs.popover")||(r=t("body")),r.popover("dispose").removeClass("tour-"+n._options.name+"-element tour-"+n._options.name+"-"+e+"-element").removeData("bs.popover"),s.reflex&&t(s.reflexElement).removeClass("tour-step-element-reflex").off(n._reflexEvent(s.reflex)+".tour-"+n._options.name),s.backdrop&&((a=null!=o&&n.getStep(o))&&a.backdrop&&a.backdropElement===s.backdropElement||n._hideOverlayElement(s)),null!=s.onHidden)return s.onHidden(n)}}(this),n=s.delay.hide||s.delay,"[object Number]"==={}.toString.call(n)&&n>0?(this._debug("Wait "+n+" milliseconds to hide the step "+(this._current+1)),window.setTimeout(function(t){return function(){return t._callOnPromiseDone(r,i)}}(this),n)):this._callOnPromiseDone(r,i),r},o.prototype.showStep=function(t){var o,n,i,r,s,a;return this.ended()?(this._debug("Tour ended, showStep prevented."),this):(a=this.getStep(t))&&(s=t0?(this._debug("Wait "+i+" milliseconds to show the step "+(this._current+1)),window.setTimeout(function(t){return function(){return t._callOnPromiseDone(n,r)}}(this),i)):this._callOnPromiseDone(n,r),n):void 0},o.prototype.getCurrentStep=function(){return this._current},o.prototype.setCurrentStep=function(t){return null!=t?(this._current=t,this._setState("current_step",t)):(this._current=this._getState("current_step"),this._current=null===this._current?null:parseInt(this._current,10)),this},o.prototype.redraw=function(){return this._showOverlayElement(this.getStep(this.getCurrentStep()))},o.prototype._setState=function(t,e){var o;if(this._options.storage){o=this._options.name+"_"+t;try{this._options.storage.setItem(o,e)}catch(t){t.code===DOMException.QUOTA_EXCEEDED_ERR&&this._debug("LocalStorage quota exceeded. State storage failed.")}return this._options.afterSetState(o,e)}return null==this._state&&(this._state={}),this._state[t]=e},o.prototype._removeState=function(t){var e;return this._options.storage?(e=this._options.name+"_"+t,this._options.storage.removeItem(e),this._options.afterRemoveState(e)):null!=this._state?delete this._state[t]:void 0},o.prototype._getState=function(t){var e,o;return this._options.storage?(e=this._options.name+"_"+t,o=this._options.storage.getItem(e)):null!=this._state&&(o=this._state[t]),void 0!==o&&"null"!==o||(o=null),this._options.afterGetState(t,o),o},o.prototype._showNextStep=function(){var t,e,o;return o=this.getStep(this._current),e=function(t){return function(e){return t.showStep(o.next)}}(this),t=this._makePromise(null!=o.onNext?o.onNext(this):void 0),this._callOnPromiseDone(t,e)},o.prototype._showPrevStep=function(){var t,e,o;return o=this.getStep(this._current),e=function(t){return function(e){return t.showStep(o.prev)}}(this),t=this._makePromise(null!=o.onPrev?o.onPrev(this):void 0),this._callOnPromiseDone(t,e)},o.prototype._debug=function(t){if(this._options.debug)return window.console.log("Bootstrap Tour '"+this._options.name+"' | "+t)},o.prototype._isRedirect=function(t,e,o){var n;return!(null==t||""===t||!("[object RegExp]"==={}.toString.call(t)&&!t.test(o.origin)||"[object String]"==={}.toString.call(t)&&this._isHostDifferent(t,o)))||(n=[o.pathname,o.search,o.hash].join(""),null!=e&&""!==e&&("[object RegExp]"==={}.toString.call(e)&&!e.test(n)||"[object String]"==={}.toString.call(e)&&this._isPathDifferent(e,n)))},o.prototype._isHostDifferent=function(t,e){switch({}.toString.call(t)){case"[object RegExp]":return!t.test(e.origin);case"[object String]":return this._getProtocol(t)!==this._getProtocol(e.href)||this._getHost(t)!==this._getHost(e.href);default:return!0}},o.prototype._isPathDifferent=function(t,e){return this._getPath(t)!==this._getPath(e)||!this._equal(this._getQuery(t),this._getQuery(e))||!this._equal(this._getHash(t),this._getHash(e))},o.prototype._isJustPathHashDifferent=function(t,e,o){var n;return(null==t||""===t||!this._isHostDifferent(t,o))&&(n=[o.pathname,o.search,o.hash].join(""),"[object String]"==={}.toString.call(e)&&(this._getPath(e)===this._getPath(n)&&this._equal(this._getQuery(e),this._getQuery(n))&&!this._equal(this._getHash(e),this._getHash(n))))},o.prototype._redirect=function(o,n,i){var r;return t.isFunction(o.redirect)?o.redirect.call(this,i):(r="[object String]"==={}.toString.call(o.host)?""+o.host+i:i,this._debug("Redirect to "+r),this._getState("redirect_to")!==""+n?(this._setState("redirect_to",""+n),e.location.href=r):(this._debug("Error redirection loop to "+i),this._removeState("redirect_to"),null!=o.onRedirectError?o.onRedirectError(this):void 0))},o.prototype._isOrphan=function(e){return null==e.element||!t(e.element).length||t(e.element).is(":hidden")&&"http://www.w3.org/2000/svg"!==t(e.element)[0].namespaceURI},o.prototype._isLast=function(){return this._current").parent().html()},o.prototype._reflexEvent=function(t){return"[object Boolean]"==={}.toString.call(t)?"click":t},o.prototype._scrollIntoView=function(e){var o,n,i,r,s,a,h,p;if(h=this.getStep(e),!(o=t(h.element)).length)return this._showPopoverAndOverlay(e);switch(n=t(window),s=o.offset().top,r=o.outerHeight(),p=n.height(),a=0,h.placement){case"top":a=Math.max(0,s-p/2);break;case"left":case"right":a=Math.max(0,s+r/2-p/2);break;case"bottom":a=Math.max(0,s+r-p/2)}return this._debug("Scroll into view. ScrollTop: "+a+". Element offset: "+s+". Window height: "+p+"."),i=0,t("body, html").stop(!0,!0).animate({scrollTop:Math.ceil(a)},function(t){return function(){if(2==++i)return t._showPopoverAndOverlay(e),t._debug("Scroll into view.\nAnimation end element offset: "+o.offset().top+".\nWindow height: "+n.height()+".")}}(this))},o.prototype._initMouseNavigation=function(){var o;return o=this,t(e).off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='prev']").off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='next']").off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='end']").off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='pause-resume']").on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='next']",function(t){return function(e){return e.preventDefault(),t.next()}}(this)).on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='prev']",function(t){return function(e){if(e.preventDefault(),t._current>0)return t.prev()}}(this)).on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='end']",function(t){return function(e){return e.preventDefault(),t.end()}}(this)).on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='pause-resume']",function(e){var n;return e.preventDefault(),(n=t(this)).text(o._paused?n.data("pause-text"):n.data("resume-text")),o._paused?o.resume():o.pause()})},o.prototype._initKeyboardNavigation=function(){if(this._options.keyboard)return t(e).on("keyup.tour-"+this._options.name,function(t){return function(e){if(e.which)switch(e.which){case 39:return e.preventDefault(),t._isLast()?t.next():t.end();case 37:if(e.preventDefault(),t._current>0)return t.prev()}}}(this))},o.prototype._makePromise=function(e){return e&&t.isFunction(e.then)?e:null},o.prototype._callOnPromiseDone=function(t,e,o){return t?t.then(function(t){return function(n){return e.call(t,o)}}(this)):e.call(this,o)},o.prototype._showBackground=function(o,n){var i,r,s,a,h,p,u,l,c;for(s=t(e).height(),c=t(e).width(),l=[],a=0,h=(u=["top","bottom","left","right"]).length;a",{class:"tour-backdrop "+p}),t(o.backdropContainer).append(i),p){case"top":l.push(i.height(n.offset.top>0?n.offset.top:0).width(c).offset({top:0,left:0}));break;case"bottom":l.push(i.offset({top:n.offset.top+n.height,left:0}).height(s-(n.offset.top+n.height)).width(c));break;case"left":l.push(i.offset({top:n.offset.top,left:0}).height(n.height).width(n.offset.left>0?n.offset.left:0));break;case"right":l.push(i.offset({top:n.offset.top,left:n.offset.left+n.width}).height(n.height).width(c-(n.offset.left+n.width)));break;default:l.push(void 0)}return l},o.prototype._showOverlayElement=function(e){var o,n;return 0===(o=t(e.backdropElement)).length?n={width:0,height:0,offset:{top:0,left:0}}:(n={width:o.innerWidth(),height:o.innerHeight(),offset:o.offset()},o.addClass("tour-step-backdrop"),e.backdropPadding&&(n=this._applyBackdropPadding(e.backdropPadding,n))),this._showBackground(e,n)},o.prototype._hideOverlayElement=function(e){var o,n,i;t(e.backdropElement).removeClass("tour-step-backdrop"),i=this.backdrops;for(n in i)(o=i[n])&&void 0!==o.remove&&o.remove();return this.backdrops=[]},o.prototype._applyBackdropPadding=function(t,e){return"object"==typeof t?(null==t.top&&(t.top=0),null==t.right&&(t.right=0),null==t.bottom&&(t.bottom=0),null==t.left&&(t.left=0),e.offset.top=e.offset.top-t.top,e.offset.left=e.offset.left-t.left,e.width=e.width+t.left+t.right,e.height=e.height+t.top+t.bottom):(e.offset.top=e.offset.top-t,e.offset.left=e.offset.left-t,e.width=e.width+2*t,e.height=e.height+2*t),e},o.prototype._clearTimer=function(){return window.clearTimeout(this._timer),this._timer=null,this._duration=null},o.prototype._getProtocol=function(t){return(t=t.split("://")).length>1?t[0]:"http"},o.prototype._getHost=function(t){return t=t.split("//"),(t=t.length>1?t[1]:t[0]).split("/")[0]},o.prototype._getPath=function(t){return t.replace(/\/?$/,"").split("?")[0].split("#")[0]},o.prototype._getQuery=function(t){return this._getParams(t,"?")},o.prototype._getHash=function(t){return this._getParams(t,"#")},o.prototype._getParams=function(t,e){var o,n,i,r,s;if(1===(r=t.split(e)).length)return{};for(s={},o=0,n=(r=r[1].split("&")).length;o - v<%= pkg.version %>
23 | * <%= pkg.homepage %>
24 | * ========================================================================
25 | * Copyright 2012-2017 <%= pkg.author.name %>
26 | *
27 | * ========================================================================
28 | * Licensed under the MIT License (the "License");
29 | * you may not use this file except in compliance with the License.
30 | * You may obtain a copy of the License at
31 | *
32 | * https://opensource.org/licenses/MIT
33 | *
34 | * Unless required by applicable law or agreed to in writing, software
35 | * distributed under the License is distributed on an "AS IS" BASIS,
36 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37 | * See the License for the specific language governing permissions and
38 | * limitations under the License.
39 | * ========================================================================
40 | */
41 |
42 | \
43 | `;
44 |
45 | // coffee
46 | gulp.task('coffee', () =>
47 | gulp
48 | .src(`${paths.src}/coffee/${name}.coffee`)
49 | .pipe($.changed(`${paths.dist}/js`))
50 | .pipe($.coffeelint('./coffeelint.json'))
51 | .pipe($.coffeelint.reporter())
52 | .on('error', $.util.log)
53 | .pipe($.coffee({bare: true}))
54 | .on('error', $.util.log)
55 | .pipe($.header(banner, {pkg}))
56 | .pipe(gulp.dest(`${paths.dist}/js`))
57 | .pipe(gulp.dest(`${paths.src}/docs/assets/js`))
58 | .pipe(gulp.dest(paths.test))
59 | .pipe($.uglify())
60 | .pipe($.header(banner, {pkg}))
61 | .pipe($.rename({suffix: '.min'}))
62 | .pipe(gulp.dest(`${paths.dist}/js`))
63 | );
64 |
65 | gulp.task('coffee-standalone', () =>
66 | streamqueue({objectMode: true},
67 | gulp
68 | .src([
69 | './node_modules/popper.js/dist/umd/popper.js',
70 | './node_modules/bootstrap/js/dist/util.js',
71 | './node_modules/bootstrap/js/dist/tooltip.js',
72 | './node_modules/bootstrap/js/dist/popover.js'
73 | ])
74 | ,
75 | gulp
76 | .src(`${paths.src}/coffee/${name}.coffee`)
77 | .pipe($.changed(`${paths.dist}/js`))
78 | .pipe($.coffeelint('./coffeelint.json'))
79 | .pipe($.coffeelint.reporter())
80 | .on('error', $.util.log)
81 | .pipe($.coffee({bare: true}))
82 | .on('error', $.util.log)).pipe($.concat(`${name}-standalone.js`))
83 | .pipe($.header(banner, {pkg}))
84 | .pipe(gulp.dest(`${paths.dist}/js`))
85 | .pipe(gulp.dest(paths.test))
86 | .pipe($.uglify())
87 | .pipe($.header(banner, {pkg}))
88 | .pipe($.rename({suffix: '.min'}))
89 | .pipe(gulp.dest(`${paths.dist}/js`))
90 | );
91 |
92 | // scss
93 | gulp.task('scss', () =>
94 | gulp
95 | .src([
96 | `${paths.src}/scss/${name}.scss`
97 | ])
98 | .pipe($.changed(`${paths.dist}/css`))
99 | .pipe($.sass().on('error', $.sass.logError))
100 | .pipe($.header(banner, {pkg}))
101 | .pipe(gulp.dest(`${paths.dist}/css`))
102 | .pipe(gulp.dest(`${paths.src}/docs/assets/css`))
103 | .pipe($.sass({outputStyle: 'compressed'}))
104 | .pipe($.header(banner, {pkg}))
105 | .pipe($.rename({suffix: '.min'}))
106 | .pipe(gulp.dest(`${paths.dist}/css`))
107 | );
108 |
109 | gulp.task('scss-standalone', () =>
110 | gulp
111 | .src(`${paths.src}/scss/${name}-standalone.scss`)
112 | .pipe($.changed(`${paths.dist}/css`))
113 | .pipe($.sass({ includePaths: ['./node_modules/bootstrap/scss/'] }).on('error', $.sass.logError))
114 | .pipe($.header(banner, {pkg}))
115 | .pipe(gulp.dest(`${paths.dist}/css`))
116 | .pipe($.sass({ outputStyle: 'compressed' })).pipe($.header(banner, {pkg}))
117 | .pipe($.rename({suffix: '.min'}))
118 | .pipe(gulp.dest(`${paths.dist}/css`))
119 | );
120 |
121 | // test
122 | gulp.task('test-coffee', ['coffee'], () =>
123 | gulp
124 | .src(`${paths.src}/coffee/${name}.spec.coffee`)
125 | .pipe($.changed(paths.test))
126 | .pipe($.coffeelint('./coffeelint.json'))
127 | .pipe($.coffeelint.reporter())
128 | .on('error', $.util.log)
129 | .pipe($.coffee())
130 | .on('error', $.util.log)
131 | .pipe(gulp.dest(paths.test))
132 | );
133 |
134 | gulp.task('test-go', ['test-coffee'], done => new KarmaServer({ configFile: __dirname + '/karma.conf.js', singleRun: true}, done).start());
135 |
136 | // docs
137 | gulp.task('docs-build', ['coffee', 'scss'], done =>
138 | spawn((process.platform === 'win32' ? 'jekyll.bat' : 'jekyll'), ['build'])
139 | .on('close', done)
140 | );
141 |
142 | gulp.task('docs-copy', ['docs-build'], () =>
143 | gulp
144 | .src([
145 | './node_modules/blueimp-md5/js/md5.min.js',
146 | './node_modules/blueimp-md5/js/md5.min.js.map',
147 | './node_modules/bootstrap/dist/css/bootstrap.min.css',
148 | './node_modules/bootstrap/dist/css/bootstrap.min.css.map',
149 | './node_modules/bootstrap/dist/js/bootstrap.min.js',
150 | './node_modules/jquery/dist/jquery.min.js',
151 | './node_modules/popper.js/dist/umd/popper.min.js',
152 | './node_modules/popper.js/dist/umd/popper.min.js.map'
153 | ])
154 | .pipe(gulp.dest(`${paths.docs}/components`))
155 | );
156 |
157 | gulp.task('docs-coffee', ['docs-build'], () =>
158 | gulp
159 | .src(`${paths.src}/coffee/${name}.docs.coffee`)
160 | .pipe($.changed(`${paths.docs}/assets/js`))
161 | .pipe($.coffeelint.reporter())
162 | .on('error', $.util.log)
163 | .pipe($.coffee())
164 | .on('error', $.util.log)
165 | .pipe(gulp.dest(`${paths.docs}/assets/js`))
166 | );
167 |
168 | // clean
169 | gulp.task('clean-dist', () =>
170 | gulp
171 | .src(paths.dist)
172 | .pipe($.clean())
173 | );
174 |
175 | gulp.task('clean-test', () =>
176 | gulp
177 | .src(paths.test)
178 | .pipe($.clean())
179 | );
180 |
181 | gulp.task('clean-docs', () =>
182 | gulp
183 | .src(paths.docs)
184 | .pipe($.clean())
185 | );
186 |
187 | // connect
188 | gulp.task('connect', ['docs'], () =>
189 | $.connect.server({
190 | root: [paths.docs],
191 | host: server.host,
192 | port: server.port,
193 | livereload: true
194 | })
195 | );
196 |
197 | // open
198 | gulp.task('open', ['connect'], () =>
199 | gulp
200 | .src(`${paths.docs}/index.html`)
201 | .pipe($.open({uri: `http://${server.host}:${server.port}`}))
202 | );
203 |
204 | gulp.task('watch', ['connect'], function() {
205 | gulp.watch(`${paths.src}/coffee/${name}.coffee`, ['coffee', 'coffee-standalone']);
206 | gulp.watch(`${paths.src}/scss/${name}.scss`, ["scss", "scss-standalone"]);
207 | gulp.watch(`${paths.src}/scss/${name}-standalone.scss`, ['scss-standalone']);
208 | gulp.watch(`${paths.src}/coffee/${name}.spec.coffee`, ['test']);
209 | gulp.watch([
210 | `${paths.src}/coffee/${name}.docs.coffee`,
211 | `${paths.src}/docs/**/*`
212 | ], ['docs']);
213 | gulp.watch([
214 | `${paths.dist}/js/**/*.js`,
215 | `${paths.dist}/css/**/*.css`,
216 | `${paths.docs}/index.html`
217 | ])
218 | .on('change', event =>
219 | gulp.src(event.path)
220 | .pipe($.connect.reload())
221 | );
222 | });
223 |
224 | // bump
225 | gulp.task('bump', ['test'], function() {
226 | const bumpType = $.util.env.type || 'patch';
227 |
228 | gulp.src(['./package.json', './smart.json'])
229 | .pipe($.bump({type: bumpType}))
230 | .pipe(gulp.dest('./'));
231 | });
232 |
233 | // tasks
234 | gulp.task('clean', ['clean-dist', 'clean-test', 'clean-docs']);
235 | gulp.task('server', ['connect', 'open', 'watch']);
236 | gulp.task('dist', ['coffee', 'coffee-standalone', 'scss', 'scss-standalone']);
237 | gulp.task('test', ['coffee', 'test-coffee', 'test-go']);
238 | gulp.task('docs', ['coffee', 'scss', 'docs-build', 'docs-copy', 'docs-coffee']);
239 | gulp.task('default', ['dist', 'docs', 'server']);
240 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | browsers: ['ChromeHeadless', 'Firefox'],
4 | files: [
5 | 'node_modules/jquery/dist/jquery.js',
6 | 'test/bootstrap-tour-standalone.js',
7 | 'test/bootstrap-tour.spec.js'
8 | ],
9 | frameworks: ['jasmine']
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/package.js:
--------------------------------------------------------------------------------
1 | Package.describe({
2 | summary: "Quick and easy way to build your product tours with Bootstrap Popovers."
3 | });
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap-tour",
3 | "description": "Quick and easy way to build your product tours with Bootstrap Popovers.",
4 | "version": "0.12.0",
5 | "keywords": [
6 | "tour",
7 | "bootstrap",
8 | "js",
9 | "tour",
10 | "intro"
11 | ],
12 | "homepage": "http://bootstraptour.com",
13 | "author": {
14 | "name": "Ulrich Sossou",
15 | "email": "sorich87@gmail.com",
16 | "url": "http://ulrichsossou.com"
17 | },
18 | "contributors": [
19 | {
20 | "name": "Emanuele Marchi",
21 | "email": "emanuele@lostcrew.it",
22 | "url": "http://lostcrew.it"
23 | },
24 | {
25 | "name": "Nicola Molinari",
26 | "email": "emmenko@gmail.com"
27 | }
28 | ],
29 | "repository": {
30 | "type": "git",
31 | "url": "https://github.com/sorich87/bootstrap-tour.git"
32 | },
33 | "bugs": {
34 | "url": "https://github.com/sorich87/bootstrap-tour/issues"
35 | },
36 | "licenses": [
37 | {
38 | "type": "MIT",
39 | "url": "https://opensource.org/licenses/MIT"
40 | }
41 | ],
42 | "dependencies": {
43 | "bootstrap": ">=4.0.0-beta",
44 | "jquery": "^3.0.0",
45 | "popper.js": "^1.12.3"
46 | },
47 | "devDependencies": {
48 | "blueimp-md5": "^2.10.0",
49 | "coffee-script": "~1.12.7",
50 | "gulp": "~3.9.0",
51 | "gulp-bump": "~2.7",
52 | "gulp-changed": "~3.1.0",
53 | "gulp-clean": "~0.3.1",
54 | "gulp-coffee": "~2.3.4",
55 | "gulp-coffeelint": "~0.6.0",
56 | "gulp-concat": "~2.6.1",
57 | "gulp-connect": "~5.0.0",
58 | "gulp-header": "~1.8.9",
59 | "gulp-jasmine": "~2.4.2",
60 | "gulp-load-plugins": "~1.5.0",
61 | "gulp-open": "~2.0.0",
62 | "gulp-rename": "~1.2.0",
63 | "gulp-sass": "^3.1.0",
64 | "gulp-uglify": "~3.0.0",
65 | "gulp-util": "~3.0.0",
66 | "karma": "~1.7.1",
67 | "karma-chrome-launcher": "^2.2.0",
68 | "karma-firefox-launcher": "^1.0.1",
69 | "karma-jasmine": "~1.1.0",
70 | "phantomjs": "^2.1.7",
71 | "streamqueue": "1.1.1"
72 | },
73 | "engines": {
74 | "node": ">= 0.8.0"
75 | },
76 | "main": "./build/js/bootstrap-tour.js",
77 | "scripts": {
78 | "build": "gulp dist",
79 | "test": "gulp test"
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/smart.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap-tour",
3 | "description": "Quick and easy way to build your product tours with Bootstrap Popovers.",
4 | "homepage": "http://bootstraptour.com",
5 | "author": "Ulrich Sossou (http://ulrichsossou.com)",
6 | "version": "0.12.0",
7 | "git": "https://github.com/sorich87/bootstrap-tour.git",
8 | "packages": {}
9 | }
10 |
--------------------------------------------------------------------------------
/src/coffee/bootstrap-tour.coffee:
--------------------------------------------------------------------------------
1 | ((window, factory) ->
2 | if typeof define is 'function' and define.amd
3 | define ['jquery'], (jQuery) -> (window.Tour = factory(jQuery))
4 | else if typeof exports is 'object'
5 | module.exports = factory(require('jquery'))
6 | else
7 | window.Tour = factory(window.jQuery)
8 | )(window, ($) ->
9 | document = window.document
10 |
11 | class Tour
12 | constructor: (options) ->
13 | try
14 | storage = window.localStorage
15 | catch
16 | # localStorage may be unavailable due to security settings
17 | storage = false
18 | @_options = $.extend
19 | name: 'tour'
20 | steps: []
21 | container: 'body'
22 | autoscroll: true
23 | keyboard: true
24 | storage: storage
25 | debug: false
26 | backdrop: false
27 | backdropContainer: 'body'
28 | backdropPadding: 0
29 | redirect: true
30 | orphan: false
31 | duration: false
32 | delay: false
33 | basePath: ''
34 | template: '
35 |
36 |
37 |
38 |
39 |
40 | « Prev
41 | Next »
42 | Pause
46 |
47 |
End tour
48 |
49 |
'
50 | afterSetState: (key, value) ->
51 | afterGetState: (key, value) ->
52 | afterRemoveState: (key) ->
53 | onStart: (tour) ->
54 | onEnd: (tour) ->
55 | onShow: (tour) ->
56 | onShown: (tour) ->
57 | onHide: (tour) ->
58 | onHidden: (tour) ->
59 | onNext: (tour) ->
60 | onPrev: (tour) ->
61 | onPause: (tour, duration) ->
62 | onResume: (tour, duration) ->
63 | onRedirectError: (tour) ->
64 | , options
65 |
66 | @_force = false
67 | @_inited = false
68 | @_current = null
69 | @backdrops = []
70 | @
71 |
72 | # Add multiple steps
73 | addSteps: (steps) ->
74 | @addStep step for step in steps
75 | @
76 |
77 | # Add a new step
78 | addStep: (step) ->
79 | @_options.steps.push step
80 | @
81 |
82 | # Get a step by its indice
83 | getStep: (i) ->
84 | if @_options.steps[i]?
85 | $.extend
86 | id: "step-#{i}"
87 | path: ''
88 | host: ''
89 | placement: 'right'
90 | title: ''
91 | content: '
' # no empty as default, otherwise popover won't show up
92 | next: if i is @_options.steps.length - 1 then -1 else i + 1
93 | prev: i - 1
94 | animation: true
95 | container: @_options.container
96 | autoscroll: @_options.autoscroll
97 | backdrop: @_options.backdrop
98 | backdropContainer: @_options.backdropContainer
99 | backdropPadding: @_options.backdropPadding
100 | redirect: @_options.redirect
101 | reflexElement: @_options.steps[i].element
102 | backdropElement: @_options.steps[i].element
103 | orphan: @_options.orphan
104 | duration: @_options.duration
105 | delay: @_options.delay
106 | template: @_options.template
107 | onShow: @_options.onShow
108 | onShown: @_options.onShown
109 | onHide: @_options.onHide
110 | onHidden: @_options.onHidden
111 | onNext: @_options.onNext
112 | onPrev: @_options.onPrev
113 | onPause: @_options.onPause
114 | onResume: @_options.onResume
115 | onRedirectError: @_options.onRedirectError
116 | , @_options.steps[i]
117 |
118 | # Setup event bindings and continue a tour that has already started
119 | init: (force) ->
120 | @_force = force
121 |
122 | if @ended()
123 | @_debug 'Tour ended, init prevented.'
124 | return @
125 |
126 | @setCurrentStep()
127 |
128 | @_initMouseNavigation()
129 | @_initKeyboardNavigation()
130 |
131 | # Continue a tour that had started on a previous page load
132 | @showStep @_current unless @_current is null
133 |
134 | @_inited = true
135 | @
136 |
137 | # Start tour from current step
138 | start: (force = false) ->
139 | @init force unless @_inited # Backward compatibility
140 |
141 | if @_current is null
142 | promise = @_makePromise(@_options.onStart(@) if @_options.onStart?)
143 | @_callOnPromiseDone(promise, @showStep, 0)
144 | @
145 |
146 | # Hide current step and show next step
147 | next: ->
148 | promise = @hideStep @_current, @_current+1
149 | @_callOnPromiseDone promise, @_showNextStep
150 |
151 | # Hide current step and show prev step
152 | prev: ->
153 | promise = @hideStep @_current, @_current-1
154 | @_callOnPromiseDone promise, @_showPrevStep
155 |
156 | goTo: (i) ->
157 | promise = @hideStep @_current, i
158 | @_callOnPromiseDone promise, @showStep, i
159 |
160 | # End tour
161 | end: ->
162 | endHelper = (e) =>
163 | $(document).off "click.tour-#{@_options.name}"
164 | $(document).off "keyup.tour-#{@_options.name}"
165 | @_setState('end', 'yes')
166 | @_inited = false
167 | @_force = false
168 |
169 | @_clearTimer()
170 |
171 | @_options.onEnd(@) if @_options.onEnd?
172 |
173 | promise = @hideStep(@_current)
174 | @_callOnPromiseDone(promise, endHelper)
175 |
176 | # Verify if tour is enabled
177 | ended: ->
178 | not @_force and not not @_getState 'end'
179 |
180 | # Restart tour
181 | restart: ->
182 | @_removeState 'current_step'
183 | @_removeState 'end'
184 | @_removeState 'redirect_to'
185 | @start()
186 |
187 | # Pause step timer
188 | pause: ->
189 | step = @getStep @_current
190 | return @ unless step and step.duration
191 |
192 | @_paused = true
193 | @_duration -= new Date().getTime() - @_start
194 | window.clearTimeout(@_timer)
195 |
196 | @_debug "Paused/Stopped step #{@_current + 1} timer (#{@_duration} remaining)."
197 |
198 | step.onPause @, @_duration if step.onPause?
199 |
200 | # Resume step timer
201 | resume: ->
202 | step = @getStep @_current
203 | return @ unless step and step.duration
204 |
205 | @_paused = false
206 | @_start = new Date().getTime()
207 | @_duration = @_duration or step.duration
208 | @_timer = window.setTimeout =>
209 | if @_isLast() then @next() else @end()
210 | , @_duration
211 |
212 | @_debug "Started step #{@_current + 1} timer with duration #{@_duration}"
213 |
214 | step.onResume @, @_duration if step.onResume? and @_duration isnt step.duration
215 |
216 | # Hide the specified step
217 | hideStep: (i, iNext) ->
218 | step = @getStep i
219 | return unless step
220 |
221 | @_clearTimer()
222 |
223 | # If onHide returns a promise, let's wait until it's done to execute
224 | promise = @_makePromise(step.onHide @, i if step.onHide?)
225 |
226 | hideStepHelper = (e) =>
227 | $element = $ step.element
228 | $element = $('body') unless $element.data('bs.popover')
229 | $element
230 | .popover('dispose')
231 | .removeClass("tour-#{@_options.name}-element tour-#{@_options.name}-#{i}-element")
232 | .removeData('bs.popover')
233 |
234 | if step.reflex
235 | $ step.reflexElement
236 | .removeClass('tour-step-element-reflex')
237 | .off "#{@_reflexEvent(step.reflex)}.tour-#{@_options.name}"
238 |
239 | if step.backdrop
240 | next_step = iNext? and @getStep iNext
241 | if !next_step or !next_step.backdrop or next_step.backdropElement != step.backdropElement
242 | @_hideOverlayElement(step)
243 |
244 | step.onHidden(@) if step.onHidden?
245 |
246 | hideDelay = step.delay.hide || step.delay
247 |
248 | if ({}).toString.call(hideDelay) is '[object Number]' and hideDelay > 0
249 | @_debug "Wait #{hideDelay} milliseconds to hide the step #{@_current + 1}"
250 | window.setTimeout =>
251 | @_callOnPromiseDone promise, hideStepHelper
252 | , hideDelay
253 | else
254 | @_callOnPromiseDone promise, hideStepHelper
255 |
256 | promise
257 |
258 | # Show the specified step
259 | showStep: (i) ->
260 | if @ended()
261 | @_debug 'Tour ended, showStep prevented.'
262 | return @
263 |
264 | step = @getStep i
265 | return unless step
266 |
267 | skipToPrevious = i < @_current
268 |
269 | # If onShow returns a promise, let's wait until it's done to execute
270 | promise = @_makePromise(step.onShow @, i if step.onShow?)
271 |
272 | @setCurrentStep i
273 |
274 | # Support string or function for path
275 | path = switch ({}).toString.call step.path
276 | when '[object Function]' then step.path()
277 | when '[object String]' then @_options.basePath + step.path
278 | else step.path
279 |
280 | # Redirect to step path if not already there
281 | if step.redirect and @_isRedirect step.host, path, document.location
282 | @_redirect step, i, path
283 |
284 | return unless @_isJustPathHashDifferent(step.host, path, document.location)
285 |
286 | showStepHelper = (e) =>
287 | # Skip if step is orphan and orphan options is false
288 | if @_isOrphan step
289 | if step.orphan is false
290 | @_debug """Skip the orphan step #{@_current + 1}.
291 | Orphan option is false and the element does not exist or is hidden."""
292 | if skipToPrevious then @_showPrevStep() else @_showNextStep()
293 | return
294 |
295 | @_debug "Show the orphan step #{@_current + 1}. Orphans option is true."
296 |
297 | # Show backdrop
298 | # @_showBackdrop(step) if step.backdrop
299 |
300 | if step.autoscroll
301 | @_scrollIntoView i
302 | else
303 | @_showPopoverAndOverlay i
304 |
305 | # Play step timer
306 | @resume() if step.duration
307 |
308 | showDelay = step.delay.show || step.delay
309 |
310 | if ({}).toString.call(showDelay) is '[object Number]' and showDelay > 0
311 | @_debug "Wait #{showDelay} milliseconds to show the step #{@_current + 1}"
312 | window.setTimeout =>
313 | @_callOnPromiseDone promise, showStepHelper
314 | , showDelay
315 | else
316 | @_callOnPromiseDone promise, showStepHelper
317 |
318 | promise
319 |
320 | getCurrentStep: ->
321 | @_current
322 |
323 | # Setup current step variable
324 | setCurrentStep: (value) ->
325 | if value?
326 | @_current = value
327 | @_setState 'current_step', value
328 | else
329 | @_current = @_getState 'current_step'
330 | @_current = if @_current is null then null else parseInt @_current, 10
331 | @
332 |
333 | # Manually trigger a redraw on the overlay element
334 | redraw: ->
335 | @_showOverlayElement(@getStep(@getCurrentStep()))
336 |
337 | # Set a state in storage
338 | _setState: (key, value) ->
339 | if @_options.storage
340 | keyName = "#{@_options.name}_#{key}"
341 | try @_options.storage.setItem keyName, value
342 | catch e
343 | if e.code is DOMException.QUOTA_EXCEEDED_ERR
344 | @_debug 'LocalStorage quota exceeded. State storage failed.'
345 | @_options.afterSetState keyName, value
346 | else
347 | @_state ?= {}
348 | @_state[key] = value
349 |
350 | # Remove the current state from the storage layer
351 | _removeState: (key) ->
352 | if @_options.storage
353 | keyName = "#{@_options.name}_#{key}"
354 | @_options.storage.removeItem keyName
355 | @_options.afterRemoveState keyName
356 | else
357 | delete @_state[key] if @_state?
358 |
359 | # Get the current state from the storage layer
360 | _getState: (key) ->
361 | if @_options.storage
362 | keyName = "#{@_options.name}_#{key}"
363 | value = @_options.storage.getItem keyName
364 | else
365 | value = @_state[key] if @_state?
366 |
367 | value = null if value is undefined or value is 'null'
368 |
369 | @_options.afterGetState key, value
370 | return value
371 |
372 | # Show next step
373 | _showNextStep: ->
374 | step = @getStep @_current
375 | showNextStepHelper = (e) => @showStep step.next
376 |
377 | promise = @_makePromise(step.onNext @ if step.onNext?)
378 | @_callOnPromiseDone promise, showNextStepHelper
379 |
380 | # Show prev step
381 | _showPrevStep: ->
382 | step = @getStep @_current
383 | showPrevStepHelper = (e) => @showStep step.prev
384 |
385 | promise = @_makePromise(step.onPrev @ if step.onPrev?)
386 | @_callOnPromiseDone promise, showPrevStepHelper
387 |
388 | # Print message in console
389 | _debug: (text) ->
390 | window.console.log "Bootstrap Tour '#{@_options.name}' | #{text}" if @_options.debug
391 |
392 | # Check if step path equals current document path
393 | _isRedirect: (host, path, location) ->
394 | return true if host? and host isnt '' and (
395 | (({}).toString.call(host) is '[object RegExp]' and not host.test(location.origin)) or
396 | (({}).toString.call(host) is '[object String]' and @_isHostDifferent(host, location))
397 | )
398 |
399 | currentPath = [
400 | location.pathname,
401 | location.search,
402 | location.hash
403 | ].join('')
404 |
405 | path? and path isnt '' and (
406 | (({}).toString.call(path) is '[object RegExp]' and not path.test(currentPath)) or
407 | (({}).toString.call(path) is '[object String]' and @_isPathDifferent(path, currentPath))
408 | )
409 |
410 | _isHostDifferent: (host, location) ->
411 | switch ({}).toString.call(host)
412 | when '[object RegExp]'
413 | not host.test(location.origin)
414 | when '[object String]'
415 | @_getProtocol(host) isnt @_getProtocol(location.href) or
416 | @_getHost(host) isnt @_getHost(location.href)
417 | else
418 | true
419 |
420 | _isPathDifferent: (path, currentPath) ->
421 | @_getPath(path) isnt @_getPath(currentPath) or not
422 | @_equal(@_getQuery(path), @_getQuery(currentPath)) or not
423 | @_equal(@_getHash(path), @_getHash(currentPath))
424 |
425 | _isJustPathHashDifferent: (host, path, location) ->
426 | if host? and host isnt ''
427 | return false if @_isHostDifferent(host, location)
428 |
429 | currentPath = [
430 | location.pathname,
431 | location.search,
432 | location.hash
433 | ].join('')
434 |
435 | if ({}).toString.call(path) is '[object String]'
436 | return @_getPath(path) is @_getPath(currentPath) and
437 | @_equal(@_getQuery(path), @_getQuery(currentPath)) and not
438 | @_equal(@_getHash(path), @_getHash(currentPath))
439 |
440 | false
441 |
442 | # Execute the redirect
443 | _redirect: (step, i, path) ->
444 | if $.isFunction step.redirect
445 | step.redirect.call this, path
446 | else
447 | href = if ({}).toString.call(step.host) is '[object String]' then "#{step.host}#{path}" else path
448 | @_debug "Redirect to #{href}"
449 |
450 | if @_getState('redirect_to') is "#{i}"
451 | @_debug "Error redirection loop to #{path}"
452 | @_removeState 'redirect_to'
453 |
454 | step.onRedirectError @ if step.onRedirectError?
455 | else
456 | @_setState 'redirect_to', "#{i}"
457 | document.location.href = href
458 |
459 | _isOrphan: (step) ->
460 | # Do not check for is(':hidden') on svg elements. jQuery does not work properly on svg.
461 | not step.element? or
462 | not $(step.element).length or
463 | $(step.element).is(':hidden') and
464 | ($(step.element)[0].namespaceURI isnt 'http://www.w3.org/2000/svg')
465 |
466 | _isLast: ->
467 | @_current < @_options.steps.length - 1
468 |
469 | _showPopoverAndOverlay: (i) =>
470 | return if @getCurrentStep() isnt i or @ended()
471 |
472 | step = @getStep i
473 |
474 | @_showOverlayElement step if step.backdrop
475 | @_showPopover step, i
476 | step.onShown @ if step.onShown?
477 | @_debug "Step #{@_current + 1} of #{@_options.steps.length}"
478 |
479 | # Show step popover
480 | _showPopover: (step, i) ->
481 | # Remove previously existing tour popovers. This prevents displaying of
482 | # multiple inactive popovers when user navigates the tour too quickly.
483 | $(".tour-#{@_options.name}").remove()
484 |
485 | options = $.extend {}, @_options
486 | isOrphan = @_isOrphan step
487 |
488 | step.template = @_template step, i
489 |
490 | if isOrphan
491 | step.element = 'body'
492 | step.placement = 'top'
493 |
494 | $element = $ step.element
495 | $element.addClass "tour-#{@_options.name}-element tour-#{@_options.name}-#{i}-element"
496 |
497 | $.extend options, step.options if step.options
498 | if step.reflex and not isOrphan
499 | $ step.reflexElement
500 | .addClass('tour-step-element-reflex')
501 | .off("#{@_reflexEvent(step.reflex)}.tour-#{@_options.name}")
502 | .on "#{@_reflexEvent(step.reflex)}.tour-#{@_options.name}", =>
503 | if @_isLast() then @next() else @end()
504 |
505 | $element
506 | .popover(
507 | placement: step.placement
508 | trigger: 'manual'
509 | title: step.title
510 | content: step.content
511 | html: true
512 | animation: step.animation
513 | container: step.container
514 | template: step.template
515 | selector: step.element
516 | )
517 | .popover 'show'
518 |
519 | # Tip adjustment
520 | $tip = $($element.data('bs.popover').getTipElement())
521 | $tip.attr 'id', step.id
522 |
523 | # Get popover template
524 | _template: (step, i) ->
525 | template = step.template
526 |
527 | if @_isOrphan(step) and ({}).toString.call(step.orphan) isnt '[object Boolean]'
528 | template = step.orphan
529 |
530 | $template = if $.isFunction template then $(template i, step) else $(template)
531 | $navigation = $template.find '.popover-navigation'
532 | $prev = $navigation.find '[data-role="prev"]'
533 | $next = $navigation.find '[data-role="next"]'
534 | $resume = $navigation.find '[data-role="pause-resume"]'
535 |
536 | $template.addClass 'orphan' if @_isOrphan step
537 | $template.addClass "tour-#{@_options.name} tour-#{@_options.name}-#{i}"
538 | $template.addClass "tour-#{@_options.name}-reflex" if step.reflex
539 |
540 | if step.prev < 0
541 | $prev.addClass('disabled')
542 | .prop('disabled', true)
543 | .prop('tabindex', -1)
544 |
545 | if step.next < 0
546 | $next.addClass('disabled')
547 | .prop('disabled', true)
548 | .prop('tabindex', -1)
549 |
550 | $resume.remove() unless step.duration
551 | $template.clone().wrap('').parent().html()
552 |
553 | _reflexEvent: (reflex) ->
554 | if ({}).toString.call(reflex) is '[object Boolean]' then 'click' else reflex
555 |
556 | # Scroll to the popup if it is not in the viewport
557 | _scrollIntoView: (i) ->
558 | step = @getStep i
559 | $element = $(step.element)
560 | return @_showPopoverAndOverlay(i) unless $element.length
561 |
562 | $window = $(window)
563 | offsetTop = $element.offset().top
564 | height = $element.outerHeight()
565 | windowHeight = $window.height()
566 | scrollTop = 0
567 |
568 | switch step.placement.replace('auto','').trim()
569 | when 'top'
570 | scrollTop = Math.max(0, offsetTop - (windowHeight / 2))
571 | when 'left', 'right'
572 | scrollTop = Math.max(0, (offsetTop + height / 2) - (windowHeight / 2))
573 | when 'bottom'
574 | scrollTop = Math.max(0, (offsetTop + height) - (windowHeight / 2))
575 |
576 | @_debug "Scroll into view. ScrollTop: #{scrollTop}. Element offset: #{offsetTop}. Window height: #{windowHeight}."
577 | counter = 0
578 | $('body, html').stop(true, true).animate
579 | scrollTop: Math.ceil(scrollTop),
580 | =>
581 | if ++counter is 2
582 | @_showPopoverAndOverlay(i)
583 | @_debug """Scroll into view.
584 | Animation end element offset: #{$element.offset().top}.
585 | Window height: #{$window.height()}."""
586 |
587 | # Event bindings for mouse navigation
588 | _initMouseNavigation: ->
589 | _this = @
590 |
591 | # Go to next step after click on element with attribute 'data-role=next'
592 | # Go to previous step after click on element with attribute 'data-role=prev'
593 | # End tour after click on element with attribute 'data-role=end'
594 | # Pause/resume tour after click on element with attribute 'data-role=pause-resume'
595 | $(document)
596 | .off("click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='prev']")
597 | .off("click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='next']")
598 | .off("click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='end']")
599 | .off("click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='pause-resume']")
600 | .on "click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='next']", (e) =>
601 | e.preventDefault()
602 | @next()
603 | .on "click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='prev']", (e) =>
604 | e.preventDefault()
605 | @prev() if @_current > 0
606 | .on "click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='end']", (e) =>
607 | e.preventDefault()
608 | @end()
609 | .on "click.tour-#{@_options.name}", ".popover.tour-#{@_options.name} *[data-role='pause-resume']", (e) ->
610 | e.preventDefault()
611 | $this = $ @
612 |
613 | $this.text if _this._paused then $this.data 'pause-text' else $this.data 'resume-text'
614 | if _this._paused then _this.resume() else _this.pause()
615 |
616 | # Keyboard navigation
617 | _initKeyboardNavigation: ->
618 | return unless @_options.keyboard
619 |
620 | $(document).on "keyup.tour-#{@_options.name}", (e) =>
621 | return unless e.which
622 |
623 | switch e.which
624 | when 39
625 | e.preventDefault()
626 | if @_isLast() then @next() else @end()
627 | when 37
628 | e.preventDefault()
629 | @prev() if @_current > 0
630 |
631 | # Checks if the result of a callback is a promise
632 | _makePromise: (result) ->
633 | if result and $.isFunction(result.then) then result else null
634 |
635 | _callOnPromiseDone: (promise, cb, arg) ->
636 | if promise
637 | promise.then (e) =>
638 | cb.call(@, arg)
639 | else
640 | cb.call(@, arg)
641 |
642 | _showBackground: (step, data) ->
643 | height = $(document).height()
644 | width = $(document).width()
645 | for pos in ['top', 'bottom', 'left', 'right']
646 | $backdrop = @backdrops[pos] ?= $('
', class: "tour-backdrop #{pos}")
647 | $(step.backdropContainer).append($backdrop)
648 |
649 | switch pos
650 | when 'top'
651 | $backdrop
652 | .height(if data.offset.top > 0 then data.offset.top else 0)
653 | .width(width)
654 | .offset(top: 0, left: 0)
655 | when 'bottom'
656 | $backdrop
657 | .offset(top: data.offset.top + data.height, left: 0)
658 | .height(height - (data.offset.top + data.height))
659 | .width(width)
660 | when 'left'
661 | $backdrop
662 | .offset(top: data.offset.top, left: 0)
663 | .height(data.height)
664 | .width(if data.offset.left > 0 then data.offset.left else 0)
665 | when 'right'
666 | $backdrop
667 | .offset(top: data.offset.top, left: data.offset.left + data.width)
668 | .height(data.height)
669 | .width(width - (data.offset.left + data.width))
670 |
671 | _showOverlayElement: (step) ->
672 | $backdropElement = $ step.backdropElement
673 |
674 | if $backdropElement.length is 0
675 | elementData =
676 | width: 0
677 | height: 0
678 | offset:
679 | top: 0
680 | left: 0
681 | else
682 | elementData =
683 | width: $backdropElement.innerWidth()
684 | height: $backdropElement.innerHeight()
685 | offset: $backdropElement.offset()
686 |
687 | $backdropElement.addClass 'tour-step-backdrop'
688 | elementData = @_applyBackdropPadding step.backdropPadding, elementData if step.backdropPadding
689 |
690 | @_showBackground(step, elementData)
691 |
692 | _hideOverlayElement: (step) ->
693 | $(step.backdropElement).removeClass 'tour-step-backdrop'
694 |
695 | for pos, $backdrop of @backdrops
696 | $backdrop.remove() if $backdrop and $backdrop.remove isnt undefined
697 |
698 | @backdrops = []
699 |
700 | _applyBackdropPadding: (padding, data) ->
701 | if typeof padding is 'object'
702 | padding.top ?= 0
703 | padding.right ?= 0
704 | padding.bottom ?= 0
705 | padding.left ?= 0
706 |
707 | data.offset.top = data.offset.top - padding.top
708 | data.offset.left = data.offset.left - padding.left
709 | data.width = data.width + padding.left + padding.right
710 | data.height = data.height + padding.top + padding.bottom
711 | else
712 | data.offset.top = data.offset.top - padding
713 | data.offset.left = data.offset.left - padding
714 | data.width = data.width + (padding * 2)
715 | data.height = data.height + (padding * 2)
716 |
717 | data
718 |
719 | _clearTimer: ->
720 | window.clearTimeout @_timer
721 | @_timer = null
722 | @_duration = null
723 |
724 | _getProtocol: (url) ->
725 | url = url.split('://')
726 | return if url.length > 1 then url[0] else 'http'
727 |
728 | _getHost: (url) ->
729 | url = url.split('//')
730 | url = if url.length > 1 then url[1] else url[0]
731 |
732 | return url.split('/')[0]
733 |
734 | _getPath: (path) ->
735 | return path.replace(/\/?$/, '').split('?')[0].split('#')[0]
736 |
737 | _getQuery: (path) ->
738 | return @_getParams(path, '?')
739 |
740 | _getHash: (path) ->
741 | return @_getParams(path, '#')
742 |
743 | _getParams: (path, start) ->
744 | params = path.split(start)
745 | return {} if params.length is 1
746 |
747 | params = params[1].split('&')
748 | paramsObject = {}
749 |
750 | for param in params
751 | param = param.split('=')
752 | paramsObject[param[0]] = param[1] or ''
753 |
754 | return paramsObject
755 |
756 | _equal: (obj1, obj2) ->
757 | if ({}).toString.call(obj1) is '[object Object]' and ({}).toString.call(obj2) is '[object Object]'
758 | obj1Keys = Object.keys(obj1)
759 | obj2Keys = Object.keys(obj2)
760 | return false if obj1Keys.length isnt obj2Keys.length
761 |
762 | for k,v of obj1
763 | return false if not @_equal(obj2[k], v)
764 |
765 | return true
766 | else if ({}).toString.call(obj1) is '[object Array]' and ({}).toString.call(obj2) is '[object Array]'
767 | return false if obj1.length isnt obj2.length
768 |
769 | for v,k in obj1
770 | return false if not @_equal(v, obj2[k])
771 |
772 | return true
773 | else
774 | return obj1 is obj2
775 |
776 | Tour
777 | )
778 |
--------------------------------------------------------------------------------
/src/coffee/bootstrap-tour.docs.coffee:
--------------------------------------------------------------------------------
1 | $ ->
2 | $demo = $("#demo")
3 | duration = 5000
4 | remaining = duration
5 | tour = new Tour(
6 | onStart: -> $demo.addClass "disabled", true
7 | onEnd: -> $demo.removeClass "disabled", true
8 | debug: true
9 | steps: [
10 | path: "/"
11 | element: "#navbar"
12 | placement: "bottom"
13 | title: "Welcome to Bootstrap Tour!"
14 | content: """
15 | Introduce new users to your product by walking them through it step by step.
16 | """
17 | ,
18 | path: "/"
19 | element: "#usage"
20 | placement: "top"
21 | title: "A super simple setup"
22 | content: "Easy is better, right? The tour is up and running with just a
23 | few options and steps."
24 | ,
25 | path: "/"
26 | element: "#license"
27 | placement: "top"
28 | title: "Best of all, it's free!"
29 | content: "Yeah! Free as in beer... or speech. Use and abuse, but don't forget to contribute!"
30 | ,
31 | path: "/api"
32 | element: "#options .page-header"
33 | placement: "top"
34 | title: "Flexibilty and expressiveness"
35 | content: """
36 | There are more options for those who want to get on the dark side.
37 | Power to the people!
38 | """
39 | reflex: true
40 | ,
41 | path: "/api"
42 | element: "#duration"
43 | placement: "top"
44 | title: "Automagically expiring step",
45 | content: """
46 | A new addition: make your tour (or step) completely automatic. You set the duration, Bootstrap
47 | Tour does the rest. For instance, this step will disappear in
5 seconds.
48 | """
49 | duration: 5000
50 | ,
51 | path: "/api"
52 | element: "#methods table"
53 | placement: "top"
54 | title: "A new shiny Backdrop option"
55 | content: """
56 | If you need to highlight the current step's element, activate the backdrop and you won't lose
57 | focus anymore!
58 | """
59 | backdrop: true
60 | backdropPadding: 5
61 | ,
62 | path: "/api"
63 | element: "#reflex"
64 | placement: "bottom"
65 | title: "Reflex mode"
66 | content: "Reflex mode is enabled, click on the text in the cell to continue!"
67 | reflex: true
68 | ,
69 | path: "/api"
70 | title: "And support for orphan steps"
71 | content: """
72 | If you activate the orphan property, the step(s) are shown centered in the page, and you can
73 | forget to specify element and placement!
74 | """
75 | orphan: true
76 | onHidden: -> window.location.assign "/"
77 | ]
78 | )
79 | .init()
80 |
81 | $('
').prependTo(".content").alert() if tour.ended()
82 |
83 | $(document).on "click", "[data-demo]", (e) ->
84 | e.preventDefault()
85 | return if $(this).hasClass "disabled"
86 | tour.restart()
87 | $(".alert").alert "close"
88 |
89 | $(".gravatar").each ->
90 | $this = $(@)
91 | email = md5 $this.data "email"
92 |
93 | $(@).attr "src", "http://www.gravatar.com/avatar/#{email}?s=60"
94 |
--------------------------------------------------------------------------------
/src/docs/CNAME:
--------------------------------------------------------------------------------
1 | bootstraptour.com
2 |
--------------------------------------------------------------------------------
/src/docs/_includes/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/src/docs/_includes/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {% if page.title == "Bootstrap Tour" %}
7 | {{ page.title }}
8 | {% else %}
9 | {{ page.title }} · Bootstrap Tour
10 | {% endif %}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
30 |
--------------------------------------------------------------------------------
/src/docs/_includes/nav.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
21 |
22 |
--------------------------------------------------------------------------------
/src/docs/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% include header.html %}
5 |
6 |
7 |
8 | {% include nav.html %}
9 | {{ content }}
10 | {% include footer.html %}
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/docs/api.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: API Documentation
4 | slug: api
5 | ---
6 |
7 |
8 |
9 |
12 |
Global options
13 | {% highlight javascript %}
14 | var tour = new Tour({
15 | name: "tour",
16 | steps: [],
17 | container: "body",
18 | keyboard: true,
19 | storage: window.localStorage,
20 | debug: false,
21 | backdrop: false,
22 | backdropContainer: 'body',
23 | backdropPadding: 0,
24 | redirect: true,
25 | orphan: false,
26 | duration: false,
27 | delay: false,
28 | basePath: "",
29 | template: "
30 |
31 |
32 |
33 |
34 | « Prev
35 | |
36 | Next »
37 |
38 |
End tour
39 |
",
40 | afterGetState: function (key, value) {},
41 | afterSetState: function (key, value) {},
42 | afterRemoveState: function (key, value) {},
43 | onStart: function (tour) {},
44 | onEnd: function (tour) {},
45 | onShow: function (tour) {},
46 | onShown: function (tour) {},
47 | onHide: function (tour) {},
48 | onHidden: function (tour) {},
49 | onNext: function (tour) {},
50 | onPrev: function (tour) {},
51 | onPause: function (tour, duration) {},
52 | onResume: function (tour, duration) {},
53 | onRedirectError: function (tour) {}
54 | });
55 | {% endhighlight %}
56 |
57 |
58 |
59 | Name
60 | Type
61 | Description
62 | Default
63 |
64 |
65 |
66 |
67 | name
68 | String
69 | This option is used to build the name of the storage item where the tour state is stored.
70 | The name should contain only alphanumerics, underscores and hyphens.
71 | You can initialize several tours with different names in the same page and application.
72 | 'tour'
73 |
74 |
75 | steps
76 | Array
77 | A list of object representing the steps to be included in the tour. Jump to
78 | Step options for the single step API.
79 | []
80 |
81 |
82 | container
83 | String
84 | Appends the step popover to a specific element.
85 | See Usage section of
86 | Popover .
87 |
88 |
89 | 'body'
90 |
91 |
92 | autoscroll
93 | Boolean
94 | Autoscrolls the window when the step popover is out of view.
95 | true
96 |
97 |
98 | keyboard
99 | Boolean
100 | This option set the left and right arrow navigation.
101 | true
102 |
103 |
104 | storage
105 | Object
106 | The storage system you want to use. Could be the objects window.localStorage,
107 | window.sessionStorage or your own object.
108 | You can set this option as
109 | false
to disable storage
110 | persistence (the tour starts from beginning every time the page is
111 | loaded).
112 | Read more about DOM Storage interfaces .
113 |
114 | window.localStorage
115 |
116 |
117 | debug
118 | Boolean
119 | Set this option to true to have some useful informations printed in the
120 | console.
121 | false
122 |
123 |
124 | backdrop
125 | Boolean
126 | Show a dark backdrop behind the popover and its element,
127 | highlighting the current step.
128 | false
129 |
130 |
131 | backdropContainer NEW
132 | String (jQuery selector)
133 | HTML element on which the backdrop should be shown.
134 | 'body'
135 |
136 |
137 | backdropPadding NEW
138 | Number|Object
139 | Add padding to the backdrop element that highlights the step element.
140 | It can be a number or a object containing optional top
, right
, bottom
and left
numbers.
141 | 0
142 |
143 |
144 | redirect
145 | Boolean|Function
146 | Set a custom function to execute as redirect function.
147 | The default redirect relies on the traditional
148 | document.location.href
149 | true
150 |
151 |
152 | orphan
153 | Boolean|String|function
154 | Allow to show the step regardless whether its element is not set, is
155 | not present in the page or is hidden. The step is fixed
156 | positioned in the middle of the page.
157 | false
158 |
159 |
160 | duration NEW
161 | Boolean|Number
162 | Set a expiration time for the steps. When the current step expires,
163 | the next step is automatically shown. See it as a sort of guided, automatized tour
164 | functionality. The value is specified in milliseconds
165 | false
166 |
167 |
168 | delay NEW
169 | Boolean|Number
170 | Specifies a delay for the showing and hiding the tour steps.
171 | It can be:
172 |
173 | a falsy - there is no delay
174 | a number - used as a delay for both showing and hiding. In milliseconds
175 | a object containing optional show
and hide
numbers - defines the delays for showing and hiding respectively
176 |
177 | 0
178 |
179 |
180 | basePath
181 | String
182 | Specify a default base path prepended to the
183 | path
option of every single
184 | step. Very useful if you need to reuse the same tour on different
185 | environments or sub-projects.
186 | ''
187 |
188 |
189 | template
190 | String|Function
191 | String or function that returns a string of the HTML template for
192 | the popovers. If you pass a Function, two parameters are available:
193 | i is the position of step in the tour and
194 | step is the an object that contains all the other step
195 | options.
196 | From version 0.5, the navigation template is included inside the
197 | template so you can easily rewrite it. However, Bootstrap Tour maps the
198 | previous , next and end logics to the elements
199 | which have the related data-role
200 | attribute. Therefore, you can also have multiple elements with the same
201 | data-role
attribute.
202 |
203 |
204 | {% highlight javascript %}
205 | "
206 |
207 |
208 |
209 |
210 | « Prev
211 | |
212 | Next »
213 | End tour
214 |
215 |
"
216 | {% endhighlight %}
217 |
218 |
219 |
220 | afterGetState, afterSetState, afterRemoveState
221 | Function
222 | You may want to do something right after Bootstrap Tour read, write or remove
223 | the state. Just pass functions to these.
224 | Your functions can have two parameters:
225 |
226 |
227 | key
228 | Contains the name of the state being saved. It can be
229 | current_step
(for the state where the
230 | latest step the visitor viewed is saved) or
231 | end
(for the state which is saved when
232 | the user complete the tour). Note that Bootstrap Tour prepends the key with
233 | tour_
when saving the state.
234 |
235 |
236 | value
237 | The value of the state been saved. Can be the index of the
238 | current step if the key is current_step
, or
239 | yes
if the key is end
.
240 |
241 |
242 | A simple example if to send a post request to your server each
243 | time there is a change:
244 | {% highlight javascript %}
245 | var tour = new Tour({
246 | afterSetState: function (key, value) {
247 | $.post("/some/path", value);
248 | }
249 | });
250 | {% endhighlight %}
251 |
252 | function (key, value) { }
253 |
254 |
255 | onStart
256 | Function
257 | Function to execute when the tour starts.
258 | function (tour) { }
259 |
260 |
261 | onEnd
262 | Function
263 | Function to execute when the tour ends.
264 | function (tour) { }
265 |
266 |
267 | onShow
268 | Function
269 | Function to execute right before each step is shown.
270 | function (tour) { }
271 |
272 |
273 | onShown
274 | Function
275 | Function to execute right after each step is shown.
276 | function (tour) { }
277 |
278 |
279 | onHide
280 | Function
281 | Function to execute right before each step is hidden.
282 | function (tour) { }
283 |
284 |
285 | onHidden
286 | Function
287 | Function to execute right after each step is hidden.
288 | function (tour) { }
289 |
290 |
291 | onNext
292 | Function
293 | Function to execute when next step is called.
294 | function (tour) { }
295 |
296 |
297 | onPrev
298 | Function
299 | Function to execute when prev step is called.
300 | function (tour) { }
301 |
302 |
303 | onPause NEW
304 | Function
305 | Function to execute when pause is called. The second argument refers to the
306 | remaining duration.
307 | function (tour, duration) { }
308 |
309 |
310 | onResume NEW
311 | Function
312 | Function to execute when resume is called. The second argument refers to the
313 | remaining duration.
314 | function (tour, duration) { }
315 |
316 |
317 |
318 | onRedirectError NEW
319 | Function
320 | Function to execute when there is a redirection error. This
321 | happens when bootstrap tour cannot redirect to the path of the step
322 | function (tour) { }
323 |
324 |
325 |
326 |
327 |
Step Options
328 | {% highlight javascript %}
329 | tour.addStep({
330 | path: "",
331 | host: "",
332 | element: "",
333 | placement: "right",
334 | title: "",
335 | content: "",
336 | next: 0,
337 | prev: 0,
338 | animation: true,
339 | container: "body",
340 | backdrop: false,
341 | backdropContainer: 'body',
342 | backdropPadding: false,
343 | redirect: true,
344 | reflex: false,
345 | orphan: false,
346 | template: "",
347 | onShow: function (tour) {},
348 | onShown: function (tour) {},
349 | onHide: function (tour) {},
350 | onHidden: function (tour) {},
351 | onNext: function (tour) {},
352 | onPrev: function (tour) {},
353 | onPause: function (tour) {},
354 | onResume: function (tour) {},
355 | onRedirectError: function (tour) {}
356 | });
357 | {% endhighlight %}
358 |
359 |
360 |
361 | Name
362 | Type
363 | Description
364 | Default
365 |
366 |
367 |
368 |
369 | path
370 | String or RegExp
371 | Path to the page on which the step should be shown. This
372 | allows you to build tours that span several pages!
373 | ''
374 |
375 |
376 |
377 | host NEW
378 | String or RegExp
379 | Host of the page on which the step should be shown. This
380 | allows you to build tours for several sub-domains
381 | ''
382 |
383 |
384 | element
385 | String (jQuery selector)
386 | HTML element on which the step popover should be shown.
387 | If orphan is false, this option is required.
388 | ''
389 |
390 |
391 | placement
392 | String|Function
393 | How to position the popover. Possible choices:
394 | 'top'
,
395 | 'bottom'
,
396 | 'left'
,
397 | 'right'
,
398 | 'auto'
.
399 | When "auto" is specified, it will dynamically reorient the popover.
400 | For example, if placement is "auto left", the popover will display to
401 | the left when possible, otherwise it will display right.
402 |
403 | 'right'
404 |
405 |
406 | title
407 | String|Function
408 | Step title
409 | ''
410 |
411 |
412 | content
413 | String|Function
414 | Step content
415 | ''
416 |
417 |
418 | next
419 | Integer
420 | Index of the step to show after this one, starting from
421 | 0
for the first step of the
422 | tour. -1
to not show the link
423 | to next step. By default, the next step (in the order you added
424 | them) will be shown.
425 | This option should be used in conjunction with
426 | prev
.
427 | 0
428 |
429 |
430 | prev
431 | Integer
432 | Index of the step to show before this one, starting from
433 | 0
for the first step of the
434 | tour. -1
to not show the link
435 | to previous step. By default, the previous step (in the order you added
436 | them) will be shown.
437 | This option should be used in conjunction with
438 | next
.
439 | 0
440 |
441 |
442 | animation
443 | Boolean
444 | Apply a css fade transition to the tooltip.
445 | true
446 |
447 |
448 | container
449 | String (jQuery selector)
450 | Attachment of popover. Pass an element to append the popover
451 | to. By default the popover is appended after the 'element' above.
452 | This option is particularly helpful for Internet Explorer.
453 | 'body'
454 |
455 |
456 | backdrop
457 | Boolean
458 | Show a dark backdrop behind the popover and its element,
459 | highlighting the current step.
460 | false
461 |
462 |
463 | backdropContainer NEW
464 | String (jQuery selector)
465 | HTML element on which the backdrop should be shown.
466 | 'body'
467 |
468 |
469 | backdropPadding NEW
470 | Boolean|Object
471 | Add padding to the backdrop element that highlights the step element.
472 | It can be a number or a object containing optional top
, right
, bottom
and left
numbers.
473 | 0
474 |
475 |
476 | redirect
477 | Boolean|Function
478 | Set a custom function to execute as redirect function.
479 | The default redirect relies on the traditional
480 | document.location.href
481 | true
482 |
483 |
484 | reflex UPDATED
485 | Boolean|String
486 | Enable the reflex mode: attach an handler on click
on the step element to continue the tour.
487 | In order to bind the handler to a custom event, you can pass a string with its name.
488 | Also, the class tour-step-element-reflex
is added to the element, as hook for your custom style (e.g: cursor: pointer).
489 | false
490 |
491 |
492 | orphan
493 | Boolean|String|Function
494 | Allow to show the step regardless whether its element is not set, is
495 | not present in the page or is hidden. The step is fixed
496 | positioned in the middle of the page.
497 | You can use a string or function that returns a string of the HTML template for
498 | the orphan popovers
499 | false
500 |
501 |
502 | duration NEW
503 | Boolean|String
504 | Set a expiration time for the steps. When the step expires,
505 | the next step is automatically shown. See it as a sort of guided, automatized tour
506 | functionality. The value is specified in milliseconds
507 | false
508 |
509 |
510 | template
511 | String|Function
512 | String or function that returns a string of the HTML template for
513 | the popovers. If you pass a Function, two parameters are available:
514 | i is the position of step in the tour and
515 | step is the object that contains all the other step
516 | options.
517 | From version 0.5, the navigation template is included inside the
518 | template so you can easily rewrite it. However, Bootstrap Tour maps the
519 | previous , next and end logics to the elements
520 | which have the related data-role
521 | attribute. Therefore, you can also have multiple elements with the same
522 | data-role
attribute.
523 |
524 |
525 | {% highlight javascript %}
526 | "
527 |
528 |
529 |
530 |
531 | « Prev
532 | |
533 | Next »
534 | End tour
535 |
536 |
"
537 | {% endhighlight %}
538 |
539 |
540 |
541 | onShow
542 | Function
543 | Function to execute right before the step is shown. It overrides the
544 | global onShow
option.
545 | function (tour) { }
546 |
547 |
548 | onShown
549 | Function
550 | Function to execute right after the step is shown. It overrides the
551 | global onShown
option.
552 | function (tour) { }
553 |
554 |
555 | onHide
556 | Function
557 | Function to execute right before the step is hidden. It overrides
558 | the global onHide
option.
559 | function (tour) { }
560 |
561 |
562 | onHidden
563 | Function
564 | Function to execute right after the step is hidden. It overrides the
565 | global onHidden
option.
566 | function (tour) { }
567 |
568 |
569 | onNext
570 | Function
571 | Function to execute when next step is called. It overrides the
572 | global onNext
option.
573 | function (tour) { }
574 |
575 |
576 | onPrev
577 | Function
578 | Function to execute when prev step is called. It overrides the global
579 | onPrev
option.
580 | function (tour) { }
581 |
582 |
583 | onPause NEW
584 | Function
585 | Function to execute when pause is called. The second argument refers to the
586 | remaining duration. It overrides the global the
587 | onPause
option
588 | function (tour, duration) { }
589 |
590 |
591 | onResume NEW
592 | Function
593 | Function to execute when resume is called. The second argument refers to the
594 | remaining duration. It overrides the global
595 | onResume
option
596 | function (tour, duration) { }
597 |
598 |
599 | onRedirectError NEW
600 | Function
601 | Function to execute when there is a redirection error. This
602 | happens when bootstrap tour cannot redirect to the path of the step. It overrides the global
603 | onRedirectError
option
604 | function (tour) { }
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
616 |
619 |
620 |
621 |
622 | Name
623 | Description
624 |
625 |
626 |
627 |
628 | addSteps([]
)
629 | Add multiple steps to the tour. Pass an array of objects.
630 |
631 |
632 | addStep({}
)
633 | Add single step to the tour. Pass an object.
634 |
635 |
636 | init()
637 | Initialize the tour. You must do it before calling start.
638 |
639 |
640 | start(true
)
641 | Start the tour. Pass true
to force the start.
642 |
643 |
644 | restart()
645 | Restart the tour after it ended.
646 |
647 |
648 | end()
649 | End the tour prematurely.
650 |
651 |
652 | next()
653 | Skip to the next step.
654 |
655 |
656 | prev()
657 | Go back to the previous step.
658 |
659 |
660 | goTo(i
)
661 | UPDATED
662 | Skip to a specific step. Pass i
as the
663 | index of the step in the tour (0-based).
664 | From version 0.7.0, the method has been renamed since some Javascript compilers
665 | are confused by the property name goto , which is a reserved word)
666 | .
667 |
668 |
669 |
670 | pause()
671 | Pause the duration timer. It works only if tour or current step has duration.
672 |
673 |
674 | resume()
675 | Resume the duration timer. It works only if tour or current step has duration.
676 |
677 |
678 | ended()
679 | Verify if the tour ended. Returns boolean.
680 |
681 |
682 | getStep(i
)
683 | Get the step object. Pass i
as the index
684 | of the step in the tour (0-based).
685 |
686 |
687 | getCurrentStep()
688 | Get the index of the current step.
689 |
690 |
691 | setCurrentStep(i
)
692 | Override the current step. Pass i
693 | as the index of the step in the tour (0-based).
694 |
695 |
696 | redraw()
697 | Triggers a redraw on the overlay element. Useful for
698 | Dynamically sized tour targets.
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
712 |
Bootstrap Tour can be used to create tours that span multiple pages. If you have URLs for each page that have
713 | unique paths, and the dependencies are loaded on each page, you can easily create a tour like so:
714 |
715 | {% highlight javascript %}
716 | var tour = new Tour({
717 | steps: [
718 | {
719 | element: "#my-element",
720 | title: "Title of my step",
721 | content: "Content of my step"
722 | },
723 | {
724 | element: "#my-other-element",
725 | title: "Title of my step",
726 | content: "Content of my step",
727 | path: "/url/to/go/to/"
728 | }
729 | ]
730 | });
731 | {% endhighlight %}
732 |
733 |
It's that simple.
734 |
735 |
If you do not know the URL you wish to go to because it contains a different value per user or per
736 | instance, you can use a regular expression as the path
attribute and set the redirect
737 | attribute to a function that performs the redirect.
738 |
739 |
For example:
740 |
741 | {% highlight javascript %}
742 | var tour = new Tour({
743 | steps: [
744 | {
745 | element: "#my-element",
746 | title: "Title of my step",
747 | content: "Content of my step",
748 | redirect: function(){
749 | document.location.href = '/url/' + userId;
750 | };
751 | },
752 | {
753 | element: "#my-other-element",
754 | title: "Title of my step",
755 | content: "Content of my step",
756 | path: RegExp("\/url\/[^/]+", "i")
757 | }
758 | ]
759 | });
760 | {% endhighlight %}
761 |
762 |
Finally, if you are only using GET parameters to define different pages, and wish to redirect using those
763 | parameters, you may run into the problem that Bootstrap Tour will consider the path of the two steps to be
764 | identical. For example, you cannot use the path parameter to go from your homepage at /
to a
765 | search results page at /?q=foo
, because from Bootstrap Tour's perspective, those are the same
766 | location (/
).
767 |
768 |
To work around this limitation, you can set the onNext
attribute a function that returns a
769 | promise.
770 |
For example:
771 |
772 | {% highlight javascript %}
773 | var tour = new Tour({
774 | steps: [
775 | {
776 | element: "#my-element",
777 | title: "Title of my step",
778 | content: "Content of my step",
779 | onNext: function(){
780 | document.location.href = '/?q=foo';
781 | return (new jQuery.Deferred()).promise();
782 | };
783 | },
784 | {
785 | element: "#my-other-element",
786 | title: "Title of my step",
787 | content: "Content of my step",
788 | }
789 | ]
790 | });
791 | {% endhighlight %}
792 |
793 |
Doing this will prevent the next step from popping up while the redirect is being completed in the
794 | onNext
function.
795 |
796 |
797 |
798 |
--------------------------------------------------------------------------------
/src/docs/assets/css/bootstrap-tour.css:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-tour - v0.12.0
3 | * http://bootstraptour.com
4 | * ========================================================================
5 | * Copyright 2012-2017 Ulrich Sossou
6 | *
7 | * ========================================================================
8 | * Licensed under the MIT License (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * https://opensource.org/licenses/MIT
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | .tour-backdrop {
23 | background-color: #000;
24 | filter: alpha(opacity=80);
25 | opacity: .8;
26 | position: absolute;
27 | z-index: 1100; }
28 |
29 | .popover[class*="tour-"] {
30 | z-index: 1102; }
31 | .popover[class*="tour-"] .popover-navigation {
32 | overflow: hidden;
33 | padding: 9px 14px; }
34 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] {
35 | float: right; }
36 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"],
37 | .popover[class*="tour-"] .popover-navigation *[data-role="next"],
38 | .popover[class*="tour-"] .popover-navigation *[data-role="end"] {
39 | cursor: pointer; }
40 | .popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled,
41 | .popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled,
42 | .popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled {
43 | cursor: default; }
44 | .popover[class*="tour-"].orphan {
45 | left: 50%;
46 | margin-top: 0;
47 | position: fixed;
48 | top: 50%;
49 | transform: translate(-50%, -50%); }
50 | .popover[class*="tour-"].orphan .arrow {
51 | display: none; }
52 |
--------------------------------------------------------------------------------
/src/docs/assets/css/bootstrap-tour.docs.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-bottom: 50px;
3 | }
4 |
5 | #github {
6 | display: block;
7 | position: absolute;
8 | width: 150px;
9 | height: 150px;
10 | right: 0;
11 | z-index: 1050;
12 | }
13 |
14 | .masthead {
15 | position: relative;
16 | padding: 30px 15px;
17 | color: #fff;
18 | text-align: center;
19 | text-shadow: 0 1px 0 rgba(0,0,0,.1);
20 | background-color: #3276b1;
21 | background-image: -webkit-linear-gradient(top, #285e8e 0%, #3276b1 100%);
22 | background-image: linear-gradient(to bottom, #285e8e 0%, #3276b1 100%);
23 | background-repeat: repeat-x;
24 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#285e8e', endColorstr='#3276b1', GradientType=0);
25 | }
26 | .masthead small {
27 | font-size: 80%;
28 | color: #ccc;
29 | }
30 |
31 | #demo {
32 | cursor: pointer;
33 | }
34 |
35 | .page-header {
36 | margin-top: 3rem;
37 | margin-bottom: 1rem;
38 | }
39 |
40 | /*
41 | * Social buttons
42 | *
43 | * Twitter and GitHub social action buttons (for homepage and footer).
44 | */
45 |
46 | .social {
47 | display: inline-block;
48 | margin-top: 40px;
49 | margin-bottom: 0;
50 | padding-left: 0;
51 | list-style: none;
52 | }
53 | .social li {
54 | display: inline-block;
55 | line-height: 1;
56 | padding: 5px 8px;
57 | }
58 | .social .tweet-btn a {
59 | width: 98px !important;
60 | }
61 | /* Style the GitHub buttons via CSS instead of inline attributes */
62 | .github-btn {
63 | border: 0;
64 | overflow: hidden;
65 | }
66 |
--------------------------------------------------------------------------------
/src/docs/assets/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorich87/bootstrap-tour/c501ce7ad1728050b0882bb9316f5c33df87f6a2/src/docs/assets/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/src/docs/assets/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorich87/bootstrap-tour/c501ce7ad1728050b0882bb9316f5c33df87f6a2/src/docs/assets/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/src/docs/assets/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorich87/bootstrap-tour/c501ce7ad1728050b0882bb9316f5c33df87f6a2/src/docs/assets/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/src/docs/assets/img/apple-touch-icon-144-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorich87/bootstrap-tour/c501ce7ad1728050b0882bb9316f5c33df87f6a2/src/docs/assets/img/apple-touch-icon-144-precomposed.png
--------------------------------------------------------------------------------
/src/docs/assets/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorich87/bootstrap-tour/c501ce7ad1728050b0882bb9316f5c33df87f6a2/src/docs/assets/img/favicon.png
--------------------------------------------------------------------------------
/src/docs/assets/img/masthead-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorich87/bootstrap-tour/c501ce7ad1728050b0882bb9316f5c33df87f6a2/src/docs/assets/img/masthead-pattern.png
--------------------------------------------------------------------------------
/src/docs/assets/vendor/pygments-manni.css:
--------------------------------------------------------------------------------
1 | .hll { background-color: #ffffcc }
2 | /*{ background: #f0f3f3; }*/
3 | .c { color: #999; } /* Comment */
4 | .err { color: #AA0000; background-color: #FFAAAA } /* Error */
5 | .k { color: #006699; } /* Keyword */
6 | .o { color: #555555 } /* Operator */
7 | .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
8 | .cp { color: #009999 } /* Comment.Preproc */
9 | .c1 { color: #999; } /* Comment.Single */
10 | .cs { color: #999; } /* Comment.Special */
11 | .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
12 | .ge { font-style: italic } /* Generic.Emph */
13 | .gr { color: #FF0000 } /* Generic.Error */
14 | .gh { color: #003300; } /* Generic.Heading */
15 | .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
16 | .go { color: #AAAAAA } /* Generic.Output */
17 | .gp { color: #000099; } /* Generic.Prompt */
18 | .gs { } /* Generic.Strong */
19 | .gu { color: #003300; } /* Generic.Subheading */
20 | .gt { color: #99CC66 } /* Generic.Traceback */
21 | .kc { color: #006699; } /* Keyword.Constant */
22 | .kd { color: #006699; } /* Keyword.Declaration */
23 | .kn { color: #006699; } /* Keyword.Namespace */
24 | .kp { color: #006699 } /* Keyword.Pseudo */
25 | .kr { color: #006699; } /* Keyword.Reserved */
26 | .kt { color: #007788; } /* Keyword.Type */
27 | .m { color: #FF6600 } /* Literal.Number */
28 | .s { color: #d44950 } /* Literal.String */
29 | .na { color: #4f9fcf } /* Name.Attribute */
30 | .nb { color: #336666 } /* Name.Builtin */
31 | .nc { color: #00AA88; } /* Name.Class */
32 | .no { color: #336600 } /* Name.Constant */
33 | .nd { color: #9999FF } /* Name.Decorator */
34 | .ni { color: #999999; } /* Name.Entity */
35 | .ne { color: #CC0000; } /* Name.Exception */
36 | .nf { color: #CC00FF } /* Name.Function */
37 | .nl { color: #9999FF } /* Name.Label */
38 | .nn { color: #00CCFF; } /* Name.Namespace */
39 | .nt { color: #2f6f9f; } /* Name.Tag */
40 | .nv { color: #003333 } /* Name.Variable */
41 | .ow { color: #000000; } /* Operator.Word */
42 | .w { color: #bbbbbb } /* Text.Whitespace */
43 | .mf { color: #FF6600 } /* Literal.Number.Float */
44 | .mh { color: #FF6600 } /* Literal.Number.Hex */
45 | .mi { color: #FF6600 } /* Literal.Number.Integer */
46 | .mo { color: #FF6600 } /* Literal.Number.Oct */
47 | .sb { color: #CC3300 } /* Literal.String.Backtick */
48 | .sc { color: #CC3300 } /* Literal.String.Char */
49 | .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
50 | .s2 { color: #CC3300 } /* Literal.String.Double */
51 | .se { color: #CC3300; } /* Literal.String.Escape */
52 | .sh { color: #CC3300 } /* Literal.String.Heredoc */
53 | .si { color: #AA0000 } /* Literal.String.Interpol */
54 | .sx { color: #CC3300 } /* Literal.String.Other */
55 | .sr { color: #33AAAA } /* Literal.String.Regex */
56 | .s1 { color: #CC3300 } /* Literal.String.Single */
57 | .ss { color: #FFCC33 } /* Literal.String.Symbol */
58 | .bp { color: #336666 } /* Name.Builtin.Pseudo */
59 | .vc { color: #003333 } /* Name.Variable.Class */
60 | .vg { color: #003333 } /* Name.Variable.Global */
61 | .vi { color: #003333 } /* Name.Variable.Instance */
62 | .il { color: #FF6600 } /* Literal.Number.Integer.Long */
63 |
64 | .css .o,
65 | .css .o + .nt,
66 | .css .nt + .nt { color: #999; }
67 |
--------------------------------------------------------------------------------
/src/docs/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Bootstrap Tour
4 | slug: home
5 | ---
6 |
7 |
33 |
34 |
35 |
38 |
Add the dependencies
39 |
If you are using Bootstrap, include bootstrap-tour.min.css
and bootstrap-tour.min.js
:
40 | {% highlight html %}
41 |
42 |
43 | ...
44 |
45 |
46 |
47 | {% endhighlight %}
48 |
Otherwise, just include bootstrap-tour-standalone.min.css
and bootstrap-tour-standalone.min.js
:
49 | {% highlight html %}
50 |
51 | ...
52 |
53 |
54 | {% endhighlight %}
55 |
Setup your tour:
56 | {% highlight javascript %}
57 | // Instance the tour
58 | var tour = new Tour({
59 | steps: [
60 | {
61 | element: "#my-element",
62 | title: "Title of my step",
63 | content: "Content of my step"
64 | },
65 | {
66 | element: "#my-other-element",
67 | title: "Title of my step",
68 | content: "Content of my step"
69 | }
70 | ]});
71 |
72 | // Initialize the tour
73 | tour.init();
74 |
75 | // Start the tour
76 | tour.start();
77 | {% endhighlight %}
78 |
Do you want to do more? Read the full documentation.
79 |
80 |
81 |
99 |
100 |
101 |
104 |
Code licensed under the MIT license .
105 | Documentation licensed under CC BY 3.0 .
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/scss/bootstrap-tour-standalone.scss:
--------------------------------------------------------------------------------
1 | @import 'functions';
2 | @import 'variables';
3 | @import 'mixins';
4 | @import 'buttons';
5 | @import 'transitions';
6 | @import 'button-group';
7 | @import 'popover';
8 | @import 'bootstrap-tour';
9 |
--------------------------------------------------------------------------------
/src/scss/bootstrap-tour.scss:
--------------------------------------------------------------------------------
1 | .tour-backdrop {
2 | background-color: #000;
3 | filter: alpha(opacity = 80);
4 | opacity: .8;
5 | position: absolute;
6 | z-index: 1100;
7 | }
8 |
9 | .popover[class*="tour-"] {
10 | z-index: 1102;
11 |
12 | .popover-navigation {
13 | overflow: hidden;
14 | padding: 9px 14px;
15 |
16 | *[data-role="end"] {
17 | float: right;
18 | }
19 |
20 | *[data-role="prev"],
21 | *[data-role="next"],
22 | *[data-role="end"] {
23 | cursor: pointer;
24 |
25 | &.disabled {
26 | cursor: default;
27 | }
28 | }
29 | }
30 |
31 | &.orphan {
32 | left: 50%;
33 | margin-top: 0;
34 | position: fixed;
35 | top: 50%;
36 | transform: translate(-50%, -50%);
37 |
38 | .arrow {
39 | display: none;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/bootstrap-tour.js:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-tour - v0.12.0
3 | * http://bootstraptour.com
4 | * ========================================================================
5 | * Copyright 2012-2017 Ulrich Sossou
6 | *
7 | * ========================================================================
8 | * Licensed under the MIT License (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * https://opensource.org/licenses/MIT
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
23 |
24 | (function(window, factory) {
25 | if (typeof define === 'function' && define.amd) {
26 | return define(['jquery'], function(jQuery) {
27 | return window.Tour = factory(jQuery);
28 | });
29 | } else if (typeof exports === 'object') {
30 | return module.exports = factory(require('jquery'));
31 | } else {
32 | return window.Tour = factory(window.jQuery);
33 | }
34 | })(window, function($) {
35 | var Tour, document;
36 | document = window.document;
37 | Tour = (function() {
38 | function Tour(options) {
39 | this._showPopoverAndOverlay = bind(this._showPopoverAndOverlay, this);
40 | var storage;
41 | try {
42 | storage = window.localStorage;
43 | } catch (error) {
44 | storage = false;
45 | }
46 | this._options = $.extend({
47 | name: 'tour',
48 | steps: [],
49 | container: 'body',
50 | autoscroll: true,
51 | keyboard: true,
52 | storage: storage,
53 | debug: false,
54 | backdrop: false,
55 | backdropContainer: 'body',
56 | backdropPadding: 0,
57 | redirect: true,
58 | orphan: false,
59 | duration: false,
60 | delay: false,
61 | basePath: '',
62 | template: '
« Prev Next » Pause
End tour ',
63 | afterSetState: function(key, value) {},
64 | afterGetState: function(key, value) {},
65 | afterRemoveState: function(key) {},
66 | onStart: function(tour) {},
67 | onEnd: function(tour) {},
68 | onShow: function(tour) {},
69 | onShown: function(tour) {},
70 | onHide: function(tour) {},
71 | onHidden: function(tour) {},
72 | onNext: function(tour) {},
73 | onPrev: function(tour) {},
74 | onPause: function(tour, duration) {},
75 | onResume: function(tour, duration) {},
76 | onRedirectError: function(tour) {}
77 | }, options);
78 | this._force = false;
79 | this._inited = false;
80 | this._current = null;
81 | this.backdrops = [];
82 | this;
83 | }
84 |
85 | Tour.prototype.addSteps = function(steps) {
86 | var j, len, step;
87 | for (j = 0, len = steps.length; j < len; j++) {
88 | step = steps[j];
89 | this.addStep(step);
90 | }
91 | return this;
92 | };
93 |
94 | Tour.prototype.addStep = function(step) {
95 | this._options.steps.push(step);
96 | return this;
97 | };
98 |
99 | Tour.prototype.getStep = function(i) {
100 | if (this._options.steps[i] != null) {
101 | return $.extend({
102 | id: "step-" + i,
103 | path: '',
104 | host: '',
105 | placement: 'right',
106 | title: '',
107 | content: '
',
108 | next: i === this._options.steps.length - 1 ? -1 : i + 1,
109 | prev: i - 1,
110 | animation: true,
111 | container: this._options.container,
112 | autoscroll: this._options.autoscroll,
113 | backdrop: this._options.backdrop,
114 | backdropContainer: this._options.backdropContainer,
115 | backdropPadding: this._options.backdropPadding,
116 | redirect: this._options.redirect,
117 | reflexElement: this._options.steps[i].element,
118 | backdropElement: this._options.steps[i].element,
119 | orphan: this._options.orphan,
120 | duration: this._options.duration,
121 | delay: this._options.delay,
122 | template: this._options.template,
123 | onShow: this._options.onShow,
124 | onShown: this._options.onShown,
125 | onHide: this._options.onHide,
126 | onHidden: this._options.onHidden,
127 | onNext: this._options.onNext,
128 | onPrev: this._options.onPrev,
129 | onPause: this._options.onPause,
130 | onResume: this._options.onResume,
131 | onRedirectError: this._options.onRedirectError
132 | }, this._options.steps[i]);
133 | }
134 | };
135 |
136 | Tour.prototype.init = function(force) {
137 | this._force = force;
138 | if (this.ended()) {
139 | this._debug('Tour ended, init prevented.');
140 | return this;
141 | }
142 | this.setCurrentStep();
143 | this._initMouseNavigation();
144 | this._initKeyboardNavigation();
145 | if (this._current !== null) {
146 | this.showStep(this._current);
147 | }
148 | this._inited = true;
149 | return this;
150 | };
151 |
152 | Tour.prototype.start = function(force) {
153 | var promise;
154 | if (force == null) {
155 | force = false;
156 | }
157 | if (!this._inited) {
158 | this.init(force);
159 | }
160 | if (this._current === null) {
161 | promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
162 | this._callOnPromiseDone(promise, this.showStep, 0);
163 | }
164 | return this;
165 | };
166 |
167 | Tour.prototype.next = function() {
168 | var promise;
169 | promise = this.hideStep(this._current, this._current + 1);
170 | return this._callOnPromiseDone(promise, this._showNextStep);
171 | };
172 |
173 | Tour.prototype.prev = function() {
174 | var promise;
175 | promise = this.hideStep(this._current, this._current - 1);
176 | return this._callOnPromiseDone(promise, this._showPrevStep);
177 | };
178 |
179 | Tour.prototype.goTo = function(i) {
180 | var promise;
181 | promise = this.hideStep(this._current, i);
182 | return this._callOnPromiseDone(promise, this.showStep, i);
183 | };
184 |
185 | Tour.prototype.end = function() {
186 | var endHelper, promise;
187 | endHelper = (function(_this) {
188 | return function(e) {
189 | $(document).off("click.tour-" + _this._options.name);
190 | $(document).off("keyup.tour-" + _this._options.name);
191 | _this._setState('end', 'yes');
192 | _this._inited = false;
193 | _this._force = false;
194 | _this._clearTimer();
195 | if (_this._options.onEnd != null) {
196 | return _this._options.onEnd(_this);
197 | }
198 | };
199 | })(this);
200 | promise = this.hideStep(this._current);
201 | return this._callOnPromiseDone(promise, endHelper);
202 | };
203 |
204 | Tour.prototype.ended = function() {
205 | return !this._force && !!this._getState('end');
206 | };
207 |
208 | Tour.prototype.restart = function() {
209 | this._removeState('current_step');
210 | this._removeState('end');
211 | this._removeState('redirect_to');
212 | return this.start();
213 | };
214 |
215 | Tour.prototype.pause = function() {
216 | var step;
217 | step = this.getStep(this._current);
218 | if (!(step && step.duration)) {
219 | return this;
220 | }
221 | this._paused = true;
222 | this._duration -= new Date().getTime() - this._start;
223 | window.clearTimeout(this._timer);
224 | this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
225 | if (step.onPause != null) {
226 | return step.onPause(this, this._duration);
227 | }
228 | };
229 |
230 | Tour.prototype.resume = function() {
231 | var step;
232 | step = this.getStep(this._current);
233 | if (!(step && step.duration)) {
234 | return this;
235 | }
236 | this._paused = false;
237 | this._start = new Date().getTime();
238 | this._duration = this._duration || step.duration;
239 | this._timer = window.setTimeout((function(_this) {
240 | return function() {
241 | if (_this._isLast()) {
242 | return _this.next();
243 | } else {
244 | return _this.end();
245 | }
246 | };
247 | })(this), this._duration);
248 | this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
249 | if ((step.onResume != null) && this._duration !== step.duration) {
250 | return step.onResume(this, this._duration);
251 | }
252 | };
253 |
254 | Tour.prototype.hideStep = function(i, iNext) {
255 | var hideDelay, hideStepHelper, promise, step;
256 | step = this.getStep(i);
257 | if (!step) {
258 | return;
259 | }
260 | this._clearTimer();
261 | promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
262 | hideStepHelper = (function(_this) {
263 | return function(e) {
264 | var $element, next_step;
265 | $element = $(step.element);
266 | if (!$element.data('bs.popover')) {
267 | $element = $('body');
268 | }
269 | $element.popover('dispose').removeClass("tour-" + _this._options.name + "-element tour-" + _this._options.name + "-" + i + "-element").removeData('bs.popover');
270 | if (step.reflex) {
271 | $(step.reflexElement).removeClass('tour-step-element-reflex').off((_this._reflexEvent(step.reflex)) + ".tour-" + _this._options.name);
272 | }
273 | if (step.backdrop) {
274 | next_step = (iNext != null) && _this.getStep(iNext);
275 | if (!next_step || !next_step.backdrop || next_step.backdropElement !== step.backdropElement) {
276 | _this._hideOverlayElement(step);
277 | }
278 | }
279 | if (step.onHidden != null) {
280 | return step.onHidden(_this);
281 | }
282 | };
283 | })(this);
284 | hideDelay = step.delay.hide || step.delay;
285 | if ({}.toString.call(hideDelay) === '[object Number]' && hideDelay > 0) {
286 | this._debug("Wait " + hideDelay + " milliseconds to hide the step " + (this._current + 1));
287 | window.setTimeout((function(_this) {
288 | return function() {
289 | return _this._callOnPromiseDone(promise, hideStepHelper);
290 | };
291 | })(this), hideDelay);
292 | } else {
293 | this._callOnPromiseDone(promise, hideStepHelper);
294 | }
295 | return promise;
296 | };
297 |
298 | Tour.prototype.showStep = function(i) {
299 | var path, promise, showDelay, showStepHelper, skipToPrevious, step;
300 | if (this.ended()) {
301 | this._debug('Tour ended, showStep prevented.');
302 | return this;
303 | }
304 | step = this.getStep(i);
305 | if (!step) {
306 | return;
307 | }
308 | skipToPrevious = i < this._current;
309 | promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
310 | this.setCurrentStep(i);
311 | path = (function() {
312 | switch ({}.toString.call(step.path)) {
313 | case '[object Function]':
314 | return step.path();
315 | case '[object String]':
316 | return this._options.basePath + step.path;
317 | default:
318 | return step.path;
319 | }
320 | }).call(this);
321 | if (step.redirect && this._isRedirect(step.host, path, document.location)) {
322 | this._redirect(step, i, path);
323 | if (!this._isJustPathHashDifferent(step.host, path, document.location)) {
324 | return;
325 | }
326 | }
327 | showStepHelper = (function(_this) {
328 | return function(e) {
329 | if (_this._isOrphan(step)) {
330 | if (step.orphan === false) {
331 | _this._debug("Skip the orphan step " + (_this._current + 1) + ".\nOrphan option is false and the element does not exist or is hidden.");
332 | if (skipToPrevious) {
333 | _this._showPrevStep();
334 | } else {
335 | _this._showNextStep();
336 | }
337 | return;
338 | }
339 | _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
340 | }
341 | if (step.autoscroll) {
342 | _this._scrollIntoView(i);
343 | } else {
344 | _this._showPopoverAndOverlay(i);
345 | }
346 | if (step.duration) {
347 | return _this.resume();
348 | }
349 | };
350 | })(this);
351 | showDelay = step.delay.show || step.delay;
352 | if ({}.toString.call(showDelay) === '[object Number]' && showDelay > 0) {
353 | this._debug("Wait " + showDelay + " milliseconds to show the step " + (this._current + 1));
354 | window.setTimeout((function(_this) {
355 | return function() {
356 | return _this._callOnPromiseDone(promise, showStepHelper);
357 | };
358 | })(this), showDelay);
359 | } else {
360 | this._callOnPromiseDone(promise, showStepHelper);
361 | }
362 | return promise;
363 | };
364 |
365 | Tour.prototype.getCurrentStep = function() {
366 | return this._current;
367 | };
368 |
369 | Tour.prototype.setCurrentStep = function(value) {
370 | if (value != null) {
371 | this._current = value;
372 | this._setState('current_step', value);
373 | } else {
374 | this._current = this._getState('current_step');
375 | this._current = this._current === null ? null : parseInt(this._current, 10);
376 | }
377 | return this;
378 | };
379 |
380 | Tour.prototype.redraw = function() {
381 | return this._showOverlayElement(this.getStep(this.getCurrentStep()));
382 | };
383 |
384 | Tour.prototype._setState = function(key, value) {
385 | var e, keyName;
386 | if (this._options.storage) {
387 | keyName = this._options.name + "_" + key;
388 | try {
389 | this._options.storage.setItem(keyName, value);
390 | } catch (error) {
391 | e = error;
392 | if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
393 | this._debug('LocalStorage quota exceeded. State storage failed.');
394 | }
395 | }
396 | return this._options.afterSetState(keyName, value);
397 | } else {
398 | if (this._state == null) {
399 | this._state = {};
400 | }
401 | return this._state[key] = value;
402 | }
403 | };
404 |
405 | Tour.prototype._removeState = function(key) {
406 | var keyName;
407 | if (this._options.storage) {
408 | keyName = this._options.name + "_" + key;
409 | this._options.storage.removeItem(keyName);
410 | return this._options.afterRemoveState(keyName);
411 | } else {
412 | if (this._state != null) {
413 | return delete this._state[key];
414 | }
415 | }
416 | };
417 |
418 | Tour.prototype._getState = function(key) {
419 | var keyName, value;
420 | if (this._options.storage) {
421 | keyName = this._options.name + "_" + key;
422 | value = this._options.storage.getItem(keyName);
423 | } else {
424 | if (this._state != null) {
425 | value = this._state[key];
426 | }
427 | }
428 | if (value === void 0 || value === 'null') {
429 | value = null;
430 | }
431 | this._options.afterGetState(key, value);
432 | return value;
433 | };
434 |
435 | Tour.prototype._showNextStep = function() {
436 | var promise, showNextStepHelper, step;
437 | step = this.getStep(this._current);
438 | showNextStepHelper = (function(_this) {
439 | return function(e) {
440 | return _this.showStep(step.next);
441 | };
442 | })(this);
443 | promise = this._makePromise(step.onNext != null ? step.onNext(this) : void 0);
444 | return this._callOnPromiseDone(promise, showNextStepHelper);
445 | };
446 |
447 | Tour.prototype._showPrevStep = function() {
448 | var promise, showPrevStepHelper, step;
449 | step = this.getStep(this._current);
450 | showPrevStepHelper = (function(_this) {
451 | return function(e) {
452 | return _this.showStep(step.prev);
453 | };
454 | })(this);
455 | promise = this._makePromise(step.onPrev != null ? step.onPrev(this) : void 0);
456 | return this._callOnPromiseDone(promise, showPrevStepHelper);
457 | };
458 |
459 | Tour.prototype._debug = function(text) {
460 | if (this._options.debug) {
461 | return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
462 | }
463 | };
464 |
465 | Tour.prototype._isRedirect = function(host, path, location) {
466 | var currentPath;
467 | if ((host != null) && host !== '' && (({}.toString.call(host) === '[object RegExp]' && !host.test(location.origin)) || ({}.toString.call(host) === '[object String]' && this._isHostDifferent(host, location)))) {
468 | return true;
469 | }
470 | currentPath = [location.pathname, location.search, location.hash].join('');
471 | return (path != null) && path !== '' && (({}.toString.call(path) === '[object RegExp]' && !path.test(currentPath)) || ({}.toString.call(path) === '[object String]' && this._isPathDifferent(path, currentPath)));
472 | };
473 |
474 | Tour.prototype._isHostDifferent = function(host, location) {
475 | switch ({}.toString.call(host)) {
476 | case '[object RegExp]':
477 | return !host.test(location.origin);
478 | case '[object String]':
479 | return this._getProtocol(host) !== this._getProtocol(location.href) || this._getHost(host) !== this._getHost(location.href);
480 | default:
481 | return true;
482 | }
483 | };
484 |
485 | Tour.prototype._isPathDifferent = function(path, currentPath) {
486 | return this._getPath(path) !== this._getPath(currentPath) || !this._equal(this._getQuery(path), this._getQuery(currentPath)) || !this._equal(this._getHash(path), this._getHash(currentPath));
487 | };
488 |
489 | Tour.prototype._isJustPathHashDifferent = function(host, path, location) {
490 | var currentPath;
491 | if ((host != null) && host !== '') {
492 | if (this._isHostDifferent(host, location)) {
493 | return false;
494 | }
495 | }
496 | currentPath = [location.pathname, location.search, location.hash].join('');
497 | if ({}.toString.call(path) === '[object String]') {
498 | return this._getPath(path) === this._getPath(currentPath) && this._equal(this._getQuery(path), this._getQuery(currentPath)) && !this._equal(this._getHash(path), this._getHash(currentPath));
499 | }
500 | return false;
501 | };
502 |
503 | Tour.prototype._redirect = function(step, i, path) {
504 | var href;
505 | if ($.isFunction(step.redirect)) {
506 | return step.redirect.call(this, path);
507 | } else {
508 | href = {}.toString.call(step.host) === '[object String]' ? "" + step.host + path : path;
509 | this._debug("Redirect to " + href);
510 | if (this._getState('redirect_to') === ("" + i)) {
511 | this._debug("Error redirection loop to " + path);
512 | this._removeState('redirect_to');
513 | if (step.onRedirectError != null) {
514 | return step.onRedirectError(this);
515 | }
516 | } else {
517 | this._setState('redirect_to', "" + i);
518 | return document.location.href = href;
519 | }
520 | }
521 | };
522 |
523 | Tour.prototype._isOrphan = function(step) {
524 | return (step.element == null) || !$(step.element).length || $(step.element).is(':hidden') && ($(step.element)[0].namespaceURI !== 'http://www.w3.org/2000/svg');
525 | };
526 |
527 | Tour.prototype._isLast = function() {
528 | return this._current < this._options.steps.length - 1;
529 | };
530 |
531 | Tour.prototype._showPopoverAndOverlay = function(i) {
532 | var step;
533 | if (this.getCurrentStep() !== i || this.ended()) {
534 | return;
535 | }
536 | step = this.getStep(i);
537 | if (step.backdrop) {
538 | this._showOverlayElement(step);
539 | }
540 | this._showPopover(step, i);
541 | if (step.onShown != null) {
542 | step.onShown(this);
543 | }
544 | return this._debug("Step " + (this._current + 1) + " of " + this._options.steps.length);
545 | };
546 |
547 | Tour.prototype._showPopover = function(step, i) {
548 | var $element, $tip, isOrphan, options;
549 | $(".tour-" + this._options.name).remove();
550 | options = $.extend({}, this._options);
551 | isOrphan = this._isOrphan(step);
552 | step.template = this._template(step, i);
553 | if (isOrphan) {
554 | step.element = 'body';
555 | step.placement = 'top';
556 | }
557 | $element = $(step.element);
558 | $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element");
559 | if (step.options) {
560 | $.extend(options, step.options);
561 | }
562 | if (step.reflex && !isOrphan) {
563 | $(step.reflexElement).addClass('tour-step-element-reflex').off((this._reflexEvent(step.reflex)) + ".tour-" + this._options.name).on((this._reflexEvent(step.reflex)) + ".tour-" + this._options.name, (function(_this) {
564 | return function() {
565 | if (_this._isLast()) {
566 | return _this.next();
567 | } else {
568 | return _this.end();
569 | }
570 | };
571 | })(this));
572 | }
573 | $element.popover({
574 | placement: step.placement,
575 | trigger: 'manual',
576 | title: step.title,
577 | content: step.content,
578 | html: true,
579 | animation: step.animation,
580 | container: step.container,
581 | template: step.template,
582 | selector: step.element
583 | }).popover('show');
584 | $tip = $($element.data('bs.popover').getTipElement());
585 | return $tip.attr('id', step.id);
586 | };
587 |
588 | Tour.prototype._template = function(step, i) {
589 | var $navigation, $next, $prev, $resume, $template, template;
590 | template = step.template;
591 | if (this._isOrphan(step) && {}.toString.call(step.orphan) !== '[object Boolean]') {
592 | template = step.orphan;
593 | }
594 | $template = $.isFunction(template) ? $(template(i, step)) : $(template);
595 | $navigation = $template.find('.popover-navigation');
596 | $prev = $navigation.find('[data-role="prev"]');
597 | $next = $navigation.find('[data-role="next"]');
598 | $resume = $navigation.find('[data-role="pause-resume"]');
599 | if (this._isOrphan(step)) {
600 | $template.addClass('orphan');
601 | }
602 | $template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i);
603 | if (step.reflex) {
604 | $template.addClass("tour-" + this._options.name + "-reflex");
605 | }
606 | if (step.prev < 0) {
607 | $prev.addClass('disabled').prop('disabled', true).prop('tabindex', -1);
608 | }
609 | if (step.next < 0) {
610 | $next.addClass('disabled').prop('disabled', true).prop('tabindex', -1);
611 | }
612 | if (!step.duration) {
613 | $resume.remove();
614 | }
615 | return $template.clone().wrap('
').parent().html();
616 | };
617 |
618 | Tour.prototype._reflexEvent = function(reflex) {
619 | if ({}.toString.call(reflex) === '[object Boolean]') {
620 | return 'click';
621 | } else {
622 | return reflex;
623 | }
624 | };
625 |
626 | Tour.prototype._scrollIntoView = function(i) {
627 | var $element, $window, counter, height, offsetTop, scrollTop, step, windowHeight;
628 | step = this.getStep(i);
629 | $element = $(step.element);
630 | if (!$element.length) {
631 | return this._showPopoverAndOverlay(i);
632 | }
633 | $window = $(window);
634 | offsetTop = $element.offset().top;
635 | height = $element.outerHeight();
636 | windowHeight = $window.height();
637 | scrollTop = 0;
638 | switch (step.placement) {
639 | case 'top':
640 | scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
641 | break;
642 | case 'left':
643 | case 'right':
644 | scrollTop = Math.max(0, (offsetTop + height / 2) - (windowHeight / 2));
645 | break;
646 | case 'bottom':
647 | scrollTop = Math.max(0, (offsetTop + height) - (windowHeight / 2));
648 | }
649 | this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
650 | counter = 0;
651 | return $('body, html').stop(true, true).animate({
652 | scrollTop: Math.ceil(scrollTop)
653 | }, (function(_this) {
654 | return function() {
655 | if (++counter === 2) {
656 | _this._showPopoverAndOverlay(i);
657 | return _this._debug("Scroll into view.\nAnimation end element offset: " + ($element.offset().top) + ".\nWindow height: " + ($window.height()) + ".");
658 | }
659 | };
660 | })(this));
661 | };
662 |
663 | Tour.prototype._initMouseNavigation = function() {
664 | var _this;
665 | _this = this;
666 | return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']", (function(_this) {
667 | return function(e) {
668 | e.preventDefault();
669 | return _this.next();
670 | };
671 | })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']", (function(_this) {
672 | return function(e) {
673 | e.preventDefault();
674 | if (_this._current > 0) {
675 | return _this.prev();
676 | }
677 | };
678 | })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", (function(_this) {
679 | return function(e) {
680 | e.preventDefault();
681 | return _this.end();
682 | };
683 | })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) {
684 | var $this;
685 | e.preventDefault();
686 | $this = $(this);
687 | $this.text(_this._paused ? $this.data('pause-text') : $this.data('resume-text'));
688 | if (_this._paused) {
689 | return _this.resume();
690 | } else {
691 | return _this.pause();
692 | }
693 | });
694 | };
695 |
696 | Tour.prototype._initKeyboardNavigation = function() {
697 | if (!this._options.keyboard) {
698 | return;
699 | }
700 | return $(document).on("keyup.tour-" + this._options.name, (function(_this) {
701 | return function(e) {
702 | if (!e.which) {
703 | return;
704 | }
705 | switch (e.which) {
706 | case 39:
707 | e.preventDefault();
708 | if (_this._isLast()) {
709 | return _this.next();
710 | } else {
711 | return _this.end();
712 | }
713 | break;
714 | case 37:
715 | e.preventDefault();
716 | if (_this._current > 0) {
717 | return _this.prev();
718 | }
719 | }
720 | };
721 | })(this));
722 | };
723 |
724 | Tour.prototype._makePromise = function(result) {
725 | if (result && $.isFunction(result.then)) {
726 | return result;
727 | } else {
728 | return null;
729 | }
730 | };
731 |
732 | Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
733 | if (promise) {
734 | return promise.then((function(_this) {
735 | return function(e) {
736 | return cb.call(_this, arg);
737 | };
738 | })(this));
739 | } else {
740 | return cb.call(this, arg);
741 | }
742 | };
743 |
744 | Tour.prototype._showBackground = function(step, data) {
745 | var $backdrop, base, height, j, len, pos, ref, results, width;
746 | height = $(document).height();
747 | width = $(document).width();
748 | ref = ['top', 'bottom', 'left', 'right'];
749 | results = [];
750 | for (j = 0, len = ref.length; j < len; j++) {
751 | pos = ref[j];
752 | $backdrop = (base = this.backdrops)[pos] != null ? base[pos] : base[pos] = $('
', {
753 | "class": "tour-backdrop " + pos
754 | });
755 | $(step.backdropContainer).append($backdrop);
756 | switch (pos) {
757 | case 'top':
758 | results.push($backdrop.height(data.offset.top > 0 ? data.offset.top : 0).width(width).offset({
759 | top: 0,
760 | left: 0
761 | }));
762 | break;
763 | case 'bottom':
764 | results.push($backdrop.offset({
765 | top: data.offset.top + data.height,
766 | left: 0
767 | }).height(height - (data.offset.top + data.height)).width(width));
768 | break;
769 | case 'left':
770 | results.push($backdrop.offset({
771 | top: data.offset.top,
772 | left: 0
773 | }).height(data.height).width(data.offset.left > 0 ? data.offset.left : 0));
774 | break;
775 | case 'right':
776 | results.push($backdrop.offset({
777 | top: data.offset.top,
778 | left: data.offset.left + data.width
779 | }).height(data.height).width(width - (data.offset.left + data.width)));
780 | break;
781 | default:
782 | results.push(void 0);
783 | }
784 | }
785 | return results;
786 | };
787 |
788 | Tour.prototype._showOverlayElement = function(step) {
789 | var $backdropElement, elementData;
790 | $backdropElement = $(step.backdropElement);
791 | if ($backdropElement.length === 0) {
792 | elementData = {
793 | width: 0,
794 | height: 0,
795 | offset: {
796 | top: 0,
797 | left: 0
798 | }
799 | };
800 | } else {
801 | elementData = {
802 | width: $backdropElement.innerWidth(),
803 | height: $backdropElement.innerHeight(),
804 | offset: $backdropElement.offset()
805 | };
806 | $backdropElement.addClass('tour-step-backdrop');
807 | if (step.backdropPadding) {
808 | elementData = this._applyBackdropPadding(step.backdropPadding, elementData);
809 | }
810 | }
811 | return this._showBackground(step, elementData);
812 | };
813 |
814 | Tour.prototype._hideOverlayElement = function(step) {
815 | var $backdrop, pos, ref;
816 | $(step.backdropElement).removeClass('tour-step-backdrop');
817 | ref = this.backdrops;
818 | for (pos in ref) {
819 | $backdrop = ref[pos];
820 | if ($backdrop && $backdrop.remove !== void 0) {
821 | $backdrop.remove();
822 | }
823 | }
824 | return this.backdrops = [];
825 | };
826 |
827 | Tour.prototype._applyBackdropPadding = function(padding, data) {
828 | if (typeof padding === 'object') {
829 | if (padding.top == null) {
830 | padding.top = 0;
831 | }
832 | if (padding.right == null) {
833 | padding.right = 0;
834 | }
835 | if (padding.bottom == null) {
836 | padding.bottom = 0;
837 | }
838 | if (padding.left == null) {
839 | padding.left = 0;
840 | }
841 | data.offset.top = data.offset.top - padding.top;
842 | data.offset.left = data.offset.left - padding.left;
843 | data.width = data.width + padding.left + padding.right;
844 | data.height = data.height + padding.top + padding.bottom;
845 | } else {
846 | data.offset.top = data.offset.top - padding;
847 | data.offset.left = data.offset.left - padding;
848 | data.width = data.width + (padding * 2);
849 | data.height = data.height + (padding * 2);
850 | }
851 | return data;
852 | };
853 |
854 | Tour.prototype._clearTimer = function() {
855 | window.clearTimeout(this._timer);
856 | this._timer = null;
857 | return this._duration = null;
858 | };
859 |
860 | Tour.prototype._getProtocol = function(url) {
861 | url = url.split('://');
862 | if (url.length > 1) {
863 | return url[0];
864 | } else {
865 | return 'http';
866 | }
867 | };
868 |
869 | Tour.prototype._getHost = function(url) {
870 | url = url.split('//');
871 | url = url.length > 1 ? url[1] : url[0];
872 | return url.split('/')[0];
873 | };
874 |
875 | Tour.prototype._getPath = function(path) {
876 | return path.replace(/\/?$/, '').split('?')[0].split('#')[0];
877 | };
878 |
879 | Tour.prototype._getQuery = function(path) {
880 | return this._getParams(path, '?');
881 | };
882 |
883 | Tour.prototype._getHash = function(path) {
884 | return this._getParams(path, '#');
885 | };
886 |
887 | Tour.prototype._getParams = function(path, start) {
888 | var j, len, param, params, paramsObject;
889 | params = path.split(start);
890 | if (params.length === 1) {
891 | return {};
892 | }
893 | params = params[1].split('&');
894 | paramsObject = {};
895 | for (j = 0, len = params.length; j < len; j++) {
896 | param = params[j];
897 | param = param.split('=');
898 | paramsObject[param[0]] = param[1] || '';
899 | }
900 | return paramsObject;
901 | };
902 |
903 | Tour.prototype._equal = function(obj1, obj2) {
904 | var j, k, len, obj1Keys, obj2Keys, v;
905 | if ({}.toString.call(obj1) === '[object Object]' && {}.toString.call(obj2) === '[object Object]') {
906 | obj1Keys = Object.keys(obj1);
907 | obj2Keys = Object.keys(obj2);
908 | if (obj1Keys.length !== obj2Keys.length) {
909 | return false;
910 | }
911 | for (k in obj1) {
912 | v = obj1[k];
913 | if (!this._equal(obj2[k], v)) {
914 | return false;
915 | }
916 | }
917 | return true;
918 | } else if ({}.toString.call(obj1) === '[object Array]' && {}.toString.call(obj2) === '[object Array]') {
919 | if (obj1.length !== obj2.length) {
920 | return false;
921 | }
922 | for (k = j = 0, len = obj1.length; j < len; k = ++j) {
923 | v = obj1[k];
924 | if (!this._equal(v, obj2[k])) {
925 | return false;
926 | }
927 | }
928 | return true;
929 | } else {
930 | return obj1 === obj2;
931 | }
932 | };
933 |
934 | return Tour;
935 |
936 | })();
937 | return Tour;
938 | });
939 |
--------------------------------------------------------------------------------