├── .gitattributes ├── 404.php ├── README.md ├── archive.php ├── codesniffer.ruleset.xml ├── comments.php ├── content-none.php ├── content-page.php ├── content-search.php ├── content-single.php ├── content.php ├── fonts ├── FontAwesome.otf ├── fontawesome-webfont.eot ├── fontawesome-webfont.svg ├── fontawesome-webfont.ttf └── fontawesome-webfont.woff ├── footer.php ├── functions.php ├── gruntfile.js ├── header.php ├── inc ├── custom-header.php ├── customizer.php ├── extras.php ├── jetpack.php ├── template-tags.php ├── wp_bootstrap_navwalker.php └── wpcom.php ├── index.php ├── js ├── _custom.js ├── bootstrap │ ├── affix.js │ ├── alert.js │ ├── button.js │ ├── carousel.js │ ├── collapse.js │ ├── dropdown.js │ ├── modal.js │ ├── popover.js │ ├── scrollspy.js │ ├── tab.js │ ├── tooltip.js │ └── transition.js └── scripts.min.js ├── languages ├── _s.pot └── readme.txt ├── layouts ├── content-sidebar.css └── sidebar-content.css ├── package.json ├── page.php ├── rtl.css ├── screenshot.png ├── search.php ├── sidebar.php ├── single.php └── styles ├── _reset.scss ├── bootstrap ├── _bootstrap.scss └── bootstrap │ ├── _alerts.scss │ ├── _badges.scss │ ├── _breadcrumbs.scss │ ├── _button-groups.scss │ ├── _buttons.scss │ ├── _carousel.scss │ ├── _close.scss │ ├── _code.scss │ ├── _component-animations.scss │ ├── _dropdowns.scss │ ├── _forms.scss │ ├── _glyphicons.scss │ ├── _grid.scss │ ├── _input-groups.scss │ ├── _jumbotron.scss │ ├── _labels.scss │ ├── _list-group.scss │ ├── _media.scss │ ├── _mixins.scss │ ├── _modals.scss │ ├── _navbar.scss │ ├── _navs.scss │ ├── _normalize.scss │ ├── _pager.scss │ ├── _pagination.scss │ ├── _panels.scss │ ├── _popovers.scss │ ├── _print.scss │ ├── _progress-bars.scss │ ├── _responsive-embed.scss │ ├── _responsive-utilities.scss │ ├── _scaffolding.scss │ ├── _tables.scss │ ├── _theme.scss │ ├── _thumbnails.scss │ ├── _tooltip.scss │ ├── _type.scss │ ├── _utilities.scss │ ├── _variables.scss │ ├── _wells.scss │ └── mixins │ ├── _alerts.scss │ ├── _background-variant.scss │ ├── _border-radius.scss │ ├── _buttons.scss │ ├── _center-block.scss │ ├── _clearfix.scss │ ├── _forms.scss │ ├── _gradients.scss │ ├── _grid-framework.scss │ ├── _grid.scss │ ├── _hide-text.scss │ ├── _image.scss │ ├── _labels.scss │ ├── _list-group.scss │ ├── _nav-divider.scss │ ├── _nav-vertical-align.scss │ ├── _opacity.scss │ ├── _pagination.scss │ ├── _panels.scss │ ├── _progress-bar.scss │ ├── _reset-filter.scss │ ├── _resize.scss │ ├── _responsive-visibility.scss │ ├── _size.scss │ ├── _tab-focus.scss │ ├── _table-row.scss │ ├── _text-emphasis.scss │ ├── _text-overflow.scss │ └── _vendor-prefixes.scss ├── font-awesome ├── _bordered-pulled.scss ├── _core.scss ├── _extras.scss ├── _fixed-width.scss ├── _icons.scss ├── _larger.scss ├── _list.scss ├── _mixins.scss ├── _path.scss ├── _rotated-flipped.scss ├── _spinning.scss ├── _stacked.scss ├── _variables.scss └── font-awesome.scss └── style.scss /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /404.php: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |
12 | 13 |
14 | 17 | 18 |
19 |

20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |

28 |
    29 | 'count', 32 | 'order' => 'DESC', 33 | 'show_count' => 1, 34 | 'title_li' => '', 35 | 'number' => 10, 36 | ) ); 37 | ?> 38 |
39 |
40 | 41 | 42 | ' . sprintf( __( 'Try looking in the monthly archives. %1$s', '_s' ), convert_smilies( ':)' ) ) . '

