├── src ├── assets │ └── css │ │ ├── app.css │ │ └── nprogress.css ├── components │ ├── avator │ │ ├── assets │ │ │ └── avator.png │ │ └── Avator.vue │ ├── header │ │ ├── Header.vue │ │ └── TopHeader.vue │ └── menu │ │ └── Menu.vue ├── api │ ├── index.js │ ├── create-api-client.js │ └── create-api-server.js ├── store │ ├── index.js │ ├── loader.js │ └── modules │ │ ├── Counter.js │ │ ├── Theme.js │ │ └── Themes.js ├── App.vue ├── util │ ├── util.js │ └── title.js ├── app.js ├── views │ ├── Counter.vue │ ├── Theme.vue │ ├── Themes.vue │ ├── About.vue │ ├── Widget.vue │ └── Home.vue ├── router │ └── index.js ├── index.template.html ├── client-entry.js └── server-entry.js ├── .eslintignore ├── .travis.yml ├── .gitignore ├── public ├── images │ └── favicon.ico ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── 404.html ├── css │ ├── bootstrap-theme.min.css │ └── bootstrap-theme.css └── js │ ├── bootstrap.min.js │ └── bootstrap.js ├── .babelrc ├── test └── unit │ ├── index.js │ ├── .eslintrc │ ├── specs │ └── Home.spec.js │ └── karma.conf.js ├── .editorconfig ├── config └── index.js ├── processes.json ├── .eslintrc.js ├── README.md ├── package.json └── server.js /src/assets/css/app.css: -------------------------------------------------------------------------------- 1 | 2 | .view { 3 | padding: 20px 4 | } 5 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "7" 5 | script: npm run unit --single-run -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | output/ 5 | npm-debug.log 6 | .vscode/ 7 | yarn.lock -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneCN/vue-ssr-template/HEAD/public/images/favicon.ico -------------------------------------------------------------------------------- /src/components/avator/assets/avator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneCN/vue-ssr-template/HEAD/src/components/avator/assets/avator.png -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneCN/vue-ssr-template/HEAD/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneCN/vue-ssr-template/HEAD/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneCN/vue-ssr-template/HEAD/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneCN/vue-ssr-template/HEAD/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import config from 'config' 2 | import { createAPI } from 'create-api' 3 | 4 | const api = createAPI(config) 5 | 6 | export default api 7 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["es2015", { "modules": false }], "stage-2"], 3 | "ignore": ["node_modules/*"] 4 | } -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | // require all test files (files that ends with .spec.js) 2 | var testsContext = require.context('./specs', true, /\.spec$/) 3 | testsContext.keys().forEach(testsContext) 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 404 - 没有找到 7 | 8 | 9 | 10 |

404 - Not Found

