diff --git a/.gitignore b/.gitignore index 9b17e15d9..84a214785 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .sass-cache node_modules/ -deps/ \ No newline at end of file +bower_components/ +.DS_Store diff --git a/.hsdoc b/.hsdoc index 26afa6c61..ef4208db2 100644 --- a/.hsdoc +++ b/.hsdoc @@ -2,4 +2,4 @@ title: "shepherd" description: "Guide your users through a tour of your app." source: "shepherd.coffee" examples: "**/*.md" -assets: "{shepherd.js,deps/tether/*.js,deps/tether/css/*,*.js,*.coffee,css/*.css,docs/css/*.css,docs/js/*,js,docs/welcome/*,examples/*}" +assets: "{shepherd.js,bower_components/tether/*.js,bower_components/tether/css/*,*.js,*.coffee,css/*.css,docs/css/*.css,docs/js/*,js,docs/welcome/*,examples/*}" diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100644 index 7338f901a..000000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,50 +0,0 @@ -module.exports = (grunt) -> - grunt.initConfig - pkg: grunt.file.readJSON('package.json') - coffee: - compile: - files: - 'shepherd.js': 'shepherd.coffee' - 'docs/welcome/js/welcome.js': 'docs/welcome/coffee/welcome.coffee' - - watch: - coffee: - files: ['*.coffee', 'sass/*', 'docs/**/*'] - tasks: ['coffee', 'uglify', 'compass'] - options: - atBegin: true - - uglify: - shepherd: - src: 'shepherd.js' - dest: 'shepherd.min.js' - options: - banner: '/*! shepherd.js <%= pkg.version %> */\n' - - compass: - dist: - options: - sassDir: 'sass' - cssDir: 'css' - welcomeDocs: - options: - sassDir: 'docs/welcome/sass' - cssDir: 'docs/welcome/css' - - bower: - install: - options: - targetDir: 'deps' - cleanup: true - layout: 'byComponent' - bowerOptions: - forceLatest: true - production: true - - grunt.loadNpmTasks 'grunt-bower-task' - grunt.loadNpmTasks 'grunt-contrib-coffee' - grunt.loadNpmTasks 'grunt-contrib-uglify' - grunt.loadNpmTasks 'grunt-contrib-compass' - grunt.loadNpmTasks 'grunt-contrib-watch' - - grunt.registerTask 'default', ['bower', 'coffee', 'uglify', 'compass'] \ No newline at end of file diff --git a/bower.json b/bower.json index 76f882c94..e6bf27b3f 100644 --- a/bower.json +++ b/bower.json @@ -1,9 +1,10 @@ { "name": "shepherd", "main": "shepherd.js", - "version": "0.2.1", + "version": "0.3.0", "homepage": "https://github.com/HubSpot/shepherd", "authors": [ + "Zack Bloom ", "Adam Schwartz " ], "description": "Guide your users through a tour of your app.", diff --git a/shepherd.coffee b/coffee/shepherd.coffee similarity index 85% rename from shepherd.coffee rename to coffee/shepherd.coffee index 1faa8351d..3acad2b45 100644 --- a/shepherd.coffee +++ b/coffee/shepherd.coffee @@ -39,9 +39,11 @@ parseShorthand = (obj, props) -> out class Step extends Evented - constructor: (@shepherd, options) -> + constructor: (@tour, options) -> @setOptions options + @ + setOptions: (@options={}) -> @destroy() @@ -53,20 +55,25 @@ class Step extends Evented @options.buttons ?= [ text: 'Next' - action: @shepherd.next + action: @tour.next ] + getTour: -> + @tour + bindAdvance: -> # An empty selector matches the step element {event, selector} = parseShorthand @options.advanceOn, ['event', 'selector'] handler = (e) => + return unless @isOpen() + if selector? if matchesSelector(e.target, selector) - @shepherd.advance() + @tour.next() else if @el and e.target is @el - @shepherd.advance() + @tour.next() document.body.addEventListener event, handler # TODO: this should also bind/unbind on show/hide @@ -131,6 +138,9 @@ class Step extends Evented @trigger 'hide' + isOpen: => + hasClass @el, 'shepherd-open' + cancel: => @hide() @@ -229,7 +239,7 @@ class Step extends Evented if typeof handler is 'string' page = handler handler = => - @shepherd.show page + @tour.show page el.addEventListener event, handler @@ -237,30 +247,50 @@ class Step extends Evented for event, handler of cfg.events el.removeEventListener event, handler -class Shepherd extends Evented +class Tour extends Evented constructor: (@options={}) -> @steps = @options.steps ? [] + # Pass these events onto the global Shepherd object + for event in ['complete', 'cancel', 'hide', 'start', 'show'] + @on event, (opts={}) => + opts.tour = @ + Shepherd.trigger event, opts + + @ + addStep: (name, step) -> if not step? step = name - else - step.id = name - step = extend {}, @options.defaults, step + unless step instanceof Step + if typeof name in ['string', 'number'] + step.id = name.toString() + + step = extend {}, @options.defaults, step - @steps.push new Step(@, step) + step = new Step(@, step) + else + step.tour = @ + + @steps.push step + + step getById: (id) -> for step in @steps when step.id is id return step + getCurrentStep: -> + @currentStep + next: => index = @steps.indexOf(@currentStep) if index is @steps.length - 1 @hide index @trigger 'complete' + @done() else @show(index + 1) @@ -273,29 +303,42 @@ class Shepherd extends Evented @currentStep?.cancel() @trigger 'cancel' + @done() hide: => @currentStep?.hide() @trigger 'hide' + @done() + + done: -> + Shepherd.activeTour = null show: (key=0) -> if @currentStep @currentStep.hide() + Shepherd.activeTour = @ + if typeof key is 'string' next = @getById key else next = @steps[key] if next - @trigger 'shown', {step: next, previous: @currentStep} + @trigger 'show', {step: next, previous: @currentStep} @currentStep = next next.show() start: -> + @trigger 'start' + @currentStep = null @next() -window.Shepherd = Shepherd \ No newline at end of file +Shepherd = new Evented + +extend Shepherd, {Tour, Step} + +window.Shepherd = Shepherd diff --git a/css/shepherd-theme-arrows.css b/css/shepherd-theme-arrows.css index 08d6813ce..345d7135e 100644 --- a/css/shepherd-theme-arrows.css +++ b/css/shepherd-theme-arrows.css @@ -1,267 +1,179 @@ -/* line 6, ../deps/tether/sass/helpers/_tether.sass */ .shepherd-element, .shepherd-element:after, .shepherd-element:before, .shepherd-element *, .shepherd-element *:after, .shepherd-element *:before { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; - box-sizing: border-box; -} + box-sizing: border-box; } -/* line 9, ../deps/tether/sass/helpers/_tether.sass */ .shepherd-element { position: absolute; - display: none; -} -/* line 13, ../deps/tether/sass/helpers/_tether.sass */ -.shepherd-element.shepherd-open { - display: block; -} + display: none; } + .shepherd-element.shepherd-open { + display: block; } -/* line 4, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ .shepherd-element.shepherd-theme-arrows { max-width: 100%; - max-height: 100%; -} -/* line 8, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content { - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -ms-border-radius: 5px; - -o-border-radius: 5px; - border-radius: 5px; - position: relative; - font-family: inherit; - background: white; - color: #444444; - padding: 1em; - font-size: 1.1em; - line-height: 1.5em; - -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); - -webkit-transform: translateZ(0); -} -/* line 22, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content:before { - content: ""; - display: block; - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-width: 16px; - border-style: solid; -} -/* line 34, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content { - margin-bottom: 16px; -} -/* line 37, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content:before { - top: 100%; - left: 50%; - margin-left: -16px; - border-top-color: white; -} -/* line 43, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content { - margin-top: 16px; -} -/* line 46, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content:before { - bottom: 100%; - left: 50%; - margin-left: -16px; - border-bottom-color: white; -} -/* line 52, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content { - margin-right: 16px; -} -/* line 55, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content:before { - left: 100%; - top: 50%; - margin-top: -16px; - border-left-color: white; -} -/* line 61, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content { - margin-left: 16px; -} -/* line 64, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content:before { - right: 100%; - top: 50%; - margin-top: -16px; - border-right-color: white; -} -/* line 72, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content { - margin-top: 16px; -} -/* line 75, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content:before { - bottom: 100%; - left: 16px; - border-bottom-color: white; -} -/* line 80, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content { - margin-top: 16px; -} -/* line 83, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content:before { - bottom: 100%; - right: 16px; - border-bottom-color: white; -} -/* line 88, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content { - margin-bottom: 16px; -} -/* line 91, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content:before { - top: 100%; - left: 16px; - border-top-color: white; -} -/* line 96, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content { - margin-bottom: 16px; -} -/* line 99, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content:before { - top: 100%; - right: 16px; - border-top-color: white; -} -/* line 106, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content { - margin-right: 16px; -} -/* line 109, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before { - top: 16px; - left: 100%; - border-left-color: white; -} -/* line 114, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content { - margin-left: 16px; -} -/* line 117, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before { - top: 16px; - right: 100%; - border-right-color: white; -} -/* line 122, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content { - margin-right: 16px; -} -/* line 125, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before { - bottom: 16px; - left: 100%; - border-left-color: white; -} -/* line 130, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content { - margin-left: 16px; -} -/* line 133, ../deps/tether/sass/helpers/_tether-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before { - bottom: 16px; - right: 100%; - border-right-color: white; -} + max-height: 100%; } + .shepherd-element.shepherd-theme-arrows .shepherd-content { + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; + position: relative; + font-family: inherit; + background: white; + color: #444444; + padding: 1em; + font-size: 1.1em; + line-height: 1.5em; + -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); + -webkit-transform: translateZ(0); } + .shepherd-element.shepherd-theme-arrows .shepherd-content:before { + content: ""; + display: block; + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-width: 16px; + border-style: solid; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content { + margin-bottom: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content:before { + top: 100%; + left: 50%; + margin-left: -16px; + border-top-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content { + margin-top: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content:before { + bottom: 100%; + left: 50%; + margin-left: -16px; + border-bottom-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content { + margin-right: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content:before { + left: 100%; + top: 50%; + margin-top: -16px; + border-left-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content { + margin-left: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content:before { + right: 100%; + top: 50%; + margin-top: -16px; + border-right-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content { + margin-top: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content:before { + bottom: 100%; + left: 16px; + border-bottom-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content { + margin-top: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content:before { + bottom: 100%; + right: 16px; + border-bottom-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content { + margin-bottom: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content:before { + top: 100%; + left: 16px; + border-top-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content { + margin-bottom: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content:before { + top: 100%; + right: 16px; + border-top-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content { + margin-right: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before { + top: 16px; + left: 100%; + border-left-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content { + margin-left: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before { + top: 16px; + right: 100%; + border-right-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content { + margin-right: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before { + bottom: 16px; + left: 100%; + border-left-color: white; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content { + margin-left: 16px; } + .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before { + bottom: 16px; + right: 100%; + border-right-color: white; } -/* line 30, ../sass/shepherd-theme-arrows.sass */ .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-center.shepherd-has-title .shepherd-content:before, .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom.shepherd-has-title .shepherd-content:before, .shepherd-element.shepherd-theme-arrows.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom.shepherd-has-title .shepherd-content:before { - border-bottom-color: #eeeeee; -} -/* line 33, ../sass/shepherd-theme-arrows.sass */ + border-bottom-color: #eeeeee; } .shepherd-element.shepherd-theme-arrows .shepherd-content { - padding: 0; -} -/* line 36, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content * { - font-size: inherit; -} -/* line 39, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content header { - -webkit-border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - -ms-border-radius: 5px 5px 0 0; - -o-border-radius: 5px 5px 0 0; - border-radius: 5px 5px 0 0; - background: #eeeeee; - padding: 1em; -} -/* line 44, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content header h3 { - margin: 0; - line-height: 1; - font-weight: normal; -} -/* line 49, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content .shepherd-text { - padding: 1em; -} -/* line 52, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content .shepherd-text p { - margin: 0 0 0.5em 0; - line-height: 1.3em; -} -/* line 56, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content .shepherd-text p:last-child { - margin-bottom: 0; -} -/* line 59, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content footer { - padding: 0 1em 1em; -} -/* line 62, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons { - text-align: right; - list-style: none; - padding: 0; - margin: 0; -} -/* line 68, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li { - display: inline; - padding: 0; - margin: 0; -} -/* line 73, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li .shepherd-button { - display: -moz-inline-stack; - display: inline-block; - vertical-align: middle; - *vertical-align: auto; - zoom: 1; - *display: inline; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - -ms-border-radius: 3px; - -o-border-radius: 3px; - border-radius: 3px; - cursor: pointer; - border: 0; - margin: 0 0.5em 0 0; - font-family: inherit; - text-transform: uppercase; - letter-spacing: 0.1em; - font-size: 0.8em; - line-height: 1em; - padding: 0.75em 2em; - background: #3288e6; - color: white; -} -/* line 88, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li .shepherd-button.shepherd-button-secondary { - background: #eeeeee; - color: #888888; -} -/* line 92, ../sass/shepherd-theme-arrows.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li:last-child .shepherd-button { - margin-right: 0; -} + padding: 0; } + .shepherd-element.shepherd-theme-arrows .shepherd-content * { + font-size: inherit; } + .shepherd-element.shepherd-theme-arrows .shepherd-content header { + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -ms-border-radius: 5px 5px 0 0; + -o-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; + background: #eeeeee; + padding: 1em; } + .shepherd-element.shepherd-theme-arrows .shepherd-content header h3 { + margin: 0; + line-height: 1; + font-weight: normal; } + .shepherd-element.shepherd-theme-arrows .shepherd-content .shepherd-text { + padding: 1em; } + .shepherd-element.shepherd-theme-arrows .shepherd-content .shepherd-text p { + margin: 0 0 0.5em 0; + line-height: 1.3em; } + .shepherd-element.shepherd-theme-arrows .shepherd-content .shepherd-text p:last-child { + margin-bottom: 0; } + .shepherd-element.shepherd-theme-arrows .shepherd-content footer { + padding: 0 1em 1em; } + .shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons { + text-align: right; + list-style: none; + padding: 0; + margin: 0; } + .shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li { + display: inline; + padding: 0; + margin: 0; } + .shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li .shepherd-button { + display: -moz-inline-stack; + display: inline-block; + vertical-align: middle; + *vertical-align: auto; + zoom: 1; + *display: inline; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; + cursor: pointer; + border: 0; + margin: 0 0.5em 0 0; + font-family: inherit; + text-transform: uppercase; + letter-spacing: 0.1em; + font-size: 0.8em; + line-height: 1em; + padding: 0.75em 2em; + background: #3288e6; + color: white; } + .shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li .shepherd-button.shepherd-button-secondary { + background: #eeeeee; + color: #888888; } + .shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li:last-child .shepherd-button { + margin-right: 0; } diff --git a/docs/intro.md b/docs/intro.md index 552e9e90f..3881054c6 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,5 +1,4 @@ - ## Shepherd @@ -9,46 +8,179 @@ Guide your users through a tour of your app. ### Dependencies Shepherd uses [Tether](http://github.hubspot.com/tether/docs/welcome) to -position each step container. You can [download Tether here](https://github.com/HubSpot/tether/releases). +position each step container. Tether is included in the `shepherd.js` and `shepherd.min.js` files. -### Usage +Otherwise, none! -Using `Shepherd` is really easy. +### Usage -First create a new `Shepherd` instance. +First create a new `Tour` instance for your tour: ```coffeescript -shepherd = new Shepherd +tour = new Shepherd.Tour defaults: - classes: 'shepherd-element shepherd-open shepherd-theme-arrows' + classes: 'shepherd-theme-arrows' scrollTo: true ``` - The main options you'll want to -set are the class names to be added to each step. To use the default -theme `shepherd-theme-arrows`, set `classes` to `"shepherd shepherd-open shepherd-theme-arrows"`. -Also, you'll want to set `scrollTo` to `true` if you want Shepherd to try to -scroll to step targets when it advances from one step to another. +The `defaults` option allows you to specify any options which should be applied +to all this tour's steps by default. -After creating an instance to work with, you'll add steps for each target you want. You can name steps if you want to be able shortcut to them later. +Next, add your steps: ```coffeescript -shepherd.addStep 'example-step', +tour.addStep 'example-step', text: 'This step is attached to the bottom of the .example-css-selector element.' attachTo: '.example-css-selector bottom' classes: 'example-step-extra-class' buttons: [ text: 'Next' - action: shepherd.next + action: tour.next ] ``` -Finally, to start the tour, just call `start`. +Finally, to start the tour, just call `start` on your `Tour` instance: ```coffeescript -shepherd.start() +tour.start() +``` + +### API + +#### Global Shepherd Object + +Shepherd exposes a single object onto the window, `Shepherd`. + +That global object fires several events to let you link up actions with events +occuring in _any_ tour: + +##### Methods + +- `Shepherd.on(eventName, handler, [context])`: Bind an event +- `Shepherd.off(eventName, [handler])`: Unbind an event +- `Shepherd.once(eventName, handler, [context])`: Bind just the next instance of an event + +##### Events + +The global Shepherd fires the following events whenever a `Tour` instance fires them. It adds to the object passed to the +event handlers a `tour` key pointing to the instance which fired the event: + +- `complete` +- `cancel` +- `hide` +- `show` +- `start` + +##### Current Tour + +The global `Shepherd` includes a property which is always set to the currently active tour, or null if there is no active tour: + +- `Shepherd.activeTour` + +#### Tour Instances + +##### Creation + +You create a `Tour` object for each tour you'd like to create. + +Tour's constructor accepts a hash of options: + +```javascript +myTour = new Shepherd.Tour({ options }) +``` + +##### Tour Options + +- `steps`: An array of Step instances to initialize the tour with +- `defaults`: Default options for Steps created through `addStep` + +##### Tour Methods + +- `addStep(id, options)`: Creates a new Step object with options. If you'd like you can also just pass an options hash which includes `id` as a key. +You can also pass an existing `Step` instance rather than `options`, but note that Shepherd does not support a Step being attached to multiple Tours. +- `getById(id)`: Return a step with a specific id +- `next()`: Advance to the next step, in the order they were added +- `back()`: Show the previous step, in the order they were added +- `cancel()`: Trigger cancel on the current step, hiding it without advancing +- `hide()`: Hide the current step +- `show([id])`: Show the step specified by id (if it's a string), or index (if it's a number) provided. Defaults to the first step. +- `start()`: Show the first step and begin the tour +- `getCurrentStep()`: Returns the currently shown step +- `on(eventName, handler, [context])`: Bind an event +- `off(eventName, [handler])`: Unbind an event +- `once(eventName, handler, [context])`: Bind just the next instance of an event + +##### Tour Events + +- `complete`: Triggered when the last step is advanced +- `cancel` +- `hide` +- `show`: Triggered with a hash of the `step` and the `previous` step +- `start` + +Steps are instances of the Step object. They are generally created by the `Tour::addStep` method, which returns the `Step` instance its +created. + +#### Steps + +##### Step Options + +- `text`: The text in the body of the step. It can either be an HTML string, or an array of +strings, each of which will become a `

` paragraph. +- `title`: The steps title. It becomes an `h3` at the top of the step. +- `attachTo`: What element the step should be attached to on the page. It can either be a string of the form +`"element on"`, or an object with those properties. For example: `".some #element left"`, or `{element: '.some #element', +on: 'left'}`. If you use the object syntax, `element` can also be a DOM element. If you don't specify an `attachTo` +the element will appear in the middle of the screen. +- `classes`: Extra classes to add to the step. `shepherd-theme-arrows` will give you our theme. +- `buttons`: An array of buttons to add to the step. By default we add a Next button which triggers `next()`, set this to false +to disable. Each button in the array is an object of the format: + - `text`: The HTML text of the button + - `classes`: Extra classes to apply to the `` + - `action`: A function executed when the button is clicked on + - `events`: A hash of events to bind onto the button, for example `{'mouseover': function(){}}`. Adding a click event to `events` when you + already have an `action` specified is not supported. +- `advanceOn`: An action which should advance shepherd to the next step. It can be of the form `"event selector"`, or an object with those +properies. For example: `"click .some-element"`, or `{element: '.some-element', event: 'click'}`. You can also always manually advance the +Tour by calling `myTour.next()`. +- `scrollTo`: Should the element be scrolled to when this step is shown? + +##### Step Methods + +- `show()`: Show this step +- `hide()`: Hide this step +- `cancel()`: Hide this step and trigger the `cancel` event +- `complete()`: Hide this step and trigger the `complete` event +- `scrollTo()`: Scroll to this step's element +- `isOpen()`: Returns true if the step is currently shown +- `destroy()`: Remove the element +- `on(eventName, handler, [context])`: Bind an event +- `off(eventName, [handler])`: Unbind an event +- `once(eventName, handler, [context])`: Bind just the next instance of an event + +##### Step Events + +- `show` +- `hide` +- `complete` +- `cancel` +- `destroy` + +Please note that `complete` and `cancel` are only ever triggered if you call the associated methods in your code. + +### Advancing on Actions + +You can use the `advanceOn` option, or the Next button, to advance steps. If you would like however to have a step advance on a +complex user action, you can do the following: + +```coffeescript +myStep = myTour.addStep 'my-step', options + +yourApp.on 'some-event', -> + if myStep.isOpen() + Shepherd.activeTour.next() ``` ### Browser Support -Same as Tether: IE9+, Chrome, Firefox, Opera. \ No newline at end of file +IE9+ and all modern browsers diff --git a/docs/welcome/coffee/welcome.coffee b/docs/welcome/coffee/welcome.coffee index 8dbeea620..f6d092fa5 100644 --- a/docs/welcome/coffee/welcome.coffee +++ b/docs/welcome/coffee/welcome.coffee @@ -2,7 +2,7 @@ init = -> setupShepherd() setupShepherd = -> - shepherd = new Shepherd + shepherd = new Shepherd.Tour defaults: classes: 'shepherd-element shepherd-open shepherd-theme-arrows' scrollTo: true diff --git a/docs/welcome/css/welcome.css b/docs/welcome/css/welcome.css index c9fc53e19..3749792ba 100644 --- a/docs/welcome/css/welcome.css +++ b/docs/welcome/css/welcome.css @@ -1,10 +1,7 @@ -/* line 3, ../sass/welcome.sass */ html, body { height: 100%; - overflow: hidden; -} + overflow: hidden; } -/* line 7, ../sass/welcome.sass */ body { margin: 0; background-color: #62c462; @@ -12,10 +9,8 @@ body { background-image: -moz-linear-gradient(-45deg, #62c462, #75beaa); background-image: -o-linear-gradient(-45deg, #62c462, #75beaa); background-image: linear-gradient(-45deg, #62c462, #75beaa); - font-family: "proxima-nova", "Helvetica Neue", sans-serif; -} + font-family: "proxima-nova", "Helvetica Neue", sans-serif; } -/* line 13, ../sass/welcome.sass */ .button { display: inline-block; border: 2px solid white; @@ -28,29 +23,20 @@ body { cursor: pointer; width: 140px; font-size: 0.8em; - line-height: 1.3em; -} -/* line 27, ../sass/welcome.sass */ -.button.dark { - background: white; - color: #75beaa; -} -@media (max-width: 568px) { - /* line 27, ../sass/welcome.sass */ + line-height: 1.3em; } .button.dark { - display: none; - } -} + background: white; + color: #75beaa; } + @media (max-width: 568px) { + .button.dark { + display: none; } } -/* line 34, ../sass/welcome.sass */ .hero-scroll { height: 100%; width: 100%; -webkit-overflow-scrolling: touch; - overflow: auto; -} + overflow: auto; } -/* line 40, ../sass/welcome.sass */ .hero-outer { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; @@ -58,82 +44,49 @@ body { padding: 20px 0; height: 100%; width: 100%; - display: table; -} -/* line 47, ../sass/welcome.sass */ -.hero-outer .hero-inner { - display: table-cell; - text-align: center; - vertical-align: middle; -} -/* line 52, ../sass/welcome.sass */ -.hero-outer .hero-inner h1, .hero-outer .hero-inner h2, .hero-outer .hero-inner h3, .hero-outer .hero-inner p { - margin: 0 0 20px; - line-height: 1; - color: white; - font-weight: normal; -} -/* line 58, ../sass/welcome.sass */ -.hero-outer .hero-inner h3 { - font-size: 1.3em; - padding-top: 13px; -} -/* line 62, ../sass/welcome.sass */ -.hero-outer .hero-inner h1 { - padding-top: 10px; -} -/* line 65, ../sass/welcome.sass */ -.hero-outer .hero-inner > * { - -webkit-transition: opacity 0.4s; - -moz-transition: opacity 0.4s; - -o-transition: opacity 0.4s; - transition: opacity 0.4s; - opacity: 0.3; -} -/* line 69, ../sass/welcome.sass */ -body.shepherd-completed .hero-outer .hero-inner > * { - opacity: 1; -} -/* line 72, ../sass/welcome.sass */ -.hero-outer .hero-inner .shepherd-target.shepherd-enabled { - opacity: 1; -} -/* line 75, ../sass/welcome.sass */ -.hero-outer .hero-inner pre { - width: 540px; - margin: 0 auto 1em; -} -@media (max-width: 600px) { - /* line 75, ../sass/welcome.sass */ - .hero-outer .hero-inner pre { - width: 340px; - } -} -@media (max-width: 360px) { - /* line 75, ../sass/welcome.sass */ - .hero-outer .hero-inner pre { - width: 200px; - } -} -/* line 85, ../sass/welcome.sass */ -.hero-outer .hero-inner .hero-followup { - padding-top: 20px; -} + display: table; } + .hero-outer .hero-inner { + display: table-cell; + text-align: center; + vertical-align: middle; } + .hero-outer .hero-inner h1, .hero-outer .hero-inner h2, .hero-outer .hero-inner h3, .hero-outer .hero-inner p { + margin: 0 0 20px; + line-height: 1; + color: white; + font-weight: normal; } + .hero-outer .hero-inner h3 { + font-size: 1.3em; + padding-top: 13px; } + .hero-outer .hero-inner h1 { + padding-top: 10px; } + .hero-outer .hero-inner > * { + -webkit-transition: opacity 0.4s; + -moz-transition: opacity 0.4s; + -o-transition: opacity 0.4s; + transition: opacity 0.4s; + opacity: 0.3; } + body.shepherd-completed .hero-outer .hero-inner > * { + opacity: 1; } + .hero-outer .hero-inner .shepherd-target.shepherd-enabled { + opacity: 1; } + .hero-outer .hero-inner pre { + width: 540px; + margin: 0 auto 1em; } + @media (max-width: 600px) { + .hero-outer .hero-inner pre { + width: 340px; } } + @media (max-width: 360px) { + .hero-outer .hero-inner pre { + width: 200px; } } + .hero-outer .hero-inner .hero-followup { + padding-top: 20px; } -/* line 90, ../sass/welcome.sass */ .shepherd-element.shepherd-theme-arrows.shepherd-transparent-text .shepherd-text { - color: #3b744f; -} -/* line 93, ../sass/welcome.sass */ + color: #3b744f; } .shepherd-element.shepherd-theme-arrows .shepherd-content { width: 400px; - max-width: 100%; -} -/* line 97, ../sass/welcome.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content a { - color: inherit; -} -/* line 100, ../sass/welcome.sass */ -.shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li .shepherd-button { - background: #55a892; -} + max-width: 100%; } + .shepherd-element.shepherd-theme-arrows .shepherd-content a { + color: inherit; } + .shepherd-element.shepherd-theme-arrows .shepherd-content footer .shepherd-buttons li .shepherd-button { + background: #55a892; } diff --git a/docs/welcome/index.html b/docs/welcome/index.html index aa818ce0a..a0f4066db 100644 --- a/docs/welcome/index.html +++ b/docs/welcome/index.html @@ -30,12 +30,11 @@

Guide your users through a tour of your app.

Including

<link rel="stylesheet" href="shepherd-theme-arrows.css" />
-<script src="tether.min.js"></script>
 <script src="shepherd.min.js"></script>

Example

-
shepherd = new Shepherd
+
shepherd = new Shepherd.Tour
   defaults:
     classes: 'shepherd-element shepherd-open shepherd-theme-arrows'
     scrollTo: true
@@ -76,9 +75,6 @@ 

Example

- - - diff --git a/docs/welcome/js/welcome.js b/docs/welcome/js/welcome.js index 9cd36d8c7..168f6e351 100644 --- a/docs/welcome/js/welcome.js +++ b/docs/welcome/js/welcome.js @@ -7,7 +7,7 @@ setupShepherd = function() { var shepherd; - shepherd = new Shepherd({ + shepherd = new Shepherd.Tour({ defaults: { classes: 'shepherd-element shepherd-open shepherd-theme-arrows', scrollTo: true diff --git a/gulpfile.coffee b/gulpfile.coffee new file mode 100644 index 000000000..1f3d0faa9 --- /dev/null +++ b/gulpfile.coffee @@ -0,0 +1,70 @@ +gulp = require('gulp') +coffee = require('gulp-coffee') +compass = require('gulp-compass') +concat = require('gulp-concat') +uglify = require('gulp-uglify') +header = require('gulp-header') +rename = require('gulp-rename') +bower = require('gulp-bower') +gutil = require('gulp-util') + +pkg = require('./package.json') +banner = "/*! #{ pkg.name } #{ pkg.version } */\n" + +gulp.task 'bower', -> + bower().pipe(gulp.dest('./bower_components')) + +gulp.task 'coffee', -> + try + gulp.src('./coffee/*') + .pipe(coffee().on('error', gutil.log)) + .pipe(gulp.dest('./js/')) + + gulp.src('./docs/welcome/coffee/*') + .pipe(coffee()) + .pipe(gulp.dest('./docs/welcome/js/')) + catch e + +gulp.task 'concat', -> + gulp.src(['./bower_components/tether/tether.js', 'js/shepherd.js']) + .pipe(concat('shepherd.js')) + .pipe(header(banner)) + .pipe(gulp.dest('./')) + +gulp.task 'uglify', -> + gulp.src('./shepherd.js') + .pipe(uglify()) + .pipe(header(banner)) + .pipe(rename('shepherd.min.js')) + .pipe(gulp.dest('./')) + +gulp.task 'js', -> + gulp.run 'coffee', -> + gulp.run 'concat', -> + gulp.run 'uglify', -> + +gulp.task 'compass', -> + for path in ['', 'docs/welcome/'] + gulp.src("./#{ path }sass/*") + .pipe(compass( + sass: "#{ path }sass" + css: "#{ path }css" + comments: false + )) + .pipe(gulp.dest("./#{ path }css")) + +gulp.task 'default', -> + gulp.run 'bower', -> + gulp.run 'js', 'compass', -> + + gulp.watch './**/*.coffee', -> + gulp.run 'js' + + gulp.watch './**/*.sass', -> + gulp.run 'compass' + + gulp.watch './bower.json', -> + gulp.run 'bower' + + gulp.watch './package.json', -> + gulp.run 'js' diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 000000000..cfbdf8719 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,2 @@ +require('coffee-script') +require('./gulpfile.coffee') diff --git a/js/shepherd.js b/js/shepherd.js new file mode 100644 index 000000000..8a1c6956a --- /dev/null +++ b/js/shepherd.js @@ -0,0 +1,463 @@ +(function() { + var ATTACHMENT, Evented, Shepherd, Step, Tour, addClass, createFromHTML, extend, matchesSelector, parseShorthand, removeClass, uniqueId, _ref, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + + _ref = Tether.Utils, extend = _ref.extend, removeClass = _ref.removeClass, addClass = _ref.addClass, Evented = _ref.Evented; + + ATTACHMENT = { + 'top': 'top center', + 'left': 'middle right', + 'right': 'middle left', + 'bottom': 'bottom center' + }; + + uniqueId = (function() { + var id; + id = 0; + return function() { + return id++; + }; + })(); + + createFromHTML = function(html) { + var el; + el = document.createElement('div'); + el.innerHTML = html; + return el.children[0]; + }; + + matchesSelector = function(el, sel) { + var matches, _ref1, _ref2, _ref3, _ref4; + matches = (_ref1 = (_ref2 = (_ref3 = (_ref4 = el.matches) != null ? _ref4 : el.matchesSelector) != null ? _ref3 : el.webkitMatchesSelector) != null ? _ref2 : el.mozMatchesSelector) != null ? _ref1 : el.oMatchesSelector; + return matches.call(el, sel); + }; + + parseShorthand = function(obj, props) { + var i, out, prop, vals, _i, _len; + if (obj == null) { + return obj; + } else if (typeof obj === 'object') { + return obj; + } else { + vals = obj.split(' '); + if (vals.length > props.length) { + vals[0] = vals.slice(0, +(vals.length - props.length) + 1 || 9e9).join(' '); + vals.splice(1, vals.length - props.length); + } + out = {}; + for (i = _i = 0, _len = props.length; _i < _len; i = ++_i) { + prop = props[i]; + out[prop] = vals[i]; + } + return out; + } + }; + + Step = (function(_super) { + __extends(Step, _super); + + function Step(tour, options) { + this.tour = tour; + this.destroy = __bind(this.destroy, this); + this.scrollTo = __bind(this.scrollTo, this); + this.complete = __bind(this.complete, this); + this.cancel = __bind(this.cancel, this); + this.isOpen = __bind(this.isOpen, this); + this.hide = __bind(this.hide, this); + this.show = __bind(this.show, this); + this.setOptions(options); + this; + } + + Step.prototype.setOptions = function(options) { + var event, handler, _base, _ref1; + this.options = options != null ? options : {}; + this.destroy(); + this.id = this.options.id || this.id || ("step-" + (uniqueId())); + if (this.options.when) { + _ref1 = this.options.when; + for (event in _ref1) { + handler = _ref1[event]; + this.on(event, handler, this); + } + } + return (_base = this.options).buttons != null ? (_base = this.options).buttons : _base.buttons = [ + { + text: 'Next', + action: this.tour.next + } + ]; + }; + + Step.prototype.getTour = function() { + return this.tour; + }; + + Step.prototype.bindAdvance = function() { + var event, handler, selector, _ref1, + _this = this; + _ref1 = parseShorthand(this.options.advanceOn, ['event', 'selector']), event = _ref1.event, selector = _ref1.selector; + handler = function(e) { + if (!_this.isOpen()) { + return; + } + if (selector != null) { + if (matchesSelector(e.target, selector)) { + return _this.tour.next(); + } + } else { + if (_this.el && e.target === _this.el) { + return _this.tour.next(); + } + } + }; + document.body.addEventListener(event, handler); + return this.on('destroy', function() { + return document.body.removeEventListener(event, handler); + }); + }; + + Step.prototype.getAttachTo = function() { + var opts; + opts = parseShorthand(this.options.attachTo, ['element', 'on']); + if (opts == null) { + opts = {}; + } + if (typeof opts.element === 'string') { + opts.element = document.querySelector(opts.element); + if (opts.element == null) { + throw new Error("Shepherd step's attachTo was not found in the page"); + } + } + return opts; + }; + + Step.prototype.setupTether = function() { + var attachment, opts, tetherOpts; + if (typeof Tether === "undefined" || Tether === null) { + throw new Error("Using the attachment feature of Shepherd requires the Tether library"); + } + opts = this.getAttachTo(); + attachment = ATTACHMENT[opts.on || 'right']; + if (opts.element == null) { + opts.element = 'viewport'; + attachment = 'middle center'; + } + tetherOpts = { + classPrefix: 'shepherd', + element: this.el, + constraints: [ + { + to: 'window', + pin: true, + attachment: 'together' + } + ], + target: opts.element, + offset: opts.offset || '0 0', + attachment: attachment + }; + return this.tether = new Tether(extend(tetherOpts, this.options.tetherOptions)); + }; + + Step.prototype.show = function() { + var _ref1, + _this = this; + if (this.el == null) { + this.render(); + } + addClass(this.el, 'shepherd-open'); + if ((_ref1 = this.tether) != null) { + _ref1.enable(); + } + if (this.options.scrollTo) { + setTimeout(function() { + return _this.scrollTo(); + }); + } + return this.trigger('show'); + }; + + Step.prototype.hide = function() { + var _ref1; + removeClass(this.el, 'shepherd-open'); + if ((_ref1 = this.tether) != null) { + _ref1.disable(); + } + return this.trigger('hide'); + }; + + Step.prototype.isOpen = function() { + return hasClass(this.el, 'shepherd-open'); + }; + + Step.prototype.cancel = function() { + this.hide(); + return this.trigger('cancel'); + }; + + Step.prototype.complete = function() { + this.hide(); + return this.trigger('complete'); + }; + + Step.prototype.scrollTo = function() { + var $attachTo, elHeight, elLeft, elTop, element, height, left, offset, top, _ref1; + element = this.getAttachTo().element; + if (element == null) { + return; + } + $attachTo = jQuery(element); + _ref1 = $attachTo.offset(), top = _ref1.top, left = _ref1.left; + height = $attachTo.outerHeight(); + offset = $(this.el).offset(); + elTop = offset.top; + elLeft = offset.left; + elHeight = $(this.el).outerHeight(); + if (top < pageYOffset || elTop < pageYOffset) { + return jQuery(document.body).scrollTop(Math.min(top, elTop) - 10); + } else if ((top + height) > (pageYOffset + innerHeight) || (elTop + elHeight) > (pageYOffset + innerHeight)) { + return jQuery(document.body).scrollTop(Math.max(top + height, elTop + elHeight) - innerHeight + 10); + } + }; + + Step.prototype.destroy = function() { + var _ref1; + if (this.el != null) { + document.body.removeChild(this.el); + delete this.el; + } + if ((_ref1 = this.tether) != null) { + _ref1.destroy(); + } + return this.trigger('destroy'); + }; + + Step.prototype.render = function() { + var button, buttons, cfg, content, footer, header, paragraph, paragraphs, text, _i, _j, _len, _len1, _ref1, _ref2, _ref3; + if (this.el != null) { + this.destroy(); + } + this.el = createFromHTML("
"); + content = document.createElement('div'); + content.className = 'shepherd-content'; + this.el.appendChild(content); + if (this.options.title != null) { + header = document.createElement('header'); + header.innerHTML = "

" + this.options.title + "

"; + this.el.className += ' shepherd-has-title'; + content.appendChild(header); + } + if (this.options.text != null) { + text = createFromHTML("
"); + paragraphs = this.options.text; + if (typeof paragraphs === 'string') { + paragraphs = [paragraphs]; + } + for (_i = 0, _len = paragraphs.length; _i < _len; _i++) { + paragraph = paragraphs[_i]; + text.innerHTML += "

" + paragraph + "

"; + } + content.appendChild(text); + } + footer = document.createElement('footer'); + if (this.options.buttons) { + buttons = createFromHTML("
    "); + _ref2 = this.options.buttons; + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + cfg = _ref2[_j]; + button = createFromHTML("
  • " + cfg.text + ""); + buttons.appendChild(button); + this.bindButtonEvents(cfg, button.querySelector('a')); + } + footer.appendChild(buttons); + } + content.appendChild(footer); + document.body.appendChild(this.el); + this.setupTether(); + if (this.options.advanceOn) { + return this.bindAdvance(); + } + }; + + Step.prototype.bindButtonEvents = function(cfg, el) { + var event, handler, page, _ref1, + _this = this; + if (cfg.events == null) { + cfg.events = {}; + } + if (cfg.action != null) { + cfg.events.click = cfg.action; + } + _ref1 = cfg.events; + for (event in _ref1) { + handler = _ref1[event]; + if (typeof handler === 'string') { + page = handler; + handler = function() { + return _this.tour.show(page); + }; + } + el.addEventListener(event, handler); + } + return this.on('destroy', function() { + var _ref2, _results; + _ref2 = cfg.events; + _results = []; + for (event in _ref2) { + handler = _ref2[event]; + _results.push(el.removeEventListener(event, handler)); + } + return _results; + }); + }; + + return Step; + + })(Evented); + + Tour = (function(_super) { + __extends(Tour, _super); + + function Tour(options) { + var event, _i, _len, _ref1, _ref2, + _this = this; + this.options = options != null ? options : {}; + this.hide = __bind(this.hide, this); + this.cancel = __bind(this.cancel, this); + this.back = __bind(this.back, this); + this.next = __bind(this.next, this); + this.steps = (_ref1 = this.options.steps) != null ? _ref1 : []; + _ref2 = ['complete', 'cancel', 'hide', 'start', 'show']; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + event = _ref2[_i]; + this.on(event, function(opts) { + if (opts == null) { + opts = {}; + } + opts.tour = _this; + return Shepherd.trigger(event, opts); + }); + } + this; + } + + Tour.prototype.addStep = function(name, step) { + var _ref1; + if (step == null) { + step = name; + } + if (!(step instanceof Step)) { + if ((_ref1 = typeof name) === 'string' || _ref1 === 'number') { + step.id = name.toString(); + } + step = extend({}, this.options.defaults, step); + step = new Step(this, step); + } else { + step.tour = this; + } + this.steps.push(step); + return step; + }; + + Tour.prototype.getById = function(id) { + var step, _i, _len, _ref1; + _ref1 = this.steps; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + step = _ref1[_i]; + if (step.id === id) { + return step; + } + } + }; + + Tour.prototype.getCurrentStep = function() { + return this.currentStep; + }; + + Tour.prototype.next = function() { + var index; + index = this.steps.indexOf(this.currentStep); + if (index === this.steps.length - 1) { + this.hide(index); + this.trigger('complete'); + return this.done(); + } else { + return this.show(index + 1); + } + }; + + Tour.prototype.back = function() { + var index; + index = this.steps.indexOf(this.currentStep); + return this.show(index - 1); + }; + + Tour.prototype.cancel = function() { + var _ref1; + if ((_ref1 = this.currentStep) != null) { + _ref1.cancel(); + } + this.trigger('cancel'); + return this.done(); + }; + + Tour.prototype.hide = function() { + var _ref1; + if ((_ref1 = this.currentStep) != null) { + _ref1.hide(); + } + this.trigger('hide'); + return this.done(); + }; + + Tour.prototype.done = function() { + return Shepherd.activeTour = null; + }; + + Tour.prototype.show = function(key) { + var next; + if (key == null) { + key = 0; + } + if (this.currentStep) { + this.currentStep.hide(); + } + Shepherd.activeTour = this; + if (typeof key === 'string') { + next = this.getById(key); + } else { + next = this.steps[key]; + } + if (next) { + this.trigger('show', { + step: next, + previous: this.currentStep + }); + this.currentStep = next; + return next.show(); + } + }; + + Tour.prototype.start = function() { + this.trigger('start'); + this.currentStep = null; + return this.next(); + }; + + return Tour; + + })(Evented); + + Shepherd = new Evented; + + extend(Shepherd, { + Tour: Tour, + Step: Step + }); + + window.Shepherd = Shepherd; + +}).call(this); diff --git a/package.json b/package.json index da6086ed7..bab1d5727 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shepherd", - "version": "0.2.1", + "version": "0.3.0", "description": "Guide your users through a tour of your app.", "authors": [ "Adam Schwartz ", @@ -8,13 +8,15 @@ ], "license": "MIT", "devDependencies": { - "grunt-contrib-coffee": "~0.7.0", "coffee-script": "~1.6.3", - "grunt-contrib-uglify": "~0.2.4", - "grunt-cli": "~0.1.9", - "grunt": "", - "grunt-contrib-watch": "~0.5.3", - "grunt-contrib-compass": "~0.5.0", - "grunt-bower-task": "~0.3.4" + "gulp": "~3.4.0", + "gulp-header": "~1.0.2", + "gulp-uglify": "~0.1.0", + "gulp-compass": "~1.0.3", + "gulp-coffee": "~1.2.5", + "gulp-concat": "~2.1.7", + "gulp-rename": "~0.2.1", + "gulp-util": "~2.2.9", + "gulp-bower": "0.0.1" } } diff --git a/sass/shepherd-theme-arrows.sass b/sass/shepherd-theme-arrows.sass index 603f3aa31..b1af6e3d9 100644 --- a/sass/shepherd-theme-arrows.sass +++ b/sass/shepherd-theme-arrows.sass @@ -1,12 +1,12 @@ @import compass/css3 @import compass/utilities/general/clearfix -@import ../deps/tether/sass/mixins/pointer-events +@import ../bower_components/tether/sass/mixins/pointer-events // Bring in base shepherd styles come from a tether helpers -@import ../deps/tether/sass/helpers/tether -@import ../deps/tether/sass/helpers/tether-theme-arrows +@import ../bower_components/tether/sass/helpers/tether +@import ../bower_components/tether/sass/helpers/tether-theme-arrows $themePrefix: "shepherd" $arrowSize: 16px @@ -90,4 +90,4 @@ $headerBackgroundColor: #eee color: #888 &:last-child .shepherd-button - margin-right: 0 \ No newline at end of file + margin-right: 0 diff --git a/shepherd.js b/shepherd.js index 96d80fd7f..386d41cb0 100644 --- a/shepherd.js +++ b/shepherd.js @@ -1,5 +1,1357 @@ +/*! shepherd 0.3.0 */ +/*! tether 0.4.8 */ (function() { - var ATTACHMENT, Evented, Shepherd, Step, addClass, createFromHTML, extend, matchesSelector, parseShorthand, removeClass, uniqueId, _ref, + var Evented, addClass, defer, deferred, extend, flush, getBounds, getOffsetParent, getOrigin, getScrollParent, hasClass, node, removeClass, uniqueId, updateClasses, zeroPosCache, + __hasProp = {}.hasOwnProperty, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, + __slice = [].slice; + + if (window.Tether == null) { + window.Tether = {}; + } + + getScrollParent = function(el) { + var parent, position, scrollParent, style, _ref; + position = getComputedStyle(el).position; + if (position === 'fixed') { + return el; + } + scrollParent = void 0; + parent = el; + while (parent = parent.parentNode) { + try { + style = getComputedStyle(parent); + } catch (_error) {} + if (style == null) { + return parent; + } + if (/(auto|scroll)/.test(style['overflow'] + style['overflow-y'] + style['overflow-x'])) { + if (position !== 'absolute' || ((_ref = style['position']) === 'relative' || _ref === 'absolute' || _ref === 'fixed')) { + return parent; + } + } + } + return document.body; + }; + + uniqueId = (function() { + var id; + id = 0; + return function() { + return id++; + }; + })(); + + zeroPosCache = {}; + + getOrigin = function(doc) { + var id, k, node, v, _ref; + node = doc._tetherZeroElement; + if (node == null) { + node = doc.createElement('div'); + node.setAttribute('data-tether-id', uniqueId()); + extend(node.style, { + top: 0, + left: 0, + position: 'absolute' + }); + doc.body.appendChild(node); + doc._tetherZeroElement = node; + } + id = node.getAttribute('data-tether-id'); + if (zeroPosCache[id] == null) { + zeroPosCache[id] = {}; + _ref = node.getBoundingClientRect(); + for (k in _ref) { + v = _ref[k]; + zeroPosCache[id][k] = v; + } + defer(function() { + return zeroPosCache[id] = void 0; + }); + } + return zeroPosCache[id]; + }; + + node = null; + + getBounds = function(el) { + var box, doc, docEl, k, origin, v, _ref; + if (el === document) { + doc = document; + el = document.documentElement; + } else { + doc = el.ownerDocument; + } + docEl = doc.documentElement; + box = {}; + _ref = el.getBoundingClientRect(); + for (k in _ref) { + v = _ref[k]; + box[k] = v; + } + origin = getOrigin(doc); + box.top -= origin.top; + box.left -= origin.left; + box.top = box.top - docEl.clientTop; + box.left = box.left - docEl.clientLeft; + box.right = doc.body.clientWidth - box.width - box.left; + box.bottom = doc.body.clientHeight - box.height - box.top; + return box; + }; + + getOffsetParent = function(el) { + return el.offsetParent || document.documentElement; + }; + + extend = function(out) { + var args, key, obj, val, _i, _len, _ref; + if (out == null) { + out = {}; + } + args = []; + Array.prototype.push.apply(args, arguments); + _ref = args.slice(1); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + obj = _ref[_i]; + if (obj) { + for (key in obj) { + if (!__hasProp.call(obj, key)) continue; + val = obj[key]; + out[key] = val; + } + } + } + return out; + }; + + removeClass = function(el, name) { + var cls, _i, _len, _ref, _results; + if (el.classList != null) { + _ref = name.split(' '); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + cls = _ref[_i]; + _results.push(el.classList.remove(cls)); + } + return _results; + } else { + return el.className = el.className.replace(new RegExp("(^| )" + (name.split(' ').join('|')) + "( |$)", 'gi'), ' '); + } + }; + + addClass = function(el, name) { + var cls, _i, _len, _ref, _results; + if (el.classList != null) { + _ref = name.split(' '); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + cls = _ref[_i]; + _results.push(el.classList.add(cls)); + } + return _results; + } else { + removeClass(el, name); + return el.className += " " + name; + } + }; + + hasClass = function(el, name) { + if (el.classList != null) { + return el.classList.contains(name); + } else { + return new RegExp("(^| )" + name + "( |$)", 'gi').test(el.className); + } + }; + + updateClasses = function(el, add, all) { + var cls, _i, _j, _len, _len1, _results; + for (_i = 0, _len = all.length; _i < _len; _i++) { + cls = all[_i]; + if (__indexOf.call(add, cls) < 0) { + if (hasClass(el, cls)) { + removeClass(el, cls); + } + } + } + _results = []; + for (_j = 0, _len1 = add.length; _j < _len1; _j++) { + cls = add[_j]; + if (!hasClass(el, cls)) { + _results.push(addClass(el, cls)); + } else { + _results.push(void 0); + } + } + return _results; + }; + + deferred = []; + + defer = function(fn) { + return deferred.push(fn); + }; + + flush = function() { + var fn, _results; + _results = []; + while (fn = deferred.pop()) { + _results.push(fn()); + } + return _results; + }; + + Evented = (function() { + function Evented() {} + + Evented.prototype.on = function(event, handler, ctx, once) { + var _base; + if (once == null) { + once = false; + } + if (this.bindings == null) { + this.bindings = {}; + } + if ((_base = this.bindings)[event] == null) { + _base[event] = []; + } + return this.bindings[event].push({ + handler: handler, + ctx: ctx, + once: once + }); + }; + + Evented.prototype.once = function(event, handler, ctx) { + return this.on(event, handler, ctx, true); + }; + + Evented.prototype.off = function(event, handler) { + var i, _ref, _results; + if (((_ref = this.bindings) != null ? _ref[event] : void 0) == null) { + return; + } + if (handler == null) { + return delete this.bindings[event]; + } else { + i = 0; + _results = []; + while (i < this.bindings[event].length) { + if (this.bindings[event][i].handler === handler) { + _results.push(this.bindings[event].splice(i, 1)); + } else { + _results.push(i++); + } + } + return _results; + } + }; + + Evented.prototype.trigger = function() { + var args, ctx, event, handler, i, once, _ref, _ref1, _results; + event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + if ((_ref = this.bindings) != null ? _ref[event] : void 0) { + i = 0; + _results = []; + while (i < this.bindings[event].length) { + _ref1 = this.bindings[event][i], handler = _ref1.handler, ctx = _ref1.ctx, once = _ref1.once; + handler.apply(ctx != null ? ctx : this, args); + if (once) { + _results.push(this.bindings[event].splice(i, 1)); + } else { + _results.push(i++); + } + } + return _results; + } + }; + + return Evented; + + })(); + + Tether.Utils = { + getScrollParent: getScrollParent, + getBounds: getBounds, + getOffsetParent: getOffsetParent, + extend: extend, + addClass: addClass, + removeClass: removeClass, + hasClass: hasClass, + updateClasses: updateClasses, + defer: defer, + flush: flush, + uniqueId: uniqueId, + Evented: Evented + }; + +}).call(this); + +(function() { + var MIRROR_LR, MIRROR_TB, OFFSET_MAP, addClass, addOffset, attachmentToOffset, autoToFixedAttachment, defer, extend, flush, getBounds, getOffsetParent, getOuterSize, getScrollParent, getSize, now, offsetToPx, parseAttachment, parseOffset, position, removeClass, tethers, transformKey, updateClasses, within, _Tether, _ref, + __slice = [].slice, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + if (typeof Tether === "undefined" || Tether === null) { + throw new Error("You must include the utils.js file before tether.js"); + } + + _ref = Tether.Utils, getScrollParent = _ref.getScrollParent, getSize = _ref.getSize, getOuterSize = _ref.getOuterSize, getBounds = _ref.getBounds, getOffsetParent = _ref.getOffsetParent, extend = _ref.extend, addClass = _ref.addClass, removeClass = _ref.removeClass, updateClasses = _ref.updateClasses, defer = _ref.defer, flush = _ref.flush; + + within = function(a, b, diff) { + if (diff == null) { + diff = 1; + } + return (a + diff >= b && b >= a - diff); + }; + + transformKey = (function() { + var el, key, _i, _len, _ref1; + el = document.createElement('div'); + _ref1 = ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + key = _ref1[_i]; + if (el.style[key] !== void 0) { + return key; + } + } + })(); + + tethers = []; + + position = function() { + var tether, _i, _len; + for (_i = 0, _len = tethers.length; _i < _len; _i++) { + tether = tethers[_i]; + tether.position(false); + } + return flush(); + }; + + now = function() { + var _ref1; + return (_ref1 = typeof performance !== "undefined" && performance !== null ? typeof performance.now === "function" ? performance.now() : void 0 : void 0) != null ? _ref1 : +(new Date); + }; + + (function() { + var event, lastCall, lastDuration, pendingTimeout, tick, _i, _len, _ref1, _results; + lastCall = null; + lastDuration = null; + pendingTimeout = null; + tick = function() { + if ((lastDuration != null) && lastDuration > 16) { + lastDuration = Math.min(lastDuration - 16, 250); + pendingTimeout = setTimeout(tick, 250); + return; + } + if ((lastCall != null) && (now() - lastCall) < 10) { + return; + } + if (pendingTimeout != null) { + clearTimeout(pendingTimeout); + pendingTimeout = null; + } + lastCall = now(); + position(); + return lastDuration = now() - lastCall; + }; + _ref1 = ['resize', 'scroll']; + _results = []; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + event = _ref1[_i]; + _results.push(window.addEventListener(event, tick)); + } + return _results; + })(); + + MIRROR_LR = { + center: 'center', + left: 'right', + right: 'left' + }; + + MIRROR_TB = { + middle: 'middle', + top: 'bottom', + bottom: 'top' + }; + + OFFSET_MAP = { + top: 0, + left: 0, + middle: '50%', + center: '50%', + bottom: '100%', + right: '100%' + }; + + autoToFixedAttachment = function(attachment, relativeToAttachment) { + var left, top; + left = attachment.left, top = attachment.top; + if (left === 'auto') { + left = MIRROR_LR[relativeToAttachment.left]; + } + if (top === 'auto') { + top = MIRROR_TB[relativeToAttachment.top]; + } + return { + left: left, + top: top + }; + }; + + attachmentToOffset = function(attachment) { + var _ref1, _ref2; + return { + left: (_ref1 = OFFSET_MAP[attachment.left]) != null ? _ref1 : attachment.left, + top: (_ref2 = OFFSET_MAP[attachment.top]) != null ? _ref2 : attachment.top + }; + }; + + addOffset = function() { + var left, offsets, out, top, _i, _len, _ref1; + offsets = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + out = { + top: 0, + left: 0 + }; + for (_i = 0, _len = offsets.length; _i < _len; _i++) { + _ref1 = offsets[_i], top = _ref1.top, left = _ref1.left; + if (typeof top === 'string') { + top = parseFloat(top, 10); + } + if (typeof left === 'string') { + left = parseFloat(left, 10); + } + out.top += top; + out.left += left; + } + return out; + }; + + offsetToPx = function(offset, size) { + if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) { + offset.left = parseFloat(offset.left, 10) / 100 * size.width; + } + if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) { + offset.top = parseFloat(offset.top, 10) / 100 * size.height; + } + return offset; + }; + + parseAttachment = parseOffset = function(value) { + var left, top, _ref1; + _ref1 = value.split(' '), top = _ref1[0], left = _ref1[1]; + return { + top: top, + left: left + }; + }; + + _Tether = (function() { + _Tether.modules = []; + + function _Tether(options) { + this.position = __bind(this.position, this); + var module, _i, _len, _ref1, _ref2; + tethers.push(this); + this.history = []; + this.setOptions(options, false); + _ref1 = Tether.modules; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + module = _ref1[_i]; + if ((_ref2 = module.initialize) != null) { + _ref2.call(this); + } + } + this.position(); + } + + _Tether.prototype.getClass = function(key) { + var _ref1, _ref2; + if ((_ref1 = this.options.classes) != null ? _ref1[key] : void 0) { + return this.options.classes[key]; + } else if (((_ref2 = this.options.classes) != null ? _ref2[key] : void 0) !== false) { + if (this.options.classPrefix) { + return "" + this.options.classPrefix + "-" + key; + } else { + return key; + } + } else { + return ''; + } + }; + + _Tether.prototype.setOptions = function(options, position) { + var defaults, key, _i, _len, _ref1, _ref2; + this.options = options; + if (position == null) { + position = true; + } + defaults = { + offset: '0 0', + targetOffset: '0 0', + targetAttachment: 'auto auto', + classPrefix: 'tether' + }; + this.options = extend(defaults, this.options); + _ref1 = this.options, this.element = _ref1.element, this.target = _ref1.target, this.targetModifier = _ref1.targetModifier; + if (this.target === 'viewport') { + this.target = document.body; + this.targetModifier = 'visible'; + } else if (this.target === 'scroll-handle') { + this.target = document.body; + this.targetModifier = 'scroll-handle'; + } + _ref2 = ['element', 'target']; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + key = _ref2[_i]; + if (this[key] == null) { + throw new Error("Tether Error: Both element and target must be defined"); + } + if (this[key].jquery != null) { + this[key] = this[key][0]; + } else if (typeof this[key] === 'string') { + this[key] = document.querySelector(this[key]); + } + } + addClass(this.element, this.getClass('element')); + addClass(this.target, this.getClass('target')); + if (!this.options.attachment) { + throw new Error("Tether Error: You must provide an attachment"); + } + this.targetAttachment = parseAttachment(this.options.targetAttachment); + this.attachment = parseAttachment(this.options.attachment); + this.offset = parseOffset(this.options.offset); + this.targetOffset = parseOffset(this.options.targetOffset); + if (this.scrollParent != null) { + this.disable(); + } + if (this.targetModifier === 'scroll-handle') { + this.scrollParent = this.target; + } else { + this.scrollParent = getScrollParent(this.target); + } + if (this.options.enabled !== false) { + return this.enable(position); + } + }; + + _Tether.prototype.getTargetBounds = function() { + var bounds, fitAdj, hasBottomScroll, height, out, scrollBottom, scrollPercentage, style, target; + if (this.targetModifier != null) { + switch (this.targetModifier) { + case 'visible': + if (this.target === document.body) { + return { + top: pageYOffset, + left: pageXOffset, + height: innerHeight, + width: innerWidth + }; + } else { + bounds = getBounds(this.target); + out = { + height: bounds.height, + width: bounds.width, + top: bounds.top, + left: bounds.left + }; + out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top)); + out.height = Math.min(out.height, bounds.height - ((bounds.top + bounds.height) - (pageYOffset + innerHeight))); + out.height = Math.min(innerHeight, out.height); + out.height -= 2; + out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left)); + out.width = Math.min(out.width, bounds.width - ((bounds.left + bounds.width) - (pageXOffset + innerWidth))); + out.width = Math.min(innerWidth, out.width); + out.width -= 2; + if (out.top < pageYOffset) { + out.top = pageYOffset; + } + if (out.left < pageXOffset) { + out.left = pageXOffset; + } + return out; + } + break; + case 'scroll-handle': + target = this.target; + if (target === document.body) { + target = document.documentElement; + bounds = { + left: pageXOffset, + top: pageYOffset, + height: innerHeight, + width: innerWidth + }; + } else { + bounds = getBounds(target); + } + style = getComputedStyle(target); + hasBottomScroll = target.scrollWidth > target.clientWidth || 'scroll' === [style.overflow, style.overflowX] || this.target !== document.body; + scrollBottom = 0; + if (hasBottomScroll) { + scrollBottom = 15; + } + height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom; + out = { + width: 15, + height: height * 0.975 * (height / target.scrollHeight), + left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15 + }; + fitAdj = 0; + if (height < 408 && this.target === document.body) { + fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58; + } + if (this.target !== document.body) { + out.height = Math.max(out.height, 24); + } + scrollPercentage = target.scrollTop / (target.scrollHeight - height); + out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth); + if (this.target === document.body) { + out.height = Math.max(out.height, 24); + } + return out; + } + } else { + return getBounds(this.target); + } + }; + + _Tether.prototype.clearCache = function() { + return this._cache = {}; + }; + + _Tether.prototype.cache = function(k, getter) { + if (this._cache == null) { + this._cache = {}; + } + if (this._cache[k] == null) { + this._cache[k] = getter.call(this); + } + return this._cache[k]; + }; + + _Tether.prototype.enable = function(position) { + if (position == null) { + position = true; + } + addClass(this.target, this.getClass('enabled')); + addClass(this.element, this.getClass('enabled')); + this.enabled = true; + if (this.scrollParent !== document) { + this.scrollParent.addEventListener('scroll', this.position); + } + if (position) { + return this.position(); + } + }; + + _Tether.prototype.disable = function() { + removeClass(this.target, this.getClass('enabled')); + removeClass(this.element, this.getClass('enabled')); + this.enabled = false; + if (this.scrollParent != null) { + return this.scrollParent.removeEventListener('scroll', this.position); + } + }; + + _Tether.prototype.destroy = function() { + var i, tether, _i, _len, _results; + this.disable(); + _results = []; + for (i = _i = 0, _len = tethers.length; _i < _len; i = ++_i) { + tether = tethers[i]; + if (tether === this) { + tethers.splice(i, 1); + break; + } else { + _results.push(void 0); + } + } + return _results; + }; + + _Tether.prototype.updateAttachClasses = function(elementAttach, targetAttach) { + var add, all, side, sides, _i, _j, _len, _len1, _ref1, + _this = this; + if (elementAttach == null) { + elementAttach = this.attachment; + } + if (targetAttach == null) { + targetAttach = this.targetAttachment; + } + sides = ['left', 'top', 'bottom', 'right', 'middle', 'center']; + if ((_ref1 = this._addAttachClasses) != null ? _ref1.length : void 0) { + this._addAttachClasses.splice(0, this._addAttachClasses.length); + } + add = this._addAttachClasses != null ? this._addAttachClasses : this._addAttachClasses = []; + if (elementAttach.top) { + add.push("" + (this.getClass('element-attached')) + "-" + elementAttach.top); + } + if (elementAttach.left) { + add.push("" + (this.getClass('element-attached')) + "-" + elementAttach.left); + } + if (targetAttach.top) { + add.push("" + (this.getClass('target-attached')) + "-" + targetAttach.top); + } + if (targetAttach.left) { + add.push("" + (this.getClass('target-attached')) + "-" + targetAttach.left); + } + all = []; + for (_i = 0, _len = sides.length; _i < _len; _i++) { + side = sides[_i]; + all.push("" + (this.getClass('element-attached')) + "-" + side); + } + for (_j = 0, _len1 = sides.length; _j < _len1; _j++) { + side = sides[_j]; + all.push("" + (this.getClass('target-attached')) + "-" + side); + } + return defer(function() { + if (_this._addAttachClasses == null) { + return; + } + updateClasses(_this.element, _this._addAttachClasses, all); + updateClasses(_this.target, _this._addAttachClasses, all); + return _this._addAttachClasses = void 0; + }); + }; + + _Tether.prototype.position = function(flushChanges) { + var elementPos, elementStyle, height, left, manualOffset, manualTargetOffset, module, next, offset, offsetBorder, offsetParent, offsetParentSize, offsetParentStyle, offsetPosition, ret, scrollLeft, scrollTop, side, targetAttachment, targetOffset, targetPos, targetSize, top, width, _i, _j, _len, _len1, _ref1, _ref2, _ref3, _ref4, + _this = this; + if (flushChanges == null) { + flushChanges = true; + } + if (!this.enabled) { + return; + } + this.clearCache(); + targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment); + this.updateAttachClasses(this.attachment, targetAttachment); + elementPos = this.cache('element-bounds', function() { + return getBounds(_this.element); + }); + width = elementPos.width, height = elementPos.height; + if (width === 0 && height === 0 && (this.lastSize != null)) { + _ref1 = this.lastSize, width = _ref1.width, height = _ref1.height; + } else { + this.lastSize = { + width: width, + height: height + }; + } + targetSize = targetPos = this.cache('target-bounds', function() { + return _this.getTargetBounds(); + }); + offset = offsetToPx(attachmentToOffset(this.attachment), { + width: width, + height: height + }); + targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize); + manualOffset = offsetToPx(this.offset, { + width: width, + height: height + }); + manualTargetOffset = offsetToPx(this.targetOffset, targetSize); + offset = addOffset(offset, manualOffset); + targetOffset = addOffset(targetOffset, manualTargetOffset); + left = targetPos.left + targetOffset.left - offset.left; + top = targetPos.top + targetOffset.top - offset.top; + _ref2 = Tether.modules; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + module = _ref2[_i]; + ret = module.position.call(this, { + left: left, + top: top, + targetAttachment: targetAttachment, + targetPos: targetPos, + elementPos: elementPos, + offset: offset, + targetOffset: targetOffset, + manualOffset: manualOffset, + manualTargetOffset: manualTargetOffset + }); + if ((ret == null) || typeof ret !== 'object') { + continue; + } else if (ret === false) { + return false; + } else { + top = ret.top, left = ret.left; + } + } + next = { + page: { + top: top, + bottom: document.body.scrollHeight - top - height, + left: left, + right: document.body.scrollWidth - left - width + }, + viewport: { + top: top - pageYOffset, + bottom: pageYOffset - top - height + innerHeight, + left: left - pageXOffset, + right: pageXOffset - left - width + innerWidth + } + }; + if (((_ref3 = this.options.optimizations) != null ? _ref3.moveElement : void 0) !== false && (this.targetModifier == null)) { + offsetParent = this.cache('target-offsetparent', function() { + return getOffsetParent(_this.target); + }); + offsetPosition = this.cache('target-offsetparent-bounds', function() { + return getBounds(offsetParent); + }); + offsetParentStyle = getComputedStyle(offsetParent); + elementStyle = getComputedStyle(this.element); + offsetParentSize = offsetPosition; + offsetBorder = {}; + _ref4 = ['top', 'left', 'bottom', 'right']; + for (_j = 0, _len1 = _ref4.length; _j < _len1; _j++) { + side = _ref4[_j]; + offsetBorder[side] = parseFloat(offsetParentStyle["border-" + side + "-width"]); + } + offsetPosition.right = document.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right; + offsetPosition.bottom = document.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom; + if (next.page.top >= (offsetPosition.top + offsetBorder.top) && next.page.bottom >= offsetPosition.bottom) { + if (next.page.left >= (offsetPosition.left + offsetBorder.left) && next.page.right >= offsetPosition.right) { + scrollTop = offsetParent.scrollTop; + scrollLeft = offsetParent.scrollLeft; + next.offset = { + top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top, + left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left + }; + } + } + } + this.move(next); + this.history.unshift(next); + if (this.history.length > 3) { + this.history.pop(); + } + if (flushChanges) { + flush(); + } + return true; + }; + + _Tether.prototype.move = function(position) { + var css, elVal, found, key, moved, offsetParent, point, same, transcribe, type, val, write, writeCSS, _i, _len, _ref1, _ref2, + _this = this; + if (this.element.parentNode == null) { + return; + } + same = {}; + for (type in position) { + same[type] = {}; + for (key in position[type]) { + found = false; + _ref1 = this.history; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + point = _ref1[_i]; + if (!within((_ref2 = point[type]) != null ? _ref2[key] : void 0, position[type][key])) { + found = true; + break; + } + } + if (!found) { + same[type][key] = true; + } + } + } + css = { + top: '', + left: '', + right: '', + bottom: '' + }; + transcribe = function(same, pos) { + var xPos, yPos, _ref3; + if (((_ref3 = _this.options.optimizations) != null ? _ref3.gpu : void 0) !== false) { + if (same.top) { + css.top = 0; + yPos = pos.top; + } else { + css.bottom = 0; + yPos = -pos.bottom; + } + if (same.left) { + css.left = 0; + xPos = pos.left; + } else { + css.right = 0; + xPos = -pos.right; + } + css[transformKey] = "translateX(" + (Math.round(xPos)) + "px) translateY(" + (Math.round(yPos)) + "px)"; + if (transformKey !== 'msTransform') { + return css[transformKey] += " translateZ(0)"; + } + } else { + if (same.top) { + css.top = "" + pos.top + "px"; + } else { + css.bottom = "" + pos.bottom + "px"; + } + if (same.left) { + return css.left = "" + pos.left + "px"; + } else { + return css.right = "" + pos.right + "px"; + } + } + }; + moved = false; + if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) { + css.position = 'absolute'; + transcribe(same.page, position.page); + } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) { + css.position = 'fixed'; + transcribe(same.viewport, position.viewport); + } else if ((same.offset != null) && same.offset.top && same.offset.left) { + css.position = 'absolute'; + offsetParent = this.cache('target-offsetparent', function() { + return getOffsetParent(_this.target); + }); + if (getOffsetParent(this.element) !== offsetParent) { + defer(function() { + _this.element.parentNode.removeChild(_this.element); + return offsetParent.appendChild(_this.element); + }); + } + transcribe(same.offset, position.offset); + moved = true; + } else { + css.position = 'absolute'; + transcribe({ + top: true, + left: true + }, position.page); + } + if (!moved && this.element.parentNode.tagName !== 'BODY') { + this.element.parentNode.removeChild(this.element); + document.body.appendChild(this.element); + } + writeCSS = {}; + write = false; + for (key in css) { + val = css[key]; + elVal = this.element.style[key]; + if (elVal !== '' && val !== '' && (key === 'top' || key === 'left' || key === 'bottom' || key === 'right')) { + elVal = parseFloat(elVal); + val = parseFloat(val); + } + if (elVal !== val) { + write = true; + writeCSS[key] = css[key]; + } + } + if (write) { + return defer(function() { + return extend(_this.element.style, writeCSS); + }); + } + }; + + return _Tether; + + })(); + + Tether.position = position; + + window.Tether = extend(_Tether, Tether); + +}).call(this); + +(function() { + var BOUNDS_FORMAT, MIRROR_ATTACH, defer, extend, getBoundingRect, getBounds, getOuterSize, getSize, updateClasses, _ref, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + _ref = Tether.Utils, getOuterSize = _ref.getOuterSize, getBounds = _ref.getBounds, getSize = _ref.getSize, extend = _ref.extend, updateClasses = _ref.updateClasses, defer = _ref.defer; + + MIRROR_ATTACH = { + left: 'right', + right: 'left', + top: 'bottom', + bottom: 'top', + middle: 'middle' + }; + + BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom']; + + getBoundingRect = function(tether, to) { + var i, pos, side, size, style, _i, _len; + if (to === 'scrollParent') { + to = tether.scrollParent; + } else if (to === 'window') { + to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset]; + } + if (to === document) { + to = to.documentElement; + } + if (to.nodeType != null) { + pos = size = getBounds(to); + style = getComputedStyle(to); + to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top]; + for (i = _i = 0, _len = BOUNDS_FORMAT.length; _i < _len; i = ++_i) { + side = BOUNDS_FORMAT[i]; + if (side === 'top' || side === 'left') { + to[i] += parseFloat(style["border-" + side + "-width"]); + } else { + to[i] -= parseFloat(style["border-" + side + "-width"]); + } + } + } + return to; + }; + + Tether.modules.push({ + position: function(_arg) { + var addClasses, allClasses, attachment, bounds, changeAttachX, changeAttachY, cls, constraint, eAttachment, height, left, oob, oobClass, p, pin, pinned, pinnedClass, removeClass, side, tAttachment, targetAttachment, targetHeight, targetSize, targetWidth, to, top, width, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, + _this = this; + top = _arg.top, left = _arg.left, targetAttachment = _arg.targetAttachment; + if (!this.options.constraints) { + return true; + } + removeClass = function(prefix) { + var side, _i, _len, _results; + _this.removeClass(prefix); + _results = []; + for (_i = 0, _len = BOUNDS_FORMAT.length; _i < _len; _i++) { + side = BOUNDS_FORMAT[_i]; + _results.push(_this.removeClass("" + prefix + "-" + side)); + } + return _results; + }; + _ref1 = this.cache('element-bounds', function() { + return getBounds(_this.element); + }), height = _ref1.height, width = _ref1.width; + if (width === 0 && height === 0 && (this.lastSize != null)) { + _ref2 = this.lastSize, width = _ref2.width, height = _ref2.height; + } + targetSize = this.cache('target-bounds', function() { + return _this.getTargetBounds(); + }); + targetHeight = targetSize.height; + targetWidth = targetSize.width; + tAttachment = {}; + eAttachment = {}; + allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')]; + _ref3 = this.options.constraints; + for (_i = 0, _len = _ref3.length; _i < _len; _i++) { + constraint = _ref3[_i]; + if (constraint.outOfBoundsClass) { + allClasses.push(constraint.outOfBoundsClass); + } + if (constraint.pinnedClass) { + allClasses.push(constraint.pinnedClass); + } + } + for (_j = 0, _len1 = allClasses.length; _j < _len1; _j++) { + cls = allClasses[_j]; + _ref4 = ['left', 'top', 'right', 'bottom']; + for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { + side = _ref4[_k]; + allClasses.push("" + cls + "-" + side); + } + } + addClasses = []; + tAttachment = extend({}, targetAttachment); + eAttachment = extend({}, this.attachment); + _ref5 = this.options.constraints; + for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) { + constraint = _ref5[_l]; + to = constraint.to, attachment = constraint.attachment, pin = constraint.pin; + if (attachment == null) { + attachment = ''; + } + if (__indexOf.call(attachment, ' ') >= 0) { + _ref6 = attachment.split(' '), changeAttachY = _ref6[0], changeAttachX = _ref6[1]; + } else { + changeAttachX = changeAttachY = attachment; + } + bounds = getBoundingRect(this, to); + if (changeAttachY === 'target' || changeAttachY === 'both') { + if (top < bounds[1] && tAttachment.top === 'top') { + top += targetHeight; + tAttachment.top = 'bottom'; + } + if (top + height > bounds[3] && tAttachment.top === 'bottom') { + top -= targetHeight; + tAttachment.top = 'top'; + } + } + if (changeAttachY === 'together') { + if (top < bounds[1] && tAttachment.top === 'top') { + if (eAttachment.top === 'bottom') { + top += targetHeight; + tAttachment.top = 'bottom'; + top += height; + eAttachment.top = 'top'; + } else if (eAttachment.top === 'top') { + top += targetHeight; + tAttachment.top = 'bottom'; + top -= height; + eAttachment.top = 'bottom'; + } + } + if (top + height > bounds[3] && tAttachment.top === 'bottom') { + if (eAttachment.top === 'top') { + top -= targetHeight; + tAttachment.top = 'top'; + top -= height; + eAttachment.top = 'bottom'; + } else if (eAttachment.top === 'bottom') { + top -= targetHeight; + tAttachment.top = 'top'; + top += height; + eAttachment.top = 'top'; + } + } + } + if (changeAttachX === 'target' || changeAttachX === 'both') { + if (left < bounds[0] && tAttachment.left === 'left') { + left += targetWidth; + tAttachment.left = 'right'; + } + if (left + width > bounds[2] && tAttachment.left === 'right') { + left -= targetWidth; + tAttachment.left = 'left'; + } + } + if (changeAttachX === 'together') { + if (left < bounds[0] && tAttachment.left === 'left') { + if (eAttachment.left === 'right') { + left += targetWidth; + tAttachment.left = 'right'; + left += width; + eAttachment.left = 'left'; + } else if (eAttachment.left === 'left') { + left += targetWidth; + tAttachment.left = 'right'; + left -= width; + eAttachment.left = 'right'; + } + } else if (left + width > bounds[2] && tAttachment.left === 'right') { + if (eAttachment.left === 'left') { + left -= targetWidth; + tAttachment.left = 'left'; + left -= width; + eAttachment.left = 'right'; + } else if (eAttachment.left === 'right') { + left -= targetWidth; + tAttachment.left = 'left'; + left += width; + eAttachment.left = 'left'; + } + } + } + if (changeAttachY === 'element' || changeAttachY === 'both') { + if (top < bounds[1] && eAttachment.top === 'bottom') { + top += height; + eAttachment.top = 'top'; + } + if (top + height > bounds[3] && eAttachment.top === 'top') { + top -= height; + eAttachment.top = 'bottom'; + } + } + if (changeAttachX === 'element' || changeAttachX === 'both') { + if (left < bounds[0] && eAttachment.left === 'right') { + left += width; + eAttachment.left = 'left'; + } + if (left + width > bounds[2] && eAttachment.left === 'left') { + left -= width; + eAttachment.left = 'right'; + } + } + if (typeof pin === 'string') { + pin = (function() { + var _len4, _m, _ref7, _results; + _ref7 = pin.split(','); + _results = []; + for (_m = 0, _len4 = _ref7.length; _m < _len4; _m++) { + p = _ref7[_m]; + _results.push(p.trim()); + } + return _results; + })(); + } else if (pin === true) { + pin = ['top', 'left', 'right', 'bottom']; + } + pin || (pin = []); + pinned = []; + oob = []; + if (top < bounds[1]) { + if (__indexOf.call(pin, 'top') >= 0) { + top = bounds[1]; + pinned.push('top'); + } else { + oob.push('top'); + } + } + if (top + height > bounds[3]) { + if (__indexOf.call(pin, 'bottom') >= 0) { + top = bounds[3] - height; + pinned.push('bottom'); + } else { + oob.push('bottom'); + } + } + if (left < bounds[0]) { + if (__indexOf.call(pin, 'left') >= 0) { + left = bounds[0]; + pinned.push('left'); + } else { + oob.push('left'); + } + } + if (left + width > bounds[2]) { + if (__indexOf.call(pin, 'right') >= 0) { + left = bounds[2] - width; + pinned.push('right'); + } else { + oob.push('right'); + } + } + if (pinned.length) { + pinnedClass = (_ref7 = this.options.pinnedClass) != null ? _ref7 : this.getClass('pinned'); + addClasses.push(pinnedClass); + for (_m = 0, _len4 = pinned.length; _m < _len4; _m++) { + side = pinned[_m]; + addClasses.push("" + pinnedClass + "-" + side); + } + } + if (oob.length) { + oobClass = (_ref8 = this.options.outOfBoundsClass) != null ? _ref8 : this.getClass('out-of-bounds'); + addClasses.push(oobClass); + for (_n = 0, _len5 = oob.length; _n < _len5; _n++) { + side = oob[_n]; + addClasses.push("" + oobClass + "-" + side); + } + } + if (__indexOf.call(pinned, 'left') >= 0 || __indexOf.call(pinned, 'right') >= 0) { + eAttachment.left = tAttachment.left = false; + } + if (__indexOf.call(pinned, 'top') >= 0 || __indexOf.call(pinned, 'bottom') >= 0) { + eAttachment.top = tAttachment.top = false; + } + if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== this.attachment.top || eAttachment.left !== this.attachment.left) { + this.updateAttachClasses(eAttachment, tAttachment); + } + } + defer(function() { + updateClasses(_this.target, addClasses, allClasses); + return updateClasses(_this.element, addClasses, allClasses); + }); + return { + top: top, + left: left + }; + } + }); + +}).call(this); + +(function() { + var defer, getBounds, updateClasses, _ref; + + _ref = Tether.Utils, getBounds = _ref.getBounds, updateClasses = _ref.updateClasses, defer = _ref.defer; + + Tether.modules.push({ + position: function(_arg) { + var abutted, addClasses, allClasses, bottom, height, left, right, side, sides, targetPos, top, width, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref1, _ref2, _ref3, _ref4, _ref5, + _this = this; + top = _arg.top, left = _arg.left; + _ref1 = this.cache('element-bounds', function() { + return getBounds(_this.element); + }), height = _ref1.height, width = _ref1.width; + targetPos = this.getTargetBounds(); + bottom = top + height; + right = left + width; + abutted = []; + if (top <= targetPos.bottom && bottom >= targetPos.top) { + _ref2 = ['left', 'right']; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + side = _ref2[_i]; + if ((_ref3 = targetPos[side]) === left || _ref3 === right) { + abutted.push(side); + } + } + } + if (left <= targetPos.right && right >= targetPos.left) { + _ref4 = ['top', 'bottom']; + for (_j = 0, _len1 = _ref4.length; _j < _len1; _j++) { + side = _ref4[_j]; + if ((_ref5 = targetPos[side]) === top || _ref5 === bottom) { + abutted.push(side); + } + } + } + allClasses = []; + addClasses = []; + sides = ['left', 'top', 'right', 'bottom']; + allClasses.push(this.getClass('abutted')); + for (_k = 0, _len2 = sides.length; _k < _len2; _k++) { + side = sides[_k]; + allClasses.push("" + (this.getClass('abutted')) + "-" + side); + } + if (abutted.length) { + addClasses.push(this.getClass('abutted')); + } + for (_l = 0, _len3 = abutted.length; _l < _len3; _l++) { + side = abutted[_l]; + addClasses.push("" + (this.getClass('abutted')) + "-" + side); + } + defer(function() { + updateClasses(_this.target, addClasses, allClasses); + return updateClasses(_this.element, addClasses, allClasses); + }); + return true; + } + }); + +}).call(this); + +(function() { + Tether.modules.push({ + position: function(_arg) { + var left, result, shift, shiftLeft, shiftTop, top, _ref; + top = _arg.top, left = _arg.left; + if (!this.options.shift) { + return; + } + result = function(val) { + if (typeof val === 'function') { + return val.call(this, { + top: top, + left: left + }); + } else { + return val; + } + }; + shift = result(this.options.shift); + if (typeof shift === 'string') { + shift = shift.split(' '); + shift[1] || (shift[1] = shift[0]); + shiftTop = shift[0], shiftLeft = shift[1]; + shiftTop = parseFloat(shiftTop, 10); + shiftLeft = parseFloat(shiftLeft, 10); + } else { + _ref = [shift.top, shift.left], shiftTop = _ref[0], shiftLeft = _ref[1]; + } + top += shiftTop; + left += shiftLeft; + return { + top: top, + left: left + }; + } + }); + +}).call(this); + +(function() { + var ATTACHMENT, Evented, Shepherd, Step, Tour, addClass, createFromHTML, extend, matchesSelector, parseShorthand, removeClass, uniqueId, _ref, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; @@ -58,15 +1410,17 @@ Step = (function(_super) { __extends(Step, _super); - function Step(shepherd, options) { - this.shepherd = shepherd; + function Step(tour, options) { + this.tour = tour; this.destroy = __bind(this.destroy, this); this.scrollTo = __bind(this.scrollTo, this); this.complete = __bind(this.complete, this); this.cancel = __bind(this.cancel, this); + this.isOpen = __bind(this.isOpen, this); this.hide = __bind(this.hide, this); this.show = __bind(this.show, this); this.setOptions(options); + this; } Step.prototype.setOptions = function(options) { @@ -84,23 +1438,30 @@ return (_base = this.options).buttons != null ? (_base = this.options).buttons : _base.buttons = [ { text: 'Next', - action: this.shepherd.next + action: this.tour.next } ]; }; + Step.prototype.getTour = function() { + return this.tour; + }; + Step.prototype.bindAdvance = function() { var event, handler, selector, _ref1, _this = this; _ref1 = parseShorthand(this.options.advanceOn, ['event', 'selector']), event = _ref1.event, selector = _ref1.selector; handler = function(e) { + if (!_this.isOpen()) { + return; + } if (selector != null) { if (matchesSelector(e.target, selector)) { - return _this.shepherd.advance(); + return _this.tour.next(); } } else { if (_this.el && e.target === _this.el) { - return _this.shepherd.advance(); + return _this.tour.next(); } } }; @@ -180,6 +1541,10 @@ return this.trigger('hide'); }; + Step.prototype.isOpen = function() { + return hasClass(this.el, 'shepherd-open'); + }; + Step.prototype.cancel = function() { this.hide(); return this.trigger('cancel'); @@ -284,7 +1649,7 @@ if (typeof handler === 'string') { page = handler; handler = function() { - return _this.shepherd.show(page); + return _this.tour.show(page); }; } el.addEventListener(event, handler); @@ -305,30 +1670,51 @@ })(Evented); - Shepherd = (function(_super) { - __extends(Shepherd, _super); + Tour = (function(_super) { + __extends(Tour, _super); - function Shepherd(options) { - var _ref1; + function Tour(options) { + var event, _i, _len, _ref1, _ref2, + _this = this; this.options = options != null ? options : {}; this.hide = __bind(this.hide, this); this.cancel = __bind(this.cancel, this); this.back = __bind(this.back, this); this.next = __bind(this.next, this); this.steps = (_ref1 = this.options.steps) != null ? _ref1 : []; + _ref2 = ['complete', 'cancel', 'hide', 'start', 'show']; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + event = _ref2[_i]; + this.on(event, function(opts) { + if (opts == null) { + opts = {}; + } + opts.tour = _this; + return Shepherd.trigger(event, opts); + }); + } + this; } - Shepherd.prototype.addStep = function(name, step) { + Tour.prototype.addStep = function(name, step) { + var _ref1; if (step == null) { step = name; + } + if (!(step instanceof Step)) { + if ((_ref1 = typeof name) === 'string' || _ref1 === 'number') { + step.id = name.toString(); + } + step = extend({}, this.options.defaults, step); + step = new Step(this, step); } else { - step.id = name; + step.tour = this; } - step = extend({}, this.options.defaults, step); - return this.steps.push(new Step(this, step)); + this.steps.push(step); + return step; }; - Shepherd.prototype.getById = function(id) { + Tour.prototype.getById = function(id) { var step, _i, _len, _ref1; _ref1 = this.steps; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { @@ -339,40 +1725,51 @@ } }; - Shepherd.prototype.next = function() { + Tour.prototype.getCurrentStep = function() { + return this.currentStep; + }; + + Tour.prototype.next = function() { var index; index = this.steps.indexOf(this.currentStep); if (index === this.steps.length - 1) { this.hide(index); - return this.trigger('complete'); + this.trigger('complete'); + return this.done(); } else { return this.show(index + 1); } }; - Shepherd.prototype.back = function() { + Tour.prototype.back = function() { var index; index = this.steps.indexOf(this.currentStep); return this.show(index - 1); }; - Shepherd.prototype.cancel = function() { + Tour.prototype.cancel = function() { var _ref1; if ((_ref1 = this.currentStep) != null) { _ref1.cancel(); } - return this.trigger('cancel'); + this.trigger('cancel'); + return this.done(); }; - Shepherd.prototype.hide = function() { + Tour.prototype.hide = function() { var _ref1; if ((_ref1 = this.currentStep) != null) { _ref1.hide(); } - return this.trigger('hide'); + this.trigger('hide'); + return this.done(); + }; + + Tour.prototype.done = function() { + return Shepherd.activeTour = null; }; - Shepherd.prototype.show = function(key) { + Tour.prototype.show = function(key) { var next; if (key == null) { key = 0; @@ -380,13 +1777,14 @@ if (this.currentStep) { this.currentStep.hide(); } + Shepherd.activeTour = this; if (typeof key === 'string') { next = this.getById(key); } else { next = this.steps[key]; } if (next) { - this.trigger('shown', { + this.trigger('show', { step: next, previous: this.currentStep }); @@ -395,15 +1793,23 @@ } }; - Shepherd.prototype.start = function() { + Tour.prototype.start = function() { + this.trigger('start'); this.currentStep = null; return this.next(); }; - return Shepherd; + return Tour; })(Evented); + Shepherd = new Evented; + + extend(Shepherd, { + Tour: Tour, + Step: Step + }); + window.Shepherd = Shepherd; }).call(this); diff --git a/shepherd.min.js b/shepherd.min.js index 0da5e3acc..d2bba5f8b 100644 --- a/shepherd.min.js +++ b/shepherd.min.js @@ -1,2 +1,2 @@ -/*! shepherd.js 0.2.1 */ -(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m=function(a,b){return function(){return a.apply(b,arguments)}},n={}.hasOwnProperty,o=function(a,b){function c(){this.constructor=a}for(var d in b)n.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};l=Tether.Utils,g=l.extend,j=l.removeClass,e=l.addClass,b=l.Evented,a={top:"top center",left:"middle right",right:"middle left",bottom:"bottom center"},k=function(){var a;return a=0,function(){return a++}}(),f=function(a){var b;return b=document.createElement("div"),b.innerHTML=a,b.children[0]},h=function(a,b){var c,d,e,f,g;return c=null!=(d=null!=(e=null!=(f=null!=(g=a.matches)?g:a.matchesSelector)?f:a.webkitMatchesSelector)?e:a.mozMatchesSelector)?d:a.oMatchesSelector,c.call(a,b)},i=function(a,b){var c,d,e,f,g,h;if(null==a)return a;if("object"==typeof a)return a;for(f=a.split(" "),f.length>b.length&&(f[0]=f.slice(0,+(f.length-b.length)+1||9e9).join(" "),f.splice(1,f.length-b.length)),d={},c=g=0,h=b.length;h>g;c=++g)e=b[c],d[e]=f[c];return d},d=function(b){function c(a,b){this.shepherd=a,this.destroy=m(this.destroy,this),this.scrollTo=m(this.scrollTo,this),this.complete=m(this.complete,this),this.cancel=m(this.cancel,this),this.hide=m(this.hide,this),this.show=m(this.show,this),this.setOptions(b)}return o(c,b),c.prototype.setOptions=function(a){var b,c,d,e;if(this.options=null!=a?a:{},this.destroy(),this.id=this.options.id||this.id||"step-"+k(),this.options.when){e=this.options.when;for(b in e)c=e[b],this.on(b,c,this)}return null!=(d=this.options).buttons?(d=this.options).buttons:d.buttons=[{text:"Next",action:this.shepherd.next}]},c.prototype.bindAdvance=function(){var a,b,c,d,e=this;return d=i(this.options.advanceOn,["event","selector"]),a=d.event,c=d.selector,b=function(a){if(null!=c){if(h(a.target,c))return e.shepherd.advance()}else if(e.el&&a.target===e.el)return e.shepherd.advance()},document.body.addEventListener(a,b),this.on("destroy",function(){return document.body.removeEventListener(a,b)})},c.prototype.getAttachTo=function(){var a;if(a=i(this.options.attachTo,["element","on"]),null==a&&(a={}),"string"==typeof a.element&&(a.element=document.querySelector(a.element),null==a.element))throw new Error("Shepherd step's attachTo was not found in the page");return a},c.prototype.setupTether=function(){var b,c,d;if("undefined"==typeof Tether||null===Tether)throw new Error("Using the attachment feature of Shepherd requires the Tether library");return c=this.getAttachTo(),b=a[c.on||"right"],null==c.element&&(c.element="viewport",b="middle center"),d={classPrefix:"shepherd",element:this.el,constraints:[{to:"window",pin:!0,attachment:"together"}],target:c.element,offset:c.offset||"0 0",attachment:b},this.tether=new Tether(g(d,this.options.tetherOptions))},c.prototype.show=function(){var a,b=this;return null==this.el&&this.render(),e(this.el,"shepherd-open"),null!=(a=this.tether)&&a.enable(),this.options.scrollTo&&setTimeout(function(){return b.scrollTo()}),this.trigger("show")},c.prototype.hide=function(){var a;return j(this.el,"shepherd-open"),null!=(a=this.tether)&&a.disable(),this.trigger("hide")},c.prototype.cancel=function(){return this.hide(),this.trigger("cancel")},c.prototype.complete=function(){return this.hide(),this.trigger("complete")},c.prototype.scrollTo=function(){var a,b,c,d,e,f,g,h,i,j;return e=this.getAttachTo().element,null!=e?(a=jQuery(e),j=a.offset(),i=j.top,g=j.left,f=a.outerHeight(),h=$(this.el).offset(),d=h.top,c=h.left,b=$(this.el).outerHeight(),pageYOffset>i||pageYOffset>d?jQuery(document.body).scrollTop(Math.min(i,d)-10):i+f>pageYOffset+innerHeight||d+b>pageYOffset+innerHeight?jQuery(document.body).scrollTop(Math.max(i+f,d+b)-innerHeight+10):void 0):void 0},c.prototype.destroy=function(){var a;return null!=this.el&&(document.body.removeChild(this.el),delete this.el),null!=(a=this.tether)&&a.destroy(),this.trigger("destroy")},c.prototype.render=function(){var a,b,c,d,e,g,h,i,j,k,l,m,n,o,p,q;if(null!=this.el&&this.destroy(),this.el=f("
    "),d=document.createElement("div"),d.className="shepherd-content",this.el.appendChild(d),null!=this.options.title&&(g=document.createElement("header"),g.innerHTML="

    "+this.options.title+"

    ",this.el.className+=" shepherd-has-title",d.appendChild(g)),null!=this.options.text){for(j=f("
    "),i=this.options.text,"string"==typeof i&&(i=[i]),k=0,m=i.length;m>k;k++)h=i[k],j.innerHTML+="

    "+h+"

    ";d.appendChild(j)}if(e=document.createElement("footer"),this.options.buttons){for(b=f("
      "),p=this.options.buttons,l=0,n=p.length;n>l;l++)c=p[l],a=f("
    • "+c.text+""),b.appendChild(a),this.bindButtonEvents(c,a.querySelector("a"));e.appendChild(b)}return d.appendChild(e),document.body.appendChild(this.el),this.setupTether(),this.options.advanceOn?this.bindAdvance():void 0},c.prototype.bindButtonEvents=function(a,b){var c,d,e,f,g=this;null==a.events&&(a.events={}),null!=a.action&&(a.events.click=a.action),f=a.events;for(c in f)d=f[c],"string"==typeof d&&(e=d,d=function(){return g.shepherd.show(e)}),b.addEventListener(c,d);return this.on("destroy",function(){var e,f;e=a.events,f=[];for(c in e)d=e[c],f.push(b.removeEventListener(c,d));return f})},c}(b),c=function(a){function b(a){var b;this.options=null!=a?a:{},this.hide=m(this.hide,this),this.cancel=m(this.cancel,this),this.back=m(this.back,this),this.next=m(this.next,this),this.steps=null!=(b=this.options.steps)?b:[]}return o(b,a),b.prototype.addStep=function(a,b){return null==b?b=a:b.id=a,b=g({},this.options.defaults,b),this.steps.push(new d(this,b))},b.prototype.getById=function(a){var b,c,d,e;for(e=this.steps,c=0,d=e.length;d>c;c++)if(b=e[c],b.id===a)return b},b.prototype.next=function(){var a;return a=this.steps.indexOf(this.currentStep),a===this.steps.length-1?(this.hide(a),this.trigger("complete")):this.show(a+1)},b.prototype.back=function(){var a;return a=this.steps.indexOf(this.currentStep),this.show(a-1)},b.prototype.cancel=function(){var a;return null!=(a=this.currentStep)&&a.cancel(),this.trigger("cancel")},b.prototype.hide=function(){var a;return null!=(a=this.currentStep)&&a.hide(),this.trigger("hide")},b.prototype.show=function(a){var b;return null==a&&(a=0),this.currentStep&&this.currentStep.hide(),b="string"==typeof a?this.getById(a):this.steps[a],b?(this.trigger("shown",{step:b,previous:this.currentStep}),this.currentStep=b,b.show()):void 0},b.prototype.start=function(){return this.currentStep=null,this.next()},b}(b),window.Shepherd=c}).call(this); \ No newline at end of file +/*! shepherd 0.3.0 */ +(function(){var t,e,n,o,i,s,r,h,l,a,p,u,f,c,d,g,m={}.hasOwnProperty,v=[].indexOf||function(t){for(var e=0,n=this.length;n>e;e++)if(e in this&&this[e]===t)return e;return-1},b=[].slice;null==window.Tether&&(window.Tether={}),a=function(t){var e,n,o,i,s;if(n=getComputedStyle(t).position,"fixed"===n)return t;for(o=void 0,e=t;e=e.parentNode;){try{i=getComputedStyle(e)}catch(r){}if(null==i)return e;if(/(auto|scroll)/.test(i.overflow+i["overflow-y"]+i["overflow-x"])&&("absolute"!==n||"relative"===(s=i.position)||"absolute"===s||"fixed"===s))return e}return document.body},c=function(){var t;return t=0,function(){return t++}}(),g={},l=function(t){var e,o,s,r,h;if(s=t._tetherZeroElement,null==s&&(s=t.createElement("div"),s.setAttribute("data-tether-id",c()),i(s.style,{top:0,left:0,position:"absolute"}),t.body.appendChild(s),t._tetherZeroElement=s),e=s.getAttribute("data-tether-id"),null==g[e]){g[e]={},h=s.getBoundingClientRect();for(o in h)r=h[o],g[e][o]=r;n(function(){return g[e]=void 0})}return g[e]},u=null,r=function(t){var e,n,o,i,s,r,h;t===document?(n=document,t=document.documentElement):n=t.ownerDocument,o=n.documentElement,e={},h=t.getBoundingClientRect();for(i in h)r=h[i],e[i]=r;return s=l(n),e.top-=s.top,e.left-=s.left,e.top=e.top-o.clientTop,e.left=e.left-o.clientLeft,e.right=n.body.clientWidth-e.width-e.left,e.bottom=n.body.clientHeight-e.height-e.top,e},h=function(t){return t.offsetParent||document.documentElement},i=function(t){var e,n,o,i,s,r,h;for(null==t&&(t={}),e=[],Array.prototype.push.apply(e,arguments),h=e.slice(1),s=0,r=h.length;r>s;s++)if(o=h[s])for(n in o)m.call(o,n)&&(i=o[n],t[n]=i);return t},f=function(t,e){var n,o,i,s,r;if(null!=t.classList){for(s=e.split(" "),r=[],o=0,i=s.length;i>o;o++)n=s[o],r.push(t.classList.remove(n));return r}return t.className=t.className.replace(new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi")," ")},e=function(t,e){var n,o,i,s,r;if(null!=t.classList){for(s=e.split(" "),r=[],o=0,i=s.length;i>o;o++)n=s[o],r.push(t.classList.add(n));return r}return f(t,e),t.className+=" "+e},p=function(t,e){return null!=t.classList?t.classList.contains(e):new RegExp("(^| )"+e+"( |$)","gi").test(t.className)},d=function(t,n,o){var i,s,r,h,l,a;for(s=0,h=o.length;h>s;s++)i=o[s],v.call(n,i)<0&&p(t,i)&&f(t,i);for(a=[],r=0,l=n.length;l>r;r++)i=n[r],a.push(p(t,i)?void 0:e(t,i));return a},o=[],n=function(t){return o.push(t)},s=function(){var t,e;for(e=[];t=o.pop();)e.push(t());return e},t=function(){function t(){}return t.prototype.on=function(t,e,n,o){var i;return null==o&&(o=!1),null==this.bindings&&(this.bindings={}),null==(i=this.bindings)[t]&&(i[t]=[]),this.bindings[t].push({handler:e,ctx:n,once:o})},t.prototype.once=function(t,e,n){return this.on(t,e,n,!0)},t.prototype.off=function(t,e){var n,o,i;if(null!=(null!=(o=this.bindings)?o[t]:void 0)){if(null==e)return delete this.bindings[t];for(n=0,i=[];n=e&&e>=t-n},T=function(){var t,e,n,o,i;for(t=document.createElement("div"),i=["transform","webkitTransform","OTransform","MozTransform","msTransform"],n=0,o=i.length;o>n;n++)if(e=i[n],void 0!==t.style[e])return e}(),C=[],y=function(){var t,e,n;for(e=0,n=C.length;n>e;e++)t=C[e],t.position(!1);return a()},g=function(){var t;return null!=(t="undefined"!=typeof performance&&null!==performance?"function"==typeof performance.now?performance.now():void 0:void 0)?t:+new Date},function(){var t,e,n,o,i,s,r,h,l;for(e=null,n=null,o=null,i=function(){if(null!=n&&n>16)return n=Math.min(n-16,250),void(o=setTimeout(i,250));if(!(null!=e&&g()-e<10))return null!=o&&(clearTimeout(o),o=null),e=g(),y(),n=g()-e},h=["resize","scroll"],l=[],s=0,r=h.length;r>s;s++)t=h[s],l.push(window.addEventListener(t,i));return l}(),t={center:"center",left:"right",right:"left"},e={middle:"middle",top:"bottom",bottom:"top"},n={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},r=function(n,o){var i,s;return i=n.left,s=n.top,"auto"===i&&(i=t[o.left]),"auto"===s&&(s=e[o.top]),{left:i,top:s}},s=function(t){var e,o;return{left:null!=(e=n[t.left])?e:t.left,top:null!=(o=n[t.top])?o:t.top}},i=function(){var t,e,n,o,i,s,r;for(e=1<=arguments.length?M.call(arguments,0):[],n={top:0,left:0},i=0,s=e.length;s>i;i++)r=e[i],o=r.top,t=r.left,"string"==typeof o&&(o=parseFloat(o,10)),"string"==typeof t&&(t=parseFloat(t,10)),n.top+=o,n.left+=t;return n},m=function(t,e){return"string"==typeof t.left&&-1!==t.left.indexOf("%")&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&-1!==t.top.indexOf("%")&&(t.top=parseFloat(t.top,10)/100*e.height),t},v=b=function(t){var e,n,o;return o=t.split(" "),n=o[0],e=o[1],{top:n,left:e}},S=function(){function t(t){this.position=A(this.position,this);var e,n,o,i,s;for(C.push(this),this.history=[],this.setOptions(t,!1),i=Tether.modules,n=0,o=i.length;o>n;n++)e=i[n],null!=(s=e.initialize)&&s.call(this);this.position()}return t.modules=[],t.prototype.getClass=function(t){var e,n;return(null!=(e=this.options.classes)?e[t]:void 0)?this.options.classes[t]:(null!=(n=this.options.classes)?n[t]:void 0)!==!1?this.options.classPrefix?""+this.options.classPrefix+"-"+t:t:""},t.prototype.setOptions=function(t,e){var n,i,s,r,h,a;for(this.options=t,null==e&&(e=!0),n={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"},this.options=l(n,this.options),h=this.options,this.element=h.element,this.target=h.target,this.targetModifier=h.targetModifier,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),a=["element","target"],s=0,r=a.length;r>s;s++){if(i=a[s],null==this[i])throw new Error("Tether Error: Both element and target must be defined");null!=this[i].jquery?this[i]=this[i][0]:"string"==typeof this[i]&&(this[i]=document.querySelector(this[i]))}if(o(this.element,this.getClass("element")),o(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");return this.targetAttachment=v(this.options.targetAttachment),this.attachment=v(this.options.attachment),this.offset=b(this.options.offset),this.targetOffset=b(this.options.targetOffset),null!=this.scrollParent&&this.disable(),this.scrollParent="scroll-handle"===this.targetModifier?this.target:c(this.target),this.options.enabled!==!1?this.enable(e):void 0},t.prototype.getTargetBounds=function(){var t,e,n,o,i,s,r,h,l;if(null==this.targetModifier)return p(this.target);switch(this.targetModifier){case"visible":return this.target===document.body?{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth}:(t=p(this.target),i={height:t.height,width:t.width,top:t.top,left:t.left},i.height=Math.min(i.height,t.height-(pageYOffset-t.top)),i.height=Math.min(i.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),i.height=Math.min(innerHeight,i.height),i.height-=2,i.width=Math.min(i.width,t.width-(pageXOffset-t.left)),i.width=Math.min(i.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),i.width=Math.min(innerWidth,i.width),i.width-=2,i.topl.clientWidth||"scroll"===[h.overflow,h.overflowX]||this.target!==document.body,s=0,n&&(s=15),o=t.height-parseFloat(h.borderTopWidth)-parseFloat(h.borderBottomWidth)-s,i={width:15,height:.975*o*(o/l.scrollHeight),left:t.left+t.width-parseFloat(h.borderLeftWidth)-15},e=0,408>o&&this.target===document.body&&(e=-11e-5*Math.pow(o,2)-.00727*o+22.58),this.target!==document.body&&(i.height=Math.max(i.height,24)),r=l.scrollTop/(l.scrollHeight-o),i.top=r*(o-i.height-e)+t.top+parseFloat(h.borderTopWidth),this.target===document.body&&(i.height=Math.max(i.height,24)),i}},t.prototype.clearCache=function(){return this._cache={}},t.prototype.cache=function(t,e){return null==this._cache&&(this._cache={}),null==this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]},t.prototype.enable=function(t){return null==t&&(t=!0),o(this.target,this.getClass("enabled")),o(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParent!==document&&this.scrollParent.addEventListener("scroll",this.position),t?this.position():void 0},t.prototype.disable=function(){return w(this.target,this.getClass("enabled")),w(this.element,this.getClass("enabled")),this.enabled=!1,null!=this.scrollParent?this.scrollParent.removeEventListener("scroll",this.position):void 0},t.prototype.destroy=function(){var t,e,n,o,i;for(this.disable(),i=[],t=n=0,o=C.length;o>n;t=++n){if(e=C[t],e===this){C.splice(t,1);break}i.push(void 0)}return i},t.prototype.updateAttachClasses=function(t,e){var n,o,i,s,r,l,a,p,u,f=this;for(null==t&&(t=this.attachment),null==e&&(e=this.targetAttachment),s=["left","top","bottom","right","middle","center"],(null!=(u=this._addAttachClasses)?u.length:void 0)&&this._addAttachClasses.splice(0,this._addAttachClasses.length),n=null!=this._addAttachClasses?this._addAttachClasses:this._addAttachClasses=[],t.top&&n.push(""+this.getClass("element-attached")+"-"+t.top),t.left&&n.push(""+this.getClass("element-attached")+"-"+t.left),e.top&&n.push(""+this.getClass("target-attached")+"-"+e.top),e.left&&n.push(""+this.getClass("target-attached")+"-"+e.left),o=[],r=0,a=s.length;a>r;r++)i=s[r],o.push(""+this.getClass("element-attached")+"-"+i);for(l=0,p=s.length;p>l;l++)i=s[l],o.push(""+this.getClass("target-attached")+"-"+i);return h(function(){return null!=f._addAttachClasses?(O(f.element,f._addAttachClasses,o),O(f.target,f._addAttachClasses,o),f._addAttachClasses=void 0):void 0})},t.prototype.position=function(t){var e,n,o,h,l,f,c,d,g,v,b,y,w,C,T,O,x,S,E,M,A,_,P,B,H,L,Y,z,F,W,N,X,j=this;if(null==t&&(t=!0),this.enabled){for(this.clearCache(),E=r(this.targetAttachment,this.attachment),this.updateAttachClasses(this.attachment,E),e=this.cache("element-bounds",function(){return p(j.element)}),B=e.width,o=e.height,0===B&&0===o&&null!=this.lastSize?(F=this.lastSize,B=F.width,o=F.height):this.lastSize={width:B,height:o},_=A=this.cache("target-bounds",function(){return j.getTargetBounds()}),g=m(s(this.attachment),{width:B,height:o}),M=m(s(E),_),l=m(this.offset,{width:B,height:o}),f=m(this.targetOffset,_),g=i(g,l),M=i(M,f),h=A.left+M.left-g.left,P=A.top+M.top-g.top,W=Tether.modules,H=0,Y=W.length;Y>H;H++)if(c=W[H],T=c.position.call(this,{left:h,top:P,targetAttachment:E,targetPos:A,elementPos:e,offset:g,targetOffset:M,manualOffset:l,manualTargetOffset:f}),null!=T&&"object"==typeof T){if(T===!1)return!1;P=T.top,h=T.left}if(d={page:{top:P,bottom:document.body.scrollHeight-P-o,left:h,right:document.body.scrollWidth-h-B},viewport:{top:P-pageYOffset,bottom:pageYOffset-P-o+innerHeight,left:h-pageXOffset,right:pageXOffset-h-B+innerWidth}},(null!=(N=this.options.optimizations)?N.moveElement:void 0)!==!1&&null==this.targetModifier){for(b=this.cache("target-offsetparent",function(){return u(j.target)}),C=this.cache("target-offsetparent-bounds",function(){return p(b)}),w=getComputedStyle(b),n=getComputedStyle(this.element),y=C,v={},X=["top","left","bottom","right"],L=0,z=X.length;z>L;L++)S=X[L],v[S]=parseFloat(w["border-"+S+"-width"]);C.right=document.body.scrollWidth-C.left-y.width+v.right,C.bottom=document.body.scrollHeight-C.top-y.height+v.bottom,d.page.top>=C.top+v.top&&d.page.bottom>=C.bottom&&d.page.left>=C.left+v.left&&d.page.right>=C.right&&(x=b.scrollTop,O=b.scrollLeft,d.offset={top:d.page.top-C.top+x-v.top,left:d.page.left-C.left+O-v.left})}return this.move(d),this.history.unshift(d),this.history.length>3&&this.history.pop(),t&&a(),!0}},t.prototype.move=function(t){var e,n,o,i,s,r,a,p,f,c,d,g,m,v,b,y,w,C=this;if(null!=this.element.parentNode){p={};for(c in t){p[c]={};for(i in t[c]){for(o=!1,y=this.history,v=0,b=y.length;b>v;v++)if(a=y[v],!x(null!=(w=a[c])?w[i]:void 0,t[c][i])){o=!0;break}o||(p[c][i]=!0)}}e={top:"",left:"",right:"",bottom:""},f=function(t,n){var o,i,s;return(null!=(s=C.options.optimizations)?s.gpu:void 0)===!1?(t.top?e.top=""+n.top+"px":e.bottom=""+n.bottom+"px",t.left?e.left=""+n.left+"px":e.right=""+n.right+"px"):(t.top?(e.top=0,i=n.top):(e.bottom=0,i=-n.bottom),t.left?(e.left=0,o=n.left):(e.right=0,o=-n.right),e[T]="translateX("+Math.round(o)+"px) translateY("+Math.round(i)+"px)","msTransform"!==T?e[T]+=" translateZ(0)":void 0)},s=!1,(p.page.top||p.page.bottom)&&(p.page.left||p.page.right)?(e.position="absolute",f(p.page,t.page)):(p.viewport.top||p.viewport.bottom)&&(p.viewport.left||p.viewport.right)?(e.position="fixed",f(p.viewport,t.viewport)):null!=p.offset&&p.offset.top&&p.offset.left?(e.position="absolute",r=this.cache("target-offsetparent",function(){return u(C.target)}),u(this.element)!==r&&h(function(){return C.element.parentNode.removeChild(C.element),r.appendChild(C.element)}),f(p.offset,t.offset),s=!0):(e.position="absolute",f({top:!0,left:!0},t.page)),s||"BODY"===this.element.parentNode.tagName||(this.element.parentNode.removeChild(this.element),document.body.appendChild(this.element)),m={},g=!1;for(i in e)d=e[i],n=this.element.style[i],""===n||""===d||"top"!==i&&"left"!==i&&"bottom"!==i&&"right"!==i||(n=parseFloat(n),d=parseFloat(d)),n!==d&&(g=!0,m[i]=e[i]);return g?h(function(){return l(C.element.style,m)}):void 0}},t}(),Tether.position=y,window.Tether=l(S,Tether)}.call(this),function(){var t,e,n,o,i,s,r,h,l,a,p=[].indexOf||function(t){for(var e=0,n=this.length;n>e;e++)if(e in this&&this[e]===t)return e;return-1};a=Tether.Utils,r=a.getOuterSize,s=a.getBounds,h=a.getSize,o=a.extend,l=a.updateClasses,n=a.defer,e={left:"right",right:"left",top:"bottom",bottom:"top",middle:"middle"},t=["left","top","right","bottom"],i=function(e,n){var o,i,r,h,l,a,p;if("scrollParent"===n?n=e.scrollParent:"window"===n&&(n=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),n===document&&(n=n.documentElement),null!=n.nodeType)for(i=h=s(n),l=getComputedStyle(n),n=[i.left,i.top,h.width+i.left,h.height+i.top],o=a=0,p=t.length;p>a;o=++a)r=t[o],"top"===r||"left"===r?n[o]+=parseFloat(l["border-"+r+"-width"]):n[o]-=parseFloat(l["border-"+r+"-width"]);return n},Tether.modules.push({position:function(e){var r,h,a,u,f,c,d,g,m,v,b,y,w,C,T,O,x,S,E,M,A,_,P,B,H,L,Y,z,F,W,N,X,j,k,q,U,R,$,D,I,Q,Z,G,J,K,V,te,ee=this;if(L=e.top,b=e.left,A=e.targetAttachment,!this.options.constraints)return!0;for(S=function(e){var n,o,i,s;for(ee.removeClass(e),s=[],o=0,i=t.length;i>o;o++)n=t[o],s.push(ee.removeClass(""+e+"-"+n));return s},I=this.cache("element-bounds",function(){return s(ee.element)}),v=I.height,Y=I.width,0===Y&&0===v&&null!=this.lastSize&&(Q=this.lastSize,Y=Q.width,v=Q.height),P=this.cache("target-bounds",function(){return ee.getTargetBounds()}),_=P.height,B=P.width,M={},m={},h=[this.getClass("pinned"),this.getClass("out-of-bounds")],Z=this.options.constraints,z=0,X=Z.length;X>z;z++)g=Z[z],g.outOfBoundsClass&&h.push(g.outOfBoundsClass),g.pinnedClass&&h.push(g.pinnedClass);for(F=0,j=h.length;j>F;F++)for(d=h[F],G=["left","top","right","bottom"],W=0,k=G.length;k>W;W++)E=G[W],h.push(""+d+"-"+E);for(r=[],M=o({},A),m=o({},this.attachment),J=this.options.constraints,N=0,q=J.length;q>N;N++){if(g=J[N],H=g.to,a=g.attachment,T=g.pin,null==a&&(a=""),p.call(a," ")>=0?(K=a.split(" "),c=K[0],f=K[1]):f=c=a,u=i(this,H),("target"===c||"both"===c)&&(Lu[3]&&"bottom"===M.top&&(L-=_,M.top="top")),"together"===c&&(Lu[3]&&"bottom"===M.top&&("top"===m.top?(L-=_,M.top="top",L-=v,m.top="bottom"):"bottom"===m.top&&(L-=_,M.top="top",L+=v,m.top="top"))),("target"===f||"both"===f)&&(bu[2]&&"right"===M.left&&(b-=B,M.left="left")),"together"===f&&(bu[2]&&"right"===M.left&&("left"===m.left?(b-=B,M.left="left",b-=Y,m.left="right"):"right"===m.left&&(b-=B,M.left="left",b+=Y,m.left="left"))),("element"===c||"both"===c)&&(Lu[3]&&"top"===m.top&&(L-=v,m.top="bottom")),("element"===f||"both"===f)&&(bu[2]&&"left"===m.left&&(b-=Y,m.left="right")),"string"==typeof T?T=function(){var t,e,n,o;for(n=T.split(","),o=[],e=0,t=n.length;t>e;e++)C=n[e],o.push(C.trim());return o}():T===!0&&(T=["top","left","right","bottom"]),T||(T=[]),O=[],y=[],L=0?(L=u[1],O.push("top")):y.push("top")),L+v>u[3]&&(p.call(T,"bottom")>=0?(L=u[3]-v,O.push("bottom")):y.push("bottom")),b=0?(b=u[0],O.push("left")):y.push("left")),b+Y>u[2]&&(p.call(T,"right")>=0?(b=u[2]-Y,O.push("right")):y.push("right")),O.length)for(x=null!=(V=this.options.pinnedClass)?V:this.getClass("pinned"),r.push(x),$=0,U=O.length;U>$;$++)E=O[$],r.push(""+x+"-"+E);if(y.length)for(w=null!=(te=this.options.outOfBoundsClass)?te:this.getClass("out-of-bounds"),r.push(w),D=0,R=y.length;R>D;D++)E=y[D],r.push(""+w+"-"+E);(p.call(O,"left")>=0||p.call(O,"right")>=0)&&(m.left=M.left=!1),(p.call(O,"top")>=0||p.call(O,"bottom")>=0)&&(m.top=M.top=!1),(M.top!==A.top||M.left!==A.left||m.top!==this.attachment.top||m.left!==this.attachment.left)&&this.updateAttachClasses(m,M)}return n(function(){return l(ee.target,r,h),l(ee.element,r,h)}),{top:L,left:b}}})}.call(this),function(){var t,e,n,o;o=Tether.Utils,e=o.getBounds,n=o.updateClasses,t=o.defer,Tether.modules.push({position:function(o){var i,s,r,h,l,a,p,u,f,c,d,g,m,v,b,y,w,C,T,O,x,S,E,M,A,_=this;if(d=o.top,a=o.left,x=this.cache("element-bounds",function(){return e(_.element)}),l=x.height,g=x.width,c=this.getTargetBounds(),h=d+l,p=a+g,i=[],d<=c.bottom&&h>=c.top)for(S=["left","right"],m=0,w=S.length;w>m;m++)u=S[m],((E=c[u])===a||E===p)&&i.push(u);if(a<=c.right&&p>=c.left)for(M=["top","bottom"],v=0,C=M.length;C>v;v++)u=M[v],((A=c[u])===d||A===h)&&i.push(u);for(r=[],s=[],f=["left","top","right","bottom"],r.push(this.getClass("abutted")),b=0,T=f.length;T>b;b++)u=f[b],r.push(""+this.getClass("abutted")+"-"+u);for(i.length&&s.push(this.getClass("abutted")),y=0,O=i.length;O>y;y++)u=i[y],s.push(""+this.getClass("abutted")+"-"+u);return t(function(){return n(_.target,s,r),n(_.element,s,r)}),!0}})}.call(this),function(){Tether.modules.push({position:function(t){var e,n,o,i,s,r,h;return r=t.top,e=t.left,this.options.shift?(n=function(t){return"function"==typeof t?t.call(this,{top:r,left:e}):t},o=n(this.options.shift),"string"==typeof o?(o=o.split(" "),o[1]||(o[1]=o[0]),s=o[0],i=o[1],s=parseFloat(s,10),i=parseFloat(i,10)):(h=[o.top,o.left],s=h[0],i=h[1]),r+=s,e+=i,{top:r,left:e}):void 0}})}.call(this),function(){var t,e,n,o,i,s,r,h,l,a,p,u,f,c=function(t,e){return function(){return t.apply(e,arguments)}},d={}.hasOwnProperty,g=function(t,e){function n(){this.constructor=t}for(var o in e)d.call(e,o)&&(t[o]=e[o]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t};f=Tether.Utils,h=f.extend,p=f.removeClass,s=f.addClass,e=f.Evented,t={top:"top center",left:"middle right",right:"middle left",bottom:"bottom center"},u=function(){var t;return t=0,function(){return t++}}(),r=function(t){var e;return e=document.createElement("div"),e.innerHTML=t,e.children[0]},l=function(t,e){var n,o,i,s,r;return n=null!=(o=null!=(i=null!=(s=null!=(r=t.matches)?r:t.matchesSelector)?s:t.webkitMatchesSelector)?i:t.mozMatchesSelector)?o:t.oMatchesSelector,n.call(t,e)},a=function(t,e){var n,o,i,s,r,h;if(null==t)return t;if("object"==typeof t)return t;for(s=t.split(" "),s.length>e.length&&(s[0]=s.slice(0,+(s.length-e.length)+1||9e9).join(" "),s.splice(1,s.length-e.length)),o={},n=r=0,h=e.length;h>r;n=++r)i=e[n],o[i]=s[n];return o},o=function(e){function n(t,e){this.tour=t,this.destroy=c(this.destroy,this),this.scrollTo=c(this.scrollTo,this),this.complete=c(this.complete,this),this.cancel=c(this.cancel,this),this.isOpen=c(this.isOpen,this),this.hide=c(this.hide,this),this.show=c(this.show,this),this.setOptions(e)}return g(n,e),n.prototype.setOptions=function(t){var e,n,o,i;if(this.options=null!=t?t:{},this.destroy(),this.id=this.options.id||this.id||"step-"+u(),this.options.when){i=this.options.when;for(e in i)n=i[e],this.on(e,n,this)}return null!=(o=this.options).buttons?(o=this.options).buttons:o.buttons=[{text:"Next",action:this.tour.next}]},n.prototype.getTour=function(){return this.tour},n.prototype.bindAdvance=function(){var t,e,n,o,i=this;return o=a(this.options.advanceOn,["event","selector"]),t=o.event,n=o.selector,e=function(t){if(i.isOpen())if(null!=n){if(l(t.target,n))return i.tour.next()}else if(i.el&&t.target===i.el)return i.tour.next()},document.body.addEventListener(t,e),this.on("destroy",function(){return document.body.removeEventListener(t,e)})},n.prototype.getAttachTo=function(){var t;if(t=a(this.options.attachTo,["element","on"]),null==t&&(t={}),"string"==typeof t.element&&(t.element=document.querySelector(t.element),null==t.element))throw new Error("Shepherd step's attachTo was not found in the page");return t},n.prototype.setupTether=function(){var e,n,o;if("undefined"==typeof Tether||null===Tether)throw new Error("Using the attachment feature of Shepherd requires the Tether library");return n=this.getAttachTo(),e=t[n.on||"right"],null==n.element&&(n.element="viewport",e="middle center"),o={classPrefix:"shepherd",element:this.el,constraints:[{to:"window",pin:!0,attachment:"together"}],target:n.element,offset:n.offset||"0 0",attachment:e},this.tether=new Tether(h(o,this.options.tetherOptions))},n.prototype.show=function(){var t,e=this;return null==this.el&&this.render(),s(this.el,"shepherd-open"),null!=(t=this.tether)&&t.enable(),this.options.scrollTo&&setTimeout(function(){return e.scrollTo()}),this.trigger("show")},n.prototype.hide=function(){var t;return p(this.el,"shepherd-open"),null!=(t=this.tether)&&t.disable(),this.trigger("hide")},n.prototype.isOpen=function(){return hasClass(this.el,"shepherd-open")},n.prototype.cancel=function(){return this.hide(),this.trigger("cancel")},n.prototype.complete=function(){return this.hide(),this.trigger("complete")},n.prototype.scrollTo=function(){var t,e,n,o,i,s,r,h,l,a;return i=this.getAttachTo().element,null!=i?(t=jQuery(i),a=t.offset(),l=a.top,r=a.left,s=t.outerHeight(),h=$(this.el).offset(),o=h.top,n=h.left,e=$(this.el).outerHeight(),pageYOffset>l||pageYOffset>o?jQuery(document.body).scrollTop(Math.min(l,o)-10):l+s>pageYOffset+innerHeight||o+e>pageYOffset+innerHeight?jQuery(document.body).scrollTop(Math.max(l+s,o+e)-innerHeight+10):void 0):void 0},n.prototype.destroy=function(){var t;return null!=this.el&&(document.body.removeChild(this.el),delete this.el),null!=(t=this.tether)&&t.destroy(),this.trigger("destroy")},n.prototype.render=function(){var t,e,n,o,i,s,h,l,a,p,u,f,c,d,g,m;if(null!=this.el&&this.destroy(),this.el=r("
      "),o=document.createElement("div"),o.className="shepherd-content",this.el.appendChild(o),null!=this.options.title&&(s=document.createElement("header"),s.innerHTML="

      "+this.options.title+"

      ",this.el.className+=" shepherd-has-title",o.appendChild(s)),null!=this.options.text){for(a=r("
      "),l=this.options.text,"string"==typeof l&&(l=[l]),p=0,f=l.length;f>p;p++)h=l[p],a.innerHTML+="

      "+h+"

      ";o.appendChild(a)}if(i=document.createElement("footer"),this.options.buttons){for(e=r("
        "),g=this.options.buttons,u=0,c=g.length;c>u;u++)n=g[u],t=r("
      • "+n.text+""),e.appendChild(t),this.bindButtonEvents(n,t.querySelector("a"));i.appendChild(e)}return o.appendChild(i),document.body.appendChild(this.el),this.setupTether(),this.options.advanceOn?this.bindAdvance():void 0},n.prototype.bindButtonEvents=function(t,e){var n,o,i,s,r=this;null==t.events&&(t.events={}),null!=t.action&&(t.events.click=t.action),s=t.events;for(n in s)o=s[n],"string"==typeof o&&(i=o,o=function(){return r.tour.show(i)}),e.addEventListener(n,o);return this.on("destroy",function(){var i,s;i=t.events,s=[];for(n in i)o=i[n],s.push(e.removeEventListener(n,o));return s})},n}(e),i=function(t){function e(t){var e,o,i,s,r,h=this;for(this.options=null!=t?t:{},this.hide=c(this.hide,this),this.cancel=c(this.cancel,this),this.back=c(this.back,this),this.next=c(this.next,this),this.steps=null!=(s=this.options.steps)?s:[],r=["complete","cancel","hide","start","show"],o=0,i=r.length;i>o;o++)e=r[o],this.on(e,function(t){return null==t&&(t={}),t.tour=h,n.trigger(e,t)})}return g(e,t),e.prototype.addStep=function(t,e){var n;return null==e&&(e=t),e instanceof o?e.tour=this:(("string"==(n=typeof t)||"number"===n)&&(e.id=t.toString()),e=h({},this.options.defaults,e),e=new o(this,e)),this.steps.push(e),e},e.prototype.getById=function(t){var e,n,o,i;for(i=this.steps,n=0,o=i.length;o>n;n++)if(e=i[n],e.id===t)return e},e.prototype.getCurrentStep=function(){return this.currentStep},e.prototype.next=function(){var t;return t=this.steps.indexOf(this.currentStep),t===this.steps.length-1?(this.hide(t),this.trigger("complete"),this.done()):this.show(t+1)},e.prototype.back=function(){var t;return t=this.steps.indexOf(this.currentStep),this.show(t-1)},e.prototype.cancel=function(){var t;return null!=(t=this.currentStep)&&t.cancel(),this.trigger("cancel"),this.done()},e.prototype.hide=function(){var t;return null!=(t=this.currentStep)&&t.hide(),this.trigger("hide"),this.done()},e.prototype.done=function(){return n.activeTour=null},e.prototype.show=function(t){var e;return null==t&&(t=0),this.currentStep&&this.currentStep.hide(),n.activeTour=this,e="string"==typeof t?this.getById(t):this.steps[t],e?(this.trigger("show",{step:e,previous:this.currentStep}),this.currentStep=e,e.show()):void 0},e.prototype.start=function(){return this.trigger("start"),this.currentStep=null,this.next()},e}(e),n=new e,h(n,{Tour:i,Step:o}),window.Shepherd=n}.call(this); \ No newline at end of file