'; 45 | the_widget( 'WP_Widget_Archives', 'dropdown=1', "after_title=$archive_content" ); 46 | ?> 47 | 48 | 49 | 50 |
51 |
52 | 53 |
54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Underscores-Strap 3 | === 4 | 5 | v0.1.0 6 | * [Wordpress starter theme called _s, or underscores](https://github.com/Automattic/_s) 7 | * [Bootstrap for Sass v3.3.1](https://github.com/twbs/bootstrap-sass) 8 | * [Grunt](http://gruntjs.com/) 9 | 10 | 11 | ##Getting Started 12 | 13 | 14 | 1. ```npm install``` 15 | 2. Setup Underscores following the [getting started guide](https://github.com/automattic/_s) 16 | 3. ```grunt``` to watch for changes and livereload 17 | 18 | 19 | ##Assets management 20 | 21 | ###CSS 22 | * Edit any file in styles/ 23 | * styles/style.scss for all the imports 24 | * Remove/Comment out unwanted components in styles/bootstrap/_bootstrap.scss 25 | 26 | ###Javascript 27 | * js/_custom.js for your custom JS 28 | * Remove unwanted Bootstrap JS components from jsFileList in gruntfile.js 29 | * _custom.js and bootstrap js gets concatenated and minified into scripts.min.js 30 | 31 | ##Misc 32 | ###Font Awesome 33 | * Glyphicons are replaced with [Font Awesome](http://fortawesome.github.io/Font-Awesome/) 34 | -------------------------------------------------------------------------------- /archive.php: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /codesniffer.ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | A custom set of code standard rules to check for Underscores. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /comments.php: -------------------------------------------------------------------------------- 1 | 20 | 21 |
22 | 23 | 24 | 25 | 26 |

27 | ' . get_the_title() . '' ); 30 | ?> 31 |

32 | 33 | 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through ?> 34 | 39 | 40 | 41 |
    42 | 'ol', 45 | 'short_ping' => true, 46 | ) ); 47 | ?> 48 |
49 | 50 | 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through ?> 51 | 56 | 57 | 58 | 59 | 60 | 64 |

65 | 66 | 67 | 68 | 69 |
70 | -------------------------------------------------------------------------------- /content-none.php: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 15 | 16 |
17 | 18 | 19 |

Get started here.', '_s' ), esc_url( admin_url( 'post-new.php' ) ) ); ?>

20 | 21 | 22 | 23 |

24 | 25 | 26 | 27 | 28 |

29 | 30 | 31 | 32 |
33 |
34 | -------------------------------------------------------------------------------- /content-page.php: -------------------------------------------------------------------------------- 1 | 8 | 9 |
> 10 |
11 | ', '' ); ?> 12 |
13 | 14 |
15 | 16 | '', 20 | ) ); 21 | ?> 22 |
23 | 24 | 27 |
28 | -------------------------------------------------------------------------------- /content-search.php: -------------------------------------------------------------------------------- 1 | 10 | 11 |
> 12 |
13 | ', esc_url( get_permalink() ) ), '' ); ?> 14 | 15 | 16 | 19 | 20 |
21 | 22 |
23 | 24 |
25 | 26 | 29 |
30 | -------------------------------------------------------------------------------- /content-single.php: -------------------------------------------------------------------------------- 1 | 6 | 7 |
> 8 |
9 | ', '' ); ?> 10 | 11 | 14 |
15 | 16 |
17 | 18 | '', 22 | ) ); 23 | ?> 24 |
25 | 26 | 29 |
30 | -------------------------------------------------------------------------------- /content.php: -------------------------------------------------------------------------------- 1 | 6 | 7 |
> 8 |
9 | ', esc_url( get_permalink() ) ), '' ); ?> 10 | 11 | 12 | 15 | 16 |
17 | 18 |
19 | →', '_s' ), 23 | the_title( '"', '"', false ) 24 | ) ); 25 | ?> 26 | 27 | '', 31 | ) ); 32 | ?> 33 |
34 | 35 | 38 |
-------------------------------------------------------------------------------- /fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DennisKo/Underscores-Strap/04e8cc9ae9d4d0c6e4232693825888d7e927b8e4/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DennisKo/Underscores-Strap/04e8cc9ae9d4d0c6e4232693825888d7e927b8e4/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DennisKo/Underscores-Strap/04e8cc9ae9d4d0c6e4232693825888d7e927b8e4/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DennisKo/Underscores-Strap/04e8cc9ae9d4d0c6e4232693825888d7e927b8e4/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /footer.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /functions.php: -------------------------------------------------------------------------------- 1 | __( 'Primary Menu', '_s' ), 46 | ) ); 47 | 48 | /* 49 | * Switch default core markup for search form, comment form, and comments 50 | * to output valid HTML5. 51 | */ 52 | add_theme_support( 'html5', array( 53 | 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 54 | ) ); 55 | 56 | /* 57 | * Enable support for Post Formats. 58 | * See http://codex.wordpress.org/Post_Formats 59 | */ 60 | add_theme_support( 'post-formats', array( 61 | 'aside', 'image', 'video', 'quote', 'link', 62 | ) ); 63 | 64 | // Set up the WordPress core custom background feature. 65 | add_theme_support( 'custom-background', apply_filters( '_s_custom_background_args', array( 66 | 'default-color' => 'ffffff', 67 | 'default-image' => '', 68 | ) ) ); 69 | } 70 | endif; // _s_setup 71 | add_action( 'after_setup_theme', '_s_setup' ); 72 | 73 | /** 74 | * Register widget area. 75 | * 76 | * @link http://codex.wordpress.org/Function_Reference/register_sidebar 77 | */ 78 | function _s_widgets_init() { 79 | register_sidebar( array( 80 | 'name' => __( 'Sidebar', '_s' ), 81 | 'id' => 'sidebar-1', 82 | 'description' => '', 83 | 'before_widget' => '
', 84 | 'after_widget' => '
', 85 | 'before_title' => '