11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/avator/Avator.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import modules from './loader' 4 | 5 | Vue.use(Vuex) 6 | 7 | const debug = process.env.NODE_ENV !== 'production' 8 | 9 | export default new Vuex.Store({ 10 | modules, 11 | strict: debug 12 | }) 13 | -------------------------------------------------------------------------------- /test/unit/specs/Home.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Home from 'views/Home' 3 | 4 | describe('Home.vue', () => { 5 | it('正常渲染 - Home.vue', () => { 6 | const vm = new Vue(Home).$mount() 7 | expect(vm.$el.textContent).to.contain('Home') 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /src/store/loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The file enables `@/store/index.js` to import all vuex modules 3 | * in a one-shot manner. There should not be any reason to edit this file. 4 | */ 5 | 6 | const files = require.context('./modules', false, /\.js$/) 7 | const modules = {} 8 | 9 | files.keys().forEach(key => { 10 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default 11 | }) 12 | 13 | export default modules 14 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | 18 | 22 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | const isProd = process.env.NODE_ENV === 'production' 2 | 3 | const proUrl = 'https://news-at.zhihu.com' // 生产环境api地址 4 | const devUrl = 'https://news-at.zhihu.com' // 开发api地址 5 | 6 | const FaceUrl = isProd ? proUrl : devUrl 7 | 8 | module.exports = { 9 | baseUrl: FaceUrl, 10 | client: { 11 | baseurl: '/api/4', 12 | timeout: 10000 13 | }, 14 | server: { 15 | baseurl: FaceUrl + '/api/4', 16 | timeout: 10000 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/header/Header.vue: -------------------------------------------------------------------------------- 1 | 7 | 18 | 23 | -------------------------------------------------------------------------------- /src/util/util.js: -------------------------------------------------------------------------------- 1 | export function toUpperCase(str) { 2 | return str.replace(/\b[a-z]/g, char => char.toUpperCase()) 3 | } 4 | 5 | export function uuid() { 6 | return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function(c) { 7 | return (c ^ window.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) 8 | }) 9 | } 10 | 11 | export function parseCookie(cookies) { 12 | var cookie = '' 13 | Object.keys(cookies).forEach(item => { 14 | cookie += `${item}=${cookies[item]};` 15 | }) 16 | return cookie 17 | } 18 | -------------------------------------------------------------------------------- /src/store/modules/Counter.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | count: 0 3 | } 4 | 5 | const getters = { 6 | getCount: state => state.count 7 | } 8 | 9 | const mutations = { 10 | INCREMENT: (state) => { 11 | state.count++ 12 | }, 13 | DECREMENT: (state) => { 14 | state.count-- 15 | } 16 | } 17 | 18 | const actions = { 19 | increment ({ state, commit }) { 20 | commit('INCREMENT') 21 | }, 22 | decrement ({ state, commit }) { 23 | commit('DECREMENT') 24 | } 25 | } 26 | 27 | export default { 28 | state, 29 | getters, 30 | mutations, 31 | actions 32 | } 33 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import store from './store' 4 | import router from './router' 5 | import { sync } from 'vuex-router-sync' 6 | import * as uiv from 'uiv' 7 | import titleMixin from './util/title' 8 | 9 | Vue.mixin(titleMixin) 10 | 11 | Vue.use(uiv) 12 | 13 | export function createApp () { 14 | // 同步路由状态(route state)到 store 15 | sync(store, router) 16 | // 创建应用程序实例,将 router 和 store 注入 17 | const app = new Vue({ 18 | router, 19 | store, 20 | render: h => h(App) 21 | }) 22 | // 暴露 app, router 和 store。 23 | return {app, router, store} 24 | } 25 | -------------------------------------------------------------------------------- /processes.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [{ 3 | "name": "vue-ssr-template", 4 | "script": "server.js", 5 | "log_date_format": "YYYY-MM-DD HH:mm Z", 6 | "error_file": "log/node-app/node-app.stderr.log", 7 | "out_file": "log/node-app.stdout.log", 8 | "pid_file": "pids/node-geo-api.pid", 9 | "min_uptime": "200s", 10 | "max_restarts": 10, 11 | "max_memory_restart": "1M", 12 | "cron_restart": "1 0 * * *", 13 | "watch": false, 14 | "merge_logs": true, 15 | "exec_interpreter": "node", 16 | "exec_mode": "cluster", 17 | "autorestart": false, 18 | "vizion": false 19 | }] 20 | } 21 | -------------------------------------------------------------------------------- /src/store/modules/Theme.js: -------------------------------------------------------------------------------- 1 | import api from 'src/api' 2 | 3 | const state = { 4 | theme: {} 5 | } 6 | 7 | const getters = { 8 | getTheme: state => state.theme 9 | } 10 | 11 | const mutations = { 12 | THEME_DTAILE: (state, theme) => { 13 | state.theme = theme 14 | } 15 | } 16 | 17 | const actions = { 18 | getTheme({ state, commit }, id) { 19 | return api.get(`/theme/${id}`).then((response) => { 20 | commit('THEME_DTAILE', response) 21 | }).catch((error) => { 22 | console.log(error) 23 | }) 24 | } 25 | } 26 | 27 | export default { 28 | state, 29 | getters, 30 | mutations, 31 | actions 32 | } 33 | -------------------------------------------------------------------------------- /src/store/modules/Themes.js: -------------------------------------------------------------------------------- 1 | import api from 'src/api' 2 | 3 | const state = { 4 | themes: [] 5 | } 6 | 7 | const getters = { 8 | getThemes: state => state.themes 9 | } 10 | 11 | const mutations = { 12 | THEMES_LIST: (state, themes) => { 13 | state.themes = themes 14 | } 15 | } 16 | 17 | const actions = { 18 | getThemes ({ state, commit }) { 19 | return api.get('/themes').then((response) => { 20 | commit('THEMES_LIST', response.others) 21 | }).catch((error) => { 22 | console.log(error) 23 | }) 24 | } 25 | } 26 | 27 | export default { 28 | state, 29 | getters, 30 | mutations, 31 | actions 32 | } 33 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | // allow paren-less arrow functions 16 | 'arrow-parens': 0, 17 | // allow async-await 18 | 'generator-star-spacing': 0, 19 | // allow debugger during development 20 | 'space-before-function-paren': 0, 21 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 22 | } 23 | } -------------------------------------------------------------------------------- /src/components/header/TopHeader.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 30 | 31 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../build/webpack.base.config') 2 | const webpack = require('webpack') 3 | const webpackConfig = Object.assign({}, baseConfig, { 4 | devtool: '#inline-source-map', 5 | plugins: [ 6 | new webpack.DefinePlugin({ 7 | 'process.env.NODE_ENV': '"test"' 8 | }) 9 | ] 10 | }) 11 | 12 | // no need for app entry during tests 13 | delete webpackConfig.entry 14 | 15 | module.exports = function (config) { 16 | config.set({ 17 | browsers: ['PhantomJS'], 18 | frameworks: ['mocha', 'sinon-chai'], 19 | reporters: ['spec'], 20 | files: ['./index.js'], 21 | preprocessors: { 22 | './index.js': ['webpack', 'sourcemap'] 23 | }, 24 | webpack: webpackConfig, 25 | webpackMiddleware: { 26 | noInfo: true 27 | } 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /src/views/Counter.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 36 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | import Home from 'views/Home.vue' 5 | import About from 'views/About.vue' 6 | import Themes from 'views/Themes.vue' 7 | import Widget from 'views/Widget.vue' 8 | import Counter from 'views/Counter.vue' 9 | import Theme from 'views/Theme.vue' 10 | 11 | Vue.use(VueRouter) 12 | 13 | const router = new VueRouter({ 14 | mode: 'history', 15 | linkActiveClass: 'active', 16 | base: __dirname, 17 | routes: [{ 18 | path: '/', 19 | component: Home 20 | }, { 21 | path: '/About', 22 | component: About 23 | }, { 24 | path: '/Themes', 25 | component: Themes 26 | }, { 27 | path: '/Widget', 28 | component: Widget 29 | }, { 30 | path: '/Counter', 31 | component: Counter 32 | }, { 33 | path: '/Theme/:id', 34 | component: Theme 35 | }] 36 | }) 37 | 38 | export default router 39 | -------------------------------------------------------------------------------- /src/components/menu/Menu.vue: -------------------------------------------------------------------------------- 1 | 8 | 41 | -------------------------------------------------------------------------------- /src/views/Theme.vue: -------------------------------------------------------------------------------- 1 | 10 | 42 | -------------------------------------------------------------------------------- /src/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{title}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | <% for (var chunk of webpack.chunks) { 14 | for (var file of chunk.files) { 15 | if (file.match(/\.(js|css)$/)) { %> 16 | 17 | <% } 18 | } 19 | } %> 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/util/title.js: -------------------------------------------------------------------------------- 1 | function getTitle (vm) { 2 | const { title } = vm.$options 3 | if (title) { 4 | return typeof title === 'function' 5 | ? title.call(vm) 6 | : title 7 | } 8 | } 9 | 10 | const serverTitleMixin = { 11 | created () { 12 | const title = getTitle(this) 13 | if (title) { 14 | this.$ssrContext.title = `${title.title} | vue-ssr-template` 15 | this.$ssrContext.keywords = title.keywords 16 | this.$ssrContext.description = title.description 17 | } 18 | } 19 | } 20 | 21 | const clientTitleMixin = { 22 | mounted () { 23 | const title = getTitle(this) 24 | if (title) { 25 | document.title = `${title.title} | vue-ssr-template` 26 | document.querySelector('meta[name="keywords"]').setAttribute('content', title.keywords) 27 | document.querySelector('meta[name="description"]').setAttribute('content', title.description) 28 | } 29 | } 30 | } 31 | 32 | export default process.env.VUE_ENV === 'server' 33 | ? serverTitleMixin 34 | : clientTitleMixin 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-ssr-template 2 | 3 | > Vue.js2.x 服务端渲染脚手架,拿来即用。 4 | 5 | ### 核心模块 6 | - [express](https://github.com/expressjs/express) 7 | - [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) 8 | - [vue](https://github.com/vuejs/vue) 9 | - [vue-router](https://github.com/vuejs/vue-router) 10 | - [vuex](https://github.com/vuejs/vuex) 11 | - [vuex-router-sync](https://github.com/vuejs/vuex-router-sync) 12 | - [vue-server-renderer](https://github.com/vuejs/vue-ssr-docs/) 13 | 14 | ## Node 版本 15 | 16 | ```bash 17 | node 6.x 18 | node 7.x 19 | ``` 20 | 21 | ## 本地运行 22 | 23 | ```bash 24 | npm install or yarn install 25 | npm run dev 26 | ``` 27 | 28 | ## 打包项目 29 | 30 | ``` bash 31 | npm install or yarn install 32 | npm run build 33 | npm start 34 | ``` 35 | 36 | ## 删除已打包项目 37 | 38 | ``` bash 39 | npm run del 40 | ``` 41 | 42 | ## 项目部署 43 | > 个人建议生产环境不放源代码,so .. 做了一些打包脚本 npm run build 后生成dist文件夹,将dist文件夹放在我们的生产服务器,安装依赖后通过npm run pm2 来启动项目(确保你已经安装了pm2),了解[pm2](https://github.com/Unitech/pm2)。 44 | 45 | ``` bash 46 | npm install or yarn install 47 | npm run pm2 48 | ``` 49 | 50 | ## 参考资源 51 | 52 | [vue-hackernews-2.0](https://github.com/vuejs/vue-hackernews-2.0) 53 | -------------------------------------------------------------------------------- /src/views/Themes.vue: -------------------------------------------------------------------------------- 1 | 19 | 46 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 21 | 52 | -------------------------------------------------------------------------------- /src/client-entry.js: -------------------------------------------------------------------------------- 1 | import { createApp } from './app' 2 | import NProgress from 'nprogress' 3 | const { app, router, store } = createApp() 4 | 5 | if (window.__INITIAL_STATE__) { 6 | store.replaceState(window.__INITIAL_STATE__) 7 | } 8 | 9 | NProgress.configure({ easing: 'ease', speed: 500, showSpinner: false }) 10 | 11 | router.onReady(() => { 12 | // Add router hook for handling asyncData. 13 | // Doing it after initial route is resolved so that we don't double-fetch 14 | // the data that we already have. Using router.beforeResolve() so that all 15 | // async components are resolved. 16 | router.beforeResolve((to, from, next) => { 17 | const matched = router.getMatchedComponents(to) 18 | const prevMatched = router.getMatchedComponents(from) 19 | 20 | let diffed = false 21 | const activated = matched.filter((c, i) => { 22 | return diffed || (diffed = (prevMatched[i] !== c)) 23 | }) 24 | if (!activated.length) { 25 | return next() 26 | } 27 | // start loading indicator 28 | Promise.all(activated.map(c => { 29 | NProgress.start() 30 | if (c.asyncData) { 31 | return c.asyncData({ store, route: to }) 32 | } 33 | })).then(() => { 34 | // stop loading indicator 35 | NProgress.done() 36 | next() 37 | }).catch(next) 38 | }) 39 | app.$mount('#app') 40 | }) 41 | 42 | // service worker 43 | if (window.location.protocol === 'https:' && navigator.serviceWorker) { 44 | navigator.serviceWorker.register('/service-worker.js') 45 | } 46 | -------------------------------------------------------------------------------- /src/server-entry.js: -------------------------------------------------------------------------------- 1 | import { createApp } from './app' 2 | 3 | export default context => { 4 | return new Promise((resolve, reject) => { 5 | const { app, router, store } = createApp() 6 | router.push(context.url) 7 | router.onReady(() => { 8 | const matchedComponents = router.getMatchedComponents() 9 | if (!matchedComponents.length) { 10 | return reject({ code: 404 }) 11 | } 12 | // Call fetchData hooks on components matched by the route. 13 | // A preFetch hook dispatches a store action and returns a Promise, 14 | // which is resolved when the action is complete and store state has been 15 | // updated. 16 | process.Cookies = context.cookies 17 | Promise.all(matchedComponents.map(Component => { 18 | if (Component.asyncData) { 19 | return Component.asyncData({ 20 | store, 21 | route: router.currentRoute, 22 | cookies: context.cookies 23 | }) 24 | } 25 | })).then(() => { 26 | // After all preFetch hooks are resolved, our store is now 27 | // filled with the state needed to render the app. 28 | // Expose the state on the render context, and let the request handler 29 | // inline the state in the HTML response. This allows the client-side 30 | // store to pick-up the server-side state without having to duplicate 31 | // the initial data fetching on the client. 32 | context.state = store.state 33 | resolve(app) 34 | }).catch(reject) 35 | }, reject) 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /src/api/create-api-client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc 创建客户端axios请求 3 | * @file create-api-client.js 4 | * @author zhangWuQiang 5 | */ 6 | import qs from 'qs' 7 | import axios from 'axios' 8 | 9 | axios.interceptors.response.use((res) => { 10 | if (res.status >= 200 && res.status < 300) { 11 | return res 12 | } 13 | return Promise.reject(res) 14 | }, (error) => { 15 | // 网络异常 16 | return Promise.reject(error) 17 | }) 18 | 19 | axios.interceptors.request.use(config => { 20 | return config 21 | }) 22 | 23 | export function createAPI({ client }) { 24 | axios.defaults.timeout = client.timeout 25 | axios.defaults.baseURL = client.baseurl 26 | axios.defaults.withCredentials = true 27 | return { 28 | get(url, params = {}) { 29 | return new Promise((resolve, reject) => { 30 | axios({ 31 | url, 32 | params, 33 | headers: { 34 | 'X-Requested-With': 'XMLHttpRequest' 35 | }, 36 | method: 'get' 37 | }).then(res => { 38 | resolve(res.data) 39 | }).catch(error => { 40 | reject(error) 41 | }) 42 | }) 43 | }, 44 | post(url, params = {}) { 45 | return new Promise((resolve, reject) => { 46 | axios({ 47 | url, 48 | data: qs.stringify(params), 49 | method: 'post', 50 | headers: { 51 | 'X-Requested-With': 'XMLHttpRequest', 52 | 'Content-Type': 'application/x-www-form-urlencoded' 53 | } 54 | }).then(res => { 55 | resolve(res.data) 56 | }).catch(error => { 57 | reject(error) 58 | }) 59 | }) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/assets/css/nprogress.css: -------------------------------------------------------------------------------- 1 | #nprogress { 2 | pointer-events: none; 3 | } 4 | 5 | #nprogress .bar { 6 | background: #29d; 7 | 8 | position: fixed; 9 | z-index: 1031; 10 | top: 0; 11 | left: 0; 12 | 13 | width: 100%; 14 | height: 2px; 15 | } 16 | 17 | 18 | /* Fancy blur effect */ 19 | 20 | #nprogress .peg { 21 | display: block; 22 | position: absolute; 23 | right: 0px; 24 | width: 100px; 25 | height: 100%; 26 | box-shadow: 0 0 10px #29d, 0 0 5px #29d; 27 | opacity: 1.0; 28 | 29 | -webkit-transform: rotate(3deg) translate(0px, -4px); 30 | -ms-transform: rotate(3deg) translate(0px, -4px); 31 | transform: rotate(3deg) translate(0px, -4px); 32 | } 33 | 34 | 35 | /* Remove these to get rid of the spinner */ 36 | 37 | #nprogress .spinner { 38 | display: block; 39 | position: fixed; 40 | z-index: 1031; 41 | top: 15px; 42 | right: 15px; 43 | } 44 | 45 | #nprogress .spinner-icon { 46 | width: 18px; 47 | height: 18px; 48 | box-sizing: border-box; 49 | 50 | border: solid 2px transparent; 51 | border-top-color: #29d; 52 | border-left-color: #29d; 53 | border-radius: 50%; 54 | 55 | -webkit-animation: nprogress-spinner 400ms linear infinite; 56 | animation: nprogress-spinner 400ms linear infinite; 57 | } 58 | 59 | .nprogress-custom-parent { 60 | overflow: hidden; 61 | position: relative; 62 | } 63 | 64 | .nprogress-custom-parent #nprogress .spinner, 65 | .nprogress-custom-parent #nprogress .bar { 66 | position: absolute; 67 | } 68 | 69 | @-webkit-keyframes nprogress-spinner { 70 | 0% { 71 | -webkit-transform: rotate(0deg); 72 | } 73 | 100% { 74 | -webkit-transform: rotate(360deg); 75 | } 76 | } 77 | 78 | @keyframes nprogress-spinner { 79 | 0% { 80 | transform: rotate(0deg); 81 | } 82 | 100% { 83 | transform: rotate(360deg); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/api/create-api-server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc 创建服务端axios请求 3 | * @file create-api-server.js 4 | * @author zhangWuQiang 5 | */ 6 | import qs from 'qs' 7 | import axios from 'axios' 8 | import { parseCookie } from 'util/util' 9 | 10 | const SSR = global.__VUE_SSR_CONTEXT__ 11 | 12 | export function createAPI({ server }) { 13 | console.log('-----------------------------') 14 | console.log('global ', SSR.cookies) 15 | console.log('-----------------------------') 16 | let api 17 | axios.defaults.timeout = server.timeout 18 | axios.defaults.baseURL = server.baseurl 19 | axios.defaults.withCredentials = true 20 | 21 | if (process.__API__) { 22 | api = process.__API__ 23 | } else { 24 | api = { 25 | get(url, params = {}) { 26 | return new Promise((resolve, reject) => { 27 | axios({ 28 | url, 29 | params, 30 | headers: { 31 | 'X-Requested-With': 'XMLHttpRequest', 32 | 'Cookie': parseCookie(SSR.cookies) 33 | }, 34 | method: 'get' 35 | }).then(res => { 36 | resolve(res.data) 37 | }).catch(error => { 38 | reject(error) 39 | }) 40 | }) 41 | }, 42 | post(url, params = {}) { 43 | return new Promise((resolve, reject) => { 44 | axios({ 45 | url, 46 | data: qs.stringify(params), 47 | method: 'post', 48 | headers: { 49 | 'X-Requested-With': 'XMLHttpRequest', 50 | 'Content-Type': 'application/x-www-form-urlencoded', 51 | 'Cookie': parseCookie(SSR.cookies) 52 | } 53 | }).then(res => { 54 | resolve(res.data) 55 | }).catch(error => { 56 | reject(error) 57 | }) 58 | }) 59 | } 60 | } 61 | } 62 | return api 63 | } 64 | -------------------------------------------------------------------------------- /src/views/Widget.vue: -------------------------------------------------------------------------------- 1 | 32 | 62 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 75 | 76 | 92 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-ssr-template", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project 2.0 for server side rendering.", 5 | "author": "zwq ", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "node server", 9 | "start": "cross-env NODE_ENV=production node server", 10 | "del": "rimraf output && rimraf dist", 11 | "cp": "node ./build/cp.js", 12 | "build:client": "cross-env NODE_ENV=production webpack --config ./build/webpack.client.config.js --progress --hide-modules", 13 | "build:server": "cross-env NODE_ENV=production webpack --config ./build/webpack.server.config.js --progress --hide-modules", 14 | "build": "npm run del && npm run build:client && npm run build:server && npm run cp", 15 | "unit": "karma start ./test/unit/karma.conf.js --single-run", 16 | "pm2": "cross-env NODE_ENV=production pm2 start processes.json" 17 | }, 18 | "dependencies": { 19 | "autoprefixer": "^7.2.4", 20 | "axios": "^0.13.1", 21 | "cookie-parser": "^1.4.3", 22 | "cross-env": "^3.1.4", 23 | "express": "^4.14.0", 24 | "extract-text-webpack-plugin": "^2.1.2", 25 | "lru-cache": "^4.0.1", 26 | "nprogress": "^0.2.0", 27 | "postcss-loader": "^2.0.10", 28 | "serialize-javascript": "^1.3.0", 29 | "serve-favicon": "^2.3.0", 30 | "uiv": "^0.14.3", 31 | "vue": "^2.3.4", 32 | "vue-router": "^2.7.0", 33 | "vue-server-renderer": "^2.3.4", 34 | "vuex": "^2.3.0", 35 | "vuex-router-sync": "^4.1.2" 36 | }, 37 | "devDependencies": { 38 | "babel-core": "^6.13.2", 39 | "babel-eslint": "^7.1.0", 40 | "babel-loader": "^6.0.0", 41 | "babel-preset-es2015": "^6.13.2", 42 | "babel-preset-stage-2": "^6.13.0", 43 | "babel-preset-stage-0": "^6.0.15", 44 | "chai": "^3.5.0", 45 | "css-loader": "^0.23.1", 46 | "eslint": "^3.2.2", 47 | "eslint-config-standard": "^6.0.0-beta.2", 48 | "eslint-friendly-formatter": "^2.0.6", 49 | "eslint-loader": "^1.5.0", 50 | "eslint-plugin-html": "^1.5.2", 51 | "eslint-plugin-promise": "^3.3.0", 52 | "eslint-plugin-standard": "^2.0.0", 53 | "extract-text-webpack-plugin": "^3.0.1", 54 | "file-loader": "^0.8.4", 55 | "html-webpack-plugin": "^2.28.0", 56 | "http-proxy-middleware": "^0.17.3", 57 | "karma": "^1.1.2", 58 | "karma-mocha": "^1.1.1", 59 | "karma-phantomjs-launcher": "^1.0.1", 60 | "karma-sinon-chai": "^1.2.3", 61 | "karma-sourcemap-loader": "^0.3.7", 62 | "karma-spec-reporter": "0.0.26", 63 | "karma-webpack": "^2.0.2", 64 | "less": "^2.7.3", 65 | "less-loader": "^4.0.5", 66 | "mocha": "^3.0.2", 67 | "phantomjs-prebuilt": "^2.1.10", 68 | "rimraf": "^2.6.0", 69 | "sinon": "^1.17.5", 70 | "sinon-chai": "^2.8.0", 71 | "style-loader": "^0.19.0", 72 | "stylus": "^0.54.5", 73 | "stylus-loader": "^2.4.0", 74 | "sw-precache-webpack-plugin": "^0.9.1", 75 | "url-loader": "^0.6.2", 76 | "vue-loader": "^10.0.0", 77 | "vue-ssr-webpack-plugin": "^1.0.2", 78 | "vue-template-compiler": "^2.0.0", 79 | "webpack": "^3.8.1", 80 | "webpack-dev-middleware": "^1.6.1", 81 | "webpack-hot-middleware": "^2.12.2", 82 | "webpack-merge": "^4.1.0" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const express = require('express') 4 | const favicon = require('serve-favicon') 5 | const resolve = file => path.resolve(__dirname, file) 6 | const proxyMiddleware = require('http-proxy-middleware') 7 | 8 | const config = require('./config') 9 | const isProd = process.env.NODE_ENV === 'production' 10 | 11 | const app = express() 12 | 13 | let renderer 14 | if (isProd) { 15 | // 生产环境使用本地打包文件来渲染 16 | const bundle = require('./output/vue-ssr-bundle.json') 17 | const template = fs.readFileSync(resolve('./output/index.html'), 'utf-8') 18 | renderer = createRenderer(bundle, template) 19 | } else { 20 | // 开发环境使用webpack热更新服务 21 | require('./build/dev-server')(app, (bundle, template) => { 22 | renderer = createRenderer(bundle, template) 23 | }) 24 | } 25 | 26 | function createRenderer(bundle, template) { 27 | return require('vue-server-renderer').createBundleRenderer(bundle, { 28 | template, 29 | cache: require('lru-cache')({ 30 | max: 1000, 31 | maxAge: 1000 * 60 * 15 32 | }) 33 | }) 34 | } 35 | 36 | const serve = (path, cache) => express.static(resolve(path), { 37 | maxAge: cache && isProd ? 60 * 60 * 24 * 30 : 0 38 | }) 39 | 40 | // 客户端跨域代理 41 | const proxyTable = { 42 | '/api': { 43 | target: config.baseUrl, 44 | changeOrigin: true, 45 | pathRewrite: { 46 | '^/api': '/api' 47 | } 48 | } 49 | } 50 | 51 | Object.keys(proxyTable).forEach(function(context) { 52 | var options = proxyTable[context] 53 | if (typeof options === 'string') { 54 | options = { target: options } 55 | } 56 | app.use(proxyMiddleware(options.filter || context, options)) 57 | }) 58 | 59 | const v = Date.now() 60 | 61 | app.use(require('cookie-parser')()) 62 | app.use('/output', serve('./output', true)) 63 | app.use('/service-worker.js', serve('./output/service-worker.js')) 64 | app.use(favicon(path.resolve(__dirname, 'public/images/favicon.ico'))) 65 | app.use(express.static(path.join(__dirname, 'public'))) 66 | 67 | app.get('*', (req, res) => { 68 | if (!renderer) { 69 | return res.end('waiting for compilation... refresh in a moment.') 70 | } 71 | 72 | const s = Date.now() 73 | 74 | res.setHeader("Content-Type", "text/html") 75 | 76 | const errorHandler = err => { 77 | if (err && err.code === 404) { 78 | // 未找到页面 79 | res.status(404).sendfile('public/404.html'); 80 | } else { 81 | // 页面渲染错误 82 | res.status(500).end('500 - Internal Server Error') 83 | console.error(`error during render : ${req.url}`) 84 | console.error(err) 85 | } 86 | } 87 | 88 | const context = { 89 | title: 'vue-ssr-template', 90 | keywords: 'vue-ssr服务端脚手架', 91 | description: 'vue-ssr-template, vue-server-renderer', 92 | version: v, 93 | url: req.url, 94 | cookies: req.cookies 95 | } 96 | 97 | renderer.renderToString(context, (err, html) => { 98 | if (err) { 99 | return errorHandler(err) 100 | } 101 | res.end(html) 102 | console.log(`whole request: ${Date.now() - s}ms`) 103 | }) 104 | }) 105 | 106 | const port = process.env.PORT || 3000 107 | app.listen(port, () => { 108 | console.log(`server started at http://localhost:${port}`) 109 | }) 110 | -------------------------------------------------------------------------------- /public/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2017 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | /*! 8 | * Generated using the Bootstrap Customizer (http://v3.bootcss.com/customize/?id=2d81d7d9ba1092cd8ff551d558f268d2) 9 | * Config saved to config.json and https://gist.github.com/2d81d7d9ba1092cd8ff551d558f268d2 10 | *//*! 11 | * Bootstrap v3.3.7 (http://getbootstrap.com) 12 | * Copyright 2011-2016 Twitter, Inc. 13 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 14 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-default.disabled,.btn-primary.disabled,.btn-success.disabled,.btn-info.disabled,.btn-warning.disabled,.btn-danger.disabled,.btn-default[disabled],.btn-primary[disabled],.btn-success[disabled],.btn-info[disabled],.btn-warning[disabled],.btn-danger[disabled],fieldset[disabled] .btn-default,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-info,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-danger{-webkit-box-shadow:none;box-shadow:none}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top, #fff 0, #e0e0e0 100%);background-image:-o-linear-gradient(top, #fff 0, #e0e0e0 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), to(#e0e0e0));background-image:linear-gradient(to bottom, #fff 0, #e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top, #337ab7 0, #265a88 100%);background-image:-o-linear-gradient(top, #337ab7 0, #265a88 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#265a88));background-image:linear-gradient(to bottom, #337ab7 0, #265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#245580}.btn-primary:hover,.btn-primary:focus{background-color:#265a88;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top, #5cb85c 0, #419641 100%);background-image:-o-linear-gradient(top, #5cb85c 0, #419641 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5cb85c), to(#419641));background-image:linear-gradient(to bottom, #5cb85c 0, #419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top, #5bc0de 0, #2aabd2 100%);background-image:-o-linear-gradient(top, #5bc0de 0, #2aabd2 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5bc0de), to(#2aabd2));background-image:linear-gradient(to bottom, #5bc0de 0, #2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top, #f0ad4e 0, #eb9316 100%);background-image:-o-linear-gradient(top, #f0ad4e 0, #eb9316 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f0ad4e), to(#eb9316));background-image:linear-gradient(to bottom, #f0ad4e 0, #eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top, #d9534f 0, #c12e2a 100%);background-image:-o-linear-gradient(top, #d9534f 0, #c12e2a 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9534f), to(#c12e2a));background-image:linear-gradient(to bottom, #d9534f 0, #c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-o-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f5f5f5), to(#e8e8e8));background-image:linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2e6da4));background-image:linear-gradient(to bottom, #337ab7 0, #2e6da4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-color:#2e6da4}.navbar-default{background-image:-webkit-linear-gradient(top, #fff 0, #f8f8f8 100%);background-image:-o-linear-gradient(top, #fff 0, #f8f8f8 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), to(#f8f8f8));background-image:linear-gradient(to bottom, #fff 0, #f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border-radius:0;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top, #dbdbdb 0, #e2e2e2 100%);background-image:-o-linear-gradient(top, #dbdbdb 0, #e2e2e2 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #dbdbdb), to(#e2e2e2));background-image:linear-gradient(to bottom, #dbdbdb 0, #e2e2e2 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top, #3c3c3c 0, #222 100%);background-image:-o-linear-gradient(top, #3c3c3c 0, #222 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #3c3c3c), to(#222));background-image:linear-gradient(to bottom, #3c3c3c 0, #222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border-radius:0}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top, #080808 0, #0f0f0f 100%);background-image:-o-linear-gradient(top, #080808 0, #0f0f0f 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #080808), to(#0f0f0f));background-image:linear-gradient(to bottom, #080808 0, #0f0f0f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-image:-webkit-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2e6da4));background-image:linear-gradient(to bottom, #337ab7 0, #2e6da4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0)}}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top, #dff0d8 0, #c8e5bc 100%);background-image:-o-linear-gradient(top, #dff0d8 0, #c8e5bc 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #dff0d8), to(#c8e5bc));background-image:linear-gradient(to bottom, #dff0d8 0, #c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top, #d9edf7 0, #b9def0 100%);background-image:-o-linear-gradient(top, #d9edf7 0, #b9def0 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9edf7), to(#b9def0));background-image:linear-gradient(to bottom, #d9edf7 0, #b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top, #fcf8e3 0, #f8efc0 100%);background-image:-o-linear-gradient(top, #fcf8e3 0, #f8efc0 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fcf8e3), to(#f8efc0));background-image:linear-gradient(to bottom, #fcf8e3 0, #f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top, #f2dede 0, #e7c3c3 100%);background-image:-o-linear-gradient(top, #f2dede 0, #e7c3c3 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f2dede), to(#e7c3c3));background-image:linear-gradient(to bottom, #f2dede 0, #e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top, #ebebeb 0, #f5f5f5 100%);background-image:-o-linear-gradient(top, #ebebeb 0, #f5f5f5 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #ebebeb), to(#f5f5f5));background-image:linear-gradient(to bottom, #ebebeb 0, #f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top, #337ab7 0, #286090 100%);background-image:-o-linear-gradient(top, #337ab7 0, #286090 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#286090));background-image:linear-gradient(to bottom, #337ab7 0, #286090 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top, #5cb85c 0, #449d44 100%);background-image:-o-linear-gradient(top, #5cb85c 0, #449d44 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5cb85c), to(#449d44));background-image:linear-gradient(to bottom, #5cb85c 0, #449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top, #5bc0de 0, #31b0d5 100%);background-image:-o-linear-gradient(top, #5bc0de 0, #31b0d5 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #5bc0de), to(#31b0d5));background-image:linear-gradient(to bottom, #5bc0de 0, #31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top, #f0ad4e 0, #ec971f 100%);background-image:-o-linear-gradient(top, #f0ad4e 0, #ec971f 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f0ad4e), to(#ec971f));background-image:linear-gradient(to bottom, #f0ad4e 0, #ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top, #d9534f 0, #c9302c 100%);background-image:-o-linear-gradient(top, #d9534f 0, #c9302c 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9534f), to(#c9302c));background-image:linear-gradient(to bottom, #d9534f 0, #c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.list-group{border-radius:0;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top, #337ab7 0, #2b669a 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2b669a 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2b669a));background-image:linear-gradient(to bottom, #337ab7 0, #2b669a 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-o-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f5f5f5), to(#e8e8e8));background-image:linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-o-linear-gradient(top, #337ab7 0, #2e6da4 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #337ab7), to(#2e6da4));background-image:linear-gradient(to bottom, #337ab7 0, #2e6da4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top, #dff0d8 0, #d0e9c6 100%);background-image:-o-linear-gradient(top, #dff0d8 0, #d0e9c6 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #dff0d8), to(#d0e9c6));background-image:linear-gradient(to bottom, #dff0d8 0, #d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top, #d9edf7 0, #c4e3f3 100%);background-image:-o-linear-gradient(top, #d9edf7 0, #c4e3f3 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #d9edf7), to(#c4e3f3));background-image:linear-gradient(to bottom, #d9edf7 0, #c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top, #fcf8e3 0, #faf2cc 100%);background-image:-o-linear-gradient(top, #fcf8e3 0, #faf2cc 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #fcf8e3), to(#faf2cc));background-image:linear-gradient(to bottom, #fcf8e3 0, #faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top, #f2dede 0, #ebcccc 100%);background-image:-o-linear-gradient(top, #f2dede 0, #ebcccc 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #f2dede), to(#ebcccc));background-image:linear-gradient(to bottom, #f2dede 0, #ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top, #e8e8e8 0, #f5f5f5 100%);background-image:-o-linear-gradient(top, #e8e8e8 0, #f5f5f5 100%);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #e8e8e8), to(#f5f5f5));background-image:linear-gradient(to bottom, #e8e8e8 0, #f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} -------------------------------------------------------------------------------- /public/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2017 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | /*! 8 | * Generated using the Bootstrap Customizer (http://v3.bootcss.com/customize/?id=2d81d7d9ba1092cd8ff551d558f268d2) 9 | * Config saved to config.json and https://gist.github.com/2d81d7d9ba1092cd8ff551d558f268d2 10 | */ 11 | /*! 12 | * Bootstrap v3.3.7 (http://getbootstrap.com) 13 | * Copyright 2011-2016 Twitter, Inc. 14 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 15 | */ 16 | .btn-default, 17 | .btn-primary, 18 | .btn-success, 19 | .btn-info, 20 | .btn-warning, 21 | .btn-danger { 22 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); 23 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); 24 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); 25 | } 26 | .btn-default:active, 27 | .btn-primary:active, 28 | .btn-success:active, 29 | .btn-info:active, 30 | .btn-warning:active, 31 | .btn-danger:active, 32 | .btn-default.active, 33 | .btn-primary.active, 34 | .btn-success.active, 35 | .btn-info.active, 36 | .btn-warning.active, 37 | .btn-danger.active { 38 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 39 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 40 | } 41 | .btn-default.disabled, 42 | .btn-primary.disabled, 43 | .btn-success.disabled, 44 | .btn-info.disabled, 45 | .btn-warning.disabled, 46 | .btn-danger.disabled, 47 | .btn-default[disabled], 48 | .btn-primary[disabled], 49 | .btn-success[disabled], 50 | .btn-info[disabled], 51 | .btn-warning[disabled], 52 | .btn-danger[disabled], 53 | fieldset[disabled] .btn-default, 54 | fieldset[disabled] .btn-primary, 55 | fieldset[disabled] .btn-success, 56 | fieldset[disabled] .btn-info, 57 | fieldset[disabled] .btn-warning, 58 | fieldset[disabled] .btn-danger { 59 | -webkit-box-shadow: none; 60 | box-shadow: none; 61 | } 62 | .btn-default .badge, 63 | .btn-primary .badge, 64 | .btn-success .badge, 65 | .btn-info .badge, 66 | .btn-warning .badge, 67 | .btn-danger .badge { 68 | text-shadow: none; 69 | } 70 | .btn:active, 71 | .btn.active { 72 | background-image: none; 73 | } 74 | .btn-default { 75 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); 76 | background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); 77 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#e0e0e0)); 78 | background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); 79 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 80 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 81 | background-repeat: repeat-x; 82 | border-color: #dbdbdb; 83 | text-shadow: 0 1px 0 #fff; 84 | border-color: #ccc; 85 | } 86 | .btn-default:hover, 87 | .btn-default:focus { 88 | background-color: #e0e0e0; 89 | background-position: 0 -15px; 90 | } 91 | .btn-default:active, 92 | .btn-default.active { 93 | background-color: #e0e0e0; 94 | border-color: #dbdbdb; 95 | } 96 | .btn-default.disabled, 97 | .btn-default[disabled], 98 | fieldset[disabled] .btn-default, 99 | .btn-default.disabled:hover, 100 | .btn-default[disabled]:hover, 101 | fieldset[disabled] .btn-default:hover, 102 | .btn-default.disabled:focus, 103 | .btn-default[disabled]:focus, 104 | fieldset[disabled] .btn-default:focus, 105 | .btn-default.disabled.focus, 106 | .btn-default[disabled].focus, 107 | fieldset[disabled] .btn-default.focus, 108 | .btn-default.disabled:active, 109 | .btn-default[disabled]:active, 110 | fieldset[disabled] .btn-default:active, 111 | .btn-default.disabled.active, 112 | .btn-default[disabled].active, 113 | fieldset[disabled] .btn-default.active { 114 | background-color: #e0e0e0; 115 | background-image: none; 116 | } 117 | .btn-primary { 118 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 119 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 120 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 121 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 122 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 123 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 124 | background-repeat: repeat-x; 125 | border-color: #245580; 126 | } 127 | .btn-primary:hover, 128 | .btn-primary:focus { 129 | background-color: #265a88; 130 | background-position: 0 -15px; 131 | } 132 | .btn-primary:active, 133 | .btn-primary.active { 134 | background-color: #265a88; 135 | border-color: #245580; 136 | } 137 | .btn-primary.disabled, 138 | .btn-primary[disabled], 139 | fieldset[disabled] .btn-primary, 140 | .btn-primary.disabled:hover, 141 | .btn-primary[disabled]:hover, 142 | fieldset[disabled] .btn-primary:hover, 143 | .btn-primary.disabled:focus, 144 | .btn-primary[disabled]:focus, 145 | fieldset[disabled] .btn-primary:focus, 146 | .btn-primary.disabled.focus, 147 | .btn-primary[disabled].focus, 148 | fieldset[disabled] .btn-primary.focus, 149 | .btn-primary.disabled:active, 150 | .btn-primary[disabled]:active, 151 | fieldset[disabled] .btn-primary:active, 152 | .btn-primary.disabled.active, 153 | .btn-primary[disabled].active, 154 | fieldset[disabled] .btn-primary.active { 155 | background-color: #265a88; 156 | background-image: none; 157 | } 158 | .btn-success { 159 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 160 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 161 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 162 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 163 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 164 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 165 | background-repeat: repeat-x; 166 | border-color: #3e8f3e; 167 | } 168 | .btn-success:hover, 169 | .btn-success:focus { 170 | background-color: #419641; 171 | background-position: 0 -15px; 172 | } 173 | .btn-success:active, 174 | .btn-success.active { 175 | background-color: #419641; 176 | border-color: #3e8f3e; 177 | } 178 | .btn-success.disabled, 179 | .btn-success[disabled], 180 | fieldset[disabled] .btn-success, 181 | .btn-success.disabled:hover, 182 | .btn-success[disabled]:hover, 183 | fieldset[disabled] .btn-success:hover, 184 | .btn-success.disabled:focus, 185 | .btn-success[disabled]:focus, 186 | fieldset[disabled] .btn-success:focus, 187 | .btn-success.disabled.focus, 188 | .btn-success[disabled].focus, 189 | fieldset[disabled] .btn-success.focus, 190 | .btn-success.disabled:active, 191 | .btn-success[disabled]:active, 192 | fieldset[disabled] .btn-success:active, 193 | .btn-success.disabled.active, 194 | .btn-success[disabled].active, 195 | fieldset[disabled] .btn-success.active { 196 | background-color: #419641; 197 | background-image: none; 198 | } 199 | .btn-info { 200 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 201 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 202 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 203 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 204 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 205 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 206 | background-repeat: repeat-x; 207 | border-color: #28a4c9; 208 | } 209 | .btn-info:hover, 210 | .btn-info:focus { 211 | background-color: #2aabd2; 212 | background-position: 0 -15px; 213 | } 214 | .btn-info:active, 215 | .btn-info.active { 216 | background-color: #2aabd2; 217 | border-color: #28a4c9; 218 | } 219 | .btn-info.disabled, 220 | .btn-info[disabled], 221 | fieldset[disabled] .btn-info, 222 | .btn-info.disabled:hover, 223 | .btn-info[disabled]:hover, 224 | fieldset[disabled] .btn-info:hover, 225 | .btn-info.disabled:focus, 226 | .btn-info[disabled]:focus, 227 | fieldset[disabled] .btn-info:focus, 228 | .btn-info.disabled.focus, 229 | .btn-info[disabled].focus, 230 | fieldset[disabled] .btn-info.focus, 231 | .btn-info.disabled:active, 232 | .btn-info[disabled]:active, 233 | fieldset[disabled] .btn-info:active, 234 | .btn-info.disabled.active, 235 | .btn-info[disabled].active, 236 | fieldset[disabled] .btn-info.active { 237 | background-color: #2aabd2; 238 | background-image: none; 239 | } 240 | .btn-warning { 241 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 242 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 243 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 244 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 245 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 246 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 247 | background-repeat: repeat-x; 248 | border-color: #e38d13; 249 | } 250 | .btn-warning:hover, 251 | .btn-warning:focus { 252 | background-color: #eb9316; 253 | background-position: 0 -15px; 254 | } 255 | .btn-warning:active, 256 | .btn-warning.active { 257 | background-color: #eb9316; 258 | border-color: #e38d13; 259 | } 260 | .btn-warning.disabled, 261 | .btn-warning[disabled], 262 | fieldset[disabled] .btn-warning, 263 | .btn-warning.disabled:hover, 264 | .btn-warning[disabled]:hover, 265 | fieldset[disabled] .btn-warning:hover, 266 | .btn-warning.disabled:focus, 267 | .btn-warning[disabled]:focus, 268 | fieldset[disabled] .btn-warning:focus, 269 | .btn-warning.disabled.focus, 270 | .btn-warning[disabled].focus, 271 | fieldset[disabled] .btn-warning.focus, 272 | .btn-warning.disabled:active, 273 | .btn-warning[disabled]:active, 274 | fieldset[disabled] .btn-warning:active, 275 | .btn-warning.disabled.active, 276 | .btn-warning[disabled].active, 277 | fieldset[disabled] .btn-warning.active { 278 | background-color: #eb9316; 279 | background-image: none; 280 | } 281 | .btn-danger { 282 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 283 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 284 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 285 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 286 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 287 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 288 | background-repeat: repeat-x; 289 | border-color: #b92c28; 290 | } 291 | .btn-danger:hover, 292 | .btn-danger:focus { 293 | background-color: #c12e2a; 294 | background-position: 0 -15px; 295 | } 296 | .btn-danger:active, 297 | .btn-danger.active { 298 | background-color: #c12e2a; 299 | border-color: #b92c28; 300 | } 301 | .btn-danger.disabled, 302 | .btn-danger[disabled], 303 | fieldset[disabled] .btn-danger, 304 | .btn-danger.disabled:hover, 305 | .btn-danger[disabled]:hover, 306 | fieldset[disabled] .btn-danger:hover, 307 | .btn-danger.disabled:focus, 308 | .btn-danger[disabled]:focus, 309 | fieldset[disabled] .btn-danger:focus, 310 | .btn-danger.disabled.focus, 311 | .btn-danger[disabled].focus, 312 | fieldset[disabled] .btn-danger.focus, 313 | .btn-danger.disabled:active, 314 | .btn-danger[disabled]:active, 315 | fieldset[disabled] .btn-danger:active, 316 | .btn-danger.disabled.active, 317 | .btn-danger[disabled].active, 318 | fieldset[disabled] .btn-danger.active { 319 | background-color: #c12e2a; 320 | background-image: none; 321 | } 322 | .thumbnail, 323 | .img-thumbnail { 324 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 325 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 326 | } 327 | .dropdown-menu > li > a:hover, 328 | .dropdown-menu > li > a:focus { 329 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 330 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 331 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 332 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 333 | background-repeat: repeat-x; 334 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 335 | background-color: #e8e8e8; 336 | } 337 | .dropdown-menu > .active > a, 338 | .dropdown-menu > .active > a:hover, 339 | .dropdown-menu > .active > a:focus { 340 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 341 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 342 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 343 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 344 | background-repeat: repeat-x; 345 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 346 | background-color: #2e6da4; 347 | } 348 | .navbar-default { 349 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); 350 | background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); 351 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f8f8f8)); 352 | background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); 353 | background-repeat: repeat-x; 354 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 355 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 356 | border-radius: 0px; 357 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 358 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 359 | } 360 | .navbar-default .navbar-nav > .open > a, 361 | .navbar-default .navbar-nav > .active > a { 362 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 363 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 364 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 365 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 366 | background-repeat: repeat-x; 367 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 368 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 369 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 370 | } 371 | .navbar-brand, 372 | .navbar-nav > li > a { 373 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); 374 | } 375 | .navbar-inverse { 376 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); 377 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%); 378 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222222)); 379 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); 380 | background-repeat: repeat-x; 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 382 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 383 | border-radius: 0px; 384 | } 385 | .navbar-inverse .navbar-nav > .open > a, 386 | .navbar-inverse .navbar-nav > .active > a { 387 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 388 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 389 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 390 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 391 | background-repeat: repeat-x; 392 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 393 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 394 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 395 | } 396 | .navbar-inverse .navbar-brand, 397 | .navbar-inverse .navbar-nav > li > a { 398 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 399 | } 400 | .navbar-static-top, 401 | .navbar-fixed-top, 402 | .navbar-fixed-bottom { 403 | border-radius: 0; 404 | } 405 | @media (max-width: 767px) { 406 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 407 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 408 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 409 | color: #fff; 410 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 411 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 412 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 413 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 414 | background-repeat: repeat-x; 415 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 416 | } 417 | } 418 | .alert { 419 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); 420 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 421 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 422 | } 423 | .alert-success { 424 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 425 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 426 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 427 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 428 | background-repeat: repeat-x; 429 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 430 | border-color: #b2dba1; 431 | } 432 | .alert-info { 433 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 434 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 435 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 436 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 437 | background-repeat: repeat-x; 438 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 439 | border-color: #9acfea; 440 | } 441 | .alert-warning { 442 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 443 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 444 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 445 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 446 | background-repeat: repeat-x; 447 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 448 | border-color: #f5e79e; 449 | } 450 | .alert-danger { 451 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 452 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 453 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 454 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 455 | background-repeat: repeat-x; 456 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 457 | border-color: #dca7a7; 458 | } 459 | .progress { 460 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 461 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 462 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 463 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 464 | background-repeat: repeat-x; 465 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 466 | } 467 | .progress-bar { 468 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 469 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 470 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 471 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 472 | background-repeat: repeat-x; 473 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 474 | } 475 | .progress-bar-success { 476 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 477 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 478 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 479 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 480 | background-repeat: repeat-x; 481 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 482 | } 483 | .progress-bar-info { 484 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 485 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 486 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 487 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 488 | background-repeat: repeat-x; 489 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 490 | } 491 | .progress-bar-warning { 492 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 493 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 494 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 495 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 496 | background-repeat: repeat-x; 497 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 498 | } 499 | .progress-bar-danger { 500 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 501 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 502 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 503 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 504 | background-repeat: repeat-x; 505 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 506 | } 507 | .progress-bar-striped { 508 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 509 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 510 | background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); 511 | } 512 | .list-group { 513 | border-radius: 0px; 514 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 515 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 516 | } 517 | .list-group-item.active, 518 | .list-group-item.active:hover, 519 | .list-group-item.active:focus { 520 | text-shadow: 0 -1px 0 #286090; 521 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 522 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 523 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 524 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 525 | background-repeat: repeat-x; 526 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 527 | border-color: #2b669a; 528 | } 529 | .list-group-item.active .badge, 530 | .list-group-item.active:hover .badge, 531 | .list-group-item.active:focus .badge { 532 | text-shadow: none; 533 | } 534 | .panel { 535 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 536 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 537 | } 538 | .panel-default > .panel-heading { 539 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 540 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 541 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 542 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 543 | background-repeat: repeat-x; 544 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 545 | } 546 | .panel-primary > .panel-heading { 547 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 548 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 549 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 550 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 551 | background-repeat: repeat-x; 552 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 553 | } 554 | .panel-success > .panel-heading { 555 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 556 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 557 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 558 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 559 | background-repeat: repeat-x; 560 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 561 | } 562 | .panel-info > .panel-heading { 563 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 564 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 565 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 566 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 567 | background-repeat: repeat-x; 568 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 569 | } 570 | .panel-warning > .panel-heading { 571 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 572 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 573 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 574 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 575 | background-repeat: repeat-x; 576 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 577 | } 578 | .panel-danger > .panel-heading { 579 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 580 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 581 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 582 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 583 | background-repeat: repeat-x; 584 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 585 | } 586 | .well { 587 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 588 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 589 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 590 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 591 | background-repeat: repeat-x; 592 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 593 | border-color: #dcdcdc; 594 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 595 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 596 | } 597 | -------------------------------------------------------------------------------- /public/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2017 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | /*! 8 | * Generated using the Bootstrap Customizer (http://v3.bootcss.com/customize/?id=2d81d7d9ba1092cd8ff551d558f268d2) 9 | * Config saved to config.json and https://gist.github.com/2d81d7d9ba1092cd8ff551d558f268d2 10 | */ 11 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(t){"use strict";var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||e[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var i=t(this),n=i.data("bs.alert");n||i.data("bs.alert",n=new o(this)),"string"==typeof e&&n[e].call(i)})}var i='[data-dismiss="alert"]',o=function(e){t(e).on("click",i,this.close)};o.VERSION="3.3.7",o.TRANSITION_DURATION=150,o.prototype.close=function(e){function i(){a.detach().trigger("closed.bs.alert").remove()}var n=t(this),s=n.attr("data-target");s||(s=n.attr("href"),s=s&&s.replace(/.*(?=#[^\s]*$)/,""));var a=t("#"===s?[]:s);e&&e.preventDefault(),a.length||(a=n.closest(".alert")),a.trigger(e=t.Event("close.bs.alert")),e.isDefaultPrevented()||(a.removeClass("in"),t.support.transition&&a.hasClass("fade")?a.one("bsTransitionEnd",i).emulateTransitionEnd(o.TRANSITION_DURATION):i())};var n=t.fn.alert;t.fn.alert=e,t.fn.alert.Constructor=o,t.fn.alert.noConflict=function(){return t.fn.alert=n,this},t(document).on("click.bs.alert.data-api",i,o.prototype.close)}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.button"),s="object"==typeof e&&e;n||o.data("bs.button",n=new i(this,s)),"toggle"==e?n.toggle():e&&n.setState(e)})}var i=function(e,o){this.$element=t(e),this.options=t.extend({},i.DEFAULTS,o),this.isLoading=!1};i.VERSION="3.3.7",i.DEFAULTS={loadingText:"loading..."},i.prototype.setState=function(e){var i="disabled",o=this.$element,n=o.is("input")?"val":"html",s=o.data();e+="Text",null==s.resetText&&o.data("resetText",o[n]()),setTimeout(t.proxy(function(){o[n](null==s[e]?this.options[e]:s[e]),"loadingText"==e?(this.isLoading=!0,o.addClass(i).attr(i,i).prop(i,!0)):this.isLoading&&(this.isLoading=!1,o.removeClass(i).removeAttr(i).prop(i,!1))},this),0)},i.prototype.toggle=function(){var t=!0,e=this.$element.closest('[data-toggle="buttons"]');if(e.length){var i=this.$element.find("input");"radio"==i.prop("type")?(i.prop("checked")&&(t=!1),e.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==i.prop("type")&&(i.prop("checked")!==this.$element.hasClass("active")&&(t=!1),this.$element.toggleClass("active")),i.prop("checked",this.$element.hasClass("active")),t&&i.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var o=t.fn.button;t.fn.button=e,t.fn.button.Constructor=i,t.fn.button.noConflict=function(){return t.fn.button=o,this},t(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(i){var o=t(i.target).closest(".btn");e.call(o,"toggle"),t(i.target).is('input[type="radio"], input[type="checkbox"]')||(i.preventDefault(),o.is("input,button")?o.trigger("focus"):o.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(e){t(e.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(e.type))})}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.carousel"),s=t.extend({},i.DEFAULTS,o.data(),"object"==typeof e&&e),a="string"==typeof e?e:s.slide;n||o.data("bs.carousel",n=new i(this,s)),"number"==typeof e?n.to(e):a?n[a]():s.interval&&n.pause().cycle()})}var i=function(e,i){this.$element=t(e),this.$indicators=this.$element.find(".carousel-indicators"),this.options=i,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",t.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",t.proxy(this.pause,this)).on("mouseleave.bs.carousel",t.proxy(this.cycle,this))};i.VERSION="3.3.7",i.TRANSITION_DURATION=600,i.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},i.prototype.keydown=function(t){if(!/input|textarea/i.test(t.target.tagName)){switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}t.preventDefault()}},i.prototype.cycle=function(e){return e||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(t.proxy(this.next,this),this.options.interval)),this},i.prototype.getItemIndex=function(t){return this.$items=t.parent().children(".item"),this.$items.index(t||this.$active)},i.prototype.getItemForDirection=function(t,e){var i=this.getItemIndex(e),o="prev"==t&&0===i||"next"==t&&i==this.$items.length-1;if(o&&!this.options.wrap)return e;var n="prev"==t?-1:1,s=(i+n)%this.$items.length;return this.$items.eq(s)},i.prototype.to=function(t){var e=this,i=this.getItemIndex(this.$active=this.$element.find(".item.active"));return t>this.$items.length-1||0>t?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){e.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",this.$items.eq(t))},i.prototype.pause=function(e){return e||(this.paused=!0),this.$element.find(".next, .prev").length&&t.support.transition&&(this.$element.trigger(t.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},i.prototype.next=function(){return this.sliding?void 0:this.slide("next")},i.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},i.prototype.slide=function(e,o){var n=this.$element.find(".item.active"),s=o||this.getItemForDirection(e,n),a=this.interval,r="next"==e?"left":"right",l=this;if(s.hasClass("active"))return this.sliding=!1;var h=s[0],d=t.Event("slide.bs.carousel",{relatedTarget:h,direction:r});if(this.$element.trigger(d),!d.isDefaultPrevented()){if(this.sliding=!0,a&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var p=t(this.$indicators.children()[this.getItemIndex(s)]);p&&p.addClass("active")}var c=t.Event("slid.bs.carousel",{relatedTarget:h,direction:r});return t.support.transition&&this.$element.hasClass("slide")?(s.addClass(e),s[0].offsetWidth,n.addClass(r),s.addClass(r),n.one("bsTransitionEnd",function(){s.removeClass([e,r].join(" ")).addClass("active"),n.removeClass(["active",r].join(" ")),l.sliding=!1,setTimeout(function(){l.$element.trigger(c)},0)}).emulateTransitionEnd(i.TRANSITION_DURATION)):(n.removeClass("active"),s.addClass("active"),this.sliding=!1,this.$element.trigger(c)),a&&this.cycle(),this}};var o=t.fn.carousel;t.fn.carousel=e,t.fn.carousel.Constructor=i,t.fn.carousel.noConflict=function(){return t.fn.carousel=o,this};var n=function(i){var o,n=t(this),s=t(n.attr("data-target")||(o=n.attr("href"))&&o.replace(/.*(?=#[^\s]+$)/,""));if(s.hasClass("carousel")){var a=t.extend({},s.data(),n.data()),r=n.attr("data-slide-to");r&&(a.interval=!1),e.call(s,a),r&&s.data("bs.carousel").to(r),i.preventDefault()}};t(document).on("click.bs.carousel.data-api","[data-slide]",n).on("click.bs.carousel.data-api","[data-slide-to]",n),t(window).on("load",function(){t('[data-ride="carousel"]').each(function(){var i=t(this);e.call(i,i.data())})})}(jQuery),+function(t){"use strict";function e(e){var i=e.attr("data-target");i||(i=e.attr("href"),i=i&&/#[A-Za-z]/.test(i)&&i.replace(/.*(?=#[^\s]*$)/,""));var o=i&&t(i);return o&&o.length?o:e.parent()}function i(i){i&&3===i.which||(t(n).remove(),t(s).each(function(){var o=t(this),n=e(o),s={relatedTarget:this};n.hasClass("open")&&(i&&"click"==i.type&&/input|textarea/i.test(i.target.tagName)&&t.contains(n[0],i.target)||(n.trigger(i=t.Event("hide.bs.dropdown",s)),i.isDefaultPrevented()||(o.attr("aria-expanded","false"),n.removeClass("open").trigger(t.Event("hidden.bs.dropdown",s)))))}))}function o(e){return this.each(function(){var i=t(this),o=i.data("bs.dropdown");o||i.data("bs.dropdown",o=new a(this)),"string"==typeof e&&o[e].call(i)})}var n=".dropdown-backdrop",s='[data-toggle="dropdown"]',a=function(e){t(e).on("click.bs.dropdown",this.toggle)};a.VERSION="3.3.7",a.prototype.toggle=function(o){var n=t(this);if(!n.is(".disabled, :disabled")){var s=e(n),a=s.hasClass("open");if(i(),!a){"ontouchstart"in document.documentElement&&!s.closest(".navbar-nav").length&&t(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(t(this)).on("click",i);var r={relatedTarget:this};if(s.trigger(o=t.Event("show.bs.dropdown",r)),o.isDefaultPrevented())return;n.trigger("focus").attr("aria-expanded","true"),s.toggleClass("open").trigger(t.Event("shown.bs.dropdown",r))}return!1}},a.prototype.keydown=function(i){if(/(38|40|27|32)/.test(i.which)&&!/input|textarea/i.test(i.target.tagName)){var o=t(this);if(i.preventDefault(),i.stopPropagation(),!o.is(".disabled, :disabled")){var n=e(o),a=n.hasClass("open");if(!a&&27!=i.which||a&&27==i.which)return 27==i.which&&n.find(s).trigger("focus"),o.trigger("click");var r=" li:not(.disabled):visible a",l=n.find(".dropdown-menu"+r);if(l.length){var h=l.index(i.target);38==i.which&&h>0&&h--,40==i.which&&hdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},i.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},i.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},i.prototype.init=function(e,i,o){if(this.enabled=!0,this.type=e,this.$element=t(i),this.options=this.getOptions(o),this.$viewport=this.options.viewport&&t(t.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var n=this.options.trigger.split(" "),s=n.length;s--;){var a=n[s];if("click"==a)this.$element.on("click."+this.type,this.options.selector,t.proxy(this.toggle,this));else if("manual"!=a){var r="hover"==a?"mouseenter":"focusin",l="hover"==a?"mouseleave":"focusout";this.$element.on(r+"."+this.type,this.options.selector,t.proxy(this.enter,this)),this.$element.on(l+"."+this.type,this.options.selector,t.proxy(this.leave,this))}}this.options.selector?this._options=t.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},i.prototype.getDefaults=function(){return i.DEFAULTS},i.prototype.getOptions=function(e){return e=t.extend({},this.getDefaults(),this.$element.data(),e),e.delay&&"number"==typeof e.delay&&(e.delay={show:e.delay,hide:e.delay}),e},i.prototype.getDelegateOptions=function(){var e={},i=this.getDefaults();return this._options&&t.each(this._options,function(t,o){i[t]!=o&&(e[t]=o)}),e},i.prototype.enter=function(e){var i=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i)),e instanceof t.Event&&(i.inState["focusin"==e.type?"focus":"hover"]=!0),i.tip().hasClass("in")||"in"==i.hoverState?void(i.hoverState="in"):(clearTimeout(i.timeout),i.hoverState="in",i.options.delay&&i.options.delay.show?void(i.timeout=setTimeout(function(){"in"==i.hoverState&&i.show()},i.options.delay.show)):i.show())},i.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},i.prototype.leave=function(e){var i=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i)),e instanceof t.Event&&(i.inState["focusout"==e.type?"focus":"hover"]=!1),i.isInStateTrue()?void 0:(clearTimeout(i.timeout),i.hoverState="out",i.options.delay&&i.options.delay.hide?void(i.timeout=setTimeout(function(){"out"==i.hoverState&&i.hide()},i.options.delay.hide)):i.hide())},i.prototype.show=function(){var e=t.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(e);var o=t.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!o)return;var n=this,s=this.tip(),a=this.getUID(this.type);this.setContent(),s.attr("id",a),this.$element.attr("aria-describedby",a),this.options.animation&&s.addClass("fade");var r="function"==typeof this.options.placement?this.options.placement.call(this,s[0],this.$element[0]):this.options.placement,l=/\s?auto?\s?/i,h=l.test(r);h&&(r=r.replace(l,"")||"top"),s.detach().css({top:0,left:0,display:"block"}).addClass(r).data("bs."+this.type,this),this.options.container?s.appendTo(this.options.container):s.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var d=this.getPosition(),p=s[0].offsetWidth,c=s[0].offsetHeight;if(h){var f=r,u=this.getPosition(this.$viewport);r="bottom"==r&&d.bottom+c>u.bottom?"top":"top"==r&&d.top-cu.width?"left":"left"==r&&d.left-pa.top+a.height&&(n.top=a.top+a.height-l)}else{var h=e.left-s,d=e.left+s+i;ha.right&&(n.left=a.left+a.width-d)}return n},i.prototype.getTitle=function(){var t,e=this.$element,i=this.options;return t=e.attr("data-original-title")||("function"==typeof i.title?i.title.call(e[0]):i.title)},i.prototype.getUID=function(t){do t+=~~(1e6*Math.random());while(document.getElementById(t));return t},i.prototype.tip=function(){if(!this.$tip&&(this.$tip=t(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},i.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},i.prototype.enable=function(){this.enabled=!0},i.prototype.disable=function(){this.enabled=!1},i.prototype.toggleEnabled=function(){this.enabled=!this.enabled},i.prototype.toggle=function(e){var i=this;e&&(i=t(e.currentTarget).data("bs."+this.type),i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i))),e?(i.inState.click=!i.inState.click,i.isInStateTrue()?i.enter(i):i.leave(i)):i.tip().hasClass("in")?i.leave(i):i.enter(i)},i.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null,t.$element=null})};var o=t.fn.tooltip;t.fn.tooltip=e,t.fn.tooltip.Constructor=i,t.fn.tooltip.noConflict=function(){return t.fn.tooltip=o,this}}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.popover"),s="object"==typeof e&&e;!n&&/destroy|hide/.test(e)||(n||o.data("bs.popover",n=new i(this,s)),"string"==typeof e&&n[e]())})}var i=function(t,e){this.init("popover",t,e)};if(!t.fn.tooltip)throw new Error("Popover requires tooltip.js");i.VERSION="3.3.7",i.DEFAULTS=t.extend({},t.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),i.prototype=t.extend({},t.fn.tooltip.Constructor.prototype),i.prototype.constructor=i,i.prototype.getDefaults=function(){return i.DEFAULTS},i.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),i=this.getContent();t.find(".popover-title")[this.options.html?"html":"text"](e),t.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof i?"html":"append":"text"](i),t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},i.prototype.hasContent=function(){return this.getTitle()||this.getContent()},i.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},i.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var o=t.fn.popover;t.fn.popover=e,t.fn.popover.Constructor=i,t.fn.popover.noConflict=function(){return t.fn.popover=o,this}}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.tab");n||o.data("bs.tab",n=new i(this)),"string"==typeof e&&n[e]()})}var i=function(e){this.element=t(e)};i.VERSION="3.3.7",i.TRANSITION_DURATION=150,i.prototype.show=function(){var e=this.element,i=e.closest("ul:not(.dropdown-menu)"),o=e.data("target");if(o||(o=e.attr("href"),o=o&&o.replace(/.*(?=#[^\s]*$)/,"")),!e.parent("li").hasClass("active")){var n=i.find(".active:last a"),s=t.Event("hide.bs.tab",{relatedTarget:e[0]}),a=t.Event("show.bs.tab",{relatedTarget:n[0]});if(n.trigger(s),e.trigger(a),!a.isDefaultPrevented()&&!s.isDefaultPrevented()){var r=t(o);this.activate(e.closest("li"),i),this.activate(r,r.parent(),function(){n.trigger({type:"hidden.bs.tab",relatedTarget:e[0]}),e.trigger({type:"shown.bs.tab",relatedTarget:n[0]})})}}},i.prototype.activate=function(e,o,n){function s(){a.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),e.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),r?(e[0].offsetWidth,e.addClass("in")):e.removeClass("fade"),e.parent(".dropdown-menu").length&&e.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),n&&n()}var a=o.find("> .active"),r=n&&t.support.transition&&(a.length&&a.hasClass("fade")||!!o.find("> .fade").length);a.length&&r?a.one("bsTransitionEnd",s).emulateTransitionEnd(i.TRANSITION_DURATION):s(),a.removeClass("in")};var o=t.fn.tab;t.fn.tab=e,t.fn.tab.Constructor=i,t.fn.tab.noConflict=function(){return t.fn.tab=o,this};var n=function(i){i.preventDefault(),e.call(t(this),"show")};t(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',n).on("click.bs.tab.data-api",'[data-toggle="pill"]',n)}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.affix"),s="object"==typeof e&&e;n||o.data("bs.affix",n=new i(this,s)),"string"==typeof e&&n[e]()})}var i=function(e,o){this.options=t.extend({},i.DEFAULTS,o),this.$target=t(this.options.target).on("scroll.bs.affix.data-api",t.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",t.proxy(this.checkPositionWithEventLoop,this)),this.$element=t(e),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};i.VERSION="3.3.7",i.RESET="affix affix-top affix-bottom",i.DEFAULTS={offset:0,target:window},i.prototype.getState=function(t,e,i,o){var n=this.$target.scrollTop(),s=this.$element.offset(),a=this.$target.height();if(null!=i&&"top"==this.affixed)return i>n?"top":!1;if("bottom"==this.affixed)return null!=i?n+this.unpin<=s.top?!1:"bottom":t-o>=n+a?!1:"bottom";var r=null==this.affixed,l=r?n:s.top,h=r?a:e;return null!=i&&i>=n?"top":null!=o&&l+h>=t-o?"bottom":!1},i.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(i.RESET).addClass("affix");var t=this.$target.scrollTop(),e=this.$element.offset();return this.pinnedOffset=e.top-t},i.prototype.checkPositionWithEventLoop=function(){setTimeout(t.proxy(this.checkPosition,this),1)},i.prototype.checkPosition=function(){if(this.$element.is(":visible")){var e=this.$element.height(),o=this.options.offset,n=o.top,s=o.bottom,a=Math.max(t(document).height(),t(document.body).height());"object"!=typeof o&&(s=n=o),"function"==typeof n&&(n=o.top(this.$element)),"function"==typeof s&&(s=o.bottom(this.$element));var r=this.getState(a,e,n,s);if(this.affixed!=r){null!=this.unpin&&this.$element.css("top","");var l="affix"+(r?"-"+r:""),h=t.Event(l+".bs.affix");if(this.$element.trigger(h),h.isDefaultPrevented())return;this.affixed=r,this.unpin="bottom"==r?this.getPinnedOffset():null,this.$element.removeClass(i.RESET).addClass(l).trigger(l.replace("affix","affixed")+".bs.affix")}"bottom"==r&&this.$element.offset({top:a-e-s})}};var o=t.fn.affix;t.fn.affix=e,t.fn.affix.Constructor=i,t.fn.affix.noConflict=function(){return t.fn.affix=o,this},t(window).on("load",function(){t('[data-spy="affix"]').each(function(){var i=t(this),o=i.data();o.offset=o.offset||{},null!=o.offsetBottom&&(o.offset.bottom=o.offsetBottom),null!=o.offsetTop&&(o.offset.top=o.offsetTop),e.call(i,o)})})}(jQuery),+function(t){"use strict";function e(e){var i,o=e.attr("data-target")||(i=e.attr("href"))&&i.replace(/.*(?=#[^\s]+$)/,"");return t(o)}function i(e){return this.each(function(){var i=t(this),n=i.data("bs.collapse"),s=t.extend({},o.DEFAULTS,i.data(),"object"==typeof e&&e);!n&&s.toggle&&/show|hide/.test(e)&&(s.toggle=!1),n||i.data("bs.collapse",n=new o(this,s)),"string"==typeof e&&n[e]()})}var o=function(e,i){this.$element=t(e),this.options=t.extend({},o.DEFAULTS,i),this.$trigger=t('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};o.VERSION="3.3.7",o.TRANSITION_DURATION=350,o.DEFAULTS={toggle:!0},o.prototype.dimension=function(){var t=this.$element.hasClass("width");return t?"width":"height"},o.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var e,n=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(n&&n.length&&(e=n.data("bs.collapse"),e&&e.transitioning))){var s=t.Event("show.bs.collapse");if(this.$element.trigger(s),!s.isDefaultPrevented()){n&&n.length&&(i.call(n,"hide"),e||n.data("bs.collapse",null));var a=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[a](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var r=function(){this.$element.removeClass("collapsing").addClass("collapse in")[a](""),this.transitioning=0, 12 | this.$element.trigger("shown.bs.collapse")};if(!t.support.transition)return r.call(this);var l=t.camelCase(["scroll",a].join("-"));this.$element.one("bsTransitionEnd",t.proxy(r,this)).emulateTransitionEnd(o.TRANSITION_DURATION)[a](this.$element[0][l])}}}},o.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var e=t.Event("hide.bs.collapse");if(this.$element.trigger(e),!e.isDefaultPrevented()){var i=this.dimension();this.$element[i](this.$element[i]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var n=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return t.support.transition?void this.$element[i](0).one("bsTransitionEnd",t.proxy(n,this)).emulateTransitionEnd(o.TRANSITION_DURATION):n.call(this)}}},o.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},o.prototype.getParent=function(){return t(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(t.proxy(function(i,o){var n=t(o);this.addAriaAndCollapsedClass(e(n),n)},this)).end()},o.prototype.addAriaAndCollapsedClass=function(t,e){var i=t.hasClass("in");t.attr("aria-expanded",i),e.toggleClass("collapsed",!i).attr("aria-expanded",i)};var n=t.fn.collapse;t.fn.collapse=i,t.fn.collapse.Constructor=o,t.fn.collapse.noConflict=function(){return t.fn.collapse=n,this},t(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(o){var n=t(this);n.attr("data-target")||o.preventDefault();var s=e(n),a=s.data("bs.collapse"),r=a?"toggle":n.data();i.call(s,r)})}(jQuery),+function(t){"use strict";function e(i,o){this.$body=t(document.body),this.$scrollElement=t(t(i).is(document.body)?window:i),this.options=t.extend({},e.DEFAULTS,o),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",t.proxy(this.process,this)),this.refresh(),this.process()}function i(i){return this.each(function(){var o=t(this),n=o.data("bs.scrollspy"),s="object"==typeof i&&i;n||o.data("bs.scrollspy",n=new e(this,s)),"string"==typeof i&&n[i]()})}e.VERSION="3.3.7",e.DEFAULTS={offset:10},e.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},e.prototype.refresh=function(){var e=this,i="offset",o=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),t.isWindow(this.$scrollElement[0])||(i="position",o=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var e=t(this),n=e.data("target")||e.attr("href"),s=/^#./.test(n)&&t(n);return s&&s.length&&s.is(":visible")&&[[s[i]().top+o,n]]||null}).sort(function(t,e){return t[0]-e[0]}).each(function(){e.offsets.push(this[0]),e.targets.push(this[1])})},e.prototype.process=function(){var t,e=this.$scrollElement.scrollTop()+this.options.offset,i=this.getScrollHeight(),o=this.options.offset+i-this.$scrollElement.height(),n=this.offsets,s=this.targets,a=this.activeTarget;if(this.scrollHeight!=i&&this.refresh(),e>=o)return a!=(t=s[s.length-1])&&this.activate(t);if(a&&e=n[t]&&(void 0===n[t+1]||e 3)) { 18 | throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4') 19 | } 20 | }(jQuery); 21 | 22 | /* ======================================================================== 23 | * Bootstrap: alert.js v3.3.7 24 | * http://getbootstrap.com/javascript/#alerts 25 | * ======================================================================== 26 | * Copyright 2011-2016 Twitter, Inc. 27 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 28 | * ======================================================================== */ 29 | 30 | 31 | +function ($) { 32 | 'use strict'; 33 | 34 | // ALERT CLASS DEFINITION 35 | // ====================== 36 | 37 | var dismiss = '[data-dismiss="alert"]' 38 | var Alert = function (el) { 39 | $(el).on('click', dismiss, this.close) 40 | } 41 | 42 | Alert.VERSION = '3.3.7' 43 | 44 | Alert.TRANSITION_DURATION = 150 45 | 46 | Alert.prototype.close = function (e) { 47 | var $this = $(this) 48 | var selector = $this.attr('data-target') 49 | 50 | if (!selector) { 51 | selector = $this.attr('href') 52 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 53 | } 54 | 55 | var $parent = $(selector === '#' ? [] : selector) 56 | 57 | if (e) e.preventDefault() 58 | 59 | if (!$parent.length) { 60 | $parent = $this.closest('.alert') 61 | } 62 | 63 | $parent.trigger(e = $.Event('close.bs.alert')) 64 | 65 | if (e.isDefaultPrevented()) return 66 | 67 | $parent.removeClass('in') 68 | 69 | function removeElement() { 70 | // detach from parent, fire event then clean up data 71 | $parent.detach().trigger('closed.bs.alert').remove() 72 | } 73 | 74 | $.support.transition && $parent.hasClass('fade') ? 75 | $parent 76 | .one('bsTransitionEnd', removeElement) 77 | .emulateTransitionEnd(Alert.TRANSITION_DURATION) : 78 | removeElement() 79 | } 80 | 81 | 82 | // ALERT PLUGIN DEFINITION 83 | // ======================= 84 | 85 | function Plugin(option) { 86 | return this.each(function () { 87 | var $this = $(this) 88 | var data = $this.data('bs.alert') 89 | 90 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 91 | if (typeof option == 'string') data[option].call($this) 92 | }) 93 | } 94 | 95 | var old = $.fn.alert 96 | 97 | $.fn.alert = Plugin 98 | $.fn.alert.Constructor = Alert 99 | 100 | 101 | // ALERT NO CONFLICT 102 | // ================= 103 | 104 | $.fn.alert.noConflict = function () { 105 | $.fn.alert = old 106 | return this 107 | } 108 | 109 | 110 | // ALERT DATA-API 111 | // ============== 112 | 113 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 114 | 115 | }(jQuery); 116 | 117 | /* ======================================================================== 118 | * Bootstrap: button.js v3.3.7 119 | * http://getbootstrap.com/javascript/#buttons 120 | * ======================================================================== 121 | * Copyright 2011-2016 Twitter, Inc. 122 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 123 | * ======================================================================== */ 124 | 125 | 126 | +function ($) { 127 | 'use strict'; 128 | 129 | // BUTTON PUBLIC CLASS DEFINITION 130 | // ============================== 131 | 132 | var Button = function (element, options) { 133 | this.$element = $(element) 134 | this.options = $.extend({}, Button.DEFAULTS, options) 135 | this.isLoading = false 136 | } 137 | 138 | Button.VERSION = '3.3.7' 139 | 140 | Button.DEFAULTS = { 141 | loadingText: 'loading...' 142 | } 143 | 144 | Button.prototype.setState = function (state) { 145 | var d = 'disabled' 146 | var $el = this.$element 147 | var val = $el.is('input') ? 'val' : 'html' 148 | var data = $el.data() 149 | 150 | state += 'Text' 151 | 152 | if (data.resetText == null) $el.data('resetText', $el[val]()) 153 | 154 | // push to event loop to allow forms to submit 155 | setTimeout($.proxy(function () { 156 | $el[val](data[state] == null ? this.options[state] : data[state]) 157 | 158 | if (state == 'loadingText') { 159 | this.isLoading = true 160 | $el.addClass(d).attr(d, d).prop(d, true) 161 | } else if (this.isLoading) { 162 | this.isLoading = false 163 | $el.removeClass(d).removeAttr(d).prop(d, false) 164 | } 165 | }, this), 0) 166 | } 167 | 168 | Button.prototype.toggle = function () { 169 | var changed = true 170 | var $parent = this.$element.closest('[data-toggle="buttons"]') 171 | 172 | if ($parent.length) { 173 | var $input = this.$element.find('input') 174 | if ($input.prop('type') == 'radio') { 175 | if ($input.prop('checked')) changed = false 176 | $parent.find('.active').removeClass('active') 177 | this.$element.addClass('active') 178 | } else if ($input.prop('type') == 'checkbox') { 179 | if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false 180 | this.$element.toggleClass('active') 181 | } 182 | $input.prop('checked', this.$element.hasClass('active')) 183 | if (changed) $input.trigger('change') 184 | } else { 185 | this.$element.attr('aria-pressed', !this.$element.hasClass('active')) 186 | this.$element.toggleClass('active') 187 | } 188 | } 189 | 190 | 191 | // BUTTON PLUGIN DEFINITION 192 | // ======================== 193 | 194 | function Plugin(option) { 195 | return this.each(function () { 196 | var $this = $(this) 197 | var data = $this.data('bs.button') 198 | var options = typeof option == 'object' && option 199 | 200 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 201 | 202 | if (option == 'toggle') data.toggle() 203 | else if (option) data.setState(option) 204 | }) 205 | } 206 | 207 | var old = $.fn.button 208 | 209 | $.fn.button = Plugin 210 | $.fn.button.Constructor = Button 211 | 212 | 213 | // BUTTON NO CONFLICT 214 | // ================== 215 | 216 | $.fn.button.noConflict = function () { 217 | $.fn.button = old 218 | return this 219 | } 220 | 221 | 222 | // BUTTON DATA-API 223 | // =============== 224 | 225 | $(document) 226 | .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 227 | var $btn = $(e.target).closest('.btn') 228 | Plugin.call($btn, 'toggle') 229 | if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) { 230 | // Prevent double click on radios, and the double selections (so cancellation) on checkboxes 231 | e.preventDefault() 232 | // The target component still receive the focus 233 | if ($btn.is('input,button')) $btn.trigger('focus') 234 | else $btn.find('input:visible,button:visible').first().trigger('focus') 235 | } 236 | }) 237 | .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { 238 | $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) 239 | }) 240 | 241 | }(jQuery); 242 | 243 | /* ======================================================================== 244 | * Bootstrap: carousel.js v3.3.7 245 | * http://getbootstrap.com/javascript/#carousel 246 | * ======================================================================== 247 | * Copyright 2011-2016 Twitter, Inc. 248 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 249 | * ======================================================================== */ 250 | 251 | 252 | +function ($) { 253 | 'use strict'; 254 | 255 | // CAROUSEL CLASS DEFINITION 256 | // ========================= 257 | 258 | var Carousel = function (element, options) { 259 | this.$element = $(element) 260 | this.$indicators = this.$element.find('.carousel-indicators') 261 | this.options = options 262 | this.paused = null 263 | this.sliding = null 264 | this.interval = null 265 | this.$active = null 266 | this.$items = null 267 | 268 | this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) 269 | 270 | this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element 271 | .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) 272 | .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 273 | } 274 | 275 | Carousel.VERSION = '3.3.7' 276 | 277 | Carousel.TRANSITION_DURATION = 600 278 | 279 | Carousel.DEFAULTS = { 280 | interval: 5000, 281 | pause: 'hover', 282 | wrap: true, 283 | keyboard: true 284 | } 285 | 286 | Carousel.prototype.keydown = function (e) { 287 | if (/input|textarea/i.test(e.target.tagName)) return 288 | switch (e.which) { 289 | case 37: this.prev(); break 290 | case 39: this.next(); break 291 | default: return 292 | } 293 | 294 | e.preventDefault() 295 | } 296 | 297 | Carousel.prototype.cycle = function (e) { 298 | e || (this.paused = false) 299 | 300 | this.interval && clearInterval(this.interval) 301 | 302 | this.options.interval 303 | && !this.paused 304 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 305 | 306 | return this 307 | } 308 | 309 | Carousel.prototype.getItemIndex = function (item) { 310 | this.$items = item.parent().children('.item') 311 | return this.$items.index(item || this.$active) 312 | } 313 | 314 | Carousel.prototype.getItemForDirection = function (direction, active) { 315 | var activeIndex = this.getItemIndex(active) 316 | var willWrap = (direction == 'prev' && activeIndex === 0) 317 | || (direction == 'next' && activeIndex == (this.$items.length - 1)) 318 | if (willWrap && !this.options.wrap) return active 319 | var delta = direction == 'prev' ? -1 : 1 320 | var itemIndex = (activeIndex + delta) % this.$items.length 321 | return this.$items.eq(itemIndex) 322 | } 323 | 324 | Carousel.prototype.to = function (pos) { 325 | var that = this 326 | var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) 327 | 328 | if (pos > (this.$items.length - 1) || pos < 0) return 329 | 330 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" 331 | if (activeIndex == pos) return this.pause().cycle() 332 | 333 | return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) 334 | } 335 | 336 | Carousel.prototype.pause = function (e) { 337 | e || (this.paused = true) 338 | 339 | if (this.$element.find('.next, .prev').length && $.support.transition) { 340 | this.$element.trigger($.support.transition.end) 341 | this.cycle(true) 342 | } 343 | 344 | this.interval = clearInterval(this.interval) 345 | 346 | return this 347 | } 348 | 349 | Carousel.prototype.next = function () { 350 | if (this.sliding) return 351 | return this.slide('next') 352 | } 353 | 354 | Carousel.prototype.prev = function () { 355 | if (this.sliding) return 356 | return this.slide('prev') 357 | } 358 | 359 | Carousel.prototype.slide = function (type, next) { 360 | var $active = this.$element.find('.item.active') 361 | var $next = next || this.getItemForDirection(type, $active) 362 | var isCycling = this.interval 363 | var direction = type == 'next' ? 'left' : 'right' 364 | var that = this 365 | 366 | if ($next.hasClass('active')) return (this.sliding = false) 367 | 368 | var relatedTarget = $next[0] 369 | var slideEvent = $.Event('slide.bs.carousel', { 370 | relatedTarget: relatedTarget, 371 | direction: direction 372 | }) 373 | this.$element.trigger(slideEvent) 374 | if (slideEvent.isDefaultPrevented()) return 375 | 376 | this.sliding = true 377 | 378 | isCycling && this.pause() 379 | 380 | if (this.$indicators.length) { 381 | this.$indicators.find('.active').removeClass('active') 382 | var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) 383 | $nextIndicator && $nextIndicator.addClass('active') 384 | } 385 | 386 | var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 387 | if ($.support.transition && this.$element.hasClass('slide')) { 388 | $next.addClass(type) 389 | $next[0].offsetWidth // force reflow 390 | $active.addClass(direction) 391 | $next.addClass(direction) 392 | $active 393 | .one('bsTransitionEnd', function () { 394 | $next.removeClass([type, direction].join(' ')).addClass('active') 395 | $active.removeClass(['active', direction].join(' ')) 396 | that.sliding = false 397 | setTimeout(function () { 398 | that.$element.trigger(slidEvent) 399 | }, 0) 400 | }) 401 | .emulateTransitionEnd(Carousel.TRANSITION_DURATION) 402 | } else { 403 | $active.removeClass('active') 404 | $next.addClass('active') 405 | this.sliding = false 406 | this.$element.trigger(slidEvent) 407 | } 408 | 409 | isCycling && this.cycle() 410 | 411 | return this 412 | } 413 | 414 | 415 | // CAROUSEL PLUGIN DEFINITION 416 | // ========================== 417 | 418 | function Plugin(option) { 419 | return this.each(function () { 420 | var $this = $(this) 421 | var data = $this.data('bs.carousel') 422 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 423 | var action = typeof option == 'string' ? option : options.slide 424 | 425 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 426 | if (typeof option == 'number') data.to(option) 427 | else if (action) data[action]() 428 | else if (options.interval) data.pause().cycle() 429 | }) 430 | } 431 | 432 | var old = $.fn.carousel 433 | 434 | $.fn.carousel = Plugin 435 | $.fn.carousel.Constructor = Carousel 436 | 437 | 438 | // CAROUSEL NO CONFLICT 439 | // ==================== 440 | 441 | $.fn.carousel.noConflict = function () { 442 | $.fn.carousel = old 443 | return this 444 | } 445 | 446 | 447 | // CAROUSEL DATA-API 448 | // ================= 449 | 450 | var clickHandler = function (e) { 451 | var href 452 | var $this = $(this) 453 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 454 | if (!$target.hasClass('carousel')) return 455 | var options = $.extend({}, $target.data(), $this.data()) 456 | var slideIndex = $this.attr('data-slide-to') 457 | if (slideIndex) options.interval = false 458 | 459 | Plugin.call($target, options) 460 | 461 | if (slideIndex) { 462 | $target.data('bs.carousel').to(slideIndex) 463 | } 464 | 465 | e.preventDefault() 466 | } 467 | 468 | $(document) 469 | .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) 470 | .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) 471 | 472 | $(window).on('load', function () { 473 | $('[data-ride="carousel"]').each(function () { 474 | var $carousel = $(this) 475 | Plugin.call($carousel, $carousel.data()) 476 | }) 477 | }) 478 | 479 | }(jQuery); 480 | 481 | /* ======================================================================== 482 | * Bootstrap: dropdown.js v3.3.7 483 | * http://getbootstrap.com/javascript/#dropdowns 484 | * ======================================================================== 485 | * Copyright 2011-2016 Twitter, Inc. 486 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 487 | * ======================================================================== */ 488 | 489 | 490 | +function ($) { 491 | 'use strict'; 492 | 493 | // DROPDOWN CLASS DEFINITION 494 | // ========================= 495 | 496 | var backdrop = '.dropdown-backdrop' 497 | var toggle = '[data-toggle="dropdown"]' 498 | var Dropdown = function (element) { 499 | $(element).on('click.bs.dropdown', this.toggle) 500 | } 501 | 502 | Dropdown.VERSION = '3.3.7' 503 | 504 | function getParent($this) { 505 | var selector = $this.attr('data-target') 506 | 507 | if (!selector) { 508 | selector = $this.attr('href') 509 | selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 510 | } 511 | 512 | var $parent = selector && $(selector) 513 | 514 | return $parent && $parent.length ? $parent : $this.parent() 515 | } 516 | 517 | function clearMenus(e) { 518 | if (e && e.which === 3) return 519 | $(backdrop).remove() 520 | $(toggle).each(function () { 521 | var $this = $(this) 522 | var $parent = getParent($this) 523 | var relatedTarget = { relatedTarget: this } 524 | 525 | if (!$parent.hasClass('open')) return 526 | 527 | if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return 528 | 529 | $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) 530 | 531 | if (e.isDefaultPrevented()) return 532 | 533 | $this.attr('aria-expanded', 'false') 534 | $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget)) 535 | }) 536 | } 537 | 538 | Dropdown.prototype.toggle = function (e) { 539 | var $this = $(this) 540 | 541 | if ($this.is('.disabled, :disabled')) return 542 | 543 | var $parent = getParent($this) 544 | var isActive = $parent.hasClass('open') 545 | 546 | clearMenus() 547 | 548 | if (!isActive) { 549 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 550 | // if mobile we use a backdrop because click events don't delegate 551 | $(document.createElement('div')) 552 | .addClass('dropdown-backdrop') 553 | .insertAfter($(this)) 554 | .on('click', clearMenus) 555 | } 556 | 557 | var relatedTarget = { relatedTarget: this } 558 | $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) 559 | 560 | if (e.isDefaultPrevented()) return 561 | 562 | $this 563 | .trigger('focus') 564 | .attr('aria-expanded', 'true') 565 | 566 | $parent 567 | .toggleClass('open') 568 | .trigger($.Event('shown.bs.dropdown', relatedTarget)) 569 | } 570 | 571 | return false 572 | } 573 | 574 | Dropdown.prototype.keydown = function (e) { 575 | if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return 576 | 577 | var $this = $(this) 578 | 579 | e.preventDefault() 580 | e.stopPropagation() 581 | 582 | if ($this.is('.disabled, :disabled')) return 583 | 584 | var $parent = getParent($this) 585 | var isActive = $parent.hasClass('open') 586 | 587 | if (!isActive && e.which != 27 || isActive && e.which == 27) { 588 | if (e.which == 27) $parent.find(toggle).trigger('focus') 589 | return $this.trigger('click') 590 | } 591 | 592 | var desc = ' li:not(.disabled):visible a' 593 | var $items = $parent.find('.dropdown-menu' + desc) 594 | 595 | if (!$items.length) return 596 | 597 | var index = $items.index(e.target) 598 | 599 | if (e.which == 38 && index > 0) index-- // up 600 | if (e.which == 40 && index < $items.length - 1) index++ // down 601 | if (!~index) index = 0 602 | 603 | $items.eq(index).trigger('focus') 604 | } 605 | 606 | 607 | // DROPDOWN PLUGIN DEFINITION 608 | // ========================== 609 | 610 | function Plugin(option) { 611 | return this.each(function () { 612 | var $this = $(this) 613 | var data = $this.data('bs.dropdown') 614 | 615 | if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) 616 | if (typeof option == 'string') data[option].call($this) 617 | }) 618 | } 619 | 620 | var old = $.fn.dropdown 621 | 622 | $.fn.dropdown = Plugin 623 | $.fn.dropdown.Constructor = Dropdown 624 | 625 | 626 | // DROPDOWN NO CONFLICT 627 | // ==================== 628 | 629 | $.fn.dropdown.noConflict = function () { 630 | $.fn.dropdown = old 631 | return this 632 | } 633 | 634 | 635 | // APPLY TO STANDARD DROPDOWN ELEMENTS 636 | // =================================== 637 | 638 | $(document) 639 | .on('click.bs.dropdown.data-api', clearMenus) 640 | .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) 641 | .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) 642 | .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) 643 | .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) 644 | 645 | }(jQuery); 646 | 647 | /* ======================================================================== 648 | * Bootstrap: modal.js v3.3.7 649 | * http://getbootstrap.com/javascript/#modals 650 | * ======================================================================== 651 | * Copyright 2011-2016 Twitter, Inc. 652 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 653 | * ======================================================================== */ 654 | 655 | 656 | +function ($) { 657 | 'use strict'; 658 | 659 | // MODAL CLASS DEFINITION 660 | // ====================== 661 | 662 | var Modal = function (element, options) { 663 | this.options = options 664 | this.$body = $(document.body) 665 | this.$element = $(element) 666 | this.$dialog = this.$element.find('.modal-dialog') 667 | this.$backdrop = null 668 | this.isShown = null 669 | this.originalBodyPad = null 670 | this.scrollbarWidth = 0 671 | this.ignoreBackdropClick = false 672 | 673 | if (this.options.remote) { 674 | this.$element 675 | .find('.modal-content') 676 | .load(this.options.remote, $.proxy(function () { 677 | this.$element.trigger('loaded.bs.modal') 678 | }, this)) 679 | } 680 | } 681 | 682 | Modal.VERSION = '3.3.7' 683 | 684 | Modal.TRANSITION_DURATION = 300 685 | Modal.BACKDROP_TRANSITION_DURATION = 150 686 | 687 | Modal.DEFAULTS = { 688 | backdrop: true, 689 | keyboard: true, 690 | show: true 691 | } 692 | 693 | Modal.prototype.toggle = function (_relatedTarget) { 694 | return this.isShown ? this.hide() : this.show(_relatedTarget) 695 | } 696 | 697 | Modal.prototype.show = function (_relatedTarget) { 698 | var that = this 699 | var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 700 | 701 | this.$element.trigger(e) 702 | 703 | if (this.isShown || e.isDefaultPrevented()) return 704 | 705 | this.isShown = true 706 | 707 | this.checkScrollbar() 708 | this.setScrollbar() 709 | this.$body.addClass('modal-open') 710 | 711 | this.escape() 712 | this.resize() 713 | 714 | this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) 715 | 716 | this.$dialog.on('mousedown.dismiss.bs.modal', function () { 717 | that.$element.one('mouseup.dismiss.bs.modal', function (e) { 718 | if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true 719 | }) 720 | }) 721 | 722 | this.backdrop(function () { 723 | var transition = $.support.transition && that.$element.hasClass('fade') 724 | 725 | if (!that.$element.parent().length) { 726 | that.$element.appendTo(that.$body) // don't move modals dom position 727 | } 728 | 729 | that.$element 730 | .show() 731 | .scrollTop(0) 732 | 733 | that.adjustDialog() 734 | 735 | if (transition) { 736 | that.$element[0].offsetWidth // force reflow 737 | } 738 | 739 | that.$element.addClass('in') 740 | 741 | that.enforceFocus() 742 | 743 | var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) 744 | 745 | transition ? 746 | that.$dialog // wait for modal to slide in 747 | .one('bsTransitionEnd', function () { 748 | that.$element.trigger('focus').trigger(e) 749 | }) 750 | .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 751 | that.$element.trigger('focus').trigger(e) 752 | }) 753 | } 754 | 755 | Modal.prototype.hide = function (e) { 756 | if (e) e.preventDefault() 757 | 758 | e = $.Event('hide.bs.modal') 759 | 760 | this.$element.trigger(e) 761 | 762 | if (!this.isShown || e.isDefaultPrevented()) return 763 | 764 | this.isShown = false 765 | 766 | this.escape() 767 | this.resize() 768 | 769 | $(document).off('focusin.bs.modal') 770 | 771 | this.$element 772 | .removeClass('in') 773 | .off('click.dismiss.bs.modal') 774 | .off('mouseup.dismiss.bs.modal') 775 | 776 | this.$dialog.off('mousedown.dismiss.bs.modal') 777 | 778 | $.support.transition && this.$element.hasClass('fade') ? 779 | this.$element 780 | .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 781 | .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 782 | this.hideModal() 783 | } 784 | 785 | Modal.prototype.enforceFocus = function () { 786 | $(document) 787 | .off('focusin.bs.modal') // guard against infinite focus loop 788 | .on('focusin.bs.modal', $.proxy(function (e) { 789 | if (document !== e.target && 790 | this.$element[0] !== e.target && 791 | !this.$element.has(e.target).length) { 792 | this.$element.trigger('focus') 793 | } 794 | }, this)) 795 | } 796 | 797 | Modal.prototype.escape = function () { 798 | if (this.isShown && this.options.keyboard) { 799 | this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { 800 | e.which == 27 && this.hide() 801 | }, this)) 802 | } else if (!this.isShown) { 803 | this.$element.off('keydown.dismiss.bs.modal') 804 | } 805 | } 806 | 807 | Modal.prototype.resize = function () { 808 | if (this.isShown) { 809 | $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) 810 | } else { 811 | $(window).off('resize.bs.modal') 812 | } 813 | } 814 | 815 | Modal.prototype.hideModal = function () { 816 | var that = this 817 | this.$element.hide() 818 | this.backdrop(function () { 819 | that.$body.removeClass('modal-open') 820 | that.resetAdjustments() 821 | that.resetScrollbar() 822 | that.$element.trigger('hidden.bs.modal') 823 | }) 824 | } 825 | 826 | Modal.prototype.removeBackdrop = function () { 827 | this.$backdrop && this.$backdrop.remove() 828 | this.$backdrop = null 829 | } 830 | 831 | Modal.prototype.backdrop = function (callback) { 832 | var that = this 833 | var animate = this.$element.hasClass('fade') ? 'fade' : '' 834 | 835 | if (this.isShown && this.options.backdrop) { 836 | var doAnimate = $.support.transition && animate 837 | 838 | this.$backdrop = $(document.createElement('div')) 839 | .addClass('modal-backdrop ' + animate) 840 | .appendTo(this.$body) 841 | 842 | this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { 843 | if (this.ignoreBackdropClick) { 844 | this.ignoreBackdropClick = false 845 | return 846 | } 847 | if (e.target !== e.currentTarget) return 848 | this.options.backdrop == 'static' 849 | ? this.$element[0].focus() 850 | : this.hide() 851 | }, this)) 852 | 853 | if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 854 | 855 | this.$backdrop.addClass('in') 856 | 857 | if (!callback) return 858 | 859 | doAnimate ? 860 | this.$backdrop 861 | .one('bsTransitionEnd', callback) 862 | .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 863 | callback() 864 | 865 | } else if (!this.isShown && this.$backdrop) { 866 | this.$backdrop.removeClass('in') 867 | 868 | var callbackRemove = function () { 869 | that.removeBackdrop() 870 | callback && callback() 871 | } 872 | $.support.transition && this.$element.hasClass('fade') ? 873 | this.$backdrop 874 | .one('bsTransitionEnd', callbackRemove) 875 | .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 876 | callbackRemove() 877 | 878 | } else if (callback) { 879 | callback() 880 | } 881 | } 882 | 883 | // these following methods are used to handle overflowing modals 884 | 885 | Modal.prototype.handleUpdate = function () { 886 | this.adjustDialog() 887 | } 888 | 889 | Modal.prototype.adjustDialog = function () { 890 | var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight 891 | 892 | this.$element.css({ 893 | paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', 894 | paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' 895 | }) 896 | } 897 | 898 | Modal.prototype.resetAdjustments = function () { 899 | this.$element.css({ 900 | paddingLeft: '', 901 | paddingRight: '' 902 | }) 903 | } 904 | 905 | Modal.prototype.checkScrollbar = function () { 906 | var fullWindowWidth = window.innerWidth 907 | if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 908 | var documentElementRect = document.documentElement.getBoundingClientRect() 909 | fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) 910 | } 911 | this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth 912 | this.scrollbarWidth = this.measureScrollbar() 913 | } 914 | 915 | Modal.prototype.setScrollbar = function () { 916 | var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) 917 | this.originalBodyPad = document.body.style.paddingRight || '' 918 | if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) 919 | } 920 | 921 | Modal.prototype.resetScrollbar = function () { 922 | this.$body.css('padding-right', this.originalBodyPad) 923 | } 924 | 925 | Modal.prototype.measureScrollbar = function () { // thx walsh 926 | var scrollDiv = document.createElement('div') 927 | scrollDiv.className = 'modal-scrollbar-measure' 928 | this.$body.append(scrollDiv) 929 | var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth 930 | this.$body[0].removeChild(scrollDiv) 931 | return scrollbarWidth 932 | } 933 | 934 | 935 | // MODAL PLUGIN DEFINITION 936 | // ======================= 937 | 938 | function Plugin(option, _relatedTarget) { 939 | return this.each(function () { 940 | var $this = $(this) 941 | var data = $this.data('bs.modal') 942 | var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 943 | 944 | if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 945 | if (typeof option == 'string') data[option](_relatedTarget) 946 | else if (options.show) data.show(_relatedTarget) 947 | }) 948 | } 949 | 950 | var old = $.fn.modal 951 | 952 | $.fn.modal = Plugin 953 | $.fn.modal.Constructor = Modal 954 | 955 | 956 | // MODAL NO CONFLICT 957 | // ================= 958 | 959 | $.fn.modal.noConflict = function () { 960 | $.fn.modal = old 961 | return this 962 | } 963 | 964 | 965 | // MODAL DATA-API 966 | // ============== 967 | 968 | $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 969 | var $this = $(this) 970 | var href = $this.attr('href') 971 | var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 972 | var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 973 | 974 | if ($this.is('a')) e.preventDefault() 975 | 976 | $target.one('show.bs.modal', function (showEvent) { 977 | if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown 978 | $target.one('hidden.bs.modal', function () { 979 | $this.is(':visible') && $this.trigger('focus') 980 | }) 981 | }) 982 | Plugin.call($target, option, this) 983 | }) 984 | 985 | }(jQuery); 986 | 987 | /* ======================================================================== 988 | * Bootstrap: tooltip.js v3.3.7 989 | * http://getbootstrap.com/javascript/#tooltip 990 | * Inspired by the original jQuery.tipsy by Jason Frame 991 | * ======================================================================== 992 | * Copyright 2011-2016 Twitter, Inc. 993 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 994 | * ======================================================================== */ 995 | 996 | 997 | +function ($) { 998 | 'use strict'; 999 | 1000 | // TOOLTIP PUBLIC CLASS DEFINITION 1001 | // =============================== 1002 | 1003 | var Tooltip = function (element, options) { 1004 | this.type = null 1005 | this.options = null 1006 | this.enabled = null 1007 | this.timeout = null 1008 | this.hoverState = null 1009 | this.$element = null 1010 | this.inState = null 1011 | 1012 | this.init('tooltip', element, options) 1013 | } 1014 | 1015 | Tooltip.VERSION = '3.3.7' 1016 | 1017 | Tooltip.TRANSITION_DURATION = 150 1018 | 1019 | Tooltip.DEFAULTS = { 1020 | animation: true, 1021 | placement: 'top', 1022 | selector: false, 1023 | template: '', 1024 | trigger: 'hover focus', 1025 | title: '', 1026 | delay: 0, 1027 | html: false, 1028 | container: false, 1029 | viewport: { 1030 | selector: 'body', 1031 | padding: 0 1032 | } 1033 | } 1034 | 1035 | Tooltip.prototype.init = function (type, element, options) { 1036 | this.enabled = true 1037 | this.type = type 1038 | this.$element = $(element) 1039 | this.options = this.getOptions(options) 1040 | this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) 1041 | this.inState = { click: false, hover: false, focus: false } 1042 | 1043 | if (this.$element[0] instanceof document.constructor && !this.options.selector) { 1044 | throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!') 1045 | } 1046 | 1047 | var triggers = this.options.trigger.split(' ') 1048 | 1049 | for (var i = triggers.length; i--;) { 1050 | var trigger = triggers[i] 1051 | 1052 | if (trigger == 'click') { 1053 | this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 1054 | } else if (trigger != 'manual') { 1055 | var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 1056 | var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 1057 | 1058 | this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 1059 | this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 1060 | } 1061 | } 1062 | 1063 | this.options.selector ? 1064 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 1065 | this.fixTitle() 1066 | } 1067 | 1068 | Tooltip.prototype.getDefaults = function () { 1069 | return Tooltip.DEFAULTS 1070 | } 1071 | 1072 | Tooltip.prototype.getOptions = function (options) { 1073 | options = $.extend({}, this.getDefaults(), this.$element.data(), options) 1074 | 1075 | if (options.delay && typeof options.delay == 'number') { 1076 | options.delay = { 1077 | show: options.delay, 1078 | hide: options.delay 1079 | } 1080 | } 1081 | 1082 | return options 1083 | } 1084 | 1085 | Tooltip.prototype.getDelegateOptions = function () { 1086 | var options = {} 1087 | var defaults = this.getDefaults() 1088 | 1089 | this._options && $.each(this._options, function (key, value) { 1090 | if (defaults[key] != value) options[key] = value 1091 | }) 1092 | 1093 | return options 1094 | } 1095 | 1096 | Tooltip.prototype.enter = function (obj) { 1097 | var self = obj instanceof this.constructor ? 1098 | obj : $(obj.currentTarget).data('bs.' + this.type) 1099 | 1100 | if (!self) { 1101 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 1102 | $(obj.currentTarget).data('bs.' + this.type, self) 1103 | } 1104 | 1105 | if (obj instanceof $.Event) { 1106 | self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true 1107 | } 1108 | 1109 | if (self.tip().hasClass('in') || self.hoverState == 'in') { 1110 | self.hoverState = 'in' 1111 | return 1112 | } 1113 | 1114 | clearTimeout(self.timeout) 1115 | 1116 | self.hoverState = 'in' 1117 | 1118 | if (!self.options.delay || !self.options.delay.show) return self.show() 1119 | 1120 | self.timeout = setTimeout(function () { 1121 | if (self.hoverState == 'in') self.show() 1122 | }, self.options.delay.show) 1123 | } 1124 | 1125 | Tooltip.prototype.isInStateTrue = function () { 1126 | for (var key in this.inState) { 1127 | if (this.inState[key]) return true 1128 | } 1129 | 1130 | return false 1131 | } 1132 | 1133 | Tooltip.prototype.leave = function (obj) { 1134 | var self = obj instanceof this.constructor ? 1135 | obj : $(obj.currentTarget).data('bs.' + this.type) 1136 | 1137 | if (!self) { 1138 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 1139 | $(obj.currentTarget).data('bs.' + this.type, self) 1140 | } 1141 | 1142 | if (obj instanceof $.Event) { 1143 | self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false 1144 | } 1145 | 1146 | if (self.isInStateTrue()) return 1147 | 1148 | clearTimeout(self.timeout) 1149 | 1150 | self.hoverState = 'out' 1151 | 1152 | if (!self.options.delay || !self.options.delay.hide) return self.hide() 1153 | 1154 | self.timeout = setTimeout(function () { 1155 | if (self.hoverState == 'out') self.hide() 1156 | }, self.options.delay.hide) 1157 | } 1158 | 1159 | Tooltip.prototype.show = function () { 1160 | var e = $.Event('show.bs.' + this.type) 1161 | 1162 | if (this.hasContent() && this.enabled) { 1163 | this.$element.trigger(e) 1164 | 1165 | var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) 1166 | if (e.isDefaultPrevented() || !inDom) return 1167 | var that = this 1168 | 1169 | var $tip = this.tip() 1170 | 1171 | var tipId = this.getUID(this.type) 1172 | 1173 | this.setContent() 1174 | $tip.attr('id', tipId) 1175 | this.$element.attr('aria-describedby', tipId) 1176 | 1177 | if (this.options.animation) $tip.addClass('fade') 1178 | 1179 | var placement = typeof this.options.placement == 'function' ? 1180 | this.options.placement.call(this, $tip[0], this.$element[0]) : 1181 | this.options.placement 1182 | 1183 | var autoToken = /\s?auto?\s?/i 1184 | var autoPlace = autoToken.test(placement) 1185 | if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 1186 | 1187 | $tip 1188 | .detach() 1189 | .css({ top: 0, left: 0, display: 'block' }) 1190 | .addClass(placement) 1191 | .data('bs.' + this.type, this) 1192 | 1193 | this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 1194 | this.$element.trigger('inserted.bs.' + this.type) 1195 | 1196 | var pos = this.getPosition() 1197 | var actualWidth = $tip[0].offsetWidth 1198 | var actualHeight = $tip[0].offsetHeight 1199 | 1200 | if (autoPlace) { 1201 | var orgPlacement = placement 1202 | var viewportDim = this.getPosition(this.$viewport) 1203 | 1204 | placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' : 1205 | placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' : 1206 | placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' : 1207 | placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' : 1208 | placement 1209 | 1210 | $tip 1211 | .removeClass(orgPlacement) 1212 | .addClass(placement) 1213 | } 1214 | 1215 | var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 1216 | 1217 | this.applyPlacement(calculatedOffset, placement) 1218 | 1219 | var complete = function () { 1220 | var prevHoverState = that.hoverState 1221 | that.$element.trigger('shown.bs.' + that.type) 1222 | that.hoverState = null 1223 | 1224 | if (prevHoverState == 'out') that.leave(that) 1225 | } 1226 | 1227 | $.support.transition && this.$tip.hasClass('fade') ? 1228 | $tip 1229 | .one('bsTransitionEnd', complete) 1230 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 1231 | complete() 1232 | } 1233 | } 1234 | 1235 | Tooltip.prototype.applyPlacement = function (offset, placement) { 1236 | var $tip = this.tip() 1237 | var width = $tip[0].offsetWidth 1238 | var height = $tip[0].offsetHeight 1239 | 1240 | // manually read margins because getBoundingClientRect includes difference 1241 | var marginTop = parseInt($tip.css('margin-top'), 10) 1242 | var marginLeft = parseInt($tip.css('margin-left'), 10) 1243 | 1244 | // we must check for NaN for ie 8/9 1245 | if (isNaN(marginTop)) marginTop = 0 1246 | if (isNaN(marginLeft)) marginLeft = 0 1247 | 1248 | offset.top += marginTop 1249 | offset.left += marginLeft 1250 | 1251 | // $.fn.offset doesn't round pixel values 1252 | // so we use setOffset directly with our own function B-0 1253 | $.offset.setOffset($tip[0], $.extend({ 1254 | using: function (props) { 1255 | $tip.css({ 1256 | top: Math.round(props.top), 1257 | left: Math.round(props.left) 1258 | }) 1259 | } 1260 | }, offset), 0) 1261 | 1262 | $tip.addClass('in') 1263 | 1264 | // check to see if placing tip in new offset caused the tip to resize itself 1265 | var actualWidth = $tip[0].offsetWidth 1266 | var actualHeight = $tip[0].offsetHeight 1267 | 1268 | if (placement == 'top' && actualHeight != height) { 1269 | offset.top = offset.top + height - actualHeight 1270 | } 1271 | 1272 | var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 1273 | 1274 | if (delta.left) offset.left += delta.left 1275 | else offset.top += delta.top 1276 | 1277 | var isVertical = /top|bottom/.test(placement) 1278 | var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 1279 | var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' 1280 | 1281 | $tip.offset(offset) 1282 | this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) 1283 | } 1284 | 1285 | Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { 1286 | this.arrow() 1287 | .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') 1288 | .css(isVertical ? 'top' : 'left', '') 1289 | } 1290 | 1291 | Tooltip.prototype.setContent = function () { 1292 | var $tip = this.tip() 1293 | var title = this.getTitle() 1294 | 1295 | $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 1296 | $tip.removeClass('fade in top bottom left right') 1297 | } 1298 | 1299 | Tooltip.prototype.hide = function (callback) { 1300 | var that = this 1301 | var $tip = $(this.$tip) 1302 | var e = $.Event('hide.bs.' + this.type) 1303 | 1304 | function complete() { 1305 | if (that.hoverState != 'in') $tip.detach() 1306 | if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary. 1307 | that.$element 1308 | .removeAttr('aria-describedby') 1309 | .trigger('hidden.bs.' + that.type) 1310 | } 1311 | callback && callback() 1312 | } 1313 | 1314 | this.$element.trigger(e) 1315 | 1316 | if (e.isDefaultPrevented()) return 1317 | 1318 | $tip.removeClass('in') 1319 | 1320 | $.support.transition && $tip.hasClass('fade') ? 1321 | $tip 1322 | .one('bsTransitionEnd', complete) 1323 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 1324 | complete() 1325 | 1326 | this.hoverState = null 1327 | 1328 | return this 1329 | } 1330 | 1331 | Tooltip.prototype.fixTitle = function () { 1332 | var $e = this.$element 1333 | if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { 1334 | $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 1335 | } 1336 | } 1337 | 1338 | Tooltip.prototype.hasContent = function () { 1339 | return this.getTitle() 1340 | } 1341 | 1342 | Tooltip.prototype.getPosition = function ($element) { 1343 | $element = $element || this.$element 1344 | 1345 | var el = $element[0] 1346 | var isBody = el.tagName == 'BODY' 1347 | 1348 | var elRect = el.getBoundingClientRect() 1349 | if (elRect.width == null) { 1350 | // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 1351 | elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) 1352 | } 1353 | var isSvg = window.SVGElement && el instanceof window.SVGElement 1354 | // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3. 1355 | // See https://github.com/twbs/bootstrap/issues/20280 1356 | var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset()) 1357 | var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } 1358 | var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null 1359 | 1360 | return $.extend({}, elRect, scroll, outerDims, elOffset) 1361 | } 1362 | 1363 | Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 1364 | return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 1365 | placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 1366 | placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 1367 | /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 1368 | 1369 | } 1370 | 1371 | Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 1372 | var delta = { top: 0, left: 0 } 1373 | if (!this.$viewport) return delta 1374 | 1375 | var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 1376 | var viewportDimensions = this.getPosition(this.$viewport) 1377 | 1378 | if (/right|left/.test(placement)) { 1379 | var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 1380 | var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 1381 | if (topEdgeOffset < viewportDimensions.top) { // top overflow 1382 | delta.top = viewportDimensions.top - topEdgeOffset 1383 | } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 1384 | delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset 1385 | } 1386 | } else { 1387 | var leftEdgeOffset = pos.left - viewportPadding 1388 | var rightEdgeOffset = pos.left + viewportPadding + actualWidth 1389 | if (leftEdgeOffset < viewportDimensions.left) { // left overflow 1390 | delta.left = viewportDimensions.left - leftEdgeOffset 1391 | } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow 1392 | delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 1393 | } 1394 | } 1395 | 1396 | return delta 1397 | } 1398 | 1399 | Tooltip.prototype.getTitle = function () { 1400 | var title 1401 | var $e = this.$element 1402 | var o = this.options 1403 | 1404 | title = $e.attr('data-original-title') 1405 | || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 1406 | 1407 | return title 1408 | } 1409 | 1410 | Tooltip.prototype.getUID = function (prefix) { 1411 | do prefix += ~~(Math.random() * 1000000) 1412 | while (document.getElementById(prefix)) 1413 | return prefix 1414 | } 1415 | 1416 | Tooltip.prototype.tip = function () { 1417 | if (!this.$tip) { 1418 | this.$tip = $(this.options.template) 1419 | if (this.$tip.length != 1) { 1420 | throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') 1421 | } 1422 | } 1423 | return this.$tip 1424 | } 1425 | 1426 | Tooltip.prototype.arrow = function () { 1427 | return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) 1428 | } 1429 | 1430 | Tooltip.prototype.enable = function () { 1431 | this.enabled = true 1432 | } 1433 | 1434 | Tooltip.prototype.disable = function () { 1435 | this.enabled = false 1436 | } 1437 | 1438 | Tooltip.prototype.toggleEnabled = function () { 1439 | this.enabled = !this.enabled 1440 | } 1441 | 1442 | Tooltip.prototype.toggle = function (e) { 1443 | var self = this 1444 | if (e) { 1445 | self = $(e.currentTarget).data('bs.' + this.type) 1446 | if (!self) { 1447 | self = new this.constructor(e.currentTarget, this.getDelegateOptions()) 1448 | $(e.currentTarget).data('bs.' + this.type, self) 1449 | } 1450 | } 1451 | 1452 | if (e) { 1453 | self.inState.click = !self.inState.click 1454 | if (self.isInStateTrue()) self.enter(self) 1455 | else self.leave(self) 1456 | } else { 1457 | self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 1458 | } 1459 | } 1460 | 1461 | Tooltip.prototype.destroy = function () { 1462 | var that = this 1463 | clearTimeout(this.timeout) 1464 | this.hide(function () { 1465 | that.$element.off('.' + that.type).removeData('bs.' + that.type) 1466 | if (that.$tip) { 1467 | that.$tip.detach() 1468 | } 1469 | that.$tip = null 1470 | that.$arrow = null 1471 | that.$viewport = null 1472 | that.$element = null 1473 | }) 1474 | } 1475 | 1476 | 1477 | // TOOLTIP PLUGIN DEFINITION 1478 | // ========================= 1479 | 1480 | function Plugin(option) { 1481 | return this.each(function () { 1482 | var $this = $(this) 1483 | var data = $this.data('bs.tooltip') 1484 | var options = typeof option == 'object' && option 1485 | 1486 | if (!data && /destroy|hide/.test(option)) return 1487 | if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 1488 | if (typeof option == 'string') data[option]() 1489 | }) 1490 | } 1491 | 1492 | var old = $.fn.tooltip 1493 | 1494 | $.fn.tooltip = Plugin 1495 | $.fn.tooltip.Constructor = Tooltip 1496 | 1497 | 1498 | // TOOLTIP NO CONFLICT 1499 | // =================== 1500 | 1501 | $.fn.tooltip.noConflict = function () { 1502 | $.fn.tooltip = old 1503 | return this 1504 | } 1505 | 1506 | }(jQuery); 1507 | 1508 | /* ======================================================================== 1509 | * Bootstrap: popover.js v3.3.7 1510 | * http://getbootstrap.com/javascript/#popovers 1511 | * ======================================================================== 1512 | * Copyright 2011-2016 Twitter, Inc. 1513 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1514 | * ======================================================================== */ 1515 | 1516 | 1517 | +function ($) { 1518 | 'use strict'; 1519 | 1520 | // POPOVER PUBLIC CLASS DEFINITION 1521 | // =============================== 1522 | 1523 | var Popover = function (element, options) { 1524 | this.init('popover', element, options) 1525 | } 1526 | 1527 | if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 1528 | 1529 | Popover.VERSION = '3.3.7' 1530 | 1531 | Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { 1532 | placement: 'right', 1533 | trigger: 'click', 1534 | content: '', 1535 | template: '' 1536 | }) 1537 | 1538 | 1539 | // NOTE: POPOVER EXTENDS tooltip.js 1540 | // ================================ 1541 | 1542 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) 1543 | 1544 | Popover.prototype.constructor = Popover 1545 | 1546 | Popover.prototype.getDefaults = function () { 1547 | return Popover.DEFAULTS 1548 | } 1549 | 1550 | Popover.prototype.setContent = function () { 1551 | var $tip = this.tip() 1552 | var title = this.getTitle() 1553 | var content = this.getContent() 1554 | 1555 | $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 1556 | $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events 1557 | this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' 1558 | ](content) 1559 | 1560 | $tip.removeClass('fade top bottom left right in') 1561 | 1562 | // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do 1563 | // this manually by checking the contents. 1564 | if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() 1565 | } 1566 | 1567 | Popover.prototype.hasContent = function () { 1568 | return this.getTitle() || this.getContent() 1569 | } 1570 | 1571 | Popover.prototype.getContent = function () { 1572 | var $e = this.$element 1573 | var o = this.options 1574 | 1575 | return $e.attr('data-content') 1576 | || (typeof o.content == 'function' ? 1577 | o.content.call($e[0]) : 1578 | o.content) 1579 | } 1580 | 1581 | Popover.prototype.arrow = function () { 1582 | return (this.$arrow = this.$arrow || this.tip().find('.arrow')) 1583 | } 1584 | 1585 | 1586 | // POPOVER PLUGIN DEFINITION 1587 | // ========================= 1588 | 1589 | function Plugin(option) { 1590 | return this.each(function () { 1591 | var $this = $(this) 1592 | var data = $this.data('bs.popover') 1593 | var options = typeof option == 'object' && option 1594 | 1595 | if (!data && /destroy|hide/.test(option)) return 1596 | if (!data) $this.data('bs.popover', (data = new Popover(this, options))) 1597 | if (typeof option == 'string') data[option]() 1598 | }) 1599 | } 1600 | 1601 | var old = $.fn.popover 1602 | 1603 | $.fn.popover = Plugin 1604 | $.fn.popover.Constructor = Popover 1605 | 1606 | 1607 | // POPOVER NO CONFLICT 1608 | // =================== 1609 | 1610 | $.fn.popover.noConflict = function () { 1611 | $.fn.popover = old 1612 | return this 1613 | } 1614 | 1615 | }(jQuery); 1616 | 1617 | /* ======================================================================== 1618 | * Bootstrap: tab.js v3.3.7 1619 | * http://getbootstrap.com/javascript/#tabs 1620 | * ======================================================================== 1621 | * Copyright 2011-2016 Twitter, Inc. 1622 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1623 | * ======================================================================== */ 1624 | 1625 | 1626 | +function ($) { 1627 | 'use strict'; 1628 | 1629 | // TAB CLASS DEFINITION 1630 | // ==================== 1631 | 1632 | var Tab = function (element) { 1633 | // jscs:disable requireDollarBeforejQueryAssignment 1634 | this.element = $(element) 1635 | // jscs:enable requireDollarBeforejQueryAssignment 1636 | } 1637 | 1638 | Tab.VERSION = '3.3.7' 1639 | 1640 | Tab.TRANSITION_DURATION = 150 1641 | 1642 | Tab.prototype.show = function () { 1643 | var $this = this.element 1644 | var $ul = $this.closest('ul:not(.dropdown-menu)') 1645 | var selector = $this.data('target') 1646 | 1647 | if (!selector) { 1648 | selector = $this.attr('href') 1649 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 1650 | } 1651 | 1652 | if ($this.parent('li').hasClass('active')) return 1653 | 1654 | var $previous = $ul.find('.active:last a') 1655 | var hideEvent = $.Event('hide.bs.tab', { 1656 | relatedTarget: $this[0] 1657 | }) 1658 | var showEvent = $.Event('show.bs.tab', { 1659 | relatedTarget: $previous[0] 1660 | }) 1661 | 1662 | $previous.trigger(hideEvent) 1663 | $this.trigger(showEvent) 1664 | 1665 | if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return 1666 | 1667 | var $target = $(selector) 1668 | 1669 | this.activate($this.closest('li'), $ul) 1670 | this.activate($target, $target.parent(), function () { 1671 | $previous.trigger({ 1672 | type: 'hidden.bs.tab', 1673 | relatedTarget: $this[0] 1674 | }) 1675 | $this.trigger({ 1676 | type: 'shown.bs.tab', 1677 | relatedTarget: $previous[0] 1678 | }) 1679 | }) 1680 | } 1681 | 1682 | Tab.prototype.activate = function (element, container, callback) { 1683 | var $active = container.find('> .active') 1684 | var transition = callback 1685 | && $.support.transition 1686 | && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length) 1687 | 1688 | function next() { 1689 | $active 1690 | .removeClass('active') 1691 | .find('> .dropdown-menu > .active') 1692 | .removeClass('active') 1693 | .end() 1694 | .find('[data-toggle="tab"]') 1695 | .attr('aria-expanded', false) 1696 | 1697 | element 1698 | .addClass('active') 1699 | .find('[data-toggle="tab"]') 1700 | .attr('aria-expanded', true) 1701 | 1702 | if (transition) { 1703 | element[0].offsetWidth // reflow for transition 1704 | element.addClass('in') 1705 | } else { 1706 | element.removeClass('fade') 1707 | } 1708 | 1709 | if (element.parent('.dropdown-menu').length) { 1710 | element 1711 | .closest('li.dropdown') 1712 | .addClass('active') 1713 | .end() 1714 | .find('[data-toggle="tab"]') 1715 | .attr('aria-expanded', true) 1716 | } 1717 | 1718 | callback && callback() 1719 | } 1720 | 1721 | $active.length && transition ? 1722 | $active 1723 | .one('bsTransitionEnd', next) 1724 | .emulateTransitionEnd(Tab.TRANSITION_DURATION) : 1725 | next() 1726 | 1727 | $active.removeClass('in') 1728 | } 1729 | 1730 | 1731 | // TAB PLUGIN DEFINITION 1732 | // ===================== 1733 | 1734 | function Plugin(option) { 1735 | return this.each(function () { 1736 | var $this = $(this) 1737 | var data = $this.data('bs.tab') 1738 | 1739 | if (!data) $this.data('bs.tab', (data = new Tab(this))) 1740 | if (typeof option == 'string') data[option]() 1741 | }) 1742 | } 1743 | 1744 | var old = $.fn.tab 1745 | 1746 | $.fn.tab = Plugin 1747 | $.fn.tab.Constructor = Tab 1748 | 1749 | 1750 | // TAB NO CONFLICT 1751 | // =============== 1752 | 1753 | $.fn.tab.noConflict = function () { 1754 | $.fn.tab = old 1755 | return this 1756 | } 1757 | 1758 | 1759 | // TAB DATA-API 1760 | // ============ 1761 | 1762 | var clickHandler = function (e) { 1763 | e.preventDefault() 1764 | Plugin.call($(this), 'show') 1765 | } 1766 | 1767 | $(document) 1768 | .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler) 1769 | .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler) 1770 | 1771 | }(jQuery); 1772 | 1773 | /* ======================================================================== 1774 | * Bootstrap: affix.js v3.3.7 1775 | * http://getbootstrap.com/javascript/#affix 1776 | * ======================================================================== 1777 | * Copyright 2011-2016 Twitter, Inc. 1778 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1779 | * ======================================================================== */ 1780 | 1781 | 1782 | +function ($) { 1783 | 'use strict'; 1784 | 1785 | // AFFIX CLASS DEFINITION 1786 | // ====================== 1787 | 1788 | var Affix = function (element, options) { 1789 | this.options = $.extend({}, Affix.DEFAULTS, options) 1790 | 1791 | this.$target = $(this.options.target) 1792 | .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 1793 | .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 1794 | 1795 | this.$element = $(element) 1796 | this.affixed = null 1797 | this.unpin = null 1798 | this.pinnedOffset = null 1799 | 1800 | this.checkPosition() 1801 | } 1802 | 1803 | Affix.VERSION = '3.3.7' 1804 | 1805 | Affix.RESET = 'affix affix-top affix-bottom' 1806 | 1807 | Affix.DEFAULTS = { 1808 | offset: 0, 1809 | target: window 1810 | } 1811 | 1812 | Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { 1813 | var scrollTop = this.$target.scrollTop() 1814 | var position = this.$element.offset() 1815 | var targetHeight = this.$target.height() 1816 | 1817 | if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false 1818 | 1819 | if (this.affixed == 'bottom') { 1820 | if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' 1821 | return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' 1822 | } 1823 | 1824 | var initializing = this.affixed == null 1825 | var colliderTop = initializing ? scrollTop : position.top 1826 | var colliderHeight = initializing ? targetHeight : height 1827 | 1828 | if (offsetTop != null && scrollTop <= offsetTop) return 'top' 1829 | if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' 1830 | 1831 | return false 1832 | } 1833 | 1834 | Affix.prototype.getPinnedOffset = function () { 1835 | if (this.pinnedOffset) return this.pinnedOffset 1836 | this.$element.removeClass(Affix.RESET).addClass('affix') 1837 | var scrollTop = this.$target.scrollTop() 1838 | var position = this.$element.offset() 1839 | return (this.pinnedOffset = position.top - scrollTop) 1840 | } 1841 | 1842 | Affix.prototype.checkPositionWithEventLoop = function () { 1843 | setTimeout($.proxy(this.checkPosition, this), 1) 1844 | } 1845 | 1846 | Affix.prototype.checkPosition = function () { 1847 | if (!this.$element.is(':visible')) return 1848 | 1849 | var height = this.$element.height() 1850 | var offset = this.options.offset 1851 | var offsetTop = offset.top 1852 | var offsetBottom = offset.bottom 1853 | var scrollHeight = Math.max($(document).height(), $(document.body).height()) 1854 | 1855 | if (typeof offset != 'object') offsetBottom = offsetTop = offset 1856 | if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) 1857 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) 1858 | 1859 | var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) 1860 | 1861 | if (this.affixed != affix) { 1862 | if (this.unpin != null) this.$element.css('top', '') 1863 | 1864 | var affixType = 'affix' + (affix ? '-' + affix : '') 1865 | var e = $.Event(affixType + '.bs.affix') 1866 | 1867 | this.$element.trigger(e) 1868 | 1869 | if (e.isDefaultPrevented()) return 1870 | 1871 | this.affixed = affix 1872 | this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null 1873 | 1874 | this.$element 1875 | .removeClass(Affix.RESET) 1876 | .addClass(affixType) 1877 | .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') 1878 | } 1879 | 1880 | if (affix == 'bottom') { 1881 | this.$element.offset({ 1882 | top: scrollHeight - height - offsetBottom 1883 | }) 1884 | } 1885 | } 1886 | 1887 | 1888 | // AFFIX PLUGIN DEFINITION 1889 | // ======================= 1890 | 1891 | function Plugin(option) { 1892 | return this.each(function () { 1893 | var $this = $(this) 1894 | var data = $this.data('bs.affix') 1895 | var options = typeof option == 'object' && option 1896 | 1897 | if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 1898 | if (typeof option == 'string') data[option]() 1899 | }) 1900 | } 1901 | 1902 | var old = $.fn.affix 1903 | 1904 | $.fn.affix = Plugin 1905 | $.fn.affix.Constructor = Affix 1906 | 1907 | 1908 | // AFFIX NO CONFLICT 1909 | // ================= 1910 | 1911 | $.fn.affix.noConflict = function () { 1912 | $.fn.affix = old 1913 | return this 1914 | } 1915 | 1916 | 1917 | // AFFIX DATA-API 1918 | // ============== 1919 | 1920 | $(window).on('load', function () { 1921 | $('[data-spy="affix"]').each(function () { 1922 | var $spy = $(this) 1923 | var data = $spy.data() 1924 | 1925 | data.offset = data.offset || {} 1926 | 1927 | if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom 1928 | if (data.offsetTop != null) data.offset.top = data.offsetTop 1929 | 1930 | Plugin.call($spy, data) 1931 | }) 1932 | }) 1933 | 1934 | }(jQuery); 1935 | 1936 | /* ======================================================================== 1937 | * Bootstrap: collapse.js v3.3.7 1938 | * http://getbootstrap.com/javascript/#collapse 1939 | * ======================================================================== 1940 | * Copyright 2011-2016 Twitter, Inc. 1941 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1942 | * ======================================================================== */ 1943 | 1944 | /* jshint latedef: false */ 1945 | 1946 | +function ($) { 1947 | 'use strict'; 1948 | 1949 | // COLLAPSE PUBLIC CLASS DEFINITION 1950 | // ================================ 1951 | 1952 | var Collapse = function (element, options) { 1953 | this.$element = $(element) 1954 | this.options = $.extend({}, Collapse.DEFAULTS, options) 1955 | this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + 1956 | '[data-toggle="collapse"][data-target="#' + element.id + '"]') 1957 | this.transitioning = null 1958 | 1959 | if (this.options.parent) { 1960 | this.$parent = this.getParent() 1961 | } else { 1962 | this.addAriaAndCollapsedClass(this.$element, this.$trigger) 1963 | } 1964 | 1965 | if (this.options.toggle) this.toggle() 1966 | } 1967 | 1968 | Collapse.VERSION = '3.3.7' 1969 | 1970 | Collapse.TRANSITION_DURATION = 350 1971 | 1972 | Collapse.DEFAULTS = { 1973 | toggle: true 1974 | } 1975 | 1976 | Collapse.prototype.dimension = function () { 1977 | var hasWidth = this.$element.hasClass('width') 1978 | return hasWidth ? 'width' : 'height' 1979 | } 1980 | 1981 | Collapse.prototype.show = function () { 1982 | if (this.transitioning || this.$element.hasClass('in')) return 1983 | 1984 | var activesData 1985 | var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') 1986 | 1987 | if (actives && actives.length) { 1988 | activesData = actives.data('bs.collapse') 1989 | if (activesData && activesData.transitioning) return 1990 | } 1991 | 1992 | var startEvent = $.Event('show.bs.collapse') 1993 | this.$element.trigger(startEvent) 1994 | if (startEvent.isDefaultPrevented()) return 1995 | 1996 | if (actives && actives.length) { 1997 | Plugin.call(actives, 'hide') 1998 | activesData || actives.data('bs.collapse', null) 1999 | } 2000 | 2001 | var dimension = this.dimension() 2002 | 2003 | this.$element 2004 | .removeClass('collapse') 2005 | .addClass('collapsing')[dimension](0) 2006 | .attr('aria-expanded', true) 2007 | 2008 | this.$trigger 2009 | .removeClass('collapsed') 2010 | .attr('aria-expanded', true) 2011 | 2012 | this.transitioning = 1 2013 | 2014 | var complete = function () { 2015 | this.$element 2016 | .removeClass('collapsing') 2017 | .addClass('collapse in')[dimension]('') 2018 | this.transitioning = 0 2019 | this.$element 2020 | .trigger('shown.bs.collapse') 2021 | } 2022 | 2023 | if (!$.support.transition) return complete.call(this) 2024 | 2025 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 2026 | 2027 | this.$element 2028 | .one('bsTransitionEnd', $.proxy(complete, this)) 2029 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) 2030 | } 2031 | 2032 | Collapse.prototype.hide = function () { 2033 | if (this.transitioning || !this.$element.hasClass('in')) return 2034 | 2035 | var startEvent = $.Event('hide.bs.collapse') 2036 | this.$element.trigger(startEvent) 2037 | if (startEvent.isDefaultPrevented()) return 2038 | 2039 | var dimension = this.dimension() 2040 | 2041 | this.$element[dimension](this.$element[dimension]())[0].offsetHeight 2042 | 2043 | this.$element 2044 | .addClass('collapsing') 2045 | .removeClass('collapse in') 2046 | .attr('aria-expanded', false) 2047 | 2048 | this.$trigger 2049 | .addClass('collapsed') 2050 | .attr('aria-expanded', false) 2051 | 2052 | this.transitioning = 1 2053 | 2054 | var complete = function () { 2055 | this.transitioning = 0 2056 | this.$element 2057 | .removeClass('collapsing') 2058 | .addClass('collapse') 2059 | .trigger('hidden.bs.collapse') 2060 | } 2061 | 2062 | if (!$.support.transition) return complete.call(this) 2063 | 2064 | this.$element 2065 | [dimension](0) 2066 | .one('bsTransitionEnd', $.proxy(complete, this)) 2067 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION) 2068 | } 2069 | 2070 | Collapse.prototype.toggle = function () { 2071 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 2072 | } 2073 | 2074 | Collapse.prototype.getParent = function () { 2075 | return $(this.options.parent) 2076 | .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') 2077 | .each($.proxy(function (i, element) { 2078 | var $element = $(element) 2079 | this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) 2080 | }, this)) 2081 | .end() 2082 | } 2083 | 2084 | Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { 2085 | var isOpen = $element.hasClass('in') 2086 | 2087 | $element.attr('aria-expanded', isOpen) 2088 | $trigger 2089 | .toggleClass('collapsed', !isOpen) 2090 | .attr('aria-expanded', isOpen) 2091 | } 2092 | 2093 | function getTargetFromTrigger($trigger) { 2094 | var href 2095 | var target = $trigger.attr('data-target') 2096 | || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 2097 | 2098 | return $(target) 2099 | } 2100 | 2101 | 2102 | // COLLAPSE PLUGIN DEFINITION 2103 | // ========================== 2104 | 2105 | function Plugin(option) { 2106 | return this.each(function () { 2107 | var $this = $(this) 2108 | var data = $this.data('bs.collapse') 2109 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 2110 | 2111 | if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false 2112 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 2113 | if (typeof option == 'string') data[option]() 2114 | }) 2115 | } 2116 | 2117 | var old = $.fn.collapse 2118 | 2119 | $.fn.collapse = Plugin 2120 | $.fn.collapse.Constructor = Collapse 2121 | 2122 | 2123 | // COLLAPSE NO CONFLICT 2124 | // ==================== 2125 | 2126 | $.fn.collapse.noConflict = function () { 2127 | $.fn.collapse = old 2128 | return this 2129 | } 2130 | 2131 | 2132 | // COLLAPSE DATA-API 2133 | // ================= 2134 | 2135 | $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 2136 | var $this = $(this) 2137 | 2138 | if (!$this.attr('data-target')) e.preventDefault() 2139 | 2140 | var $target = getTargetFromTrigger($this) 2141 | var data = $target.data('bs.collapse') 2142 | var option = data ? 'toggle' : $this.data() 2143 | 2144 | Plugin.call($target, option) 2145 | }) 2146 | 2147 | }(jQuery); 2148 | 2149 | /* ======================================================================== 2150 | * Bootstrap: scrollspy.js v3.3.7 2151 | * http://getbootstrap.com/javascript/#scrollspy 2152 | * ======================================================================== 2153 | * Copyright 2011-2016 Twitter, Inc. 2154 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2155 | * ======================================================================== */ 2156 | 2157 | 2158 | +function ($) { 2159 | 'use strict'; 2160 | 2161 | // SCROLLSPY CLASS DEFINITION 2162 | // ========================== 2163 | 2164 | function ScrollSpy(element, options) { 2165 | this.$body = $(document.body) 2166 | this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) 2167 | this.options = $.extend({}, ScrollSpy.DEFAULTS, options) 2168 | this.selector = (this.options.target || '') + ' .nav li > a' 2169 | this.offsets = [] 2170 | this.targets = [] 2171 | this.activeTarget = null 2172 | this.scrollHeight = 0 2173 | 2174 | this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) 2175 | this.refresh() 2176 | this.process() 2177 | } 2178 | 2179 | ScrollSpy.VERSION = '3.3.7' 2180 | 2181 | ScrollSpy.DEFAULTS = { 2182 | offset: 10 2183 | } 2184 | 2185 | ScrollSpy.prototype.getScrollHeight = function () { 2186 | return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) 2187 | } 2188 | 2189 | ScrollSpy.prototype.refresh = function () { 2190 | var that = this 2191 | var offsetMethod = 'offset' 2192 | var offsetBase = 0 2193 | 2194 | this.offsets = [] 2195 | this.targets = [] 2196 | this.scrollHeight = this.getScrollHeight() 2197 | 2198 | if (!$.isWindow(this.$scrollElement[0])) { 2199 | offsetMethod = 'position' 2200 | offsetBase = this.$scrollElement.scrollTop() 2201 | } 2202 | 2203 | this.$body 2204 | .find(this.selector) 2205 | .map(function () { 2206 | var $el = $(this) 2207 | var href = $el.data('target') || $el.attr('href') 2208 | var $href = /^#./.test(href) && $(href) 2209 | 2210 | return ($href 2211 | && $href.length 2212 | && $href.is(':visible') 2213 | && [[$href[offsetMethod]().top + offsetBase, href]]) || null 2214 | }) 2215 | .sort(function (a, b) { return a[0] - b[0] }) 2216 | .each(function () { 2217 | that.offsets.push(this[0]) 2218 | that.targets.push(this[1]) 2219 | }) 2220 | } 2221 | 2222 | ScrollSpy.prototype.process = function () { 2223 | var scrollTop = this.$scrollElement.scrollTop() + this.options.offset 2224 | var scrollHeight = this.getScrollHeight() 2225 | var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() 2226 | var offsets = this.offsets 2227 | var targets = this.targets 2228 | var activeTarget = this.activeTarget 2229 | var i 2230 | 2231 | if (this.scrollHeight != scrollHeight) { 2232 | this.refresh() 2233 | } 2234 | 2235 | if (scrollTop >= maxScroll) { 2236 | return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) 2237 | } 2238 | 2239 | if (activeTarget && scrollTop < offsets[0]) { 2240 | this.activeTarget = null 2241 | return this.clear() 2242 | } 2243 | 2244 | for (i = offsets.length; i--;) { 2245 | activeTarget != targets[i] 2246 | && scrollTop >= offsets[i] 2247 | && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1]) 2248 | && this.activate(targets[i]) 2249 | } 2250 | } 2251 | 2252 | ScrollSpy.prototype.activate = function (target) { 2253 | this.activeTarget = target 2254 | 2255 | this.clear() 2256 | 2257 | var selector = this.selector + 2258 | '[data-target="' + target + '"],' + 2259 | this.selector + '[href="' + target + '"]' 2260 | 2261 | var active = $(selector) 2262 | .parents('li') 2263 | .addClass('active') 2264 | 2265 | if (active.parent('.dropdown-menu').length) { 2266 | active = active 2267 | .closest('li.dropdown') 2268 | .addClass('active') 2269 | } 2270 | 2271 | active.trigger('activate.bs.scrollspy') 2272 | } 2273 | 2274 | ScrollSpy.prototype.clear = function () { 2275 | $(this.selector) 2276 | .parentsUntil(this.options.target, '.active') 2277 | .removeClass('active') 2278 | } 2279 | 2280 | 2281 | // SCROLLSPY PLUGIN DEFINITION 2282 | // =========================== 2283 | 2284 | function Plugin(option) { 2285 | return this.each(function () { 2286 | var $this = $(this) 2287 | var data = $this.data('bs.scrollspy') 2288 | var options = typeof option == 'object' && option 2289 | 2290 | if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) 2291 | if (typeof option == 'string') data[option]() 2292 | }) 2293 | } 2294 | 2295 | var old = $.fn.scrollspy 2296 | 2297 | $.fn.scrollspy = Plugin 2298 | $.fn.scrollspy.Constructor = ScrollSpy 2299 | 2300 | 2301 | // SCROLLSPY NO CONFLICT 2302 | // ===================== 2303 | 2304 | $.fn.scrollspy.noConflict = function () { 2305 | $.fn.scrollspy = old 2306 | return this 2307 | } 2308 | 2309 | 2310 | // SCROLLSPY DATA-API 2311 | // ================== 2312 | 2313 | $(window).on('load.bs.scrollspy.data-api', function () { 2314 | $('[data-spy="scroll"]').each(function () { 2315 | var $spy = $(this) 2316 | Plugin.call($spy, $spy.data()) 2317 | }) 2318 | }) 2319 | 2320 | }(jQuery); 2321 | 2322 | /* ======================================================================== 2323 | * Bootstrap: transition.js v3.3.7 2324 | * http://getbootstrap.com/javascript/#transitions 2325 | * ======================================================================== 2326 | * Copyright 2011-2016 Twitter, Inc. 2327 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2328 | * ======================================================================== */ 2329 | 2330 | 2331 | +function ($) { 2332 | 'use strict'; 2333 | 2334 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 2335 | // ============================================================ 2336 | 2337 | function transitionEnd() { 2338 | var el = document.createElement('bootstrap') 2339 | 2340 | var transEndEventNames = { 2341 | WebkitTransition : 'webkitTransitionEnd', 2342 | MozTransition : 'transitionend', 2343 | OTransition : 'oTransitionEnd otransitionend', 2344 | transition : 'transitionend' 2345 | } 2346 | 2347 | for (var name in transEndEventNames) { 2348 | if (el.style[name] !== undefined) { 2349 | return { end: transEndEventNames[name] } 2350 | } 2351 | } 2352 | 2353 | return false // explicit for ie8 ( ._.) 2354 | } 2355 | 2356 | // http://blog.alexmaccaw.com/css-transitions 2357 | $.fn.emulateTransitionEnd = function (duration) { 2358 | var called = false 2359 | var $el = this 2360 | $(this).one('bsTransitionEnd', function () { called = true }) 2361 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 2362 | setTimeout(callback, duration) 2363 | return this 2364 | } 2365 | 2366 | $(function () { 2367 | $.support.transition = transitionEnd() 2368 | 2369 | if (!$.support.transition) return 2370 | 2371 | $.event.special.bsTransitionEnd = { 2372 | bindType: $.support.transition.end, 2373 | delegateType: $.support.transition.end, 2374 | handle: function (e) { 2375 | if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 2376 | } 2377 | } 2378 | }) 2379 | 2380 | }(jQuery); 2381 | --------------------------------------------------------------------------------