├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── README.md ├── bower.json ├── example.html ├── jquery.scrolltab.js ├── package.json └── scrolltab.jquery.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | 4 | .sizecache.json 5 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss": true, 3 | "browser": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "eqnull": true, 7 | "expr": true, 8 | "evil": true, 9 | "newcap": true, 10 | "noarg": true, 11 | "undef": true, 12 | "globals": { 13 | "jQuery": true, 14 | "define": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*jshint node: true */ 2 | 3 | 'use strict'; 4 | 5 | module.exports = function (grunt) { 6 | 7 | grunt.initConfig({ 8 | pkg: grunt.file.readJSON('package.json'), 9 | jshint: { 10 | files: [ 11 | 'Gruntfile.js', 12 | 'jquery.scrolltab.js' 13 | ], 14 | options: { 15 | jshintrc: '.jshintrc' 16 | } 17 | }, 18 | uglify: { 19 | options: { 20 | banner: '/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.license %> | http://chris-saylor.com/Scrolltab */\n', 21 | compress: true 22 | }, 23 | build: { 24 | files: { 25 | 'build/jquery.scrolltab-<%= pkg.version %>.min.js': 'jquery.scrolltab.js' 26 | } 27 | } 28 | }, 29 | watch: { 30 | files: [ 31 | 'jquery.scrolltab.js' 32 | ], 33 | tasks: 'default' 34 | }, 35 | compare_size: { 36 | files: [ 37 | 'build/jquery.scrolltab-<%= pkg.version %>.min.js', 38 | 'jquery.scrolltab.js' 39 | ], 40 | options: { 41 | compress: { 42 | gz: function (fileContents) { 43 | return require('gzip-js').zip(fileContents, {}).length; 44 | } 45 | } 46 | } 47 | } 48 | }); 49 | 50 | grunt.loadNpmTasks('grunt-contrib-jshint'); 51 | grunt.loadNpmTasks('grunt-contrib-uglify'); 52 | grunt.loadNpmTasks('grunt-contrib-watch'); 53 | grunt.loadNpmTasks('grunt-compare-size'); 54 | 55 | grunt.registerTask('default', ['jshint', 'uglify', 'compare_size']); 56 | grunt.registerTask('ci', ['jshint']); 57 | }; 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Scrolltab is a jQuery plugin that adds tabs visually associated to their position relative to the scroll bar. 2 | 3 | This enables a developer to attach floating tabs to the scrollbar of the brwoser that will scroll the user to the position indicated by the tab. This tab is expandable with content within. 4 | 5 | ## Demo 6 | 7 | http://chris-saylor.com/Scrolltab/example.html 8 | 9 | ## Install 10 | 11 | There are two ways of installing: 12 | 13 | 1. Bower - ```bower install jquery-scrolltab``` 14 | 15 | 2. Download - You can install traditionally by downloading the [minified version](https://github.com/cjsaylor/Scrolltab/releases/latest). 16 | 17 | ## Options 18 | 19 | * `title`: HTML to display within the pin 20 | * `classname`: The classname for the pin to use 21 | * `mouseenter`: function to execute when the mouseenter event fires on this pin 22 | * `mouseleave`: function to execute when the mouseleave event fires on this pin 23 | * `click`: function to execute when the click event fire on this pin 24 | 25 | ## Setting Options via `data` attributes 26 | 27 | You can set the title and classname of the pin via data attributes on the object. 28 | 29 | ```html 30 |

Title