', 86 | 'after_title' => '

', 87 | ) ); 88 | } 89 | add_action( 'widgets_init', '_s_widgets_init' ); 90 | 91 | /** 92 | * Enqueue scripts and styles. 93 | */ 94 | function _s_scripts() { 95 | wp_enqueue_style( '_s-style', get_stylesheet_uri() ); 96 | 97 | wp_enqueue_script( '_s-scripts', get_template_directory_uri() . '/js/scripts.min.js', array('jquery'), '20120206', true ); 98 | 99 | } 100 | add_action( 'wp_enqueue_scripts', '_s_scripts' ); 101 | 102 | /** 103 | * Implement the Custom Header feature. 104 | */ 105 | //require get_template_directory() . '/inc/custom-header.php'; 106 | 107 | /** 108 | * Custom template tags for this theme. 109 | */ 110 | require get_template_directory() . '/inc/template-tags.php'; 111 | 112 | /** 113 | * Custom functions that act independently of the theme templates. 114 | */ 115 | require get_template_directory() . '/inc/extras.php'; 116 | 117 | /** 118 | * Customizer additions. 119 | */ 120 | require get_template_directory() . '/inc/customizer.php'; 121 | 122 | /** 123 | * Load Jetpack compatibility file. 124 | */ 125 | require get_template_directory() . '/inc/jetpack.php'; 126 | 127 | // Register Custom Navigation Walker for Bootstrap 128 | require_once('inc/wp_bootstrap_navwalker.php'); 129 | -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | var mountFolder = function(connect, dir) { 2 | return connect.static(require('path').resolve(dir)); 3 | }; 4 | 5 | module.exports = function(grunt) { 6 | 7 | // Time how long tasks take. Can help when optimizing build times 8 | require('time-grunt')(grunt); 9 | 10 | // Load grunt tasks automatically 11 | // require('load-grunt-tasks')(grunt); 12 | require('jit-grunt')(grunt); 13 | 14 | var jsFileList = [ 15 | 'js/bootstrap/transition.js', 16 | 'js/bootstrap/alert.js', 17 | 'js/bootstrap/button.js', 18 | 'js/bootstrap/carousel.js', 19 | 'js/bootstrap/collapse.js', 20 | 'js/bootstrap/dropdown.js', 21 | 'js/bootstrap/modal.js', 22 | 'js/bootstrap/tooltip.js', 23 | 'js/bootstrap/popover.js', 24 | 'js/bootstrap/scrollspy.js', 25 | 'js/bootstrap/tab.js', 26 | 'js/bootstrap/affix.js', 27 | 'js/_*.js' 28 | ]; 29 | 30 | grunt.initConfig({ 31 | pkg: grunt.file.readJSON('package.json'), 32 | 33 | concat: { 34 | options: { 35 | separator: ';', 36 | }, 37 | dist: { 38 | src: [jsFileList], 39 | dest: 'js/scripts.min.js', 40 | }, 41 | }, 42 | 43 | uglify: { 44 | dist: { 45 | files: { 46 | 'js/scripts.min.js': [jsFileList] 47 | } 48 | } 49 | }, 50 | 51 | sass: { 52 | dist: { 53 | options: { 54 | trace: true, 55 | style: 'compressed' 56 | }, 57 | files: { 58 | 'style.css': 'styles/style.scss' 59 | } 60 | } 61 | }, 62 | 63 | autoprefixer: { 64 | options: { 65 | browsers:['last 2 versions', 'ie 8', 'ie 7'] 66 | }, 67 | target: { 68 | src: 'style.css', 69 | dest: 'style.css' 70 | } 71 | }, 72 | 73 | watch: { 74 | sass: { 75 | files: [ 76 | 'styles/*.scss', 77 | 'styles/**/*.scss' 78 | ], 79 | tasks: ['sass', 'autoprefixer'] 80 | }, 81 | js: { 82 | files: [ 83 | jsFileList 84 | ], 85 | tasks: ['concat','uglify'] 86 | }, 87 | livereload: { 88 | // Browser live reloading 89 | // https://github.com/gruntjs/grunt-contrib-watch#live-reloading 90 | options: { 91 | livereload: true 92 | }, 93 | files: [ 94 | 'style.css', 95 | 'js/scripts.min.js', 96 | 'inc/*.php', 97 | '*.php' 98 | ] 99 | } 100 | } 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | }); 109 | 110 | 111 | // default task(s) 112 | grunt.registerTask('default', function() { 113 | grunt.task.run([ 114 | 'concat', 115 | 'uglify', 116 | 'sass', 117 | 'watch' 118 | ]); 119 | }); 120 | }; 121 | -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 | section and everything up till
6 | * 7 | * @package _s 8 | */ 9 | ?> 10 | > 11 | 12 | 13 | 14 | <?php wp_title( '|', true, 'right' ); ?> 15 | 16 | 17 | 18 | 19 | 20 | 21 | > 22 |
23 | 55 |
56 | -------------------------------------------------------------------------------- /inc/custom-header.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | * 15 | * @package _s 16 | */ 17 | 18 | /** 19 | * Set up the WordPress core custom header feature. 20 | * 21 | * @uses _s_header_style() 22 | * @uses _s_admin_header_style() 23 | * @uses _s_admin_header_image() 24 | */ 25 | function _s_custom_header_setup() { 26 | add_theme_support( 'custom-header', apply_filters( '_s_custom_header_args', array( 27 | 'default-image' => '', 28 | 'default-text-color' => '000000', 29 | 'width' => 1000, 30 | 'height' => 250, 31 | 'flex-height' => true, 32 | 'wp-head-callback' => '_s_header_style', 33 | 'admin-head-callback' => '_s_admin_header_style', 34 | 'admin-preview-callback' => '_s_admin_header_image', 35 | ) ) ); 36 | } 37 | add_action( 'after_setup_theme', '_s_custom_header_setup' ); 38 | 39 | if ( ! function_exists( '_s_header_style' ) ) : 40 | /** 41 | * Styles the header image and text displayed on the blog 42 | * 43 | * @see _s_custom_header_setup(). 44 | */ 45 | function _s_header_style() { 46 | $header_text_color = get_header_textcolor(); 47 | 48 | // If no custom options for text are set, let's bail 49 | // get_header_textcolor() options: HEADER_TEXTCOLOR is default, hide text (returns 'blank') or any hex value 50 | if ( HEADER_TEXTCOLOR == $header_text_color ) { 51 | return; 52 | } 53 | 54 | // If we get this far, we have custom styles. Let's do this. 55 | ?> 56 | 76 | Header admin panel. 83 | * 84 | * @see _s_custom_header_setup(). 85 | */ 86 | function _s_admin_header_style() { 87 | ?> 88 | 104 | Header admin panel. 111 | * 112 | * @see _s_custom_header_setup(). 113 | */ 114 | function _s_admin_header_image() { 115 | $style = sprintf( ' style="color:#%s;"', get_header_textcolor() ); 116 | ?> 117 |
118 |

onclick="return false;" href="">

119 |
>
120 | 121 | 122 | 123 |
124 | get_setting( 'blogname' )->transport = 'postMessage'; 15 | $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; 16 | $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage'; 17 | } 18 | add_action( 'customize_register', '_s_customize_register' ); 19 | 20 | /** 21 | * Binds JS handlers to make Theme Customizer preview reload changes asynchronously. 22 | */ 23 | function _s_customize_preview_js() { 24 | wp_enqueue_script( '_s_customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), '20130508', true ); 25 | } 26 | add_action( 'customize_preview_init', '_s_customize_preview_js' ); 27 | -------------------------------------------------------------------------------- /inc/extras.php: -------------------------------------------------------------------------------- 1 | tag based on what is being viewed. 40 | * 41 | * @param string $title Default title text for current view. 42 | * @param string $sep Optional separator. 43 | * @return string The filtered title. 44 | */ 45 | function _s_wp_title( $title, $sep ) { 46 | if ( is_feed() ) { 47 | return $title; 48 | } 49 | 50 | global $page, $paged; 51 | 52 | // Add the blog name 53 | $title .= get_bloginfo( 'name', 'display' ); 54 | 55 | // Add the blog description for the home/front page. 56 | $site_description = get_bloginfo( 'description', 'display' ); 57 | if ( $site_description && ( is_home() || is_front_page() ) ) { 58 | $title .= " $sep $site_description"; 59 | } 60 | 61 | // Add a page number if necessary: 62 | if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) { 63 | $title .= " $sep " . sprintf( __( 'Page %s', '_s' ), max( $paged, $page ) ); 64 | } 65 | 66 | return $title; 67 | } 68 | add_filter( 'wp_title', '_s_wp_title', 10, 2 ); 69 | 70 | /** 71 | * Sets the authordata global when viewing an author archive. 72 | * 73 | * This provides backwards compatibility with 74 | * http://core.trac.wordpress.org/changeset/25574 75 | * 76 | * It removes the need to call the_post() and rewind_posts() in an author 77 | * template to print information about the author. 78 | * 79 | * @global WP_Query $wp_query WordPress Query object. 80 | * @return void 81 | */ 82 | function _s_setup_author() { 83 | global $wp_query; 84 | 85 | if ( $wp_query->is_author() && isset( $wp_query->post ) ) { 86 | $GLOBALS['authordata'] = get_userdata( $wp_query->post->post_author ); 87 | } 88 | } 89 | add_action( 'wp', '_s_setup_author' ); 90 | -------------------------------------------------------------------------------- /inc/jetpack.php: -------------------------------------------------------------------------------- 1 | 'main', 16 | 'footer' => 'page', 17 | ) ); 18 | } 19 | add_action( 'after_setup_theme', '_s_jetpack_setup' ); 20 | -------------------------------------------------------------------------------- /inc/wpcom.php: -------------------------------------------------------------------------------- 1 | '', 22 | 'border' => '', 23 | 'text' => '', 24 | 'link' => '', 25 | 'url' => '', 26 | ); 27 | } 28 | } 29 | add_action( 'after_setup_theme', '_s_wpcom_setup' ); 30 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 15 | 16 |
17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /js/_custom.js: -------------------------------------------------------------------------------- 1 | // Your custom js here 2 | -------------------------------------------------------------------------------- /js/bootstrap/affix.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: affix.js v3.3.1 3 | * http://getbootstrap.com/javascript/#affix 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // AFFIX CLASS DEFINITION 14 | // ====================== 15 | 16 | var Affix = function (element, options) { 17 | this.options = $.extend({}, Affix.DEFAULTS, options) 18 | 19 | this.$target = $(this.options.target) 20 | .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 21 | .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 22 | 23 | this.$element = $(element) 24 | this.affixed = 25 | this.unpin = 26 | this.pinnedOffset = null 27 | 28 | this.checkPosition() 29 | } 30 | 31 | Affix.VERSION = '3.3.1' 32 | 33 | Affix.RESET = 'affix affix-top affix-bottom' 34 | 35 | Affix.DEFAULTS = { 36 | offset: 0, 37 | target: window 38 | } 39 | 40 | Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { 41 | var scrollTop = this.$target.scrollTop() 42 | var position = this.$element.offset() 43 | var targetHeight = this.$target.height() 44 | 45 | if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false 46 | 47 | if (this.affixed == 'bottom') { 48 | if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' 49 | return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' 50 | } 51 | 52 | var initializing = this.affixed == null 53 | var colliderTop = initializing ? scrollTop : position.top 54 | var colliderHeight = initializing ? targetHeight : height 55 | 56 | if (offsetTop != null && colliderTop <= offsetTop) return 'top' 57 | if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' 58 | 59 | return false 60 | } 61 | 62 | Affix.prototype.getPinnedOffset = function () { 63 | if (this.pinnedOffset) return this.pinnedOffset 64 | this.$element.removeClass(Affix.RESET).addClass('affix') 65 | var scrollTop = this.$target.scrollTop() 66 | var position = this.$element.offset() 67 | return (this.pinnedOffset = position.top - scrollTop) 68 | } 69 | 70 | Affix.prototype.checkPositionWithEventLoop = function () { 71 | setTimeout($.proxy(this.checkPosition, this), 1) 72 | } 73 | 74 | Affix.prototype.checkPosition = function () { 75 | if (!this.$element.is(':visible')) return 76 | 77 | var height = this.$element.height() 78 | var offset = this.options.offset 79 | var offsetTop = offset.top 80 | var offsetBottom = offset.bottom 81 | var scrollHeight = $('body').height() 82 | 83 | if (typeof offset != 'object') offsetBottom = offsetTop = offset 84 | if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) 85 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) 86 | 87 | var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) 88 | 89 | if (this.affixed != affix) { 90 | if (this.unpin != null) this.$element.css('top', '') 91 | 92 | var affixType = 'affix' + (affix ? '-' + affix : '') 93 | var e = $.Event(affixType + '.bs.affix') 94 | 95 | this.$element.trigger(e) 96 | 97 | if (e.isDefaultPrevented()) return 98 | 99 | this.affixed = affix 100 | this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null 101 | 102 | this.$element 103 | .removeClass(Affix.RESET) 104 | .addClass(affixType) 105 | .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') 106 | } 107 | 108 | if (affix == 'bottom') { 109 | this.$element.offset({ 110 | top: scrollHeight - height - offsetBottom 111 | }) 112 | } 113 | } 114 | 115 | 116 | // AFFIX PLUGIN DEFINITION 117 | // ======================= 118 | 119 | function Plugin(option) { 120 | return this.each(function () { 121 | var $this = $(this) 122 | var data = $this.data('bs.affix') 123 | var options = typeof option == 'object' && option 124 | 125 | if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 126 | if (typeof option == 'string') data[option]() 127 | }) 128 | } 129 | 130 | var old = $.fn.affix 131 | 132 | $.fn.affix = Plugin 133 | $.fn.affix.Constructor = Affix 134 | 135 | 136 | // AFFIX NO CONFLICT 137 | // ================= 138 | 139 | $.fn.affix.noConflict = function () { 140 | $.fn.affix = old 141 | return this 142 | } 143 | 144 | 145 | // AFFIX DATA-API 146 | // ============== 147 | 148 | $(window).on('load', function () { 149 | $('[data-spy="affix"]').each(function () { 150 | var $spy = $(this) 151 | var data = $spy.data() 152 | 153 | data.offset = data.offset || {} 154 | 155 | if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom 156 | if (data.offsetTop != null) data.offset.top = data.offsetTop 157 | 158 | Plugin.call($spy, data) 159 | }) 160 | }) 161 | 162 | }(jQuery); 163 | -------------------------------------------------------------------------------- /js/bootstrap/alert.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: alert.js v3.3.1 3 | * http://getbootstrap.com/javascript/#alerts 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // ALERT CLASS DEFINITION 14 | // ====================== 15 | 16 | var dismiss = '[data-dismiss="alert"]' 17 | var Alert = function (el) { 18 | $(el).on('click', dismiss, this.close) 19 | } 20 | 21 | Alert.VERSION = '3.3.1' 22 | 23 | Alert.TRANSITION_DURATION = 150 24 | 25 | Alert.prototype.close = function (e) { 26 | var $this = $(this) 27 | var selector = $this.attr('data-target') 28 | 29 | if (!selector) { 30 | selector = $this.attr('href') 31 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 32 | } 33 | 34 | var $parent = $(selector) 35 | 36 | if (e) e.preventDefault() 37 | 38 | if (!$parent.length) { 39 | $parent = $this.closest('.alert') 40 | } 41 | 42 | $parent.trigger(e = $.Event('close.bs.alert')) 43 | 44 | if (e.isDefaultPrevented()) return 45 | 46 | $parent.removeClass('in') 47 | 48 | function removeElement() { 49 | // detach from parent, fire event then clean up data 50 | $parent.detach().trigger('closed.bs.alert').remove() 51 | } 52 | 53 | $.support.transition && $parent.hasClass('fade') ? 54 | $parent 55 | .one('bsTransitionEnd', removeElement) 56 | .emulateTransitionEnd(Alert.TRANSITION_DURATION) : 57 | removeElement() 58 | } 59 | 60 | 61 | // ALERT PLUGIN DEFINITION 62 | // ======================= 63 | 64 | function Plugin(option) { 65 | return this.each(function () { 66 | var $this = $(this) 67 | var data = $this.data('bs.alert') 68 | 69 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 70 | if (typeof option == 'string') data[option].call($this) 71 | }) 72 | } 73 | 74 | var old = $.fn.alert 75 | 76 | $.fn.alert = Plugin 77 | $.fn.alert.Constructor = Alert 78 | 79 | 80 | // ALERT NO CONFLICT 81 | // ================= 82 | 83 | $.fn.alert.noConflict = function () { 84 | $.fn.alert = old 85 | return this 86 | } 87 | 88 | 89 | // ALERT DATA-API 90 | // ============== 91 | 92 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 93 | 94 | }(jQuery); 95 | -------------------------------------------------------------------------------- /js/bootstrap/button.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: button.js v3.3.1 3 | * http://getbootstrap.com/javascript/#buttons 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // BUTTON PUBLIC CLASS DEFINITION 14 | // ============================== 15 | 16 | var Button = function (element, options) { 17 | this.$element = $(element) 18 | this.options = $.extend({}, Button.DEFAULTS, options) 19 | this.isLoading = false 20 | } 21 | 22 | Button.VERSION = '3.3.1' 23 | 24 | Button.DEFAULTS = { 25 | loadingText: 'loading...' 26 | } 27 | 28 | Button.prototype.setState = function (state) { 29 | var d = 'disabled' 30 | var $el = this.$element 31 | var val = $el.is('input') ? 'val' : 'html' 32 | var data = $el.data() 33 | 34 | state = state + 'Text' 35 | 36 | if (data.resetText == null) $el.data('resetText', $el[val]()) 37 | 38 | // push to event loop to allow forms to submit 39 | setTimeout($.proxy(function () { 40 | $el[val](data[state] == null ? this.options[state] : data[state]) 41 | 42 | if (state == 'loadingText') { 43 | this.isLoading = true 44 | $el.addClass(d).attr(d, d) 45 | } else if (this.isLoading) { 46 | this.isLoading = false 47 | $el.removeClass(d).removeAttr(d) 48 | } 49 | }, this), 0) 50 | } 51 | 52 | Button.prototype.toggle = function () { 53 | var changed = true 54 | var $parent = this.$element.closest('[data-toggle="buttons"]') 55 | 56 | if ($parent.length) { 57 | var $input = this.$element.find('input') 58 | if ($input.prop('type') == 'radio') { 59 | if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 60 | else $parent.find('.active').removeClass('active') 61 | } 62 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 63 | } else { 64 | this.$element.attr('aria-pressed', !this.$element.hasClass('active')) 65 | } 66 | 67 | if (changed) this.$element.toggleClass('active') 68 | } 69 | 70 | 71 | // BUTTON PLUGIN DEFINITION 72 | // ======================== 73 | 74 | function Plugin(option) { 75 | return this.each(function () { 76 | var $this = $(this) 77 | var data = $this.data('bs.button') 78 | var options = typeof option == 'object' && option 79 | 80 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 81 | 82 | if (option == 'toggle') data.toggle() 83 | else if (option) data.setState(option) 84 | }) 85 | } 86 | 87 | var old = $.fn.button 88 | 89 | $.fn.button = Plugin 90 | $.fn.button.Constructor = Button 91 | 92 | 93 | // BUTTON NO CONFLICT 94 | // ================== 95 | 96 | $.fn.button.noConflict = function () { 97 | $.fn.button = old 98 | return this 99 | } 100 | 101 | 102 | // BUTTON DATA-API 103 | // =============== 104 | 105 | $(document) 106 | .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 107 | var $btn = $(e.target) 108 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 109 | Plugin.call($btn, 'toggle') 110 | e.preventDefault() 111 | }) 112 | .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { 113 | $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) 114 | }) 115 | 116 | }(jQuery); 117 | -------------------------------------------------------------------------------- /js/bootstrap/collapse.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: collapse.js v3.3.1 3 | * http://getbootstrap.com/javascript/#collapse 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // COLLAPSE PUBLIC CLASS DEFINITION 14 | // ================================ 15 | 16 | var Collapse = function (element, options) { 17 | this.$element = $(element) 18 | this.options = $.extend({}, Collapse.DEFAULTS, options) 19 | this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]') 20 | this.transitioning = null 21 | 22 | if (this.options.parent) { 23 | this.$parent = this.getParent() 24 | } else { 25 | this.addAriaAndCollapsedClass(this.$element, this.$trigger) 26 | } 27 | 28 | if (this.options.toggle) this.toggle() 29 | } 30 | 31 | Collapse.VERSION = '3.3.1' 32 | 33 | Collapse.TRANSITION_DURATION = 350 34 | 35 | Collapse.DEFAULTS = { 36 | toggle: true, 37 | trigger: '[data-toggle="collapse"]' 38 | } 39 | 40 | Collapse.prototype.dimension = function () { 41 | var hasWidth = this.$element.hasClass('width') 42 | return hasWidth ? 'width' : 'height' 43 | } 44 | 45 | Collapse.prototype.show = function () { 46 | if (this.transitioning || this.$element.hasClass('in')) return 47 | 48 | var activesData 49 | var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing') 50 | 51 | if (actives && actives.length) { 52 | activesData = actives.data('bs.collapse') 53 | if (activesData && activesData.transitioning) return 54 | } 55 | 56 | var startEvent = $.Event('show.bs.collapse') 57 | this.$element.trigger(startEvent) 58 | if (startEvent.isDefaultPrevented()) return 59 | 60 | if (actives && actives.length) { 61 | Plugin.call(actives, 'hide') 62 | activesData || actives.data('bs.collapse', null) 63 | } 64 | 65 | var dimension = this.dimension() 66 | 67 | this.$element 68 | .removeClass('collapse') 69 | .addClass('collapsing')[dimension](0) 70 | .attr('aria-expanded', true) 71 | 72 | this.$trigger 73 | .removeClass('collapsed') 74 | .attr('aria-expanded', true) 75 | 76 | this.transitioning = 1 77 | 78 | var complete = function () { 79 | this.$element 80 | .removeClass('collapsing') 81 | .addClass('collapse in')[dimension]('') 82 | this.transitioning = 0 83 | this.$element 84 | .trigger('shown.bs.collapse') 85 | } 86 | 87 | if (!$.support.transition) return complete.call(this) 88 | 89 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 90 | 91 | this.$element 92 | .one('bsTransitionEnd', $.proxy(complete, this)) 93 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) 94 | } 95 | 96 | Collapse.prototype.hide = function () { 97 | if (this.transitioning || !this.$element.hasClass('in')) return 98 | 99 | var startEvent = $.Event('hide.bs.collapse') 100 | this.$element.trigger(startEvent) 101 | if (startEvent.isDefaultPrevented()) return 102 | 103 | var dimension = this.dimension() 104 | 105 | this.$element[dimension](this.$element[dimension]())[0].offsetHeight 106 | 107 | this.$element 108 | .addClass('collapsing') 109 | .removeClass('collapse in') 110 | .attr('aria-expanded', false) 111 | 112 | this.$trigger 113 | .addClass('collapsed') 114 | .attr('aria-expanded', false) 115 | 116 | this.transitioning = 1 117 | 118 | var complete = function () { 119 | this.transitioning = 0 120 | this.$element 121 | .removeClass('collapsing') 122 | .addClass('collapse') 123 | .trigger('hidden.bs.collapse') 124 | } 125 | 126 | if (!$.support.transition) return complete.call(this) 127 | 128 | this.$element 129 | [dimension](0) 130 | .one('bsTransitionEnd', $.proxy(complete, this)) 131 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION) 132 | } 133 | 134 | Collapse.prototype.toggle = function () { 135 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 136 | } 137 | 138 | Collapse.prototype.getParent = function () { 139 | return $(this.options.parent) 140 | .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') 141 | .each($.proxy(function (i, element) { 142 | var $element = $(element) 143 | this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) 144 | }, this)) 145 | .end() 146 | } 147 | 148 | Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { 149 | var isOpen = $element.hasClass('in') 150 | 151 | $element.attr('aria-expanded', isOpen) 152 | $trigger 153 | .toggleClass('collapsed', !isOpen) 154 | .attr('aria-expanded', isOpen) 155 | } 156 | 157 | function getTargetFromTrigger($trigger) { 158 | var href 159 | var target = $trigger.attr('data-target') 160 | || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 161 | 162 | return $(target) 163 | } 164 | 165 | 166 | // COLLAPSE PLUGIN DEFINITION 167 | // ========================== 168 | 169 | function Plugin(option) { 170 | return this.each(function () { 171 | var $this = $(this) 172 | var data = $this.data('bs.collapse') 173 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 174 | 175 | if (!data && options.toggle && option == 'show') options.toggle = false 176 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 177 | if (typeof option == 'string') data[option]() 178 | }) 179 | } 180 | 181 | var old = $.fn.collapse 182 | 183 | $.fn.collapse = Plugin 184 | $.fn.collapse.Constructor = Collapse 185 | 186 | 187 | // COLLAPSE NO CONFLICT 188 | // ==================== 189 | 190 | $.fn.collapse.noConflict = function () { 191 | $.fn.collapse = old 192 | return this 193 | } 194 | 195 | 196 | // COLLAPSE DATA-API 197 | // ================= 198 | 199 | $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 200 | var $this = $(this) 201 | 202 | if (!$this.attr('data-target')) e.preventDefault() 203 | 204 | var $target = getTargetFromTrigger($this) 205 | var data = $target.data('bs.collapse') 206 | var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this }) 207 | 208 | Plugin.call($target, option) 209 | }) 210 | 211 | }(jQuery); 212 | -------------------------------------------------------------------------------- /js/bootstrap/dropdown.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: dropdown.js v3.3.1 3 | * http://getbootstrap.com/javascript/#dropdowns 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // DROPDOWN CLASS DEFINITION 14 | // ========================= 15 | 16 | var backdrop = '.dropdown-backdrop' 17 | var toggle = '[data-toggle="dropdown"]' 18 | var Dropdown = function (element) { 19 | $(element).on('click.bs.dropdown', this.toggle) 20 | } 21 | 22 | Dropdown.VERSION = '3.3.1' 23 | 24 | Dropdown.prototype.toggle = function (e) { 25 | var $this = $(this) 26 | 27 | if ($this.is('.disabled, :disabled')) return 28 | 29 | var $parent = getParent($this) 30 | var isActive = $parent.hasClass('open') 31 | 32 | clearMenus() 33 | 34 | if (!isActive) { 35 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 36 | // if mobile we use a backdrop because click events don't delegate 37 | $('