From d775fa0d088994fbf9d4b68260f0c6cdadd959fe Mon Sep 17 00:00:00 2001 From: Alexander Machehin Date: Wed, 29 Aug 2012 20:58:58 +0600 Subject: [PATCH] [refs #616] ugly md preview --- Gemfile | 2 +- Gemfile.lock | 4 +- app/assets/javascripts/application.js | 6 +- app/assets/stylesheets/design/custom.scss | 26 ++ .../projects/projects_controller.rb | 4 + app/helpers/application_helper.rb | 7 + app/models/ability.rb | 2 +- app/presenters/comment_presenter.rb | 2 +- app/views/projects/comments/_add.html.haml | 2 +- app/views/projects/comments/_body.html.haml | 40 +++ app/views/projects/comments/_form.html.haml | 4 +- app/views/projects/comments/edit.html.haml | 2 +- app/views/projects/issues/_form.html.haml | 11 +- app/views/projects/issues/show.html.haml | 3 +- app/views/shared/_feed_message.html.haml | 2 +- config/routes.rb | 1 + vendor/assets/javascripts/bootstrap-tab.js | 130 +++++++ vendor/assets/javascripts/vendor.js | 1 + vendor/assets/stylesheets/bootstrap.css | 324 ++++++++++++++++++ 19 files changed, 557 insertions(+), 16 deletions(-) create mode 100644 app/views/projects/comments/_body.html.haml create mode 100644 vendor/assets/javascripts/bootstrap-tab.js diff --git a/Gemfile b/Gemfile index 60869b4bb..3ef671a19 100644 --- a/Gemfile +++ b/Gemfile @@ -32,7 +32,7 @@ gem 'diff-display', '~> 0.0.1' # Wiki gem "gollum", :git => 'git://github.com/github/gollum.git' -gem "redcarpet", "1.17.2" +gem "redcarpet", "~> 2.1.1" gem 'creole' gem 'rdiscount' # gem 'org-ruby' diff --git a/Gemfile.lock b/Gemfile.lock index 896f7a8ab..939f82499 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -251,7 +251,7 @@ GEM rdiscount (1.6.8) rdoc (3.12) json (~> 1.4) - redcarpet (1.17.2) + redcarpet (2.1.1) redis (3.0.1) redis-namespace (1.2.0) redis (~> 3.0.0) @@ -399,7 +399,7 @@ DEPENDENCIES rails3-generators rails3-jquery-autocomplete (~> 1.0.7) rdiscount - redcarpet (= 1.17.2) + redcarpet (~> 2.1.1) redhillonrails_core! resque (~> 1.21.0) resque-status (~> 0.3.3) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 6b311c6f5..21522b5a9 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -34,7 +34,7 @@ $(document).ready(function() { var current = $(this); current.parent().find('input.user_role_chbx').each(function(i,el) { if ($(el).attr('id') != current.attr('id')) { - $(el).removeAttr('checked'); + $(el).removeAttr('checked'); } }); }); @@ -81,4 +81,8 @@ $(document).ready(function() { } return false; }); + + $('.md_and_cm code').each(function (code) { + CodeMirror.runMode(this.innerHTML.replace(/&/gi, '&'), this.className, this); + }); }); diff --git a/app/assets/stylesheets/design/custom.scss b/app/assets/stylesheets/design/custom.scss index ec5e20392..1678428fc 100644 --- a/app/assets/stylesheets/design/custom.scss +++ b/app/assets/stylesheets/design/custom.scss @@ -1481,3 +1481,29 @@ div.log-wrapper { } } } + +.md_and_cm { + overflow: auto; + + pre { + background-color: #F8F8F8; + border: 1px solid #D6D6D6; + border-radius: 5px 5px 5px 5px; + color: #333333; + padding: 6px 10px; + overflow: auto; + + code { + background-color: transparent; + border: none; + } + } + + code { + background-color: #F8F8F8; + border: 1px solid #D6D6D6; + border-radius: 5px 5px 5px 5px; + margin: 0 2px; + padding: 0px 5px; + } +} diff --git a/app/controllers/projects/projects_controller.rb b/app/controllers/projects/projects_controller.rb index 30b452dc4..633c9a6da 100644 --- a/app/controllers/projects/projects_controller.rb +++ b/app/controllers/projects/projects_controller.rb @@ -86,6 +86,10 @@ class Projects::ProjectsController < Projects::BaseController redirect_to projects_path end + def preview + render :inline => view_context.markdown(params[:text]), :layout => false + end + protected def prepare_list(projects) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 26ed84332..4d49542e8 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -39,4 +39,11 @@ module ApplicationHelper else object.class.name end end + + def markdown(text) + html_options = {filter_html: true, hard_wrap: true, with_toc_data: true} + options = {no_intraemphasis: true, tables: true, fenced_code_blocks: true, autolink: true, strikethrough: true, lax_html_blocks: true} + + Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(html_options), options).render(text).html_safe + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index c356badc8..1b3eb94d5 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -53,7 +53,7 @@ class Ability can :read, Project, :visibility => 'open' can [:read, :archive], Project, :owner_type => 'User', :owner_id => user.id can [:read, :archive], Project, :owner_type => 'Group', :owner_id => user.group_ids - can([:read, :membered], Project, read_relations_for('projects')) {|project| local_reader? project} + can([:read, :membered, :preview], Project, read_relations_for('projects')) {|project| local_reader? project} can(:write, Project) {|project| local_writer? project} # for grack can([:update, :sections, :manage_collaborators], Project) {|project| local_admin? project} can(:fork, Project) {|project| can? :read, project} diff --git a/app/presenters/comment_presenter.rb b/app/presenters/comment_presenter.rb index bab0b3343..8c3a7163b 100644 --- a/app/presenters/comment_presenter.rb +++ b/app/presenters/comment_presenter.rb @@ -9,7 +9,7 @@ class CommentPresenter < ApplicationPresenter @user = comment.user @options = opts - @content = simple_format(@comment.body, {}, :sanitize => true).html_safe + @content = @comment.body end def expandable? diff --git a/app/views/projects/comments/_add.html.haml b/app/views/projects/comments/_add.html.haml index e78fe2ac3..561ae2e30 100644 --- a/app/views/projects/comments/_add.html.haml +++ b/app/views/projects/comments/_add.html.haml @@ -10,7 +10,7 @@ - subscribe_path = is_subscribed ? unsubscribe_commit_path(project, commentable) : subscribe_commit_path(project, commentable) = form_for :comment, :url => new_path, :method => :post, :html => { :class => :form } do |f| - = render "projects/comments/form", :f => f + = render "projects/comments/form", :f => f, :id => 'new' .comment-left = t("layout.comments.notifications_are") %span.bold diff --git a/app/views/projects/comments/_body.html.haml b/app/views/projects/comments/_body.html.haml new file mode 100644 index 000000000..654bb9a45 --- /dev/null +++ b/app/views/projects/comments/_body.html.haml @@ -0,0 +1,40 @@ +%ul.nav.nav-tabs#md_tabs + %li + %a{"data-toggle" => "tab", :href => "##{id}_edit"} edit + %li + %a{"data-toggle" => "tab", :href => "##{id}_preview"} preview + +.tab-content + .tab-pane.active{:id => "#{id}_edit"} + .wrapper= f.text_area :body, :cols => 80, :id => "#{id}_edit_input" + =hidden_field_tag :body_dup, nil, :name => 'text', :id => "#{id}_edit_input_dup" + .tab-pane{:id => "#{id}_preview"} + .formatted.cm-s-default.md_and_cm{:style => 'background: #FFF'} + +:javascript + $(document).ready(function() { + $('#md_tabs a:first').tab('show'); + + $('#md_tabs a[data-toggle="tab"]').on('shown', function (e) { + var hash = e.relatedTarget.hash; + var el = $(hash+'_input'); + var el_dup = $(hash+'_input_dup'); + if(el.val() != el_dup.val()) { + el_dup.val(el.val()); + $.ajax({ + type: 'POST', + url: '#{project_md_preview_path @project}', + data: el_dup.serialize(), + success: function(data){ + $(e.target.hash+' > .formatted.cm-s-default').html(data) + .find('code').each(function (code) { + CodeMirror.runMode(this.innerHTML.replace(/&/gi, '&'), this.className, this); + }); + }, + error: function(data){ + alert('error'); // TODO remove + } + }); + }; + }); + }); diff --git a/app/views/projects/comments/_form.html.haml b/app/views/projects/comments/_form.html.haml index d7814ddad..19193058d 100644 --- a/app/views/projects/comments/_form.html.haml +++ b/app/views/projects/comments/_form.html.haml @@ -1,2 +1,2 @@ -.wrapper= f.text_area :body, :cols => 80 -.comment-right= submit_tag t("layout.save") \ No newline at end of file +.wrapper=render 'projects/comments/body', :f => f, :id => id +.comment-right= submit_tag t("layout.save") diff --git a/app/views/projects/comments/edit.html.haml b/app/views/projects/comments/edit.html.haml index a27158367..c58c30b49 100644 --- a/app/views/projects/comments/edit.html.haml +++ b/app/views/projects/comments/edit.html.haml @@ -8,4 +8,4 @@ = t("layout.comments.edit_header") .inner = form_for @comment, :url => project_commentable_comment_path(@project, @commentable, @comment), :html => {:class => :form} do |f| - = render "form", :f => f + = render "form", :f => f, :id => "edit_#{@comment.id}" diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml index 72c9f4cc7..3ce77098c 100644 --- a/app/views/projects/issues/_form.html.haml +++ b/app/views/projects/issues/_form.html.haml @@ -1,7 +1,10 @@ -.leftlist= t('activerecord.attributes.issue.title') + ':' -.rightlist= f.text_field :title -.leftlist= t('activerecord.attributes.issue.body') + ':' -.rightlist= f.text_area :body +#open-comment.comment.view + %h3.tmargin0{:style => 'margin-bottom: 0;'}= t 'activerecord.attributes.issue.title' + .wrapper= f.text_area :title, :cols => 80, :rows => 1, :style => 'height: 16px; margin: 0 0 10px;' +#open-comment.comment.view + %h3.tmargin0= t 'activerecord.attributes.issue.body' + =render 'projects/comments/body', :f => f, :id => 'new' + .both .leftlist= t('activerecord.attributes.issue.assignee') + ':' .rightlist diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 6e9cc015b..407f76a9e 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -14,7 +14,7 @@ %span.date=@issue.created_at.to_s(:long) %br/ .both - .fulltext.view.issue_body=simple_format @issue.body + .fulltext.view.issue_body.formatted.cm-s-default.md_and_cm=markdown @issue.body .both %br - if can? :update, @issue @@ -33,3 +33,4 @@ = render "projects/comments/list", :list => @issue.comments, :project => @project, :commentable => @issue %br = render "projects/comments/add", :project => @project, :commentable => @issue if current_user + diff --git a/app/views/shared/_feed_message.html.haml b/app/views/shared/_feed_message.html.haml index 42b5d942a..0e7e8e420 100644 --- a/app/views/shared/_feed_message.html.haml +++ b/app/views/shared/_feed_message.html.haml @@ -19,5 +19,5 @@ - if presenter.content? .fulltext{:class => "#{presenter.expandable? ? "hidden" : ''} #{presenter.caption? ? "" : "alone"}", :id => presenter.expandable? ? "content-expand#{item_no}" : ''} - = presenter.content + .cm-s-default.md_and_cm=markdown presenter.content .both diff --git a/config/routes.rb b/config/routes.rb index f680bfbf0..128cf895d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -181,6 +181,7 @@ Rosa::Application.routes.draw do resources :collaborators do get :find, :on => :collection end + post '/preview' => 'projects#preview', :as => 'md_preview' end # Resource get '/modify' => 'projects#edit', :as => :edit_project diff --git a/vendor/assets/javascripts/bootstrap-tab.js b/vendor/assets/javascripts/bootstrap-tab.js new file mode 100644 index 000000000..a26da9b6c --- /dev/null +++ b/vendor/assets/javascripts/bootstrap-tab.js @@ -0,0 +1,130 @@ +/* ======================================================== + * bootstrap-tab.js v2.0.2 + * http://twitter.github.com/bootstrap/javascript.html#tabs + * ======================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================== */ + + +!function( $ ){ + + "use strict" + + /* TAB CLASS DEFINITION + * ==================== */ + + var Tab = function ( element ) { + this.element = $(element) + } + + Tab.prototype = { + + constructor: Tab + + , show: function () { + var $this = this.element + , $ul = $this.closest('ul:not(.dropdown-menu)') + , selector = $this.attr('data-target') + , previous + , $target + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + if ( $this.parent('li').hasClass('active') ) return + + previous = $ul.find('.active a').last()[0] + + $this.trigger({ + type: 'show' + , relatedTarget: previous + }) + + $target = $(selector) + + this.activate($this.parent('li'), $ul) + this.activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown' + , relatedTarget: previous + }) + }) + } + + , activate: function ( element, container, callback) { + var $active = container.find('> .active') + , transition = callback + && $.support.transition + && $active.hasClass('fade') + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + + element.addClass('active') + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if ( element.parent('.dropdown-menu') ) { + element.closest('li.dropdown').addClass('active') + } + + callback && callback() + } + + transition ? + $active.one($.support.transition.end, next) : + next() + + $active.removeClass('in') + } + } + + + /* TAB PLUGIN DEFINITION + * ===================== */ + + $.fn.tab = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('tab') + if (!data) $this.data('tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tab.Constructor = Tab + + + /* TAB DATA-API + * ============ */ + + $(function () { + $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') + }) + }) + +}( window.jQuery ); diff --git a/vendor/assets/javascripts/vendor.js b/vendor/assets/javascripts/vendor.js index a4d1ebcfb..4c332a44e 100644 --- a/vendor/assets/javascripts/vendor.js +++ b/vendor/assets/javascripts/vendor.js @@ -13,6 +13,7 @@ // require bootstrap-tooltip // require bootstrap-popover //= require bootstrap-alert +//= require bootstrap-tab //= require chosen.jquery // require html5shiv // require_tree . diff --git a/vendor/assets/stylesheets/bootstrap.css b/vendor/assets/stylesheets/bootstrap.css index f43391083..e5b61c73c 100644 --- a/vendor/assets/stylesheets/bootstrap.css +++ b/vendor/assets/stylesheets/bootstrap.css @@ -419,4 +419,328 @@ -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; +} +.nav { + margin-left: 0; + margin-bottom: 20px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav > .pull-right { + float: right; +} +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 15px; + padding-right: 15px; + margin-bottom: 0; +} +.nav-list > li > a, +.nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list > .active > a, +.nav-list > .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} +.nav-tabs, +.nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; + line-height: 0; +} +.nav-tabs:after, +.nav-pills:after { + clear: both; +} +.nav-tabs > li, +.nav-pills > li { + float: left; +} +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills > .active > a, +.nav-pills > .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.nav .dropdown-toggle .caret { + border-top-color: #0088cc; + border-bottom-color: #0088cc; + margin-top: 6px; +} +.nav .dropdown-toggle:hover .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} +/* move down carets for tabs */ +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} +.nav > .dropdown.active > a:hover { + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, +.tabbable:after { + display: table; + content: ""; + line-height: 0; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: auto; +} +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} +.tab-content > .active, +.pill-content > .active { + display: block; +} +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below > .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left > .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right > .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.nav > .disabled > a { + color: #999999; +} +.nav > .disabled > a:hover { + text-decoration: none; + background-color: transparent; + cursor: default; } \ No newline at end of file