31 | ``` 32 | 33 | ## Behaviors 34 | 35 | The behavior of how the pin displays and hides is customizable by overriding the behavior functions. 36 | 37 | #### Initial Display 38 | 39 | When a new pin is created by the `.scrolltab()` call. 40 | 41 | * Default behavior: `fadeIn('slow')` 42 | 43 | ``` 44 | $.fn.scrolltab.pinInitialDisplay 45 | ``` 46 | 47 | #### Display On Update 48 | 49 | If the element the scrollpin was tracking becomes visible again, this will redisplay the pin. 50 | 51 | * Default behavior: `fadeIn('slow')` 52 | 53 | ``` 54 | $.fn.scrolltab.pinDisplay 55 | ``` 56 | 57 | #### Pin Hide 58 | 59 | If the element the scrollpin was tracking is hidden from the dom, this will hide the pin. 60 | 61 | * Default behavior: `fadeOut('fast')` 62 | 63 | ``` 64 | $.fn.scrolltab.pinHide 65 | ``` 66 | 67 | ## Examples 68 | 69 | ```javascript 70 | // Enables a pin with the default classname 71 | $('').scrolltab(); 72 | ``` 73 | 74 | ```javascript 75 | // Changes the classname of the created (or existing) pin 76 | $('').scrolltab({ classname: 'test' }); 77 | ``` 78 | 79 | ```javascript 80 | // Modifies the behavior of the click event on the pin 81 | $('').scrolltab(); 96 | ``` 97 | 98 | ```javascript 99 | // Modify the default attributes of all pins created now on 100 | // In this example, I want all pins to have a click event function 101 | // callback attached. 102 | $.fn.scrolltab.default = $.extend($.fn.scrolltab.default, { 103 | click: function (e) { 104 | e.preventDefault(); 105 | alert('Pin clicked!'); 106 | } 107 | }); 108 | $('').scrolltab(); 109 | ``` 110 | 111 | ## Build 112 | 113 | Scrolltab uses [Grunt CLI](http://gruntjs.com/) via [NodeJS](http://nodejs.org/) for linting and building the minified production file. 114 | 115 | #### Setup 116 | 117 | Install grunt cli globally: 118 | 119 | ```bash 120 | $ npm install -g grunt-cli 121 | ``` 122 | 123 | Install dev dependencies: 124 | 125 | ```bash 126 | $ npm install -d 127 | ``` 128 | 129 | Execute lint and build: 130 | 131 | ```bash 132 | $ grunt 133 | ``` 134 | 135 | ## License 136 | 137 | This software is protected under the MIT license. 138 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-scrolltab", 3 | "version": "1.0.5", 4 | "homepage": "http://chris-saylor.com/Scrolltab/", 5 | "authors": [ 6 | "Chris Saylor " 7 | ], 8 | "description": "jQuery plugin to add tabs visually associated to their position relative to the scroll bar.", 9 | "main": "jquery.scrolltab.js", 10 | "keywords": [ 11 | "scroll", 12 | "scrollspy", 13 | "animation" 14 | ], 15 | "license": "MIT", 16 | "dependencies": { 17 | "jquery": ">= 1.7.1" 18 | }, 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Scrolltab Demo 7 | 58 | 59 | 60 | 111 | 112 | 113 |
114 | 117 |
118 | Add Box
119 | Show All
120 |

Click on a box to hide it.

