diff --git a/404.php b/404.php index e54b95e8..01f43441 100644 --- a/404.php +++ b/404.php @@ -1,42 +1,42 @@ - -
- -
+ +
+ +
-
- -
+
+ +
-
- -

-

- -
- -
- -
- -

+
+ +

+

+ +
+ +
+ +
+ +

-
-
- -
-
- -
- -
- -
- -
- -
+
+
+ +
+
+ + + +
+ +
+ + + +
-
+
\ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 265d32dd..a59cdc47 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,134 +1,142 @@ 'use strict'; -module.exports = function(grunt) { +module.exports = function (grunt) { - grunt.initConfig({ - jshint: { - options: { - jshintrc: '.jshintrc' - }, - all: [ - 'library/js/scripts.js', - 'bower_components/bootstrap/js/*.js' - ] - }, - less: { - dist: { - files: { - 'library/dist/css/styles.css': [ - 'library/less/styles.less' - ] - }, - options: { - compress: true, - // LESS source map - // To enable, set sourceMap to true and update sourceMapRootpath based on your install - sourceMap: true, - sourceMapFilename: 'library/dist/css/styles.css.map', - sourceMapRootpath: '/wp-content/themes/wordpress-bootstrap/' // If you name your theme something different you may need to change this + grunt.initConfig( + { + jshint: { + options: { + jshintrc: '.jshintrc' + }, + all: [ + 'library/js/scripts.js', + 'bower_components/bootstrap/js/*.js' + ] + }, + less: { + dist: { + files: { + 'library/dist/css/styles.css': [ + 'library/less/styles.less' + ] + }, + options: { + compress: true, + // LESS source map + // To enable, set sourceMap to true and update sourceMapRootpath based on your install + sourceMap: true, + sourceMapFilename: 'library/dist/css/styles.css.map', + sourceMapRootpath: '/wp-content/themes/wordpress-bootstrap/' // If you name your theme something different you may need to change this + } + } + }, + uglify: { + dist: { + files: { + 'library/dist/js/scripts.min.js': [ + 'library/js/*.js' + ] + // Consider adding bootstrap js files here to consolidate your browser requests + }, + options: { + // JS source map: to enable, uncomment the lines below and update sourceMappingURL based on your install + // sourceMap: 'assets/js/scripts.min.js.map', + // sourceMappingURL: '/app/themes/roots/assets/js/scripts.min.js.map' + } + } + }, + grunticon: { + myIcons: { + files: [{ + expand: true, + cwd: 'library/img', + src: ['*.svg', '*.png'], + dest: "library/img" + }], + options: { + } + } + }, + version: { + assets: { + files: { + 'functions.php': ['library/dist/css/styles.css', 'library/dist/js/scripts.min.js'] + } + } + }, + watch: { + less: { + files: [ + 'bower_components/bootstrap/less/*.less', + 'bower_components/font-awesome/less/*.less', + 'library/less/*.less' + ], + tasks: ['less', 'version'] + }, + js: { + files: [ + '<%= jshint.all %>' + ], + tasks: ['uglify'] + }, + livereload: { + // Browser live reloading + // https://github.com/gruntjs/grunt-contrib-watch#live-reloading + options: { + livereload: true + }, + files: [ + 'library/dist/css/styles.css', + 'library/js/*', + 'style.css', + '*.php' + ] + } + }, + clean: { + dist: [ + 'library/dist/css', + 'library/dist/js' + ] + } } - } - }, - uglify: { - dist: { - files: { - 'library/dist/js/scripts.min.js': [ - 'library/js/*.js' - ] - // Consider adding bootstrap js files here to consolidate your browser requests - }, - options: { - // JS source map: to enable, uncomment the lines below and update sourceMappingURL based on your install - // sourceMap: 'assets/js/scripts.min.js.map', - // sourceMappingURL: '/app/themes/roots/assets/js/scripts.min.js.map' - } - } - }, - grunticon: { - myIcons: { - files: [{ - expand: true, - cwd: 'library/img', - src: ['*.svg', '*.png'], - dest: "library/img" - }], - options: { - } - } - }, - version: { - assets: { - files: { - 'functions.php': ['library/dist/css/styles.css', 'library/dist/js/scripts.min.js'] - } - } - }, - watch: { - less: { - files: [ - 'bower_components/bootstrap/less/*.less', - 'bower_components/font-awesome/less/*.less', - 'library/less/*.less' - ], - tasks: ['less', 'version'] - }, - js: { - files: [ - '<%= jshint.all %>' - ], - tasks: ['uglify'] - }, - livereload: { - // Browser live reloading - // https://github.com/gruntjs/grunt-contrib-watch#live-reloading - options: { - livereload: true - }, - files: [ - 'library/dist/css/styles.css', - 'library/js/*', - 'style.css', - '*.php' - ] - } - }, - clean: { - dist: [ - 'library/dist/css', - 'library/dist/js' - ] - } - }); + ); - // Load tasks - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-less'); - grunt.loadNpmTasks('grunt-wp-assets'); - grunt.loadNpmTasks('grunt-grunticon'); - grunt.loadNpmTasks('grunt-svgstore'); + // Load tasks + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-less'); + grunt.loadNpmTasks('grunt-wp-assets'); + grunt.loadNpmTasks('grunt-grunticon'); + grunt.loadNpmTasks('grunt-svgstore'); - // Register tasks - grunt.registerTask('default', [ - 'clean', - 'less', - 'uglify', - 'grunticon', - 'version' - ]); + // Register tasks + grunt.registerTask( + 'default', [ + 'clean', + 'less', + 'uglify', + 'grunticon', + 'version' + ] + ); - grunt.registerTask('build', [ - 'clean:dist', - 'less', - 'uglify', - 'grunticon', - 'version' - ]); + grunt.registerTask( + 'build', [ + 'clean:dist', + 'less', + 'uglify', + 'grunticon', + 'version' + ] + ); - grunt.registerTask('dev', [ - 'grunticon', - 'watch' - ]); + grunt.registerTask( + 'dev', [ + 'grunticon', + 'watch' + ] + ); }; diff --git a/README.md b/README.md index ae84809b..b748ee86 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,30 @@ -WP BOOTSTRAP +#WORDPRESS BOOTSTRAP =================== -Bootstrap (http://getbootstrap.com) in WordPress theme form. +Bootstrap (https://github.com/arnabwahid/wordpress-bootstrap/) in WordPress theme form. -GETTING STARTED -_______________ +# GETTING STARTED To get started, open Terminal or a command prompt and run: cd path/to/wp-content/themes - git clone https://github.com/320press/wordpress-bootstrap.git + git clone https://github.com/arnabwahid/wordpress-bootstrap.git npm install grunt dev -FEATURES -________ +# FEATURES We’ve built the WP Bootstrap theme so that it could be used as-is as a very basic theme or as a starting point for theme developers. It uses v3.3.1 of Bootstrap. WP-Bootstrap uses grunt as a task manager to help aid development. Check out the gruntfile.js file for more detail on the default tasks. WP-Bootstrap comes with the livereload, less, grunticon and more tasks out of the box. -Watch or star this project to keep up with its progress. +Watch or star this project to keep up with its progress.Thank you!🙂 -Multi-Lingual -_____________ +# Multi-Lingual WP-Bootstrap is translated in 7 languages - Spanish, French, Portuguese, Italian, Dutch, Swedish and German. -Page Templates +# Page Templates ______________ We’ve packaged four different page templates into this theme. @@ -37,24 +34,20 @@ We’ve packaged four different page templates into this theme. - Page with left sidebar - Full width page -Theme Options Panel -___________________ +# Theme Options Panel We've removed the custom theme options panel in version 3.0. Currently working on moving all of the options that used to appear there over to the theme customizer. -Shortcodes -__________ +# Shortcodes We’ve built in some shortcodes so you can easily add UI elements found in Bootstrap. -Sidebars -________ +# Sidebars There are two different sidebars. One for the homepage and one for the other pages. Add widgets to them. -CONTRIBUTE! -___________ +# CONTRIBUTE! This project would not exist in its current state today were it not for lots of generous folks who have contributed to it. Thank you! -If you'd like to commit to this project please submit a pull request and I will do my best to merge appropriately. \ No newline at end of file +If you'd like to commit to this project please submit a pull request and I will do my best to merge appropriately. diff --git a/archive.php b/archive.php index b76d4882..9aaaa8bc 100644 --- a/archive.php +++ b/archive.php @@ -1,98 +1,98 @@ - -
- -
- - + +
+ +
+ + - - -
role="article"> - -
- -

- -

& .

- -
- -
- - - - - -
- -
- -
- -
- - - - - - + + +
role="article"> + +
+ +

+ +

& .

+ +
+ +
+ + + + + +
+ +
+ +
+ +
+ + + + + + - - - - - - - -
-
-

-
-
-

-
-
-
-
- - - -
+ + + + + + + +
+
+

+
+
+

+
+
+
+
+ + + +
- + -
+
\ No newline at end of file diff --git a/attachment.php b/attachment.php index 505238db..6efba974 100644 --- a/attachment.php +++ b/attachment.php @@ -1,58 +1,58 @@ - -
- -
+ +
+ +
- - -
role="article" itemscope itemtype="http://schema.org/BlogPosting"> - -
- - - -

& .

- -
- -
- - - -
- -
- - ' . __("Tags","wpbootstrap") . ': ', ' ', '

'); ?> - -
- -
- - - - - - - -
-
-

-
-
-

-
-
-
-
- - - -
+ + +
role="article" itemscope itemtype="http://schema.org/BlogPosting"> + +
+ + + +

& .

+ +
+ +
+ + + +
+ +
+ + ' . __("Tags", "wpbootstrap") . ': ', ' ', '

'); ?> + +
+ +
+ + + + + + + +
+
+

+
+
+

+
+
+
+
+ + + +
- + -
+
\ No newline at end of file diff --git a/author.php b/author.php index 7675d039..31a9be55 100644 --- a/author.php +++ b/author.php @@ -1,86 +1,86 @@ - -
- -
- - - - - -
role="article"> - -
- -

- -

& .

- -
- -
- - - - - -
- -
- -
- -
- - - - - - + +
+ +
+ + + + + +
role="article"> + +
+ +

+ +

& .

+ +
+ +
+ + + + + +
+ +
+ +
+ +
+ + + + + + - - - - - - - -
-
-

-
-
-

-
-
-
-
- - - -
+ + + + + + + +
+
+

+
+
+

+
+
+
+
+ + + +
- + -
+
\ No newline at end of file diff --git a/bower_components/bootstrap/Gruntfile.js b/bower_components/bootstrap/Gruntfile.js index 76fbbcba..71c901b6 100644 --- a/bower_components/bootstrap/Gruntfile.js +++ b/bower_components/bootstrap/Gruntfile.js @@ -6,467 +6,483 @@ */ module.exports = function (grunt) { - 'use strict'; - - // Force use of Unix newlines - grunt.util.linefeed = '\n'; - - RegExp.quote = function (string) { - return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&'); - }; - - var fs = require('fs'); - var path = require('path'); - var npmShrinkwrap = require('npm-shrinkwrap'); - var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js'); - var getLessVarsData = function () { - var filePath = path.join(__dirname, 'less/variables.less'); - var fileContent = fs.readFileSync(filePath, { encoding: 'utf8' }); - var parser = new BsLessdocParser(fileContent); - return { sections: parser.parseFile() }; - }; - var generateRawFiles = require('./grunt/bs-raw-files-generator.js'); - var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js'); - var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' }); - - Object.keys(configBridge.paths).forEach(function (key) { - configBridge.paths[key].forEach(function (val, i, arr) { - arr[i] = path.join('./docs/assets', val); - }); - }); - - // Project configuration. - grunt.initConfig({ - - // Metadata. - pkg: grunt.file.readJSON('package.json'), - banner: '/*!\n' + + 'use strict'; + + // Force use of Unix newlines + grunt.util.linefeed = '\n'; + + RegExp.quote = function (string) { + return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&'); + }; + + var fs = require('fs'); + var path = require('path'); + var npmShrinkwrap = require('npm-shrinkwrap'); + var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js'); + var getLessVarsData = function () { + var filePath = path.join(__dirname, 'less/variables.less'); + var fileContent = fs.readFileSync(filePath, { encoding: 'utf8' }); + var parser = new BsLessdocParser(fileContent); + return { sections: parser.parseFile() }; + }; + var generateRawFiles = require('./grunt/bs-raw-files-generator.js'); + var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js'); + var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' }); + + Object.keys(configBridge.paths).forEach( + function (key) { + configBridge.paths[key].forEach( + function (val, i, arr) { + arr[i] = path.join('./docs/assets', val); + } + ); + } + ); + + // Project configuration. + grunt.initConfig( + { + + // Metadata. + pkg: grunt.file.readJSON('package.json'), + banner: '/*!\n' + ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' + ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + ' * Licensed under <%= pkg.license.type %> (<%= pkg.license.url %>)\n' + ' */\n', - jqueryCheck: configBridge.config.jqueryCheck.join('\n'), - jqueryVersionCheck: configBridge.config.jqueryVersionCheck.join('\n'), - - // Task configuration. - clean: { - dist: 'dist', - docs: 'docs/dist' - }, - - jshint: { - options: { - jshintrc: 'js/.jshintrc' - }, - grunt: { - options: { - jshintrc: 'grunt/.jshintrc' - }, - src: ['Gruntfile.js', 'grunt/*.js'] - }, - core: { - src: 'js/*.js' - }, - test: { - options: { - jshintrc: 'js/tests/unit/.jshintrc' - }, - src: 'js/tests/unit/*.js' - }, - assets: { - src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js'] - } - }, - - jscs: { - options: { - config: 'js/.jscsrc' - }, - grunt: { - src: '<%= jshint.grunt.src %>' - }, - core: { - src: '<%= jshint.core.src %>' - }, - test: { - src: '<%= jshint.test.src %>' - }, - assets: { - options: { - requireCamelCaseOrUpperCaseIdentifiers: null - }, - src: '<%= jshint.assets.src %>' - } - }, - - concat: { - options: { - banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>', - stripBanners: false - }, - bootstrap: { - src: [ - 'js/transition.js', - 'js/alert.js', - 'js/button.js', - 'js/carousel.js', - 'js/collapse.js', - 'js/dropdown.js', - 'js/modal.js', - 'js/tooltip.js', - 'js/popover.js', - 'js/scrollspy.js', - 'js/tab.js', - 'js/affix.js' - ], - dest: 'dist/js/<%= pkg.name %>.js' - } - }, - - uglify: { - options: { - preserveComments: 'some' - }, - core: { - src: '<%= concat.bootstrap.dest %>', - dest: 'dist/js/<%= pkg.name %>.min.js' - }, - customize: { - src: configBridge.paths.customizerJs, - dest: 'docs/assets/js/customize.min.js' - }, - docsJs: { - src: configBridge.paths.docsJs, - dest: 'docs/assets/js/docs.min.js' - } - }, - - qunit: { - options: { - inject: 'js/tests/unit/phantom.js' - }, - files: 'js/tests/index.html' - }, - - less: { - compileCore: { - options: { - strictMath: true, - sourceMap: true, - outputSourceFiles: true, - sourceMapURL: '<%= pkg.name %>.css.map', - sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map' - }, - src: 'less/bootstrap.less', - dest: 'dist/css/<%= pkg.name %>.css' - }, - compileTheme: { - options: { - strictMath: true, - sourceMap: true, - outputSourceFiles: true, - sourceMapURL: '<%= pkg.name %>-theme.css.map', - sourceMapFilename: 'dist/css/<%= pkg.name %>-theme.css.map' - }, - src: 'less/theme.less', - dest: 'dist/css/<%= pkg.name %>-theme.css' - } - }, - - autoprefixer: { - options: { - browsers: configBridge.config.autoprefixerBrowsers - }, - core: { - options: { - map: true - }, - src: 'dist/css/<%= pkg.name %>.css' - }, - theme: { - options: { - map: true - }, - src: 'dist/css/<%= pkg.name %>-theme.css' - }, - docs: { - src: 'docs/assets/css/src/docs.css' - }, - examples: { - expand: true, - cwd: 'docs/examples/', - src: ['**/*.css'], - dest: 'docs/examples/' - } - }, - - csslint: { - options: { - csslintrc: 'less/.csslintrc' - }, - dist: [ - 'dist/css/bootstrap.css', - 'dist/css/bootstrap-theme.css' - ], - examples: [ - 'docs/examples/**/*.css' - ], - docs: { - options: { - ids: false, - 'overqualified-elements': false - }, - src: 'docs/assets/css/src/docs.css' - } - }, - - cssmin: { - options: { - compatibility: 'ie8', - keepSpecialComments: '*', - noAdvanced: true - }, - minifyCore: { - src: 'dist/css/<%= pkg.name %>.css', - dest: 'dist/css/<%= pkg.name %>.min.css' - }, - minifyTheme: { - src: 'dist/css/<%= pkg.name %>-theme.css', - dest: 'dist/css/<%= pkg.name %>-theme.min.css' - }, - docs: { - src: [ - 'docs/assets/css/src/docs.css', - 'docs/assets/css/src/pygments-manni.css' - ], - dest: 'docs/assets/css/docs.min.css' - } - }, - - usebanner: { - options: { - position: 'top', - banner: '<%= banner %>' - }, - files: { - src: 'dist/css/*.css' - } - }, - - csscomb: { - options: { - config: 'less/.csscomb.json' - }, - dist: { - expand: true, - cwd: 'dist/css/', - src: ['*.css', '!*.min.css'], - dest: 'dist/css/' - }, - examples: { - expand: true, - cwd: 'docs/examples/', - src: '**/*.css', - dest: 'docs/examples/' - }, - docs: { - src: 'docs/assets/css/src/docs.css', - dest: 'docs/assets/css/src/docs.css' - } - }, - - copy: { - fonts: { - src: 'fonts/*', - dest: 'dist/' - }, - docs: { - src: 'dist/*/*', - dest: 'docs/' - } - }, - - connect: { - server: { - options: { - port: 3000, - base: '.' - } - } - }, - - jekyll: { - docs: {} - }, - - jade: { - options: { - pretty: true, - data: getLessVarsData - }, - customizerVars: { - src: 'docs/_jade/customizer-variables.jade', - dest: 'docs/_includes/customizer-variables.html' - }, - customizerNav: { - src: 'docs/_jade/customizer-nav.jade', - dest: 'docs/_includes/nav/customize.html' - } - }, - - validation: { - options: { - charset: 'utf-8', - doctype: 'HTML5', - failHard: true, - reset: true, - relaxerror: [ - 'Element img is missing required attribute src.', - 'Attribute autocomplete not allowed on element input at this point.', - 'Attribute autocomplete not allowed on element button at this point.' - ] - }, - files: { - src: '_gh_pages/**/*.html' - } - }, - - watch: { - src: { - files: '<%= jshint.core.src %>', - tasks: ['jshint:src', 'qunit', 'concat'] - }, - test: { - files: '<%= jshint.test.src %>', - tasks: ['jshint:test', 'qunit'] - }, - less: { - files: 'less/**/*.less', - tasks: 'less' - } - }, - - sed: { - versionNumber: { - pattern: (function () { - var old = grunt.option('oldver'); - return old ? RegExp.quote(old) : old; - })(), - replacement: grunt.option('newver'), - recursive: true - } - }, - - 'saucelabs-qunit': { - all: { - options: { - build: process.env.TRAVIS_JOB_ID, - concurrency: 10, - maxRetries: 3, - urls: ['http://127.0.0.1:3000/js/tests/index.html'], - browsers: grunt.file.readYAML('grunt/sauce_browsers.yml') + jqueryCheck: configBridge.config.jqueryCheck.join('\n'), + jqueryVersionCheck: configBridge.config.jqueryVersionCheck.join('\n'), + + // Task configuration. + clean: { + dist: 'dist', + docs: 'docs/dist' + }, + + jshint: { + options: { + jshintrc: 'js/.jshintrc' + }, + grunt: { + options: { + jshintrc: 'grunt/.jshintrc' + }, + src: ['Gruntfile.js', 'grunt/*.js'] + }, + core: { + src: 'js/*.js' + }, + test: { + options: { + jshintrc: 'js/tests/unit/.jshintrc' + }, + src: 'js/tests/unit/*.js' + }, + assets: { + src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js'] + } + }, + + jscs: { + options: { + config: 'js/.jscsrc' + }, + grunt: { + src: '<%= jshint.grunt.src %>' + }, + core: { + src: '<%= jshint.core.src %>' + }, + test: { + src: '<%= jshint.test.src %>' + }, + assets: { + options: { + requireCamelCaseOrUpperCaseIdentifiers: null + }, + src: '<%= jshint.assets.src %>' + } + }, + + concat: { + options: { + banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>', + stripBanners: false + }, + bootstrap: { + src: [ + 'js/transition.js', + 'js/alert.js', + 'js/button.js', + 'js/carousel.js', + 'js/collapse.js', + 'js/dropdown.js', + 'js/modal.js', + 'js/tooltip.js', + 'js/popover.js', + 'js/scrollspy.js', + 'js/tab.js', + 'js/affix.js' + ], + dest: 'dist/js/<%= pkg.name %>.js' + } + }, + + uglify: { + options: { + preserveComments: 'some' + }, + core: { + src: '<%= concat.bootstrap.dest %>', + dest: 'dist/js/<%= pkg.name %>.min.js' + }, + customize: { + src: configBridge.paths.customizerJs, + dest: 'docs/assets/js/customize.min.js' + }, + docsJs: { + src: configBridge.paths.docsJs, + dest: 'docs/assets/js/docs.min.js' + } + }, + + qunit: { + options: { + inject: 'js/tests/unit/phantom.js' + }, + files: 'js/tests/index.html' + }, + + less: { + compileCore: { + options: { + strictMath: true, + sourceMap: true, + outputSourceFiles: true, + sourceMapURL: '<%= pkg.name %>.css.map', + sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map' + }, + src: 'less/bootstrap.less', + dest: 'dist/css/<%= pkg.name %>.css' + }, + compileTheme: { + options: { + strictMath: true, + sourceMap: true, + outputSourceFiles: true, + sourceMapURL: '<%= pkg.name %>-theme.css.map', + sourceMapFilename: 'dist/css/<%= pkg.name %>-theme.css.map' + }, + src: 'less/theme.less', + dest: 'dist/css/<%= pkg.name %>-theme.css' + } + }, + + autoprefixer: { + options: { + browsers: configBridge.config.autoprefixerBrowsers + }, + core: { + options: { + map: true + }, + src: 'dist/css/<%= pkg.name %>.css' + }, + theme: { + options: { + map: true + }, + src: 'dist/css/<%= pkg.name %>-theme.css' + }, + docs: { + src: 'docs/assets/css/src/docs.css' + }, + examples: { + expand: true, + cwd: 'docs/examples/', + src: ['**/*.css'], + dest: 'docs/examples/' + } + }, + + csslint: { + options: { + csslintrc: 'less/.csslintrc' + }, + dist: [ + 'dist/css/bootstrap.css', + 'dist/css/bootstrap-theme.css' + ], + examples: [ + 'docs/examples/**/*.css' + ], + docs: { + options: { + ids: false, + 'overqualified-elements': false + }, + src: 'docs/assets/css/src/docs.css' + } + }, + + cssmin: { + options: { + compatibility: 'ie8', + keepSpecialComments: '*', + noAdvanced: true + }, + minifyCore: { + src: 'dist/css/<%= pkg.name %>.css', + dest: 'dist/css/<%= pkg.name %>.min.css' + }, + minifyTheme: { + src: 'dist/css/<%= pkg.name %>-theme.css', + dest: 'dist/css/<%= pkg.name %>-theme.min.css' + }, + docs: { + src: [ + 'docs/assets/css/src/docs.css', + 'docs/assets/css/src/pygments-manni.css' + ], + dest: 'docs/assets/css/docs.min.css' + } + }, + + usebanner: { + options: { + position: 'top', + banner: '<%= banner %>' + }, + files: { + src: 'dist/css/*.css' + } + }, + + csscomb: { + options: { + config: 'less/.csscomb.json' + }, + dist: { + expand: true, + cwd: 'dist/css/', + src: ['*.css', '!*.min.css'], + dest: 'dist/css/' + }, + examples: { + expand: true, + cwd: 'docs/examples/', + src: '**/*.css', + dest: 'docs/examples/' + }, + docs: { + src: 'docs/assets/css/src/docs.css', + dest: 'docs/assets/css/src/docs.css' + } + }, + + copy: { + fonts: { + src: 'fonts/*', + dest: 'dist/' + }, + docs: { + src: 'dist/*/*', + dest: 'docs/' + } + }, + + connect: { + server: { + options: { + port: 3000, + base: '.' + } + } + }, + + jekyll: { + docs: {} + }, + + jade: { + options: { + pretty: true, + data: getLessVarsData + }, + customizerVars: { + src: 'docs/_jade/customizer-variables.jade', + dest: 'docs/_includes/customizer-variables.html' + }, + customizerNav: { + src: 'docs/_jade/customizer-nav.jade', + dest: 'docs/_includes/nav/customize.html' + } + }, + + validation: { + options: { + charset: 'utf-8', + doctype: 'HTML5', + failHard: true, + reset: true, + relaxerror: [ + 'Element img is missing required attribute src.', + 'Attribute autocomplete not allowed on element input at this point.', + 'Attribute autocomplete not allowed on element button at this point.' + ] + }, + files: { + src: '_gh_pages/**/*.html' + } + }, + + watch: { + src: { + files: '<%= jshint.core.src %>', + tasks: ['jshint:src', 'qunit', 'concat'] + }, + test: { + files: '<%= jshint.test.src %>', + tasks: ['jshint:test', 'qunit'] + }, + less: { + files: 'less/**/*.less', + tasks: 'less' + } + }, + + sed: { + versionNumber: { + pattern: (function () { + var old = grunt.option('oldver'); + return old ? RegExp.quote(old) : old; + })(), + replacement: grunt.option('newver'), + recursive: true + } + }, + + 'saucelabs-qunit': { + all: { + options: { + build: process.env.TRAVIS_JOB_ID, + concurrency: 10, + maxRetries: 3, + urls: ['http://127.0.0.1:3000/js/tests/index.html'], + browsers: grunt.file.readYAML('grunt/sauce_browsers.yml') + } + } + }, + + exec: { + npmUpdate: { + command: 'npm update' + } + } } - } - }, + ); + + + // These plugins provide necessary tasks. + require('load-grunt-tasks')(grunt, { scope: 'devDependencies' }); + require('time-grunt')(grunt); + + // Docs HTML validation task + grunt.registerTask('validate-html', ['jekyll', 'validation']); - exec: { - npmUpdate: { - command: 'npm update' - } + var runSubset = function (subset) { + return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset; + }; + var isUndefOrNonZero = function (val) { + return val === undefined || val !== '0'; + }; + + // Test task. + var testSubtasks = []; + // Skip core tests if running a different subset of the test suite + if (runSubset('core')) { + testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'csslint:dist', 'test-js', 'docs']); + } + // Skip HTML validation if running a different subset of the test suite + if (runSubset('validate-html') + // Skip HTML5 validator on Travis when [skip validator] is in the commit message + && isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR) + ) { + testSubtasks.push('validate-html'); } - }); - - - // These plugins provide necessary tasks. - require('load-grunt-tasks')(grunt, { scope: 'devDependencies' }); - require('time-grunt')(grunt); - - // Docs HTML validation task - grunt.registerTask('validate-html', ['jekyll', 'validation']); - - var runSubset = function (subset) { - return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset; - }; - var isUndefOrNonZero = function (val) { - return val === undefined || val !== '0'; - }; - - // Test task. - var testSubtasks = []; - // Skip core tests if running a different subset of the test suite - if (runSubset('core')) { - testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'csslint:dist', 'test-js', 'docs']); - } - // Skip HTML validation if running a different subset of the test suite - if (runSubset('validate-html') && - // Skip HTML5 validator on Travis when [skip validator] is in the commit message - isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) { - testSubtasks.push('validate-html'); - } - // Only run Sauce Labs tests if there's a Sauce access key - if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' && - // Skip Sauce if running a different subset of the test suite - runSubset('sauce-js-unit') && - // Skip Sauce on Travis when [skip sauce] is in the commit message - isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) { - testSubtasks.push('connect'); - testSubtasks.push('saucelabs-qunit'); - } - grunt.registerTask('test', testSubtasks); - grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']); - - // JS distribution task. - grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs']); - - // CSS distribution task. - grunt.registerTask('less-compile', ['less:compileCore', 'less:compileTheme']); - grunt.registerTask('dist-css', ['less-compile', 'autoprefixer:core', 'autoprefixer:theme', 'usebanner', 'csscomb:dist', 'cssmin:minifyCore', 'cssmin:minifyTheme']); - - // Full distribution task. - grunt.registerTask('dist', ['clean:dist', 'dist-css', 'copy:fonts', 'dist-js']); - - // Default task. - grunt.registerTask('default', ['clean:dist', 'copy:fonts', 'test']); - - // Version numbering task. - // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z - // This can be overzealous, so its changes should always be manually reviewed! - grunt.registerTask('change-version-number', 'sed'); - - // task for building customizer - grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']); - grunt.registerTask('build-customizer-html', 'jade'); - grunt.registerTask('build-raw-files', 'Add scripts/less files to customizer.', function () { - var banner = grunt.template.process('<%= banner %>'); - generateRawFiles(grunt, banner); - }); - - grunt.registerTask('commonjs', 'Generate CommonJS entrypoint module in dist dir.', function () { - var srcFiles = grunt.config.get('concat.bootstrap.src'); - var destFilepath = 'dist/js/npm.js'; - generateCommonJSModule(grunt, srcFiles, destFilepath); - }); - - // Docs task. - grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']); - grunt.registerTask('lint-docs-css', ['csslint:docs', 'csslint:examples']); - grunt.registerTask('docs-js', ['uglify:docsJs', 'uglify:customize']); - grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']); - grunt.registerTask('docs', ['docs-css', 'lint-docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs', 'build-customizer']); - - // Task for updating the cached npm packages used by the Travis build (which are controlled by test-infra/npm-shrinkwrap.json). - // This task should be run and the updated file should be committed whenever Bootstrap's dependencies change. - grunt.registerTask('update-shrinkwrap', ['exec:npmUpdate', '_update-shrinkwrap']); - grunt.registerTask('_update-shrinkwrap', function () { - var done = this.async(); - npmShrinkwrap({ dev: true, dirname: __dirname }, function (err) { - if (err) { - grunt.fail.warn(err); - } - var dest = 'test-infra/npm-shrinkwrap.json'; - fs.renameSync('npm-shrinkwrap.json', dest); - grunt.log.writeln('File ' + dest.cyan + ' updated.'); - done(); - }); - }); + // Only run Sauce Labs tests if there's a Sauce access key + if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' + // Skip Sauce if running a different subset of the test suite + && runSubset('sauce-js-unit') + // Skip Sauce on Travis when [skip sauce] is in the commit message + && isUndefOrNonZero(process.env.TWBS_DO_SAUCE) + ) { + testSubtasks.push('connect'); + testSubtasks.push('saucelabs-qunit'); + } + grunt.registerTask('test', testSubtasks); + grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']); + + // JS distribution task. + grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs']); + + // CSS distribution task. + grunt.registerTask('less-compile', ['less:compileCore', 'less:compileTheme']); + grunt.registerTask('dist-css', ['less-compile', 'autoprefixer:core', 'autoprefixer:theme', 'usebanner', 'csscomb:dist', 'cssmin:minifyCore', 'cssmin:minifyTheme']); + + // Full distribution task. + grunt.registerTask('dist', ['clean:dist', 'dist-css', 'copy:fonts', 'dist-js']); + + // Default task. + grunt.registerTask('default', ['clean:dist', 'copy:fonts', 'test']); + + // Version numbering task. + // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z + // This can be overzealous, so its changes should always be manually reviewed! + grunt.registerTask('change-version-number', 'sed'); + + // task for building customizer + grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']); + grunt.registerTask('build-customizer-html', 'jade'); + grunt.registerTask( + 'build-raw-files', 'Add scripts/less files to customizer.', function () { + var banner = grunt.template.process('<%= banner %>'); + generateRawFiles(grunt, banner); + } + ); + + grunt.registerTask( + 'commonjs', 'Generate CommonJS entrypoint module in dist dir.', function () { + var srcFiles = grunt.config.get('concat.bootstrap.src'); + var destFilepath = 'dist/js/npm.js'; + generateCommonJSModule(grunt, srcFiles, destFilepath); + } + ); + + // Docs task. + grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']); + grunt.registerTask('lint-docs-css', ['csslint:docs', 'csslint:examples']); + grunt.registerTask('docs-js', ['uglify:docsJs', 'uglify:customize']); + grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']); + grunt.registerTask('docs', ['docs-css', 'lint-docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs', 'build-customizer']); + + // Task for updating the cached npm packages used by the Travis build (which are controlled by test-infra/npm-shrinkwrap.json). + // This task should be run and the updated file should be committed whenever Bootstrap's dependencies change. + grunt.registerTask('update-shrinkwrap', ['exec:npmUpdate', '_update-shrinkwrap']); + grunt.registerTask( + '_update-shrinkwrap', function () { + var done = this.async(); + npmShrinkwrap( + { dev: true, dirname: __dirname }, function (err) { + if (err) { + grunt.fail.warn(err); + } + var dest = 'test-infra/npm-shrinkwrap.json'; + fs.renameSync('npm-shrinkwrap.json', dest); + grunt.log.writeln('File ' + dest.cyan + ' updated.'); + done(); + } + ); + } + ); }; diff --git a/bower_components/bootstrap/dist/js/bootstrap.js b/bower_components/bootstrap/dist/js/bootstrap.js index b6ac8d99..5b023c8d 100644 --- a/bower_components/bootstrap/dist/js/bootstrap.js +++ b/bower_components/bootstrap/dist/js/bootstrap.js @@ -5,14 +5,14 @@ */ if (typeof jQuery === 'undefined') { - throw new Error('Bootstrap\'s JavaScript requires jQuery') + throw new Error('Bootstrap\'s JavaScript requires jQuery') } +function ($) { - var version = $.fn.jquery.split(' ')[0].split('.') - if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { - throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') - } + var version = $.fn.jquery.split(' ')[0].split('.') + if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { + throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') + } }(jQuery); /* ======================================================================== @@ -25,53 +25,63 @@ if (typeof jQuery === 'undefined') { +function ($) { - 'use strict'; - - // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) - // ============================================================ - - function transitionEnd() { - var el = document.createElement('bootstrap') - - var transEndEventNames = { - WebkitTransition : 'webkitTransitionEnd', - MozTransition : 'transitionend', - OTransition : 'oTransitionEnd otransitionend', - transition : 'transitionend' - } + 'use strict'; - for (var name in transEndEventNames) { - if (el.style[name] !== undefined) { - return { end: transEndEventNames[name] } - } - } + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ - return false // explicit for ie8 ( ._.) - } + function transitionEnd() + { + var el = document.createElement('bootstrap') - // http://blog.alexmaccaw.com/css-transitions - $.fn.emulateTransitionEnd = function (duration) { - var called = false - var $el = this - $(this).one('bsTransitionEnd', function () { called = true }) - var callback = function () { if (!called) $($el).trigger($.support.transition.end) } - setTimeout(callback, duration) - return this - } + var transEndEventNames = { + WebkitTransition : 'webkitTransitionEnd', + MozTransition : 'transitionend', + OTransition : 'oTransitionEnd otransitionend', + transition : 'transitionend' + } - $(function () { - $.support.transition = transitionEnd() + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } - if (!$.support.transition) return + return false // explicit for ie8 ( ._.) + } - $.event.special.bsTransitionEnd = { - bindType: $.support.transition.end, - delegateType: $.support.transition.end, - handle: function (e) { - if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) - } + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false + var $el = this + $(this).one( + 'bsTransitionEnd', function () { + called = true } + ) + var callback = function () { + if (!called) { $($el).trigger($.support.transition.end) } + } + setTimeout(callback, duration) + return this } - }) + + $( + function () { + $.support.transition = transitionEnd() + + if (!$.support.transition) { return + + $.event.special.bsTransitionEnd = { + bindType: $.support.transition.end, + delegateType: $.support.transition.end, + handle: function (e) { + if ($(e.target).is(this)) { return e.handleObj.handler.apply(this, arguments) + } + } + } + } + } + ) }(jQuery); @@ -85,88 +95,96 @@ if (typeof jQuery === 'undefined') { +function ($) { - 'use strict'; + 'use strict'; - // ALERT CLASS DEFINITION - // ====================== + // ALERT CLASS DEFINITION + // ====================== - var dismiss = '[data-dismiss="alert"]' - var Alert = function (el) { - $(el).on('click', dismiss, this.close) - } + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } - Alert.VERSION = '3.3.1' + Alert.VERSION = '3.3.1' - Alert.TRANSITION_DURATION = 150 + Alert.TRANSITION_DURATION = 150 - Alert.prototype.close = function (e) { - var $this = $(this) - var selector = $this.attr('data-target') + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } - var $parent = $(selector) + var $parent = $(selector) - if (e) e.preventDefault() + if (e) { e.preventDefault() - if (!$parent.length) { - $parent = $this.closest('.alert') - } + if (!$parent.length) { + $parent = $this.closest('.alert') + } + } - $parent.trigger(e = $.Event('close.bs.alert')) + $parent.trigger(e = $.Event('close.bs.alert')) - if (e.isDefaultPrevented()) return + if (e.isDefaultPrevented()) { return - $parent.removeClass('in') + $parent.removeClass('in') - function removeElement() { - // detach from parent, fire event then clean up data - $parent.detach().trigger('closed.bs.alert').remove() - } + function removeElement() + { + // detach from parent, fire event then clean up data + $parent.detach().trigger('closed.bs.alert').remove() + } + } - $.support.transition && $parent.hasClass('fade') ? - $parent + $.support.transition && $parent.hasClass('fade') ? + $parent .one('bsTransitionEnd', removeElement) .emulateTransitionEnd(Alert.TRANSITION_DURATION) : - removeElement() - } + removeElement() + } - // ALERT PLUGIN DEFINITION - // ======================= + // ALERT PLUGIN DEFINITION + // ======================= - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.alert') + function Plugin(option) + { + return this.each( + function () { + var $this = $(this) + var data = $this.data('bs.alert') - if (!data) $this.data('bs.alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } + if (!data) { $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') { data[option].call($this) + } + } + } + ) + } - var old = $.fn.alert + var old = $.fn.alert - $.fn.alert = Plugin - $.fn.alert.Constructor = Alert + $.fn.alert = Plugin + $.fn.alert.Constructor = Alert - // ALERT NO CONFLICT - // ================= + // ALERT NO CONFLICT + // ================= - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } - // ALERT DATA-API - // ============== + // ALERT DATA-API + // ============== - $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) }(jQuery); @@ -180,110 +198,127 @@ if (typeof jQuery === 'undefined') { +function ($) { - 'use strict'; - - // BUTTON PUBLIC CLASS DEFINITION - // ============================== - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Button.DEFAULTS, options) - this.isLoading = false - } - - Button.VERSION = '3.3.1' - - Button.DEFAULTS = { - loadingText: 'loading...' - } - - Button.prototype.setState = function (state) { - var d = 'disabled' - var $el = this.$element - var val = $el.is('input') ? 'val' : 'html' - var data = $el.data() - - state = state + 'Text' + 'use strict'; - if (data.resetText == null) $el.data('resetText', $el[val]()) + // BUTTON PUBLIC CLASS DEFINITION + // ============================== - // push to event loop to allow forms to submit - setTimeout($.proxy(function () { - $el[val](data[state] == null ? this.options[state] : data[state]) - - if (state == 'loadingText') { - this.isLoading = true - $el.addClass(d).attr(d, d) - } else if (this.isLoading) { + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) this.isLoading = false - $el.removeClass(d).removeAttr(d) - } - }, this), 0) - } + } - Button.prototype.toggle = function () { - var changed = true - var $parent = this.$element.closest('[data-toggle="buttons"]') + Button.VERSION = '3.3.1' - if ($parent.length) { - var $input = this.$element.find('input') - if ($input.prop('type') == 'radio') { - if ($input.prop('checked') && this.$element.hasClass('active')) changed = false - else $parent.find('.active').removeClass('active') - } - if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') - } else { - this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + Button.DEFAULTS = { + loadingText: 'loading...' } - if (changed) this.$element.toggleClass('active') - } + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (data.resetText == null) { $el.data('resetText', $el[val]()) + + // push to event loop to allow forms to submit + setTimeout( + $.proxy( + function () { + $el[val](data[state] == null ? this.options[state] : data[state]) + + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this + ), 0 + ) + } + } + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) { changed = false + else { $parent.find('.active').removeClass('active') + } + } + } + if (changed) { $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } } else { + this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + } + + if (changed) { this.$element.toggleClass('active') + } + } - // BUTTON PLUGIN DEFINITION - // ======================== - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.button') - var options = typeof option == 'object' && option + // BUTTON PLUGIN DEFINITION + // ======================== - if (!data) $this.data('bs.button', (data = new Button(this, options))) + function Plugin(option) + { + return this.each( + function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } + if (!data) $this.data('bs.button', (data = new Button(this, options))) - var old = $.fn.button + if (option == 'toggle') data.toggle() + else if (option) { data.setState(option) + } + } + ) + } - $.fn.button = Plugin - $.fn.button.Constructor = Button + var old = $.fn.button + $.fn.button = Plugin + $.fn.button.Constructor = Button - // BUTTON NO CONFLICT - // ================== - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } + // BUTTON NO CONFLICT + // ================== + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } - // BUTTON DATA-API - // =============== - $(document) - .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - Plugin.call($btn, 'toggle') - e.preventDefault() - }) - .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { - $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) - }) + // BUTTON DATA-API + // =============== + + $(document) + .on( + 'click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) { $btn = $btn.closest('.btn') + Plugin.call($btn, 'toggle') + e.preventDefault() + } + } + ) + .on( + 'focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { + $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) + } + ) }(jQuery); @@ -297,234 +332,262 @@ if (typeof jQuery === 'undefined') { +function ($) { - 'use strict'; - - // CAROUSEL CLASS DEFINITION - // ========================= - - var Carousel = function (element, options) { - this.$element = $(element) - this.$indicators = this.$element.find('.carousel-indicators') - this.options = options - this.paused = - this.sliding = - this.interval = - this.$active = - this.$items = null - - this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) + + this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element + .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) + .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) + } - this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element - .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) - .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) - } + Carousel.VERSION = '3.3.1' - Carousel.VERSION = '3.3.1' + Carousel.TRANSITION_DURATION = 600 - Carousel.TRANSITION_DURATION = 600 + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true, + keyboard: true + } - Carousel.DEFAULTS = { - interval: 5000, - pause: 'hover', - wrap: true, - keyboard: true - } + Carousel.prototype.keydown = function (e) { + if (/input|textarea/i.test(e.target.tagName)) { return + switch (e.which) { + case 37: this.prev(); break + case 39: this.next(); break + default: return + } + } - Carousel.prototype.keydown = function (e) { - if (/input|textarea/i.test(e.target.tagName)) return - switch (e.which) { - case 37: this.prev(); break - case 39: this.next(); break - default: return + e.preventDefault() } - e.preventDefault() - } + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) - Carousel.prototype.cycle = function (e) { - e || (this.paused = false) + this.interval && clearInterval(this.interval) - this.interval && clearInterval(this.interval) + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) - this.options.interval - && !this.paused - && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) - - return this - } - - Carousel.prototype.getItemIndex = function (item) { - this.$items = item.parent().children('.item') - return this.$items.index(item || this.$active) - } + return this + } - Carousel.prototype.getItemForDirection = function (direction, active) { - var delta = direction == 'prev' ? -1 : 1 - var activeIndex = this.getItemIndex(active) - var itemIndex = (activeIndex + delta) % this.$items.length - return this.$items.eq(itemIndex) - } + Carousel.prototype.getItemIndex = function (item) { + this.$items = item.parent().children('.item') + return this.$items.index(item || this.$active) + } - Carousel.prototype.to = function (pos) { - var that = this - var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) + Carousel.prototype.getItemForDirection = function (direction, active) { + var delta = direction == 'prev' ? -1 : 1 + var activeIndex = this.getItemIndex(active) + var itemIndex = (activeIndex + delta) % this.$items.length + return this.$items.eq(itemIndex) + } - if (pos > (this.$items.length - 1) || pos < 0) return + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) - if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" - if (activeIndex == pos) return this.pause().cycle() + if (pos > (this.$items.length - 1) || pos < 0) { return - return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) - } - - Carousel.prototype.pause = function (e) { - e || (this.paused = true) + if (this.sliding) { return this.$element.one( + 'slid.bs.carousel', function () { + that.to(pos) } + ) // yes, "slid" + if (activeIndex == pos) { return this.pause().cycle() - if (this.$element.find('.next, .prev').length && $.support.transition) { - this.$element.trigger($.support.transition.end) - this.cycle(true) + return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) + } + } + } } - this.interval = clearInterval(this.interval) + Carousel.prototype.pause = function (e) { + e || (this.paused = true) - return this - } + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } - Carousel.prototype.next = function () { - if (this.sliding) return - return this.slide('next') - } + this.interval = clearInterval(this.interval) - Carousel.prototype.prev = function () { - if (this.sliding) return - return this.slide('prev') - } + return this + } - Carousel.prototype.slide = function (type, next) { - var $active = this.$element.find('.item.active') - var $next = next || this.getItemForDirection(type, $active) - var isCycling = this.interval - var direction = type == 'next' ? 'left' : 'right' - var fallback = type == 'next' ? 'first' : 'last' - var that = this + Carousel.prototype.next = function () { + if (this.sliding) { return + return this.slide('next') + } + } - if (!$next.length) { - if (!this.options.wrap) return - $next = this.$element.find('.item')[fallback]() + Carousel.prototype.prev = function () { + if (this.sliding) { return + return this.slide('prev') + } } - if ($next.hasClass('active')) return (this.sliding = false) + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || this.getItemForDirection(type, $active) + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) { return + $next = this.$element.find('.item')[fallback]() + } + } - var relatedTarget = $next[0] - var slideEvent = $.Event('slide.bs.carousel', { - relatedTarget: relatedTarget, - direction: direction - }) - this.$element.trigger(slideEvent) - if (slideEvent.isDefaultPrevented()) return + if ($next.hasClass('active')) { return (this.sliding = false) - this.sliding = true + var relatedTarget = $next[0] + var slideEvent = $.Event( + 'slide.bs.carousel', { + relatedTarget: relatedTarget, + direction: direction + } + ) + this.$element.trigger(slideEvent) + if (slideEvent.isDefaultPrevented()) { return - isCycling && this.pause() + this.sliding = true - if (this.$indicators.length) { - this.$indicators.find('.active').removeClass('active') - var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) - $nextIndicator && $nextIndicator.addClass('active') - } + isCycling && this.pause() - var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" - if ($.support.transition && this.$element.hasClass('slide')) { - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - $active - .one('bsTransitionEnd', function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { - that.$element.trigger(slidEvent) - }, 0) - }) - .emulateTransitionEnd(Carousel.TRANSITION_DURATION) - } else { - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger(slidEvent) - } + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) + $nextIndicator && $nextIndicator.addClass('active') + } + } + } - isCycling && this.cycle() + var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one( + 'bsTransitionEnd', function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout( + function () { + that.$element.trigger(slidEvent) + }, 0 + ) + } + ) + .emulateTransitionEnd(Carousel.TRANSITION_DURATION) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger(slidEvent) + } - return this - } + isCycling && this.cycle() + return this + } - // CAROUSEL PLUGIN DEFINITION - // ========================== - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.carousel') - var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) - var action = typeof option == 'string' ? option : options.slide + // CAROUSEL PLUGIN DEFINITION + // ========================== + + function Plugin(option) + { + return this.each( + function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) { data.pause().cycle() + } + } + ) + } - if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (action) data[action]() - else if (options.interval) data.pause().cycle() - }) - } + var old = $.fn.carousel - var old = $.fn.carousel + $.fn.carousel = Plugin + $.fn.carousel.Constructor = Carousel - $.fn.carousel = Plugin - $.fn.carousel.Constructor = Carousel + // CAROUSEL NO CONFLICT + // ==================== - // CAROUSEL NO CONFLICT - // ==================== + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } - $.fn.carousel.noConflict = function () { - $.fn.carousel = old - return this - } + // CAROUSEL DATA-API + // ================= - // CAROUSEL DATA-API - // ================= + var clickHandler = function (e) { + var href + var $this = $(this) + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + if (!$target.hasClass('carousel')) { return + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) { options.interval = false - var clickHandler = function (e) { - var href - var $this = $(this) - var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 - if (!$target.hasClass('carousel')) return - var options = $.extend({}, $target.data(), $this.data()) - var slideIndex = $this.attr('data-slide-to') - if (slideIndex) options.interval = false + Plugin.call($target, options) - Plugin.call($target, options) + if (slideIndex) { + $target.data('bs.carousel').to(slideIndex) + } + } + } - if (slideIndex) { - $target.data('bs.carousel').to(slideIndex) + e.preventDefault() } - e.preventDefault() - } - - $(document) + $(document) .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) - $(window).on('load', function () { - $('[data-ride="carousel"]').each(function () { - var $carousel = $(this) - Plugin.call($carousel, $carousel.data()) - }) - }) + $(window).on( + 'load', function () { + $('[data-ride="carousel"]').each( + function () { + var $carousel = $(this) + Plugin.call($carousel, $carousel.data()) + } + ) + } + ) }(jQuery); @@ -538,205 +601,227 @@ if (typeof jQuery === 'undefined') { +function ($) { - 'use strict'; - - // COLLAPSE PUBLIC CLASS DEFINITION - // ================================ + 'use strict'; - var Collapse = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Collapse.DEFAULTS, options) - this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]') - this.transitioning = null - - if (this.options.parent) { - this.$parent = this.getParent() - } else { - this.addAriaAndCollapsedClass(this.$element, this.$trigger) - } + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ - if (this.options.toggle) this.toggle() - } + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]') + this.transitioning = null - Collapse.VERSION = '3.3.1' - - Collapse.TRANSITION_DURATION = 350 + if (this.options.parent) { + this.$parent = this.getParent() + } else { + this.addAriaAndCollapsedClass(this.$element, this.$trigger) + } - Collapse.DEFAULTS = { - toggle: true, - trigger: '[data-toggle="collapse"]' - } + if (this.options.toggle) { this.toggle() + } + } - Collapse.prototype.dimension = function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } + Collapse.VERSION = '3.3.1' - Collapse.prototype.show = function () { - if (this.transitioning || this.$element.hasClass('in')) return + Collapse.TRANSITION_DURATION = 350 - var activesData - var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing') + Collapse.DEFAULTS = { + toggle: true, + trigger: '[data-toggle="collapse"]' + } - if (actives && actives.length) { - activesData = actives.data('bs.collapse') - if (activesData && activesData.transitioning) return + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' } - var startEvent = $.Event('show.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) { return - if (actives && actives.length) { - Plugin.call(actives, 'hide') - activesData || actives.data('bs.collapse', null) - } + var activesData + var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing') - var dimension = this.dimension() + if (actives && actives.length) { + activesData = actives.data('bs.collapse') + if (activesData && activesData.transitioning) { return + } + } + } - this.$element - .removeClass('collapse') - .addClass('collapsing')[dimension](0) - .attr('aria-expanded', true) + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) { return - this.$trigger - .removeClass('collapsed') - .attr('aria-expanded', true) + if (actives && actives.length) { + Plugin.call(actives, 'hide') + activesData || actives.data('bs.collapse', null) + } + } - this.transitioning = 1 + var dimension = this.dimension() - var complete = function () { - this.$element - .removeClass('collapsing') - .addClass('collapse in')[dimension]('') - this.transitioning = 0 - this.$element - .trigger('shown.bs.collapse') - } + this.$element + .removeClass('collapse') + .addClass('collapsing')[dimension](0) + .attr('aria-expanded', true) - if (!$.support.transition) return complete.call(this) + this.$trigger + .removeClass('collapsed') + .attr('aria-expanded', true) - var scrollSize = $.camelCase(['scroll', dimension].join('-')) + this.transitioning = 1 - this.$element - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) - } + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in')[dimension]('') + this.transitioning = 0 + this.$element + .trigger('shown.bs.collapse') + } - Collapse.prototype.hide = function () { - if (this.transitioning || !this.$element.hasClass('in')) return + if (!$.support.transition) { return complete.call(this) - var startEvent = $.Event('hide.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return + var scrollSize = $.camelCase(['scroll', dimension].join('-')) - var dimension = this.dimension() + this.$element + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) + } + } - this.$element[dimension](this.$element[dimension]())[0].offsetHeight + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) { return - this.$element - .addClass('collapsing') - .removeClass('collapse in') - .attr('aria-expanded', false) + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) { return - this.$trigger - .addClass('collapsed') - .attr('aria-expanded', false) + var dimension = this.dimension() - this.transitioning = 1 + this.$element[dimension](this.$element[dimension]())[0].offsetHeight - var complete = function () { - this.transitioning = 0 - this.$element - .removeClass('collapsing') - .addClass('collapse') - .trigger('hidden.bs.collapse') - } + this.$element + .addClass('collapsing') + .removeClass('collapse in') + .attr('aria-expanded', false) - if (!$.support.transition) return complete.call(this) + this.$trigger + .addClass('collapsed') + .attr('aria-expanded', false) - this.$element - [dimension](0) - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION) - } + this.transitioning = 1 - Collapse.prototype.toggle = function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } + var complete = function () { + this.transitioning = 0 + this.$element + .removeClass('collapsing') + .addClass('collapse') + .trigger('hidden.bs.collapse') + } + } + } - Collapse.prototype.getParent = function () { - return $(this.options.parent) - .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') - .each($.proxy(function (i, element) { - var $element = $(element) - this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) - }, this)) - .end() - } + if (!$.support.transition) { return complete.call(this) - Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { - var isOpen = $element.hasClass('in') + this.$element + [dimension](0) + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION) + } + } - $element.attr('aria-expanded', isOpen) - $trigger - .toggleClass('collapsed', !isOpen) - .attr('aria-expanded', isOpen) - } + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } - function getTargetFromTrigger($trigger) { - var href - var target = $trigger.attr('data-target') - || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + Collapse.prototype.getParent = function () { + return $(this.options.parent) + .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') + .each( + $.proxy( + function (i, element) { + var $element = $(element) + this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) + }, this + ) + ) + .end() + } - return $(target) - } + Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { + var isOpen = $element.hasClass('in') + $element.attr('aria-expanded', isOpen) + $trigger + .toggleClass('collapsed', !isOpen) + .attr('aria-expanded', isOpen) + } - // COLLAPSE PLUGIN DEFINITION - // ========================== + function getTargetFromTrigger($trigger) + { + var href + var target = $trigger.attr('data-target') + || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.collapse') - var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + return $(target) + } - if (!data && options.toggle && option == 'show') options.toggle = false - if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } - var old = $.fn.collapse + // COLLAPSE PLUGIN DEFINITION + // ========================== + + function Plugin(option) + { + return this.each( + function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && option == 'show') { options.toggle = false + if (!data) { $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') { data[option]() + } + } + } + } + ) + } - $.fn.collapse = Plugin - $.fn.collapse.Constructor = Collapse + var old = $.fn.collapse + $.fn.collapse = Plugin + $.fn.collapse.Constructor = Collapse - // COLLAPSE NO CONFLICT - // ==================== - $.fn.collapse.noConflict = function () { - $.fn.collapse = old - return this - } + // COLLAPSE NO CONFLICT + // ==================== + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } - // COLLAPSE DATA-API - // ================= - $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { - var $this = $(this) + // COLLAPSE DATA-API + // ================= - if (!$this.attr('data-target')) e.preventDefault() + $(document).on( + 'click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { + var $this = $(this) - var $target = getTargetFromTrigger($this) - var data = $target.data('bs.collapse') - var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this }) + if (!$this.attr('data-target')) { e.preventDefault() - Plugin.call($target, option) - }) + var $target = getTargetFromTrigger($this) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this }) + + Plugin.call($target, option) + } + } + ) }(jQuery); @@ -750,151 +835,175 @@ if (typeof jQuery === 'undefined') { +function ($) { - 'use strict'; + 'use strict'; - // DROPDOWN CLASS DEFINITION - // ========================= + // DROPDOWN CLASS DEFINITION + // ========================= - var backdrop = '.dropdown-backdrop' - var toggle = '[data-toggle="dropdown"]' - var Dropdown = function (element) { - $(element).on('click.bs.dropdown', this.toggle) - } + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle="dropdown"]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } - Dropdown.VERSION = '3.3.1' + Dropdown.VERSION = '3.3.1' - Dropdown.prototype.toggle = function (e) { - var $this = $(this) + Dropdown.prototype.toggle = function (e) { + var $this = $(this) - if ($this.is('.disabled, :disabled')) return + if ($this.is('.disabled, :disabled')) { return - var $parent = getParent($this) - var isActive = $parent.hasClass('open') + var $parent = getParent($this) + var isActive = $parent.hasClass('open') - clearMenus() + clearMenus() - if (!isActive) { - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { - // if mobile we use a backdrop because click events don't delegate - $('