From 1700d12aba07d24a33454985b370f38e9b5517d4 Mon Sep 17 00:00:00 2001 From: uu59 Date: Wed, 21 May 2014 13:04:31 +0900 Subject: [PATCH] Apply design theme basically. close #7 --- Gemfile.lock | 3 + app/assets/javascripts/application.js | 2 + app/assets/stylesheets/application.css | 3 + app/controllers/sessions_controller.rb | 2 + app/helpers/application_helper.rb | 42 +- app/views/layouts/application.html.erb | 106 +- app/views/layouts/sign_in.html.erb | 35 + app/views/plugins/_installing.html.haml | 8 - app/views/plugins/_nav.html.haml | 5 - app/views/plugins/installed.html.haml | 73 +- app/views/plugins/recommended.html.haml | 57 +- app/views/plugins/updated.html.haml | 7 +- app/views/sessions/new.html.haml | 12 +- app/views/shared/_alerts.html.haml | 21 + app/views/shared/_global_nav.html.erb | 44 + app/views/shared/_global_nav.html.haml | 4 - config/locales/translation_ja.yml | 9 + fluentd-ui.gemspec | 1 + .../javascripts/sb-admin-v2/bootstrap.js | 1951 +++ .../javascripts/sb-admin-v2/bootstrap.min.js | 6 + .../sb-admin-v2/demo/dashboard-demo.js | 117 + .../javascripts/sb-admin-v2/demo/flot-demo.js | 1242 ++ .../sb-admin-v2/demo/morris-demo.js | 155 + .../javascripts/sb-admin-v2/jquery-1.10.2.js | 6 + .../dataTables/dataTables.bootstrap.js | 245 + .../plugins/dataTables/jquery.dataTables.js | 14013 ++++++++++++++++ .../sb-admin-v2/plugins/flot/excanvas.min.js | 1 + .../sb-admin-v2/plugins/flot/jquery.flot.js | 2599 +++ .../plugins/flot/jquery.flot.pie.js | 750 + .../plugins/flot/jquery.flot.resize.js | 60 + .../plugins/flot/jquery.flot.tooltip.min.js | 12 + .../plugins/metisMenu/jquery.metisMenu.js | 45 + .../sb-admin-v2/plugins/morris/morris.js | 1888 +++ .../plugins/morris/raphael-2.1.0.min.js | 10 + .../javascripts/sb-admin-v2/sb-admin.js | 18 + .../stylesheets/sb-admin-v2/bootstrap.css | 5831 +++++++ .../stylesheets/sb-admin-v2/bootstrap.min.css | 7 + .../font-awesome/css/font-awesome.css | 1338 ++ .../font-awesome/css/font-awesome.min.css | 4 + .../font-awesome/fonts/FontAwesome.otf | Bin 0 -> 62856 bytes .../fonts/fontawesome-webfont.eot | Bin 0 -> 38205 bytes .../fonts/fontawesome-webfont.svg | 414 + .../fonts/fontawesome-webfont.ttf | Bin 0 -> 80652 bytes .../fonts/fontawesome-webfont.woff | Bin 0 -> 44432 bytes .../font-awesome/scss/_bordered-pulled.scss | 16 + .../sb-admin-v2/font-awesome/scss/_core.scss | 12 + .../font-awesome/scss/_fixed-width.scss | 6 + .../sb-admin-v2/font-awesome/scss/_icons.scss | 412 + .../font-awesome/scss/_larger.scss | 13 + .../sb-admin-v2/font-awesome/scss/_list.scss | 19 + .../font-awesome/scss/_mixins.scss | 20 + .../sb-admin-v2/font-awesome/scss/_path.scss | 14 + .../font-awesome/scss/_rotated-flipped.scss | 9 + .../font-awesome/scss/_spinning.scss | 30 + .../font-awesome/scss/_stacked.scss | 20 + .../font-awesome/scss/_variables.scss | 381 + .../font-awesome/scss/font-awesome.scss | 17 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20290 bytes .../fonts/glyphicons-halflings-regular.svg | 229 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 41236 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23292 bytes .../dataTables/dataTables.bootstrap.css | 233 + .../plugins/morris/morris-0.4.3.min.css | 2 + .../plugins/social-buttons/social-buttons.css | 68 + .../sb-admin-v2/plugins/timeline/timeline.css | 144 + .../stylesheets/sb-admin-v2/sb-admin.css | 329 + 66 files changed, 33020 insertions(+), 100 deletions(-) create mode 100644 app/views/layouts/sign_in.html.erb delete mode 100644 app/views/plugins/_installing.html.haml delete mode 100644 app/views/plugins/_nav.html.haml create mode 100644 app/views/shared/_alerts.html.haml create mode 100644 app/views/shared/_global_nav.html.erb delete mode 100644 app/views/shared/_global_nav.html.haml create mode 100644 vendor/assets/javascripts/sb-admin-v2/bootstrap.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/bootstrap.min.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/demo/dashboard-demo.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/demo/flot-demo.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/demo/morris-demo.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/jquery-1.10.2.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/dataTables/dataTables.bootstrap.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/dataTables/jquery.dataTables.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/flot/excanvas.min.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/flot/jquery.flot.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/flot/jquery.flot.pie.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/flot/jquery.flot.resize.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/flot/jquery.flot.tooltip.min.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/metisMenu/jquery.metisMenu.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/morris/morris.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/plugins/morris/raphael-2.1.0.min.js create mode 100644 vendor/assets/javascripts/sb-admin-v2/sb-admin.js create mode 100644 vendor/assets/stylesheets/sb-admin-v2/bootstrap.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/bootstrap.min.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/css/font-awesome.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/css/font-awesome.min.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/fonts/FontAwesome.otf create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/fonts/fontawesome-webfont.eot create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/fonts/fontawesome-webfont.svg create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/fonts/fontawesome-webfont.ttf create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/fonts/fontawesome-webfont.woff create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_bordered-pulled.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_core.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_fixed-width.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_icons.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_larger.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_list.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_mixins.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_path.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_rotated-flipped.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_spinning.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_stacked.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/_variables.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/font-awesome/scss/font-awesome.scss create mode 100644 vendor/assets/stylesheets/sb-admin-v2/fonts/glyphicons-halflings-regular.eot create mode 100644 vendor/assets/stylesheets/sb-admin-v2/fonts/glyphicons-halflings-regular.svg create mode 100644 vendor/assets/stylesheets/sb-admin-v2/fonts/glyphicons-halflings-regular.ttf create mode 100644 vendor/assets/stylesheets/sb-admin-v2/fonts/glyphicons-halflings-regular.woff create mode 100644 vendor/assets/stylesheets/sb-admin-v2/plugins/dataTables/dataTables.bootstrap.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/plugins/morris/morris-0.4.3.min.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/plugins/social-buttons/social-buttons.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/plugins/timeline/timeline.css create mode 100644 vendor/assets/stylesheets/sb-admin-v2/sb-admin.css diff --git a/Gemfile.lock b/Gemfile.lock index 5f43149..3e8640c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,6 +6,7 @@ PATH bundler (~> 1.5) coffee-rails (~> 4.0.0) fluentd (= 0.10.46) + font-awesome-rails haml-rails (~> 0.5.3) httpclient i18n_generators (= 1.2.1) @@ -87,6 +88,8 @@ GEM msgpack (>= 0.4.4, < 0.6.0, != 0.5.3, != 0.5.2, != 0.5.1, != 0.5.0) sigdump (~> 0.2.2) yajl-ruby (~> 1.0) + font-awesome-rails (4.0.3.1) + railties (>= 3.2, < 5.0) haml (4.0.5) tilt haml-rails (0.5.3) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 1ca0e3b..37975ec 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,4 +12,6 @@ // //= require jquery //= require jquery_ujs +//= require sb-admin-v2/bootstrap +//= require sb-admin-v2/sb-admin //= require_tree . diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index a443db3..acb4bbe 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -10,6 +10,9 @@ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * + *= require sb-admin-v2/bootstrap + *= require "sb-admin-v2/sb-admin" + *= require "sb-admin-v2/font-awesome/scss/font-awesome.scss" *= require_tree . *= require_self */ diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index cca3903..ae46c2b 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,4 +1,6 @@ class SessionsController < ApplicationController + layout "sign_in" + def create user = User.find_by(name: session_params[:name]).try(:authenticate, session_params[:password]) unless user diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e706227..3ee117f 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -4,7 +4,43 @@ module ApplicationHelper end def installing_gem? - GemInstaller::WORKING.present? + installing_gems.length > 0 + end + + def installing_gems + GemInstaller::WORKING || [] + end + + def uninstalling_gem? + uninstalling_gems.length > 0 + end + + def uninstalling_gems + GemUninstaller::WORKING || [] + end + + def has_alert? + installing_gem? || uninstalling_gem? + end + + def alerts + alerts = [] + if installing_gem? + #GemInstaller::WORKING.each do |plugin| + Plugin.installed.each do |plugin| + # TODO: i18n + alerts << alert_line("fa-spinner fa-spin", "Installing #{plugin.gem_name} (#{plugin.version})") + end + end + Plugin.installed.each do |plugin| + # TODO: i18n + alerts << alert_line("fa-spinner fa-spin", "Installing #{plugin.gem_name} (#{plugin.version})") + end + alerts + end + + def alert_line(icon_class, text) + %Q|
  • #{icon icon_class} #{text}
  • |.html_safe end def link_to_other(text, path) @@ -14,4 +50,8 @@ module ApplicationHelper link_to text, path end end + + def icon(classes, inner=nil) + %Q!#{inner}!.html_safe + end end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 1a88456..e1747b4 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,15 +1,111 @@ + - FluentdUi + + + + + Fluentd-UI <%= stylesheet_link_tag 'application', media: 'all'%> <%= javascript_include_tag 'application' %> <%= csrf_meta_tags %> - - - <%= render partial: "shared/global_nav" %> -<%= yield %> + + + + + +
    + + + +
    +
    +
    +

    Dashboard

    +
    + +
    + +
    +
    + <%= yield %> +
    +
    + +
    + + +
    + + + + + + + + + + + + + + + + + diff --git a/app/views/layouts/sign_in.html.erb b/app/views/layouts/sign_in.html.erb new file mode 100644 index 0000000..cb304a3 --- /dev/null +++ b/app/views/layouts/sign_in.html.erb @@ -0,0 +1,35 @@ + + + + + + + + + Fluentd-UI + <%= stylesheet_link_tag 'application', media: 'all'%> + <%= javascript_include_tag 'application' %> + <%= csrf_meta_tags %> + + + + + +
    +
    +
    + +
    +
    +
    + + + + diff --git a/app/views/plugins/_installing.html.haml b/app/views/plugins/_installing.html.haml deleted file mode 100644 index 626c6f3..0000000 --- a/app/views/plugins/_installing.html.haml +++ /dev/null @@ -1,8 +0,0 @@ -- if installing_gem? - %p.alert - / TODO: i18n - installing plugins... - %ol - - GemInstaller::WORKING.each do |plugin| - %li= "#{plugin.gem_name} (#{plugin.version})" - diff --git a/app/views/plugins/_nav.html.haml b/app/views/plugins/_nav.html.haml deleted file mode 100644 index 8a109c2..0000000 --- a/app/views/plugins/_nav.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -%p.nav - = link_to_other(t("terms.plugin.pages.updated"), updated_plugins_path) - = link_to_other(t("terms.plugin.pages.installed"), installed_plugins_path) - = link_to_other(t("terms.plugin.pages.recommended"), recommended_plugins_path) - diff --git a/app/views/plugins/installed.html.haml b/app/views/plugins/installed.html.haml index 13ab821..7955a2b 100644 --- a/app/views/plugins/installed.html.haml +++ b/app/views/plugins/installed.html.haml @@ -1,39 +1,38 @@ -= render partial: "installing" -= render partial: "nav" - -%table - %tr - %th= t('terms.uninstall') - %th= t('terms.plugin.name') - %th= t('terms.plugin.status') - %th= t('terms.plugin.installed_version') - %th= t('terms.plugin.latest_version') - %th - - @plugins.each do |plugin| +%table{class: "table table-striped table-hover"} + %thead %tr - %td - = form_tag(uninstall_plugins_path, method: :patch) do - = hidden_field_tag("plugins[]", plugin.gem_name) - = submit_tag t('terms.uninstall') - %td - %label{for: "plugin_#{plugin.gem_name}"} - = plugin.gem_name - %td - - if plugin.installed? - - if plugin.latest_version? - = t("terms.installed") + %th{width: "32"} + %th= t('terms.plugin.name') + %th= t('terms.plugin.status') + %th= t('terms.plugin.installed_version') + %th= t('terms.plugin.latest_version') + %th + %tbody + - @plugins.each do |plugin| + %tr + %td + = form_tag(uninstall_plugins_path, method: :patch) do + = hidden_field_tag("plugins[]", plugin.gem_name) + = submit_tag t('terms.uninstall'), class: "btn btn-default" + %td + %label{for: "plugin_#{plugin.gem_name}"} + = plugin.gem_name + %td + - if plugin.installed? + - if plugin.latest_version? + = t("terms.installed") + - else + = t("terms.new_version", version: plugin.latest_version) - else - = t("terms.new_version", version: plugin.latest_version) - - else - = t("terms.not_installed") - %td - = plugin.installed_version - %td - = plugin.latest_version - %td - = form_tag(upgrade_plugins_path, method: :patch) do - = hidden_field_tag("plugins[name]", plugin.gem_name) - %select{name: "plugins[version]"} - - plugin.released_versions.each do |ver| - %option{value: ver, disabled: (ver == plugin.installed_version)}= ver - = submit_tag "version fix" + = t("terms.not_installed") + %td + = plugin.installed_version + %td + = plugin.latest_version + %td + = form_tag(upgrade_plugins_path, method: :patch) do + = hidden_field_tag("plugins[name]", plugin.gem_name) + %select{name: "plugins[version]"} + - plugin.released_versions.each do |ver| + %option{value: ver, disabled: (ver == plugin.installed_version)}= ver + = submit_tag "version fix", class: "btn btn-sm btn-info" diff --git a/app/views/plugins/recommended.html.haml b/app/views/plugins/recommended.html.haml index c70d096..65766ba 100644 --- a/app/views/plugins/recommended.html.haml +++ b/app/views/plugins/recommended.html.haml @@ -1,33 +1,32 @@ -= render partial: "installing" -= render partial: "nav" - = form_tag(install_plugins_path, method: :patch) do - %table - %tr - %th - %th= t('terms.plugin.name') - %th= t('terms.plugin.status') - %th= t('terms.plugin.installed_version') - %th= t('terms.plugin.latest_version') - - @plugins.each do |plugin| + %table{class: "table table-striped table-hover"} + %thead %tr - %td - - unless plugin.installed? - = check_box_tag("plugins[]", plugin.gem_name, false, id: "plugin_#{plugin.gem_name}") - %td - %label{for: "plugin_#{plugin.gem_name}"} - = plugin.gem_name - %td - - if plugin.installed? - - if plugin.latest_version? - = t("terms.installed") + %th{width: "24"} + %th= t('terms.plugin.name') + %th= t('terms.plugin.status') + %th{width: "100"}= t('terms.plugin.installed_version') + %th{width: "100"}= t('terms.plugin.latest_version') + %tbody + - @plugins.each do |plugin| + %tr + %td + - unless plugin.installed? + = check_box_tag("plugins[]", plugin.gem_name, false, id: "plugin_#{plugin.gem_name}") + %td + %label{for: "plugin_#{plugin.gem_name}"} + = plugin.gem_name + %td + - if plugin.installed? + - if plugin.latest_version? + = t("terms.installed") + - else + = t("terms.new_version", version: plugin.latest_version) - else - = t("terms.new_version", version: plugin.latest_version) - - else - = t("terms.not_installed") - %td - = plugin.installed_version - %td - = plugin.latest_version - = submit_tag t("terms.install") + = t("terms.not_installed") + %td + = plugin.installed_version + %td + = plugin.latest_version + = submit_tag t("terms.install"), class: "btn btn-primary" diff --git a/app/views/plugins/updated.html.haml b/app/views/plugins/updated.html.haml index 147afd6..9568ec4 100644 --- a/app/views/plugins/updated.html.haml +++ b/app/views/plugins/updated.html.haml @@ -1,11 +1,8 @@ -= render partial: "installing" -= render partial: "nav" - - unless @plugins.present? = t('terms.plugin.no_updates') - else = form_tag(install_plugins_path, method: :patch) do - %table + %table{class: "table table-striped table-hover"} %tr %th %th= t('terms.plugin.name') @@ -31,5 +28,5 @@ = plugin.installed_version %td = plugin.latest_version - = submit_tag t("terms.install") + = submit_tag t("terms.install"), class: "btn btn-primary" diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml index f1d3e69..bae46db 100644 --- a/app/views/sessions/new.html.haml +++ b/app/views/sessions/new.html.haml @@ -1,8 +1,8 @@ = render partial: "shared/error" = form_for(:session, url: sessions_path) do |f| - = f.label :name - = f.text_field :name - = f.label :password - = f.text_field :password - = submit_tag t("terms.sign_in") - + %div.form-group + = f.text_field :name, placeholder: "Name" + %div.form-group + = f.password_field :password, placeholder: "Password" + + = submit_tag t("terms.sign_in"), class: "btn btn-success" diff --git a/app/views/shared/_alerts.html.haml b/app/views/shared/_alerts.html.haml new file mode 100644 index 0000000..7eb73a4 --- /dev/null +++ b/app/views/shared/_alerts.html.haml @@ -0,0 +1,21 @@ +%li + %a + %div + = icon "fa-cog fa-fw fa-lg" + Installing Plugins + %span{class: "pull-right text-muted small"}= "(#{installing_gems.length})" + +- installing_gems.each do |plugin| + = alert_line 'fa-refresh fa-spin', "#{plugin.gem_name} (#{plugin.version})" + +%li{class: "divider"} + +%li + %a + %div + = icon "fa-cog fa-fw fa-lg" + Uninstalling Plugins + %span{class: "pull-right text-muted small"}= "(#{uninstalling_gems.length})" + +- uninstalling_gems.each do |plugin| + = alert_line 'fa-spinner fa-spin', plugin.gem_name diff --git a/app/views/shared/_global_nav.html.erb b/app/views/shared/_global_nav.html.erb new file mode 100644 index 0000000..7406f64 --- /dev/null +++ b/app/views/shared/_global_nav.html.erb @@ -0,0 +1,44 @@ + diff --git a/app/views/shared/_global_nav.html.haml b/app/views/shared/_global_nav.html.haml deleted file mode 100644 index f8a0ef3..0000000 --- a/app/views/shared/_global_nav.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -= link_to_other "plugins", plugins_path -= link_to_other "system information", information_misc_path - -= current_user ? link_to(t("terms.sign_out"), sessions_path, method: :delete) : link_to(t("terms.sign_in"), new_sessions_path) diff --git a/config/locales/translation_ja.yml b/config/locales/translation_ja.yml index 245fb8b..0d66543 100644 --- a/config/locales/translation_ja.yml +++ b/config/locales/translation_ja.yml @@ -19,8 +19,17 @@ ja: recommended: おすすめプラグイン updated: 更新あり + sidebar: + dashboard: ダッシュボード + plugins: プラグイン + plugin_installed: インストール済み + plugin_recommended: おすすめプラグイン + plugin_updated: アップデート + + messages: need_restart: fluentd-uiの再起動が必要です + please_sign_in: ログイン error: login_failed: ログインに失敗しました。 diff --git a/fluentd-ui.gemspec b/fluentd-ui.gemspec index 6321cda..5e9016b 100644 --- a/fluentd-ui.gemspec +++ b/fluentd-ui.gemspec @@ -24,6 +24,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'i18n_generators', '1.2.1' spec.add_dependency 'bcrypt', '~> 3.1.5' spec.add_dependency 'sqlite3' + spec.add_dependency "font-awesome-rails" spec.add_dependency 'sass-rails', '~> 4.0.3' spec.add_dependency 'uglifier', '>= 1.3.0' spec.add_dependency 'coffee-rails', '~> 4.0.0' diff --git a/vendor/assets/javascripts/sb-admin-v2/bootstrap.js b/vendor/assets/javascripts/sb-admin-v2/bootstrap.js new file mode 100644 index 0000000..39ec471 --- /dev/null +++ b/vendor/assets/javascripts/sb-admin-v2/bootstrap.js @@ -0,0 +1,1951 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +if (typeof jQuery === 'undefined') { throw new Error('Bootstrap requires jQuery') } + +/* ======================================================================== + * Bootstrap: transition.js v3.1.0 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd', + 'MozTransition' : 'transitionend', + 'OTransition' : 'oTransitionEnd otransitionend', + 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.1.0 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.1.0 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.1.0 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + if ($next.hasClass('active')) return this.sliding = false + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid.bs.carousel', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) + }) + .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid.bs.carousel') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.1.0 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && option == 'show') option = !option + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.1.0 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('