├── test ├── dummy │ ├── log │ │ └── .keep │ ├── app │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ └── page.rb │ │ ├── assets │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── stylesheets │ │ │ │ └── application.css.sass │ │ │ └── javascripts │ │ │ │ └── application.js.coffee │ │ ├── controllers │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ ├── welcome_controller.rb │ │ │ ├── application_controller.rb │ │ │ └── pages_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ └── views │ │ │ ├── layouts │ │ │ └── application.html.haml │ │ │ ├── welcome │ │ │ └── index.html.haml │ │ │ └── pages │ │ │ └── _page.html.haml │ ├── lib │ │ └── assets │ │ │ └── .keep │ ├── public │ │ ├── favicon.ico │ │ ├── 500.html │ │ ├── 422.html │ │ └── 404.html │ ├── bin │ │ ├── rake │ │ ├── bundle │ │ └── rails │ ├── config.ru │ ├── config │ │ ├── initializers │ │ │ ├── session_store.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── mime_types.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── wrap_parameters.rb │ │ │ ├── secret_token.rb │ │ │ └── inflections.rb │ │ ├── environment.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── locales │ │ │ └── en.yml │ │ ├── application.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── test.rb │ │ │ └── production.rb │ │ └── routes.rb │ ├── db │ │ ├── seeds.rb │ │ ├── migrate │ │ │ └── 20131115152536_create_pages.rb │ │ └── schema.rb │ ├── Rakefile │ └── README.rdoc ├── x-editable-rails_test.rb ├── test_helper.rb └── view_helpers_test.rb ├── Procfile ├── gemfiles ├── rails_4_0.gemfile ├── rails_4_1.gemfile └── rails_4_2.gemfile ├── vendor └── assets │ ├── images │ └── editable │ │ ├── clear.png │ │ └── loading.gif │ ├── javascripts │ └── editable │ │ ├── rails.js.coffee │ │ ├── rails │ │ ├── error_handling.js.coffee │ │ ├── data_classes.js.coffee │ │ └── editable_form.js.coffee │ │ └── inputs-ext │ │ ├── typeahead-editable.js │ │ ├── wysihtml5-editable.js │ │ ├── address.js │ │ └── bootstrap-wysihtml5.js │ └── stylesheets │ └── editable │ ├── inputs-ext │ ├── address.css │ ├── wysiwyg-color.css │ ├── bootstrap-typeahead.css │ └── bootstrap-wysihtml5.css │ ├── jquery-editable.scss │ ├── jqueryui-editable.scss │ ├── bootstrap-editable.scss │ └── bootstrap2-editable.scss ├── lib ├── x-editable-rails │ ├── version.rb │ ├── configuration.rb │ └── view_helpers.rb ├── generators │ └── x_editable_rails │ │ ├── install_generator.rb │ │ └── templates │ │ └── x-editable.yml └── x-editable-rails.rb ├── .travis.yml ├── Gemfile ├── .gitignore ├── Rakefile ├── x-editable-rails.gemspec ├── LICENSE.txt ├── Gemfile.lock └── README.md /test/dummy/log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: cd test/dummy && bin/rails server -p $PORT 2 | -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /gemfiles/rails_4_0.gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'rails', '~> 4.0.0' 6 | -------------------------------------------------------------------------------- /gemfiles/rails_4_1.gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'rails', '~> 4.1.0' 6 | -------------------------------------------------------------------------------- /gemfiles/rails_4_2.gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'rails', '~> 4.2.0' 6 | -------------------------------------------------------------------------------- /test/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /vendor/assets/images/editable/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/werein/x-editable-rails/HEAD/vendor/assets/images/editable/clear.png -------------------------------------------------------------------------------- /vendor/assets/images/editable/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/werein/x-editable-rails/HEAD/vendor/assets/images/editable/loading.gif -------------------------------------------------------------------------------- /lib/x-editable-rails/version.rb: -------------------------------------------------------------------------------- 1 | module X 2 | module Editable 3 | module Rails 4 | VERSION = "1.5.5.1" 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | class WelcomeController < ApplicationController 2 | def index 3 | @pages = Page.all 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /test/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/rails.js.coffee: -------------------------------------------------------------------------------- 1 | #= require editable/rails/editable_form 2 | #= require editable/rails/data_classes 3 | #= require editable/rails/error_handling 4 | -------------------------------------------------------------------------------- /test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Dummy::Application.initialize! 6 | -------------------------------------------------------------------------------- /test/x-editable-rails_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class XEditableRailsTest < ActiveSupport::TestCase 4 | test "truth" do 5 | assert_kind_of Module, X::Editable::Rails 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy/app/models/page.rb: -------------------------------------------------------------------------------- 1 | class Page < ActiveRecord::Base 2 | translates :title 3 | accepts_nested_attributes_for :translations, allow_destroy: true 4 | validates :name, length: { minimum: 5 }, allow_blank: true 5 | end 6 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/inputs-ext/address.css: -------------------------------------------------------------------------------- 1 | .editable-address { 2 | display: block; 3 | margin-bottom: 5px; 4 | } 5 | 6 | .editable-address span { 7 | width: 70px; 8 | display: inline-block; 9 | } -------------------------------------------------------------------------------- /test/dummy/db/seeds.rb: -------------------------------------------------------------------------------- 1 | Page.create!( 2 | active: true, name: 'Apple iPhone', description: 'Apple
iPhone is a ...', 3 | translations_attributes: [{ title: 'Apple CS', locale: 'cs' }, { title: 'Apple EN', locale: 'en' } ]) -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/rails/error_handling.js.coffee: -------------------------------------------------------------------------------- 1 | $.fn.editable.defaults.error = (response, newValue) -> 2 | field_name = $(this).data("name") 3 | error_msgs = response.responseJSON.errors[field_name] 4 | error_msgs.join "; " -------------------------------------------------------------------------------- /test/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) 6 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Dummy::Application.load_tasks 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | branches: master 2 | cache: bundler 3 | gemfile: 4 | - gemfiles/rails_4_0.gemfile 5 | - gemfiles/rails_4_1.gemfile 6 | - gemfiles/rails_4_2.gemfile 7 | language: ruby 8 | matrix: 9 | allow_failures: 10 | - rvm: ruby-head 11 | rvm: 12 | - "2.0" 13 | - "2.1" 14 | - "2.2" 15 | - ruby-head 16 | sudo: false 17 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | %title Dummy 5 | = stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true 6 | = csrf_meta_tags 7 | %body 8 | .container 9 | = yield 10 | = javascript_include_tag "application", "data-turbolinks-track" => true -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in x-editable-rails.gemspec 4 | gemspec 5 | 6 | gem 'sprockets' 7 | gem 'sass-rails' 8 | gem 'bootstrap-sass' 9 | gem 'coffee-rails' 10 | gem 'jquery-rails' 11 | gem 'haml' 12 | gem 'globalize' 13 | gem 'responders' 14 | gem 'pg' 15 | gem 'rails_12factor' 16 | gem 'uglifier' 17 | -------------------------------------------------------------------------------- /test/dummy/app/views/welcome/index.html.haml: -------------------------------------------------------------------------------- 1 | %h1 Welcome#index 2 | %p Find me in app/views/welcome/index.html.haml 3 | 4 | .pull-right 5 | = link_to 'Denied access', root_path(denied: true) 6 | | 7 | = link_to 'Enabled access', root_path 8 | 9 | %table.table.table-striped 10 | %thead 11 | %tr 12 | %th Description 13 | %th Example 14 | %th Code 15 | %tbody 16 | = render @pages -------------------------------------------------------------------------------- /lib/generators/x_editable_rails/install_generator.rb: -------------------------------------------------------------------------------- 1 | module XEditableRails 2 | module Generators 3 | class InstallGenerator < Rails::Generators::Base 4 | source_root File.expand_path('../templates', __FILE__) 5 | 6 | desc 'Copy example of x-editable config' 7 | def copy_x_editable_yml 8 | template 'x-editable.yml', 'config/x-editable.yml' 9 | end 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /lib/x-editable-rails.rb: -------------------------------------------------------------------------------- 1 | require 'x-editable-rails/version' 2 | require 'x-editable-rails/configuration' 3 | require 'x-editable-rails/view_helpers' 4 | 5 | module X 6 | module Editable 7 | module Rails 8 | class Engine < ::Rails::Engine 9 | initializer 'x-editable-rails.view_helpers' do 10 | ActionView::Base.send :include, ViewHelpers 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | .idea 7 | .DS_Store 8 | gemfiles/*.gemfile.lock 9 | InstalledFiles 10 | _yardoc 11 | coverage 12 | doc/ 13 | lib/bundler/man 14 | pkg 15 | rdoc 16 | spec/reports 17 | test/tmp 18 | test/version_tmp 19 | test/dummy/db/*.sqlite3 20 | test/dummy/db/*.sqlite3-journal 21 | test/dummy/log/*.log 22 | test/dummy/tmp/ 23 | test/dummy/.sass-cache 24 | test/dummy/public/uploads/ 25 | coverage/ 26 | tmp 27 | .project -------------------------------------------------------------------------------- /test/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /lib/generators/x_editable_rails/templates/x-editable.yml: -------------------------------------------------------------------------------- 1 | # More informations you can find here: https://github.com/werein/x-editable-rails 2 | class_options: 3 | MailingList: 4 | name: Mailing list name 5 | enabled: 6 | type: select 7 | source: 8 | - Active 9 | - Disabled 10 | reply_email: 11 | type: email 12 | title: Reply-to email 13 | User: 14 | email: 15 | type: email 16 | password: 17 | type: password 18 | mailing_lists: 19 | type: select -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | # protect_from_forgery with: :exception 5 | 6 | def xeditable? object = nil 7 | xeditable = params[:denied] ? false : true 8 | can?(:edit, object) and xeditable ? true : false 9 | end 10 | helper_method :xeditable? 11 | 12 | def can? edit, model 13 | true 14 | end 15 | helper_method :can? 16 | end -------------------------------------------------------------------------------- /test/dummy/db/migrate/20131115152536_create_pages.rb: -------------------------------------------------------------------------------- 1 | class CreatePages < ActiveRecord::Migration 2 | def change 3 | create_table :pages do |t| 4 | t.boolean :active 5 | t.string :name 6 | t.text :description 7 | 8 | t.timestamps 9 | end 10 | 11 | create_table :page_translations do |t| 12 | t.references :page, index: true 13 | t.string :locale, null: false 14 | t.string :title 15 | t.timestamps 16 | end 17 | 18 | add_index :page_translations, :locale 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Environment 2 | ENV["RAILS_ENV"] = "test" 3 | 4 | require File.expand_path("../dummy/config/environment.rb", __FILE__) 5 | require "rails/test_help" 6 | 7 | Rails.backtrace_cleaner.remove_silencers! 8 | 9 | # Load support files 10 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } 11 | 12 | # Load fixtures from the engine 13 | if ActiveSupport::TestCase.method_defined?(:fixture_path=) 14 | ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) 15 | end 16 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /test/dummy/README.rdoc: -------------------------------------------------------------------------------- 1 | == README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | 26 | 27 | Please feel free to use a different markup language if you do not plan to run 28 | rake doc:app. 29 | -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: sqlite3 17 | database: db/test.sqlite3 18 | pool: 5 19 | timeout: 5000 20 | 21 | production: 22 | adapter: sqlite3 23 | database: db/production.sqlite3 24 | pool: 5 25 | timeout: 5000 26 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'bundler/setup' 3 | rescue LoadError 4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 5 | end 6 | 7 | require 'rdoc/task' 8 | 9 | RDoc::Task.new(:rdoc) do |rdoc| 10 | rdoc.rdoc_dir = 'rdoc' 11 | rdoc.title = 'X::Editable::Rails' 12 | rdoc.options << '--line-numbers' 13 | rdoc.rdoc_files.include('README.rdoc') 14 | rdoc.rdoc_files.include('lib/**/*.rb') 15 | end 16 | 17 | 18 | 19 | 20 | Bundler::GemHelper.install_tasks 21 | 22 | require 'rake/testtask' 23 | 24 | Rake::TestTask.new(:test) do |t| 25 | t.libs << 'lib' 26 | t.libs << 'test' 27 | t.pattern = 'test/**/*_test.rb' 28 | t.verbose = false 29 | end 30 | 31 | 32 | task default: :test 33 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure your secret_key_base is kept private 11 | # if you're sharing your code publicly. 12 | Dummy::Application.config.secret_key_base = '029c36f961f43fec4a2b2d75900636c7dcd45d8f2a046245d77971f6930c44919246db38e63ffdf4caf72725528f79278c93fc5a0ce3cf0426a228a75b5c2f03' 13 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/application.css.sass: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.css, which will include all the files 2 | // listed below. 3 | // 4 | // Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 5 | // or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // You're free to add application-wide styles to this file and they'll appear at the top of the 8 | // compiled file, but it's generally better to create a new file per style scope. 9 | // 10 | //= require_self 11 | //= require_tree . 12 | 13 | @import "bootstrap" 14 | @import "editable/bootstrap-editable" 15 | @import "editable/inputs-ext/bootstrap-wysihtml5" 16 | @import "editable/inputs-ext/wysiwyg-color" -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/rails/data_classes.js.coffee: -------------------------------------------------------------------------------- 1 | 2 | # make things editable that can be edited 3 | 4 | # $('.editable').editable( 5 | # success: (response, value) -> 6 | # element = $(this) 7 | # css = element.data('classes') || {} 8 | # element.removeClass(class_name) for key, class_name of css 9 | # element.addClass(css[value]) 10 | # element.css('background-color', '') 11 | # ) 12 | 13 | # swap CSS classes when the value changes 14 | 15 | jQuery ($) -> 16 | $("[data-classes]").on "save", (e, data) -> 17 | value = data.newValue 18 | element = $(this) 19 | css = element.data('classes') || {} 20 | element.removeClass(class_name) for key, class_name of css 21 | element.addClass(css[value]) 22 | element.css('background-color', '') 23 | 24 | -------------------------------------------------------------------------------- /test/dummy/app/assets/javascripts/application.js.coffee: -------------------------------------------------------------------------------- 1 | # This is a manifest file that'll be compiled into application.js, which will include all the files 2 | # listed below. 3 | # 4 | # Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | # or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | # 7 | # It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | # compiled file. 9 | # 10 | # Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | # about supported directives. 12 | # 13 | #= require jquery 14 | #= require bootstrap 15 | #= require editable/bootstrap-editable 16 | #= require editable/inputs-ext/wysihtml5 17 | #= require editable/inputs-ext/bootstrap-wysihtml5 18 | #= require editable/inputs-ext/wysihtml5-editable 19 | #= require editable/rails 20 | #= require_tree . 21 | 22 | $('.editable').editable() -------------------------------------------------------------------------------- /test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | require "x-editable-rails" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | # Settings in config/environments/* take precedence over those specified here. 11 | # Application configuration should go into files in config/initializers 12 | # -- all .rb files in that directory are automatically loaded. 13 | 14 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 15 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 16 | # config.time_zone = 'Central Time (US & Canada)' 17 | 18 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 19 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 20 | # config.i18n.default_locale = :de 21 | 22 | config.i18n.available_locales = [:en, :cs] 23 | end 24 | end 25 | 26 | -------------------------------------------------------------------------------- /x-editable-rails.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'x-editable-rails/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "x-editable-rails" 8 | spec.version = X::Editable::Rails::VERSION 9 | spec.authors = ["We're in"] 10 | spec.email = ["info@wereinhq.com"] 11 | spec.description = %q{X-editable for Rails} 12 | spec.summary = %q{X-editable for Rails} 13 | spec.homepage = "https://github.com/werein/x-editable-rails" 14 | spec.license = "MIT" 15 | 16 | spec.files = Dir["{lib,vendor}/**/*"] + ["LICENSE.txt", "README.md"] 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib", "vendor"] 20 | 21 | spec.add_dependency "railties" 22 | 23 | spec.add_development_dependency "rails", "~> 4.0" 24 | spec.add_development_dependency "sqlite3" 25 | end 26 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/inputs-ext/wysiwyg-color.css: -------------------------------------------------------------------------------- 1 | .wysiwyg-color-black { 2 | color: black; 3 | } 4 | 5 | .wysiwyg-color-silver { 6 | color: silver; 7 | } 8 | 9 | .wysiwyg-color-gray { 10 | color: gray; 11 | } 12 | 13 | .wysiwyg-color-white { 14 | color: white; 15 | } 16 | 17 | .wysiwyg-color-maroon { 18 | color: maroon; 19 | } 20 | 21 | .wysiwyg-color-red { 22 | color: red; 23 | } 24 | 25 | .wysiwyg-color-purple { 26 | color: purple; 27 | } 28 | 29 | .wysiwyg-color-fuchsia { 30 | color: fuchsia; 31 | } 32 | 33 | .wysiwyg-color-green { 34 | color: green; 35 | } 36 | 37 | .wysiwyg-color-lime { 38 | color: lime; 39 | } 40 | 41 | .wysiwyg-color-olive { 42 | color: olive; 43 | } 44 | 45 | .wysiwyg-color-yellow { 46 | color: yellow; 47 | } 48 | 49 | .wysiwyg-color-navy { 50 | color: navy; 51 | } 52 | 53 | .wysiwyg-color-blue { 54 | color: blue; 55 | } 56 | 57 | .wysiwyg-color-teal { 58 | color: teal; 59 | } 60 | 61 | .wysiwyg-color-aqua { 62 | color: aqua; 63 | } 64 | 65 | .wysiwyg-color-orange { 66 | color: orange; 67 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jiri Kolarik 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /test/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | end 30 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | respond_to :html, :json 3 | before_action :set_page, only: [:show, :edit, :update, :destroy] 4 | 5 | # GET /pages 6 | def index 7 | @pages = Page.all 8 | respond_with @pages 9 | end 10 | 11 | # GET /pages/1 12 | def show 13 | respond_with @page 14 | end 15 | 16 | # GET /pages/new 17 | def new 18 | @page = Page.new 19 | respond_with @page 20 | end 21 | 22 | # GET /pages/1/edit 23 | def edit 24 | respond_with @page 25 | end 26 | 27 | # POST /pages 28 | def create 29 | @page = Page.new(page_params) 30 | flash[:notice] = 'Page was successfully created.' if @page.save 31 | respond_with @page 32 | end 33 | 34 | # PATCH/PUT /pages/1 35 | def update 36 | flash[:notice] = 'Page was successfully updated.' if @page.update(page_params) 37 | respond_with @page 38 | end 39 | 40 | # DELETE /pages/1 41 | def destroy 42 | @page.destroy 43 | redirect_to pages_url, notice: 'Page was successfully destroyed.' 44 | end 45 | 46 | private 47 | # Use callbacks to share common setup or constraints between actions. 48 | def set_page 49 | @page = Page.find(params[:id]) 50 | end 51 | 52 | # Only allow a trusted parameter "white list" through. 53 | def page_params 54 | params.require(:page).permit(:active, :name, :description, translations_attributes: [:id, :title, :locale, :_destroy]) 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /test/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20131115152536) do 15 | 16 | create_table "page_translations", force: true do |t| 17 | t.integer "page_id" 18 | t.string "locale", null: false 19 | t.string "title" 20 | t.datetime "created_at" 21 | t.datetime "updated_at" 22 | end 23 | 24 | add_index "page_translations", ["locale"], name: "index_page_translations_on_locale" 25 | add_index "page_translations", ["page_id"], name: "index_page_translations_on_page_id" 26 | 27 | create_table "pages", force: true do |t| 28 | t.boolean "active" 29 | t.string "name" 30 | t.text "description" 31 | t.datetime "created_at" 32 | t.datetime "updated_at" 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /test/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