121 |
122 |
123 |
124 |
125 |
126 |
127 | 128 | 129 | -------------------------------------------------------------------------------- /jquery.scrolltab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery Scrolltab Plugin v1.0.5 3 | * https://github.com/cjsaylor/scrolltab 4 | * 5 | * Options 6 | * title: HTML to display within the pin. 7 | * classname: Choose the classname you want the pin to use. 8 | * 9 | * Supported events: 10 | * click, mouseenter, mouseleave 11 | * 12 | * This is a simple plugin that enables a developer to attach floating 13 | * tabs to the scrollbar of the browser that will scroll the user to 14 | * the position indicated by the tab. This tab is expandable with content 15 | * within. 16 | * 17 | * The pins react to changes in the pinned object, dom structure/size, 18 | * and the size of the window. 19 | * 20 | * --------------------------------------------------------------------- 21 | * Copyright (c) 2010 - 2014 Chris Saylor 22 | * Permission is hereby granted, free of charge, to any person obtaining a copy 23 | * of this software and associated documentation files (the "Software"), to deal 24 | * in the Software without restriction, including without limitation the rights 25 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | * copies of the Software, and to permit persons to whom the Software is 27 | * furnished to do so, subject to the following conditions: 28 | * 29 | * The above copyright notice and this permission notice shall be included in 30 | * all copies or substantial portions of the Software. 31 | * 32 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 38 | * THE SOFTWARE. 39 | */ 40 | 41 | (function (factory) { 42 | if (typeof define === 'function' && define.amd) { 43 | define(['jquery'], factory); 44 | } else { 45 | factory(jQuery); 46 | } 47 | }(function($) { 48 | $.fn.scrolltab = function(options) { 49 | 50 | var settings = $.extend({}, $.fn.scrolltab.defaults, options); 51 | 52 | var data = { 53 | body: 0, 54 | pinId: 1 55 | }; 56 | 57 | return this.each(function() { 58 | var obj = $(this); 59 | 60 | // Detect if this object has already had a pin created 61 | if(!obj.data('scrolltab_enabled')) { 62 | initializePin.call(obj); 63 | } else { 64 | // The pin already exists, so lets select the existing pin. 65 | updateExistingPin.call(obj); 66 | } 67 | }); 68 | 69 | /** 70 | * Create a pin associated with the subject object. 71 | * 72 | * @return void 73 | */ 74 | function initializePin() { 75 | this.data('scrolltab_enabled', true); 76 | data.body = $('body').height(); 77 | 78 | var id = 'scrolltab_' + data.pinId++; 79 | 80 | // Create the pin and position 81 | var pin = $('
') 82 | .attr('id', id) 83 | .attr('class', this.data('st-classname') || settings.classname) 84 | .html(this.data('st-title') || settings.title) 85 | .css('position', 'fixed') 86 | .css('right', 0) 87 | .bind('mouseenter.scrolltab', settings.mouseenter) 88 | .bind('mouseleave.scrolltab', settings.mouseleave) 89 | .bind('click.scrolltab', settings.click); 90 | 91 | this.data('scrolltab_id', id); 92 | 93 | // Append to dom so we can calculate object height. 94 | $('body').append(pin); 95 | 96 | // Calculate scroll bar position for this element 97 | var pos = calc.call(this, pin); 98 | 99 | // Attach click action (scroll) 100 | pin.css('top', pos) 101 | .hide() 102 | .bind('click.scrolltab', function(e) { 103 | e.preventDefault(); 104 | $('html,body').animate({scrollTop: this.offset().top+"px"}, 1000); 105 | }.bind(this)) 106 | .css('cursor', 'pointer'); 107 | 108 | $.fn.scrolltab.pinInitialDisplay.call(this, pin); 109 | 110 | // Update pin status (if applicable) every second. 111 | setInterval(function() { 112 | update.call(this, pin); 113 | }.bind(this), 1000); 114 | } 115 | 116 | /** 117 | * Update a pin via the pin's subject. 118 | * 119 | * @param object obj 120 | * @return void 121 | */ 122 | function updateExistingPin() { 123 | var pin = $('#' + this.data('scrolltab_id')); 124 | 125 | // Only remap what has been set in the options. 126 | if(options.mouseenter) { 127 | pin.unbind('mouseenter.scrolltab').on('mouseenter.scrolltab', options.mouseenter); 128 | } 129 | if(options.mouseleave) { 130 | pin.unbind('mouseleave.scrolltab').on('mouseleave.scrolltab', options.mouseleave); 131 | } 132 | if(options.click) { 133 | pin.unbind('click.scrolltab').on('click.scrolltab', options.click); 134 | } 135 | if(options.classname) { 136 | pin.attr('class', options.classname); 137 | } 138 | if(options.title) { 139 | pin.html(options.title); 140 | } 141 | } 142 | 143 | 144 | /** 145 | * Updates the positions of each scroll pin. If the object of the scroll 146 | * pin is no longer within the visible dom, the corresponding pin is removed. 147 | * 148 | * If the window size is greater than that of the body, hide all pins. 149 | * 150 | * @param jQuery pin - Pin object 151 | * @return void 152 | */ 153 | function update(pin) { 154 | if(this.parents().length === 0) { 155 | setTimeout(function() { pin.remove(); }, 1000); 156 | } else if(this.css('display') === 'none') { 157 | $.fn.scrolltab.pinHide.call(this, pin); 158 | } else { 159 | setTimeout(function() { 160 | pin.animate({top: calc.call(this, pin)}); 161 | }.bind(this), 1000); 162 | } 163 | 164 | if(!isPinable()) { 165 | $.fn.scrolltab.pinHide.call(this, pin); 166 | } else if(isPinable() && this.css('display') !== 'none') { 167 | $.fn.scrolltab.pinDisplay.call(this, pin); 168 | } 169 | } 170 | 171 | /** 172 | * Calculates the vertical position of the main object to pin for scrolling. 173 | * 174 | * @param jQuery pin - Pin object 175 | * @return float Vertical position result 176 | */ 177 | function calc(pin) { 178 | return parseInt( 179 | this.offset().top / $('body').height() * $(window).height() + (pin.height() / 2), 180 | 10 181 | ); 182 | } 183 | 184 | /** 185 | * Returns true if the any of the pins should be showing 186 | * 187 | * @return boolean 188 | */ 189 | function isPinable() { 190 | return $('body').height() > $(window).height(); 191 | } 192 | 193 | }; 194 | 195 | /** 196 | * Exposed default options. 197 | * 198 | * @type Object 199 | */ 200 | $.fn.scrolltab.defaults = { 201 | title: '', 202 | classname: 'scrolltab-item', 203 | mouseenter: function(){}, 204 | mouseleave: function(){}, 205 | click: function(){} 206 | }; 207 | 208 | /** 209 | * Behavior when a pin needs to be displayed. 210 | * 211 | * This is both the initial display and pin display on update. 212 | * 213 | * @param Object pin jQuery object pin 214 | * @return void 215 | */ 216 | $.fn.scrolltab.pinInitialDisplay = $.fn.scrolltab.pinDisplay = function (pin) { 217 | pin.fadeIn('slow'); 218 | }; 219 | 220 | /** 221 | * Behavior when a pin needs to be hidden. 222 | * 223 | * @param object pin jQuery object pin 224 | * @return void 225 | */ 226 | $.fn.scrolltab.pinHide = function (pin) { 227 | pin.fadeOut('fast'); 228 | }; 229 | })); 230 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery.scrolltab", 3 | "version": "1.0.5", 4 | "description": "jQuery plugin to add tabs visually associated to their position relative to the scroll bar.", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/cjsaylor/scrolltab.git" 9 | }, 10 | "author": "Chris Saylor", 11 | "license": "MIT", 12 | "readmeFilename": "README.md", 13 | "devDependencies": { 14 | "grunt": "~0.4.0", 15 | "grunt-contrib-jshint": "~0.4.0", 16 | "grunt-contrib-uglify": "~0.2.0", 17 | "grunt-contrib-watch": "~0.3.0", 18 | "grunt-compare-size": "~0.4.0", 19 | "gzip-js": "~0.3.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scrolltab.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrolltab", 3 | "title": "Scrolltab", 4 | "description": "A jQuery plugin that adds tabs for elements visually associated to their position relative to the scroll bar", 5 | "keywords": [ 6 | "scroll", 7 | "scrollspy", 8 | "animation" 9 | ], 10 | "version": "1.0.5", 11 | "author": { 12 | "name": "Chris Saylor", 13 | "url": "http://chris-saylor.com" 14 | }, 15 | "licenses": [ 16 | { 17 | "type": "MIT", 18 | "url": "https://github.com/cjsaylor/scrolltab/blob/master/README.md" 19 | } 20 | ], 21 | "homepage": "http://chris-saylor.com/Scrolltab/", 22 | "demo": "http://chris-saylor.com/Scrolltab/example.html", 23 | "dependencies": { 24 | "jquery": ">=1.7" 25 | } 26 | } 27 | --------------------------------------------------------------------------------