We're sorry, but something went wrong.

54 |
55 |

If you are the application owner check the logs for more information.

56 | 57 | 58 | -------------------------------------------------------------------------------- /test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The change you wanted was rejected.

54 |

Maybe you tried to change something you didn't have access to.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /test/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The page you were looking for doesn't exist.

54 |

You may have mistyped the address or the page may have moved.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/inputs-ext/bootstrap-typeahead.css: -------------------------------------------------------------------------------- 1 | .twitter-typeahead .tt-query, 2 | .twitter-typeahead .tt-hint { 3 | margin-bottom: 0; 4 | } 5 | 6 | .tt-dropdown-menu { 7 | min-width: 160px; 8 | margin-top: 2px; 9 | padding: 5px 0; 10 | background-color: #fff; 11 | border: 1px solid #ccc; 12 | border: 1px solid rgba(0,0,0,.2); 13 | *border-right-width: 2px; 14 | *border-bottom-width: 2px; 15 | -webkit-border-radius: 6px; 16 | -moz-border-radius: 6px; 17 | border-radius: 6px; 18 | -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); 19 | -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); 20 | box-shadow: 0 5px 10px rgba(0,0,0,.2); 21 | -webkit-background-clip: padding-box; 22 | -moz-background-clip: padding; 23 | background-clip: padding-box; 24 | } 25 | 26 | .tt-suggestion { 27 | display: block; 28 | padding: 3px 20px; 29 | } 30 | 31 | .tt-suggestion.tt-is-under-cursor { 32 | color: #fff; 33 | background-color: #0081c2; 34 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 35 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 36 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 37 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 38 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 39 | background-repeat: repeat-x; 40 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0) 41 | } 42 | 43 | .tt-suggestion.tt-is-under-cursor a { 44 | color: #fff; 45 | } 46 | 47 | .tt-suggestion p { 48 | margin: 0; 49 | } 50 | -------------------------------------------------------------------------------- /test/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static asset server for tests with Cache-Control for performance. 16 | # config.serve_static_assets = true 17 | # config.static_cache_control = "public, max-age=3600" 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Print deprecation notices to the stderr. 35 | config.active_support.deprecation = :stderr 36 | 37 | config.active_support.test_order = :random 38 | end 39 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/rails/editable_form.js.coffee: -------------------------------------------------------------------------------- 1 | unless EditableForm 2 | EditableForm = $.fn.editableform.Constructor 3 | EditableForm.prototype.saveWithUrlHook = (value) -> 4 | originalUrl = @options.url 5 | model = @options.model 6 | nestedName = @options.nested 7 | nestedId = @options.nid 8 | nestedLocale = @options.locale 9 | 10 | @options.url = (params) => 11 | if typeof originalUrl == 'function' 12 | originalUrl.call(@options.scope, params) 13 | else if originalUrl? && @options.send != 'never' 14 | myName = params.name 15 | myValue = params.value 16 | 17 | # if there are no values in a list, add a blank value so Rails knows all values were removed 18 | if Object.prototype.toString.call(params.value) == '[object Array]' && params.value.length == 0 19 | params.value.push("") 20 | 21 | obj = {} 22 | 23 | if nestedName 24 | nested = {} 25 | nested[myName] = myValue 26 | nested['id'] = nestedId 27 | 28 | if nestedLocale 29 | nested['locale'] = nestedLocale 30 | 31 | obj[nestedName + '_attributes'] = nested 32 | else 33 | obj[myName] = myValue 34 | 35 | params[model] = obj 36 | 37 | delete params.name 38 | delete params.value 39 | delete params.pk 40 | 41 | $.ajax($.extend({ 42 | url: originalUrl 43 | data: params 44 | type: 'PUT' 45 | dataType: 'json' 46 | }, @options.ajaxOptions)) 47 | 48 | @saveWithoutUrlHook(value) 49 | 50 | EditableForm.prototype.saveWithoutUrlHook = EditableForm.prototype.save 51 | EditableForm.prototype.save = EditableForm.prototype.saveWithUrlHook 52 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.routes.draw do 2 | 3 | root "welcome#index" 4 | resources :pages 5 | 6 | # The priority is based upon order of creation: first created -> highest priority. 7 | # See how all your routes lay out with "rake routes". 8 | 9 | # You can have the root of your site routed with "root" 10 | # root 'welcome#index' 11 | 12 | # Example of regular route: 13 | # get 'products/:id' => 'catalog#view' 14 | 15 | # Example of named route that can be invoked with purchase_url(id: product.id) 16 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 17 | 18 | # Example resource route (maps HTTP verbs to controller actions automatically): 19 | # resources :products 20 | 21 | # Example resource route with options: 22 | # resources :products do 23 | # member do 24 | # get 'short' 25 | # post 'toggle' 26 | # end 27 | # 28 | # collection do 29 | # get 'sold' 30 | # end 31 | # end 32 | 33 | # Example resource route with sub-resources: 34 | # resources :products do 35 | # resources :comments, :sales 36 | # resource :seller 37 | # end 38 | 39 | # Example resource route with more complex sub-resources: 40 | # resources :products do 41 | # resources :comments 42 | # resources :sales do 43 | # get 'recent', on: :collection 44 | # end 45 | # end 46 | 47 | # Example resource route with concerns: 48 | # concern :toggleable do 49 | # post 'toggle' 50 | # end 51 | # resources :posts, concerns: :toggleable 52 | # resources :photos, concerns: :toggleable 53 | 54 | # Example resource route within a namespace: 55 | # namespace :admin do 56 | # # Directs /admin/products/* to Admin::ProductsController 57 | # # (app/controllers/admin/products_controller.rb) 58 | # resources :products 59 | # end 60 | end 61 | -------------------------------------------------------------------------------- /lib/x-editable-rails/configuration.rb: -------------------------------------------------------------------------------- 1 | module X 2 | module Editable 3 | module Rails 4 | module Configuration 5 | 6 | def method_options_for(object, method) 7 | class_options_for(object).fetch(method, {}) 8 | end 9 | 10 | def class_options_for(object) 11 | class_options = options.fetch(:class_options, {}) 12 | class_options.fetch(object.class.name, {}) 13 | end 14 | 15 | def class_options 16 | options.fetch(:class_options, {}) 17 | end 18 | 19 | def options 20 | config_fn = ::Rails.root.join("config", "x-editable.yml") 21 | if File.file?(config_fn) 22 | @options ||= begin 23 | options = load_yaml_file config_fn 24 | format_class_options! options 25 | end 26 | else 27 | @options = {} 28 | end 29 | end 30 | 31 | def load_yaml_file(path) 32 | source = File.read path 33 | source = ERB.new(source).result 34 | 35 | result = YAML.load(source) 36 | result = {} if result.blank? 37 | 38 | result.with_indifferent_access 39 | end 40 | 41 | private 42 | 43 | # if the specified options are a string, convert to Hash and make the string the title 44 | def format_class_options!(options) 45 | if class_options = options[:class_options] 46 | class_options.each do |class_name, methods| 47 | methods.each do |method, method_options| 48 | unless method_options.is_a? Hash 49 | methods[method] = { title: method_options }.with_indifferent_access 50 | end 51 | end 52 | end 53 | end 54 | 55 | options 56 | end 57 | 58 | extend self 59 | end 60 | end 61 | end 62 | end -------------------------------------------------------------------------------- /test/dummy/app/views/pages/_page.html.haml: -------------------------------------------------------------------------------- 1 | %tr{id: 'default'} 2 | %td String attribute 3 | %td= editable page, :name 4 | %td 5 | %code = editable page, :name 6 | %tr{id: 'boolean'} 7 | %td Boolean attribute Yes/no 8 | %td= editable page, :active 9 | %td 10 | %code = editable page, :active 11 | %tr{id: 'boolean_source'} 12 | %td Boolean attribute with custom source 13 | %td= editable page, :active, data: { source: ['Active', 'Disabled'] } 14 | %td 15 | %code = editable page, :active, 16 | %br/ 17 | %code data: { source: ['Active', 'Disabled'] } 18 | %tr{id: 'nested_translations'} 19 | %td Globalize gem example 20 | %td= editable page, :title, nested: :translations, nid: page.translation.id 21 | %td 22 | %code = editable page, :title, nested: :translations, nid: page.translation.id 23 | %tr{id: 'select_source'} 24 | %td Select from given source 25 | %td= editable page, :name, type: :select, data: { source: ['iPhone', 'iPad', 'MacBook'] } 26 | %td 27 | %code = editable page, :name, type: :select, 28 | %br/ 29 | %code data: { source: ['iPhone', 'iPad', 'MacBook'] } 30 | %tr{id: 'custom_value'} 31 | %td Custom value (Upcased name) 32 | %td= editable page, :name, value: page.name.upcase 33 | %td 34 | %code = editable page, :name, value: page.name.upcase 35 | %tr{id: 'exception'} 36 | %td Custom exception 37 | %td= editable page, :name, e: "You're not authorized" 38 | %td 39 | %code = editable page, :name, e: "You're not authorized" 40 | %tr{id: 'custom_title'} 41 | %td Custom title 42 | %td= editable page, :name, title: 'Your name please :)' 43 | %td 44 | %code = editable page, :name, title: 'Your name please :)' 45 | %tr{id: 'custom_class'} 46 | %td Custom class (float right) 47 | %td= editable page, :name, class: 'pull-right' 48 | %td 49 | %code = editable page, :name, class: 'pull-right' 50 | %tr{id: 'custom_tag'} 51 | %td Custom tag (its header) 52 | %td= editable page, :name, tag: 'h3' 53 | %td 54 | %code = editable page, :name, tag: 'h3' 55 | %tr{id: 'type_textarea'} 56 | %td Textarea 57 | %td= editable page, :description, type: :textarea 58 | %td 59 | %code = editable page, :description, type: :textarea 60 | %tr{id: 'type_wysihtml5'} 61 | %td Wysihtml5 62 | %td= editable page, :description, type: :wysihtml5 63 | %td 64 | %code = editable page, :description, type: :wysihtml5 -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/inputs-ext/typeahead-editable.js: -------------------------------------------------------------------------------- 1 | /** 2 | Typeahead.js input, based on [Twitter Typeahead](http://twitter.github.io/typeahead.js). 3 | It is mainly replacement of typeahead in Bootstrap 3. 4 | 5 | 6 | @class typeaheadjs 7 | @extends text 8 | @since 1.5.0 9 | @final 10 | @example 11 | 12 | 30 | **/ 31 | (function ($) { 32 | "use strict"; 33 | 34 | var Constructor = function (options) { 35 | this.init('typeaheadjs', options, Constructor.defaults); 36 | }; 37 | 38 | $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.text); 39 | 40 | $.extend(Constructor.prototype, { 41 | render: function() { 42 | this.renderClear(); 43 | this.setClass(); 44 | this.setAttr('placeholder'); 45 | this.$input.typeahead(this.options.typeahead); 46 | 47 | // copy `input-sm | input-lg` classes to placeholder input 48 | if($.fn.editableform.engine === 'bs3') { 49 | if(this.$input.hasClass('input-sm')) { 50 | this.$input.siblings('input.tt-hint').addClass('input-sm'); 51 | } 52 | if(this.$input.hasClass('input-lg')) { 53 | this.$input.siblings('input.tt-hint').addClass('input-lg'); 54 | } 55 | } 56 | } 57 | }); 58 | 59 | Constructor.defaults = $.extend({}, $.fn.editabletypes.list.defaults, { 60 | /** 61 | @property tpl 62 | @default 63 | **/ 64 | tpl:'', 65 | /** 66 | Configuration of typeahead itself. 67 | [Full list of options](https://github.com/twitter/typeahead.js#dataset). 68 | 69 | @property typeahead 70 | @type object 71 | @default null 72 | **/ 73 | typeahead: null, 74 | /** 75 | Whether to show `clear` button 76 | 77 | @property clear 78 | @type boolean 79 | @default true 80 | **/ 81 | clear: true 82 | }); 83 | 84 | $.fn.editabletypes.typeaheadjs = Constructor; 85 | 86 | }(window.jQuery)); -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/inputs-ext/bootstrap-wysihtml5.css: -------------------------------------------------------------------------------- 1 | ul.wysihtml5-toolbar { 2 | margin: 0; 3 | padding: 0; 4 | display: block; 5 | } 6 | 7 | ul.wysihtml5-toolbar::after { 8 | clear: both; 9 | display: table; 10 | content: ""; 11 | } 12 | 13 | ul.wysihtml5-toolbar > li { 14 | float: left; 15 | display: list-item; 16 | list-style: none; 17 | margin: 0 5px 10px 0; 18 | } 19 | 20 | ul.wysihtml5-toolbar a[data-wysihtml5-command=bold] { 21 | font-weight: bold; 22 | } 23 | 24 | ul.wysihtml5-toolbar a[data-wysihtml5-command=italic] { 25 | font-style: italic; 26 | } 27 | 28 | ul.wysihtml5-toolbar a[data-wysihtml5-command=underline] { 29 | text-decoration: underline; 30 | } 31 | 32 | ul.wysihtml5-toolbar a.btn.wysihtml5-command-active { 33 | background-image: none; 34 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 35 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 36 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 37 | background-color: #E6E6E6; 38 | background-color: #D9D9D9; 39 | outline: 0; 40 | } 41 | 42 | ul.wysihtml5-commands-disabled .dropdown-menu { 43 | display: none !important; 44 | } 45 | 46 | ul.wysihtml5-toolbar div.wysihtml5-colors { 47 | display:block; 48 | width: 50px; 49 | height: 20px; 50 | margin-top: 2px; 51 | margin-left: 5px; 52 | position: absolute; 53 | pointer-events: none; 54 | } 55 | 56 | ul.wysihtml5-toolbar a.wysihtml5-colors-title { 57 | padding-left: 70px; 58 | } 59 | 60 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="black"] { 61 | background: black !important; 62 | } 63 | 64 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="silver"] { 65 | background: silver !important; 66 | } 67 | 68 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="gray"] { 69 | background: gray !important; 70 | } 71 | 72 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="maroon"] { 73 | background: maroon !important; 74 | } 75 | 76 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="red"] { 77 | background: red !important; 78 | } 79 | 80 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="purple"] { 81 | background: purple !important; 82 | } 83 | 84 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="green"] { 85 | background: green !important; 86 | } 87 | 88 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="olive"] { 89 | background: olive !important; 90 | } 91 | 92 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="navy"] { 93 | background: navy !important; 94 | } 95 | 96 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="blue"] { 97 | background: blue !important; 98 | } 99 | 100 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="orange"] { 101 | background: orange !important; 102 | } 103 | -------------------------------------------------------------------------------- /test/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both thread web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 20 | # config.action_dispatch.rack_cache = true 21 | 22 | # Disable Rails's static asset server (Apache or nginx will already do this). 23 | # config.serve_static_assets = false 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = true 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = false 34 | 35 | # Version of your assets, change this if you want to expire all your assets. 36 | config.assets.version = '1.0' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Set to :debug to see everything in the log. 46 | config.log_level = :info 47 | 48 | # Prepend all log lines with the following tags. 49 | # config.log_tags = [ :subdomain, :uuid ] 50 | 51 | # Use a different logger for distributed setups. 52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 58 | # config.action_controller.asset_host = "http://assets.example.com" 59 | 60 | # Precompile additional assets. 61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 62 | # config.assets.precompile += %w( search.js ) 63 | 64 | # Ignore bad email addresses and do not raise email delivery errors. 65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 66 | # config.action_mailer.raise_delivery_errors = false 67 | 68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 69 | # the I18n.default_locale when a translation can not be found). 70 | config.i18n.fallbacks = true 71 | 72 | # Send deprecation notices to registered listeners. 73 | config.active_support.deprecation = :notify 74 | 75 | # Disable automatic flushing of the log to improve performance. 76 | # config.autoflush_log = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | end 81 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | x-editable-rails (1.5.5) 5 | railties 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actionmailer (4.2.4) 11 | actionpack (= 4.2.4) 12 | actionview (= 4.2.4) 13 | activejob (= 4.2.4) 14 | mail (~> 2.5, >= 2.5.4) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | actionpack (4.2.4) 17 | actionview (= 4.2.4) 18 | activesupport (= 4.2.4) 19 | rack (~> 1.6) 20 | rack-test (~> 0.6.2) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 23 | actionview (4.2.4) 24 | activesupport (= 4.2.4) 25 | builder (~> 3.1) 26 | erubis (~> 2.7.0) 27 | rails-dom-testing (~> 1.0, >= 1.0.5) 28 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 29 | activejob (4.2.4) 30 | activesupport (= 4.2.4) 31 | globalid (>= 0.3.0) 32 | activemodel (4.2.4) 33 | activesupport (= 4.2.4) 34 | builder (~> 3.1) 35 | activerecord (4.2.4) 36 | activemodel (= 4.2.4) 37 | activesupport (= 4.2.4) 38 | arel (~> 6.0) 39 | activesupport (4.2.4) 40 | i18n (~> 0.7) 41 | json (~> 1.7, >= 1.7.7) 42 | minitest (~> 5.1) 43 | thread_safe (~> 0.3, >= 0.3.4) 44 | tzinfo (~> 1.1) 45 | arel (6.0.3) 46 | autoprefixer-rails (6.0.3) 47 | execjs 48 | json 49 | bootstrap-sass (3.3.5) 50 | autoprefixer-rails (>= 5.0.0.1) 51 | sass (>= 3.2.19) 52 | builder (3.2.2) 53 | coffee-rails (4.1.0) 54 | coffee-script (>= 2.2.0) 55 | railties (>= 4.0.0, < 5.0) 56 | coffee-script (2.4.1) 57 | coffee-script-source 58 | execjs 59 | coffee-script-source (1.9.1.1) 60 | erubis (2.7.0) 61 | execjs (2.6.0) 62 | globalid (0.3.6) 63 | activesupport (>= 4.1.0) 64 | globalize (4.0.3) 65 | activemodel (>= 4.0.0, < 5) 66 | activerecord (>= 4.0.0, < 5) 67 | haml (4.0.7) 68 | tilt 69 | i18n (0.7.0) 70 | jquery-rails (4.2.1) 71 | rails-dom-testing (>= 1, < 3) 72 | railties (>= 4.2.0) 73 | thor (>= 0.14, < 2.0) 74 | json (1.8.3) 75 | loofah (2.0.3) 76 | nokogiri (>= 1.5.9) 77 | mail (2.6.3) 78 | mime-types (>= 1.16, < 3) 79 | mime-types (2.6.2) 80 | mini_portile (0.6.2) 81 | minitest (5.8.0) 82 | nokogiri (1.6.6.2) 83 | mini_portile (~> 0.6.0) 84 | pg (0.18.4) 85 | rack (1.6.4) 86 | rack-test (0.6.3) 87 | rack (>= 1.0) 88 | rails (4.2.4) 89 | actionmailer (= 4.2.4) 90 | actionpack (= 4.2.4) 91 | actionview (= 4.2.4) 92 | activejob (= 4.2.4) 93 | activemodel (= 4.2.4) 94 | activerecord (= 4.2.4) 95 | activesupport (= 4.2.4) 96 | bundler (>= 1.3.0, < 2.0) 97 | railties (= 4.2.4) 98 | sprockets-rails 99 | rails-deprecated_sanitizer (1.0.3) 100 | activesupport (>= 4.2.0.alpha) 101 | rails-dom-testing (1.0.7) 102 | activesupport (>= 4.2.0.beta, < 5.0) 103 | nokogiri (~> 1.6.0) 104 | rails-deprecated_sanitizer (>= 1.0.1) 105 | rails-html-sanitizer (1.0.2) 106 | loofah (~> 2.0) 107 | rails_12factor (0.0.3) 108 | rails_serve_static_assets 109 | rails_stdout_logging 110 | rails_serve_static_assets (0.0.4) 111 | rails_stdout_logging (0.0.4) 112 | railties (4.2.4) 113 | actionpack (= 4.2.4) 114 | activesupport (= 4.2.4) 115 | rake (>= 0.8.7) 116 | thor (>= 0.18.1, < 2.0) 117 | rake (10.4.2) 118 | responders (2.1.0) 119 | railties (>= 4.2.0, < 5) 120 | sass (3.4.19) 121 | sass-rails (5.0.6) 122 | railties (>= 4.0.0, < 6) 123 | sass (~> 3.1) 124 | sprockets (>= 2.8, < 4.0) 125 | sprockets-rails (>= 2.0, < 4.0) 126 | tilt (>= 1.1, < 3) 127 | sprockets (3.3.4) 128 | rack (~> 1.0) 129 | sprockets-rails (2.3.3) 130 | actionpack (>= 3.0) 131 | activesupport (>= 3.0) 132 | sprockets (>= 2.8, < 4.0) 133 | sqlite3 (1.3.10) 134 | thor (0.19.1) 135 | thread_safe (0.3.5) 136 | tilt (2.0.1) 137 | tzinfo (1.2.2) 138 | thread_safe (~> 0.1) 139 | uglifier (2.7.2) 140 | execjs (>= 0.3.0) 141 | json (>= 1.8.0) 142 | 143 | PLATFORMS 144 | ruby 145 | 146 | DEPENDENCIES 147 | bootstrap-sass 148 | coffee-rails 149 | globalize 150 | haml 151 | jquery-rails 152 | pg 153 | rails (~> 4.0) 154 | rails_12factor 155 | responders 156 | sass-rails 157 | sprockets 158 | sqlite3 159 | uglifier 160 | x-editable-rails! 161 | 162 | BUNDLED WITH 163 | 1.10.6 164 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/inputs-ext/wysihtml5-editable.js: -------------------------------------------------------------------------------- 1 | /** 2 | Bootstrap wysihtml5 editor. Based on [bootstrap-wysihtml5](https://github.com/jhollingworth/bootstrap-wysihtml5). 3 | You should include **manually** distributives of `wysihtml5` and `bootstrap-wysihtml5`: 4 | 5 | 6 | 7 | 8 | 9 | And also include `wysihtml5.js` from `inputs-ext` directory of x-editable: 10 | 11 | 12 | 13 | **Note:** It's better to use fresh bootstrap-wysihtml5 from it's [master branch](https://github.com/jhollingworth/bootstrap-wysihtml5/tree/master/src) as there is update for correct image insertion. 14 | 15 | @class wysihtml5 16 | @extends abstractinput 17 | @final 18 | @since 1.4.0 19 | @example 20 |

awesome

comment!
21 | 29 | **/ 30 | (function ($) { 31 | "use strict"; 32 | 33 | var Wysihtml5 = function (options) { 34 | this.init('wysihtml5', options, Wysihtml5.defaults); 35 | 36 | //extend wysihtml5 manually as $.extend not recursive 37 | this.options.wysihtml5 = $.extend({}, Wysihtml5.defaults.wysihtml5, options.wysihtml5); 38 | }; 39 | 40 | $.fn.editableutils.inherit(Wysihtml5, $.fn.editabletypes.abstractinput); 41 | 42 | $.extend(Wysihtml5.prototype, { 43 | render: function () { 44 | var deferred = $.Deferred(), 45 | msieOld; 46 | 47 | //generate unique id as it required for wysihtml5 48 | this.$input.attr('id', 'textarea_'+(new Date()).getTime()); 49 | 50 | this.setClass(); 51 | this.setAttr('placeholder'); 52 | 53 | //resolve deffered when widget loaded 54 | $.extend(this.options.wysihtml5, { 55 | events: { 56 | load: function() { 57 | deferred.resolve(); 58 | } 59 | } 60 | }); 61 | 62 | this.$input.wysihtml5(this.options.wysihtml5); 63 | 64 | /* 65 | In IE8 wysihtml5 iframe stays on the same line with buttons toolbar (inside popover). 66 | The only solution I found is to add
. If you fine better way, please send PR. 67 | */ 68 | msieOld = /msie\s*(8|7|6)/.test(navigator.userAgent.toLowerCase()); 69 | if(msieOld) { 70 | this.$input.before('

'); 71 | } 72 | 73 | return deferred.promise(); 74 | }, 75 | 76 | valueIsEncoded: true, 77 | 78 | value2html: function(value, element) { 79 | $(element).html(value); 80 | this.valueIsEncoded = false; 81 | }, 82 | 83 | html2value: function(html) { 84 | return html; 85 | }, 86 | 87 | value2input: function(value) { 88 | value = (this.valueIsEncoded ? this.base65decode(value) : value); 89 | this.$input.data("wysihtml5").editor.setValue(value, true); 90 | }, 91 | 92 | base65decode: function(value) { 93 | return decodeURIComponent( escape( atob( value.replace(/\s/g, '')))); 94 | }, 95 | 96 | activate: function() { 97 | this.$input.data("wysihtml5").editor.focus(); 98 | }, 99 | 100 | isEmpty: function($element) { 101 | if($.trim($element.html()) === '') { 102 | return true; 103 | } else if($.trim($element.text()) !== '') { 104 | return false; 105 | } else { 106 | //e.g. '', '
', '

' 107 | return !$element.height() || !$element.width(); 108 | } 109 | } 110 | }); 111 | 112 | Wysihtml5.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 113 | /** 114 | @property tpl 115 | @default 116 | **/ 117 | tpl:'', 118 | /** 119 | @property inputclass 120 | @default editable-wysihtml5 121 | **/ 122 | inputclass: 'editable-wysihtml5', 123 | /** 124 | Placeholder attribute of input. Shown when input is empty. 125 | 126 | @property placeholder 127 | @type string 128 | @default null 129 | **/ 130 | placeholder: null, 131 | /** 132 | Wysihtml5 default options. 133 | See https://github.com/jhollingworth/bootstrap-wysihtml5#options 134 | 135 | @property wysihtml5 136 | @type object 137 | @default {stylesheets: false} 138 | **/ 139 | wysihtml5: { 140 | stylesheets: false //see https://github.com/jhollingworth/bootstrap-wysihtml5/issues/183 141 | } 142 | }); 143 | 144 | $.fn.editabletypes.wysihtml5 = Wysihtml5; 145 | 146 | }(window.jQuery)); 147 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/jquery-editable.scss: -------------------------------------------------------------------------------- 1 | /*! X-editable - v1.5.0 2 | * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery 3 | * http://github.com/vitalets/x-editable 4 | * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ 5 | .editableform { 6 | margin-bottom: 0; /* overwrites bootstrap margin */ 7 | } 8 | 9 | .editableform .control-group { 10 | margin-bottom: 0; /* overwrites bootstrap margin */ 11 | white-space: nowrap; /* prevent wrapping buttons on new line */ 12 | line-height: 20px; /* overwriting bootstrap line-height. See #133 */ 13 | } 14 | 15 | .editable-buttons { 16 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 17 | vertical-align: top; 18 | margin-left: 7px; 19 | /* inline-block emulation for IE7*/ 20 | zoom: 1; 21 | *display: inline; 22 | } 23 | 24 | .editable-buttons.editable-buttons-bottom { 25 | display: block; 26 | margin-top: 7px; 27 | margin-left: 0; 28 | } 29 | 30 | .editable-input { 31 | vertical-align: top; 32 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 33 | width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ 34 | white-space: normal; /* reset white-space decalred in parent*/ 35 | /* display-inline emulation for IE7*/ 36 | zoom: 1; 37 | *display: inline; 38 | } 39 | 40 | .editable-buttons .editable-cancel { 41 | margin-left: 7px; 42 | } 43 | 44 | /*for jquery-ui buttons need set height to look more pretty*/ 45 | .editable-buttons button.ui-button-icon-only { 46 | height: 24px; 47 | width: 30px; 48 | } 49 | 50 | .editableform-loading { 51 | background: image-url('editable/loading.gif') center center no-repeat; 52 | height: 25px; 53 | width: auto; 54 | min-width: 25px; 55 | } 56 | 57 | .editable-inline .editableform-loading { 58 | background-position: left 5px; 59 | } 60 | 61 | .editable-error-block { 62 | max-width: 300px; 63 | margin: 5px 0 0 0; 64 | width: auto; 65 | white-space: normal; 66 | } 67 | 68 | /*add padding for jquery ui*/ 69 | .editable-error-block.ui-state-error { 70 | padding: 3px; 71 | } 72 | 73 | .editable-error { 74 | color: red; 75 | } 76 | 77 | /* ---- For specific types ---- */ 78 | 79 | .editableform .editable-date { 80 | padding: 0; 81 | margin: 0; 82 | float: left; 83 | } 84 | 85 | /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ 86 | .editable-inline .add-on .icon-th { 87 | margin-top: 3px; 88 | margin-left: 1px; 89 | } 90 | 91 | 92 | /* checklist vertical alignment */ 93 | .editable-checklist label input[type="checkbox"], 94 | .editable-checklist label span { 95 | vertical-align: middle; 96 | margin: 0; 97 | } 98 | 99 | .editable-checklist label { 100 | white-space: nowrap; 101 | } 102 | 103 | /* set exact width of textarea to fit buttons toolbar */ 104 | .editable-wysihtml5 { 105 | width: 566px; 106 | height: 250px; 107 | } 108 | 109 | /* clear button shown as link in date inputs */ 110 | .editable-clear { 111 | clear: both; 112 | font-size: 0.9em; 113 | text-decoration: none; 114 | text-align: right; 115 | } 116 | 117 | /* IOS-style clear button for text inputs */ 118 | .editable-clear-x { 119 | background: image-url('editable/clear.png') center center no-repeat; 120 | display: block; 121 | width: 13px; 122 | height: 13px; 123 | position: absolute; 124 | opacity: 0.6; 125 | z-index: 100; 126 | 127 | top: 50%; 128 | right: 6px; 129 | margin-top: -6px; 130 | 131 | } 132 | 133 | .editable-clear-x:hover { 134 | opacity: 1; 135 | } 136 | 137 | .editable-pre-wrapped { 138 | white-space: pre-wrap; 139 | } 140 | .editable-container.editable-popup { 141 | max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ 142 | } 143 | 144 | .editable-container.popover { 145 | width: auto; /* without this rule popover does not stretch */ 146 | } 147 | 148 | .editable-container.editable-inline { 149 | display: inline-block; 150 | vertical-align: middle; 151 | width: auto; 152 | /* inline-block emulation for IE7*/ 153 | zoom: 1; 154 | *display: inline; 155 | } 156 | 157 | .editable-container.ui-widget { 158 | font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ 159 | z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ 160 | } 161 | .editable-click, 162 | a.editable-click, 163 | a.editable-click:hover { 164 | text-decoration: none; 165 | border-bottom: dashed 1px #0088cc; 166 | } 167 | 168 | .editable-click.editable-disabled, 169 | a.editable-click.editable-disabled, 170 | a.editable-click.editable-disabled:hover { 171 | color: #585858; 172 | cursor: default; 173 | border-bottom: none; 174 | } 175 | 176 | .editable-empty, .editable-empty:hover, .editable-empty:focus{ 177 | font-style: italic; 178 | color: #DD1144; 179 | /* border-bottom: none; */ 180 | text-decoration: none; 181 | } 182 | 183 | .editable-unsaved { 184 | font-weight: bold; 185 | } 186 | 187 | .editable-unsaved:after { 188 | /* content: '*'*/ 189 | } 190 | 191 | .editable-bg-transition { 192 | -webkit-transition: background-color 1400ms ease-out; 193 | -moz-transition: background-color 1400ms ease-out; 194 | -o-transition: background-color 1400ms ease-out; 195 | -ms-transition: background-color 1400ms ease-out; 196 | transition: background-color 1400ms ease-out; 197 | } 198 | 199 | /*see https://github.com/vitalets/x-editable/issues/139 */ 200 | .form-horizontal .editable 201 | { 202 | padding-top: 5px; 203 | display:inline-block; 204 | } 205 | 206 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/jqueryui-editable.scss: -------------------------------------------------------------------------------- 1 | /*! X-editable - v1.5.0 2 | * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery 3 | * http://github.com/vitalets/x-editable 4 | * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ 5 | .editableform { 6 | margin-bottom: 0; /* overwrites bootstrap margin */ 7 | } 8 | 9 | .editableform .control-group { 10 | margin-bottom: 0; /* overwrites bootstrap margin */ 11 | white-space: nowrap; /* prevent wrapping buttons on new line */ 12 | line-height: 20px; /* overwriting bootstrap line-height. See #133 */ 13 | } 14 | 15 | .editable-buttons { 16 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 17 | vertical-align: top; 18 | margin-left: 7px; 19 | /* inline-block emulation for IE7*/ 20 | zoom: 1; 21 | *display: inline; 22 | } 23 | 24 | .editable-buttons.editable-buttons-bottom { 25 | display: block; 26 | margin-top: 7px; 27 | margin-left: 0; 28 | } 29 | 30 | .editable-input { 31 | vertical-align: top; 32 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 33 | width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ 34 | white-space: normal; /* reset white-space decalred in parent*/ 35 | /* display-inline emulation for IE7*/ 36 | zoom: 1; 37 | *display: inline; 38 | } 39 | 40 | .editable-buttons .editable-cancel { 41 | margin-left: 7px; 42 | } 43 | 44 | /*for jquery-ui buttons need set height to look more pretty*/ 45 | .editable-buttons button.ui-button-icon-only { 46 | height: 24px; 47 | width: 30px; 48 | } 49 | 50 | .editableform-loading { 51 | background: image-url('editable/loading.gif') center center no-repeat; 52 | height: 25px; 53 | width: auto; 54 | min-width: 25px; 55 | } 56 | 57 | .editable-inline .editableform-loading { 58 | background-position: left 5px; 59 | } 60 | 61 | .editable-error-block { 62 | max-width: 300px; 63 | margin: 5px 0 0 0; 64 | width: auto; 65 | white-space: normal; 66 | } 67 | 68 | /*add padding for jquery ui*/ 69 | .editable-error-block.ui-state-error { 70 | padding: 3px; 71 | } 72 | 73 | .editable-error { 74 | color: red; 75 | } 76 | 77 | /* ---- For specific types ---- */ 78 | 79 | .editableform .editable-date { 80 | padding: 0; 81 | margin: 0; 82 | float: left; 83 | } 84 | 85 | /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ 86 | .editable-inline .add-on .icon-th { 87 | margin-top: 3px; 88 | margin-left: 1px; 89 | } 90 | 91 | 92 | /* checklist vertical alignment */ 93 | .editable-checklist label input[type="checkbox"], 94 | .editable-checklist label span { 95 | vertical-align: middle; 96 | margin: 0; 97 | } 98 | 99 | .editable-checklist label { 100 | white-space: nowrap; 101 | } 102 | 103 | /* set exact width of textarea to fit buttons toolbar */ 104 | .editable-wysihtml5 { 105 | width: 566px; 106 | height: 250px; 107 | } 108 | 109 | /* clear button shown as link in date inputs */ 110 | .editable-clear { 111 | clear: both; 112 | font-size: 0.9em; 113 | text-decoration: none; 114 | text-align: right; 115 | } 116 | 117 | /* IOS-style clear button for text inputs */ 118 | .editable-clear-x { 119 | background: image-url('editable/clear.png') center center no-repeat; 120 | display: block; 121 | width: 13px; 122 | height: 13px; 123 | position: absolute; 124 | opacity: 0.6; 125 | z-index: 100; 126 | 127 | top: 50%; 128 | right: 6px; 129 | margin-top: -6px; 130 | 131 | } 132 | 133 | .editable-clear-x:hover { 134 | opacity: 1; 135 | } 136 | 137 | .editable-pre-wrapped { 138 | white-space: pre-wrap; 139 | } 140 | .editable-container.editable-popup { 141 | max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ 142 | } 143 | 144 | .editable-container.popover { 145 | width: auto; /* without this rule popover does not stretch */ 146 | } 147 | 148 | .editable-container.editable-inline { 149 | display: inline-block; 150 | vertical-align: middle; 151 | width: auto; 152 | /* inline-block emulation for IE7*/ 153 | zoom: 1; 154 | *display: inline; 155 | } 156 | 157 | .editable-container.ui-widget { 158 | font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ 159 | z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ 160 | } 161 | .editable-click, 162 | a.editable-click, 163 | a.editable-click:hover { 164 | text-decoration: none; 165 | border-bottom: dashed 1px #0088cc; 166 | } 167 | 168 | .editable-click.editable-disabled, 169 | a.editable-click.editable-disabled, 170 | a.editable-click.editable-disabled:hover { 171 | color: #585858; 172 | cursor: default; 173 | border-bottom: none; 174 | } 175 | 176 | .editable-empty, .editable-empty:hover, .editable-empty:focus{ 177 | font-style: italic; 178 | color: #DD1144; 179 | /* border-bottom: none; */ 180 | text-decoration: none; 181 | } 182 | 183 | .editable-unsaved { 184 | font-weight: bold; 185 | } 186 | 187 | .editable-unsaved:after { 188 | /* content: '*'*/ 189 | } 190 | 191 | .editable-bg-transition { 192 | -webkit-transition: background-color 1400ms ease-out; 193 | -moz-transition: background-color 1400ms ease-out; 194 | -o-transition: background-color 1400ms ease-out; 195 | -ms-transition: background-color 1400ms ease-out; 196 | transition: background-color 1400ms ease-out; 197 | } 198 | 199 | /*see https://github.com/vitalets/x-editable/issues/139 */ 200 | .form-horizontal .editable 201 | { 202 | padding-top: 5px; 203 | display:inline-block; 204 | } 205 | 206 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/inputs-ext/address.js: -------------------------------------------------------------------------------- 1 | /** 2 | Address editable input. 3 | Internally value stored as {city: "Moscow", street: "Lenina", building: "15"} 4 | 5 | @class address 6 | @extends abstractinput 7 | @final 8 | @example 9 | awesome 10 | 23 | **/ 24 | (function ($) { 25 | "use strict"; 26 | 27 | var Address = function (options) { 28 | this.init('address', options, Address.defaults); 29 | }; 30 | 31 | //inherit from Abstract input 32 | $.fn.editableutils.inherit(Address, $.fn.editabletypes.abstractinput); 33 | 34 | $.extend(Address.prototype, { 35 | /** 36 | Renders input from tpl 37 | 38 | @method render() 39 | **/ 40 | render: function() { 41 | this.$input = this.$tpl.find('input'); 42 | }, 43 | 44 | /** 45 | Default method to show value in element. Can be overwritten by display option. 46 | 47 | @method value2html(value, element) 48 | **/ 49 | value2html: function(value, element) { 50 | if(!value) { 51 | $(element).empty(); 52 | return; 53 | } 54 | var html = $('
').text(value.city).html() + ', ' + $('
').text(value.street).html() + ' st., bld. ' + $('
').text(value.building).html(); 55 | $(element).html(html); 56 | }, 57 | 58 | /** 59 | Gets value from element's html 60 | 61 | @method html2value(html) 62 | **/ 63 | html2value: function(html) { 64 | /* 65 | you may write parsing method to get value by element's html 66 | e.g. "Moscow, st. Lenina, bld. 15" => {city: "Moscow", street: "Lenina", building: "15"} 67 | but for complex structures it's not recommended. 68 | Better set value directly via javascript, e.g. 69 | editable({ 70 | value: { 71 | city: "Moscow", 72 | street: "Lenina", 73 | building: "15" 74 | } 75 | }); 76 | */ 77 | return null; 78 | }, 79 | 80 | /** 81 | Converts value to string. 82 | It is used in internal comparing (not for sending to server). 83 | 84 | @method value2str(value) 85 | **/ 86 | value2str: function(value) { 87 | var str = ''; 88 | if(value) { 89 | for(var k in value) { 90 | str = str + k + ':' + value[k] + ';'; 91 | } 92 | } 93 | return str; 94 | }, 95 | 96 | /* 97 | Converts string to value. Used for reading value from 'data-value' attribute. 98 | 99 | @method str2value(str) 100 | */ 101 | str2value: function(str) { 102 | /* 103 | this is mainly for parsing value defined in data-value attribute. 104 | If you will always set value by javascript, no need to overwrite it 105 | */ 106 | return str; 107 | }, 108 | 109 | /** 110 | Sets value of input. 111 | 112 | @method value2input(value) 113 | @param {mixed} value 114 | **/ 115 | value2input: function(value) { 116 | if(!value) { 117 | return; 118 | } 119 | this.$input.filter('[name="city"]').val(value.city); 120 | this.$input.filter('[name="street"]').val(value.street); 121 | this.$input.filter('[name="building"]').val(value.building); 122 | }, 123 | 124 | /** 125 | Returns value of input. 126 | 127 | @method input2value() 128 | **/ 129 | input2value: function() { 130 | return { 131 | city: this.$input.filter('[name="city"]').val(), 132 | street: this.$input.filter('[name="street"]').val(), 133 | building: this.$input.filter('[name="building"]').val() 134 | }; 135 | }, 136 | 137 | /** 138 | Activates input: sets focus on the first field. 139 | 140 | @method activate() 141 | **/ 142 | activate: function() { 143 | this.$input.filter('[name="city"]').focus(); 144 | }, 145 | 146 | /** 147 | Attaches handler to submit form in case of 'showbuttons=false' mode 148 | 149 | @method autosubmit() 150 | **/ 151 | autosubmit: function() { 152 | this.$input.keydown(function (e) { 153 | if (e.which === 13) { 154 | $(this).closest('form').submit(); 155 | } 156 | }); 157 | } 158 | }); 159 | 160 | Address.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 161 | tpl: '
'+ 162 | '
'+ 163 | '
', 164 | 165 | inputclass: '' 166 | }); 167 | 168 | $.fn.editabletypes.address = Address; 169 | 170 | }(window.jQuery)); -------------------------------------------------------------------------------- /test/view_helpers_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ViewHelpersTest < ActionView::TestCase 4 | include X::Editable::Rails::ViewHelpers 5 | 6 | class Subject < OpenStruct 7 | include ActiveModel::Model 8 | 9 | attr_accessor :id, :name, :content, :active 10 | 11 | def self.model_name 12 | ActiveModel::Name.new(self, nil, "Page") 13 | end 14 | 15 | def initialize(attributes={}) 16 | super(attributes.merge(id: 1, name: "test subject")) 17 | end 18 | end 19 | 20 | test "editable should escape unsafe values" do 21 | subject = Subject.new(content: "

unsafe content

") 22 | assert_match %r{<h1>unsafe content</h1>}, 23 | editable(subject, :content), 24 | "ViewHelpers#editable should escape unsafe content" 25 | end 26 | 27 | test "editable should NOT escape safe values" do 28 | subject = Subject.new(content: "

html_safe'd content

".html_safe) 29 | assert_match %r{

html_safe'd content

}, 30 | editable(subject, :content), 31 | "ViewHelpers#editable should not escape safe content" 32 | 33 | subject.content = "safe content" 34 | assert_match %r{safe content}, 35 | editable(subject, :content), 36 | "ViewHelpers#editable should not escape safe content" 37 | end 38 | 39 | test "editable should generate content tag with html options" do 40 | subject = Subject.new 41 | 42 | assert_match %r{]+id="subject-id"}, 43 | editable(subject, :name, html: { id: 'subject-id' }), 44 | "ViewHelpers#editable should generate content tag with html options" 45 | 46 | assert_match %r{]+name="subject\[name\]"}, 47 | editable(subject, :name, html: { name: 'subject[name]' }), 48 | "ViewHelpers#editable should generate content tag with html options" 49 | 50 | assert_match %r{]+title="First Title"}, 51 | editable(subject, :name, title: "First Title", html: { title: 'Second Title' }), 52 | "ViewHelpers#editable should generate content tag with html options" 53 | end 54 | 55 | test "editable should generate content tag with data attributes" do 56 | subject = Subject.new 57 | 58 | assert_match %r{]+data-model="page"}, 59 | editable(subject, :name), 60 | "ViewHelpers#editable should generate content tag with data attributes" 61 | 62 | assert_no_match %r{]+data-model="page"}, 63 | editable(subject, :name, model: "custom"), 64 | "ViewHelpers#editable should generate content tag with data attributes" 65 | end 66 | 67 | test "editable should generate content tag with the current value" do 68 | subject_1 = Subject.new(content: "foo") 69 | 70 | assert_match %r{]+>foo}, 71 | editable(subject_1, :content), 72 | "ViewHelpers#editable should generate content tag with the current value" 73 | 74 | assert_match %r{]+>foo}, 75 | editable(subject_1, :content, type: "select", source: ["foo", "bar"]), 76 | "ViewHelpers#editable should generate content tag with the current value" 77 | 78 | assert_match %r{]+>Foo}, 79 | editable(subject_1, :content, type: "select", source: [["foo", "Foo"], ["bar", "Bar"]]), 80 | "ViewHelpers#editable should generate content tag with the current value" 81 | 82 | assert_match %r{]+>Foo}, 83 | editable(subject_1, :content, type: "select", source: { "foo" => "Foo", "bar" => "Bar" }), 84 | "ViewHelpers#editable should generate content tag with the current value" 85 | 86 | assert_match %r{]+>Foo}, 87 | editable(subject_1, :content, type: "select", source: [{ text: "Foo", value: "foo" }, { text: "Bar", value: "bar" }]), 88 | "ViewHelpers#editable should generate content tag with the current value" 89 | 90 | refute_match %r{data-source=}, 91 | editable(subject_1, :content, type: "select"), 92 | "ViewHelpers#editable should generate content tag without source" 93 | 94 | subject_2 = Subject.new(active: true) 95 | 96 | assert_match %r{]+>Yes}, 97 | editable(subject_2, :active), 98 | "ViewHelpers#editable should generate content tag with the current value" 99 | end 100 | 101 | test "editable should store the source url as a data attribute" do 102 | subject = Subject.new 103 | assert_match %r{]+data-source="http://example.org"}, 104 | editable(subject, :name, type: "select", 105 | source: "http://example.org"), 106 | "ViewHelpers#editable should generate content tag with url source as a data attribute" 107 | end 108 | 109 | test "editable should generate content tag without current value" do 110 | subject_1 = Subject.new(content: nil) 111 | 112 | assert_match %r{]+>}, 113 | editable(subject_1, :content), 114 | "ViewHelpers#editable should generate content tag with the current value" 115 | 116 | assert_match %r{]+>}, 117 | editable(subject_1, :content, type: "select", source: ["foo", "bar"]), 118 | "ViewHelpers#editable should generate content tag with the current value" 119 | 120 | assert_match %r{]+>}, 121 | editable(subject_1, :content, type: "select", source: [["foo", "Foo"], ["bar", "Bar"]]), 122 | "ViewHelpers#editable should generate content tag with the current value" 123 | 124 | assert_match %r{]+>}, 125 | editable(subject_1, :content, type: "select", source: { "foo" => "Foo", "bar" => "Bar" }), 126 | "ViewHelpers#editable should generate content tag with the current value" 127 | 128 | assert_match %r{]+>}, 129 | editable(subject_1, :content, type: "select", source: [{ text: "Foo", value: "foo" }, { text: "Bar", value: "bar" }]), 130 | "ViewHelpers#editable should generate content tag with the current value" 131 | end 132 | 133 | private 134 | 135 | def view_helpers_test_subject_path(subject) 136 | "/#{subject.to_param}" 137 | end 138 | 139 | def xeditable?(*args) 140 | true 141 | end 142 | end 143 | -------------------------------------------------------------------------------- /lib/x-editable-rails/view_helpers.rb: -------------------------------------------------------------------------------- 1 | require 'base64' 2 | 3 | module X 4 | module Editable 5 | module Rails 6 | module ViewHelpers 7 | # 8 | # Options determine how the HTML tag is rendered and the remaining options are converted to data-* attributes. 9 | # 10 | # options: 11 | # tag: tag name of element returned 12 | # class: "class" attribute on element 13 | # placeholder: "placeholder" attribute on element 14 | # title: "title" attribute on element (defaults to placeholder) 15 | # data: "data-*" attributes on element 16 | # source: a Hash of friendly display values used by input elements based on (object) value 17 | # - boolean shorthand ['Enabled', 'Disabled'] becomes { '1' => 'Enabled', '0' => 'Disabled' } 18 | # - enumerable shorthand ['Yes', 'No', 'Maybe'] becomes { 'Yes' => 'Yes', 'No' => 'No', 'Maybe' => 'Maybe' } 19 | # classes: a Hash of classes to add based on the value (same format and shorthands as source) 20 | # value: override the object's value 21 | # 22 | def editable(object, method, options = {}) 23 | options = Configuration.method_options_for(object, method).deep_merge(options).with_indifferent_access 24 | # merge data attributes for backwards-compatibility 25 | options.merge! options.delete(:data){ Hash.new } 26 | 27 | url = options.delete(:url){ polymorphic_path(object) } 28 | object = object.last if object.kind_of?(Array) 29 | value = options.delete(:value){ object.send(method) } 30 | source = options[:source] ? format_source(options.delete(:source), value) : default_source_for(value) 31 | classes = format_source(options.delete(:classes), value) 32 | error = options.delete(:e) 33 | html_options = options.delete(:html){ Hash.new } 34 | 35 | if xeditable?(object) 36 | model = object.class.model_name.param_key 37 | nid = options.delete(:nid) 38 | nested = options.delete(:nested) 39 | title = options.delete(:title) do 40 | klass = nested ? object.class.const_get(nested.to_s.classify) : object.class 41 | klass.human_attribute_name(method) 42 | end 43 | 44 | output_value = output_value_for(value) 45 | css_list = options.delete(:class).to_s.split(/\s+/).unshift('editable') 46 | css_list << classes[output_value] if classes 47 | type = options.delete(:type){ default_type_for(value) } 48 | css = css_list.compact.uniq.join(' ') 49 | tag = options.delete(:tag){ 'span' } 50 | placeholder = options.delete(:placeholder){ title } 51 | 52 | # any remaining options become data attributes 53 | data = { 54 | type: type, 55 | model: model, 56 | name: method, 57 | value: ( type == 'wysihtml5' ? Base64.encode64(output_value) : output_value ), 58 | placeholder: placeholder, 59 | classes: classes, 60 | source: source, 61 | url: url, 62 | nested: nested, 63 | nid: nid 64 | }.merge(options.symbolize_keys) 65 | 66 | data.reject!{|_, value| value.nil?} 67 | 68 | html_options.update({ 69 | class: css, 70 | title: title, 71 | data: data 72 | }) 73 | 74 | content_tag tag, html_options do 75 | if %w(select checklist).include?(data[:type].to_s) && !source.is_a?(String) 76 | source = normalize_source(source) 77 | content = source.detect { |t| output_value == output_value_for(t[0]) } 78 | content.present? ? content[1] : "" 79 | else 80 | safe_join(source_values_for(value, source), tag(:br)) 81 | end 82 | end 83 | else 84 | error || safe_join(source_values_for(value || options[:emptytext], source), tag(:br)) 85 | end 86 | end 87 | 88 | private 89 | 90 | def normalize_source(source) 91 | return [] unless source 92 | source.map do |el| 93 | if el.is_a? Array 94 | el 95 | else 96 | [el[:value], el[:text]] 97 | end 98 | end 99 | end 100 | 101 | def output_value_for(value) 102 | value = case value 103 | when TrueClass 104 | '1' 105 | when FalseClass 106 | '0' 107 | when NilClass 108 | '' 109 | when Array 110 | value.map{|item| output_value_for item}.join(',') 111 | else 112 | value.to_s 113 | end 114 | 115 | value 116 | end 117 | 118 | def source_values_for(value, source = nil) 119 | source ||= default_source_for value 120 | 121 | values = Array.wrap(value) 122 | 123 | if source && ( source.first.is_a?(String) || source.kind_of?(Hash) ) 124 | values.map{|item| source[output_value_for item]} 125 | else 126 | values 127 | end 128 | end 129 | 130 | def default_type_for(value) 131 | case value 132 | when TrueClass, FalseClass 133 | 'select' 134 | when Array 135 | 'checklist' 136 | else 137 | 'text' 138 | end 139 | end 140 | 141 | def default_source_for(value) 142 | case value 143 | when TrueClass, FalseClass 144 | { '1' => 'Yes', '0' => 'No' } 145 | end 146 | end 147 | 148 | # helper method that take some shorthand source definitions and reformats them 149 | def format_source(source, value) 150 | formatted_source = case value 151 | when TrueClass, FalseClass 152 | if source.is_a?(Array) && source.first.is_a?(String) && source.size == 2 153 | { '1' => source[0], '0' => source[1] } 154 | end 155 | else 156 | if source.is_a?(Array) && source.first.is_a?(String) 157 | source.map { |v| { value: v, text: v } } 158 | end 159 | end 160 | 161 | formatted_source || source 162 | end 163 | 164 | end 165 | end 166 | end 167 | end 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # X::Editable::Rails 2 | 3 | [![Build Status](https://travis-ci.org/werein/x-editable-rails.svg)](https://travis-ci.org/werein/x-editable-rails) [![Code Climate](https://codeclimate.com/github/werein/x-editable-rails/badges/gpa.svg)](https://codeclimate.com/github/werein/x-editable-rails) [![Test coverage](https://codeclimate.com/github/werein/x-editable-rails/badges/coverage.svg)](https://codeclimate.com/github/werein/x-editable-rails) [![Version](https://badge.fury.io/rb/x-editable-rails.svg)](https://badge.fury.io/rb/x-editable-rails) [![Dependencies](https://gemnasium.com/werein/x-editable-rails.svg)](https://gemnasium.com/werein/x-editable-rails) 4 | 5 | X-editable for Rails 6 | 7 | ## Live demo 8 | 9 | Checkout live demo [here](https://x-editable-rails.herokuapp.com/?denied=true) 10 | 11 | ## Installation 12 | 13 | Add this line to your application's Gemfile: 14 | 15 | gem 'x-editable-rails' 16 | 17 | And then execute: 18 | 19 | $ bundle 20 | 21 | Or install it yourself as: 22 | 23 | $ gem install x-editable-rails 24 | 25 | ## Usage 26 | 27 | ### Assets 28 | 29 | Choose between the following javascripts: 30 | 31 | * bootstrap-editable 32 | * bootstrap2-editable 33 | * jqueryui-editable 34 | * jquery-editable-poshytip 35 | 36 | You'll also need to include editable/rails in your scripts for this to work. 37 | 38 | ```coffee 39 | #= require editable/bootstrap-editable 40 | #= require editable/rails 41 | ``` 42 | 43 | Choose the corresponding stylesheets: 44 | 45 | * bootstrap-editable 46 | * bootstrap2-editable 47 | * jqueryui-editable 48 | * jquery-editable 49 | 50 | ```scss 51 | // as CSS 52 | *= require editable/bootstrap-editable 53 | 54 | // or SCSS 55 | @import "editable/bootstrap-editable"; 56 | ``` 57 | 58 | Enable editing with jQuery: 59 | 60 | ```coffee 61 | $('.editable').editable() 62 | ``` 63 | 64 | For custom inputs like the Wysihtml5 editor, add these dependencies: 65 | 66 | ```coffee 67 | #= require editable/bootstrap-editable 68 | #= require editable/inputs-ext/wysihtml5 69 | #= require editable/inputs-ext/bootstrap-wysihtml5 70 | #= require editable/inputs-ext/wysihtml5-editable 71 | #= require editable/rails 72 | ``` 73 | 74 | And related stylesheets: 75 | 76 | ```css 77 | //= require editable/bootstrap-editable 78 | //= require editable/inputs-ext/bootstrap-wysihtml5 79 | //= require editable/inputs-ext/wysiwyg-color 80 | ``` 81 | 82 | ### Making Things Editable 83 | 84 | `x-editable-rails` provides a helper method in your view to make your model values editable. 85 | By default, you need to specify the model and property that should be editable. 86 | A `span` element is rendered with `data-*` attributes used by `x-editable`. 87 | 88 | ```ruby 89 | # the editable object and the attribute to edit 90 | %h1= editable @model, :name 91 | ``` 92 | 93 | You can customize the tag name and title attribute: 94 | 95 | * **tag** - `span` by default. 96 | * **title** - The model and attribute name are used to create a capitalized title 97 | 98 | The `editable` helper method automatically adds these `data-*` attributes used by [x-editable](http://vitalets.github.io/x-editable/docs.html). 99 | 100 | * **url** - Uses the `polymorphic_path(model)` helper method. 101 | * **source** - Only populated if the value is a boolean to convert `true` or `false` to "Yes" and "No". 102 | * **value** - Uses `model.name`. If `model.name` were a boolean value or if a `source` is specified, the `source` text would be displayed rather than the raw value. (Presumably the value is an ID and the source would have the text associated with that value.) 103 | * **placeholder** - Uses the `title` value by default 104 | 105 | ```ruby 106 | # editable object, what_you_want_update, e: exception - when is xeditable? false or can? :edit, object is false 107 | %h1= editable @model, :name, url: model_path, value: @model.name.upcase 108 | ``` 109 | 110 | Here are some special features to enhance what's baked into [x-editable](http://vitalets.github.io/x-editable/docs.html): 111 | 112 | * **type** - The type of input is automatically detected. By default, if the value is a boolean, the `type` is "select" with a built-in `source` that outputs "Yes" and "No" (unless another `source` is specified). 113 | * **source** - In addition to hashes or arrays of hashes, you can also use an array of strings for a simpler structure if the name and value are the same: 114 | 115 | ```ruby 116 | source = [ "Active", "Disabled" ] 117 | editable @model, :enabled, source: source 118 | ``` 119 | 120 | * **value** - This option will override the `model.name` value 121 | * **classes** - This is a custom option for `x-editable-rails` that will change the editable element's CSS class based on the selected value. Use the `source` hash structure to map a CSS class name to a value. (This [functionality](vendor/assets/javascripts/editable/rails/data_classes.js.coffee) is toggled when the value changes and the "save" event is triggered.) 122 | 123 | ```ruby 124 | source = [ "Active", "Disabled" ] 125 | classes = { "Active" => "label-success", "Disabled" => "label-default" } 126 | editable @model, :enabled, source: source, classes: classes, class: "label" 127 | ``` 128 | 129 | * **nested** - Name of a nested attributes (such as [globalize](https://github.com/globalize/globalize)'s `translations`) 130 | * **nid** - ID of the nested attribute 131 | 132 | ```ruby 133 | %h1= editable @model, :name, nested: :translations, nid: @model.translation.id 134 | 135 | # example of nested resource 136 | %h1= editable [picture.gallery, picture], :name, nested: :translations, nid: picture.translation.id 137 | ``` 138 | 139 | ### Authorization 140 | 141 | Add a helper method to your controllers to indicate if `x-editable` should be enabled. 142 | 143 | ```ruby 144 | def xeditable? object = nil 145 | true # Or something like current_user.xeditable? 146 | end 147 | ``` 148 | 149 | You can use [CanCan](https://github.com/ryanb/cancan) and checks the `:edit` permission for the model being edited. 150 | 151 | ```ruby 152 | def xeditable? object = nil 153 | can?(:edit, object) ? true : false 154 | end 155 | ``` 156 | 157 | * **e** - Specify a custom (error) message to display if the value isn't editable 158 | 159 | ### "Don't Repeat Yourself" Templates 160 | 161 | To make your views cleaner, you can specify all your options for each class and attribute in a YAML configuration file. 162 | Attributes where the `title` or `placeholder` are not different except maybe capitalized can be left out because they are automatically capitalized when rendered (see above). 163 | 164 | This example uses the `MailingList` class and its attributes. 165 | The attribute value can be a string, which is used as the `title` and `placeholder`. 166 | If you want to specify other options, create a hash of options. 167 | 168 | Install configuration file like this: `rails g x_editable_rails:install`, this step is not necessary 169 | 170 | ```yaml 171 | class_options: 172 | MailingList: 173 | # Specify placeholder text for each attribute or a Hash of options 174 | name: Mailing list name 175 | enabled: 176 | type: select 177 | source: 178 | - Active 179 | - Disabled 180 | reply_email: 181 | type: email 182 | title: Reply-to email 183 | User: 184 | email: 185 | type: email 186 | password: 187 | type: password 188 | mailing_lists: 189 | type: select 190 | # specify a URL to get source via AJAX (see x-editable docs) 191 | source: <%= ::Rails.application.routes.url_helpers.mailing_lists_source_path %> 192 | ``` 193 | 194 | Now you can specify your editable fields without options because they will be inherited from your YAML config. 195 | 196 | ```ruby 197 | model = MailingList.new 198 | 199 | editable model, :name # type: "text", title: "Mailing list name" 200 | editable model, :enabled # type: "select", title: "Enabled", source: [ "Active", "Disabled" ] 201 | ``` 202 | 203 | ### Examples 204 | 205 | Gem also contains demo application with integrated x-editable 206 | 207 | ``` 208 | cd test/dummy 209 | rake db:migrate 210 | rake db:seed 211 | rails g x_editable_rails:install # optional, it generate config example 212 | rails s 213 | ``` 214 | 215 | ## Contributing 216 | 217 | 1. Fork it 218 | 2. Create your feature branch (`git checkout -b my-new-feature`) 219 | 3. Commit your changes (`git commit -am 'Add some feature'`) 220 | 4. Push to the branch (`git push origin my-new-feature`) 221 | 5. Create new Pull Request 222 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/editable/inputs-ext/bootstrap-wysihtml5.js: -------------------------------------------------------------------------------- 1 | !function($, wysi) { 2 | "use strict"; 3 | 4 | var tpl = { 5 | "font-styles": function(locale, options) { 6 | var size = (options && options.size) ? ' btn-'+options.size : ''; 7 | return ""; 18 | }, 19 | 20 | "emphasis": function(locale, options) { 21 | var size = (options && options.size) ? ' btn-'+options.size : ''; 22 | return "
  • " + 23 | "" + 28 | "
  • "; 29 | }, 30 | 31 | "lists": function(locale, options) { 32 | var size = (options && options.size) ? ' btn-'+options.size : ''; 33 | return "
  • " + 34 | "
    " + 35 | "" + 36 | "" + 37 | "" + 38 | "" + 39 | "
    " + 40 | "
  • "; 41 | }, 42 | 43 | "link": function(locale, options) { 44 | var size = (options && options.size) ? ' btn-'+options.size : ''; 45 | return "
  • " + 46 | "" + 59 | "" + 60 | "
  • "; 61 | }, 62 | 63 | "image": function(locale, options) { 64 | var size = (options && options.size) ? ' btn-'+options.size : ''; 65 | return "
  • " + 66 | "" + 79 | "" + 80 | "
  • "; 81 | }, 82 | 83 | "html": function(locale, options) { 84 | var size = (options && options.size) ? ' btn-'+options.size : ''; 85 | return "
  • " + 86 | "
    " + 87 | "" + 88 | "
    " + 89 | "
  • "; 90 | }, 91 | 92 | "color": function(locale, options) { 93 | var size = (options && options.size) ? ' btn-'+options.size : ''; 94 | return ""; 112 | } 113 | }; 114 | 115 | var templates = function(key, locale, options) { 116 | return tpl[key](locale, options); 117 | }; 118 | 119 | 120 | var Wysihtml5 = function(el, options) { 121 | this.el = el; 122 | var toolbarOpts = options || defaultOptions; 123 | for(var t in toolbarOpts.customTemplates) { 124 | tpl[t] = toolbarOpts.customTemplates[t]; 125 | } 126 | this.toolbar = this.createToolbar(el, toolbarOpts); 127 | this.editor = this.createEditor(options); 128 | 129 | window.editor = this.editor; 130 | 131 | $('iframe.wysihtml5-sandbox').each(function(i, el){ 132 | $(el.contentWindow).off('focus.wysihtml5').on({ 133 | 'focus.wysihtml5' : function(){ 134 | $('li.dropdown').removeClass('open'); 135 | } 136 | }); 137 | }); 138 | }; 139 | 140 | Wysihtml5.prototype = { 141 | 142 | constructor: Wysihtml5, 143 | 144 | createEditor: function(options) { 145 | options = options || {}; 146 | 147 | // Add the toolbar to a clone of the options object so multiple instances 148 | // of the WYISYWG don't break because "toolbar" is already defined 149 | options = $.extend(true, {}, options); 150 | options.toolbar = this.toolbar[0]; 151 | 152 | var editor = new wysi.Editor(this.el[0], options); 153 | 154 | if(options && options.events) { 155 | for(var eventName in options.events) { 156 | editor.on(eventName, options.events[eventName]); 157 | } 158 | } 159 | return editor; 160 | }, 161 | 162 | createToolbar: function(el, options) { 163 | var self = this; 164 | var toolbar = $("
      ", { 165 | 'class' : "wysihtml5-toolbar", 166 | 'style': "display:none" 167 | }); 168 | var culture = options.locale || defaultOptions.locale || "en"; 169 | for(var key in defaultOptions) { 170 | var value = false; 171 | 172 | if(options[key] !== undefined) { 173 | if(options[key] === true) { 174 | value = true; 175 | } 176 | } else { 177 | value = defaultOptions[key]; 178 | } 179 | 180 | if(value === true) { 181 | toolbar.append(templates(key, locale[culture], options)); 182 | 183 | if(key === "html") { 184 | this.initHtml(toolbar); 185 | } 186 | 187 | if(key === "link") { 188 | this.initInsertLink(toolbar); 189 | } 190 | 191 | if(key === "image") { 192 | this.initInsertImage(toolbar); 193 | } 194 | } 195 | } 196 | 197 | if(options.toolbar) { 198 | for(key in options.toolbar) { 199 | toolbar.append(options.toolbar[key]); 200 | } 201 | } 202 | 203 | toolbar.find("a[data-wysihtml5-command='formatBlock']").click(function(e) { 204 | var target = e.target || e.srcElement; 205 | var el = $(target); 206 | self.toolbar.find('.current-font').text(el.html()); 207 | }); 208 | 209 | toolbar.find("a[data-wysihtml5-command='foreColor']").click(function(e) { 210 | var target = e.target || e.srcElement; 211 | var el = $(target); 212 | self.toolbar.find('.current-color').text(el.html()); 213 | }); 214 | 215 | this.el.before(toolbar); 216 | 217 | return toolbar; 218 | }, 219 | 220 | initHtml: function(toolbar) { 221 | var changeViewSelector = "a[data-wysihtml5-action='change_view']"; 222 | toolbar.find(changeViewSelector).click(function(e) { 223 | toolbar.find('a.btn').not(changeViewSelector).toggleClass('disabled'); 224 | }); 225 | }, 226 | 227 | initInsertImage: function(toolbar) { 228 | var self = this; 229 | var insertImageModal = toolbar.find('.bootstrap-wysihtml5-insert-image-modal'); 230 | var urlInput = insertImageModal.find('.bootstrap-wysihtml5-insert-image-url'); 231 | var insertButton = insertImageModal.find('a.btn-primary'); 232 | var initialValue = urlInput.val(); 233 | var caretBookmark; 234 | 235 | var insertImage = function() { 236 | var url = urlInput.val(); 237 | urlInput.val(initialValue); 238 | self.editor.currentView.element.focus(); 239 | if (caretBookmark) { 240 | self.editor.composer.selection.setBookmark(caretBookmark); 241 | caretBookmark = null; 242 | } 243 | self.editor.composer.commands.exec("insertImage", url); 244 | }; 245 | 246 | urlInput.keypress(function(e) { 247 | if(e.which == 13) { 248 | insertImage(); 249 | insertImageModal.modal('hide'); 250 | } 251 | }); 252 | 253 | insertButton.click(insertImage); 254 | 255 | insertImageModal.on('shown', function() { 256 | urlInput.focus(); 257 | }); 258 | 259 | insertImageModal.on('hide', function() { 260 | self.editor.currentView.element.focus(); 261 | }); 262 | 263 | toolbar.find('a[data-wysihtml5-command=insertImage]').click(function() { 264 | var activeButton = $(this).hasClass("wysihtml5-command-active"); 265 | 266 | if (!activeButton) { 267 | self.editor.currentView.element.focus(false); 268 | caretBookmark = self.editor.composer.selection.getBookmark(); 269 | insertImageModal.appendTo('body').modal('show'); 270 | insertImageModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) { 271 | e.stopPropagation(); 272 | }); 273 | return false; 274 | } 275 | else { 276 | return true; 277 | } 278 | }); 279 | }, 280 | 281 | initInsertLink: function(toolbar) { 282 | var self = this; 283 | var insertLinkModal = toolbar.find('.bootstrap-wysihtml5-insert-link-modal'); 284 | var urlInput = insertLinkModal.find('.bootstrap-wysihtml5-insert-link-url'); 285 | var insertButton = insertLinkModal.find('a.btn-primary'); 286 | var initialValue = urlInput.val(); 287 | var caretBookmark; 288 | 289 | var insertLink = function() { 290 | var url = urlInput.val(); 291 | urlInput.val(initialValue); 292 | self.editor.currentView.element.focus(); 293 | if (caretBookmark) { 294 | self.editor.composer.selection.setBookmark(caretBookmark); 295 | caretBookmark = null; 296 | } 297 | self.editor.composer.commands.exec("createLink", { 298 | href: url, 299 | target: "_blank", 300 | rel: "nofollow" 301 | }); 302 | }; 303 | var pressedEnter = false; 304 | 305 | urlInput.keypress(function(e) { 306 | if(e.which == 13) { 307 | insertLink(); 308 | insertLinkModal.modal('hide'); 309 | } 310 | }); 311 | 312 | insertButton.click(insertLink); 313 | 314 | insertLinkModal.on('shown', function() { 315 | urlInput.focus(); 316 | }); 317 | 318 | insertLinkModal.on('hide', function() { 319 | self.editor.currentView.element.focus(); 320 | }); 321 | 322 | toolbar.find('a[data-wysihtml5-command=createLink]').click(function() { 323 | var activeButton = $(this).hasClass("wysihtml5-command-active"); 324 | 325 | if (!activeButton) { 326 | self.editor.currentView.element.focus(false); 327 | caretBookmark = self.editor.composer.selection.getBookmark(); 328 | insertLinkModal.appendTo('body').modal('show'); 329 | insertLinkModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) { 330 | e.stopPropagation(); 331 | }); 332 | return false; 333 | } 334 | else { 335 | return true; 336 | } 337 | }); 338 | } 339 | }; 340 | 341 | // these define our public api 342 | var methods = { 343 | resetDefaults: function() { 344 | $.fn.wysihtml5.defaultOptions = $.extend(true, {}, $.fn.wysihtml5.defaultOptionsCache); 345 | }, 346 | bypassDefaults: function(options) { 347 | return this.each(function () { 348 | var $this = $(this); 349 | $this.data('wysihtml5', new Wysihtml5($this, options)); 350 | }); 351 | }, 352 | shallowExtend: function (options) { 353 | var settings = $.extend({}, $.fn.wysihtml5.defaultOptions, options || {}); 354 | var that = this; 355 | return methods.bypassDefaults.apply(that, [settings]); 356 | }, 357 | deepExtend: function(options) { 358 | var settings = $.extend(true, {}, $.fn.wysihtml5.defaultOptions, options || {}); 359 | var that = this; 360 | return methods.bypassDefaults.apply(that, [settings]); 361 | }, 362 | init: function(options) { 363 | var that = this; 364 | return methods.shallowExtend.apply(that, [options]); 365 | } 366 | }; 367 | 368 | $.fn.wysihtml5 = function ( method ) { 369 | if ( methods[method] ) { 370 | return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); 371 | } else if ( typeof method === 'object' || ! method ) { 372 | return methods.init.apply( this, arguments ); 373 | } else { 374 | $.error( 'Method ' + method + ' does not exist on jQuery.wysihtml5' ); 375 | } 376 | }; 377 | 378 | $.fn.wysihtml5.Constructor = Wysihtml5; 379 | 380 | var defaultOptions = $.fn.wysihtml5.defaultOptions = { 381 | "font-styles": true, 382 | "color": false, 383 | "emphasis": true, 384 | "lists": true, 385 | "html": false, 386 | "link": true, 387 | "image": true, 388 | events: {}, 389 | parserRules: { 390 | classes: { 391 | // (path_to_project/lib/css/wysiwyg-color.css) 392 | "wysiwyg-color-silver" : 1, 393 | "wysiwyg-color-gray" : 1, 394 | "wysiwyg-color-white" : 1, 395 | "wysiwyg-color-maroon" : 1, 396 | "wysiwyg-color-red" : 1, 397 | "wysiwyg-color-purple" : 1, 398 | "wysiwyg-color-fuchsia" : 1, 399 | "wysiwyg-color-green" : 1, 400 | "wysiwyg-color-lime" : 1, 401 | "wysiwyg-color-olive" : 1, 402 | "wysiwyg-color-yellow" : 1, 403 | "wysiwyg-color-navy" : 1, 404 | "wysiwyg-color-blue" : 1, 405 | "wysiwyg-color-teal" : 1, 406 | "wysiwyg-color-aqua" : 1, 407 | "wysiwyg-color-orange" : 1 408 | }, 409 | tags: { 410 | "b": {}, 411 | "i": {}, 412 | "br": {}, 413 | "ol": {}, 414 | "ul": {}, 415 | "li": {}, 416 | "h1": {}, 417 | "h2": {}, 418 | "h3": {}, 419 | "blockquote": {}, 420 | "u": 1, 421 | "img": { 422 | "check_attributes": { 423 | "width": "numbers", 424 | "alt": "alt", 425 | "src": "url", 426 | "height": "numbers" 427 | } 428 | }, 429 | "a": { 430 | set_attributes: { 431 | target: "_blank", 432 | rel: "nofollow" 433 | }, 434 | check_attributes: { 435 | href: "url" // important to avoid XSS 436 | } 437 | }, 438 | "span": 1, 439 | "div": 1, 440 | // to allow save and edit files with code tag hacks 441 | "code": 1, 442 | "pre": 1 443 | } 444 | }, 445 | stylesheets: ["./lib/css/wysiwyg-color.css"], // (path_to_project/lib/css/wysiwyg-color.css) 446 | locale: "en" 447 | }; 448 | 449 | if (typeof $.fn.wysihtml5.defaultOptionsCache === 'undefined') { 450 | $.fn.wysihtml5.defaultOptionsCache = $.extend(true, {}, $.fn.wysihtml5.defaultOptions); 451 | } 452 | 453 | var locale = $.fn.wysihtml5.locale = { 454 | en: { 455 | font_styles: { 456 | normal: "Normal text", 457 | h1: "Heading 1", 458 | h2: "Heading 2", 459 | h3: "Heading 3" 460 | }, 461 | emphasis: { 462 | bold: "Bold", 463 | italic: "Italic", 464 | underline: "Underline" 465 | }, 466 | lists: { 467 | unordered: "Unordered list", 468 | ordered: "Ordered list", 469 | outdent: "Outdent", 470 | indent: "Indent" 471 | }, 472 | link: { 473 | insert: "Insert link", 474 | cancel: "Cancel" 475 | }, 476 | image: { 477 | insert: "Insert image", 478 | cancel: "Cancel" 479 | }, 480 | html: { 481 | edit: "Edit HTML" 482 | }, 483 | colours: { 484 | black: "Black", 485 | silver: "Silver", 486 | gray: "Grey", 487 | maroon: "Maroon", 488 | red: "Red", 489 | purple: "Purple", 490 | green: "Green", 491 | olive: "Olive", 492 | navy: "Navy", 493 | blue: "Blue", 494 | orange: "Orange" 495 | } 496 | } 497 | }; 498 | 499 | }(window.jQuery, window.wysihtml5); 500 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/bootstrap-editable.scss: -------------------------------------------------------------------------------- 1 | /*! X-editable - v1.5.0 2 | * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery 3 | * http://github.com/vitalets/x-editable 4 | * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ 5 | .editableform { 6 | margin-bottom: 0; /* overwrites bootstrap margin */ 7 | } 8 | 9 | .editableform .control-group { 10 | margin-bottom: 0; /* overwrites bootstrap margin */ 11 | white-space: nowrap; /* prevent wrapping buttons on new line */ 12 | line-height: 20px; /* overwriting bootstrap line-height. See #133 */ 13 | } 14 | 15 | .editable-buttons { 16 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 17 | vertical-align: top; 18 | margin-left: 7px; 19 | /* inline-block emulation for IE7*/ 20 | zoom: 1; 21 | *display: inline; 22 | } 23 | 24 | .editable-buttons.editable-buttons-bottom { 25 | display: block; 26 | margin-top: 7px; 27 | margin-left: 0; 28 | } 29 | 30 | .editable-input { 31 | vertical-align: top; 32 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 33 | width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ 34 | white-space: normal; /* reset white-space decalred in parent*/ 35 | /* display-inline emulation for IE7*/ 36 | zoom: 1; 37 | *display: inline; 38 | } 39 | 40 | .editable-buttons .editable-cancel { 41 | margin-left: 7px; 42 | } 43 | 44 | /*for jquery-ui buttons need set height to look more pretty*/ 45 | .editable-buttons button.ui-button-icon-only { 46 | height: 24px; 47 | width: 30px; 48 | } 49 | 50 | .editableform-loading { 51 | background: image-url('editable/loading.gif') center center no-repeat; 52 | height: 25px; 53 | width: auto; 54 | min-width: 25px; 55 | } 56 | 57 | .editable-inline .editableform-loading { 58 | background-position: left 5px; 59 | } 60 | 61 | .editable-error-block { 62 | max-width: 300px; 63 | margin: 5px 0 0 0; 64 | width: auto; 65 | white-space: normal; 66 | } 67 | 68 | /*add padding for jquery ui*/ 69 | .editable-error-block.ui-state-error { 70 | padding: 3px; 71 | } 72 | 73 | .editable-error { 74 | color: red; 75 | } 76 | 77 | /* ---- For specific types ---- */ 78 | 79 | .editableform .editable-date { 80 | padding: 0; 81 | margin: 0; 82 | float: left; 83 | } 84 | 85 | /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ 86 | .editable-inline .add-on .icon-th { 87 | margin-top: 3px; 88 | margin-left: 1px; 89 | } 90 | 91 | 92 | /* checklist vertical alignment */ 93 | .editable-checklist label input[type="checkbox"], 94 | .editable-checklist label span { 95 | vertical-align: middle; 96 | margin: 0; 97 | } 98 | 99 | .editable-checklist label { 100 | white-space: nowrap; 101 | } 102 | 103 | /* set exact width of textarea to fit buttons toolbar */ 104 | .editable-wysihtml5 { 105 | width: 566px; 106 | height: 250px; 107 | } 108 | 109 | /* clear button shown as link in date inputs */ 110 | .editable-clear { 111 | clear: both; 112 | font-size: 0.9em; 113 | text-decoration: none; 114 | text-align: right; 115 | } 116 | 117 | /* IOS-style clear button for text inputs */ 118 | .editable-clear-x { 119 | background: image-url('editable/clear.png') center center no-repeat; 120 | display: block; 121 | width: 13px; 122 | height: 13px; 123 | position: absolute; 124 | opacity: 0.6; 125 | z-index: 100; 126 | 127 | top: 50%; 128 | right: 6px; 129 | margin-top: -6px; 130 | 131 | } 132 | 133 | .editable-clear-x:hover { 134 | opacity: 1; 135 | } 136 | 137 | .editable-pre-wrapped { 138 | white-space: pre-wrap; 139 | } 140 | .editable-container.editable-popup { 141 | max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ 142 | } 143 | 144 | .editable-container.popover { 145 | width: auto; /* without this rule popover does not stretch */ 146 | } 147 | 148 | .editable-container.editable-inline { 149 | display: inline-block; 150 | vertical-align: middle; 151 | width: auto; 152 | /* inline-block emulation for IE7*/ 153 | zoom: 1; 154 | *display: inline; 155 | } 156 | 157 | .editable-container.ui-widget { 158 | font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ 159 | z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ 160 | } 161 | .editable-click, 162 | a.editable-click, 163 | a.editable-click:hover { 164 | text-decoration: none; 165 | border-bottom: dashed 1px #0088cc; 166 | } 167 | 168 | .editable-click.editable-disabled, 169 | a.editable-click.editable-disabled, 170 | a.editable-click.editable-disabled:hover { 171 | color: #585858; 172 | cursor: default; 173 | border-bottom: none; 174 | } 175 | 176 | .editable-empty, .editable-empty:hover, .editable-empty:focus{ 177 | font-style: italic; 178 | color: #DD1144; 179 | /* border-bottom: none; */ 180 | text-decoration: none; 181 | } 182 | 183 | .editable-unsaved { 184 | font-weight: bold; 185 | } 186 | 187 | .editable-unsaved:after { 188 | /* content: '*'*/ 189 | } 190 | 191 | .editable-bg-transition { 192 | -webkit-transition: background-color 1400ms ease-out; 193 | -moz-transition: background-color 1400ms ease-out; 194 | -o-transition: background-color 1400ms ease-out; 195 | -ms-transition: background-color 1400ms ease-out; 196 | transition: background-color 1400ms ease-out; 197 | } 198 | 199 | /*see https://github.com/vitalets/x-editable/issues/139 */ 200 | .form-horizontal .editable 201 | { 202 | padding-top: 5px; 203 | display:inline-block; 204 | } 205 | 206 | 207 | /*! 208 | * Datepicker for Bootstrap 209 | * 210 | * Copyright 2012 Stefan Petre 211 | * Improvements by Andrew Rowls 212 | * Licensed under the Apache License v2.0 213 | * http://www.apache.org/licenses/LICENSE-2.0 214 | * 215 | */ 216 | .datepicker { 217 | padding: 4px; 218 | -webkit-border-radius: 4px; 219 | -moz-border-radius: 4px; 220 | border-radius: 4px; 221 | direction: ltr; 222 | /*.dow { 223 | border-top: 1px solid #ddd !important; 224 | }*/ 225 | 226 | } 227 | .datepicker-inline { 228 | width: 220px; 229 | } 230 | .datepicker.datepicker-rtl { 231 | direction: rtl; 232 | } 233 | .datepicker.datepicker-rtl table tr td span { 234 | float: right; 235 | } 236 | .datepicker-dropdown { 237 | top: 0; 238 | left: 0; 239 | } 240 | .datepicker-dropdown:before { 241 | content: ''; 242 | display: inline-block; 243 | border-left: 7px solid transparent; 244 | border-right: 7px solid transparent; 245 | border-bottom: 7px solid #ccc; 246 | border-bottom-color: rgba(0, 0, 0, 0.2); 247 | position: absolute; 248 | top: -7px; 249 | left: 6px; 250 | } 251 | .datepicker-dropdown:after { 252 | content: ''; 253 | display: inline-block; 254 | border-left: 6px solid transparent; 255 | border-right: 6px solid transparent; 256 | border-bottom: 6px solid #ffffff; 257 | position: absolute; 258 | top: -6px; 259 | left: 7px; 260 | } 261 | .datepicker > div { 262 | display: none; 263 | } 264 | .datepicker.days div.datepicker-days { 265 | display: block; 266 | } 267 | .datepicker.months div.datepicker-months { 268 | display: block; 269 | } 270 | .datepicker.years div.datepicker-years { 271 | display: block; 272 | } 273 | .datepicker table { 274 | margin: 0; 275 | } 276 | .datepicker td, 277 | .datepicker th { 278 | text-align: center; 279 | width: 20px; 280 | height: 20px; 281 | -webkit-border-radius: 4px; 282 | -moz-border-radius: 4px; 283 | border-radius: 4px; 284 | border: none; 285 | } 286 | .table-striped .datepicker table tr td, 287 | .table-striped .datepicker table tr th { 288 | background-color: transparent; 289 | } 290 | .datepicker table tr td.day:hover { 291 | background: #eeeeee; 292 | cursor: pointer; 293 | } 294 | .datepicker table tr td.old, 295 | .datepicker table tr td.new { 296 | color: #999999; 297 | } 298 | .datepicker table tr td.disabled, 299 | .datepicker table tr td.disabled:hover { 300 | background: none; 301 | color: #999999; 302 | cursor: default; 303 | } 304 | .datepicker table tr td.today, 305 | .datepicker table tr td.today:hover, 306 | .datepicker table tr td.today.disabled, 307 | .datepicker table tr td.today.disabled:hover { 308 | background-color: #fde19a; 309 | background-image: -moz-linear-gradient(to bottom, #fdd49a, #fdf59a); 310 | background-image: -ms-linear-gradient(to bottom, #fdd49a, #fdf59a); 311 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); 312 | background-image: -webkit-linear-gradient(to bottom, #fdd49a, #fdf59a); 313 | background-image: -o-linear-gradient(to bottom, #fdd49a, #fdf59a); 314 | background-image: linear-gradient(to bottom, #fdd49a, #fdf59a); 315 | background-repeat: repeat-x; 316 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); 317 | border-color: #fdf59a #fdf59a #fbed50; 318 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 319 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 320 | color: #000; 321 | } 322 | .datepicker table tr td.today:hover, 323 | .datepicker table tr td.today:hover:hover, 324 | .datepicker table tr td.today.disabled:hover, 325 | .datepicker table tr td.today.disabled:hover:hover, 326 | .datepicker table tr td.today:active, 327 | .datepicker table tr td.today:hover:active, 328 | .datepicker table tr td.today.disabled:active, 329 | .datepicker table tr td.today.disabled:hover:active, 330 | .datepicker table tr td.today.active, 331 | .datepicker table tr td.today:hover.active, 332 | .datepicker table tr td.today.disabled.active, 333 | .datepicker table tr td.today.disabled:hover.active, 334 | .datepicker table tr td.today.disabled, 335 | .datepicker table tr td.today:hover.disabled, 336 | .datepicker table tr td.today.disabled.disabled, 337 | .datepicker table tr td.today.disabled:hover.disabled, 338 | .datepicker table tr td.today[disabled], 339 | .datepicker table tr td.today:hover[disabled], 340 | .datepicker table tr td.today.disabled[disabled], 341 | .datepicker table tr td.today.disabled:hover[disabled] { 342 | background-color: #fdf59a; 343 | } 344 | .datepicker table tr td.today:active, 345 | .datepicker table tr td.today:hover:active, 346 | .datepicker table tr td.today.disabled:active, 347 | .datepicker table tr td.today.disabled:hover:active, 348 | .datepicker table tr td.today.active, 349 | .datepicker table tr td.today:hover.active, 350 | .datepicker table tr td.today.disabled.active, 351 | .datepicker table tr td.today.disabled:hover.active { 352 | background-color: #fbf069 \9; 353 | } 354 | .datepicker table tr td.today:hover:hover { 355 | color: #000; 356 | } 357 | .datepicker table tr td.today.active:hover { 358 | color: #fff; 359 | } 360 | .datepicker table tr td.range, 361 | .datepicker table tr td.range:hover, 362 | .datepicker table tr td.range.disabled, 363 | .datepicker table tr td.range.disabled:hover { 364 | background: #eeeeee; 365 | -webkit-border-radius: 0; 366 | -moz-border-radius: 0; 367 | border-radius: 0; 368 | } 369 | .datepicker table tr td.range.today, 370 | .datepicker table tr td.range.today:hover, 371 | .datepicker table tr td.range.today.disabled, 372 | .datepicker table tr td.range.today.disabled:hover { 373 | background-color: #f3d17a; 374 | background-image: -moz-linear-gradient(to bottom, #f3c17a, #f3e97a); 375 | background-image: -ms-linear-gradient(to bottom, #f3c17a, #f3e97a); 376 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); 377 | background-image: -webkit-linear-gradient(to bottom, #f3c17a, #f3e97a); 378 | background-image: -o-linear-gradient(to bottom, #f3c17a, #f3e97a); 379 | background-image: linear-gradient(to bottom, #f3c17a, #f3e97a); 380 | background-repeat: repeat-x; 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); 382 | border-color: #f3e97a #f3e97a #edde34; 383 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 384 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 385 | -webkit-border-radius: 0; 386 | -moz-border-radius: 0; 387 | border-radius: 0; 388 | } 389 | .datepicker table tr td.range.today:hover, 390 | .datepicker table tr td.range.today:hover:hover, 391 | .datepicker table tr td.range.today.disabled:hover, 392 | .datepicker table tr td.range.today.disabled:hover:hover, 393 | .datepicker table tr td.range.today:active, 394 | .datepicker table tr td.range.today:hover:active, 395 | .datepicker table tr td.range.today.disabled:active, 396 | .datepicker table tr td.range.today.disabled:hover:active, 397 | .datepicker table tr td.range.today.active, 398 | .datepicker table tr td.range.today:hover.active, 399 | .datepicker table tr td.range.today.disabled.active, 400 | .datepicker table tr td.range.today.disabled:hover.active, 401 | .datepicker table tr td.range.today.disabled, 402 | .datepicker table tr td.range.today:hover.disabled, 403 | .datepicker table tr td.range.today.disabled.disabled, 404 | .datepicker table tr td.range.today.disabled:hover.disabled, 405 | .datepicker table tr td.range.today[disabled], 406 | .datepicker table tr td.range.today:hover[disabled], 407 | .datepicker table tr td.range.today.disabled[disabled], 408 | .datepicker table tr td.range.today.disabled:hover[disabled] { 409 | background-color: #f3e97a; 410 | } 411 | .datepicker table tr td.range.today:active, 412 | .datepicker table tr td.range.today:hover:active, 413 | .datepicker table tr td.range.today.disabled:active, 414 | .datepicker table tr td.range.today.disabled:hover:active, 415 | .datepicker table tr td.range.today.active, 416 | .datepicker table tr td.range.today:hover.active, 417 | .datepicker table tr td.range.today.disabled.active, 418 | .datepicker table tr td.range.today.disabled:hover.active { 419 | background-color: #efe24b \9; 420 | } 421 | .datepicker table tr td.selected, 422 | .datepicker table tr td.selected:hover, 423 | .datepicker table tr td.selected.disabled, 424 | .datepicker table tr td.selected.disabled:hover { 425 | background-color: #9e9e9e; 426 | background-image: -moz-linear-gradient(to bottom, #b3b3b3, #808080); 427 | background-image: -ms-linear-gradient(to bottom, #b3b3b3, #808080); 428 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); 429 | background-image: -webkit-linear-gradient(to bottom, #b3b3b3, #808080); 430 | background-image: -o-linear-gradient(to bottom, #b3b3b3, #808080); 431 | background-image: linear-gradient(to bottom, #b3b3b3, #808080); 432 | background-repeat: repeat-x; 433 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); 434 | border-color: #808080 #808080 #595959; 435 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 436 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 437 | color: #fff; 438 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 439 | } 440 | .datepicker table tr td.selected:hover, 441 | .datepicker table tr td.selected:hover:hover, 442 | .datepicker table tr td.selected.disabled:hover, 443 | .datepicker table tr td.selected.disabled:hover:hover, 444 | .datepicker table tr td.selected:active, 445 | .datepicker table tr td.selected:hover:active, 446 | .datepicker table tr td.selected.disabled:active, 447 | .datepicker table tr td.selected.disabled:hover:active, 448 | .datepicker table tr td.selected.active, 449 | .datepicker table tr td.selected:hover.active, 450 | .datepicker table tr td.selected.disabled.active, 451 | .datepicker table tr td.selected.disabled:hover.active, 452 | .datepicker table tr td.selected.disabled, 453 | .datepicker table tr td.selected:hover.disabled, 454 | .datepicker table tr td.selected.disabled.disabled, 455 | .datepicker table tr td.selected.disabled:hover.disabled, 456 | .datepicker table tr td.selected[disabled], 457 | .datepicker table tr td.selected:hover[disabled], 458 | .datepicker table tr td.selected.disabled[disabled], 459 | .datepicker table tr td.selected.disabled:hover[disabled] { 460 | background-color: #808080; 461 | } 462 | .datepicker table tr td.selected:active, 463 | .datepicker table tr td.selected:hover:active, 464 | .datepicker table tr td.selected.disabled:active, 465 | .datepicker table tr td.selected.disabled:hover:active, 466 | .datepicker table tr td.selected.active, 467 | .datepicker table tr td.selected:hover.active, 468 | .datepicker table tr td.selected.disabled.active, 469 | .datepicker table tr td.selected.disabled:hover.active { 470 | background-color: #666666 \9; 471 | } 472 | .datepicker table tr td.active, 473 | .datepicker table tr td.active:hover, 474 | .datepicker table tr td.active.disabled, 475 | .datepicker table tr td.active.disabled:hover { 476 | background-color: #006dcc; 477 | background-image: -moz-linear-gradient(to bottom, #0088cc, #0044cc); 478 | background-image: -ms-linear-gradient(to bottom, #0088cc, #0044cc); 479 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 480 | background-image: -webkit-linear-gradient(to bottom, #0088cc, #0044cc); 481 | background-image: -o-linear-gradient(to bottom, #0088cc, #0044cc); 482 | background-image: linear-gradient(to bottom, #0088cc, #0044cc); 483 | background-repeat: repeat-x; 484 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 485 | border-color: #0044cc #0044cc #002a80; 486 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 487 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 488 | color: #fff; 489 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 490 | } 491 | .datepicker table tr td.active:hover, 492 | .datepicker table tr td.active:hover:hover, 493 | .datepicker table tr td.active.disabled:hover, 494 | .datepicker table tr td.active.disabled:hover:hover, 495 | .datepicker table tr td.active:active, 496 | .datepicker table tr td.active:hover:active, 497 | .datepicker table tr td.active.disabled:active, 498 | .datepicker table tr td.active.disabled:hover:active, 499 | .datepicker table tr td.active.active, 500 | .datepicker table tr td.active:hover.active, 501 | .datepicker table tr td.active.disabled.active, 502 | .datepicker table tr td.active.disabled:hover.active, 503 | .datepicker table tr td.active.disabled, 504 | .datepicker table tr td.active:hover.disabled, 505 | .datepicker table tr td.active.disabled.disabled, 506 | .datepicker table tr td.active.disabled:hover.disabled, 507 | .datepicker table tr td.active[disabled], 508 | .datepicker table tr td.active:hover[disabled], 509 | .datepicker table tr td.active.disabled[disabled], 510 | .datepicker table tr td.active.disabled:hover[disabled] { 511 | background-color: #0044cc; 512 | } 513 | .datepicker table tr td.active:active, 514 | .datepicker table tr td.active:hover:active, 515 | .datepicker table tr td.active.disabled:active, 516 | .datepicker table tr td.active.disabled:hover:active, 517 | .datepicker table tr td.active.active, 518 | .datepicker table tr td.active:hover.active, 519 | .datepicker table tr td.active.disabled.active, 520 | .datepicker table tr td.active.disabled:hover.active { 521 | background-color: #003399 \9; 522 | } 523 | .datepicker table tr td span { 524 | display: block; 525 | width: 23%; 526 | height: 54px; 527 | line-height: 54px; 528 | float: left; 529 | margin: 1%; 530 | cursor: pointer; 531 | -webkit-border-radius: 4px; 532 | -moz-border-radius: 4px; 533 | border-radius: 4px; 534 | } 535 | .datepicker table tr td span:hover { 536 | background: #eeeeee; 537 | } 538 | .datepicker table tr td span.disabled, 539 | .datepicker table tr td span.disabled:hover { 540 | background: none; 541 | color: #999999; 542 | cursor: default; 543 | } 544 | .datepicker table tr td span.active, 545 | .datepicker table tr td span.active:hover, 546 | .datepicker table tr td span.active.disabled, 547 | .datepicker table tr td span.active.disabled:hover { 548 | background-color: #006dcc; 549 | background-image: -moz-linear-gradient(to bottom, #0088cc, #0044cc); 550 | background-image: -ms-linear-gradient(to bottom, #0088cc, #0044cc); 551 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 552 | background-image: -webkit-linear-gradient(to bottom, #0088cc, #0044cc); 553 | background-image: -o-linear-gradient(to bottom, #0088cc, #0044cc); 554 | background-image: linear-gradient(to bottom, #0088cc, #0044cc); 555 | background-repeat: repeat-x; 556 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 557 | border-color: #0044cc #0044cc #002a80; 558 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 559 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 560 | color: #fff; 561 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 562 | } 563 | .datepicker table tr td span.active:hover, 564 | .datepicker table tr td span.active:hover:hover, 565 | .datepicker table tr td span.active.disabled:hover, 566 | .datepicker table tr td span.active.disabled:hover:hover, 567 | .datepicker table tr td span.active:active, 568 | .datepicker table tr td span.active:hover:active, 569 | .datepicker table tr td span.active.disabled:active, 570 | .datepicker table tr td span.active.disabled:hover:active, 571 | .datepicker table tr td span.active.active, 572 | .datepicker table tr td span.active:hover.active, 573 | .datepicker table tr td span.active.disabled.active, 574 | .datepicker table tr td span.active.disabled:hover.active, 575 | .datepicker table tr td span.active.disabled, 576 | .datepicker table tr td span.active:hover.disabled, 577 | .datepicker table tr td span.active.disabled.disabled, 578 | .datepicker table tr td span.active.disabled:hover.disabled, 579 | .datepicker table tr td span.active[disabled], 580 | .datepicker table tr td span.active:hover[disabled], 581 | .datepicker table tr td span.active.disabled[disabled], 582 | .datepicker table tr td span.active.disabled:hover[disabled] { 583 | background-color: #0044cc; 584 | } 585 | .datepicker table tr td span.active:active, 586 | .datepicker table tr td span.active:hover:active, 587 | .datepicker table tr td span.active.disabled:active, 588 | .datepicker table tr td span.active.disabled:hover:active, 589 | .datepicker table tr td span.active.active, 590 | .datepicker table tr td span.active:hover.active, 591 | .datepicker table tr td span.active.disabled.active, 592 | .datepicker table tr td span.active.disabled:hover.active { 593 | background-color: #003399 \9; 594 | } 595 | .datepicker table tr td span.old, 596 | .datepicker table tr td span.new { 597 | color: #999999; 598 | } 599 | .datepicker th.datepicker-switch { 600 | width: 145px; 601 | } 602 | .datepicker thead tr:first-child th, 603 | .datepicker tfoot tr th { 604 | cursor: pointer; 605 | } 606 | .datepicker thead tr:first-child th:hover, 607 | .datepicker tfoot tr th:hover { 608 | background: #eeeeee; 609 | } 610 | .datepicker .cw { 611 | font-size: 10px; 612 | width: 12px; 613 | padding: 0 2px 0 5px; 614 | vertical-align: middle; 615 | } 616 | .datepicker thead tr:first-child th.cw { 617 | cursor: default; 618 | background-color: transparent; 619 | } 620 | .input-append.date .add-on i, 621 | .input-prepend.date .add-on i { 622 | display: block; 623 | cursor: pointer; 624 | width: 16px; 625 | height: 16px; 626 | } 627 | .input-daterange input { 628 | text-align: center; 629 | } 630 | .input-daterange input:first-child { 631 | -webkit-border-radius: 3px 0 0 3px; 632 | -moz-border-radius: 3px 0 0 3px; 633 | border-radius: 3px 0 0 3px; 634 | } 635 | .input-daterange input:last-child { 636 | -webkit-border-radius: 0 3px 3px 0; 637 | -moz-border-radius: 0 3px 3px 0; 638 | border-radius: 0 3px 3px 0; 639 | } 640 | .input-daterange .add-on { 641 | display: inline-block; 642 | width: auto; 643 | min-width: 16px; 644 | height: 18px; 645 | padding: 4px 5px; 646 | font-weight: normal; 647 | line-height: 18px; 648 | text-align: center; 649 | text-shadow: 0 1px 0 #ffffff; 650 | vertical-align: middle; 651 | background-color: #eeeeee; 652 | border: 1px solid #ccc; 653 | margin-left: -5px; 654 | margin-right: -5px; 655 | } 656 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/editable/bootstrap2-editable.scss: -------------------------------------------------------------------------------- 1 | /*! X-editable - v1.5.0 2 | * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery 3 | * http://github.com/vitalets/x-editable 4 | * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ 5 | .editableform { 6 | margin-bottom: 0; /* overwrites bootstrap margin */ 7 | } 8 | 9 | .editableform .control-group { 10 | margin-bottom: 0; /* overwrites bootstrap margin */ 11 | white-space: nowrap; /* prevent wrapping buttons on new line */ 12 | line-height: 20px; /* overwriting bootstrap line-height. See #133 */ 13 | } 14 | 15 | .editable-buttons { 16 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 17 | vertical-align: top; 18 | margin-left: 7px; 19 | /* inline-block emulation for IE7*/ 20 | zoom: 1; 21 | *display: inline; 22 | } 23 | 24 | .editable-buttons.editable-buttons-bottom { 25 | display: block; 26 | margin-top: 7px; 27 | margin-left: 0; 28 | } 29 | 30 | .editable-input { 31 | vertical-align: top; 32 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 33 | width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ 34 | white-space: normal; /* reset white-space decalred in parent*/ 35 | /* display-inline emulation for IE7*/ 36 | zoom: 1; 37 | *display: inline; 38 | } 39 | 40 | .editable-buttons .editable-cancel { 41 | margin-left: 7px; 42 | } 43 | 44 | /*for jquery-ui buttons need set height to look more pretty*/ 45 | .editable-buttons button.ui-button-icon-only { 46 | height: 24px; 47 | width: 30px; 48 | } 49 | 50 | .editableform-loading { 51 | background: image-url('editable/loading.gif') center center no-repeat; 52 | height: 25px; 53 | width: auto; 54 | min-width: 25px; 55 | } 56 | 57 | .editable-inline .editableform-loading { 58 | background-position: left 5px; 59 | } 60 | 61 | .editable-error-block { 62 | max-width: 300px; 63 | margin: 5px 0 0 0; 64 | width: auto; 65 | white-space: normal; 66 | } 67 | 68 | /*add padding for jquery ui*/ 69 | .editable-error-block.ui-state-error { 70 | padding: 3px; 71 | } 72 | 73 | .editable-error { 74 | color: red; 75 | } 76 | 77 | /* ---- For specific types ---- */ 78 | 79 | .editableform .editable-date { 80 | padding: 0; 81 | margin: 0; 82 | float: left; 83 | } 84 | 85 | /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ 86 | .editable-inline .add-on .icon-th { 87 | margin-top: 3px; 88 | margin-left: 1px; 89 | } 90 | 91 | 92 | /* checklist vertical alignment */ 93 | .editable-checklist label input[type="checkbox"], 94 | .editable-checklist label span { 95 | vertical-align: middle; 96 | margin: 0; 97 | } 98 | 99 | .editable-checklist label { 100 | white-space: nowrap; 101 | } 102 | 103 | /* set exact width of textarea to fit buttons toolbar */ 104 | .editable-wysihtml5 { 105 | width: 566px; 106 | height: 250px; 107 | } 108 | 109 | /* clear button shown as link in date inputs */ 110 | .editable-clear { 111 | clear: both; 112 | font-size: 0.9em; 113 | text-decoration: none; 114 | text-align: right; 115 | } 116 | 117 | /* IOS-style clear button for text inputs */ 118 | .editable-clear-x { 119 | background: image-url('editable/clear.png') center center no-repeat; 120 | display: block; 121 | width: 13px; 122 | height: 13px; 123 | position: absolute; 124 | opacity: 0.6; 125 | z-index: 100; 126 | 127 | top: 50%; 128 | right: 6px; 129 | margin-top: -6px; 130 | 131 | } 132 | 133 | .editable-clear-x:hover { 134 | opacity: 1; 135 | } 136 | 137 | .editable-pre-wrapped { 138 | white-space: pre-wrap; 139 | } 140 | .editable-container.editable-popup { 141 | max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ 142 | } 143 | 144 | .editable-container.popover { 145 | width: auto; /* without this rule popover does not stretch */ 146 | } 147 | 148 | .editable-container.editable-inline { 149 | display: inline-block; 150 | vertical-align: middle; 151 | width: auto; 152 | /* inline-block emulation for IE7*/ 153 | zoom: 1; 154 | *display: inline; 155 | } 156 | 157 | .editable-container.ui-widget { 158 | font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ 159 | z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ 160 | } 161 | .editable-click, 162 | a.editable-click, 163 | a.editable-click:hover { 164 | text-decoration: none; 165 | border-bottom: dashed 1px #0088cc; 166 | } 167 | 168 | .editable-click.editable-disabled, 169 | a.editable-click.editable-disabled, 170 | a.editable-click.editable-disabled:hover { 171 | color: #585858; 172 | cursor: default; 173 | border-bottom: none; 174 | } 175 | 176 | .editable-empty, .editable-empty:hover, .editable-empty:focus{ 177 | font-style: italic; 178 | color: #DD1144; 179 | /* border-bottom: none; */ 180 | text-decoration: none; 181 | } 182 | 183 | .editable-unsaved { 184 | font-weight: bold; 185 | } 186 | 187 | .editable-unsaved:after { 188 | /* content: '*'*/ 189 | } 190 | 191 | .editable-bg-transition { 192 | -webkit-transition: background-color 1400ms ease-out; 193 | -moz-transition: background-color 1400ms ease-out; 194 | -o-transition: background-color 1400ms ease-out; 195 | -ms-transition: background-color 1400ms ease-out; 196 | transition: background-color 1400ms ease-out; 197 | } 198 | 199 | /*see https://github.com/vitalets/x-editable/issues/139 */ 200 | .form-horizontal .editable 201 | { 202 | padding-top: 5px; 203 | display:inline-block; 204 | } 205 | 206 | 207 | /*! 208 | * Datepicker for Bootstrap 209 | * 210 | * Copyright 2012 Stefan Petre 211 | * Improvements by Andrew Rowls 212 | * Licensed under the Apache License v2.0 213 | * http://www.apache.org/licenses/LICENSE-2.0 214 | * 215 | */ 216 | .datepicker { 217 | padding: 4px; 218 | -webkit-border-radius: 4px; 219 | -moz-border-radius: 4px; 220 | border-radius: 4px; 221 | direction: ltr; 222 | /*.dow { 223 | border-top: 1px solid #ddd !important; 224 | }*/ 225 | 226 | } 227 | .datepicker-inline { 228 | width: 220px; 229 | } 230 | .datepicker.datepicker-rtl { 231 | direction: rtl; 232 | } 233 | .datepicker.datepicker-rtl table tr td span { 234 | float: right; 235 | } 236 | .datepicker-dropdown { 237 | top: 0; 238 | left: 0; 239 | } 240 | .datepicker-dropdown:before { 241 | content: ''; 242 | display: inline-block; 243 | border-left: 7px solid transparent; 244 | border-right: 7px solid transparent; 245 | border-bottom: 7px solid #ccc; 246 | border-bottom-color: rgba(0, 0, 0, 0.2); 247 | position: absolute; 248 | top: -7px; 249 | left: 6px; 250 | } 251 | .datepicker-dropdown:after { 252 | content: ''; 253 | display: inline-block; 254 | border-left: 6px solid transparent; 255 | border-right: 6px solid transparent; 256 | border-bottom: 6px solid #ffffff; 257 | position: absolute; 258 | top: -6px; 259 | left: 7px; 260 | } 261 | .datepicker > div { 262 | display: none; 263 | } 264 | .datepicker.days div.datepicker-days { 265 | display: block; 266 | } 267 | .datepicker.months div.datepicker-months { 268 | display: block; 269 | } 270 | .datepicker.years div.datepicker-years { 271 | display: block; 272 | } 273 | .datepicker table { 274 | margin: 0; 275 | } 276 | .datepicker td, 277 | .datepicker th { 278 | text-align: center; 279 | width: 20px; 280 | height: 20px; 281 | -webkit-border-radius: 4px; 282 | -moz-border-radius: 4px; 283 | border-radius: 4px; 284 | border: none; 285 | } 286 | .table-striped .datepicker table tr td, 287 | .table-striped .datepicker table tr th { 288 | background-color: transparent; 289 | } 290 | .datepicker table tr td.day:hover { 291 | background: #eeeeee; 292 | cursor: pointer; 293 | } 294 | .datepicker table tr td.old, 295 | .datepicker table tr td.new { 296 | color: #999999; 297 | } 298 | .datepicker table tr td.disabled, 299 | .datepicker table tr td.disabled:hover { 300 | background: none; 301 | color: #999999; 302 | cursor: default; 303 | } 304 | .datepicker table tr td.today, 305 | .datepicker table tr td.today:hover, 306 | .datepicker table tr td.today.disabled, 307 | .datepicker table tr td.today.disabled:hover { 308 | background-color: #fde19a; 309 | background-image: -moz-linear-gradient(to bottom, #fdd49a, #fdf59a); 310 | background-image: -ms-linear-gradient(to bottom, #fdd49a, #fdf59a); 311 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); 312 | background-image: -webkit-linear-gradient(to bottom, #fdd49a, #fdf59a); 313 | background-image: -o-linear-gradient(to bottom, #fdd49a, #fdf59a); 314 | background-image: linear-gradient(to bottom, #fdd49a, #fdf59a); 315 | background-repeat: repeat-x; 316 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); 317 | border-color: #fdf59a #fdf59a #fbed50; 318 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 319 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 320 | color: #000; 321 | } 322 | .datepicker table tr td.today:hover, 323 | .datepicker table tr td.today:hover:hover, 324 | .datepicker table tr td.today.disabled:hover, 325 | .datepicker table tr td.today.disabled:hover:hover, 326 | .datepicker table tr td.today:active, 327 | .datepicker table tr td.today:hover:active, 328 | .datepicker table tr td.today.disabled:active, 329 | .datepicker table tr td.today.disabled:hover:active, 330 | .datepicker table tr td.today.active, 331 | .datepicker table tr td.today:hover.active, 332 | .datepicker table tr td.today.disabled.active, 333 | .datepicker table tr td.today.disabled:hover.active, 334 | .datepicker table tr td.today.disabled, 335 | .datepicker table tr td.today:hover.disabled, 336 | .datepicker table tr td.today.disabled.disabled, 337 | .datepicker table tr td.today.disabled:hover.disabled, 338 | .datepicker table tr td.today[disabled], 339 | .datepicker table tr td.today:hover[disabled], 340 | .datepicker table tr td.today.disabled[disabled], 341 | .datepicker table tr td.today.disabled:hover[disabled] { 342 | background-color: #fdf59a; 343 | } 344 | .datepicker table tr td.today:active, 345 | .datepicker table tr td.today:hover:active, 346 | .datepicker table tr td.today.disabled:active, 347 | .datepicker table tr td.today.disabled:hover:active, 348 | .datepicker table tr td.today.active, 349 | .datepicker table tr td.today:hover.active, 350 | .datepicker table tr td.today.disabled.active, 351 | .datepicker table tr td.today.disabled:hover.active { 352 | background-color: #fbf069 \9; 353 | } 354 | .datepicker table tr td.today:hover:hover { 355 | color: #000; 356 | } 357 | .datepicker table tr td.today.active:hover { 358 | color: #fff; 359 | } 360 | .datepicker table tr td.range, 361 | .datepicker table tr td.range:hover, 362 | .datepicker table tr td.range.disabled, 363 | .datepicker table tr td.range.disabled:hover { 364 | background: #eeeeee; 365 | -webkit-border-radius: 0; 366 | -moz-border-radius: 0; 367 | border-radius: 0; 368 | } 369 | .datepicker table tr td.range.today, 370 | .datepicker table tr td.range.today:hover, 371 | .datepicker table tr td.range.today.disabled, 372 | .datepicker table tr td.range.today.disabled:hover { 373 | background-color: #f3d17a; 374 | background-image: -moz-linear-gradient(to bottom, #f3c17a, #f3e97a); 375 | background-image: -ms-linear-gradient(to bottom, #f3c17a, #f3e97a); 376 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); 377 | background-image: -webkit-linear-gradient(to bottom, #f3c17a, #f3e97a); 378 | background-image: -o-linear-gradient(to bottom, #f3c17a, #f3e97a); 379 | background-image: linear-gradient(to bottom, #f3c17a, #f3e97a); 380 | background-repeat: repeat-x; 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); 382 | border-color: #f3e97a #f3e97a #edde34; 383 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 384 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 385 | -webkit-border-radius: 0; 386 | -moz-border-radius: 0; 387 | border-radius: 0; 388 | } 389 | .datepicker table tr td.range.today:hover, 390 | .datepicker table tr td.range.today:hover:hover, 391 | .datepicker table tr td.range.today.disabled:hover, 392 | .datepicker table tr td.range.today.disabled:hover:hover, 393 | .datepicker table tr td.range.today:active, 394 | .datepicker table tr td.range.today:hover:active, 395 | .datepicker table tr td.range.today.disabled:active, 396 | .datepicker table tr td.range.today.disabled:hover:active, 397 | .datepicker table tr td.range.today.active, 398 | .datepicker table tr td.range.today:hover.active, 399 | .datepicker table tr td.range.today.disabled.active, 400 | .datepicker table tr td.range.today.disabled:hover.active, 401 | .datepicker table tr td.range.today.disabled, 402 | .datepicker table tr td.range.today:hover.disabled, 403 | .datepicker table tr td.range.today.disabled.disabled, 404 | .datepicker table tr td.range.today.disabled:hover.disabled, 405 | .datepicker table tr td.range.today[disabled], 406 | .datepicker table tr td.range.today:hover[disabled], 407 | .datepicker table tr td.range.today.disabled[disabled], 408 | .datepicker table tr td.range.today.disabled:hover[disabled] { 409 | background-color: #f3e97a; 410 | } 411 | .datepicker table tr td.range.today:active, 412 | .datepicker table tr td.range.today:hover:active, 413 | .datepicker table tr td.range.today.disabled:active, 414 | .datepicker table tr td.range.today.disabled:hover:active, 415 | .datepicker table tr td.range.today.active, 416 | .datepicker table tr td.range.today:hover.active, 417 | .datepicker table tr td.range.today.disabled.active, 418 | .datepicker table tr td.range.today.disabled:hover.active { 419 | background-color: #efe24b \9; 420 | } 421 | .datepicker table tr td.selected, 422 | .datepicker table tr td.selected:hover, 423 | .datepicker table tr td.selected.disabled, 424 | .datepicker table tr td.selected.disabled:hover { 425 | background-color: #9e9e9e; 426 | background-image: -moz-linear-gradient(to bottom, #b3b3b3, #808080); 427 | background-image: -ms-linear-gradient(to bottom, #b3b3b3, #808080); 428 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); 429 | background-image: -webkit-linear-gradient(to bottom, #b3b3b3, #808080); 430 | background-image: -o-linear-gradient(to bottom, #b3b3b3, #808080); 431 | background-image: linear-gradient(to bottom, #b3b3b3, #808080); 432 | background-repeat: repeat-x; 433 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); 434 | border-color: #808080 #808080 #595959; 435 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 436 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 437 | color: #fff; 438 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 439 | } 440 | .datepicker table tr td.selected:hover, 441 | .datepicker table tr td.selected:hover:hover, 442 | .datepicker table tr td.selected.disabled:hover, 443 | .datepicker table tr td.selected.disabled:hover:hover, 444 | .datepicker table tr td.selected:active, 445 | .datepicker table tr td.selected:hover:active, 446 | .datepicker table tr td.selected.disabled:active, 447 | .datepicker table tr td.selected.disabled:hover:active, 448 | .datepicker table tr td.selected.active, 449 | .datepicker table tr td.selected:hover.active, 450 | .datepicker table tr td.selected.disabled.active, 451 | .datepicker table tr td.selected.disabled:hover.active, 452 | .datepicker table tr td.selected.disabled, 453 | .datepicker table tr td.selected:hover.disabled, 454 | .datepicker table tr td.selected.disabled.disabled, 455 | .datepicker table tr td.selected.disabled:hover.disabled, 456 | .datepicker table tr td.selected[disabled], 457 | .datepicker table tr td.selected:hover[disabled], 458 | .datepicker table tr td.selected.disabled[disabled], 459 | .datepicker table tr td.selected.disabled:hover[disabled] { 460 | background-color: #808080; 461 | } 462 | .datepicker table tr td.selected:active, 463 | .datepicker table tr td.selected:hover:active, 464 | .datepicker table tr td.selected.disabled:active, 465 | .datepicker table tr td.selected.disabled:hover:active, 466 | .datepicker table tr td.selected.active, 467 | .datepicker table tr td.selected:hover.active, 468 | .datepicker table tr td.selected.disabled.active, 469 | .datepicker table tr td.selected.disabled:hover.active { 470 | background-color: #666666 \9; 471 | } 472 | .datepicker table tr td.active, 473 | .datepicker table tr td.active:hover, 474 | .datepicker table tr td.active.disabled, 475 | .datepicker table tr td.active.disabled:hover { 476 | background-color: #006dcc; 477 | background-image: -moz-linear-gradient(to bottom, #0088cc, #0044cc); 478 | background-image: -ms-linear-gradient(to bottom, #0088cc, #0044cc); 479 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 480 | background-image: -webkit-linear-gradient(to bottom, #0088cc, #0044cc); 481 | background-image: -o-linear-gradient(to bottom, #0088cc, #0044cc); 482 | background-image: linear-gradient(to bottom, #0088cc, #0044cc); 483 | background-repeat: repeat-x; 484 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 485 | border-color: #0044cc #0044cc #002a80; 486 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 487 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 488 | color: #fff; 489 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 490 | } 491 | .datepicker table tr td.active:hover, 492 | .datepicker table tr td.active:hover:hover, 493 | .datepicker table tr td.active.disabled:hover, 494 | .datepicker table tr td.active.disabled:hover:hover, 495 | .datepicker table tr td.active:active, 496 | .datepicker table tr td.active:hover:active, 497 | .datepicker table tr td.active.disabled:active, 498 | .datepicker table tr td.active.disabled:hover:active, 499 | .datepicker table tr td.active.active, 500 | .datepicker table tr td.active:hover.active, 501 | .datepicker table tr td.active.disabled.active, 502 | .datepicker table tr td.active.disabled:hover.active, 503 | .datepicker table tr td.active.disabled, 504 | .datepicker table tr td.active:hover.disabled, 505 | .datepicker table tr td.active.disabled.disabled, 506 | .datepicker table tr td.active.disabled:hover.disabled, 507 | .datepicker table tr td.active[disabled], 508 | .datepicker table tr td.active:hover[disabled], 509 | .datepicker table tr td.active.disabled[disabled], 510 | .datepicker table tr td.active.disabled:hover[disabled] { 511 | background-color: #0044cc; 512 | } 513 | .datepicker table tr td.active:active, 514 | .datepicker table tr td.active:hover:active, 515 | .datepicker table tr td.active.disabled:active, 516 | .datepicker table tr td.active.disabled:hover:active, 517 | .datepicker table tr td.active.active, 518 | .datepicker table tr td.active:hover.active, 519 | .datepicker table tr td.active.disabled.active, 520 | .datepicker table tr td.active.disabled:hover.active { 521 | background-color: #003399 \9; 522 | } 523 | .datepicker table tr td span { 524 | display: block; 525 | width: 23%; 526 | height: 54px; 527 | line-height: 54px; 528 | float: left; 529 | margin: 1%; 530 | cursor: pointer; 531 | -webkit-border-radius: 4px; 532 | -moz-border-radius: 4px; 533 | border-radius: 4px; 534 | } 535 | .datepicker table tr td span:hover { 536 | background: #eeeeee; 537 | } 538 | .datepicker table tr td span.disabled, 539 | .datepicker table tr td span.disabled:hover { 540 | background: none; 541 | color: #999999; 542 | cursor: default; 543 | } 544 | .datepicker table tr td span.active, 545 | .datepicker table tr td span.active:hover, 546 | .datepicker table tr td span.active.disabled, 547 | .datepicker table tr td span.active.disabled:hover { 548 | background-color: #006dcc; 549 | background-image: -moz-linear-gradient(to bottom, #0088cc, #0044cc); 550 | background-image: -ms-linear-gradient(to bottom, #0088cc, #0044cc); 551 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 552 | background-image: -webkit-linear-gradient(to bottom, #0088cc, #0044cc); 553 | background-image: -o-linear-gradient(to bottom, #0088cc, #0044cc); 554 | background-image: linear-gradient(to bottom, #0088cc, #0044cc); 555 | background-repeat: repeat-x; 556 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 557 | border-color: #0044cc #0044cc #002a80; 558 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 559 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 560 | color: #fff; 561 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 562 | } 563 | .datepicker table tr td span.active:hover, 564 | .datepicker table tr td span.active:hover:hover, 565 | .datepicker table tr td span.active.disabled:hover, 566 | .datepicker table tr td span.active.disabled:hover:hover, 567 | .datepicker table tr td span.active:active, 568 | .datepicker table tr td span.active:hover:active, 569 | .datepicker table tr td span.active.disabled:active, 570 | .datepicker table tr td span.active.disabled:hover:active, 571 | .datepicker table tr td span.active.active, 572 | .datepicker table tr td span.active:hover.active, 573 | .datepicker table tr td span.active.disabled.active, 574 | .datepicker table tr td span.active.disabled:hover.active, 575 | .datepicker table tr td span.active.disabled, 576 | .datepicker table tr td span.active:hover.disabled, 577 | .datepicker table tr td span.active.disabled.disabled, 578 | .datepicker table tr td span.active.disabled:hover.disabled, 579 | .datepicker table tr td span.active[disabled], 580 | .datepicker table tr td span.active:hover[disabled], 581 | .datepicker table tr td span.active.disabled[disabled], 582 | .datepicker table tr td span.active.disabled:hover[disabled] { 583 | background-color: #0044cc; 584 | } 585 | .datepicker table tr td span.active:active, 586 | .datepicker table tr td span.active:hover:active, 587 | .datepicker table tr td span.active.disabled:active, 588 | .datepicker table tr td span.active.disabled:hover:active, 589 | .datepicker table tr td span.active.active, 590 | .datepicker table tr td span.active:hover.active, 591 | .datepicker table tr td span.active.disabled.active, 592 | .datepicker table tr td span.active.disabled:hover.active { 593 | background-color: #003399 \9; 594 | } 595 | .datepicker table tr td span.old, 596 | .datepicker table tr td span.new { 597 | color: #999999; 598 | } 599 | .datepicker th.datepicker-switch { 600 | width: 145px; 601 | } 602 | .datepicker thead tr:first-child th, 603 | .datepicker tfoot tr th { 604 | cursor: pointer; 605 | } 606 | .datepicker thead tr:first-child th:hover, 607 | .datepicker tfoot tr th:hover { 608 | background: #eeeeee; 609 | } 610 | .datepicker .cw { 611 | font-size: 10px; 612 | width: 12px; 613 | padding: 0 2px 0 5px; 614 | vertical-align: middle; 615 | } 616 | .datepicker thead tr:first-child th.cw { 617 | cursor: default; 618 | background-color: transparent; 619 | } 620 | .input-append.date .add-on i, 621 | .input-prepend.date .add-on i { 622 | display: block; 623 | cursor: pointer; 624 | width: 16px; 625 | height: 16px; 626 | } 627 | .input-daterange input { 628 | text-align: center; 629 | } 630 | .input-daterange input:first-child { 631 | -webkit-border-radius: 3px 0 0 3px; 632 | -moz-border-radius: 3px 0 0 3px; 633 | border-radius: 3px 0 0 3px; 634 | } 635 | .input-daterange input:last-child { 636 | -webkit-border-radius: 0 3px 3px 0; 637 | -moz-border-radius: 0 3px 3px 0; 638 | border-radius: 0 3px 3px 0; 639 | } 640 | .input-daterange .add-on { 641 | display: inline-block; 642 | width: auto; 643 | min-width: 16px; 644 | height: 18px; 645 | padding: 4px 5px; 646 | font-weight: normal; 647 | line-height: 18px; 648 | text-align: center; 649 | text-shadow: 0 1px 0 #ffffff; 650 | vertical-align: middle; 651 | background-color: #eeeeee; 652 | border: 1px solid #ccc; 653 | margin-left: -5px; 654 | margin-right: -5px; 655 | } 656 | --------------------------------------------------------------------------------