diff --git a/.travis.yml b/.travis.yml
index 8c47098a54..1e8419d708 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
language: ruby
rvm:
- 1.9.3
- - 1.9.2
+ - 2.0.0
env:
- DB=mysql
@@ -10,16 +10,6 @@ env:
gemfile: Gemfile.ci
-# Only run a cross-section of 4 builds majoring on r1.9.3
-matrix:
- exclude:
- - rvm: 1.9.2
- env: DB=sqlite
- gemfile: Gemfile.ci
- - rvm: 1.9.2
- env: DB=postgres
- gemfile: Gemfile.ci
-
bundler_args: --path=vendor/bundle --without heroku
before_install:
diff --git a/Capfile b/Capfile
index 72ef1245de..f3634e86a0 100644
--- a/Capfile
+++ b/Capfile
@@ -1,5 +1,2 @@
load 'deploy'
-# Uncomment if you are using Rails' asset pipeline
- # load 'deploy/assets'
-Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
-load 'config/deploy' # remove this line to skip loading any of the default tasks
+load 'config/deploy'
diff --git a/Gemfile b/Gemfile
index 524818bf3e..409b4b9d78 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,15 +6,6 @@ source 'https://rubygems.org'
# gem 'sqlite3'
#gem 'pg', '~> 0.13.2'
-# Allows easy switching between locally developed gems, and gems installed from rubygems.org
-# See README for more info at: https://github.com/ndbroadbent/bundler_local_development
-gem 'bundler_local_development', :group => :development, :require => false
-begin
- require 'bundler_local_development'
- Bundler.development_gems = [/^ffcrm_/, /ransack/]
-rescue LoadError
-end
-
# Removes a gem dependency
def remove(name)
@dependencies.reject! {|d| d.name == name }
@@ -29,7 +20,7 @@ end
# Bundler no longer treats runtime dependencies as base dependencies.
# The following code restores this behaviour.
# (See https://github.com/carlhuda/bundler/issues/1041)
-spec = Bundler.load_gemspec(Dir["./{,*}.gemspec"].first)
+spec = Bundler.load_gemspec( File.expand_path("../fat_free_crm.gemspec", __FILE__) )
spec.runtime_dependencies.each do |dep|
gem dep.name, *(dep.requirement.as_list)
end
@@ -42,15 +33,12 @@ remove 'fat_free_crm'
#remove 'ffcrm_merge'
group :development do
- gem 'thin'
- gem 'quiet_assets'
- # Uncomment the following two gems to deploy via Capistrano
- gem 'rvm-capistrano'
- gem 'capistrano_colors'
-
- # Use zeus and guard gems to speed up development
- # Run 'zeus start' and 'bundle exec guard' to get going
+ # don't load these gems in travis
unless ENV["CI"]
+ gem 'thin'
+ gem 'quiet_assets'
+ gem 'rvm-capistrano'
+ gem 'capistrano_colors'
gem 'guard'
gem 'guard-rspec'
gem 'guard-rails'
@@ -71,7 +59,7 @@ group :development, :test do
end
group :test do
- gem 'capybara', '~> 2.0.3'
+ gem 'capybara'
gem 'selenium-webdriver'
gem 'database_cleaner'
gem "acts_as_fu"
@@ -82,9 +70,9 @@ end
group :heroku do
gem 'unicorn', :platform => :ruby
+ gem 'rails_12factor'
end
-
# Gems used only for assets and not required
# in production environments by default.
group :assets do
diff --git a/Gemfile.lock b/Gemfile.lock
index 5b5fd79e1b..48f6acee5b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -6,7 +6,7 @@ GIT
GIT
remote: git://github.com/reubenjs/saasu.git
- revision: db542759e17a7f8b828417012fda2539b8c0e04f
+ revision: 184334ea60138aa0c86e387b48638557b48953ff
specs:
saasu (0.0.15)
activesupport (>= 2.3.2)
@@ -15,12 +15,12 @@ GIT
GEM
remote: https://rubygems.org/
specs:
- actionmailer (3.2.13)
- actionpack (= 3.2.13)
- mail (~> 2.5.3)
- actionpack (3.2.13)
- activemodel (= 3.2.13)
- activesupport (= 3.2.13)
+ actionmailer (3.2.16)
+ actionpack (= 3.2.16)
+ mail (~> 2.5.4)
+ actionpack (3.2.16)
+ activemodel (= 3.2.16)
+ activesupport (= 3.2.16)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
@@ -28,19 +28,19 @@ GEM
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
- activemodel (3.2.13)
- activesupport (= 3.2.13)
+ activemodel (3.2.16)
+ activesupport (= 3.2.16)
builder (~> 3.0.0)
- activerecord (3.2.13)
- activemodel (= 3.2.13)
- activesupport (= 3.2.13)
+ activerecord (3.2.16)
+ activemodel (= 3.2.16)
+ activesupport (= 3.2.16)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
- activeresource (3.2.13)
- activemodel (= 3.2.13)
- activesupport (= 3.2.13)
- activesupport (3.2.13)
- i18n (= 0.6.1)
+ activeresource (3.2.16)
+ activemodel (= 3.2.16)
+ activesupport (= 3.2.16)
+ activesupport (3.2.16)
+ i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
acts-as-taggable-on (2.3.3)
rails (~> 3.0)
@@ -48,181 +48,176 @@ GEM
acts_as_fu (0.0.8)
activerecord
sqlite3
- acts_as_list (0.1.6)
- addressable (2.3.3)
- ajax-chosen-rails (0.2.1)
- chosen-rails_ffcrm
- railties (~> 3.0)
- thor (~> 0.14)
- arel (3.0.2)
+ acts_as_list (0.1.9)
+ addressable (2.3.5)
+ arel (3.0.3)
+ atomic (1.1.14)
authlogic (3.1.0)
activerecord (>= 3.0.7)
activerecord (>= 3.0.7)
- awesome_print (1.1.0)
- binding_of_caller (0.6.8)
+ awesome_print (1.2.0)
+ binding_of_caller (0.7.2)
+ debug_inspector (>= 0.0.1)
builder (3.0.4)
- bundler_local_development (0.4.1)
- bundler
- cache_digests (0.2.0)
+ cache_digests (0.3.1)
actionpack (>= 3.2)
- cancan (1.6.8)
- capistrano (2.14.1)
+ thread_safe
+ cancan (1.6.10)
+ capistrano (2.15.5)
highline
net-scp (>= 1.0.0)
net-sftp (>= 2.0.0)
net-ssh (>= 2.0.14)
net-ssh-gateway (>= 1.1.0)
capistrano_colors (0.5.5)
- capybara (2.0.3)
+ capybara (2.2.1)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
- selenium-webdriver (~> 2.0)
- xpath (~> 1.0.0)
- childprocess (0.3.9)
+ xpath (~> 2.0)
+ celluloid (0.15.2)
+ timers (~> 1.1.0)
+ childprocess (0.4.0)
ffi (~> 1.0, >= 1.0.11)
- chosen-rails_ffcrm (0.9.5)
- railties (~> 3.0)
- thor (~> 0.14)
- chronic (0.6.7)
+ chronic (0.10.2)
climate_control (0.0.3)
activesupport (>= 3.0)
- cocaine (0.5.1)
+ cocaine (0.5.3)
climate_control (>= 0.0.3, < 1.0)
- coderay (1.0.9)
+ coderay (1.1.0)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
coffee-script (2.2.0)
coffee-script-source
execjs
- coffee-script-source (1.3.1)
- colorize (0.5.8)
+ coffee-script-source (1.6.3)
columnize (0.3.6)
combined_time_select (0.0.1)
- coveralls (0.5.7)
- colorize
- json
+ coveralls (0.7.0)
+ multi_json (~> 1.3)
rest-client
simplecov (>= 0.7)
+ term-ansicolor
thor
- css_parser (1.3.4)
+ css_parser (1.3.5)
addressable
- rdoc
daemons (1.1.9)
- dalli (2.6.0)
- database_cleaner (0.9.1)
- debugger (1.5.0)
+ dalli (2.7.0)
+ database_cleaner (1.2.0)
+ debug_inspector (0.0.2)
+ debugger (1.6.5)
columnize (>= 0.3.1)
debugger-linecache (~> 1.2.0)
- debugger-ruby_core_source (~> 1.2.0)
+ debugger-ruby_core_source (~> 1.3.1)
debugger-linecache (1.2.0)
- debugger-ruby_core_source (1.2.0)
- delayed_job (3.0.4)
- activesupport (~> 3.0)
- delayed_job_active_record (0.3.3)
- activerecord (>= 2.1.0, < 4)
- delayed_job (~> 3.0)
- diff-lcs (1.2.1)
+ debugger-ruby_core_source (1.3.1)
+ delayed_job (4.0.0)
+ activesupport (>= 3.0, < 4.1)
+ delayed_job_active_record (4.0.0)
+ activerecord (>= 3.0, < 4.1)
+ delayed_job (>= 3.0, < 4.1)
+ diff-lcs (1.2.5)
+ docile (1.1.2)
dynamic_form (1.1.4)
email_reply_parser_ffcrm (0.5.0)
erubis (2.7.0)
- eventmachine (1.0.0)
- execjs (1.3.1)
- multi_json (~> 1.0)
- factory_girl (4.2.0)
+ eventmachine (1.0.3)
+ execjs (2.0.2)
+ factory_girl (4.3.0)
activesupport (>= 3.0.0)
- factory_girl_rails (4.2.1)
- factory_girl (~> 4.2.0)
+ factory_girl_rails (4.3.0)
+ factory_girl (~> 4.3.0)
railties (>= 3.0.0)
- ffaker (1.14.0)
- ffi (1.8.1)
- guard (1.4.0)
- listen (>= 0.4.2)
- thor (>= 0.14.6)
- guard-rails (0.4.2)
+ ffaker (1.23.0)
+ ffi (1.9.3)
+ font-awesome-rails (4.0.3.1)
+ railties (>= 3.2, < 5.0)
+ formatador (0.2.4)
+ guard (2.3.0)
+ formatador (>= 0.2.4)
+ listen (~> 2.1)
+ lumberjack (~> 1.0)
+ pry (>= 0.9.12)
+ thor (>= 0.18.1)
+ guard-rails (0.4.7)
guard (>= 0.2.2)
- guard-rspec (2.5.3)
- guard (>= 1.1)
- rspec (~> 2.11)
- haml (3.1.7)
+ guard-rspec (4.2.5)
+ guard (~> 2.1)
+ rspec (>= 2.14, < 4.0)
+ haml (3.1.8)
headless (1.0.1)
- highline (1.6.15)
- hike (1.2.1)
+ highline (1.6.20)
+ hike (1.2.3)
htmlentities (4.3.1)
- httparty (0.10.0)
- multi_json (~> 1.0)
- multi_xml
- httpi (2.0.0)
- rack
- i18n (0.6.1)
- ice_cube (0.9.3)
+ httparty (0.12.0)
+ json (~> 1.8)
+ multi_xml (>= 0.5.2)
+ i18n (0.6.9)
+ ice_cube (0.11.2)
journey (1.0.4)
jquery-rails (2.1.4)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
- json (1.7.7)
- kgio (2.7.4)
- libv8 (3.11.8.13)
- libwebsocket (0.1.7.1)
- addressable
- websocket
- listen (0.7.3)
- mail (2.5.3)
- i18n (>= 0.4.0)
+ json (1.8.1)
+ kgio (2.8.1)
+ libv8 (3.16.14.3)
+ listen (2.4.0)
+ celluloid (>= 0.15.2)
+ rb-fsevent (>= 0.9.3)
+ rb-inotify (>= 0.9)
+ lumberjack (1.0.4)
+ mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
- mailchimp (0.0.7.alpha)
+ mailchimp (0.0.9)
httparty
- mandrill (0.0.2)
- httpi
- json
- mandrill-rails (0.0.2)
+ mandrill-rails (1.0.1)
activesupport (>= 3.0.3)
- mandrill (~> 0.0.2)
- method_source (0.8.1)
- mime-types (1.23)
- multi_json (1.7.2)
- multi_xml (0.5.2)
- mysql2 (0.3.10)
- net-scp (1.0.4)
- net-ssh (>= 1.99.1)
- net-sftp (2.0.5)
- net-ssh (>= 2.0.9)
- net-ssh (2.6.1)
- net-ssh-gateway (1.1.0)
- net-ssh (>= 1.99.1)
- nokogiri (1.5.9)
- paper_trail (2.6.3)
+ method_source (0.8.2)
+ mime-types (1.25.1)
+ mini_portile (0.5.2)
+ multi_json (1.8.4)
+ multi_xml (0.5.5)
+ mysql2 (0.3.15)
+ net-scp (1.1.2)
+ net-ssh (>= 2.6.5)
+ net-sftp (2.1.2)
+ net-ssh (>= 2.6.5)
+ net-ssh (2.7.0)
+ net-ssh-gateway (1.2.0)
+ net-ssh (>= 2.6.5)
+ nokogiri (1.6.1)
+ mini_portile (~> 0.5.0)
+ paper_trail (2.7.2)
activerecord (~> 3.0)
railties (~> 3.0)
- paperclip (3.4.1)
+ paperclip (3.5.3)
activemodel (>= 3.0.0)
- activerecord (>= 3.0.0)
activesupport (>= 3.0.0)
- cocaine (~> 0.5.0)
+ cocaine (~> 0.5.3)
mime-types
- polyamorous (0.5.0)
- activerecord (~> 3.0)
+ polyamorous (0.6.4)
+ activerecord (>= 3.0)
polyglot (0.3.3)
- premailer (1.7.3)
- css_parser (>= 1.1.9)
+ premailer (1.8.0)
+ css_parser (>= 1.3.5)
htmlentities (>= 4.0.0)
- prototype-rails (3.2.1)
- rails (~> 3.2)
- pry (0.9.12.2)
- coderay (~> 1.0.5)
+ pry (0.9.12.4)
+ coderay (~> 1.0)
method_source (~> 0.8)
slop (~> 3.4)
- pry-nav (0.2.1)
- pry (~> 0.9.9)
- pry-rails (0.2.0)
- pry
- pry-stack_explorer (0.4.7)
- binding_of_caller (~> 0.6.8)
- quiet_assets (1.0.1)
- railties (~> 3.1)
+ pry-nav (0.2.3)
+ pry (~> 0.9.10)
+ pry-rails (0.3.2)
+ pry (>= 0.9.10)
+ pry-stack_explorer (0.4.9.1)
+ binding_of_caller (>= 0.7)
+ pry (>= 0.9.11)
+ psych (1.3.4)
+ quiet_assets (1.0.2)
+ railties (>= 3.1, < 5.0)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
@@ -230,127 +225,135 @@ GEM
rack
rack-test (0.6.2)
rack (>= 1.0)
- rails (3.2.13)
- actionmailer (= 3.2.13)
- actionpack (= 3.2.13)
- activerecord (= 3.2.13)
- activeresource (= 3.2.13)
- activesupport (= 3.2.13)
+ rails (3.2.16)
+ actionmailer (= 3.2.16)
+ actionpack (= 3.2.16)
+ activerecord (= 3.2.16)
+ activeresource (= 3.2.16)
+ activesupport (= 3.2.16)
bundler (~> 1.0)
- railties (= 3.2.13)
- rails3-jquery-autocomplete (1.0.7)
- rails (~> 3.0)
- railties (3.2.13)
- actionpack (= 3.2.13)
- activesupport (= 3.2.13)
+ railties (= 3.2.16)
+ rails3-jquery-autocomplete (1.0.12)
+ rails (>= 3.0)
+ rails_12factor (0.0.2)
+ rails_serve_static_assets
+ rails_stdout_logging
+ rails_serve_static_assets (0.0.2)
+ rails_stdout_logging (0.0.3)
+ railties (3.2.16)
+ actionpack (= 3.2.16)
+ activesupport (= 3.2.16)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
- raindrops (0.8.0)
- rake (10.0.3)
- ransack (0.7.2)
- actionpack (~> 3.0)
- activerecord (~> 3.0)
- polyamorous (~> 0.5.0)
+ raindrops (0.12.0)
+ rake (10.1.1)
+ ransack (1.1.0)
+ actionpack (>= 3.0)
+ activerecord (>= 3.0)
+ polyamorous (~> 0.6.0)
ransack_chronic (1.1.0)
chronic (>= 0.6.7)
- ransack_ffcrm (0.7.1)
- actionpack (~> 3.0)
- activerecord (~> 3.0)
- chronic (~> 0.6.7)
- polyamorous (~> 0.5.0)
- ransack_ui (1.1.0)
+ ransack_ui (1.2.2)
ransack
ransack_chronic (>= 1.1.0)
rb-fchange (0.0.6)
ffi
- rb-fsevent (0.9.3)
- rb-inotify (0.9.0)
+ rb-fsevent (0.9.4)
+ rb-inotify (0.9.3)
ffi (>= 0.5.0)
rdoc (3.12.2)
json (~> 1.4)
- ref (1.0.2)
+ ref (1.0.5)
responds_to_parent (1.1.0)
rest-client (1.6.7)
mime-types (>= 1.16)
- rspec (2.13.0)
- rspec-core (~> 2.13.0)
- rspec-expectations (~> 2.13.0)
- rspec-mocks (~> 2.13.0)
- rspec-core (2.13.1)
- rspec-expectations (2.13.0)
+ rspec (2.14.1)
+ rspec-core (~> 2.14.0)
+ rspec-expectations (~> 2.14.0)
+ rspec-mocks (~> 2.14.0)
+ rspec-core (2.14.7)
+ rspec-expectations (2.14.4)
diff-lcs (>= 1.1.3, < 2.0)
- rspec-mocks (2.13.0)
- rspec-rails (2.13.0)
+ rspec-mocks (2.14.4)
+ rspec-rails (2.14.1)
actionpack (>= 3.0)
+ activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
- rspec (~> 2.13.0)
- rubyzip (0.9.9)
- rvm-capistrano (1.2.7)
- capistrano (>= 2.0.0)
- sass (3.2.5)
+ rspec-core (~> 2.14.0)
+ rspec-expectations (~> 2.14.0)
+ rspec-mocks (~> 2.14.0)
+ rubyzip (1.1.0)
+ rvm-capistrano (1.5.1)
+ capistrano (~> 2.15.4)
+ sass (3.2.14)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
- select2-rails (3.3.1)
- sass-rails (>= 3.2)
+ select2-rails (3.5.2)
thor (~> 0.14)
- selenium-webdriver (2.32.1)
+ selenium-webdriver (2.39.0)
childprocess (>= 0.2.5)
- libwebsocket (~> 0.1.3)
multi_json (~> 1.0)
- rubyzip
+ rubyzip (~> 1.0)
websocket (~> 1.0.4)
- simple_form (2.0.2)
+ simple_form (2.0.4)
actionpack (~> 3.0)
activemodel (~> 3.0)
- simplecov (0.7.1)
- multi_json (~> 1.0)
- simplecov-html (~> 0.7.1)
- simplecov-html (0.7.1)
- slop (3.4.5)
+ simplecov (0.8.2)
+ docile (~> 1.1.0)
+ multi_json
+ simplecov-html (~> 0.8.0)
+ simplecov-html (0.8.0)
+ slop (3.4.7)
sprockets (2.2.2)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
- sqlite3 (1.3.7)
- therubyracer (0.11.3)
- libv8 (~> 3.11.8.12)
+ sqlite3 (1.3.8)
+ term-ansicolor (1.2.2)
+ tins (~> 0.8)
+ therubyracer (0.12.0)
+ libv8 (~> 3.16.14.0)
ref
- thin (1.5.0)
+ thin (1.6.1)
daemons (>= 1.0.9)
- eventmachine (>= 0.12.6)
+ eventmachine (>= 1.0.0)
rack (>= 1.0.0)
thor (0.18.1)
+ thread_safe (0.1.3)
+ atomic
tilt (1.4.1)
- tinymce-rails (3.5.8.2)
+ timers (1.1.0)
+ tins (0.13.1)
+ tinymce-rails (4.0.12)
railties (>= 3.1.1)
- treetop (1.4.12)
+ treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
- turbo-sprockets-rails3 (0.3.6)
+ turbo-sprockets-rails3 (0.3.11)
railties (> 3.2.8, < 4.0.0)
- sprockets (>= 2.0.0)
- tzinfo (0.3.37)
- uglifier (1.2.4)
+ sprockets (>= 2.2.0)
+ tzinfo (0.3.38)
+ uglifier (2.4.0)
execjs (>= 0.3.0)
- multi_json (>= 1.0.2)
- unicorn (4.3.1)
+ json (>= 1.8.0)
+ unicorn (4.8.0)
kgio (~> 2.6)
rack
raindrops (~> 0.7)
valium (0.5.0)
activerecord (>= 3.0.2)
websocket (1.0.7)
- whenever (0.8.2)
+ whenever (0.9.0)
activesupport (>= 2.3.4)
chronic (>= 0.6.3)
- will_paginate (3.0.3)
- xpath (1.0.0)
+ will_paginate (3.0.5)
+ xpath (2.0.0)
nokogiri (~> 1.3)
zeus (0.13.3)
method_source (>= 0.6.7)
@@ -363,14 +366,12 @@ DEPENDENCIES
acts_as_commentable (~> 3.0.1)
acts_as_fu
acts_as_list (~> 0.1.4)
- ajax-chosen-rails (>= 0.2.1)
authlogic (= 3.1.0)
awesome_print
- bundler_local_development
cache_digests
cancan
capistrano_colors
- capybara (~> 2.0.3)
+ capybara
chronic
cocaine
coffee-rails (~> 3.2.1)
@@ -387,6 +388,7 @@ DEPENDENCIES
execjs
factory_girl_rails
ffaker (>= 1.12.0)
+ font-awesome-rails
guard
guard-rails
guard-rspec
@@ -398,17 +400,17 @@ DEPENDENCIES
mandrill-rails
mysql2
nokogiri
- paper_trail
+ paper_trail (~> 2.7.0)
paperclip
premailer
- prototype-rails
pry-nav
pry-rails
pry-stack_explorer
+ psych (~> 1)
quiet_assets
rails (~> 3.2.12)
rails3-jquery-autocomplete
- ransack_ffcrm (~> 0.7.1)
+ rails_12factor
ransack_ui (>= 1.1.0)
rb-fchange
rb-fsevent
@@ -431,5 +433,5 @@ DEPENDENCIES
unicorn
valium
whenever
- will_paginate (~> 3.0.2)
+ will_paginate
zeus
diff --git a/MIT-LICENSE b/MIT-LICENSE
index a818c1dd28..2810da57e3 100644
--- a/MIT-LICENSE
+++ b/MIT-LICENSE
@@ -1,5 +1,5 @@
Fat Free CRM
-Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+Copyright (c) 2008-2014 Michael Dvorkin and contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/Procfile b/Procfile
index fd3e2d3f07..9c8237414c 100644
--- a/Procfile
+++ b/Procfile
@@ -1 +1 @@
-web: ./bin/unicorn -p $PORT -c config/unicorn.rb
+web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
diff --git a/README.md b/README.md
index a8185cef4f..b5ce623f5d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Fat Free CRM [![TravisCI][travis-img-url]][travis-ci-url]
+# Fat Free CRM [![TravisCI][travis-img-url]][travis-ci-url] [](https://codeclimate.com/github/fatfreecrm/fat_free_crm)
[travis-img-url]: https://secure.travis-ci.org/fatfreecrm/fat_free_crm.png?branch=master
[travis-ci-url]: http://travis-ci.org/fatfreecrm/fat_free_crm
@@ -14,29 +14,29 @@ contact lists, and opportunity tracking.
-
-
+
+
Contacts
-
-
+
+
Opportunities
-
-
+
+
Accounts
-
-
+
+
Tasks
@@ -51,11 +51,16 @@ Pull requests and bug reports are always welcome!
Visit our website at http://www.fatfreecrm.com/
+## Important security note
+
+Please note that several severe vulnerabilities have been fixed recently. You should upgrade to versions 0.12.3 or 0.13.2 or higher. See the [**security vulnerabilities**](https://github.com/fatfreecrm/fat_free_crm/wiki/Security) page for more details.
## System Requirements
-* Ruby v1.9.3 recommended (1.9.2 also works, ruby 2.0.0 does NOT)
- * Note that Ruby v1.8.7 was supported until v0.11.4 (see https://github.com/fatfreecrm/fat_free_crm/tree/ruby1.8)
+* Ruby v2.0.0 recommended (it's faster!)
+ * Ruby 1.9.3 is also compatible
+ * Ruby 1.9.2 should be compatible but is not longer supported
+ * Ruby v1.8.7 was supported until v0.11.4 (see https://github.com/fatfreecrm/fat_free_crm/tree/ruby1.8)
* MySQL v4.1.1 or later (v5+ is recommended), SQLite v3.4 or later, or Postgres 8.4.8 or later.
* ImageMagick (optional, only needed if you would like to use avatars)
@@ -81,7 +86,7 @@ Installing Fat Free CRM on Microsoft Windows
### [Running Fat Free CRM as a Rails Engine](http://guides.fatfreecrm.com/Running-as-a-Rails-Engine.html)
Run the Fat Free CRM gem within a separate Rails application.
-This is the best way to deploy Fat Free CRM if you need to add plugins or make any customizations.
+This is the best way to deploy Fat Free CRM if you need to add plugins or make any customizations. Note that it is not yet simple to 'bolt' Fat Free CRM into your existing rails project, but we're heading in that direction.
## Upgrading from previous versions of Fat Free CRM
@@ -108,27 +113,25 @@ Please read the [Release Notes](http://guides.fatfreecrm.com/Release-Notes.html)
## For Developers
-Fat Free CRM can be customized by implementing callback hooks and extended by
-creating Rails Engines plugins. Check out these sample repositories demonstrating
-the concepts:
+Fat Free CRM is released under the MIT license and is freely available for you to use for your own purposes. We do encourage contributions to make Fat Free CRM even better. Send us a pull-request and we'll do our best to accomodate your needs.
+
+Specific features that are not 'Fat Free' in nature, can be added by creating Rails Engines. See the [wiki](http://github.com/fatfreecrm/fat_free_crm/wiki) for information on how to do this.
+
+Tests can easily be run by typing 'rake' but please note that they do take a while to run! Alternatively, you can see the test build status over at our [travis page](http://travis-ci.org/fatfreecrm/fat_free_crm)
-* http://github.com/michaeldv/crm_sample_plugin/tree/master
-* http://github.com/michaeldv/crm_sample_tabs/tree/master
-* http://github.com/michaeldv/crm_web_to_lead/tree/master
-* http://github.com/michaeldv/crm_tags/tree/master
## Main contributors
* [Michael Dvorkin (@michaeldv)](https://github.com/michaeldv) - Founding creator
+* [Steve Kenworthy (@steveyken)](https://github.com/steveyken) - Maintainer
* [Nathan Broadbent (@ndbroadbent)](https://github.com/ndbroadbent)
-* [Steve Kenworthy (@steveyken)](https://github.com/steveyken)
See the [contributors graph](https://github.com/fatfreecrm/fat_free_crm/graphs/contributors) and the [contributors file](https://github.com/fatfreecrm/fat_free_crm/blob/master/CONTRIBUTORS) for further details.
## License
Fat Free CRM
-Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+Copyright (c) 2008-2014 Michael Dvorkin and contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/app/assets/images/delete.png b/app/assets/images/delete.png
deleted file mode 100644
index 2f5d665c4d..0000000000
Binary files a/app/assets/images/delete.png and /dev/null differ
diff --git a/app/assets/images/facebook-close.gif b/app/assets/images/facebook-close.gif
deleted file mode 100644
index cc2199248c..0000000000
Binary files a/app/assets/images/facebook-close.gif and /dev/null differ
diff --git a/app/assets/images/iconset_attribution.png b/app/assets/images/iconset_attribution.png
deleted file mode 100644
index 4ab9c1f7e2..0000000000
Binary files a/app/assets/images/iconset_attribution.png and /dev/null differ
diff --git a/app/assets/javascripts/admin/fields.js.coffee b/app/assets/javascripts/admin/fields.js.coffee
index 2dc5f2e307..6fa0eb829c 100644
--- a/app/assets/javascripts/admin/fields.js.coffee
+++ b/app/assets/javascripts/admin/fields.js.coffee
@@ -6,7 +6,25 @@
(($) ->
- $('.fields select[name="field[as]"]').live 'change', ->
+ #----------------------------------------------------------------------------
+ # Custom field tabs switcher
+ $(document).on "click", "*[data-tab-class]", (event) ->
+ event.preventDefault()
+ $el = $(this)
+
+ $(".fields").each ->
+ $(this).hide()
+
+ $(".inline_tabs ul li").each ->
+ $(this).removeClass "selected"
+
+ klass = $el.data("tab-class")
+ $("#" + klass + "_section").show()
+ $el.addClass "selected"
+
+ #----------------------------------------------------------------------------
+ # Load custom field subform
+ $(document).on 'change', '.fields select[name="field[as]"]', ->
$.ajax(
url: '/admin/fields/subform?' + $(this).parents('form').serialize()
dataType: 'html'
@@ -16,7 +34,9 @@
$(this).find('input').first().focus()
)
- $('.fields a.create').live 'click', ->
+ #----------------------------------------------------------------------------
+ # Open new field form
+ $(document).on 'click', '.fields a.create', ->
$('.edit_field').hide()
field_group = $(this).closest('.field_group')
field_group.find('.empty').hide()
@@ -24,13 +44,16 @@
field_group.find('.create_field').slideDown().find('input[name="field[label]"]').focus()
false
- $('.create_field a.close, .create_field a.cancel').live 'click', ->
+ #----------------------------------------------------------------------------
+ # Close new field form
+ $(document).on 'click', '.create_field a.close, .create_field a.cancel', ->
$(this).closest('.create_field').hide()
- $(this).closest('.field_group').find('.empty').show()
$(this).closest('.field_group').find('.create .arrow').html(crm.COLLAPSED)
false
- $('.fields a.edit').live 'click', ->
+ #----------------------------------------------------------------------------
+ # Edit an existing field
+ $(document).on 'click', '.fields a.edit', ->
$('.edit_field').hide()
$.ajax(
url: $(this).attr('href')
@@ -40,10 +63,10 @@
)
false
- $('.edit_field a.close, .edit_field a.cancel').live 'click', ->
+ #----------------------------------------------------------------------------
+ # Close edit field form
+ $(document).on 'click', '.edit_field a.close, .edit_field a.cancel', ->
$(this).closest('.edit_field').hide()
false
- false
-
) jQuery
diff --git a/app/assets/javascripts/application.js.erb b/app/assets/javascripts/application.js.erb
index 193fd7de55..ceefb2e644 100644
--- a/app/assets/javascripts/application.js.erb
+++ b/app/assets/javascripts/application.js.erb
@@ -4,46 +4,43 @@
// See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
//------------------------------------------------------------------------------
-//= require prototype
-//= require effects
-//= require controls
-//= require dragdrop
-//= require prototype_ujs
-
//= require jquery
+//= require jquery_ujs
//= require jquery-ui
//= require jquery.mobile.custom.min
-//= require jquery-noconflict
+// require jquery-noconflict
//= require select2
-
-//= require modalbox
//= require crm
//= require crm_classes
//= require crm_loginout
-//= require crm_fields
-// require ffcrm_merge
+//= require crm_tags
+//= require crm_sortable
+//= require crm_draggable
//= require textarea_autocomplete
//= require crm_textarea_autocomplete
-//= require event.simulate
-//= require ajax-chosen-prototype
+//= require ajax-chosen-jquery
//= require crm_chosen
+//= require crm_select2
//= require ransack_ui_jquery
//= require search
//= require lists
//= require autocomplete-rails
// require datepair
-//= require datepicker
-//= require jquery-timepicker/jquery.timepicker
-//= require jquery-timepicker/lib/datepair-old
-// require jquery-timepicker/lib/base
-//= require jquery.disable
+//= require jquery-timepicker/lib/base
// require jquery_ui_datepicker/jquery-ui-timepicker-addon
+//= require jquery-timepicker/jquery.timepicker
+//= require jquery-timepicker/lib/datepair
+//= require datepicker
+// require jquery.disable
//= require admin/fields
//= require format_buttons
//= require tinymce
+//= require crm_comments
+//= require jquery_timeago
+//= require timeago
+//= require pagination
//= require_self
-
<%
Gem.loaded_specs.keys.grep(/^ffcrm_/).each do |plugin|
require_asset(plugin) rescue Sprockets::FileNotFound
diff --git a/app/assets/javascripts/crm.js b/app/assets/javascripts/crm.js
deleted file mode 100644
index d652dfd8de..0000000000
--- a/app/assets/javascripts/crm.js
+++ /dev/null
@@ -1,568 +0,0 @@
-// Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-//
-// Fat Free CRM is freely distributable under the terms of MIT license.
-// See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-//------------------------------------------------------------------------------
-var crm = {
-
- EXPANDED : "▼",
- COLLAPSED : "►",
- searchRequest : null,
- autocompleter : null,
- base_url : "",
-
- //----------------------------------------------------------------------------
- find_form: function(class_name) {
- var forms = $$('form.' + class_name);
- return (forms.length > 0 ? forms[0].id : null);
- },
-
- //----------------------------------------------------------------------------
- search_tagged: function(query, controller) {
- if ($('query')) {
- $('query').value = query;
- }
- crm.search(query, controller);
- },
-
- /*
- * remove any duplicate 'facebook-list' elements before running the 'BlindUp' effect.
- * (The disappearing facebook-list takes precedence over the newly created facebook-list
- * that is being AJAX loaded, and messes up the initialization.. )
- */
- hide_form: function(id) {
- if($('facebook-list')) $('facebook-list').remove();
- var arrow = $(id + "_arrow") || $("arrow");
- if (arrow) arrow.update(this.COLLAPSED);
- $(id).hide().update("").setStyle({height: 'auto'});
- },
-
- //----------------------------------------------------------------------------
- show_form: function(id) {
- var arrow = $(id + "_arrow") || $("arrow");
- if (arrow) arrow.update(this.EXPANDED);
- Effect.BlindDown(id, { duration: 0.25, afterFinish: function() {
- var input = $(id).down("input[type=text]");
- if (input) input.focus();
- }
- });
- },
-
- //----------------------------------------------------------------------------
- flip_form: function(id) {
- if ($(id)) {
- if (Element.visible(id)) {
- this.hide_form(id);
- } else {
- this.show_form(id);
- }
- }
- },
-
- //----------------------------------------------------------------------------
- set_title: function(id, caption) {
- var title = $(id + "_title") || $("title");
- if (typeof(caption) == "undefined") {
- var words = id.split("_");
- if (words.length == 1) {
- caption = id.capitalize();
- } else {
- caption = words[0].capitalize() + " " + words[1].capitalize();
- }
- }
- title.update(caption);
- },
-
- //----------------------------------------------------------------------------
- highlight_off: function(id) {
- $(id).onmouseover = $(id).onmouseout = null;
- $(id).style.background = "white";
- },
-
- //----------------------------------------------------------------------------
- focus_on_first_field: function() {
- if ($$("form") != "") {
- var first_element = $$("form")[0].findFirstElement();
- if (first_element) {
- first_element.focus();
- first_element.value = first_element.value;
- }
- } else if ($("query")) {
- $("query").focus();
- }
- var basic_search_input = $("query")
- if (basic_search_input.value != "") {
- basic_search_input.focus();
- }
- },
-
- // Hide accounts dropdown and show create new account edit field instead.
- //----------------------------------------------------------------------------
- create_account: function(and_focus) {
- crm.ensure_chosen_account();
- $("account_disabled_title").hide();
- $("account_select_title").hide();
- $("account_create_title").show();
- $("account_id_chzn").hide();
- $("account_id").disable();
- $("account_name").enable();
- $("account_name").clear();
- $("account_name").show();
- if (and_focus) {
- $("account_name").focus();
- }
- },
-
- // Hide create account edit field and show accounts dropdown instead.
- //----------------------------------------------------------------------------
- select_account: function(and_focus) {
- crm.ensure_chosen_account();
- $("account_disabled_title").hide();
- $("account_create_title").hide();
- $("account_select_title").show();
- $("account_name").hide();
- $("account_name").disable();
- $("account_id").enable();
- $("account_id_chzn").show();
- },
-
- // Show accounts dropdown and disable it to prevent changing the account.
- //----------------------------------------------------------------------------
- select_existing_account: function() {
- crm.ensure_chosen_account();
- $("account_create_title").hide();
- $("account_select_title").hide();
- $("account_disabled_title").show();
- $("account_name").hide();
- $("account_name").disable();
- // Disable chosen account select
- $("account_id").disable();
- Event.fire($("account_id"), "liszt:updated");
- $("account_id_chzn").show();
- // Enable hidden account id select so that value is POSTed
- $("account_id").enable();
- },
-
- //----------------------------------------------------------------------------
- create_or_select_account: function(selector) {
- if (selector !== true && selector > 0) {
- this.select_existing_account(); // disabled accounts dropdown
- } else if (selector) {
- this.create_account(); // create account edit field
- } else {
- this.select_account(); // accounts dropdown
- }
- },
-
- //----------------------------------------------------------------------------
- create_contact: function() {
- if ($("contact_business_address_attributes_country")) {
- this.clear_all_hints();
- }
- $("account_assigned_to").value = $F("contact_assigned_to");
- if ($("account_id").visible()) {
- $("account_id").enable();
- }
- },
-
- //----------------------------------------------------------------------------
- save_contact: function() {
- if ($("contact_business_address_attributes_country")) {
- this.clear_all_hints();
- }
- $("account_assigned_to").value = $F("contact_assigned_to");
- },
-
- //----------------------------------------------------------------------------
- flip_calendar: function(value) {
- if (value == "specific_time") {
- $("task_bucket").toggle(); // Hide dropdown.
- $("task_calendar").toggle(); // Show editable date field.
- $("task_calendar").focus(); // Focus to invoke calendar popup.
- }
- },
-
- //----------------------------------------------------------------------------
- show_repeats: function(value) {
- $("repeats").toggle(); // Hide dropdown.
- },
-
- //----------------------------------------------------------------------------
- show_scheduled: function(value) {
- $("scheduled").toggle(); // Hide dropdown.
- },
-
- //----------------------------------------------------------------------------
- show_comments: function(value) {
- $("com_contact_" + value ).toggle(); // show/hide comments section for attendances
- },
-
- //----------------------------------------------------------------------------
- update_part_time: function(value) {
- if(value) {
- $("part_time").show();
- } else {
- $("part_time").hide();
- }
-
- },
-
-
- //----------------------------------------------------------------------------
- flip_campaign_permissions: function(value) {
- if (value) {
- $("lead_access_campaign").enable();
- $("lead_access_campaign").checked = 1;
- $("copy_permissions").style.color = "#3f3f3f";
- } else {
- $("lead_access_campaign").disable();
- $("copy_permissions").style.color = "grey";
- $("lead_access_private").checked = 1;
- }
- },
-
- //----------------------------------------------------------------------------
- flip_subtitle: function(el) {
- var arrow = Element.down(el, "small");
- var intro = Element.down(Element.next(Element.up(el)), "small");
- // Optionally, the intro might be next to the link.
- if(!intro){ intro = Element.next(el, "small");};
- var section = Element.down(Element.next(Element.up(el)), "div");
-
- if (Element.visible(section)) {
- arrow.update(this.COLLAPSED);
- Effect.toggle(section, 'slide', { duration: 0.25, afterFinish: function() { intro.toggle(); } });
- } else {
- arrow.update(this.EXPANDED);
- Effect.toggle(section, 'slide', { duration: 0.25, beforeStart: function() { intro.toggle(); } });
- }
- },
-
- //----------------------------------------------------------------------------
- flip_subtitle2: function(el) {
- var arrow = Element.down(el, "small");
- //var intro = Element.down(Element.next(Element.up(el)), "small");
- // Optionally, the intro might be next to the link.
- //if(!intro){ intro = Element.next(el, "small");};
- //var section = Element.down(Element.down(Element.next(Element.up(Element.up(el))), "div"), "div");
- var section = Element.down(Element.next(Element.up(Element.up(el))), "div");
-
- if (Element.visible(section)) {
- arrow.update(this.COLLAPSED);
- Effect.toggle(section, 'slide', { duration: 0.25 });
- } else {
- arrow.update(this.EXPANDED);
- Effect.toggle(section, 'slide', { duration: 0.25 });
- }
- },
-
- //----------------------------------------------------------------------------
- flip_note_or_email: function(link, more, less) {
- var body, state;
-
- if (link.innerHTML == more) {
- body = Element.next(Element.up(link));
- body.hide();
- $(body.id.replace('truncated', 'formatted')).show(); // expand
- link.innerHTML = less;
- state = "Expanded";
- } else {
- body = Element.next(Element.next(Element.up(link)));
- body.hide();
- $(body.id.replace('formatted', 'truncated')).show(); // collapse
- link.innerHTML = more;
- state = "Collapsed";
- }
- // Ex: "formatted_email_42" => [ "formatted", "email", "42" ]
- var arr = body.id.split("_");
-
- new Ajax.Request(this.base_url + "/home/timeline", {
- method : "get",
- parameters : { type : arr[1], id : arr[2], state : state }
- });
- },
-
- //----------------------------------------------------------------------------
- flip_notes_and_emails: function(state, more, less, el_prefix) {
- if(!el_prefix){
- var notes_field = "shown_notes";
- var emails_field = "shown_emails";
- var comment_new_field = "comment_new";
- } else {
- var notes_field = el_prefix + "_shown_notes";
- var emails_field = el_prefix + "_shown_emails";
- var comment_new_field = el_prefix + "_comment_new";
- };
-
- var notes = $(notes_field).value;
- var emails = $(emails_field).value;
-
- if (notes != "" || emails != "") {
- new Ajax.Request(this.base_url + "/home/timeline", {
- method : "get",
- parameters : { type : "", id : notes + "+" + emails, state : state },
- onComplete : function() {
- $(comment_new_field).adjacent("li").each( function(li) {
- var a = li.select("tt a.toggle")[0];
- var dt = li.select("dt");
- if (typeof(a) != "undefined") {
- if (state == "Expanded") {
- dt[0].hide(); dt[1].show();
- if (a.innerHTML != less) {
- a.innerHTML = less;
- }
- } else {
- dt[1].hide(); dt[0].show();
- if (a.innerHTML != more) {
- a.innerHTML = more;
- }
- }
- }
- }) // each(li)
- }.bind(this) // onComplete
- });
- }
- },
-
- copyToClipboard: function(text) {
- window.prompt ("Copy to clipboard: Ctrl+C, Enter", text);
- },
-
- //----------------------------------------------------------------------------
- reschedule_task: function(id, bucket) {
- $("task_bucket").value = bucket;
- $$('#edit_task_' + id + ' input[type="submit"]')[0].click();
- },
-
- //----------------------------------------------------------------------------
- flick: function(element, action) {
- if ($(element)) {
- switch(action) {
- case "show": $(element).show(); break;
- case "hide": $(element).hide(); break;
- case "clear": $(element).update(""); break;
- case "remove": $(element).remove(); break;
- case "toggle": $(element).toggle(); break;
- }
- }
- },
-
- //----------------------------------------------------------------------------
- flash: function(type, sticky) {
- $("flash").hide();
- if (type == "warning" || type == "error") {
- $("flash").className = "flash_warning";
- } else {
- $("flash").className = "flash_notice";
- }
- Effect.Appear("flash", { duration: 0.5 });
- if (!sticky) {
- setTimeout("Effect.Fade('flash')", 3000);
- }
- },
-
- //----------------------------------------------------------------------------
- // Will be deprecated soon: html5 placeholder replaced it on address fields
- show_hint: function(el, hint) {
- if (el.value == '') {
- el.value = hint;
- el.style.color = 'silver'
- el.setAttribute('hint', true);
- }
- },
-
- //----------------------------------------------------------------------------
- // Will be deprecated soon: html5 placeholder replaced it on address fields
- hide_hint: function(el, value) {
- if (arguments.length == 2) {
- el.value = value;
- } else {
- if (el.getAttribute('hint') == "true") {
- el.value = '';
- }
- }
- el.style.color = 'black'
- el.setAttribute('hint', false);
- },
-
- //----------------------------------------------------------------------------
- // Will be deprecated soon: html5 placeholder replaced it on address fields
- clear_all_hints: function() {
- $$("input[hint=true]").each( function(field) {
- field.value = '';
- }.bind(this));
- },
-
- //----------------------------------------------------------------------------
- copy_address: function(from, to) {
- $(from + "_attributes_full_address").value = $(to + "_attributes_full_address").value;
- },
-
- //----------------------------------------------------------------------------
- copy_compound_address: function(from, to) {
- $w("street1 street2 city state zipcode").each( function(field) {
- var source = $(from + "_attributes_" + field);
- var destination = $(to + "_attributes_" + field);
- if (source.getAttribute('hint') != "true") {
- this.hide_hint(destination, source.value);
- }
- }.bind(this));
-
- // Country dropdown needs special treatment ;-)
- $(to + "_attributes_country").selectedIndex = $(from + "_attributes_country").selectedIndex;
- // Update Chosen select
- Event.fire($(to + "_attributes_country"), "liszt:updated");
- },
-
- //----------------------------------------------------------------------------
-
- search: function(query, controller) {
- var list = controller; // ex. "users"
- if (list.indexOf("/") >= 0) { // ex. "admin/users"
- list = list.split("/")[1];
- }
- $("loading").show();
- $(list).setStyle({ opacity: 0.4 });
- if (this.searchRequest && this.searchRequest.readyState != -4) { this.searchRequest.abort(); }
- this.searchRequest = jQuery.ajax({
- url: this.base_url + "/" + controller + '.js',
- type: 'GET',
- data: { query : query },
- success : function() {
- $("loading").hide();
- $(list).setStyle({ opacity: 1 });
- this.searchRequest = null;
- }
- });
- },
-
- //----------------------------------------------------------------------------
-
- search_show: function(query, controller, related_id, list) {
- // var list = controller; // ex. "users"
- // if (list.indexOf("/") >= 0) { // ex. "admin/users"
- // list = list.split("/")[1];
- // }
- $("loading").show();
- $(list).setStyle({ opacity: 0.4 });
- if (this.searchRequest && this.searchRequest.readyState != -4) { this.searchRequest.abort(); }
- this.searchRequest = jQuery.ajax({
- url: this.base_url + "/" + controller + "/" + related_id + '/redraw_show.js',
- type: 'POST',
- data: { query : query },
- success : function() {
- $("loading").hide();
- $(list).setStyle({ opacity: 1 });
- this.searchRequest = null;
- }
- });
- },
-
- //----------------------------------------------------------------------------
- jumper: function(controller) {
- var name = controller.capitalize();
- $$("#jumpbox_menu a").each(function(link) {
- if (link.innerHTML == name) {
- link.addClassName("selected");
- } else {
- link.removeClassName("selected");
- }
- });
- this.auto_complete(controller, null, true);
- },
-
- //----------------------------------------------------------------------------
- auto_complete: function(controller, related, focus) {
- if (this.autocompleter) {
- Event.stopObserving(this.autocompleter.element);
- delete this.autocompleter;
- }
- this.autocompleter = new Ajax.Autocompleter("auto_complete_query", "auto_complete_dropdown", this.base_url + "/" + controller + "/auto_complete", {
- frequency: 0.25,
- parameters: (related) ? ('related=' + related) : null,
- onShow: function(element, update) {
- // overridding onShow to include a fix for IE browsers
- // see https://prototype.lighthouseapp.com/projects/8887/tickets/263-displayinline-fixes-positioning-of-autocomplete-results-div-in-ie8
- update.style.display = (Prototype.Browser.IE) ? 'inline':'absolute';
- // below is default onShow from controls.js
- if(!update.style.position || update.style.position=='absolute') {
- update.style.position = 'absolute';
- Position.clone(element, update, {
- setHeight: false,
- offsetTop: element.offsetHeight
- });
- }
- Effect.Appear(update,{duration:0.15});
- },
- afterUpdateElement: function(text, el) {
- if (el.id) { // Autocomplete entry found.
- if (related) { // Attach to related asset.
- new Ajax.Request(this.base_url + "/" + related + "/attach", {
- method : "put",
- parameters : { assets : controller, asset_id : escape(el.id) },
- onComplete : function() { $("auto_complete_query").value = "" ; }//$("jumpbox").hide(); }
- });
- } else { // Quick Find: redirect to asset#show.
- window.location.href = this.base_url + "/" + controller + "/" + escape(el.id);
- }
- } else { // Autocomplete entry not found: refresh current page.
- $("auto_complete_query").value = "";
- window.location.href = window.location.href;
- }
- }.bind(this) // Binding for this.base_url.
- });
- $("auto_complete_dropdown").update("");
- $("auto_complete_query").value = "";
- if (focus) {
- $("auto_complete_query").focus();
- }
- }
-}
-
-document.observe("dom:loaded", function() {
- // the element in which we will observe all clicks and capture
- // ones originating from pagination links
- var container = $(document.body)
-
- if (container) {
- var img = new Image;
- img.src = crm.base_url + '/assets/loading.gif';
-
- function createSpinner() {
- return new Element('img', { src: img.src, 'class': 'spinner' })
- }
-
- container.observe('click', function(e) {
- var el = e.element();
- if (el.match('.pagination a')) {
- el.up('.pagination').update(createSpinner());
- new Ajax.Request(el.href, { method: 'get' });
- e.stop();
- }
- if (el.match('.per_page_options a')) {
- el.up('.per_page_options').update(createSpinner());
- new Ajax.Request(el.href, { method: 'post' });
- e.stop();
- }
- });
- }
-});
-
-// Note: observing "dom:loaded" is supposedly faster that "window.onload" since
-// it will fire immediately after the HTML document is fully loaded, but before
-// images on the page are fully loaded.
-
-// Event.observe(window, "load", function() { crm.focus_on_first_field() })
-document.observe("dom:loaded", function() { crm.focus_on_first_field() });
-
-// Admin Field Tabs
-document.on("click", "*[data-tab-class]", function(event, element) {
- event.stop();
-
- var klass = element.readAttribute('data-tab-class');
- $$(".fields").each(function(el){ el.hide(); });
- $$(".inline_tabs ul li").each(function(el){ el.removeClassName('selected'); });
-
- $(klass + "_section").show();
- element.addClassName('selected');
-});
diff --git a/app/assets/javascripts/crm.js.coffee b/app/assets/javascripts/crm.js.coffee
new file mode 100644
index 0000000000..c1c4d5e02e
--- /dev/null
+++ b/app/assets/javascripts/crm.js.coffee
@@ -0,0 +1,474 @@
+# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+(($) ->
+
+ String::capitalize = ->
+ @[0].toUpperCase() + @.substring(1)
+
+ window.crm =
+ EXPANDED: "▼"
+ COLLAPSED: "►"
+ searchRequest: null
+ autocompleter: null
+ base_url: ""
+ language: "en-US"
+
+ #----------------------------------------------------------------------------
+ find_form: (class_name) ->
+ forms = $("form." + class_name)
+ (if forms.length > 0 then forms[0].id else null)
+
+
+ #----------------------------------------------------------------------------
+ search_tagged: (query, controller) ->
+ $("#query").val(query)
+ crm.search query, controller
+
+ #
+ # * remove any duplicate 'facebook-list' elements before running the 'BlindUp' effect.
+ # * (The disappearing facebook-list takes precedence over the newly created facebook-list
+ # * that is being AJAX loaded, and messes up the initialization.. )
+ #
+ hide_form: (id) ->
+ $("#facebook-list").remove()
+ arrow = $("#" + id + "_arrow")
+ arrow = $("#arrow") unless arrow.length
+ arrow.html(@COLLAPSED)
+ $("#" + id).hide().html("").css height: "auto"
+
+
+ #----------------------------------------------------------------------------
+ show_form: (id) ->
+ arrow = $("#" + id + "_arrow")
+ arrow = $("#arrow") unless arrow.length
+ arrow.html(@EXPANDED)
+ $("#" + id).slideDown(
+ 250
+ ->
+ $("#" + id).find(":input[type=text]:first").focus()
+ )
+
+
+ #----------------------------------------------------------------------------
+ flip_form: (id) ->
+ if $("#" + id + ":visible").length
+ @hide_form id
+ else
+ @show_form id
+
+
+ #----------------------------------------------------------------------------
+ set_title: (id, caption) ->
+ title = $("#" + id + "_title")
+ title = $("#title") unless title.length
+ if typeof (caption) is "undefined"
+ words = id.split("_")
+ if words.length is 1
+ caption = id.capitalize()
+ else
+ caption = words[0].capitalize() + " " + words[1].capitalize()
+ title.html caption
+
+
+ #----------------------------------------------------------------------------
+ highlight_off: (id) ->
+ el = $("#" + id)
+ el.onmouseover = el.onmouseout = null
+ el.css background: "white"
+
+
+ #----------------------------------------------------------------------------
+ focus_on_first_field: ->
+ first_element = $("form:input[type=text]:first")
+ if first_element.length
+ first_element.focus()
+ first_element.val first_element.val()
+ else $("#query").focus()
+
+
+ # Hide accounts dropdown and show create new account edit field instead.
+ #----------------------------------------------------------------------------
+ create_account: (and_focus) ->
+ crm.makeAjaxChosen()
+ $("#account_disabled_title").hide()
+ $("#account_select_title").hide()
+ $("#account_create_title").show()
+ $("#account_id_chzn").hide()
+ $("#account_id").prop('disabled', true)
+ $("#account_name").prop('disabled', false)
+ $("#account_name").html ""
+ $("#account_name").show()
+ $("#account_name").focus() if and_focus
+
+
+ # Hide create account edit field and show accounts dropdown instead.
+ #----------------------------------------------------------------------------
+ select_account: (and_focus) ->
+ crm.makeAjaxChosen()
+ $("#account_disabled_title").hide()
+ $("#account_create_title").hide()
+ $("#account_select_title").show()
+ $("#account_name").hide()
+ $("#account_name").prop('disabled', true)
+ $("#account_id").prop('disabled', false)
+ $("#account_id_chzn").show()
+
+
+ # Show accounts dropdown and disable it to prevent changing the account.
+ #----------------------------------------------------------------------------
+ select_existing_account: ->
+ crm.makeAjaxChosen()
+ $("#account_create_title").hide()
+ $("#account_select_title").hide()
+ $("#account_disabled_title").show()
+ $("#account_name").hide()
+ $("#account_name").prop('disabled', true)
+
+ # Disable chosen account select
+ $("#account_id").prop('disabled', true)
+ $("#account_id").trigger "liszt:updated"
+ $("#account_id_chzn").show()
+
+ # Enable hidden account id select so that value is POSTed
+ $("#account_id").prop('disabled', false)
+
+
+ #----------------------------------------------------------------------------
+ create_or_select_account: (selector) ->
+ if selector isnt true and selector > 0
+ @select_existing_account() # disabled accounts dropdown
+ else if selector
+ @create_account() # create account edit field
+ else
+ @select_account() # accounts dropdown
+
+
+ #----------------------------------------------------------------------------
+ create_contact: ->
+ @clear_all_hints() if $("#contact_business_address_attributes_country")
+ $("#account_assigned_to").val $("contact_assigned_to").val()
+ $("#account_id").prop('disabled', false) if $("#account_id:visible").length
+
+
+ #----------------------------------------------------------------------------
+ save_contact: ->
+ @clear_all_hints() if $("#contact_business_address_attributes_country")
+ $("#account_assigned_to").val $("contact_assigned_to").val()
+
+
+ #----------------------------------------------------------------------------
+ flip_calendar: (value) ->
+ if value is "specific_time"
+ $("#task_bucket").toggle() # Hide dropdown.
+ $("#task_calendar").toggle() # Show editable date field.
+ $("#task_calendar").datepicker().focus() # Focus to invoke calendar popup.
+
+ #----------------------------------------------------------------------------
+ show_repeats: (value) ->
+ $("#repeats").toggle(); # Hide dropdown.
+
+ #----------------------------------------------------------------------------
+ show_scheduled: (value) ->
+ $("scheduled").toggle(); # Hide dropdown.
+
+ #----------------------------------------------------------------------------
+ show_comments: (value) ->
+ $("com_contact_" + value ).toggle(); # show/hide comments section for attendances
+
+ #----------------------------------------------------------------------------
+ flip_campaign_permissions: (value) ->
+ if value
+ $("#lead_access_campaign").prop('disabled', false)
+ $("#lead_access_campaign").checked = 1
+ $("#copy_permissions").css color: "#3f3f3f"
+ else
+ $("#lead_access_campaign").prop('disabled', true)
+ $("#copy_permissions").css color: "grey"
+ $("#lead_access_private").checked = 1
+
+
+ #----------------------------------------------------------------------------
+ flip_subtitle: (el) ->
+ $el = $(el)
+ arrow = $el.find("small")
+ intro = $el.parent().next().children("small")
+
+ # Optionally, the intro might be next to the link.
+ intro = $el.next("small") unless intro.length
+ section = $el.parent().next().children("div")
+ section.slideToggle(
+ 250
+ =>
+ arrow.html(if section.css('display') is 'none' then @COLLAPSED else @EXPANDED)
+ intro.toggle()
+ )
+
+ #----------------------------------------------------------------------------
+ flip_subtitle2: (el) ->
+ $el = $(el)
+ arrow = $el.find("small")
+ #intro = $el.parent().next().children("small")
+
+ # Optionally, the intro might be next to the link.
+ #intro = $el.next("small") unless intro.length
+ section = $el.parent().parent().next().children("div")
+ section.slideToggle(
+ 250
+ =>
+ arrow.html(if section.css('display') is 'none' then @COLLAPSED else @EXPANDED)
+ #intro.toggle()
+ )
+
+
+ #----------------------------------------------------------------------------
+ flip_note_or_email: (link, more, less) ->
+ body = undefined
+ state = undefined
+ if link.innerHTML is more
+ body = $(link).parent().next()
+ body.hide()
+ $("#" + body.attr('id').replace("truncated", "formatted")).show() # expand
+ link.innerHTML = less
+ state = "Expanded"
+ else
+ body = $(link).parent().next().next()
+ body.hide()
+ $("#" + body.attr('id').replace("formatted", "truncated")).show() # collapse
+ link.innerHTML = more
+ state = "Collapsed"
+
+ # Ex: "formatted_email_42" => [ "formatted", "email", "42" ]
+ arr = body.attr('id').split("_")
+ $.get(@base_url + "/home/timeline", {
+ type: arr[1]
+ id: arr[2]
+ state: state
+ })
+
+
+ #----------------------------------------------------------------------------
+ flip_notes_and_emails: (state, more, less, el_prefix) ->
+ unless el_prefix
+ notes_field = "#shown_notes"
+ emails_field = "#shown_emails"
+ comment_new_field = "#comment_new"
+ else
+ notes_field = "#" + el_prefix + "_shown_notes"
+ emails_field = "#" + el_prefix + "_shown_emails"
+ comment_new_field = "#" + el_prefix + "_comment_new"
+
+ $(comment_new_field).siblings("li").each ->
+ $li = $(this)
+ $a = $li.find("tt a.toggle")
+ $dt = $li.find("dt")
+ if $a.length
+ if state is "Expanded"
+ $($dt[0]).hide()
+ $($dt[1]).show()
+ $a.html(less)
+ else
+ $($dt[0]).show()
+ $($dt[1]).hide()
+ $a.html(more)
+
+ notes = $(notes_field).val()
+ emails = $(emails_field).val()
+ if notes isnt "" or emails isnt ""
+ $.post(@base_url + "/home/timeline"
+ {
+ type: ""
+ id: notes + "+" + emails
+ state: state
+ }
+ )
+
+ #----------------------------------------------------------------------------
+ copyToClipboard: (text) ->
+ window.prompt "Copy to clipboard: Ctrl+C, Enter", text
+
+ #----------------------------------------------------------------------------
+ reschedule_task: (id, bucket) ->
+ $("#task_bucket").val bucket
+ $("#edit_task_" + id + " input[type=submit]")[0].click()
+
+
+ #----------------------------------------------------------------------------
+ flick: (id, action) ->
+ $el = $("#" + id)
+ if $el.length
+ switch action
+ when "show"
+ $el.show()
+ when "hide"
+ $el.hide()
+ when "clear"
+ $el.html ""
+ when "remove"
+ $el.remove()
+ when "toggle"
+ $el.toggle()
+
+
+ #----------------------------------------------------------------------------
+ flash: (type, sticky) ->
+ $el = $("#flash")
+ $el.hide()
+ if type is "warning" or type is "error"
+ $el.addClass "flash_warning"
+ else
+ $el.addClass "flash_notice"
+ $el.fadeIn 500
+
+ setTimeout (-> $el.fadeOut(500)), 3000 unless sticky
+
+
+ #----------------------------------------------------------------------------
+ # Will be deprecated soon: html5 placeholder replaced it on address fields
+ show_hint: (el, hint) ->
+ $el = $(el)
+ if $el.val() is ""
+ $el.val hint
+ $el.css color: "silver"
+ $el.attr "hint", true
+
+
+ #----------------------------------------------------------------------------
+ # Will be deprecated soon: html5 placeholder replaced it on address fields
+ hide_hint: (el, value) ->
+ $el = $(el)
+ if arguments.length is 2
+ $el.val value
+ else
+ $el.val("") if $el.attr("hint") is "true"
+ $el.css color: "black"
+ $el.attr "hint", false
+
+
+ #----------------------------------------------------------------------------
+ # Will be deprecated soon: html5 placeholder replaced it on address fields
+ clear_all_hints: ->
+ for field in $("input[hint=true]")
+ $(field).val ""
+
+
+ #----------------------------------------------------------------------------
+ copy_address: (from, to) ->
+ $("#" + from + "_attributes_full_address").val $("#" + to + "_attributes_full_address").val()
+
+
+ #----------------------------------------------------------------------------
+ copy_compound_address: (from, to) ->
+ for field in ["street1", "street2", "city", "state", "zipcode"]
+ source = $("#" + from + "_attributes_" + field)
+ destination = $("#" + to + "_attributes_" + field)
+ @hide_hint destination, source.val() unless source.attr("hint") is "true"
+
+ # Country dropdown needs special treatment ;-)
+ country = $("#" + from + "_attributes_country").select2("data")
+ $("#" + to + "_attributes_country").select2("data", country, true)
+
+
+ #----------------------------------------------------------------------------
+ search: (query, controller) ->
+ list = controller # ex. "users"
+ # ex. "admin/users"
+ list = list.split("/")[1] if list.indexOf("/") >= 0
+ $("#loading").show()
+ $list = $(list)
+ $list.css opacity: 0.4
+ @searchRequest.abort() if @searchRequest and @searchRequest.readyState isnt -4
+ @searchRequest = $.get(
+ @base_url + "/" + controller + ".js"
+ query: query
+ ->
+ $("#loading").hide()
+ $list.css opacity: 1
+ @searchRequest = null
+ )
+
+ #----------------------------------------------------------------------------
+ search_show: (query, controller, related_id, list) ->
+ #list = controller # ex. "users"
+ # ex. "admin/users"
+ #list = list.split("/")[1] if list.indexOf("/") >= 0
+ $("#loading").show()
+ $list = $(list)
+ $list.css opacity: 0.4
+ @searchRequest.abort() if @searchRequest and @searchRequest.readyState isnt -4
+ @searchRequest = $.get(
+ @base_url + "/" + controller + "/" + related_id + "/redraw_show.js"
+ query: query
+ ->
+ $("#loading").hide()
+ $list.css opacity: 1
+ @searchRequest = null
+ )
+
+
+ #----------------------------------------------------------------------------
+ jumper: (controller) ->
+ name = controller #.capitalize()
+ $("#jumpbox_menu a").each ->
+ $(this).toggleClass("selected", $(this).attr('html-data') is name) #the internal controller name, so this can work with i18
+
+ @auto_complete controller, null, true
+ $("#auto_complete_query").focus()
+
+
+ #----------------------------------------------------------------------------
+ auto_complete: (controller, related, focus) ->
+ $("#auto_complete_query").autocomplete(
+ source: (request, response) =>
+ request = {auto_complete_query: request['term'], related: related}
+ $.get @base_url + "/" + controller + "/auto_complete.json", request, (data) ->
+ response $.map(data, (value, key) ->
+ label: value
+ value: key
+ )
+
+ # Attach to related asset.
+ # Quick Find: redirect to asset#show.
+ select: (event, ui) => # Binding for this.base_url.
+ event.preventDefault()
+ if ui.item
+ if related
+ $.ajax(@base_url + "/" + related + "/attach", type: 'PUT', data: {
+ assets: controller
+ asset_id: ui.item.value
+ }
+ ).then ->
+ $("#auto_complete_query").val ""
+ else
+ window.location.href = @base_url + "/" + controller + "/" + ui.item.value
+
+ focus: (event, ui) =>
+ event.preventDefault()
+ $("#auto_complete_query").val(ui.item.label)
+ )
+
+ $.extend $.ui.autocomplete::,
+ _renderItem: (ul, item) ->
+ term = @element.val()
+ html = item.label.replace(term, "$& ")
+ $(" ").data("item.autocomplete", item).append($(" ").html(html)).appendTo ul
+
+ #----------------------------------------------------------------------------
+ # Define different icons for each entity type
+ get_icon: (listType) ->
+ switch (listType)
+ when "tasks" then "fa-check-square-o"
+ when "campaigns" then "fa-bar-chart-o"
+ when "leads" then "fa-tasks"
+ when "accounts" then "fa-users"
+ when "contacts" then "fa-user"
+ when "opportunities" then "fa-money"
+ when "team" then "fa-globe"
+
+
+ $ ->
+ crm.focus_on_first_field()
+
+) jQuery
diff --git a/app/assets/javascripts/crm_chosen.js.coffee b/app/assets/javascripts/crm_chosen.js.coffee
index 192e4e7e28..87aa3d0436 100644
--- a/app/assets/javascripts/crm_chosen.js.coffee
+++ b/app/assets/javascripts/crm_chosen.js.coffee
@@ -3,46 +3,27 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-# Initialize chosen for multiselect tag list
-crm.chosen_taglist = (asset, controller, id)->
- new Chosen $(asset + '_tag_list'), {
- allow_option_creation: true
- on_option_add: (tag) ->
- crm.load_field_group(controller, tag, id)
- on_option_remove: (tag) ->
- crm.remove_field_group(tag)
- }
+(($) ->
-crm.ensure_chosen_account = ->
- unless $("account_id_chzn")
- new ajaxChosen $("account_id"), {
- allow_single_deselect: true
- show_on_activate: true
- url: "/accounts/auto_complete.json"
- parameters: { limit: 25 }
- query_key: "auto_complete_query"
- }
+ window.crm ||= {}
-(($j) ->
-
- # Prefer standard select2 dropdown for non-Ajaxy selectboxes
- add_select2_boxes = ->
- $j("select[name*='assigned_to'], select[name*='[country]'], .chzn-select" ).each ->
- $j(this).select2()
+ # Use the 'ajax_chosen' class on select boxes that need to lookup values from server
+ # Each select should have a 'data-url' attribute to specify the autocomplete path
+ #----------------------------------------------------------------------------
+ crm.makeAjaxChosen = ->
+ $("select.ajax_chosen").each ->
+ $(this).ajaxChosen({
+ url: $(this).data('url')
+ jsonTermKey: "auto_complete_query",
+ minTermLength: 2},
+ null,
+ {allow_single_deselect: true, show_on_activate: true}
+ )
- # Apply pop up to merge links when document is loaded
- $j(document).ready ->
- add_select2_boxes()
+ $(document).ready ->
+ crm.makeAjaxChosen()
- # Apply pop up to merge links when jquery event (e.g. search) occurs
- $j(document).ajaxComplete ->
- add_select2_boxes()
+ $(document).ajaxComplete ->
+ crm.makeAjaxChosen()
- # Apply pop up to merge links when protoype event (e.g. cancel edit) occurs
- Ajax.Responders.register({
- onComplete: ->
- add_select2_boxes()
-
- })
-
-) (jQuery)
+) jQuery
diff --git a/app/assets/javascripts/crm_classes.js b/app/assets/javascripts/crm_classes.js
deleted file mode 100644
index c06f191ead..0000000000
--- a/app/assets/javascripts/crm_classes.js
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-//
-// Fat Free CRM is freely distributable under the terms of MIT license.
-// See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-//------------------------------------------------------------------------------
-if (Object.isUndefined(crm)) {
- var crm = {};
-};
-
-crm.Popup = Class.create({
-
- //----------------------------------------------------------------------------
- initialize: function() {
- this.options = Object.extend({
- trigger : "trigger", // #id of the element that triggers on_mouseover popup.
- target : "popup", // #id of the popup div that is shown or hidden.
- appear : 0, // duration of EffectAppear or 0 for show().
- fade : 0, // duration of EffectFade or 0 for hide().
- under : false, // true to show popup right under the trigger div.
- zindex : 100, // zIndex value for the popup.
- before_show : Prototype.emptyFunction, // before show callback.
- before_hide : Prototype.emptyFunction, // before hide callback.
- after_show : Prototype.emptyFunction, // after show callback.
- after_hide : Prototype.emptyFunction // after hide callback.
- }, arguments[0] || {});
-
- this.popup = $(this.options.target); // actual popup div.
-
- this.setup_toggle_observer();
- this.setup_hide_observer();
- },
-
- //----------------------------------------------------------------------------
- setup_toggle_observer: function() {
- $(this.options.trigger).observe("click", function(e) {
- this.toggle_popup(e);
- }.bind(this));
- },
-
- //----------------------------------------------------------------------------
- setup_hide_observer: function() {
- document.observe("click", function(e) {
- if (this.popup && this.popup.visible()) {
- var clicked_on = Event.findElement(e, "div");
- if (typeof(clicked_on) == "undefined" || clicked_on.id != this.options.target) {
- this.hide_popup(e);
- }
- }
- }.bind(this));
- },
-
- //----------------------------------------------------------------------------
- show_popup: function(e) {
- e.stop();
- this.popup.setStyle({ zIndex: this.options.zindex });
-
- // Add custom "trigger" attribute to the popup div so we could check who has triggered it.
- this.popup.writeAttribute("trigger", this.options.trigger);
-
- this.options.before_show(e);
- if (!this.options.appear) {
- this.popup.show();
- this.set_position(e);
- this.options.after_show(e);
- } else {
- this.popup.show();
- this.set_position(e);
- this.popup.hide();
- Effect.Appear(this.popup, { duration: this.options.appear, afterFinish: function(e) { this.options.after_show(e); }.bind(this) });
- }
- },
-
- //----------------------------------------------------------------------------
- toggle_popup: function(e) {
- if (this.popup.visible()) {
- if (this.options.trigger != this.popup.readAttribute("trigger")) {
- // Currently shown popup was opened by some other trigger: hide it immediately
- // without any fancy callbacks, then show this popup.
- this.popup.hide();
- this.show_popup(e);
- } else {
- this.hide_popup(e);
- }
- } else {
- this.show_popup(e);
- }
- },
-
- //----------------------------------------------------------------------------
- hide_popup: function(e) {
- this.options.before_hide(e);
- if (!this.options.fade) {
- this.popup.hide();
- this.options.after_hide(e);
- } else {
- Effect.Fade(this.popup, { duration: this.options.fade, afterFinish: function(e) { this.options.after_hide(e); }.bind(this) });
- }
- },
-
- set_position: function(e) {
- if (this.options.under) {
- var coordinates = $(this.options.under).viewportOffset();
- var under = $(this.options.under)
- var popup = $(this.popup)
- var y_offset = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
-
- var x = (coordinates[0] + under.offsetWidth - popup.offsetWidth) + "px";
- var y = (coordinates[1] + under.offsetHeight + y_offset) + "px";
- this.popup.setStyle({ left: x, top: y });
- }
- }
-
-});
-
-
-crm.Menu = Class.create({
-
- //----------------------------------------------------------------------------
- initialize: function() {
- this.options = Object.extend({
- trigger : "menu", // #id of the element clicking on which triggers dropdown menu.
- align : "left", // align the menu left or right
- appear : 0, // duration of EffectAppear or 0 for show().
- fade : 0, // duration of EffectFade or 0 for hide().
- width : 0, // explicit menu width if set to non-zero
- zindex : 100, // zIndex value for the popup.
- before_show : Prototype.emptyFunction, // before show callback.
- before_hide : Prototype.emptyFunction, // before hide callback.
- after_show : Prototype.emptyFunction, // after show callback.
- after_hide : Prototype.emptyFunction // after hide callback.
- }, arguments[0] || {});
-
- this.build_menu();
- this.setup_show_observer();
- this.setup_hide_observer();
- },
-
- //----------------------------------------------------------------------------
- build_menu: function() {
- var ul = new Element("ul");
- this.options.menu_items.each(function(item) {
- var a = new Element("a", { href: "#", title: item.name });
- if (item.on_select) {
- a = Object.extend(a, { on_select: item.on_select });
- }
- var li = new Element("li").insert(a.observe("click", this.select_menu.bind(this)).update(item.name));
- ul.insert(li);
- }.bind(this));
-
- this.menu = new Element("div", { className: "menu", style: "display:none" });
- if (this.options.width) {
- this.menu.setStyle({ width: this.options.width + "px" })
- }
- $(document.body).insert(this.menu.insert(ul).observe("click", Event.stop));
- },
-
- //----------------------------------------------------------------------------
- setup_hide_observer: function() {
- document.observe("click", function(e) {
- if (this.menu && this.menu.visible()) {
- this.hide_menu();
- }
- }.bind(this));
- },
-
- //----------------------------------------------------------------------------
- setup_show_observer: function() {
- $(this.options.trigger).observe("click", function(e) {
- if (this.menu && !this.menu.visible()) {
- this.show_menu(e);
- }
- }.bind(this));
- },
-
- //----------------------------------------------------------------------------
- hide_menu: function(e) {
- this.options.before_hide(e);
- if (!this.options.fade) {
- this.menu.hide();
- this.options.after_hide(e);
- } else {
- Effect.Fade(this.menu, { duration: this.options.fade, afterFinish: function(e) { this.options.after_hide(e); }.bind(this) });
- }
- },
-
- //----------------------------------------------------------------------------
- show_menu: function(e) {
- e.stop();
-
- var dimensions = Event.element(e).getDimensions();
- var coordinates = Event.element(e).viewportOffset();
- var x = coordinates[0] + "px";
- var y = coordinates[1] + dimensions.height + "px";
- if (this.options.align == "right") {
- x = (coordinates[0] - (this.options.width - dimensions.width + 1)) + "px";
- }
-
- this.menu.setStyle({ left: x, top: y }).setStyle({ zIndex: this.options.zindex });
-
- this.options.before_show(e);
- if (!this.options.appear) {
- this.menu.show();
- this.options.after_show(e);
- } else {
- Effect.Appear(this.menu, { duration: this.options.appear, afterFinish: function(e) { this.options.after_show(e); }.bind(this) });
- }
- this.event = e;
- },
-
- //----------------------------------------------------------------------------
- select_menu: function(e) {
- e.stop();
- if (e.target.on_select) {
- this.hide_menu();
- e.target.on_select(this.event);
- }
- }
-});
diff --git a/app/assets/javascripts/crm_classes.js.coffee b/app/assets/javascripts/crm_classes.js.coffee
new file mode 100644
index 0000000000..e626d6ecd4
--- /dev/null
+++ b/app/assets/javascripts/crm_classes.js.coffee
@@ -0,0 +1,215 @@
+# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+(($) ->
+
+ window.crm ||= {}
+
+ class crm.Popup
+
+ #----------------------------------------------------------------------------
+ constructor: (options = {}) ->
+ @options = $.extend(
+ trigger: "#trigger" # #id of the element that triggers on_mouseover popup.
+ target: "#popup" # #id of the popup div that is shown or hidden.
+ appear: 0 # duration of EffectAppear or 0 for show().
+ fade: 0 # duration of EffectFade or 0 for hide().
+ under: false # true to show popup right under the trigger div.
+ zindex: 100 # zIndex value for the popup.
+ before_show: $.noop # before show callback.
+ before_hide: $.noop # before hide callback.
+ after_show: $.noop # after show callback.
+ after_hide: $.noop # after hide callback.
+ , options)
+ @popup = $(@options.target) # actual popup div.
+ @setup_toggle_observer()
+ @setup_hide_observer()
+
+
+ #----------------------------------------------------------------------------
+ setup_toggle_observer: ->
+ $(@options.trigger).on "click", (e) =>
+ @toggle_popup e
+
+
+ #----------------------------------------------------------------------------
+ setup_hide_observer: ->
+ $(document).on "click", (e) =>
+ if @popup and @popup.css('display') isnt 'none'
+ clicked_on = $(e.target).closest("div")
+ @hide_popup e if clicked_on.length is 0 or ('#' + clicked_on.attr('id')) isnt @options.target
+
+
+ #----------------------------------------------------------------------------
+ show_popup: (e) ->
+ e.preventDefault()
+ e.stopPropagation()
+ @popup.css zIndex: @options.zindex
+
+ # Add custom "trigger" attribute to the popup div so we could check who has triggered it.
+ @popup.attr trigger: @options.trigger
+ @options.before_show e
+ unless @options.appear
+ @popup.show()
+ @set_position e
+ @options.after_show e
+ else
+ @set_position e
+ @popup.fadeIn(
+ @options.appear
+ @options.after_show
+ )
+
+
+ #----------------------------------------------------------------------------
+ toggle_popup: (e) ->
+ if @popup.filter(':visible').length
+ unless @options.trigger is @popup.attr("trigger")
+
+ # Currently shown popup was opened by some other trigger: hide it immediately
+ # without any fancy callbacks, then show this popup.
+ @popup.hide()
+ @show_popup e
+ else
+ @hide_popup e
+ else
+ @show_popup e
+
+
+ #----------------------------------------------------------------------------
+ hide_popup: (e) ->
+ e.preventDefault() if e
+ @options.before_hide e
+ unless @options.fade
+ @popup.hide()
+ @options.after_hide e
+ else
+ @popup.fadeOut(
+ @options.fade
+ @options.after_hide
+ )
+
+ set_position: (e) ->
+ if @options.under
+ under = $(@options.under)
+ popup = $(@popup)
+ offset = under.offset()
+ x = (offset.left + under.width() - popup.width()) + "px"
+ y = (offset.top + under.height()) + "px"
+ @popup.css
+ left: x
+ top: y
+
+
+
+ class crm.Menu
+
+ #----------------------------------------------------------------------------
+ constructor: (options = {}) ->
+ @options = $.extend(
+ trigger: "#menu" # #id of the element clicking on which triggers dropdown menu.
+ align: "left" # align the menu left or right
+ appear: 0 # duration of EffectAppear or 0 for show().
+ fade: 0 # duration of EffectFade or 0 for hide().
+ width: 0 # explicit menu width if set to non-zero
+ zindex: 100 # zIndex value for the popup.
+ before_show: $.noop # before show callback.
+ before_hide: $.noop # before hide callback.
+ after_show: $.noop # after show callback.
+ after_hide: $.noop # after hide callback.
+ , options)
+ @build_menu()
+ @setup_show_observer()
+ @setup_hide_observer()
+
+
+ #----------------------------------------------------------------------------
+ build_menu: ->
+ @menu = $("",
+ class: "menu"
+ style: "display:none;";
+ on:
+ click: (e) ->
+ e.preventDefault()
+ )
+ @menu.css width: @options.width + "px" if @options.width
+ @menu.appendTo(document.body)
+
+ ul = $("
")
+ ul.appendTo(@menu)
+
+ for item in @options.menu_items
+ li = $("")
+ li.appendTo(ul)
+ a = $("",
+ href: "#"
+ title: item.name
+ on:
+ click: @select_menu.bind(this)
+ ).html(item.name)
+ a.data(on_select: item.on_select) if item.on_select
+ a.appendTo(li)
+
+
+ #----------------------------------------------------------------------------
+ setup_hide_observer: ->
+ $(document).on "click", (e) =>
+ @hide_menu(e) if @menu and @menu.css('display') isnt 'none'
+
+
+ #----------------------------------------------------------------------------
+ setup_show_observer: ->
+ $(@options.trigger).on "click", (e) =>
+ @show_menu(e) if @menu and @menu.css('display') is 'none'
+
+
+ #----------------------------------------------------------------------------
+ hide_menu: (e) ->
+ @options.before_hide e
+ unless @options.fade
+ @menu.hide()
+ @options.after_hide e
+ else
+ @menu.fadeOut(
+ @options.fade
+ @options.after_hide
+ )
+
+
+ #----------------------------------------------------------------------------
+ show_menu: (e) ->
+ e.preventDefault()
+ e.stopPropagation()
+ $el = $(e.target)
+ offset = $el.offset()
+ x = offset.left + "px"
+ y = offset.top + $el.height() + "px"
+ x = (offset.left - (@options.width - $el.width() + 1)) + "px" if @options.align is "right"
+ @menu.css
+ left: x
+ top: y
+ zIndex: @options.zindex
+ @options.before_show e
+ unless @options.appear
+ @menu.show()
+ @options.after_show e
+ else
+ @menu.fadeIn(
+ @options.appear
+ @options.after_show
+ )
+
+ @event = e
+
+
+ #----------------------------------------------------------------------------
+ select_menu: (e) ->
+ e.preventDefault()
+ $el = $(e.target)
+ if on_select = $el.data('on_select')
+ @hide_menu()
+ on_select @event
+
+) jQuery
diff --git a/app/assets/javascripts/crm_comments.js.coffee b/app/assets/javascripts/crm_comments.js.coffee
new file mode 100644
index 0000000000..a7295d1db2
--- /dev/null
+++ b/app/assets/javascripts/crm_comments.js.coffee
@@ -0,0 +1,28 @@
+# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+
+(($) ->
+
+ # Show/hide the comment form
+ $(document).on 'click', '.new_comment a.cancel, input[name=post_new_note]', ->
+ $container = $(this).closest('div.new_comment')
+ baseId = $container.attr('id').replace('_comment_new', '')
+ $post = $container.find('#' + baseId + '_post')
+ $ask = $container.find('#' + baseId + '_ask')
+ $comment = $container.find('#' + baseId + '_comment_comment')
+ $post.toggle()
+ $ask.toggle()
+ if $comment.is(":visible")
+ $container.find('form [type=submit]').removeAttr("disabled")
+ $container.find('.spinner').hide()
+ crm.textarea_user_autocomplete(baseId + '_comment_comment')
+ $comment.focus()
+
+ # When comment form is submitted, disable the form button and show the spinner
+ $(document).on 'submit', 'form.new_comment', ->
+ $(this).find('input[type=submit]').attr("disabled", "disabled").prev('.spinner').show()
+
+)(jQuery)
diff --git a/app/assets/javascripts/crm_draggable.js.coffee b/app/assets/javascripts/crm_draggable.js.coffee
new file mode 100644
index 0000000000..3a907eba2d
--- /dev/null
+++ b/app/assets/javascripts/crm_draggable.js.coffee
@@ -0,0 +1,33 @@
+(($) ->
+ window.crm ||= {}
+
+ crm.init_draggables = ->
+ $('.draggable').draggable(
+ #revert: true
+ handle: '.gravatar'
+ scroll: true
+ helper: "clone"
+ opacity: 0.6
+ )
+
+ crm.init_droppables = ->
+ $('.droppable').droppable(
+ hoverClass: "dropover"
+ tolerance: "pointer"
+ drop: (event, ui) ->
+ $.post( window.crm.base_url + "/" + this.id.split("_")[0] + "s/" + this.id.split("_").pop() + "/move_contact"
+ {
+ contact_id: ui.draggable.attr('id').split("_").pop()
+ }
+ )
+ )
+
+ $(document).ready ->
+ crm.init_draggables()
+ crm.init_droppables()
+
+ $(document).ajaxComplete ->
+ crm.init_draggables()
+ crm.init_droppables()
+
+) jQuery
diff --git a/app/assets/javascripts/crm_fields.js b/app/assets/javascripts/crm_fields.js
deleted file mode 100644
index a9ac2a0ff1..0000000000
--- a/app/assets/javascripts/crm_fields.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-//
-// Fat Free CRM is freely distributable under the terms of MIT license.
-// See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-//------------------------------------------------------------------------------
-//----------------------------------------------------------------------------
-// AJAX loads the form fields for each field group
-crm.load_field_group = function(controller, tag, asset_id) {
- new Ajax.Request(crm.base_url + '/' + controller +'/field_group', {
- asynchronous: true,
- evalScripts: true,
- method: 'get',
- parameters: { tag : tag,
- asset_id : asset_id,
- collapsed : "no" }
- });
-};
-
-//----------------------------------------------------------------------------
-// Remove the form fields for the field group with the given tag
-crm.remove_field_group = function(tag) {
- el = $$("#field_groups div[data-tag='"+tag+"']")[0];
- if (el) el.remove();
-}
-
-
-//----------------------------------------------------------------------------
-// Fires an 'onclick' event on all '.close' buttons in the DOM.
-// (closes any current edit forms)
-crm.close_all_forms = function() {
- $$('.close').each(function(el){
- new Ajax.Request(el.href, {asynchronous: true, method: "get"})
- });
-};
diff --git a/app/assets/javascripts/crm_loginout.js b/app/assets/javascripts/crm_loginout.js
deleted file mode 100644
index 915fa71f93..0000000000
--- a/app/assets/javascripts/crm_loginout.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-//
-// Fat Free CRM is freely distributable under the terms of MIT license.
-// See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-//------------------------------------------------------------------------------
-if (Object.isUndefined(crm)) {
- var crm = {};
-};
-
-//----------------------------------------------------------------------------
-crm.toggle_open_id_login = function(first_field) {
- if (arguments.length == 0) {
- first_field = "authentication_openid_identifier";
- }
- $("login").toggle();
- $("openid").toggle();
- $("login_link").toggle();
- $("openid_link").toggle();
- $(first_field).focus();
- };
-
-//----------------------------------------------------------------------------
-crm.toggle_open_id_signup = function() {
- $("login").toggle();
- $("openid").toggle();
- $("login_link").toggle();
- $("openid_link").toggle();
- $('user_email').focus();
- };
diff --git a/app/assets/javascripts/crm_loginout.js.coffee b/app/assets/javascripts/crm_loginout.js.coffee
new file mode 100644
index 0000000000..b643105b68
--- /dev/null
+++ b/app/assets/javascripts/crm_loginout.js.coffee
@@ -0,0 +1,27 @@
+# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+(($) ->
+
+ window.crm ||= {}
+
+ #----------------------------------------------------------------------------
+ crm.toggle_open_id_login = (first_field = "#authentication_openid_identifier") ->
+ $("#login").toggle()
+ $("#openid").toggle()
+ $("#login_link").toggle()
+ $("#openid_link").toggle()
+ $(first_field).focus()
+
+
+ #----------------------------------------------------------------------------
+ crm.toggle_open_id_signup = ->
+ $("#login").toggle()
+ $("#openid").toggle()
+ $("#login_link").toggle()
+ $("#openid_link").toggle()
+ $("#user_email").focus()
+
+) jQuery
diff --git a/app/assets/javascripts/crm_select2.js.coffee b/app/assets/javascripts/crm_select2.js.coffee
new file mode 100644
index 0000000000..90aae80287
--- /dev/null
+++ b/app/assets/javascripts/crm_select2.js.coffee
@@ -0,0 +1,22 @@
+# Copyright (c) 2008-2014 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+
+# Any select box with 'select2' class will be transformed
+(($) ->
+
+ window.crm ||= {}
+
+ crm.make_select2 = ->
+ $("select.select2").each ->
+ $(this).select2({ 'width':'resolve' })
+
+ $(document).ready ->
+ crm.make_select2()
+
+ $(document).ajaxComplete ->
+ crm.make_select2()
+
+) jQuery
diff --git a/app/assets/javascripts/crm_sortable.js.coffee b/app/assets/javascripts/crm_sortable.js.coffee
new file mode 100644
index 0000000000..ef25b7c960
--- /dev/null
+++ b/app/assets/javascripts/crm_sortable.js.coffee
@@ -0,0 +1,32 @@
+(($) ->
+ window.crm ||= {}
+
+ crm.init_sortables = ->
+ $('[data-sortable]').each ->
+ $el = $(this)
+
+ checkEmpty = ->
+ $el.children('.empty').toggle($el.sortable('toArray').length is 1)
+
+ $el.sortable(
+ forcePlaceholderSize: true
+ connectWith: $el.data('sortable-connect-with')
+ handle: $el.data('sortable-handle')
+ create: checkEmpty
+ update: ->
+ ids = []
+ for dom_id in $el.sortable('toArray')
+ ids.push dom_id.replace(/[^\d]/g, '')
+ data = {}
+ data[$el.attr('id')] = ids
+ $.post($el.attr('data-sortable'), data)
+ checkEmpty()
+ )
+
+ $(document).ready ->
+ crm.init_sortables()
+
+ $(document).ajaxComplete ->
+ crm.init_sortables()
+
+) jQuery
diff --git a/app/assets/javascripts/crm_tags.js.coffee b/app/assets/javascripts/crm_tags.js.coffee
new file mode 100644
index 0000000000..e6a075d4a9
--- /dev/null
+++ b/app/assets/javascripts/crm_tags.js.coffee
@@ -0,0 +1,26 @@
+# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+(($) ->
+
+ window.crm ||= {}
+
+ # The multiselect tag list has listeners to load/remove tag fieldsets
+ #----------------------------------------------------------------------------
+ crm.chosen_taglist = (asset, controller, id) ->
+ $('#' + asset + '_tag_list').chosen(
+ allow_option_creation: true
+ ).on('change', (event, params = {}) ->
+ if tag = params.selected
+ $.get(crm.base_url + "/" + controller + "/field_group", {
+ tag: tag
+ asset_id: id
+ collapsed: "no"
+ })
+ else if tag = params.deselected
+ $("#field_groups div[data-tag='" + tag + "']").remove()
+ )
+
+) jQuery
diff --git a/app/assets/javascripts/crm_textarea_autocomplete.js b/app/assets/javascripts/crm_textarea_autocomplete.js
deleted file mode 100644
index 68fd06c8a1..0000000000
--- a/app/assets/javascripts/crm_textarea_autocomplete.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-//
-// Fat Free CRM is freely distributable under the terms of MIT license.
-// See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-//------------------------------------------------------------------------------
-crm.textarea_user_autocomplete = function(el_id) {
- if (! jQuery('#areacomplete_' + el_id)[0]) {
- jQuery('#' + el_id).areacomplete({
- wordCount: 1,
- mode: "outter",
- on: {
- query: function(text,cb) {
- // Only autocomplete if search term starts with '@'
- if (text.indexOf("@") != 0) { return []; }
-
- var words = [];
- for( var i=0; i < _ffcrm_users.length; i++ ) {
- var name_query = text.replace("@",'').toLowerCase();
- if (_ffcrm_users[i].toLowerCase().indexOf(name_query) != -1 ) {
- words.push(_ffcrm_users[i]);
- }
- }
- cb(words, text.replace("@",''));
- },
- selected: function(text, data) {
- var username_regEx = new RegExp("\\((@[^)]+)\\)");
- return text.match(username_regEx)[1];
- }
- }
- });
- }
-}
diff --git a/app/assets/javascripts/crm_textarea_autocomplete.js.coffee b/app/assets/javascripts/crm_textarea_autocomplete.js.coffee
new file mode 100644
index 0000000000..9de3c7399c
--- /dev/null
+++ b/app/assets/javascripts/crm_textarea_autocomplete.js.coffee
@@ -0,0 +1,33 @@
+# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+(($) ->
+
+ window.crm ||= {}
+
+ crm.textarea_user_autocomplete = (el_id) ->
+ unless $("#areacomplete_" + el_id)[0]
+ $("#" + el_id).areacomplete
+ wordCount: 1
+ mode: "outter"
+ on:
+ query: (text, cb) ->
+
+ # Only autocomplete if search term starts with '@'
+ return [] unless text.indexOf("@") is 0
+ words = []
+ i = 0
+
+ while i < _ffcrm_users.length
+ name_query = text.replace("@", "").toLowerCase()
+ words.push _ffcrm_users[i] unless _ffcrm_users[i].toLowerCase().indexOf(name_query) is -1
+ i++
+ cb words, text.replace("@", "")
+
+ selected: (text, data) ->
+ username_regEx = new RegExp("\\((@[^)]+)\\)")
+ text.match(username_regEx)[1]
+
+) jQuery
diff --git a/app/assets/javascripts/datepicker.js.coffee b/app/assets/javascripts/datepicker.js.coffee
index 70d6c52327..a3d4e2a5af 100644
--- a/app/assets/javascripts/datepicker.js.coffee
+++ b/app/assets/javascripts/datepicker.js.coffee
@@ -5,13 +5,13 @@
#------------------------------------------------------------------------------
(($) ->
- $('input.date').live 'click focus', ->
- $(this).datepicker({
- showOn: 'focus',
- changeMonth: true,
- dateFormat: 'dd/mm/yy'})
+ $(document).on 'click focus', 'input.date', ->
+ $(this).datepicker({
+ showOn: 'focus',
+ changeMonth: true,
+ dateFormat: 'yy-mm-dd'})
- $('input.datetime').live 'click focus', ->
+ $(document).on 'click focus', 'input.datetime', ->
$(this).datetimepicker({
showOn: 'focus',
controlType: 'select',
diff --git a/app/assets/javascripts/format_buttons.js.coffee b/app/assets/javascripts/format_buttons.js.coffee
index c3d9ac12a5..671f3e9fe0 100644
--- a/app/assets/javascripts/format_buttons.js.coffee
+++ b/app/assets/javascripts/format_buttons.js.coffee
@@ -3,51 +3,50 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-(($j) ->
+(($) ->
- $j('a[data-view]').live 'click', ->
+ $(document).on 'click', 'a[data-view]', ->
- if $j(this).data('context') == 'show'
+ if $(this).data('context') == 'show'
# replace the '#main' div with the new 'show' contents
- $j.ajax(
- url: $j(this).data('url'),
+ $.ajax(
+ url: $(this).data('url'),
dataType: "script"
data:
- view: $j(this).data('view')
+ view: $(this).data('view')
beforeSend: ->
- $j('#loading').show()
+ $('#loading').show()
complete: ->
- $j('#loading').hide()
+ $('#loading').hide()
)
- else
+ else
# update the index view by firing off the searches again
- if $j('#search .tabs li a[data-search-form="advanced_search"].active').length == 1
+ if $('#search .tabs li a[data-search-form="advanced_search"].active').length == 1
# handle view change via advanced search form by setting the hidden 'view' field
- $j('#advanced_search_view').remove()
- $j("#advanced_search form input:submit").before(' ')
- $j("#advanced_search form input:submit").click()
+ $('#advanced_search_view').remove()
+ $("#advanced_search form input:submit").before(' ')
+ $("#advanced_search form input:submit").click()
else
# basic search
- $j.ajax(
- url: $j(this).data('url'),
- type: "POST",
+ $.ajax(
+ url: $(this).data('url'),
dataType: "script"
data:
- view: $j(this).data('view')
- query: $('query').value
+ view: $(this).data('view')
+ query: $('#query').val()
beforeSend: ->
- $j('#contacts').css({ opacity: 0.4 })
- $j('#loading').show()
+ $('#contacts').css({ opacity: 0.4 })
+ $('#loading').show()
complete: ->
- $j('#contacts').css({ opacity: 1 })
- $j('#loading').hide()
+ $('#contacts').css({ opacity: 1 })
+ $('#loading').hide()
)
# TODO: code for when viewing a single contact, not just index
# need to refresh the page or just the segment
- $j('a[data-view]').removeClass('active')
- $j(this).addClass('active')
+ $('a[data-view]').removeClass('active')
+ $(this).addClass('active')
) jQuery
diff --git a/app/assets/javascripts/groups.js.coffee b/app/assets/javascripts/groups.js.coffee
deleted file mode 100644
index 61504874a7..0000000000
--- a/app/assets/javascripts/groups.js.coffee
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-#
-# Fat Free CRM is freely distributable under the terms of MIT license.
-# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-#------------------------------------------------------------------------------
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/app/assets/javascripts/jquery-timepicker/GruntFile.js b/app/assets/javascripts/jquery-timepicker/GruntFile.js
new file mode 100755
index 0000000000..73e84a6797
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/GruntFile.js
@@ -0,0 +1,18 @@
+module.exports = function(grunt) {
+
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ uglify: {
+ dist: {
+ files: {
+ 'jquery.timepicker.min.js': ['jquery.timepicker.js']
+ }
+ }
+ }
+ });
+
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+
+ grunt.registerTask('default', ['uglify']);
+
+};
\ No newline at end of file
diff --git a/app/assets/javascripts/jquery-timepicker/README.md b/app/assets/javascripts/jquery-timepicker/README.md
new file mode 100755
index 0000000000..e2078e25f4
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/README.md
@@ -0,0 +1,231 @@
+Timepicker Plugin for jQuery
+========================
+
+[ ](http://jonthornton.github.com/jquery-timepicker)
+
+[See a demo and examples here](http://jonthornton.github.com/jquery-timepicker)
+
+jquery.timepicker is a lightweight timepicker plugin for jQuery inspired by Google Calendar. It supports both mouse and keyboard navigation, and weighs in at 2.5kb minified and gzipped.
+
+Requirements
+------------
+* [jQuery](http://jquery.com/) (>= 1.7)
+
+Usage
+-----
+
+```javascript
+$('.some-time-inputs').timepicker(options);
+```
+
+```options``` is an optional javascript object with parameters explained below.
+
+You can also set options as [data attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes) on the intput elements, like ``` ```. Timepicker still needs to be initialized by calling ```$('#someElement').timepicker();```.
+
+Options
+-------
+
+- **appendTo**
+Override where the dropdown is appended.
+Takes either a `string` to use as a selector, a `function` that gets passed the clicked input element as argument or a jquery `object` to use directly.
+*default: "body"*
+
+- **className**
+A class name to apply to the HTML element that contains the timepicker dropdown.
+*default: null*
+
+- **closeOnWindowScroll**
+Close the timepicker when the window is scrolled. (Replicates `````` behavior.)
+*default: false*
+
+- **disableTimeRanges**
+Disable selection of certain time ranges. Input is an array of time pairs, like ```[['3:00am', '4:30am'], ['5:00pm', '8:00pm']]``
+*default: []*
+
+- **disableTouchKeyboard**
+Disable the onscreen keyboard for touch devices.
+*default: false*
+
+- **durationTime**
+The time against which ```showDuration``` will compute relative times. If this is a function, its result will be used.
+*default: minTime*
+
+- **forceRoundTime**
+Force update the time to ```step``` settings as soon as it loses focus.
+*default: false*
+
+- **lang**
+Language constants used in the timepicker. Can override the defaults by passing an object with one or more of the following properties: decimal, mins, hr, hrs.
+*default:* ```{
+ decimal: '.',
+ mins: 'mins',
+ hr: 'hr',
+ hrs: 'hrs'
+}```
+
+- **maxTime**
+The time that should appear last in the dropdown list. Can be used to limit the range of time options.
+*default: 24 hours after minTime*
+
+- **minTime**
+The time that should appear first in the dropdown list.
+*default: 12:00am*
+
+- **noneOption**
+Adds a "None" option to the top of the timepicker dropdown
+*default: false*
+
+- **scrollDefaultNow**
+If no time value is selected, set the dropdown scroll position to show the current time.
+*default: false*
+
+- **scrollDefaultTime**
+If no time value is selected, set the dropdown scroll position to show the time provided, e.g. "09:00".
+*default: false*
+
+- **selectOnBlur**
+Update the input with the currently highlighted time value when the timepicker loses focus.
+*default: false*
+
+- **showDuration**
+Shows the relative time for each item in the dropdown. ```minTime``` or ```durationTime``` must be set.
+*default: false*
+
+- **step**
+The amount of time, in minutes, between each item in the dropdown.
+*default: 30*
+
+- **timeFormat**
+How times should be displayed in the list and input element. Uses [PHP's date() formatting syntax](http://php.net/manual/en/function.date.php).
+*default: 'g:ia'*
+
+- **typeaheadHighlight**
+Highlight the nearest corresponding time option as a value is typed into the form input.
+*default: true*
+
+- **useSelect**
+Convert the input to an HTML control. This is ideal for small screen devices. This option is not compatible with the following options: ```appendTo```, ```closeOnWindowScroll```, ```disableTouchKeyboard```, ```forceRoundTime```, ```scrollDefaultNow```, ```selectOnBlur```, ```typeAheadHighlight```.
+*default: true*
+
+Methods
+-------
+
+- **getSecondsFromMidnight**
+Get the time as an integer, expressed as seconds from 12am.
+
+ ```javascript
+ $('#getTimeExample').timepicker('getSecondsFromMidnight');
+ ```
+
+- **getTime**
+Get the time using a Javascript Date object, relative to a Date object (default: today).
+
+ ```javascript
+ $('#getTimeExample').timepicker('getTime'[, new Date()]);
+ ```
+
+ You can get the time as a string using jQuery's built-in ```val()``` function:
+
+ ```javascript
+ $('#getTimeExample').val();
+ ```
+
+- **hide**
+Close the timepicker dropdown.
+
+ ```javascript
+ $('#hideExample').timepicker('hide');
+ ```
+
+- **option**
+Change the settings of an existing timepicker. Calling ```option``` on a visible timepicker will cause the picker to be hidden.
+
+ ```javascript
+ $('#optionExample').timepicker({ 'timeFormat': 'g:ia' });
+ $('#optionExample').timepicker('option', 'minTime', '2:00am');
+ $('#optionExample').timepicker('option', { 'minTime': '4:00am', 'timeFormat': 'H:i' });
+ ```
+
+- **remove**
+Unbind an existing timepicker element.
+
+ ```javascript
+ $('#removeExample').timepicker('remove');
+ ```
+
+- **setTime**
+Set the time using a Javascript Date object.
+
+ ```javascript
+ $('#setTimeExample').timepicker('setTime', new Date());
+ ```
+
+- **show**
+Display the timepicker dropdown.
+
+ ```javascript
+ $('#showExample').timepicker('show');
+ ```
+
+Events
+------
+
+- **change**
+The native ```onChange``` event will fire any time the input value is updated, whether by selection from the timepicker list or manual entry into the text input. Your code should bind to ```change``` after initializing timepicker, or use [event delegation](http://api.jquery.com/on/).
+
+- **changeTime**
+Called after a valid time value is entered or selected. See ```timeFormatError``` and ```timeRangeError``` for error events. Fires before ```change``` event.
+
+- **hideTimepicker**
+Called after the timepicker is closed.
+
+- **selectTime**
+Called after a time value is selected from the timepicker list. Fires before ```change``` event.
+
+- **showTimepicker**
+Called after the timepicker is shown.
+
+- **timeFormatError**
+Called if an unparseable time string is manually entered into the timepicker input. Fires before ```change``` event.
+
+- **timeRangeError**
+Called if a maxTime, minTime, or disableTimeRanges is set and an invalid time is manually entered into the timepicker input. Fires before ```change``` event.
+
+Theming
+-------
+
+Sample markup with class names:
+
+```html
+
+...
+
+
+ 12:00am
+ 12:30am
+ ...
+ 4:30pm
+ 5:00pm
+ 5:30pm
+ 6:00pm (1 hour)
+ 6:30pm
+ ...
+ 11:30pm
+
+
+```
+
+Help
+----
+
+Submit a [GitHub Issues request](https://github.com/jonthornton/jquery-timepicker/issues/new).
+
+Development guidelines
+----------------------
+
+1. Install dependencies (jquery + grunt) `npm install`
+2. For sanity checks and minification run `grunt`, or just `grunt lint` to have the code linted
+
+- - -
+
+This software is made available under the open source MIT License. © 2012 [Jon Thornton](http://www.jonthornton.com), contributions from [Anthony Fojas](https://github.com/fojas), [Vince Mi](https://github.com/vinc3m1), [Nikita Korotaev](https://github.com/websirnik), [Spoon88](https://github.com/Spoon88), [elarkin](https://github.com/elarkin), [lodewijk](https://github.com/lodewijk), [jayzawrotny](https://github.com/jayzawrotny), [David Mazza](https://github.com/dmzza), [Matt Jurik](https://github.com/exabytes18), [Phil Freo](https://github.com/philfreo), [orloffv](https://github.com/orloffv), [patdenice](https://github.com/patdenice), [Raymond Julin](https://github.com/nervetattoo), [Gavin Ballard](https://github.com/gavinballard), [Steven Schmid](https://github.com/stevschmid), [ddaanet](https://github.com/ddaanet)
diff --git a/app/assets/javascripts/jquery-timepicker/component.json b/app/assets/javascripts/jquery-timepicker/component.json
new file mode 100755
index 0000000000..f4b6446da2
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/component.json
@@ -0,0 +1,16 @@
+{
+ "name" : "jt.timepicker",
+ "version" : "1.3.1",
+ "description" : "A jQuery timepicker plugin inspired by Google Calendar.",
+ "homepage" : "http://jonthornton.github.com/jquery-timepicker",
+ "main" : [ "./jquery.timepicker.js", "./jquery.timepicker.min.js", "./jquery.timepicker.css" ],
+ "dependencies" : {
+ "jquery" : ">= 1.7"
+ },
+ "keywords" : [ "time", "picker", "google calendar" ],
+ "author" : {
+ "name" : "Jon Thornton",
+ "web" : "https://github.com/jonthornton"
+ },
+ "license": "http://opensource.org/licenses/MIT"
+}
diff --git a/app/assets/javascripts/jquery-timepicker/index.html b/app/assets/javascripts/jquery-timepicker/index.html
new file mode 100755
index 0000000000..58cb072fb6
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/index.html
@@ -0,0 +1,343 @@
+
+
+
+
+
+ Timepicker for jQuery – Demos and Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A lightweight, customizable jQuery timepicker plugin inspired by Google Calendar.
+
+
+
Use this plugin to unobtrusively add a timepicker dropdown to your forms. It's lightweight (2.5kb minified and gzipped) and easy to customize.
+ View the source code on GitHub or download (zip) .
+
+
+
Full documentation available here
+
+
+
+
+
Basic Example
+
+
+
$('#basicExample').timepicker();
+
+
+
+
+
+
+
+
+
+
Scroll Default Example
+
Set the scroll position to local time if no value selected.
+
+
+
$('#defaultValueExample').timepicker({ 'scrollDefaultNow': true });
+
+
+
+
+
+
+
+
+
+
Set Time Example
+
Dynamically set the time using a Javascript Date object.
+
+
+ Set current time
+
+
+
$('#setTimeExample').timepicker();
+$('#setTimeButton').on('click', function (){
+ $('#setTimeExample').timepicker('setTime', new Date());
+});
+
+
+
+
+
+
+
+
+
+
Duration Example
+
Set a starting time and see duration from that starting time. You can optionally set an maxTime as well.
+
+
+
$('#durationExample').timepicker({
+ 'minTime': '2:00pm',
+ 'maxTime': '11:30pm',
+ 'showDuration': true
+});
+
+
+
+
+
+
+
+
+
Event Example
+
Trigger an event after selecting a value. Fires before the input onchange event.
+
+
+
+
+
+
$('#onselectExample').timepicker();
+$('#onselectExample').on('changeTime', function() {
+ $('#onselectTarget').text($(this).val());
+});
+
+
+
+
+
+
+
+
+
+
DisableTimeRanges Example
+
Prevent selection of certain time values.
+
+
+
$('#disableTimeRangesExample').timepicker({
+ 'disableTimeRanges': [
+ ['1am', '2am'],
+ ['3am', '4:01am']
+ ]
+});
+
+
+
+
+
+
+
+
+
+
timeFormat Example
+
timepicker.jquery uses the time portion of PHP's date formatting commands .
+
+
+
$('#timeformatExample1').timepicker({ 'timeFormat': 'H:i:s' });
+$('#timeformatExample2').timepicker({ 'timeFormat': 'h:i A' });
+
+
+
+
+
+
+
+
+
+
Step Example
+
Generate drop-down options with varying levels of precision.
+
+
+
$('#stepExample1').timepicker({ 'step': 15 });
+$('#stepExample2').timepicker({ 'step': 60 });
+
+
+
+
+
+
+
+
+
forceRoundTime Example
+
jquery-timepicker allows entering times via the keyboard. Setting forceRoundTime to true will
+ round the entered time to the nearest option on the dropdown list.
+
+
+
$('#roundTimeExample').timepicker({ 'forceRoundTime': true });
+
+
+
+
+
+
+
+
+
+
Select Example
+
jquery-timepicker can render itself as a select element too.
+
Toggle
+
+
$('#selectExample').timepicker();
+$('#selectButton').click(function(e) {
+ $('#selectExample').timepicker('option', { useSelect: true });
+ $(this).hide();
+});
+
+
+
+
+
+
+
+
+
Non-input Example
+
jquery-timepicker can be bound to any visibile DOM element, such as spans or divs.
+
Pick Time
+
+
$('#spanExample').timepicker();
+ $('#openSpanExample').on('click', function(){
+ $('#spanExample').timepicker('show');
+});
+
+
+
+
+
+
+
+
+
+
+
Want to get paid to work on stuff like this?
+
+
Shameless plug: ParkWhiz is looking for talented developers
+ to help us drag the parking industry out of the Stone Age. Visit ParkWhiz's
+ jobs page or email
+ jobs@parkwhiz.com and introduce yourself!
+
+
+
Contact
+
Jon Thornton — [lastname].[firstname]@gmail.com
+
+
+
Download
+
+ You can download this project in either
+ zip or
+ tar formats .
+ Get the source code on GitHub: jonthornton/jquery.timepicker
+
+
You can also clone the project with
Git
+ by running:
+
$ git clone git://github.com/jonthornton/jquery-timepicker
+
+
+
+
+
+
+
+
+
+
diff --git a/app/assets/javascripts/jquery-timepicker/jquery.timepicker.css b/app/assets/javascripts/jquery-timepicker/jquery.timepicker.css
new file mode 100755
index 0000000000..0935d49c5f
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/jquery.timepicker.css
@@ -0,0 +1,67 @@
+.ui-timepicker-wrapper {
+ overflow-y: auto;
+ height: 150px;
+ width: 6.5em;
+ background: #fff;
+ border: 1px solid #ddd;
+ -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ outline: none;
+ z-index: 10001;
+ margin: 0;
+}
+
+.ui-timepicker-wrapper.ui-timepicker-with-duration {
+ width: 11em;
+}
+
+.ui-timepicker-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.ui-timepicker-duration {
+ margin-left: 5px; color: #888;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-duration {
+ color: #888;
+}
+
+.ui-timepicker-list li {
+ padding: 3px 0 3px 5px;
+ cursor: pointer;
+ white-space: nowrap;
+ color: #000;
+ list-style: none;
+ margin: 0;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-selected {
+ background: #fff; color: #000;
+}
+
+li.ui-timepicker-selected,
+.ui-timepicker-list li:hover,
+.ui-timepicker-list .ui-timepicker-selected:hover {
+ background: #1980EC; color: #fff;
+}
+
+li.ui-timepicker-selected .ui-timepicker-duration,
+.ui-timepicker-list li:hover .ui-timepicker-duration {
+ color: #ccc;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled,
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ color: #888;
+ cursor: default;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ background: #f2f2f2;
+}
diff --git a/app/assets/javascripts/jquery-timepicker/jquery.timepicker.js b/app/assets/javascripts/jquery-timepicker/jquery.timepicker.js
index 4ff58c9ad6..7e29dc50a4 100755
--- a/app/assets/javascripts/jquery-timepicker/jquery.timepicker.js
+++ b/app/assets/javascripts/jquery-timepicker/jquery.timepicker.js
@@ -1,14 +1,20 @@
/************************
-jquery-timepicker
+jquery-timepicker v1.3.1
http://jonthornton.github.com/jquery-timepicker/
requires jQuery 1.7+
************************/
-!(function($)
-{
-
+(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
var _baseDate = _generateBaseDate();
var _ONE_DAY = 86400;
var _defaults = {
@@ -21,7 +27,14 @@ requires jQuery 1.7+
timeFormat: 'g:ia',
scrollDefaultNow: false,
scrollDefaultTime: false,
- selectOnBlur: false
+ selectOnBlur: false,
+ disableTouchKeyboard: false,
+ forceRoundTime: false,
+ appendTo: 'body',
+ disableTimeRanges: [],
+ closeOnWindowScroll: false,
+ typeaheadHighlight: true,
+ noneOption: false
};
var _lang = {
decimal: '.',
@@ -29,7 +42,6 @@ requires jQuery 1.7+
hr: 'hr',
hrs: 'hrs'
};
- var globalInit = false;
var methods =
{
@@ -39,87 +51,70 @@ requires jQuery 1.7+
{
var self = $(this);
- // convert dropdowns to text input
- if (self[0].tagName == 'SELECT') {
- var input = $(' ');
- var attrs = { 'type': 'text', 'value': self.val() };
- var raw_attrs = self[0].attributes;
-
- for (var i=0; i < raw_attrs.length; i++) {
- attrs[raw_attrs[i].nodeName] = raw_attrs[i].nodeValue;
+ // pick up settings from data attributes
+ var attributeOptions = [];
+ for (key in _defaults) {
+ if (self.data(key)) {
+ attributeOptions[key] = self.data(key);
}
-
- input.attr(attrs);
- self.replaceWith(input);
- self = input;
- }
-
- var settings = $.extend({}, _defaults);
-
- if (options) {
- settings = $.extend(settings, options);
- }
-
- if (settings.minTime) {
- settings.minTime = _time2int(settings.minTime);
- }
-
- if (settings.maxTime) {
- settings.maxTime = _time2int(settings.maxTime);
}
- if (settings.durationTime) {
- settings.durationTime = _time2int(settings.durationTime);
- }
+ var settings = $.extend({}, _defaults, attributeOptions, options);
if (settings.lang) {
_lang = $.extend(_lang, settings.lang);
}
+ settings = _parseSettings(settings);
self.data('timepicker-settings', settings);
- self.attr('autocomplete', 'off');
- self.on('click.timepicker focus.timepicker', methods.show);
- self.on('blur.timepicker', _formatValue);
- self.on('keydown.timepicker', _keyhandler);
self.addClass('ui-timepicker-input');
- _formatValue.call(self.get(0));
+ if (settings.useSelect) {
+ _render(self);
+ } else {
+ self.prop('autocomplete', 'off');
+ self.on('click.timepicker focus.timepicker', methods.show);
+ self.on('change.timepicker', _formatValue);
+ self.on('keydown.timepicker', _keydownhandler);
+ self.on('keyup.timepicker', _keyuphandler);
- if (!globalInit) {
- // close the dropdown when container loses focus
- $('body').on('mousedown', function(e) {
- if ($(e.target).closest('.ui-timepicker-input').length == 0 && $(e.target).closest('.ui-timepicker-list').length == 0) {
- methods.hide();
- }
- });
- globalInit = true;
+ _formatValue.call(self.get(0));
}
});
},
show: function(e)
{
+ if (e) {
+ e.preventDefault();
+ }
+
var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (settings.useSelect) {
+ self.data('timepicker-list').focus();
+ return;
+ }
+
+ if (_hideKeyboard(self)) {
+ // block the keyboard on mobile devices
+ self.blur();
+ }
+
var list = self.data('timepicker-list');
// check if input is readonly
- if (self.attr('readonly')) {
+ if (self.prop('readonly')) {
return;
}
// check if list needs to be rendered
- if (!list || list.length == 0) {
+ if (!list || list.length === 0 || typeof settings.durationTime === 'function') {
_render(self);
list = self.data('timepicker-list');
}
- // check if a flag was set to close this picker
- if (self.hasClass('ui-timepicker-hideme')) {
- self.removeClass('ui-timepicker-hideme');
- list.hide();
- return;
- }
-
if (list.is(':visible')) {
return;
}
@@ -127,27 +122,32 @@ requires jQuery 1.7+
// make sure other pickers are hidden
methods.hide();
+ list.show();
+
if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
// position the dropdown on top
- list.css({ 'left':(self.offset().left), 'top': self.offset().top - list.outerHeight() });
+ list.offset({
+ 'left': self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10),
+ 'top': self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10)
+ });
} else {
// put it under the input
- list.css({ 'left':(self.offset().left), 'top': self.offset().top + self.outerHeight() });
+ list.offset({
+ 'left':self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10),
+ 'top': self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10)
+ });
}
- list.show();
-
- var settings = self.data('timepicker-settings');
// position scrolling
var selected = list.find('.ui-timepicker-selected');
if (!selected.length) {
- if (self.val()) {
- selected = _findRow(self, list, _time2int(self.val()));
+ if (_getTimeValue(self)) {
+ selected = _findRow(self, list, _time2int(_getTimeValue(self)));
} else if (settings.scrollDefaultNow) {
selected = _findRow(self, list, _time2int(new Date()));
} else if (settings.scrollDefaultTime !== false) {
- selected = _findRow(self, list, _time2int(settings.scrollDefaultTime));
+ selected = _findRow(self, list, _time2int(settings.scrollDefaultTime));
}
}
@@ -158,12 +158,27 @@ requires jQuery 1.7+
list.scrollTop(0);
}
+ // attach close handlers
+ $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler);
+ if (settings.closeOnWindowScroll) {
+ $(document).on('scroll.ui-timepicker', _closeHandler);
+ }
+
self.trigger('showTimepicker');
+
+ return this;
},
hide: function(e)
{
- $('.ui-timepicker-list:visible').each(function() {
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (settings && settings.useSelect) {
+ self.blur();
+ }
+
+ $('.ui-timepicker-wrapper:visible').each(function() {
var list = $(this);
var self = list.data('timepicker-input');
var settings = self.data('timepicker-settings');
@@ -175,11 +190,13 @@ requires jQuery 1.7+
list.hide();
self.trigger('hideTimepicker');
});
+
+ return this;
},
option: function(key, value)
{
- var self = $(this);
+ var self = this;
var settings = self.data('timepicker-settings');
var list = self.data('timepicker-list');
@@ -193,17 +210,7 @@ requires jQuery 1.7+
return settings[key];
}
- if (settings.minTime) {
- settings.minTime = _time2int(settings.minTime);
- }
-
- if (settings.maxTime) {
- settings.maxTime = _time2int(settings.maxTime);
- }
-
- if (settings.durationTime) {
- settings.durationTime = _time2int(settings.durationTime);
- }
+ settings = _parseSettings(settings);
self.data('timepicker-settings', settings);
@@ -212,28 +219,51 @@ requires jQuery 1.7+
self.data('timepicker-list', false);
}
+ if (settings.useSelect) {
+ _render(self);
+ }
+
+ return this;
},
getSecondsFromMidnight: function()
{
- return _time2int($(this).val());
+ return _time2int(_getTimeValue(this));
},
- getTime: function()
+ getTime: function(relative_date)
{
- return new Date(_baseDate.valueOf() + (_time2int($(this).val())*1000));
+ var self = this;
+
+ var time_string = _getTimeValue(self);
+ if (!time_string) {
+ return null;
+ }
+
+ if (!relative_date) {
+ relative_date = new Date();
+ }
+
+ relative_date.setHours(0, 0, 0, 0);
+ return new Date(relative_date.valueOf() + (_time2int(time_string)*1000));
},
setTime: function(value)
{
- var self = $(this);
+ var self = this;
var prettyTime = _int2time(_time2int(value), self.data('timepicker-settings').timeFormat);
- self.val(prettyTime);
+
+ _setTimeValue(self, prettyTime);
+ if (self.data('timepicker-list')) {
+ _setSelected(self, self.data('timepicker-list'));
+ }
+
+ return this;
},
remove: function()
{
- var self = $(this);
+ var self = this;
// check if this element is a timepicker
if (!self.hasClass('ui-timepicker-input')) {
@@ -251,11 +281,56 @@ requires jQuery 1.7+
}
self.removeData('timepicker-list');
+
+ return this;
}
};
// private methods
+ function _parseSettings(settings)
+ {
+ if (settings.minTime) {
+ settings.minTime = _time2int(settings.minTime);
+ }
+
+ if (settings.maxTime) {
+ settings.maxTime = _time2int(settings.maxTime);
+ }
+
+ if (settings.durationTime && typeof settings.durationTime !== 'function') {
+ settings.durationTime = _time2int(settings.durationTime);
+ }
+
+ if (settings.disableTimeRanges.length > 0) {
+ // convert string times to integers
+ for (var i in settings.disableTimeRanges) {
+ settings.disableTimeRanges[i] = [
+ _time2int(settings.disableTimeRanges[i][0]),
+ _time2int(settings.disableTimeRanges[i][1])
+ ];
+ }
+
+ // sort by starting time
+ settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){
+ return a[0] - b[0];
+ });
+
+ // merge any overlapping ranges
+ for (var i = settings.disableTimeRanges.length-1; i > 0; i--) {
+ if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) {
+ settings.disableTimeRanges[i-1] = [
+ Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]),
+ Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1])
+ ];
+ settings.disableTimeRanges.splice(i, 1);
+ }
+ }
+ }
+
+ return settings;
+ }
+
function _render(self)
{
var settings = self.data('timepicker-settings');
@@ -266,20 +341,38 @@ requires jQuery 1.7+
self.data('timepicker-list', false);
}
- list = $('');
- list.attr('tabindex', -1);
- list.addClass('ui-timepicker-list');
- if (settings.className) {
- list.addClass(settings.className);
+ if (settings.useSelect) {
+ list = $(' ', { 'class': 'ui-timepicker-select' });
+ var wrapped_list = list;
+ } else {
+ list = $('', { 'class': 'ui-timepicker-list' });
+
+ var wrapped_list = $('
', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 });
+ wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list);
}
- list.css({'display':'none', 'position': 'absolute' });
+ if (settings.noneOption) {
+ if (settings.useSelect) {
+ list.append($('Time... '));
+ } else {
+ list.append($('None '));
+ }
+ }
+
+ if (settings.className) {
+ wrapped_list.addClass(settings.className);
+ }
- if (settings.minTime !== null && settings.showDuration) {
- list.addClass('ui-timepicker-with-duration');
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ wrapped_list.addClass('ui-timepicker-with-duration');
}
- var durStart = (settings.durationTime !== null) ? settings.durationTime : settings.minTime;
+ var durStart = settings.minTime;
+ if (typeof settings.durationTime === 'function') {
+ durStart = _time2int(settings.durationTime());
+ } else if (settings.durationTime !== null) {
+ durStart = settings.durationTime;
+ }
var start = (settings.minTime !== null) ? settings.minTime : 0;
var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
@@ -288,49 +381,144 @@ requires jQuery 1.7+
end += _ONE_DAY;
}
+ if (end === _ONE_DAY-1 && settings.timeFormat.indexOf('H') !== -1) {
+ // show a 24:00 option when using military time
+ end = _ONE_DAY;
+ }
+
+ var dr = settings.disableTimeRanges;
+ var drCur = 0;
+ var drLen = dr.length;
+
for (var i=start; i <= end; i += settings.step*60) {
- var timeInt = i%_ONE_DAY;
- var row = $(' ');
- row.data('time', timeInt)
- row.text(_int2time(timeInt, settings.timeFormat));
+ var timeInt = i;
+ var timeString = _int2time(timeInt, settings.timeFormat);
+
+ if (settings.useSelect) {
+ var row = $(' ', { 'value': timeString });
+ row.text(timeString);
+ } else {
+ var row = $(' ');
+ row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
+ row.text(timeString);
+ }
- if (settings.minTime !== null && settings.showDuration) {
- var duration = $(' ');
- duration.addClass('ui-timepicker-duration');
- duration.text(' ('+_int2duration(i - durStart)+')');
- row.append(duration)
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ var durationString = _int2duration(i - durStart);
+ if (settings.useSelect) {
+ row.text(row.text()+' ('+durationString+')');
+ } else {
+ var duration = $(' ', { 'class': 'ui-timepicker-duration' });
+ duration.text(' ('+durationString+')');
+ row.append(duration);
+ }
+ }
+
+ if (drCur < drLen) {
+ if (timeInt >= dr[drCur][1]) {
+ drCur += 1;
+ }
+
+ if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) {
+ if (settings.useSelect) {
+ row.prop('disabled', true);
+ } else {
+ row.addClass('ui-timepicker-disabled');
+ }
+ }
}
list.append(row);
}
- list.data('timepicker-input', self);
- self.data('timepicker-list', list);
+ wrapped_list.data('timepicker-input', self);
+ self.data('timepicker-list', wrapped_list);
+
+ if (settings.useSelect) {
+ list.val(_roundTime(self.val(), settings));
+ list.on('focus', function(){
+ $(this).data('timepicker-input').trigger('showTimepicker');
+ });
+ list.on('blur', function(){
+ $(this).data('timepicker-input').trigger('hideTimepicker');
+ });
+ list.on('change', function(){
+ _setTimeValue(self, $(this).val(), 'select');
+ });
+
+ self.hide().after(list);
+ } else {
+ var appendTo = settings.appendTo;
+ if (typeof appendTo === 'string') {
+ appendTo = $(appendTo);
+ } else if (typeof appendTo === 'function') {
+ appendTo = appendTo(self);
+ }
+ appendTo.append(wrapped_list);
+ _setSelected(self, list);
- $('body').append(list);
- _setSelected(self, list);
+ list.on('click', 'li', function(e) {
- list.on('click', 'li', function(e) {
- self.addClass('ui-timepicker-hideme');
- self[0].focus();
+ // hack: temporarily disable the focus handler
+ // to deal with the fact that IE fires 'focus'
+ // events asynchronously
+ self.off('focus.timepicker');
+ self.on('focus.timepicker-ie-hack', function(){
+ self.off('focus.timepicker-ie-hack');
+ self.on('focus.timepicker', methods.show);
+ });
- // make sure only the clicked row is selected
- list.find('li').removeClass('ui-timepicker-selected');
- $(this).addClass('ui-timepicker-selected');
+ if (!_hideKeyboard(self)) {
+ self[0].focus();
+ }
- _selectValue(self);
- list.hide();
- });
- };
+ // make sure only the clicked row is selected
+ list.find('li').removeClass('ui-timepicker-selected');
+ $(this).addClass('ui-timepicker-selected');
+
+ if (_selectValue(self)) {
+ self.trigger('hideTimepicker');
+ wrapped_list.hide();
+ }
+ });
+ }
+ }
+
+ function _roundTime(time, settings)
+ {
+ if (!$.isNumeric(time)) {
+ time = _time2int(time);
+ }
+
+ if (time === null) {
+ return null;
+ } else {
+ var step = settings.step*60;
+ // round to the nearest step
+ return _int2time(Math.round(time / step) * step, settings.timeFormat);
+ }
+ }
function _generateBaseDate()
{
- var _baseDate = new Date();
- var _currentTimezoneOffset = _baseDate.getTimezoneOffset()*60000;
- _baseDate.setHours(0); _baseDate.setMinutes(0); _baseDate.setSeconds(0);
- var _baseDateTimezoneOffset = _baseDate.getTimezoneOffset()*60000;
+ return new Date(1970, 1, 1, 0, 0, 0);
+ }
+
+ // event handler to decide whether to close timepicker
+ function _closeHandler(e)
+ {
+ var target = $(e.target);
+ var input = target.closest('.ui-timepicker-input');
+ if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) {
+ methods.hide();
+ $(document).unbind('.ui-timepicker');
+ }
+ }
- return new Date(_baseDate.valueOf() - _baseDateTimezoneOffset + _currentTimezoneOffset);
+ function _hideKeyboard(self)
+ {
+ var settings = self.data('timepicker-settings');
+ return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard);
}
function _findRow(self, list, value)
@@ -341,13 +529,16 @@ requires jQuery 1.7+
var settings = self.data('timepicker-settings');
var out = false;
+ var halfStep = settings.step*30;
// loop through the menu items
list.find('li').each(function(i, obj) {
var jObj = $(obj);
+ var offset = jObj.data('time') - value;
+
// check if the value is less than half a step from each row
- if (Math.abs(jObj.data('time') - value) <= settings.step*30) {
+ if (Math.abs(offset) < halfStep || offset == halfStep) {
out = jObj;
return false;
}
@@ -358,59 +549,156 @@ requires jQuery 1.7+
function _setSelected(self, list)
{
- var timeValue = _time2int(self.val());
+ list.find('li').removeClass('ui-timepicker-selected');
+
+ var timeValue = _time2int(_getTimeValue(self));
+ if (timeValue === null) {
+ return;
+ }
var selected = _findRow(self, list, timeValue);
- if (selected) selected.addClass('ui-timepicker-selected');
+ if (selected) {
+
+ var topDelta = selected.offset().top - list.offset().top;
+
+ if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) {
+ list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight());
+ }
+
+ selected.addClass('ui-timepicker-selected');
+ }
}
function _formatValue()
{
- if (this.value == '') {
+ if (this.value === '') {
return;
}
var self = $(this);
- var timeInt = _time2int(this.value);
+ var list = self.data('timepicker-list');
+
+ if (list && list.is(':visible')) {
+ return;
+ }
- if (timeInt === null) {
+ var seconds = _time2int(this.value);
+
+ if (seconds === null) {
self.trigger('timeFormatError');
return;
}
- var prettyTime = _int2time(timeInt, self.data('timepicker-settings').timeFormat);
- self.val(prettyTime);
+ var settings = self.data('timepicker-settings');
+ var rangeError = false;
+ // check that the time in within bounds
+ if (settings.minTime !== null && seconds < settings.minTime) {
+ rangeError = true;
+ } else if (settings.maxTime !== null && seconds > settings.maxTime) {
+ rangeError = true;
+ }
+
+ // check that time isn't within disabled time ranges
+ $.each(settings.disableTimeRanges, function(){
+ if (seconds >= this[0] && seconds < this[1]) {
+ rangeError = true;
+ return false;
+ }
+ });
+
+ if (settings.forceRoundTime) {
+ var offset = seconds % (settings.step*60); // step is in minutes
+
+ if (offset >= settings.step*30) {
+ // if offset is larger than a half step, round up
+ seconds += (settings.step*60) - offset;
+ } else {
+ // round down
+ seconds -= offset;
+ }
+ }
+
+ var prettyTime = _int2time(seconds, settings.timeFormat);
+
+ if (rangeError) {
+ if (_setTimeValue(self, prettyTime, 'error')) {
+ self.trigger('timeRangeError');
+ }
+ } else {
+ _setTimeValue(self, prettyTime);
+ }
}
- function _keyhandler(e)
+ function _getTimeValue(self)
+ {
+ if (self.is('input')) {
+ return self.val();
+ } else {
+ // use the element's data attributes to store values
+ return self.data('ui-timepicker-value');
+ }
+ }
+
+ function _setTimeValue(self, value, source)
+ {
+ if (self.is('input')) {
+ self.val(value);
+
+ var settings = self.data('timepicker-settings');
+ if (settings.useSelect) {
+ self.data('timepicker-list').val(_roundTime(value, settings));
+ }
+ }
+
+ if (self.data('ui-timepicker-value') != value) {
+ self.data('ui-timepicker-value', value);
+ if (source == 'select') {
+ self.trigger('selectTime').trigger('changeTime').trigger('change');
+ } else if (source != 'error') {
+ self.trigger('changeTime');
+ }
+
+ return true;
+ } else {
+ self.trigger('selectTime');
+ return false;
+ }
+ }
+
+ /*
+ * Keyboard navigation via arrow keys
+ */
+ function _keydownhandler(e)
{
var self = $(this);
var list = self.data('timepicker-list');
- if (!list.is(':visible')) {
+ if (!list || !list.is(':visible')) {
if (e.keyCode == 40) {
- self.focus();
+ if (!_hideKeyboard(self)) {
+ self.focus();
+ }
} else {
return true;
}
- };
+ }
switch (e.keyCode) {
case 13: // return
- _selectValue(self);
- methods.hide.apply(this);
+ if (_selectValue(self)) {
+ methods.hide.apply(this);
+ }
+
e.preventDefault();
return false;
- break;
case 38: // up
var selected = list.find('.ui-timepicker-selected');
if (!selected.length) {
- var selected;
- list.children().each(function(i, obj) {
+ list.find('li').each(function(i, obj) {
if ($(obj).position().top > 0) {
selected = $(obj);
return false;
@@ -427,14 +715,13 @@ requires jQuery 1.7+
}
}
- break;
+ return false;
case 40: // down
- var selected = list.find('.ui-timepicker-selected');
+ selected = list.find('.ui-timepicker-selected');
- if (selected.length == 0) {
- var selected;
- list.children().each(function(i, obj) {
+ if (selected.length === 0) {
+ list.find('li').each(function(i, obj) {
if ($(obj).position().top > 0) {
selected = $(obj);
return false;
@@ -451,71 +738,115 @@ requires jQuery 1.7+
}
}
- break;
+ return false;
case 27: // escape
list.find('li').removeClass('ui-timepicker-selected');
- list.hide();
+ methods.hide();
break;
case 9: //tab
methods.hide();
break;
- case 16:
- case 17:
- case 18:
- case 19:
- case 20:
- case 33:
- case 34:
- case 35:
- case 36:
- case 37:
- case 39:
- case 45:
- return;
+ default:
+ return true;
+ }
+ }
+
+ /*
+ * Time typeahead
+ */
+ function _keyuphandler(e)
+ {
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (!list || !list.is(':visible')) {
+ return true;
+ }
+
+ if (!self.data('timepicker-settings').typeaheadHighlight) {
+ list.find('li').removeClass('ui-timepicker-selected');
+ return true;
+ }
+
+ switch (e.keyCode) {
+
+ case 96: // numpad numerals
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 48: // numerals
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 65: // a
+ case 77: // m
+ case 80: // p
+ case 186: // colon
+ case 8: // backspace
+ case 46: // delete
+ _setSelected(self, list);
+ break;
default:
- list.find('li').removeClass('ui-timepicker-selected');
+ // list.find('li').removeClass('ui-timepicker-selected');
return;
}
- };
+ }
function _selectValue(self)
{
- var settings = self.data('timepicker-settings')
+ var settings = self.data('timepicker-settings');
var list = self.data('timepicker-list');
var timeValue = null;
var cursor = list.find('.ui-timepicker-selected');
+ if (cursor.hasClass('ui-timepicker-disabled')) {
+ return false;
+ }
+
if (cursor.length) {
// selected value found
- var timeValue = cursor.data('time');
+ timeValue = cursor.data('time');
- } else if (self.val()) {
+ } else if (_getTimeValue(self)) {
// no selected value; fall back on input value
- var timeValue = _time2int(self.val());
+ timeValue = _time2int(_getTimeValue(self));
_setSelected(self, list);
}
if (timeValue !== null) {
var timeString = _int2time(timeValue, settings.timeFormat);
- self.attr('value', timeString);
+ _setTimeValue(self, timeString, 'select');
}
- self.trigger('change').trigger('changeTime');
- };
+ //self.trigger('change').trigger('selectTime');
+ return true;
+ }
function _int2duration(seconds)
{
var minutes = Math.round(seconds/60);
var duration;
- if (minutes < 60) {
+ if (Math.abs(minutes) < 60) {
duration = [minutes, _lang.mins];
} else if (minutes == 60) {
duration = ['1', _lang.hr];
@@ -526,7 +857,7 @@ requires jQuery 1.7+
}
return duration.join(' ');
- };
+ }
function _int2time(seconds, format)
{
@@ -535,11 +866,17 @@ requires jQuery 1.7+
}
var time = new Date(_baseDate.valueOf() + (seconds*1000));
+
+ if (isNaN(time.getTime())) {
+ return;
+ }
+
var output = '';
+ var hour, code;
for (var i=0; i 9) ? hour : '0'+hour;
break;
@@ -580,7 +918,7 @@ requires jQuery 1.7+
break;
case 's':
- var seconds = time.getSeconds();
+ seconds = time.getSeconds();
output += (seconds > 9) ? seconds : '0'+seconds;
break;
@@ -590,47 +928,67 @@ requires jQuery 1.7+
}
return output;
- };
+ }
function _time2int(timeString)
{
- if (timeString == '') return null;
- if (timeString+0 == timeString) return timeString;
+ if (timeString === '') return null;
+ if (!timeString || timeString+0 == timeString) return timeString;
if (typeof(timeString) == 'object') {
- timeString = timeString.getHours()+':'+timeString.getMinutes()+':'+timeString.getSeconds();
+ timeString = timeString.getHours()+':'+_pad2(timeString.getMinutes())+':'+_pad2(timeString.getSeconds());
}
+ timeString = timeString.toLowerCase();
+
var d = new Date(0);
- var time = timeString.toLowerCase().match(/(\d{1,2})(?::(\d{1,2}))?(?::(\d{2}))?\s*([pa]?)/);
+ var time;
+
+ // try to parse time input
+ if (timeString.indexOf(":") === -1) {
+ // no colon present
+ time = timeString.match(/^([0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/);
+
+ if (!time) {
+ time = timeString.match(/^([0-2][0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/);
+ }
+ } else {
+ time = timeString.match(/^(\d{1,2})(?::([0-5][0-9]))?(?::([0-5][0-9]))?\s*([pa]?)m?$/);
+ }
if (!time) {
return null;
}
- var hour = parseInt(time[1]*1);
+ var hour = parseInt(time[1]*1, 10);
+ var hours;
if (time[4]) {
if (hour == 12) {
- var hours = (time[4] == 'p') ? 12 : 0;
+ hours = (time[4] == 'p') ? 12 : 0;
} else {
- var hours = (hour + (time[4] == 'p' ? 12 : 0));
+ hours = (hour + (time[4] == 'p' ? 12 : 0));
}
} else {
- var hours = hour;
+ hours = hour;
}
var minutes = ( time[2]*1 || 0 );
var seconds = ( time[3]*1 || 0 );
return hours*3600 + minutes*60 + seconds;
- };
+ }
+
+ function _pad2(n) {
+ return ("0" + n).slice(-2);
+ }
// Plugin entry
$.fn.timepicker = function(method)
{
+ if (!this.length) return this;
if(methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); }
else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
};
-})(jQuery);
\ No newline at end of file
+}));
diff --git a/app/assets/javascripts/jquery-timepicker/jquery.timepicker.min.js b/app/assets/javascripts/jquery-timepicker/jquery.timepicker.min.js
new file mode 100755
index 0000000000..4ed5e10e48
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/jquery.timepicker.min.js
@@ -0,0 +1 @@
+!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function g(a){if(a.minTime&&(a.minTime=w(a.minTime)),a.maxTime&&(a.maxTime=w(a.maxTime)),a.durationTime&&"function"!=typeof a.durationTime&&(a.durationTime=w(a.durationTime)),a.disableTimeRanges.length>0){for(var b in a.disableTimeRanges)a.disableTimeRanges[b]=[w(a.disableTimeRanges[b][0]),w(a.disableTimeRanges[b][1])];a.disableTimeRanges=a.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var b=a.disableTimeRanges.length-1;b>0;b--)a.disableTimeRanges[b][0]<=a.disableTimeRanges[b-1][1]&&(a.disableTimeRanges[b-1]=[Math.min(a.disableTimeRanges[b][0],a.disableTimeRanges[b-1][0]),Math.max(a.disableTimeRanges[b][1],a.disableTimeRanges[b-1][1])],a.disableTimeRanges.splice(b,1))}return a}function h(b){var d=b.data("timepicker-settings"),e=b.data("timepicker-list");if(e&&e.length&&(e.remove(),b.data("timepicker-list",!1)),d.useSelect){e=a(" ",{"class":"ui-timepicker-select"});var g=e}else{e=a("",{"class":"ui-timepicker-list"});var g=a("
",{"class":"ui-timepicker-wrapper",tabindex:-1});g.css({display:"none",position:"absolute"}).append(e)}d.noneOption&&(d.useSelect?e.append(a('Time... ')):e.append(a("None "))),d.className&&g.addClass(d.className),null===d.minTime&&null===d.durationTime||!d.showDuration||g.addClass("ui-timepicker-with-duration");var h=d.minTime;"function"==typeof d.durationTime?h=w(d.durationTime()):null!==d.durationTime&&(h=d.durationTime);var j=null!==d.minTime?d.minTime:0,k=null!==d.maxTime?d.maxTime:j+c-1;j>=k&&(k+=c),k===c-1&&-1!==d.timeFormat.indexOf("H")&&(k=c);for(var m=d.disableTimeRanges,o=0,p=m.length,r=j;k>=r;r+=60*d.step){var s=r,x=v(s,d.timeFormat);if(d.useSelect){var y=a(" ",{value:x});y.text(x)}else{var y=a(" ");y.data("time",86400>=s?s:s%86400),y.text(x)}if((null!==d.minTime||null!==d.durationTime)&&d.showDuration){var z=u(r-h);if(d.useSelect)y.text(y.text()+" ("+z+")");else{var A=a(" ",{"class":"ui-timepicker-duration"});A.text(" ("+z+")"),y.append(A)}}p>o&&(s>=m[o][1]&&(o+=1),m[o]&&s>=m[o][0]&&sb.outerHeight()||0>e)&&b.scrollTop(b.scrollTop()+d.position().top-d.outerHeight()),d.addClass("ui-timepicker-selected")}}}function o(){if(""!==this.value){var b=a(this),c=b.data("timepicker-list");if(!c||!c.is(":visible")){var d=w(this.value);if(null===d)return b.trigger("timeFormatError"),void 0;var e=b.data("timepicker-settings"),f=!1;if(null!==e.minTime&&de.maxTime&&(f=!0),a.each(e.disableTimeRanges,function(){return d>=this[0]&&d=30*e.step?d+=60*e.step-g:d-=g}var h=v(d,e.timeFormat);f?q(b,h,"error")&&b.trigger("timeRangeError"):q(b,h)}}}function p(a){return a.is("input")?a.val():a.data("ui-timepicker-value")}function q(a,b,c){if(a.is("input")){a.val(b);var d=a.data("timepicker-settings");d.useSelect&&a.data("timepicker-list").val(i(b,d))}return a.data("ui-timepicker-value")!=b?(a.data("ui-timepicker-value",b),"select"==c?a.trigger("selectTime").trigger("changeTime").trigger("change"):"error"!=c&&a.trigger("changeTime"),!0):(a.trigger("selectTime"),!1)}function r(b){var c=a(this),d=c.data("timepicker-list");if(!d||!d.is(":visible")){if(40!=b.keyCode)return!0;l(c)||c.focus()}switch(b.keyCode){case 13:return t(c)&&f.hide.apply(this),b.preventDefault(),!1;case 38:var e=d.find(".ui-timepicker-selected");return e.length?e.is(":first-child")||(e.removeClass("ui-timepicker-selected"),e.prev().addClass("ui-timepicker-selected"),e.prev().position().top0?(e=a(c),!1):void 0}),e.addClass("ui-timepicker-selected")),!1;case 40:return e=d.find(".ui-timepicker-selected"),0===e.length?(d.find("li").each(function(b,c){return a(c).position().top>0?(e=a(c),!1):void 0}),e.addClass("ui-timepicker-selected")):e.is(":last-child")||(e.removeClass("ui-timepicker-selected"),e.next().addClass("ui-timepicker-selected"),e.next().position().top+2*e.outerHeight()>d.outerHeight()&&d.scrollTop(d.scrollTop()+e.outerHeight())),!1;case 27:d.find("li").removeClass("ui-timepicker-selected"),f.hide();break;case 9:f.hide();break;default:return!0}}function s(b){var c=a(this),d=c.data("timepicker-list");if(!d||!d.is(":visible"))return!0;if(!c.data("timepicker-settings").typeaheadHighlight)return d.find("li").removeClass("ui-timepicker-selected"),!0;switch(b.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:n(c,d);break;default:return}}function t(a){var b=a.data("timepicker-settings"),c=a.data("timepicker-list"),d=null,e=c.find(".ui-timepicker-selected");if(e.hasClass("ui-timepicker-disabled"))return!1;if(e.length?d=e.data("time"):p(a)&&(d=w(p(a)),n(a,c)),null!==d){var f=v(d,b.timeFormat);q(a,f,"select")}return!0}function u(a){var c,b=Math.round(a/60);if(Math.abs(b)<60)c=[b,e.mins];else if(60==b)c=["1",e.hr];else{var d=(b/60).toFixed(1);"."!=e.decimal&&(d=d.replace(".",e.decimal)),c=[d,e.hrs]}return c.join(" ")}function v(a,d){if(null!==a){var e=new Date(b.valueOf()+1e3*a);if(!isNaN(e.getTime())){for(var g,h,f="",i=0;i11?"pm":"am";break;case"A":f+=e.getHours()>11?"PM":"AM";break;case"g":g=e.getHours()%12,f+=0===g?"12":g;break;case"G":f+=e.getHours();break;case"h":g=e.getHours()%12,0!==g&&10>g&&(g="0"+g),f+=0===g?"12":g;break;case"H":g=e.getHours(),a===c&&(g=24),f+=g>9?g:"0"+g;break;case"i":var j=e.getMinutes();f+=j>9?j:"0"+j;break;case"s":a=e.getSeconds(),f+=a>9?a:"0"+a;break;default:f+=h}return f}}}function w(a){if(""===a)return null;if(!a||a+0==a)return a;"object"==typeof a&&(a=a.getHours()+":"+x(a.getMinutes())+":"+x(a.getSeconds())),a=a.toLowerCase(),new Date(0);var c;if(-1===a.indexOf(":")?(c=a.match(/^([0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/),c||(c=a.match(/^([0-2][0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/))):c=a.match(/^(\d{1,2})(?::([0-5][0-9]))?(?::([0-5][0-9]))?\s*([pa]?)m?$/),!c)return null;var e,d=parseInt(1*c[1],10);e=c[4]?12==d?"p"==c[4]?12:0:d+("p"==c[4]?12:0):d;var f=1*c[2]||0,g=1*c[3]||0;return 3600*e+60*f+g}function x(a){return("0"+a).slice(-2)}var b=j(),c=86400,d={className:null,minTime:null,maxTime:null,durationTime:null,step:30,showDuration:!1,timeFormat:"g:ia",scrollDefaultNow:!1,scrollDefaultTime:!1,selectOnBlur:!1,disableTouchKeyboard:!1,forceRoundTime:!1,appendTo:"body",disableTimeRanges:[],closeOnWindowScroll:!1,typeaheadHighlight:!0,noneOption:!1},e={decimal:".",mins:"mins",hr:"hr",hrs:"hrs"},f={init:function(b){return this.each(function(){var c=a(this),i=[];for(key in d)c.data(key)&&(i[key]=c.data(key));var j=a.extend({},d,i,b);j.lang&&(e=a.extend(e,j.lang)),j=g(j),c.data("timepicker-settings",j),c.addClass("ui-timepicker-input"),j.useSelect?h(c):(c.prop("autocomplete","off"),c.on("click.timepicker focus.timepicker",f.show),c.on("change.timepicker",o),c.on("keydown.timepicker",r),c.on("keyup.timepicker",s),o.call(c.get(0)))})},show:function(b){b&&b.preventDefault();var c=a(this),d=c.data("timepicker-settings");if(d.useSelect)return c.data("timepicker-list").focus(),void 0;l(c)&&c.blur();var e=c.data("timepicker-list");if(!c.prop("readonly")&&(e&&0!==e.length&&"function"!=typeof d.durationTime||(h(c),e=c.data("timepicker-list")),!e.is(":visible"))){f.hide(),e.show(),c.offset().top+c.outerHeight(!0)+e.outerHeight()>a(window).height()+a(window).scrollTop()?e.offset({left:c.offset().left+parseInt(e.css("marginLeft").replace("px",""),10),top:c.offset().top-e.outerHeight()+parseInt(e.css("marginTop").replace("px",""),10)}):e.offset({left:c.offset().left+parseInt(e.css("marginLeft").replace("px",""),10),top:c.offset().top+c.outerHeight()+parseInt(e.css("marginTop").replace("px",""),10)});var g=e.find(".ui-timepicker-selected");if(g.length||(p(c)?g=m(c,e,w(p(c))):d.scrollDefaultNow?g=m(c,e,w(new Date)):d.scrollDefaultTime!==!1&&(g=m(c,e,w(d.scrollDefaultTime)))),g&&g.length){var i=e.scrollTop()+g.position().top-g.outerHeight();e.scrollTop(i)}else e.scrollTop(0);return a(document).on("touchstart.ui-timepicker mousedown.ui-timepicker",k),d.closeOnWindowScroll&&a(document).on("scroll.ui-timepicker",k),c.trigger("showTimepicker"),this}},hide:function(){var c=a(this),d=c.data("timepicker-settings");return d&&d.useSelect&&c.blur(),a(".ui-timepicker-wrapper:visible").each(function(){var b=a(this),c=b.data("timepicker-input"),d=c.data("timepicker-settings");d&&d.selectOnBlur&&t(c),b.hide(),c.trigger("hideTimepicker")}),this},option:function(b,c){var d=this,e=d.data("timepicker-settings"),f=d.data("timepicker-list");if("object"==typeof b)e=a.extend(e,b);else if("string"==typeof b&&"undefined"!=typeof c)e[b]=c;else if("string"==typeof b)return e[b];return e=g(e),d.data("timepicker-settings",e),f&&(f.remove(),d.data("timepicker-list",!1)),e.useSelect&&h(d),this},getSecondsFromMidnight:function(){return w(p(this))},getTime:function(a){var b=this,c=p(b);return c?(a||(a=new Date),a.setHours(0,0,0,0),new Date(a.valueOf()+1e3*w(c))):null},setTime:function(a){var b=this,c=v(w(a),b.data("timepicker-settings").timeFormat);return q(b,c),b.data("timepicker-list")&&n(b,b.data("timepicker-list")),this},remove:function(){var a=this;if(a.hasClass("ui-timepicker-input"))return a.removeAttr("autocomplete","off"),a.removeClass("ui-timepicker-input"),a.removeData("timepicker-settings"),a.off(".timepicker"),a.data("timepicker-list")&&a.data("timepicker-list").remove(),a.removeData("timepicker-list"),this}};a.fn.timepicker=function(b){return this.length?f[b]?f[b].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof b&&b?(a.error("Method "+b+" does not exist on jQuery.timepicker"),void 0):f.init.apply(this,arguments):this}});
diff --git a/app/assets/javascripts/jquery-timepicker/jt.timepicker.jquery.json b/app/assets/javascripts/jquery-timepicker/jt.timepicker.jquery.json
new file mode 100755
index 0000000000..e36c118319
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/jt.timepicker.jquery.json
@@ -0,0 +1,27 @@
+{
+ "name": "jt.timepicker",
+ "version": "1.3.1",
+ "title": "jquery-timepicker",
+ "description": "A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.",
+ "author": {
+ "name": "Jon Thornton",
+ "email": "thornton.jon@gmail.com",
+ "url": "https://github.com/jonthornton"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "MIT-LICENSE.txt"
+ }
+ ],
+ "dependencies": {
+ "jquery": ">=1.7"
+ },
+ "keywords": [ "timepicker", "time", "picker", "ui", "calendar", "input", "form" ],
+ "homepage": "http://jonthornton.github.com/jquery-timepicker/",
+ "bugs": {
+ "url": "https://github.com/jonthornton/jquery-timepicker/issues"
+ },
+ "docs": "https://github.com/jonthornton/jquery-timepicker",
+ "download": "https://github.com/jonthornton/jquery-timepicker"
+}
diff --git a/app/assets/javascripts/jquery-timepicker/lib/base.css b/app/assets/javascripts/jquery-timepicker/lib/base.css
new file mode 100755
index 0000000000..c2223d80eb
--- /dev/null
+++ b/app/assets/javascripts/jquery-timepicker/lib/base.css
@@ -0,0 +1,455 @@
+
+div.ui-datepicker { font-size: 11px; }
+
+/**
+ * Blackboard theme
+ *
+ * Adapted from Domenico Carbotta's TextMate theme of the same name
+ *
+ * @author Domenico Carbotta
+ * @author Craig Campbell
+ * @version 1.0.2
+ */
+pre {
+ background: #0B1022;
+ word-wrap: break-word;
+ margin: 0px;
+ padding: 0px;
+ padding: 10px;
+ color: #fff;
+ font-size: 14px;
+ margin-bottom: 20px;
+}
+
+pre, code {
+ font-family: 'Monaco', courier, monospace;
+}
+
+pre .comment {
+ color: #727272;
+}
+
+pre .constant {
+ color: #D8FA3C;
+}
+
+pre .storage {
+ color: #FBDE2D;
+}
+
+pre .string, pre .comment.docstring {
+ color: #61CE3C;
+}
+
+pre .string.regexp, pre .support.tag.script, pre .support.tag.style {
+ color: #fff;
+}
+
+pre .keyword, pre .selector {
+ color: #FBDE2D;
+}
+
+pre .inherited-class {
+ font-style: italic;
+}
+
+pre .entity {
+ color: #FF6400;
+}
+
+pre .support, *[data-language="c"] .function.call {
+ color: #8DA6CE;
+}
+
+pre .variable.global, pre .variable.class, pre .variable.instance {
+ color: #FF6400;
+}
+
+
+
+/* Bootstrap datepicker CSS */
+.dropdown { position:relative; }
+.dropdown-toggle { *margin-bottom:-3px; }
+.dropdown-toggle:active, .open .dropdown-toggle { outline:0; }
+.caret {
+ display:inline-block;
+ width:0;
+ height:0;
+ text-indent:-99999px;
+ *text-indent:0;
+ vertical-align:top;
+ border-left:4px solid transparent;
+ border-right:4px solid transparent;
+ border-top:4px solid #000000;
+ opacity:0.3;
+ filter:alpha(opacity=30);
+ content:"\2193";
+}
+.dropdown .caret {
+ margin-top:8px;
+ margin-left:2px;
+}
+.dropdown:hover .caret, .open.dropdown .caret {
+ opacity:1;
+ filter:alpha(opacity=100);
+}
+.dropdown-menu {
+ position:absolute;
+ top:100%;
+ left:0;
+ z-index:1000;
+ float:left;
+ display:none;
+ min-width:160px;
+ max-width:220px;
+ _width:160px;
+ padding:4px 0;
+ margin:0;
+ list-style:none;
+ background-color:#ffffff;
+ border-color:#cccccc;
+ border-color:rgba(0,0,0,0.2);
+ border-style:solid;
+ border-width:1px;
+ -webkit-border-radius:0 0 5px 5px;
+ -moz-border-radius:0 0 5px 5px;
+ border-radius:0 0 5px 5px;
+ -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ -webkit-background-clip:padding-box;
+ -moz-background-clip:padding;
+ background-clip:padding-box;
+ *border-right-width:2px;
+ *border-bottom-width:2px;
+}
+.dropdown-menu.bottom-up {
+ top:auto;
+ bottom:100%;
+ margin-bottom:2px;
+}
+.dropdown-menu .divider {
+ height:1px;
+ margin:5px 1px;
+ overflow:hidden;
+ background-color:#e5e5e5;
+ border-bottom:1px solid #ffffff;
+ *width:100%;
+ *margin:-5px 0 5px;
+}
+.dropdown-menu a {
+ display:block;
+ padding:3px 15px;
+ clear:both;
+ font-weight:normal;
+ line-height:18px;
+ color:#555555;
+ white-space:nowrap;
+}
+.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover {
+ color:#ffffff;
+ text-decoration:none;
+ background-color:#0060b6;
+}
+.dropdown.open { *z-index:1000; }
+.dropdown.open .dropdown-toggle {
+ color:#ffffff;
+ background:#cccccc;
+ background:rgba(0,0,0,0.3);
+}
+.dropdown.open .dropdown-menu { display:block; }
+.typeahead {
+ margin-top:2px;
+ -webkit-border-radius:4px;
+ -moz-border-radius:4px;
+ border-radius:4px;
+}
+/*!
+ * Datepicker for Bootstrap
+ *
+ * Copyright 2012 Stefan Petre
+ * Improvements by Andrew Rowls
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+.datepicker {
+ top: 0;
+ left: 0;
+ padding: 4px;
+ margin-top: 1px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ /*.dow {
+ border-top: 1px solid #ddd !important;
+ }*/
+
+}
+.datepicker:before {
+ content: '';
+ display: inline-block;
+ border-left: 7px solid transparent;
+ border-right: 7px solid transparent;
+ border-bottom: 7px solid #ccc;
+ border-bottom-color: rgba(0, 0, 0, 0.2);
+ position: absolute;
+ top: -7px;
+ left: 6px;
+}
+.datepicker:after {
+ content: '';
+ display: inline-block;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid #ffffff;
+ position: absolute;
+ top: -6px;
+ left: 7px;
+}
+.datepicker > div {
+ display: none;
+}
+.datepicker.days div.datepicker-days {
+ display: block;
+}
+.datepicker.months div.datepicker-months {
+ display: block;
+}
+.datepicker.years div.datepicker-years {
+ display: block;
+}
+.datepicker table {
+ margin: 0;
+}
+.datepicker td,
+.datepicker th {
+ text-align: center;
+ width: 20px;
+ height: 20px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.datepicker td.day:hover {
+ background: #eeeeee;
+ cursor: pointer;
+}
+.datepicker td.old,
+.datepicker td.new {
+ color: #999999;
+}
+.datepicker td.disabled,
+.datepicker td.disabled:hover {
+ background: none;
+ color: #999999;
+ cursor: default;
+}
+.datepicker td.today,
+.datepicker td.today:hover,
+.datepicker td.today.disabled,
+.datepicker td.today.disabled:hover {
+ background-color: #fde19a;
+ background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
+ background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
+ background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
+ background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
+ background-image: linear-gradient(top, #fdd49a, #fdf59a);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
+ border-color: #fdf59a #fdf59a #fbed50;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+.datepicker td.today:hover,
+.datepicker td.today:hover:hover,
+.datepicker td.today.disabled:hover,
+.datepicker td.today.disabled:hover:hover,
+.datepicker td.today:active,
+.datepicker td.today:hover:active,
+.datepicker td.today.disabled:active,
+.datepicker td.today.disabled:hover:active,
+.datepicker td.today.active,
+.datepicker td.today:hover.active,
+.datepicker td.today.disabled.active,
+.datepicker td.today.disabled:hover.active,
+.datepicker td.today.disabled,
+.datepicker td.today:hover.disabled,
+.datepicker td.today.disabled.disabled,
+.datepicker td.today.disabled:hover.disabled,
+.datepicker td.today[disabled],
+.datepicker td.today:hover[disabled],
+.datepicker td.today.disabled[disabled],
+.datepicker td.today.disabled:hover[disabled] {
+ background-color: #fdf59a;
+}
+.datepicker td.today:active,
+.datepicker td.today:hover:active,
+.datepicker td.today.disabled:active,
+.datepicker td.today.disabled:hover:active,
+.datepicker td.today.active,
+.datepicker td.today:hover.active,
+.datepicker td.today.disabled.active,
+.datepicker td.today.disabled:hover.active {
+ background-color: #fbf069 \9;
+}
+.datepicker td.active,
+.datepicker td.active:hover,
+.datepicker td.active.disabled,
+.datepicker td.active.disabled:hover {
+ background-color: #006dcc;
+ background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
+ background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -o-linear-gradient(top, #0088cc, #0044cc);
+ background-image: linear-gradient(top, #0088cc, #0044cc);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
+ border-color: #0044cc #0044cc #002a80;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ color: #fff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+.datepicker td.active:hover,
+.datepicker td.active:hover:hover,
+.datepicker td.active.disabled:hover,
+.datepicker td.active.disabled:hover:hover,
+.datepicker td.active:active,
+.datepicker td.active:hover:active,
+.datepicker td.active.disabled:active,
+.datepicker td.active.disabled:hover:active,
+.datepicker td.active.active,
+.datepicker td.active:hover.active,
+.datepicker td.active.disabled.active,
+.datepicker td.active.disabled:hover.active,
+.datepicker td.active.disabled,
+.datepicker td.active:hover.disabled,
+.datepicker td.active.disabled.disabled,
+.datepicker td.active.disabled:hover.disabled,
+.datepicker td.active[disabled],
+.datepicker td.active:hover[disabled],
+.datepicker td.active.disabled[disabled],
+.datepicker td.active.disabled:hover[disabled] {
+ background-color: #0044cc;
+}
+.datepicker td.active:active,
+.datepicker td.active:hover:active,
+.datepicker td.active.disabled:active,
+.datepicker td.active.disabled:hover:active,
+.datepicker td.active.active,
+.datepicker td.active:hover.active,
+.datepicker td.active.disabled.active,
+.datepicker td.active.disabled:hover.active {
+ background-color: #003399 \9;
+}
+.datepicker td span {
+ display: block;
+ width: 23%;
+ height: 54px;
+ line-height: 54px;
+ float: left;
+ margin: 1%;
+ cursor: pointer;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.datepicker td span:hover {
+ background: #eeeeee;
+}
+.datepicker td span.disabled,
+.datepicker td span.disabled:hover {
+ background: none;
+ color: #999999;
+ cursor: default;
+}
+.datepicker td span.active,
+.datepicker td span.active:hover,
+.datepicker td span.active.disabled,
+.datepicker td span.active.disabled:hover {
+ background-color: #006dcc;
+ background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
+ background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
+ background-image: -o-linear-gradient(top, #0088cc, #0044cc);
+ background-image: linear-gradient(top, #0088cc, #0044cc);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
+ border-color: #0044cc #0044cc #002a80;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ color: #fff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+.datepicker td span.active:hover,
+.datepicker td span.active:hover:hover,
+.datepicker td span.active.disabled:hover,
+.datepicker td span.active.disabled:hover:hover,
+.datepicker td span.active:active,
+.datepicker td span.active:hover:active,
+.datepicker td span.active.disabled:active,
+.datepicker td span.active.disabled:hover:active,
+.datepicker td span.active.active,
+.datepicker td span.active:hover.active,
+.datepicker td span.active.disabled.active,
+.datepicker td span.active.disabled:hover.active,
+.datepicker td span.active.disabled,
+.datepicker td span.active:hover.disabled,
+.datepicker td span.active.disabled.disabled,
+.datepicker td span.active.disabled:hover.disabled,
+.datepicker td span.active[disabled],
+.datepicker td span.active:hover[disabled],
+.datepicker td span.active.disabled[disabled],
+.datepicker td span.active.disabled:hover[disabled] {
+ background-color: #0044cc;
+}
+.datepicker td span.active:active,
+.datepicker td span.active:hover:active,
+.datepicker td span.active.disabled:active,
+.datepicker td span.active.disabled:hover:active,
+.datepicker td span.active.active,
+.datepicker td span.active:hover.active,
+.datepicker td span.active.disabled.active,
+.datepicker td span.active.disabled:hover.active {
+ background-color: #003399 \9;
+}
+.datepicker td span.old {
+ color: #999999;
+}
+.datepicker th.switch {
+ width: 145px;
+}
+.datepicker thead tr:first-child th,
+.datepicker tfoot tr:first-child th {
+ cursor: pointer;
+}
+.datepicker thead tr:first-child th:hover,
+.datepicker tfoot tr:first-child th:hover {
+ background: #eeeeee;
+}
+.input-append.date .add-on i,
+.input-prepend.date .add-on i {
+ display: block;
+ cursor: pointer;
+ width: 16px;
+ height: 16px;
+}
+
+[class^="icon-"], [class*=" icon-"] {
+ display:inline-block;
+ width:14px;
+ height:14px;
+ *margin-right:.3em;
+ line-height:14px;
+ vertical-align:text-top;
+ background-image:url("glyphicons-halflings.png");
+ background-position:14px 14px;
+ background-repeat:no-repeat;
+}
+[class^="icon-"]:last-child, [class*=" icon-"]:last-child { *margin-left:0; }
+.icon-arrow-left { background-position:-240px -96px; }
+.icon-arrow-right { background-position:-264px -96px; }
\ No newline at end of file
diff --git a/app/assets/javascripts/jquery-timepicker/lib/base.js b/app/assets/javascripts/jquery-timepicker/lib/base.js
index b41a04ffe8..e23cda97d1 100755
--- a/app/assets/javascripts/jquery-timepicker/lib/base.js
+++ b/app/assets/javascripts/jquery-timepicker/lib/base.js
@@ -1,14 +1,14 @@
-/* Rainbow v1.1.8 rainbowco.de | included languages: generic, javascript */
-window.Rainbow=function(){function q(a){var b,c=a.getAttribute&&a.getAttribute("data-language")||0;if(!c){a=a.attributes;for(b=0;b=e[d][c])delete e[d][c],delete j[d][c];if(a>=c&&ac&&b'+b+""}function s(a,b,c,h){var f=a.exec(c);if(f){++t;!b.name&&"string"==typeof b.matches[0]&&(b.name=b.matches[0],delete b.matches[0]);var k=f[0],i=f.index,u=f[0].length+i,g=function(){function f(){s(a,b,c,h)}t%100>0?f():setTimeout(f,0)};if(C(i,u))g();else{var m=v(b.matches),l=function(a,c,h){if(a>=c.length)h(k);else{var d=f[c[a]];if(d){var e=b.matches[c[a]],i=e.language,g=e.name&&e.matches?
-e.matches:e,j=function(b,d,e){var i;i=0;var g;for(g=1;g/g,">").replace(/&(?![\w\#]+;)/g,
-"&"),b,c)}function o(a,b,c){if(b'+b.dates.daysMin[(d++)%7]+""}e+=" ";this.picker.find(".datepicker-days thead").append(e)},fillMonths:function(){var e="";var d=0;while(d<12){e+=''+b.dates.monthsShort[d++]+" "}this.picker.find(".datepicker-months td").append(e)},fill:function(){var o=new Date(this.viewDate),p=o.getFullYear(),n=o.getMonth(),f=this.date.valueOf();this.picker.find(".datepicker-days th:eq(1)").text(b.dates.months[n]+" "+p);var j=new Date(p,n-1,28,0,0,0,0),q=b.getDaysInMonth(j.getFullYear(),j.getMonth());j.setDate(q);j.setDate(q-(j.getDay()-this.weekStart+7)%7);var l=new Date(j);l.setDate(l.getDate()+42);l=l.valueOf();html=[];var h;while(j.valueOf()")}h="";if(this.options.minDate&&this.options.minDate>j){h+=" invalid"}else{if(this.options.maxDate&&this.options.maxDaten){h+=" new"}}}}if(j.valueOf()==f){h+=" active"}html.push(''+j.getDate()+" ");if(j.getDay()==this.weekEnd){html.push("")}j.setDate(j.getDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(html.join(""));var m=this.date.getFullYear();var e=this.picker.find(".datepicker-months").find("th:eq(1)").text(p).end().find("span").removeClass("active");if(m==p){e.eq(this.date.getMonth()).addClass("active")}html="";p=parseInt(p/10,10)*10;var g=this.picker.find(".datepicker-years").find("th:eq(1)").text(p+"-"+(p+9)).end().find("td");p-=1;for(var k=-1;k<11;k++){html+=''+p+" ";p+=1}g.html(html)},click:function(i){i.stopPropagation();i.preventDefault();var h=c(i.target).closest("span, td, th");if(h.length==1){switch(h[0].nodeName.toLowerCase()){case"th":switch(h[0].className){case"switch":this.showMode(1);break;case"prev":case"next":this.viewDate["set"+b.modes[this.viewMode].navFnc].call(this.viewDate,this.viewDate["get"+b.modes[this.viewMode].navFnc].call(this.viewDate)+b.modes[this.viewMode].navStep*(h[0].className=="prev"?-1:1));this.fill();break}break;case"span":if(h.is(".month")){var g=h.parent().find("span").index(h);this.viewDate.setMonth(g)}else{var f=parseInt(h.text(),10)||0;this.viewDate.setFullYear(f)}this.showMode(-1);this.fill();break;case"td":if(h.is(".day")){if(h.is(".invalid")){return}var d=parseInt(h.text(),10)||1;var g=this.viewDate.getMonth();if(h.is(".old")){g-=1}else{if(h.is(".new")){g+=1}}var f=this.viewDate.getFullYear();this.date=new Date(f,g,d,0,0,0,0);this.viewDate=new Date(f,g,d,0,0,0,0);this.fill();this.setValue();this.hide();this.element.blur();this.element.trigger({type:"changeDate",date:this.date})}break}}},mousedown:function(d){d.stopPropagation();d.preventDefault()},showMode:function(d){if(d){this.viewMode=Math.max(0,Math.min(2,this.viewMode+d))}this.picker.find(">div").hide().filter(".datepicker-"+b.modes[this.viewMode].clsName).show()}};c.fn.datepicker=function(e){var d=arguments;return this.each(function(){var h=c(this),g=h.data("datepicker"),f=typeof e=="object"&&e;if(!g){h.data("datepicker",(g=new a(this,c.extend({},c.fn.datepicker.defaults,f))))}if(typeof e=="string"){g[e].apply(g,Array.prototype.slice.call(d,1))}})};c.fn.datepicker.defaults={};c.fn.datepicker.Constructor=a;var b={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],dates:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},isLeapYear:function(d){return(((d%4===0)&&(d%100!==0))||(d%400===0))},getDaysInMonth:function(d,e){return[31,(b.isLeapYear(d)?29:28),31,30,31,30,31,31,30,31,30,31][e]},parseFormat:function(f){var e=f.match(/[.\/-].*?/),d=f.split(/\W+/);if(!e||!d||d.length==0){throw new Error("Invalid date format.")}return{separator:e,parts:d}},parseDate:function(d,h){var g=d.split(h.separator),d=new Date(1970,1,1,0,0,0),j;if(g.length==h.parts.length){for(var f=0,e=h.parts.length;f ',contTemplate:' '};b.template='"}(window.jQuery);
+/* Rainbow v1.1.9 rainbowco.de | included languages: generic, javascript */
+window.Rainbow=function(){function q(a){var b,c=a.getAttribute&&a.getAttribute("data-language")||0;if(!c){a=a.attributes;for(b=0;b=e[d][c])delete e[d][c],delete j[d][c];if(a>=c&&ac&&b'+b+""}function s(a,b,c,h){var f=a.exec(c);if(f){++t;!b.name&&"string"==typeof b.matches[0]&&(b.name=b.matches[0],delete b.matches[0]);var k=f[0],i=f.index,u=f[0].length+i,g=function(){function f(){s(a,b,c,h)}t%100>0?f():setTimeout(f,0)};if(C(i,u))g();else{var m=v(b.matches),l=function(a,c,h){if(a>=c.length)h(k);else{var d=f[c[a]];if(d){var e=b.matches[c[a]],i=e.language,g=e.name&&e.matches?
+e.matches:e,j=function(b,d,e){var i;i=0;var g;for(g=1;g/g,">").replace(/&(?![\w\#]+;)/g,
+"&"),b,c)}function o(a,b,c){if(bb;b++)c=this._events[b][0],d=this._events[b][1],c.on(d)},_detachEvents:function(){for(var b,c,a=0;this._events.length>a;a++)b=this._events[a][0],c=this._events[a][1],b.off(c);this._events=[]},show:function(b){this.picker.show(),this.height=this.component?this.component.outerHeight():this.element.outerHeight(),this.update(),this.place(),a(window).on("resize",a.proxy(this.place,this)),b&&(b.stopPropagation(),b.preventDefault()),this.element.trigger({type:"show",date:this.date})},hide:function(){this.picker.hide(),a(window).off("resize",this.place),this.viewMode=this.startViewMode,this.showMode(),this.isInput||a(document).off("mousedown",this.hide),this.forceParse&&(this.isInput&&this.element.val()||this.hasInput&&this.element.find("input").val())&&this.setValue(),this.element.trigger({type:"hide",date:this.date})},remove:function(){this._detachEvents(),this.picker.remove(),delete this.element.data().datepicker},getDate:function(){var a=this.getUTCDate();return new Date(a.getTime()+6e4*a.getTimezoneOffset())},getUTCDate:function(){return this.date},setDate:function(a){this.setUTCDate(new Date(a.getTime()-6e4*a.getTimezoneOffset()))},setUTCDate:function(a){this.date=a,this.setValue()},setValue:function(){var a=f.formatDate(this.date,this.format,this.language);this.isInput?this.element.prop("value",a):(this.component&&this.element.find("input").prop("value",a),this.element.data("date",a))},setStartDate:function(a){this.startDate=a||-1/0,this.startDate!==-1/0&&(this.startDate=f.parseDate(this.startDate,this.format,this.language)),this.update(),this.updateNavArrows()},setEndDate:function(a){this.endDate=a||1/0,1/0!==this.endDate&&(this.endDate=f.parseDate(this.endDate,this.format,this.language)),this.update(),this.updateNavArrows()},setDaysOfWeekDisabled:function(b){this.daysOfWeekDisabled=b||[],a.isArray(this.daysOfWeekDisabled)||(this.daysOfWeekDisabled=this.daysOfWeekDisabled.split(/,\s*/)),this.daysOfWeekDisabled=a.map(this.daysOfWeekDisabled,function(a){return parseInt(a,10)}),this.update(),this.updateNavArrows()},place:function(){var b=parseInt(this.element.parents().filter(function(){return"auto"!=a(this).css("z-index")}).first().css("z-index"))+10,c=this.component?this.component.offset():this.element.offset();this.picker.css({top:c.top+this.height,left:c.left,zIndex:b})},update:function(){this.date=f.parseDate(this.isInput?this.element.prop("value"):this.element.data("date")||this.element.find("input").prop("value"),this.format,this.language),this.viewDate=this.datethis.endDate?new Date(this.endDate):new Date(this.date),this.fill()},fillDow:function(){for(var a=this.weekStart,b="";this.weekStart+7>a;)b+=''+e[this.language].daysMin[a++%7]+" ";b+=" ",this.picker.find(".datepicker-days thead").append(b)},fillMonths:function(){for(var a="",b=0;12>b;)a+=''+e[this.language].monthsShort[b++]+" ";this.picker.find(".datepicker-months td").html(a)},fill:function(){var c=new Date(this.viewDate),d=c.getUTCFullYear(),g=c.getUTCMonth(),h=this.startDate!==-1/0?this.startDate.getUTCFullYear():-1/0,i=this.startDate!==-1/0?this.startDate.getUTCMonth():-1/0,j=1/0!==this.endDate?this.endDate.getUTCFullYear():1/0,k=1/0!==this.endDate?this.endDate.getUTCMonth():1/0,l=this.date.valueOf(),m=new Date;this.picker.find(".datepicker-days thead th:eq(1)").text(e[this.language].months[g]+" "+d),this.picker.find("tfoot th.today").text(e[this.language].today).toggle(this.todayBtn!==!1),this.updateNavArrows(),this.fillMonths();var n=b(d,g-1,28,0,0,0,0),o=f.getDaysInMonth(n.getUTCFullYear(),n.getUTCMonth());n.setUTCDate(o),n.setUTCDate(o-(n.getUTCDay()-this.weekStart+7)%7);var p=new Date(n);p.setUTCDate(p.getUTCDate()+42),p=p.valueOf();for(var r,q=[];p>n.valueOf();)n.getUTCDay()==this.weekStart&&q.push(""),r="",d>n.getUTCFullYear()||n.getUTCFullYear()==d&&g>n.getUTCMonth()?r+=" old":(n.getUTCFullYear()>d||n.getUTCFullYear()==d&&n.getUTCMonth()>g)&&(r+=" new"),this.todayHighlight&&n.getUTCFullYear()==m.getFullYear()&&n.getUTCMonth()==m.getMonth()&&n.getUTCDate()==m.getDate()&&(r+=" today"),n.valueOf()==l&&(r+=" active"),(n.valueOf()this.endDate||-1!==a.inArray(n.getUTCDay(),this.daysOfWeekDisabled))&&(r+=" disabled"),q.push(''+n.getUTCDate()+" "),n.getUTCDay()==this.weekEnd&&q.push(" "),n.setUTCDate(n.getUTCDate()+1);this.picker.find(".datepicker-days tbody").empty().append(q.join(""));var s=this.date.getUTCFullYear(),t=this.picker.find(".datepicker-months").find("th:eq(1)").text(d).end().find("span").removeClass("active");s==d&&t.eq(this.date.getUTCMonth()).addClass("active"),(h>d||d>j)&&t.addClass("disabled"),d==h&&t.slice(0,i).addClass("disabled"),d==j&&t.slice(k+1).addClass("disabled"),q="",d=10*parseInt(d/10,10);var u=this.picker.find(".datepicker-years").find("th:eq(1)").text(d+"-"+(d+9)).end().find("td");d-=1;for(var v=-1;11>v;v++)q+='d||d>j?" disabled":"")+'">'+d+" ",d+=1;u.html(q)},updateNavArrows:function(){var a=new Date(this.viewDate),b=a.getUTCFullYear(),c=a.getUTCMonth();switch(this.viewMode){case 0:this.startDate!==-1/0&&this.startDate.getUTCFullYear()>=b&&this.startDate.getUTCMonth()>=c?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.endDate&&b>=this.endDate.getUTCFullYear()&&c>=this.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:case 2:this.startDate!==-1/0&&this.startDate.getUTCFullYear()>=b?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.endDate&&b>=this.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}},click:function(c){c.stopPropagation(),c.preventDefault();var d=a(c.target).closest("span, td, th");if(1==d.length)switch(d[0].nodeName.toLowerCase()){case"th":switch(d[0].className){case"switch":this.showMode(1);break;case"prev":case"next":var e=f.modes[this.viewMode].navStep*("prev"==d[0].className?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveMonth(this.viewDate,e);break;case 1:case 2:this.viewDate=this.moveYear(this.viewDate,e)}this.fill();break;case"today":var g=new Date;g.setUTCHours(0),g.setUTCMinutes(0),g.setUTCSeconds(0),g.setUTCMilliseconds(0),this.showMode(-2);var h="linked"==this.todayBtn?null:"view";this._setDate(g,h)}break;case"span":if(!d.is(".disabled")){if(this.viewDate.setUTCDate(1),d.is(".month")){var i=d.parent().find("span").index(d);this.viewDate.setUTCMonth(i),this.element.trigger({type:"changeMonth",date:this.viewDate})}else{var j=parseInt(d.text(),10)||0;this.viewDate.setUTCFullYear(j),this.element.trigger({type:"changeYear",date:this.viewDate})}this.showMode(-1),this.fill()}break;case"td":if(d.is(".day")&&!d.is(".disabled")){var k=parseInt(d.text(),10)||1,j=this.viewDate.getUTCFullYear(),i=this.viewDate.getUTCMonth();d.is(".old")?0==i?(i=11,j-=1):i-=1:d.is(".new")&&(11==i?(i=0,j+=1):i+=1),this._setDate(b(j,i,k,0,0,0,0))}}},_setDate:function(a,b){b&&"date"!=b||(this.date=a),b&&"view"!=b||(this.viewDate=a),this.fill(),this.setValue(),this.element.trigger({type:"changeDate",date:this.date});var c;this.isInput?c=this.element:this.component&&(c=this.element.find("input")),c&&(c.change(),this.autoclose&&this.hide())},moveMonth:function(a,b){if(!b)return a;var g,h,c=new Date(a.valueOf()),d=c.getUTCDate(),e=c.getUTCMonth(),f=Math.abs(b);if(b=b>0?1:-1,1==f)h=-1==b?function(){return c.getUTCMonth()==e}:function(){return c.getUTCMonth()!=g},g=e+b,c.setUTCMonth(g),(0>g||g>11)&&(g=(g+12)%12);else{for(var i=0;f>i;i++)c=this.moveMonth(c,b);g=c.getUTCMonth(),c.setUTCDate(d),h=function(){return g!=c.getUTCMonth()}}for(;h();)c.setUTCDate(--d),c.setUTCMonth(g);return c},moveYear:function(a,b){return this.moveMonth(a,12*b)},dateWithinRange:function(a){return a>=this.startDate&&this.endDate>=a},keydown:function(a){if(this.picker.is(":not(:visible)"))return 27==a.keyCode&&this.show(),void 0;var c,f,g,b=!1;switch(a.keyCode){case 27:this.hide(),a.preventDefault();break;case 37:case 39:if(!this.keyboardNavigation)break;c=37==a.keyCode?-1:1,a.ctrlKey?(f=this.moveYear(this.date,c),g=this.moveYear(this.viewDate,c)):a.shiftKey?(f=this.moveMonth(this.date,c),g=this.moveMonth(this.viewDate,c)):(f=new Date(this.date),f.setUTCDate(this.date.getUTCDate()+c),g=new Date(this.viewDate),g.setUTCDate(this.viewDate.getUTCDate()+c)),this.dateWithinRange(f)&&(this.date=f,this.viewDate=g,this.setValue(),this.update(),a.preventDefault(),b=!0);break;case 38:case 40:if(!this.keyboardNavigation)break;c=38==a.keyCode?-1:1,a.ctrlKey?(f=this.moveYear(this.date,c),g=this.moveYear(this.viewDate,c)):a.shiftKey?(f=this.moveMonth(this.date,c),g=this.moveMonth(this.viewDate,c)):(f=new Date(this.date),f.setUTCDate(this.date.getUTCDate()+7*c),g=new Date(this.viewDate),g.setUTCDate(this.viewDate.getUTCDate()+7*c)),this.dateWithinRange(f)&&(this.date=f,this.viewDate=g,this.setValue(),this.update(),a.preventDefault(),b=!0);break;case 13:this.hide(),a.preventDefault();break;case 9:this.hide()}if(b){this.element.trigger({type:"changeDate",date:this.date});var h;this.isInput?h=this.element:this.component&&(h=this.element.find("input")),h&&h.change()}},showMode:function(a){a&&(this.viewMode=Math.max(0,Math.min(2,this.viewMode+a))),this.picker.find(">div").hide().filter(".datepicker-"+f.modes[this.viewMode].clsName).show(),this.updateNavArrows()}},a.fn.datepicker=function(b){var c=Array.apply(null,arguments);return c.shift(),this.each(function(){var e=a(this),f=e.data("datepicker"),g="object"==typeof b&&b;f||e.data("datepicker",f=new d(this,a.extend({},a.fn.datepicker.defaults,g))),"string"==typeof b&&"function"==typeof f[b]&&f[b].apply(f,c)})},a.fn.datepicker.defaults={},a.fn.datepicker.Constructor=d;var e=a.fn.datepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today"}},f={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(a){return 0===a%4&&0!==a%100||0===a%400},getDaysInMonth:function(a,b){return[31,f.isLeapYear(a)?29:28,31,30,31,30,31,31,30,31,30,31][b]},validParts:/dd?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[-`{-~\t\n\r]+/g,parseFormat:function(a){var b=a.replace(this.validParts,"\0").split("\0"),c=a.match(this.validParts);if(!b||!b.length||!c||0==c.length)throw Error("Invalid date format.");return{separators:b,parts:c}},parseDate:function(c,f,g){if(c instanceof Date)return c;if(/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(c)){var j,k,h=/([-+]\d+)([dmwy])/,i=c.match(/([-+]\d+)([dmwy])/g);c=new Date;for(var l=0;i.length>l;l++)switch(j=h.exec(i[l]),k=parseInt(j[1]),j[2]){case"d":c.setUTCDate(c.getUTCDate()+k);break;case"m":c=d.prototype.moveMonth.call(d.prototype,c,k);break;case"w":c.setUTCDate(c.getUTCDate()+7*k);break;case"y":c=d.prototype.moveYear.call(d.prototype,c,k)}return b(c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate(),0,0,0)}var p,q,j,i=c&&c.match(this.nonpunctuation)||[],c=new Date,m={},n=["yyyy","yy","M","MM","m","mm","d","dd"],o={yyyy:function(a,b){return a.setUTCFullYear(b)},yy:function(a,b){return a.setUTCFullYear(2e3+b)},m:function(a,b){for(b-=1;0>b;)b+=12;for(b%=12,a.setUTCMonth(b);a.getUTCMonth()!=b;)a.setUTCDate(a.getUTCDate()-1);return a},d:function(a,b){return a.setUTCDate(b)}};if(o.M=o.MM=o.mm=o.m,o.dd=o.d,c=b(c.getFullYear(),c.getMonth(),c.getDate(),0,0,0),i.length==f.parts.length){for(var l=0,r=f.parts.length;r>l;l++){if(p=parseInt(i[l],10),j=f.parts[l],isNaN(p))switch(j){case"MM":q=a(e[g].months).filter(function(){var a=this.slice(0,i[l].length),b=i[l].slice(0,a.length);return a==b}),p=a.inArray(q[0],e[g].months)+1;break;case"M":q=a(e[g].monthsShort).filter(function(){var a=this.slice(0,i[l].length),b=i[l].slice(0,a.length);return a==b}),p=a.inArray(q[0],e[g].monthsShort)+1}m[j]=p}for(var s,l=0;n.length>l;l++)s=n[l],s in m&&!isNaN(m[s])&&o[s](c,m[s])}return c},formatDate:function(b,c,d){var f={d:b.getUTCDate(),m:b.getUTCMonth()+1,M:e[d].monthsShort[b.getUTCMonth()],MM:e[d].months[b.getUTCMonth()],yy:(""+b.getUTCFullYear()).substring(2),yyyy:b.getUTCFullYear()};f.dd=(10>f.d?"0":"")+f.d,f.mm=(10>f.m?"0":"")+f.m;for(var b=[],g=a.extend([],c.separators),h=0,i=c.parts.length;i>h;h++)g.length&&b.push(g.shift()),b.push(f[c.parts[h]]);return b.join("")},headTemplate:' ',contTemplate:' ',footTemplate:' '};f.template='"}(window.jQuery);
diff --git a/app/assets/javascripts/jquery-timepicker/lib/datepair-old.js b/app/assets/javascripts/jquery-timepicker/lib/datepair-old.js
deleted file mode 100755
index 9a34d0a5a2..0000000000
--- a/app/assets/javascripts/jquery-timepicker/lib/datepair-old.js
+++ /dev/null
@@ -1,201 +0,0 @@
-(function() {
-
- (function($) {
- $('.datepair input.date').live("click focus", function(){
- var $this = $(this);
- $this.datepicker({ 'showOn': 'focus', 'dateFormat': 'dd/mm/yy' });
-
- if ($this.hasClass('start') || $this.hasClass('end')) {
- $this.on('changeDate change', doDatepair);
- }
-
- });
-
- $('.datepair input.time').live("click focus", function() {
- var $this = $(this);
- var opts = { 'showDuration': true, 'timeFormat': 'g:ia', 'scrollDefaultNow': true };
-
- if ($this.hasClass('start') || $this.hasClass('end')) {
- $this.on('changeTime change', doDatepair);
- }
-
- $this.timepicker(opts);
- });
-
- $('.datepair').live("click", function(){
- initDatepair;
- });
-
- function initDatepair()
- {
- var container = $(this);
-
- var startDateInput = container.find('input.start.date');
- var endDateInput = container.find('input.end.date');
- var dateDelta = 0;
-
- if (startDateInput.length && endDateInput.length) {
- var startDate = new Date(startDateInput.val());
- var endDate = new Date(endDateInput.val());
-
- dateDelta = endDate.getTime() - startDate.getTime();
-
- container.data('dateDelta', dateDelta);
- }
-
- var startTimeInput = container.find('input.start.time');
- var endTimeInput = container.find('input.end.time');
-
- if (startTimeInput.length && endTimeInput.length) {
- var startInt = startTimeInput.timepicker('getSecondsFromMidnight');
- var endInt = endTimeInput.timepicker('getSecondsFromMidnight');
-
- container.data('timeDelta', endInt - startInt);
-
- if (dateDelta < 86400000) {
- endTimeInput.timepicker('option', 'minTime', startInt);
- }
- }
- }
-
- function doDatepair()
- {
- var target = $(this);
- if (target.val() == '') {
- return;
- }
-
- var container = target.closest('.datepair');
-
- if (target.hasClass('date')) {
- updateDatePair(target, container);
-
- } else if (target.hasClass('time')) {
- updateTimePair(target, container);
- }
- }
-
- function updateDatePair(target, container)
- {
- var start = container.find('input.start.date');
- var end = container.find('input.end.date');
-
- if (!start.length || !end.length) {
- return;
- }
-
- var startDate = new Date(start.val());
- var endDate = new Date(end.val());
-
- var oldDelta = container.data('dateDelta');
-
- if (oldDelta && target.hasClass('start')) {
- var newEnd = new Date(startDate.getTime()+oldDelta);
- end.val(newEnd.format('m/d/Y'));
- end.datepicker('update');
- return;
-
- } else {
- var newDelta = endDate.getTime() - startDate.getTime();
-
- if (newDelta < 0) {
- newDelta = 0;
-
- if (target.hasClass('start')) {
- end.val(startDate.format('m/d/Y'));
- end.datepicker('update');
- } else if (target.hasClass('end')) {
- start.val(endDate.format('m/d/Y'));
- start.datepicker('update');
- }
- }
-
- if (newDelta < 86400000) {
- var startTimeVal = container.find('input.start.time').val();
-
- if (startTimeVal) {
- container.find('input.end.time').timepicker('option', {'minTime': startTimeVal});
- }
- } else {
- container.find('input.end.time').timepicker('option', {'minTime': null});
- }
-
- container.data('dateDelta', newDelta);
- }
- }
-
- function updateTimePair(target, container)
- {
- var start = container.find('input.start.time');
- var end = container.find('input.end.time');
-
- if (!start.length || !end.length) {
- return;
- }
-
- var startInt = start.timepicker('getSecondsFromMidnight');
- var endInt = end.timepicker('getSecondsFromMidnight');
-
- var oldDelta = container.data('timeDelta');
- var dateDelta = container.data('dateDelta');
-
- if (target.hasClass('start') && (!dateDelta || dateDelta < 86400000)) {
- end.timepicker('option', 'minTime', startInt);
- }
-
- var endDateAdvance = 0;
- var newDelta;
-
- if (oldDelta && target.hasClass('start')) {
- // lock the duration and advance the end time
-
- var newEnd = (startInt+oldDelta)%86400;
-
- if (newEnd < 0) {
- newEnd += 86400;
- }
-
- end.timepicker('setTime', newEnd);
- newDelta = newEnd - startInt;
- } else if (startInt !== null && endInt !== null) {
- newDelta = endInt - startInt;
- } else {
- return;
- }
-
- container.data('timeDelta', newDelta);
-
- if (newDelta < 0 && (!oldDelta || oldDelta > 0)) {
- // overnight time span. advance the end date 1 day
- var endDateAdvance = 86400000;
-
- } else if (newDelta > 0 && oldDelta < 0) {
- // switching from overnight to same-day time span. decrease the end date 1 day
- var endDateAdvance = -86400000;
- }
-
- var startInput = container.find('.start.date');
- var endInput = container.find('.end.date');
-
- if (startInput.val() && !endInput.val()) {
- endInput.val(startInput.val());
- endInput.datepicker('update');
- dateDelta = 0;
- container.data('dateDelta', 0);
- }
-
- if (endDateAdvance != 0) {
- if (dateDelta || dateDelta === 0) {
- var endDate = new Date(endInput.val());
- var newEnd = new Date(endDate.getTime() + endDateAdvance);
- endInput.val(newEnd.format('m/d/Y'));
- endInput.datepicker('update');
- container.data('dateDelta', dateDelta + endDateAdvance);
- }
- }
- }
-})(jQuery);
-}).call(this);
-
-// Simulates PHP's date function
-Date.prototype.format=function(format){var returnStr='';var replace=Date.replaceChars;for(var i=0;i 0)) {
- // overnight time span. advance the end date 1 day
- var endDateAdvance = 86400000;
-
- } else if (newDelta > 0 && oldDelta < 0) {
- // switching from overnight to same-day time span. decrease the end date 1 day
- var endDateAdvance = -86400000;
- }
-
- var startInput = container.find('.start.date');
- var endInput = container.find('.end.date');
-
- if (startInput.val() && !endInput.val()) {
- endInput.val(startInput.val());
- endInput.datepicker('update');
- dateDelta = 0;
- container.data('dateDelta', 0);
- }
-
- if (endDateAdvance != 0) {
- if (dateDelta || dateDelta === 0) {
- var endDate = new Date(endInput.val());
- var newEnd = new Date(endDate.getTime() + endDateAdvance);
- endInput.val(newEnd.format('m/d/Y'));
- endInput.datepicker('update');
- container.data('dateDelta', dateDelta + endDateAdvance);
- }
- }
- }
-});
-
-// Simulates PHP's date function
-Date.prototype.format=function(format){var returnStr='';var replace=Date.replaceChars;for(var i=0;i 0)) {
+ // overnight time span. advance the end date 1 day
+ endDateAdvance = 86400000;
+
+ } else if (newDelta > 0 && oldDelta < 0) {
+ // switching from overnight to same-day time span. decrease the end date 1 day
+ endDateAdvance = -86400000;
+ }
+
+ var startInput = container.find('.start.date');
+ var endInput = container.find('.end.date');
+
+ if (startInput.val() && !endInput.val()) {
+ endInput.val(startInput.val());
+ endInput.datepicker('update');
+ dateDelta = 0;
+ container.data('dateDelta', 0);
+ }
+
+ if (endDateAdvance != 0) {
+ if (dateDelta || dateDelta === 0) {
+ var endDate = parseDate(endInput.val(), DATEPICKER_FORMAT);
+ var newEnd = new Date(endDate.getTime() + endDateAdvance);
+ endInput.val(newEnd.format(DATE_FORMAT));
+ endInput.datepicker('update');
+ container.data('dateDelta', dateDelta + endDateAdvance);
+ }
+ }
+ }
+};
+
+function parseDate(input, format) {
+ if (input == '')
+ return new Date('');
+
+ format = format || 'yyyy-mm-dd'; // default format
+ var parts = input.match(/(\d+)/g), i = 0, fmt = {};
+ // extract date-part indexes from the format
+ format.replace(/(yyyy|dd?|mm?)/g, function(part) { fmt[part] = i++; });
+
+ return new Date(parts[fmt['yyyy']], parts[fmt['mm'] == undefined ? fmt['m'] : fmt['mm']]-1, parts[fmt['dd'] == undefined ? fmt['d'] : fmt['dd']]);
+}
+
+// Simulates PHP's date function
+Date.prototype.format=function(format){var returnStr='';var replace=Date.replaceChars;for(var i=0;i=1.7"
},
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-contrib-uglify": "~0.2.2"
+ },
"description": "A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.",
- "keywords": [ "time", "picker", "google calendar" ],
- "homepage": "http://jonthornton.github.com/jquery-timepicker/",
- "files": [ "jquery.timepicker.js", "jquery.timepicker.css" ]
-}
\ No newline at end of file
+ "keywords": [ "timepicker", "time", "picker", "ui", "google calendar" ],
+ "homepage": "http://jonthornton.github.com/jquery-timepicker/"
+}
diff --git a/app/assets/javascripts/lists.js.coffee b/app/assets/javascripts/lists.js.coffee
old mode 100644
new mode 100755
index 54f4496fdd..0a7af86238
--- a/app/assets/javascripts/lists.js.coffee
+++ b/app/assets/javascripts/lists.js.coffee
@@ -4,40 +4,51 @@
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
(($) ->
- class @Lists
- constructor: (@templates = {}) ->
-
- show_save_form: ->
- $(".save_list").show()
- $('.save_list #list_name').focus()
-
- hide_save_form: ->
- $(".save_list").hide()
-
- $(document).ready ->
- lists = new Lists()
-
- $(".show_lists_save_form").live "click", ->
- lists.show_save_form()
- $(".show_lists_save_form").hide()
- false
-
- $(".hide_lists_save_form").live "click", ->
- lists.hide_save_form()
- $(".show_lists_save_form").show()
- false
-
- $("input#save_list").live "click", ->
- # Set value of hidden list_url field to serialized search form
- $("#list_url").val(window.location.pathname + '?' + $('form.ransack_search').serialize())
- true
-
- # When mouseover on li, change asset icons to delete buttons
- $("#lists li").live "mouseover", ->
- img_el = $(this).find('.delete_on_hover img')
- img_el.attr('src', "/assets/delete.png")
- $("#lists li").live "mouseout", ->
- img_el = $(this).find('.delete_on_hover img')
- img_el.attr('src', "/assets/tab_icons/" + img_el.data('controller') + "_active.png")
+
+ # Open list save form
+ $(document).on "click", ".lists .list_save a", ->
+ $list = $(this).closest('.lists')
+ $list.find(".list_form").show().find("[name='list[name]']").focus()
+ $list.find(".list_save").hide()
+ false
+
+ # Close list save form
+ $(document).on "click", ".lists .cancel", ->
+ $list = $(this).closest('.lists')
+ $list.find(".list_form").hide()
+ $list.find(".list_save").show()
+ false
+
+ # Set value of hidden list[url] field to serialized search form
+ $(document).on "click", ".lists .list_form [type=submit]", ->
+ $form = $(this).closest('form')
+ $form.find("[name='list[url]']").val(window.location.pathname + '?' + $('form.ransack_search').serialize())
+ true
+
+ # Disable submit button when form is submitted
+ $(document).on "submit", ".lists .list_form [type=submit]", ->
+ $form = $(this).closest('form')
+ $form.find("[type=submit]").prop('disabled', true);
+
+ # On li mouseover, change icons to delete buttons
+ $(document).on "mouseover", ".lists li", ->
+ icon = $(this).find('.delete_on_hover i.fa')
+ iconText = crm.get_icon(icon.attr('data-controller'))
+ icon.removeClass(iconText).addClass('fa-times-circle')
+
+ # On li mouseout, change asset icons back
+ $(document).on "mouseout", ".lists li", ->
+ icon = $(this).find('.delete_on_hover i.fa')
+ iconText = crm.get_icon(icon.attr('data-controller'))
+ icon.removeClass('fa-times-circle').addClass(iconText)
+
+ # On search tab click, toggle list save on/off
+ $(document).on 'click', '#search .tabs a', ->
+ search_form = $(this).data('search-form')
+ switch search_form
+ when 'basic_search'
+ $('.lists .list_save').hide()
+ when 'advanced_search'
+ $('.lists .list_save').show()
) jQuery
diff --git a/app/assets/javascripts/pagination.js.coffee b/app/assets/javascripts/pagination.js.coffee
new file mode 100644
index 0000000000..d5208c829b
--- /dev/null
+++ b/app/assets/javascripts/pagination.js.coffee
@@ -0,0 +1,16 @@
+# Copyright (c) 2008-2014 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+(($) ->
+
+ $(document).on 'ajax:send', '.pagination, .per_page_options', ->
+ $(this).find('a').prop('disabled', true)
+ $(this).closest('#paginate').find('.spinner').show()
+
+ $(document).on 'ajax:complete', '.pagination, .per_page_options', ->
+ $(this).find('a').prop('disabled', false)
+ $(this).closest('#paginate').find('.spinner').hide()
+
+) jQuery
diff --git a/app/assets/javascripts/search.js.coffee b/app/assets/javascripts/search.js.coffee
index a11aa389f0..41a79b411d 100755
--- a/app/assets/javascripts/search.js.coffee
+++ b/app/assets/javascripts/search.js.coffee
@@ -7,37 +7,22 @@
$ ->
$("#advanced_search").ransack_search_form()
-
+
# For basic search, remove placeholder text on focus, restore on blur
$('#query').focusin (e) ->
$(this).data('placeholder', $(this).attr('placeholder')).attr('placeholder', '')
- $(this).parent().addClass("ui-focus");
- $(this).parent().find(".ui-icon-delete").show();
$('#query').focusout (e) ->
$(this).attr('placeholder', $(this).data('placeholder'))
- $(this).parent().removeClass("ui-focus");
- $(".ui-icon-delete").live "click", ->
- $(this).parent().find("input.clear-ui").val("");
- $(this).hide();
- # For advanced search we show a spinner and dim the page when loading results
- # This method undoes that when the results are returned. Ideally, this should
- # be converted to jQuery (using the 'live' method)
- # but we have to move to jquery-ujs first as all ajax events are current
- # registered with prototype
- Event.observe document.body, 'ajax:complete', (e, el) ->
- if e.findElement('.ransack_search')
+ $(document).ajaxComplete ->
+ if $('.ransack_search').length
$("#loading").hide()
$("#advanced_search").css('opacity', 1)
- Event.observe document.body, 'ajax:failure', (e, el) ->
- if e.findElement('.ransack_search')
- $('#flash').html('An error occurred whilst trying to search') # no i18n
- crm.flash('error')
-
# Search tabs
# -----------------------------------------------------
- activate_search_form = (search_form) ->
+ $(document).on 'click', '#search .tabs a', ->
+ search_form = $(this).data('search-form')
# Hide all
$('#search .search_form').hide()
$('#search .tabs li a').removeClass('active')
@@ -47,25 +32,18 @@
# Run search for current query
switch search_form
when 'basic_search'
- $('#lists .show_lists_save_form').hide()
query_input = $('#basic_search input#query')
if !query_input.is('.defaultTextActive')
value = query_input.val()
else
value = ""
crm.search(value, window.controller)
- $('#filters').enable() # Enable filters panel (if present)
- if query_input.val() != ""
- query_input.focus()
+ $('#filters').prop('disabled', false) # Enable filters panel (if present)
when 'advanced_search'
- $('#lists .show_lists_save_form').show()
$("#advanced_search form input:submit").click()
- $('#filters').disable() # Disable filters panel (if present)
+ $('#filters').prop('disabled', true) # Disable filters panel (if present)
return
- $("#search .tabs a").click ->
- activate_search_form($(this).data('search-form'))
-
) jQuery
diff --git a/app/assets/javascripts/timeago.js.coffee b/app/assets/javascripts/timeago.js.coffee
new file mode 100644
index 0000000000..bfdf0ee7f2
--- /dev/null
+++ b/app/assets/javascripts/timeago.js.coffee
@@ -0,0 +1,21 @@
+(($) ->
+
+ # Run function on page load
+ $ ->
+ $.timeago.settings.allowFuture = true
+
+ # our modification to choose correct language
+ $.timeago.settings.strings = $.timeago.settings.locales[crm.language]
+ $("span.timeago").timeago()
+
+ # update every minute
+ setInterval (->
+ $("span.timeago").timeago()
+ ), 60000
+
+
+ # Run after $ ajax event
+ $(document).ajaxComplete ->
+ $("span.timeago").timeago()
+
+) jQuery
diff --git a/app/assets/stylesheets/advanced_search.css.scss b/app/assets/stylesheets/advanced_search.css.scss
index 706adefa75..57528ededb 100644
--- a/app/assets/stylesheets/advanced_search.css.scss
+++ b/app/assets/stylesheets/advanced_search.css.scss
@@ -6,25 +6,26 @@
#search {
margin-top: 15px;
- .tabs {
- background: none;
-
- li {
- a:link, a:visited {
- background-color: #ddd;
- color: #222;
- font-weight: normal;
- font-size: 11px;
- }
- a:hover {
- background-color: #ccc;
- }
- a.active {
- background-color: #eee;
+
+ .tabs {
+ background: none;
+
+ li {
+ a:link, a:visited {
+ background-color: #ddd;
+ color: #222;
+ font-weight: normal;
+ font-size: 11px;
+ }
+ a:hover {
+ background-color: #ccc;
+ }
+ a.active {
+ background-color: #eee;
color: black;
- }
- }
- }
+ }
+ }
+ }
.search_form {
border: none;
@@ -53,8 +54,8 @@
}
#query {
- margin-top: 6px;
- }
+ margin-top: 6px;
+ }
div {
.clearable-input {
@@ -116,8 +117,32 @@
margin-bottom: 7px;
margin-top: 3px;
}
-
- #advanced_search .fields.sort { float:right; }
+
+ #advanced_search {
+ .combinator {
+ margin-top: 15px;
+ }
+
+ .filters {
+ margin-top: 15px;
+ }
+
+ .fields.condition {
+ margin: 10px 0;
+ }
+
+ .fields.sort {
+ float:right;
+ }
+
+ .submit-search {
+ margin-top: 20px;
+ }
+ }
+
+ .pull-right {
+ float: none;
+ }
}
diff --git a/app/assets/stylesheets/application.css.erb b/app/assets/stylesheets/application.css.erb
index c9acccc852..2a05ee70b9 100644
--- a/app/assets/stylesheets/application.css.erb
+++ b/app/assets/stylesheets/application.css.erb
@@ -10,7 +10,6 @@
*= require jquery-ui.custom
*= require select2
*= require modalbox
- *= require facebooklist
*= require rails
*= require safari
*= require base
@@ -23,10 +22,13 @@
*= require admin/fields
*= require advanced_search
*= require jquery-timepicker/jquery.timepicker
- *= require jquery-timepicker/base
+ *= require jquery-timepicker/lib/base
*= require format_buttons
*= require jquery.mobile.custom
+ *= require font-awesome
+ *= require lists
*= require_self
+
*/
<%
diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss
index 1419f6123a..14e1f57a48 100644
--- a/app/assets/stylesheets/common.scss
+++ b/app/assets/stylesheets/common.scss
@@ -620,7 +620,7 @@ li.mobile {
font-size: 12px;
list-style: none;
padding: 3px 0px 3px 0px;
- .gravatar {
+ .gravatar {
float: left;
padding: 0px 0px 0px 0px; }
tt {
@@ -947,19 +947,6 @@ span.handle img {
.field_group .list {
padding-bottom: 30px; }
-#lists {
- .show_lists_save_form {
- text-align: right; }
- .show_lists_save_form, .save_list {
- margin: 10px 0 0; }
- .list_icon {
- opacity: 0.5;
- width: 12px; }
- img.input_info {
- vertical-align: middle; }
- input#save_list {
- margin-top: 6px; } }
-
.fields .subtitle {
cursor: move; }
@@ -1041,3 +1028,24 @@ table.asset_attributes {
padding: 10px;
background-color: lightyellow;
}
+
+.spinner {
+ margin: 7px 4px 0px 4px;
+ float: right;
+}
+
+.comment .spinner {
+ margin: 5px 4px 0px 4px;
+ float: left;
+}
+
+.comment .buttons {
+ padding-left: 40px;
+}
+
+// Jumpbox
+
+span.jumpbox-highlight {
+ background-color: lightyellow;
+ font-weight: bold;
+}
diff --git a/app/assets/stylesheets/format_buttons.css.scss b/app/assets/stylesheets/format_buttons.css.scss
index e37f7fdaf0..20c78e60d3 100644
--- a/app/assets/stylesheets/format_buttons.css.scss
+++ b/app/assets/stylesheets/format_buttons.css.scss
@@ -20,16 +20,21 @@
ul.format-buttons li {
display: inline;
- margin: 0 3px;
-
+ margin: 3px;
a {
- display: inline-block;
- width: 16px;
- height: 16px;
- opacity: 0.3;
+ color: gray;
+ i.fa {
+ font-size: 160%;
+ opacity: 0.3;
+ }
+ }
+ a.active i.fa { opacity: 1; }
+ a:hover i.fa {
+ opacity: 1;
+ }
+ a:active i.fa { opacity: 1; }
+ a:hover {
+ background:none;
+ color:gray;
}
- a.active { opacity: 1; }
- a:hover { opacity: 0.6; }
- a:active { opacity: 1; }
-
}
diff --git a/app/assets/stylesheets/header.scss b/app/assets/stylesheets/header.scss
index aca8bf640e..43efe6e588 100644
--- a/app/assets/stylesheets/header.scss
+++ b/app/assets/stylesheets/header.scss
@@ -80,6 +80,9 @@ $color_footer: grey;
padding: 0px;
text-align: center;
width: 100%;
+ i.fa {
+ font-size: 130%;
+ vertical-align:text-top; }
ul {
// :margin 0px 25%, 18% for 5th tab
margin-left: 15px; }
diff --git a/app/assets/stylesheets/lists.css.scss b/app/assets/stylesheets/lists.css.scss
index 088b180f58..355ab26d7b 100644
--- a/app/assets/stylesheets/lists.css.scss
+++ b/app/assets/stylesheets/lists.css.scss
@@ -6,3 +6,21 @@
// Place all the styles related to the Lists controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
+
+.lists {
+ i.fa { font-size: 130% }
+ a:hover { background:none; color:#0033cc }
+ .list_icon { opacity: 0.5; }
+ img.input_info { vertical-align: middle; }
+ .list_save {
+ text-align: right;
+ margin: 10px 0 0;
+ }
+ .list_form {
+ margin: 10px 0 0;
+ input[type=submit] {
+ margin-top: 10px;
+ vertical-align: baseline;
+ }
+ }
+}
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index d95521b5f4..6076e2ac58 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -35,7 +35,8 @@ def edit
# POST /groups
#----------------------------------------------------------------------------
def create
- @group.update_attributes(params[:group])
+ @group.attributes = params[:group]
+ @group.save
respond_with(@group)
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index ebc5c60939..e8c35878e4 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -5,6 +5,8 @@
#------------------------------------------------------------------------------
class ApplicationController < ActionController::Base
+ protect_from_forgery
+
before_filter :set_context
before_filter :clear_setting_cache
before_filter :check_for_mobile
@@ -23,6 +25,8 @@ class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :respond_to_not_found
rescue_from CanCan::AccessDenied, :with => :respond_to_access_denied
+ include ERB::Util # to give us h and j methods
+
# Common auto_complete handler for all core controllers.
#----------------------------------------------------------------------------
def auto_complete
@@ -39,7 +43,7 @@ def auto_complete
respond_to do |format|
format.any(:js, :html) { render :partial => 'auto_complete' }
format.json { render :json => @auto_complete.inject({}){|h,a|
- h[a.id] = a.respond_to?(:full_name) ? a.full_name : a.name; h
+ h[a.id] = a.respond_to?(:full_name) ? h(a.full_name) : h(a.name); h
}}
end
end
@@ -74,7 +78,7 @@ def prepare_for_mobile
#
# Takes { :related => 'campaigns/7' } or { :related => '5' }
# and returns array of object ids that should be excluded from search
- # assumes controller_name is an method on 'related' class that returns a collection
+ # assumes controller_name is a method on 'related' class that returns a collection
#----------------------------------------------------------------------------
def auto_complete_ids_to_exclude(related)
return [] if related.blank?
@@ -142,7 +146,7 @@ def require_user
flash[:notice] = t(:msg_login_needed) if request.fullpath != "/"
respond_to do |format|
format.html { redirect_to login_url }
- format.js { render(:index) { |page| page.redirect_to login_url } }
+ format.js { render :text => "window.location = '#{login_url}';" }
end
end
end
@@ -169,7 +173,7 @@ def redirect_back_or_default(default)
#----------------------------------------------------------------------------
def can_signup?
- [ :allowed, :needs_approval ].include? Setting.user_signup
+ User.can_signup?
end
#----------------------------------------------------------------------------
@@ -223,10 +227,10 @@ def respond_to_not_found(*types)
flash[:warning] = t(:msg_asset_not_available, asset)
respond_to do |format|
- format.html { redirect_to :action => :index }
- format.js { render(:update) { |page| page.reload } }
- format.json { render :text => flash[:warning], :status => :not_found }
- format.xml { render :text => flash[:warning], :status => :not_found }
+ format.html { redirect_to(redirection_url) }
+ format.js { render :text => 'window.location.reload();' }
+ format.json { render :text => flash[:warning], :status => :not_found }
+ format.xml { render :xml => [flash[:warning]], :status => :not_found }
end
end
@@ -237,32 +241,32 @@ def respond_to_related_not_found(related, *types)
url = send("#{related.pluralize}_path")
respond_to do |format|
- format.html { redirect_to url }
- format.js { render(:update) { |page| page.redirect_to url } }
- format.json { render :text => flash[:warning], :status => :not_found }
- format.xml { render :text => flash[:warning], :status => :not_found }
+ format.html { redirect_to(url) }
+ format.js { render :text => %Q{window.location.href = "#{url}";} }
+ format.json { render :text => flash[:warning], :status => :not_found }
+ format.xml { render :xml => [flash[:warning]], :status => :not_found }
end
end
#----------------------------------------------------------------------------
def respond_to_access_denied
- if self.action_name == "show"
- flash[:warning] = t(:msg_asset_not_authorized, asset)
-
- else
- flick = case self.action_name
- when "destroy" then "delete"
- when "promote" then "convert"
- else self.action_name
- end
- flash[:warning] = t(:msg_cant_do, :action => flick, :asset => asset)
+ flash[:warning] = t(:msg_not_authorized, default: 'You are not authorized to take this action.')
+ respond_to do |format|
+ format.html { redirect_to(redirection_url) }
+ format.js { render :text => 'window.location.reload();' }
+ format.json { render :text => flash[:warning], :status => :unauthorized }
+ format.xml { render :xml => [flash[:warning]], :status => :unauthorized }
end
+ end
- respond_to do |format|
- format.html { redirect_to :action => :index }
- format.js { render(:update) { |page| page.reload } }
- format.json { render :text => flash[:warning], :status => :unauthorized }
- format.xml { render :text => flash[:warning], :status => :unauthorized }
+ #----------------------------------------------------------------------------
+ def redirection_url
+ # Try to redirect somewhere sensible. Note: not all controllers have an index action
+ url = if current_user.present?
+ (respond_to?(:index) and self.action_name != 'index') ? { action: 'index' } : root_url
+ else
+ login_url
end
end
+
end
diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index 06781defe4..5f444a88d8 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -6,8 +6,6 @@
class CommentsController < ApplicationController
before_filter :require_user
-
-
# GET /comments
# GET /comments.json
# GET /comments.xml
@@ -31,24 +29,6 @@ def index
end
end
- # GET /comments/new
- # GET /comments/new.json
- # GET /comments/new.xml AJAX
- #----------------------------------------------------------------------------
- def new
- @comment = Comment.new
- @commentable = extract_commentable_name(params)
-
- if @commentable
- update_commentable_session
- unless @commentable.classify.constantize.my.find_by_id(params[:"#{@commentable}_id"])
- respond_to_related_not_found(@commentable) and return
- end
- end
-
- respond_with(@comment)
- end
-
# GET /comments/1/edit AJAX
#----------------------------------------------------------------------------
def edit
@@ -73,10 +53,10 @@ def create
model, id = @comment.commentable_type, @comment.commentable_id
unless model.constantize.my.find_by_id(id)
respond_to_related_not_found(model.downcase)
+ else
+ @comment.save
+ respond_with(@comment)
end
-
- @comment.save
- respond_with(@comment)
end
# PUT /comments/1
@@ -106,12 +86,4 @@ def extract_commentable_name(params)
params.keys.detect {|x| x =~ /_id$/ }.try(:sub, /_id$/, '')
end
- #----------------------------------------------------------------------------
- def update_commentable_session
- if params[:cancel].true?
- session.delete("#{@commentable}_new_comment")
- else
- session["#{@commentable}_new_comment"] = true
- end
- end
end
diff --git a/app/controllers/emails_controller.rb b/app/controllers/emails_controller.rb
index 9a791544b3..de7cca98e2 100644
--- a/app/controllers/emails_controller.rb
+++ b/app/controllers/emails_controller.rb
@@ -6,35 +6,6 @@
class EmailsController < ApplicationController
before_filter :require_user
- # GET /email
- # GET /email.xml not implemented
- #----------------------------------------------------------------------------
- # def index
- # end
-
- # GET /email/1
- # GET /email/1.xml not implemented
- #----------------------------------------------------------------------------
- # def show
- # end
-
- # GET /emails/new
- # GET /emails/new.xml not implemented
- #----------------------------------------------------------------------------
- # def new
- # end
-
- # GET /emails/1/edit not implemented
- #----------------------------------------------------------------------------
- # def edit
- # end
-
- # PUT /emails/1
- # PUT /emails/1.xml not implemented
- #----------------------------------------------------------------------------
- # def update
- # end
-
# DELETE /emails/1
# DELETE /emails/1.json
# DELETE /emails/1.xml AJAX
@@ -42,7 +13,7 @@ class EmailsController < ApplicationController
def destroy
@email = Email.find(params[:id])
@email.destroy
-
respond_with(@email)
end
+
end
diff --git a/app/controllers/entities/accounts_controller.rb b/app/controllers/entities/accounts_controller.rb
index e7bd235bb4..7cd78eb43b 100644
--- a/app/controllers/entities/accounts_controller.rb
+++ b/app/controllers/entities/accounts_controller.rb
@@ -141,7 +141,7 @@ def destroy
#----------------------------------------------------------------------------
# Handled by ApplicationController :auto_complete
- # POST /accounts/redraw AJAX
+ # GET /accounts/redraw AJAX
#----------------------------------------------------------------------------
def redraw
current_user.pref[:accounts_per_page] = params[:per_page] if params[:per_page]
diff --git a/app/controllers/entities/campaigns_controller.rb b/app/controllers/entities/campaigns_controller.rb
index afe6d8e42a..a9ed3a2d83 100644
--- a/app/controllers/entities/campaigns_controller.rb
+++ b/app/controllers/entities/campaigns_controller.rb
@@ -136,7 +136,7 @@ def destroy
#----------------------------------------------------------------------------
# Handled by ApplicationController :auto_complete
- # POST /campaigns/redraw AJAX
+ # GET /campaigns/redraw AJAX
#----------------------------------------------------------------------------
def redraw
current_user.pref[:campaigns_per_page] = params[:per_page] if params[:per_page]
diff --git a/app/controllers/entities/contact_groups_controller.rb b/app/controllers/entities/contact_groups_controller.rb
index bd662f394b..a4f1ae3752 100644
--- a/app/controllers/entities/contact_groups_controller.rb
+++ b/app/controllers/entities/contact_groups_controller.rb
@@ -210,13 +210,30 @@ def redraw_show
# POST /accounts/filter AJAX
#----------------------------------------------------------------------------
def filter
- session[:contact_groups_filter] = params[:category]
- @contact_groups = get_contact_groups(:page => 1)
- render :index
+ update_session do |filters|
+ if params[:checked].true?
+ filters << params[:category]
+ else
+ filters.delete(params[:category])
+ end
+ end
+
+ respond_with(@contact_groups = get_contact_groups(:page => 1, :per_page => params[:per_page])) do |format|
+ format.js { render :index }
+ end
end
private
+ # Yields array of current filters and updates the session using new values.
+ #----------------------------------------------------------------------------
+ def update_session
+ name = "contact_groups_filter"
+ filters = (session[name].nil? ? [] : session[name].split(","))
+ yield filters
+ session[name] = filters.uniq.join(",")
+ end
+
#----------------------------------------------------------------------------
alias :get_contact_groups :get_list_of_records
diff --git a/app/controllers/entities/contacts_controller.rb b/app/controllers/entities/contacts_controller.rb
index 8cc5927045..7b5e9708c4 100644
--- a/app/controllers/entities/contacts_controller.rb
+++ b/app/controllers/entities/contacts_controller.rb
@@ -208,7 +208,7 @@ def create
unless params[:account][:id].blank?
@account = Account.find(params[:account][:id])
else
- if request.referer =~ /\/accounts\/(.+)$/
+ if request.referer =~ /\/accounts\/(\d+)\z/
@account = Account.find($1) # related account
else
@account = Account.new(:user => current_user)
@@ -302,7 +302,7 @@ def attendances
#----------------------------------------------------------------------------
# Handled by ApplicationController :auto_complete
- # POST /contacts/redraw AJAX
+ # GET /contacts/redraw AJAX
#----------------------------------------------------------------------------
def redraw
current_user.pref[:contacts_per_page] = params[:per_page] if params[:per_page]
@@ -330,8 +330,29 @@ def redraw
# POST /contacts/filter AJAX
#----------------------------------------------------------------------------
def filter
- session[:contacts_filter] = params[:folder] if params[:folder].present?
- session[:contacts_user_filter] = params[:user] if params[:user].present?
+ if params[:folders].present?
+ session[:contacts_filter] = params[:folders].join(",")
+ else
+ update_session(:contacts_filter) do |filters|
+ if params[:checked].true?
+ filters << params[:folder]
+ else
+ filters.delete(params[:folder])
+ end
+ end
+ end
+
+ if params[:users].present?
+ session[:contacts_user_filter] = params[:users].join(",")
+ else
+ update_session(:contacts_user_filter) do |filters|
+ if params[:checked].true?
+ filters << params[:user]
+ else
+ filters.delete(params[:user])
+ end
+ end
+ end
respond_with(@contacts = get_contacts(:page => 1, :per_page => params[:per_page])) do |format|
format.js { render :index }
@@ -344,6 +365,16 @@ def options
end
private
+
+ # Yields array of current filters and updates the session using new values.
+ #----------------------------------------------------------------------------
+ def update_session(name)
+ #name = "contacts_filter"
+ filters = (session[name].nil? ? [] : session[name].split(","))
+ yield filters
+ session[name] = filters.uniq.join(",")
+ end
+
#----------------------------------------------------------------------------
alias :get_contacts :get_list_of_records
diff --git a/app/controllers/entities/event_instances_controller.rb b/app/controllers/entities/event_instances_controller.rb
index 7d19b1b52b..c6aa4ce3d0 100644
--- a/app/controllers/entities/event_instances_controller.rb
+++ b/app/controllers/entities/event_instances_controller.rb
@@ -125,9 +125,8 @@ def report_attendance
# PUT /tasks/1/complete
#----------------------------------------------------------------------------
def mark
- #debugger
@contact = Contact.find(params[:contact_id])
- #@event_instance = EventInstance.find(event_instance)
+ #@event_instance = EventInstance.find(param[:id])
#check if already marked
if @event_instance.attendances.where(:contact_id => @contact.id).empty?
previously_deleted_versions = Version.destroys.where(
@@ -153,16 +152,14 @@ def mark
@event_instance.attendances << @attendance
end
end
- #@attendance.save
+
@event_instance.event.touch
- #update_sidebar unless params[:bucket].blank?
- respond_with(@contact)
+
end
# PUT /tasks/1/complete
#----------------------------------------------------------------------------
def unmark
- #debugger
@contact = Contact.find(params[:contact_id])
#@event_instance = EventInstance.find(event_instance)
@attendances = @event_instance.attendances.where(:contact_id => @contact.id)
@@ -171,10 +168,9 @@ def unmark
@attendances.each do |a|
@event_instance.attendances.delete(a)
end
- #@attendance.save
+
@event_instance.event.touch
- #update_sidebar unless params[:bucket].blank?
- respond_with(@contact)
+
end
# PUT /accounts/1/attach
diff --git a/app/controllers/entities/events_controller.rb b/app/controllers/entities/events_controller.rb
index 95c2ddf438..f18982420c 100644
--- a/app/controllers/entities/events_controller.rb
+++ b/app/controllers/entities/events_controller.rb
@@ -288,9 +288,17 @@ def redraw_show
# POST /accounts/filter AJAX
#----------------------------------------------------------------------------
def filter
- session[:events_filter] = params[:category]
- @events = get_events(:page => 1)
- render :index
+ update_session do |filters|
+ if params[:checked].true?
+ filters << params[:category]
+ else
+ filters.delete(params[:category])
+ end
+ end
+
+ respond_with(@events = get_events(:page => 1, :per_page => params[:per_page])) do |format|
+ format.js { render :index }
+ end
end
def toggle_comments
@@ -299,6 +307,15 @@ def toggle_comments
private
+ # Yields array of current filters and updates the session using new values.
+ #----------------------------------------------------------------------------
+ def update_session
+ name = "events_filter"
+ filters = (session[name].nil? ? [] : session[name].split(","))
+ yield filters
+ session[name] = filters.uniq.join(",")
+ end
+
def create_event_instances(list_of_dates, start_week)
event_instances_list = []
public_holidays = Setting.academic_dates[:public_holidays].split(",")
diff --git a/app/controllers/entities/leads_controller.rb b/app/controllers/entities/leads_controller.rb
index acb0d2b413..a8e6d3cd3c 100644
--- a/app/controllers/entities/leads_controller.rb
+++ b/app/controllers/entities/leads_controller.rb
@@ -157,7 +157,7 @@ def reject
# Handled by ApplicationController :auto_complete
- # POST /leads/redraw AJAX
+ # GET /leads/redraw AJAX
#----------------------------------------------------------------------------
def redraw
current_user.pref[:leads_per_page] = params[:per_page] if params[:per_page]
diff --git a/app/controllers/entities/mandrill_emails_controller.rb b/app/controllers/entities/mandrill_emails_controller.rb
index 94f410b6a7..595524ad7b 100644
--- a/app/controllers/entities/mandrill_emails_controller.rb
+++ b/app/controllers/entities/mandrill_emails_controller.rb
@@ -166,14 +166,30 @@ def redraw
# POST /accounts/filter AJAX
#----------------------------------------------------------------------------
- def filter
- session[:mandrill_emails_filter] = params[:category]
+ def filter
+ update_session do |filters|
+ if params[:checked].true?
+ filters << params[:category]
+ else
+ filters.delete(params[:category])
+ end
+ end
+
@mandrill_emails = get_mandrill_emails(:page => 1)
- render :index
+ #render :index
end
private
+ # Yields array of current filters and updates the session using new values.
+ #----------------------------------------------------------------------------
+ def update_session
+ name = "mandrill_emails_filter"
+ filters = (session[name].nil? ? [] : session[name].split(","))
+ yield filters
+ session[name] = filters.uniq.join(",")
+ end
+
#----------------------------------------------------------------------------
alias :get_mandrill_emails :get_list_of_records
diff --git a/app/controllers/entities/opportunities_controller.rb b/app/controllers/entities/opportunities_controller.rb
index 94c11f4ebd..b2bd5bcb4c 100644
--- a/app/controllers/entities/opportunities_controller.rb
+++ b/app/controllers/entities/opportunities_controller.rb
@@ -39,7 +39,8 @@ def new
model, id = params[:related].split('_')
if related = model.classify.constantize.my.find_by_id(id)
instance_variable_set("@#{model}", related)
- @account = related.account if related.respond_to?(:account)
+ @account = related.account if related.respond_to?(:account) && !related.account.nil?
+ @campaign = related.campaign if related.respond_to?(:campaign)
else
respond_to_related_not_found(model) and return
end
@@ -81,7 +82,7 @@ def create
unless params[:account][:id].blank?
@account = Account.find(params[:account][:id])
else
- if request.referer =~ /\/accounts\/(.+)$/
+ if request.referer =~ /\/accounts\/(\d+)\z/
@account = Account.find($1) # related account
else
@account = Account.new(:user => current_user)
@@ -144,7 +145,7 @@ def destroy
#----------------------------------------------------------------------------
# Handled by ApplicationController :auto_complete
- # POST /opportunities/redraw AJAX
+ # GET /opportunities/redraw AJAX
#----------------------------------------------------------------------------
def redraw
@opportunities = get_opportunities(:page => 1, :per_page => params[:per_page])
diff --git a/app/controllers/entities_controller.rb b/app/controllers/entities_controller.rb
index f25cab6c60..b0b069acd9 100755
--- a/app/controllers/entities_controller.rb
+++ b/app/controllers/entities_controller.rb
@@ -115,7 +115,6 @@ def entities
def set_options
unless params[:cancel].true?
klass = controller_name.classify.constantize
- action = params['action']
@per_page = current_user.pref[:"#{controller_name}_per_page"] || klass.per_page
@sort_by = current_user.pref[:"#{controller_name}_sort_by"] || klass.sort_by
end
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 77dc05c8b4..55854ca9f0 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -6,14 +6,11 @@
class HomeController < ApplicationController
before_filter :require_user, :except => [ :toggle, :timezone ]
before_filter :set_current_tab, :only => :index
- before_filter "hook(:home_before_filter, self, :amazing => true)"
before_filter :check_for_mobile
+
#----------------------------------------------------------------------------
def index
- @hello = "Hello world" # The hook below can access controller's instance variables.
- hook(:home_controller, self, :params => "it works!")
-
@activities = get_activities
@my_tasks = Task.visible_on_dashboard(current_user).by_due_at
@open_tasks = Task.dashboard_open(current_user).by_due_at
@@ -34,15 +31,18 @@ def options
end
end
- # POST /home/redraw AJAX
+ # GET /home/redraw AJAX
#----------------------------------------------------------------------------
def redraw
current_user.pref[:activity_asset] = params[:asset] if params[:asset]
current_user.pref[:activity_event] = params[:event] if params[:event]
current_user.pref[:activity_user] = params[:user] if params[:user]
current_user.pref[:activity_duration] = params[:duration] if params[:duration]
+ @activities = get_activities
- render :index
+ respond_with(@activities) do |format|
+ format.js { render :index }
+ end
end
# GET /home/toggle AJAX
@@ -59,14 +59,19 @@ def toggle
# GET /home/timeline AJAX
#----------------------------------------------------------------------------
def timeline
- unless params[:type].empty?
- model = params[:type].camelize.constantize
- item = model.find(params[:id])
- item.update_attribute(:state, params[:state])
- else
- comments, emails = params[:id].split("+")
- Comment.update_all("state = '#{params[:state]}'", "id IN (#{comments})") unless comments.blank?
- Email.update_all("state = '#{params[:state]}'", "id IN (#{emails})") unless emails.blank?
+ state = params[:state].to_s
+ if %w(Collapsed Expanded).include?(state)
+ if (model_type = params[:type].to_s).present?
+ if %w(comment email).include?(model_type)
+ model = model_type.camelize.constantize
+ item = model.find(params[:id])
+ item.update_attribute(:state, state)
+ end
+ else
+ comments, emails = params[:id].split("+")
+ Comment.where(:id => comments.split(',')).update_all(:state => state) unless comments.blank?
+ Email.where(:id => emails.split(',')).update_all(:state => state) unless emails.blank?
+ end
end
render :nothing => true
@@ -119,6 +124,9 @@ def activity_event
end
#----------------------------------------------------------------------------
+ # TODO: this is ugly, ugly code. It's being security patched now but urgently
+ # needs refactoring to use user id instead. Permuations based on name or email
+ # yield incorrect results.
def activity_user
user = current_user.pref[:activity_user]
if user && user != "all_users"
@@ -127,12 +135,11 @@ def activity_user
else # first_name middle_name last_name any_name
name_query = if user.include?(" ")
user.name_permutations.map{ |first, last|
- "(upper(first_name) LIKE upper('%#{first}%') AND upper(last_name) LIKE upper('%#{last}%'))"
- }.join(" OR ")
+ User.where(:first_name => first, :last_name => last)
+ }.map(&:to_a).flatten.first
else
- "upper(first_name) LIKE upper('%#{user}%') OR upper(last_name) LIKE upper('%#{user}%')"
+ [User.where(:first_name => user), User.where(:last_name => user)].map(&:to_a).flatten.first
end
- User.where(name_query).first
end
end
user.is_a?(User) ? user.id : nil
@@ -143,7 +150,7 @@ def activity_duration
duration = current_user.pref[:activity_duration]
if duration
words = duration.split("_") # "two_weeks" => 2.weeks
- if %w(one two).include?(words.first)
+ if %w(one two).include?(words.first) and %w(hour day days week weeks month).include?(words.last)
%w(zero one two).index(words.first).send(words.last)
end
end
diff --git a/app/controllers/lists_controller.rb b/app/controllers/lists_controller.rb
index c820c511c8..2212ebcd91 100644
--- a/app/controllers/lists_controller.rb
+++ b/app/controllers/lists_controller.rb
@@ -8,8 +8,15 @@ class ListsController < ApplicationController
# POST /lists
#----------------------------------------------------------------------------
def create
+
+ if params[:is_global].to_i.zero?
+ params[:list][:user_id] = current_user.id
+ else
+ params[:list][:user_id] = nil
+ end
+
# Find any existing list with the same name (case insensitive)
- if @list = List.find(:first, :conditions => ["lower(name) = ?", params[:list][:name].downcase])
+ if @list = List.where("lower(name) = ?", params[:list][:name].downcase).where({:user_id => params[:list][:user_id]}).first
@list.update_attributes(params[:list])
else
@list = List.create(params[:list])
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index 0d37c390f1..25510ca3de 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -44,8 +44,9 @@ def update
end
end
- #----------------------------------------------------------------------------
private
+
+ #----------------------------------------------------------------------------
def load_user_using_perishable_token
@user = User.find_using_perishable_token(params[:id])
unless @user
@@ -60,7 +61,6 @@ def load_user_using_perishable_token
#----------------------------------------------------------------------------
def empty_password?
(params[:user][:password] == params[:user][:password_confirmation]) &&
- (params[:user][:password] =~ /^\s*$/)
+ (params[:user][:password].blank?) # " ".blank? == true
end
end
-
diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb
index 26afb2a786..88bbcb535b 100644
--- a/app/controllers/tasks_controller.rb
+++ b/app/controllers/tasks_controller.rb
@@ -11,7 +11,7 @@ class TasksController < ApplicationController
# GET /tasks
#----------------------------------------------------------------------------
def index
- @view = params[:view] || "pending"
+ @view = view
@tasks = Task.find_all_grouped(current_user, @view)
respond_with @tasks do |format|
@@ -25,14 +25,13 @@ def index
#----------------------------------------------------------------------------
def show
@task = Task.tracked_by(current_user).find(params[:id])
-
respond_with(@task)
end
# GET /tasks/new
#----------------------------------------------------------------------------
def new
- @view = params[:view] || "pending"
+ @view = view
@task = Task.new
@bucket = Setting.unroll(:task_bucket)[1..-1] << [ t(:due_specific_date, :default => 'On Specific Date...'), :specific_time ]
@category = Setting.unroll(:task_category)
@@ -52,7 +51,7 @@ def new
# GET /tasks/1/edit AJAX
#----------------------------------------------------------------------------
def edit
- @view = params[:view] || "pending"
+ @view = view
@task = Task.tracked_by(current_user).find(params[:id])
@bucket = Setting.unroll(:task_bucket)[1..-1] << [ t(:due_specific_date, :default => 'On Specific Date...'), :specific_time ]
@category = Setting.unroll(:task_category)
@@ -68,7 +67,7 @@ def edit
# POST /tasks
#----------------------------------------------------------------------------
def create
- @view = params[:view] || "pending"
+ @view = view
@task = Task.new(params[:task]) # NOTE: we don't display validation messages for tasks.
respond_with(@task) do |format|
@@ -81,7 +80,7 @@ def create
# PUT /tasks/1
#----------------------------------------------------------------------------
def update
- @view = params[:view] || "pending"
+ @view = view
@task = Task.tracked_by(current_user).find(params[:id])
@task_before_update = @task.dup
@@ -107,7 +106,7 @@ def update
# DELETE /tasks/1
#----------------------------------------------------------------------------
def destroy
- @view = params[:view] || "pending"
+ @view = view
@task = Task.tracked_by(current_user).find(params[:id])
@task.destroy
@@ -142,7 +141,7 @@ def complete
# Ajax request to filter out a list of tasks. AJAX
#----------------------------------------------------------------------------
def filter
- @view = params[:view] || "pending"
+ @view = view
update_session do |filters|
if params[:checked].true?
@@ -167,8 +166,7 @@ def update_session
# Collect data necessary to render filters sidebar.
#----------------------------------------------------------------------------
def update_sidebar
- @view = params[:view]
- @view = "pending" unless %w(pending assigned completed).include?(@view)
+ @view = view
@task_total = Task.totals(current_user, @view)
# Update filters session if we added, deleted, or completed a task.
@@ -189,4 +187,13 @@ def update_sidebar
session[name] = filters unless filters.blank?
end
end
+
+ # Ensure view is allowed
+ #----------------------------------------------------------------------------
+ def view
+ view = params[:view]
+ views = Task::ALLOWED_VIEWS
+ views.include?(view) ? view : views.first
+ end
+
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index f12ff92ff9..9a5e52f1ba 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -5,44 +5,30 @@
#------------------------------------------------------------------------------
class UsersController < ApplicationController
- before_filter :require_no_user, :only => [ :new, :create ]
- before_filter :require_user, :only => [ :show, :redraw ]
before_filter :set_current_tab, :only => [ :show, :opportunities_overview ] # Don't hightlight any tabs.
- before_filter :require_and_assign_user, :except => [ :new, :create, :show, :avatar, :upload_avatar ]
- before_filter :assign_given_or_current_user, :only => [ :show, :avatar, :upload_avatar, :edit, :update ]
- load_resource
+ check_authorization
+ load_and_authorize_resource # handles all security
respond_to :html, :only => [ :show, :new ]
# GET /users/1
- # GET /users/1.json
- # GET /users/1.xml HTML
+ # GET /users/1.js
#----------------------------------------------------------------------------
def show
+ @user = current_user if params[:id].nil?
respond_with(@user)
end
# GET /users/new
- # GET /users/new.json
- # GET /users/new.xml HTML
+ # GET /users/new.js
#----------------------------------------------------------------------------
def new
- if can_signup?
- respond_with(@user)
- else
- redirect_to login_path
- end
- end
-
- # GET /users/1/edit AJAX
- #----------------------------------------------------------------------------
- def edit
respond_with(@user)
end
# POST /users
- # POST /users.xml HTML
+ # POST /users.js
#----------------------------------------------------------------------------
def create
if @user.save
@@ -58,16 +44,13 @@ def create
end
end
- # PUT /users/1
- # PUT /users/1.json
- # PUT /users/1.xml AJAX
+ # GET /users/1/edit.js
#----------------------------------------------------------------------------
- def update
- @user.update_attributes(params[:user])
+ def edit
respond_with(@user)
end
- def assign_contact
+ def move_contact
@contact = Contact.find(params[:contact_id])
@contact.assigned_to = params[:id] # confusing, but it's as good as I could figure out with the dropable helper
@contact.save
@@ -94,22 +77,23 @@ def assign_contact
@user_total[:all] = organized + @user_total[:other]
end
- # DELETE /users/1
- # DELETE /users/1.xml HTML and AJAX (not directly exposed yet)
+ # PUT /users/1
+ # PUT /users/1.js
#----------------------------------------------------------------------------
- def destroy
- # not exposed
+ def update
+ @user.update_attributes(params[:user])
+ respond_with(@user)
end
# GET /users/1/avatar
- # GET /users/1/avatar.xml AJAX
+ # GET /users/1/avatar.js
#----------------------------------------------------------------------------
def avatar
respond_with(@user)
end
# PUT /users/1/upload_avatar
- # PUT /users/1/upload_avatar.xml AJAX
+ # PUT /users/1/upload_avatar.js
#----------------------------------------------------------------------------
def upload_avatar
if params[:gravatar]
@@ -133,19 +117,21 @@ def upload_avatar
end
# GET /users/1/password
- # GET /users/1/password.xml AJAX
+ # GET /users/1/password.js
#----------------------------------------------------------------------------
def password
respond_with(@user)
end
# PUT /users/1/change_password
- # PUT /users/1/change_password.xml AJAX
+ # PUT /users/1/change_password.js
#----------------------------------------------------------------------------
def change_password
if @user.valid_password?(params[:current_password], true) || @user.password_hash.blank?
unless params[:user][:password].blank?
- @user.update_attributes(params[:user])
+ @user.password = params[:user][:password]
+ @user.password_confirmation = params[:user][:password_confirmation]
+ @user.save
flash[:notice] = t(:msg_password_changed)
else
flash[:notice] = t(:msg_password_not_changed)
@@ -157,27 +143,18 @@ def change_password
respond_with(@user)
end
- # POST /users/1/redraw AJAX
+ # GET /users/1/redraw
#----------------------------------------------------------------------------
def redraw
current_user.preference[:locale] = params[:locale]
- render(:update) { |page| page.redirect_to user_path(current_user) }
+ render :text => %Q{window.location.href = "#{user_path(current_user)}";}
end
+ # GET /users/opportunities_overview
+ #----------------------------------------------------------------------------
def opportunities_overview
@users_with_opportunities = User.have_assigned_opportunities.order(:first_name)
@unassigned_opportunities = Opportunity.unassigned.pipeline.order(:stage)
end
- private
-
- #----------------------------------------------------------------------------
- def require_and_assign_user
- require_user
- @user = current_user
- end
-
- def assign_given_or_current_user
- @user = params[:id] ? User.find(params[:id]) : current_user
- end
end
diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb
index a7bf358991..87b913c43c 100644
--- a/app/helpers/accounts_helper.rb
+++ b/app/helpers/accounts_helper.rb
@@ -22,14 +22,17 @@ def account_summary(account)
].join(', ')
end
+ # Generates a select list with the first 25 accounts
+ # and prepends the currently selected account, if any.
+ #----------------------------------------------------------------------------
def account_select(options = {})
- # Generates a select list with the first 25 accounts,
- # and prepends the currently selected account, if available
options[:selected] = (@account && @account.id) || 0
accounts = ([@account] + Account.my.order(:name).limit(25)).compact.uniq
collection_select :account, :id, accounts, :id, :name, options,
{:"data-placeholder" => t(:select_an_account),
- :style => "width:#{mobile_device? ? "245" : "324"}px; display:none;", :onchange => set_campus }
+ :"data-url" => auto_complete_accounts_path(format: 'json'),
+ :style => "width:#{mobile_device? ? "245" : "324"}px; display:none;",
+ :class => 'ajax_chosen' }
end
def set_campus
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 3c70a7f510..0bd8be328d 100755
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -54,7 +54,7 @@ def section(related, assets, no_select=false, views=false, sort_by_model=Contact
asset_count = related.try(assets).count
if (views && related.present?)
- sort_by_menu_items = sort_by_model.sort_by_fields.map { |field| options_menu_item(:sort_by, field, url_for(:controller => related.class.name.tableize.to_sym, :action => :redraw_show, :id => related.id, :remote => true), false) }
+ sort_by_menu_items = sort_by_model.sort_by_fields.map { |field| options_menu_item(:sort_by, field, url_for(:controller => related.class.name.tableize.to_sym, :action => :redraw_show, :id => related.id, :remote => true)) }
sort_by = current_user.pref[:"#{sort_by_model.name.tableize}_sort_by"] || sort_by_model.sort_by
current_sort_by = t("option_" + sort_by_model.sort_by_map.invert[sort_by])
end
@@ -66,10 +66,9 @@ def section(related, assets, no_select=false, views=false, sort_by_model=Contact
html << content_tag(:div, " | ".html_safe, :class => "subtitle_tools") if (views && related.present? && !no_create)
html << javascript_tag(
"new crm.Menu({
- trigger : \"sort_by\",
- fade : 0.5,
- appear : 0.5,
- align : \"left\",
+ trigger : \"\#sort_by\",
+ fade : 500,
+ appear : 500,
menu_items: [ #{sort_by_menu_items.join(",")} ]
});"
) if (views && related.present?)
@@ -84,7 +83,7 @@ def section(related, assets, no_select=false, views=false, sort_by_model=Contact
def load_select_popups_for(related, *assets)
js = generate_js_for_popups(related, *assets)
content_for(:javascript_epilogue) do
- raw "document.observe('dom:loaded', function() { #{js} });"
+ raw "$(function() { #{js} });"
end
end
@@ -113,7 +112,7 @@ def link_to_inline(id, url, options = {})
link_to(text,
url + "#{url.include?('?') ? '&' : '?'}cancel=false" + related + event_instance,
:remote => true,
- :onclick => "this.href = this.href.replace(/cancel=(true|false)/,'cancel='+ Element.visible('#{id}'));",
+ :onclick => "this.href = this.href.replace(/cancel=(true|false)/,'cancel='+ ($('##{id}').css('display') != 'none'));",
:class => options[:class]
)
end
@@ -133,7 +132,7 @@ def link_to_edit(record, options = {})
link_to(edit_text,
options[:url] || polymorphic_url(record, :action => :edit),
:remote => true,
- :onclick => "this.href = this.href.split('?')[0] + '?previous='+crm.find_form('edit_#{name}');".html_safe
+ :onclick => "this.href = this.href.split('?')[0] + '?previous='+crm.find_form('edit_#{name}') + '#{related}';".html_safe
)
end
@@ -203,7 +202,7 @@ def jumpbox(current)
tabs = [ :contacts, :accounts, :contact_groups, :events ]
current = tabs.first unless tabs.include?(current)
tabs.map do |tab|
- link_to_function(t("tab_#{tab}"), "crm.jumper('#{tab}')", :class => (tab == current ? 'selected' : ''))
+ link_to_function(t("tab_#{tab}"), "crm.jumper('#{tab}')", "html-data" => tab, :class => (tab == current ? 'selected' : ''))
end.join(" | ").html_safe
end
@@ -221,7 +220,7 @@ def visible; { :style => "visibility:visible;" }; end
#----------------------------------------------------------------------------
def one_submit_only(form='')
- { :onsubmit => "jQuery('#'+this.id+' input[type=\\'submit\\']').disable()".html_safe }
+ { :onsubmit => "$('#'+this.id+' input[type=submit]').prop('disabled', true)".html_safe }
end
#----------------------------------------------------------------------------
@@ -243,9 +242,9 @@ def invisible_if(you_ask)
def confirm_delete(model, params = {})
question = %(#{t(:confirm_delete, model.class.to_s.downcase)} ).html_safe
yes = link_to(t(:yes_button), params[:url] || model, :method => :delete)
- no = link_to_function(t(:no_button), "jQuery('#menu').html(jQuery('#confirm').html());")
- text = "jQuery('#confirm').html( jQuery('#menu').html() );\n"
- text << "jQuery('#menu').html('#{question} #{yes} : #{no}');"
+ no = link_to_function(t(:no_button), "$('#menu').html($('#confirm').html());")
+ text = "$('#confirm').html( $('#menu').html() );\n"
+ text << "$('#menu').html('#{question} #{yes} : #{no}');"
text.html_safe
end
@@ -264,8 +263,8 @@ def refresh_sidebar(action = nil, shake = nil)
#----------------------------------------------------------------------------
def refresh_sidebar_for(view, action = nil, shake = nil)
text = ""
- text << "jQuery('#sidebar').html('#{ j render(:partial => "layouts/sidebar", :locals => { :view => view, :action => action }) }');"
- text << "jQuery('##{j shake.to_s}').effect('shake', { duration:200, distance: 3 });" if shake
+ text << "$('#sidebar').html('#{ j render(:partial => "layouts/sidebar", :locals => { :view => view, :action => action }) }');"
+ text << "$('##{j shake.to_s}').effect('shake', { duration:200, distance: 3 });" if shake
text.html_safe
end
@@ -287,42 +286,41 @@ def web_presence_icons(person)
# Ajax helper to refresh current index page once the user selects an option.
#----------------------------------------------------------------------------
- def redraw(option, value, url = nil)
+ def redraw(option, value, url = send("redraw_#{controller.controller_name}_path"))
if value.is_a?(Array)
param, value = value.first, value.last
end
- remote_function(
- :url => url || send("redraw_#{controller.controller_name}_path"),
- :with => "'#{option}=#{param || value}'",
- :condition => "$('#{option}').innerHTML != '#{value}'",
- :loading => "$('#{option}').update('#{value}'); $('loading').show()",
- :complete => "$('loading').hide()"
- )
+ %Q{
+ if ($('##{option}').html() != '#{value}') {
+ $('##{option}').html('#{value}');
+ $('#loading').show();
+ $.post('#{url}', {#{option}: '#{param || value}'}, function () {
+ $('#loading').hide();
+ });
+ }
+ }
end
#----------------------------------------------------------------------------
- def options_menu_item(option, key, url = nil, query=true)
- name = t("option_#{key.include?(".") ? key.split(".")[1] : key}")
- with = query ? "'#{option}=#{key}&query=' + $(\"query\").value" : "'#{option}=#{key}'"
-
+ def options_menu_item(option, key, url = send("redraw_#{controller.controller_name}_path"))
+ name = t("option_#{key}")
"{ name: \"#{name.titleize}\", on_select: function() {" +
- remote_function(
- :url => url || send("redraw_#{controller.controller_name}_path"),
- :with => with,
- :condition => "$('#{option}').innerHTML != '#{name}'",
- :loading => "$('#{option}').update('#{name}'); $('loading').show()",
- :complete => "$('loading').hide()"
- ) + "}}"
+ %Q{
+ if ($('##{option}').html() != '#{name}') {
+ $('##{option}').html('#{name}');
+ $('#loading').show();
+ $.get('#{url}', {#{option}: '#{key}', query: $('#query').val()}, function () {
+ $('#loading').hide();
+ });
+ }
+ } + "}}"
end
# Ajax helper to pass browser timezone offset to the server.
#----------------------------------------------------------------------------
def get_browser_timezone_offset
unless session[:timezone_offset]
- remote_function(
- :url => timezone_path,
- :with => "'offset='+(new Date()).getTimezoneOffset()"
- )
+ "$.get('#{timezone_path}', {offset: (new Date()).getTimezoneOffset()});"
end
end
@@ -334,7 +332,6 @@ def avatar_for(model, args = {})
args = { :class => 'gravatar', :size => :large }.merge(args)
if model.respond_to?(:avatar) and model.avatar.present?
- Avatar
image_tag(model.avatar.image.url(args[:size]), args)
else
args = Avatar.size_from_style!(args) # convert size format :large => '75x75'
@@ -434,19 +431,21 @@ def list_of_entities
def entity_filter_checkbox(name, value, count)
checked = (session["#{controller_name}_filter"].present? ? session["#{controller_name}_filter"].split(",").include?(value.to_s) : count.to_i > 0)
- values = %Q{$$("input[name='#{name}[]']").findAll(function (el) { return el.checked }).pluck("value")}
- params = h(%Q{"#{name}=" + #{values} + "&query=" + $("query").value})
-
- onclick = remote_function(
- :url => { :action => :filter },
- :with => params,
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ url = url_for(:action => :filter)
+ onclick = %Q{
+ var query = $('#query').val(),
+ values = [];
+ $('input[name="#{name}[]"]').filter(':checked').each(function () {
+ values.push(this.value);
+ });
+ $('#loading').show();
+ $.post('#{url}', {#{name}: values.join(','), query: query}, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
check_box_tag("#{name}[]", value, checked, :id => value, :onclick => onclick)
end
-
# Create a column in the 'asset_attributes' table.
#----------------------------------------------------------------------------
def col(title, value, last = false, email = false)
@@ -526,7 +525,8 @@ def view_buttons
content_tag(:li) do
url = (action == "index") ? send("redraw_#{controller}_path") : send("#{controller.singularize}_path")
link_to('#', :title => t(view.name, :default => view.title), :"data-view" => view.name, :"data-url" => url, :"data-context" => action, :class => classes) do
- image_tag(view.icon || 'brief.png')
+ icon = view.icon || 'fa-bars'
+ content_tag(:i, nil, class: "fa #{icon}")
end
end
end.join('').html_safe
@@ -538,7 +538,7 @@ def link_to_confirm_delete(model)
url_for(model),
:method => :delete,
:remote => true,
- :onclick => visual_effect(:highlight, dom_id(model), :startcolor => "#ffe4e1")
+ :onclick => "$('\##{dom_id(model)}').effect(\"highlight\");".html_safe
)
end
@@ -546,4 +546,36 @@ def indefinite_article(params_word)
%w(a e i o u).include?(params_word[0].downcase) ? "an" : "a"
end
+ #----------------------------------------------------------------------------
+ # Generate the html for $.timeago function
+ # July 17, 2008
+ def timeago(time, options = {})
+ options[:class] ||= "timeago"
+ content_tag(:span, time.to_s, options.merge( title: time.getutc.iso8601)) if time
+ end
+
+ #----------------------------------------------------------------------------
+ # Translate List name to FontAwesome icon text
+ def get_icon(name)
+ case name
+ when "tasks" then "fa-check-square-o"
+ when "campaigns" then "fa-bar-chart-o"
+ when "leads" then "fa-tasks"
+ when "accounts" then "fa-users"
+ when "contacts" then "fa-user"
+ when "opportunities" then "fa-money"
+ when "team" then "fa-globe"
+ end
+ end
+
+ #----------------------------------------------------------------------------
+ # Ajaxification FTW!
+ # e.g. collection = Opportunity.my.scope
+ # options = { renderer: {...} , params: {...}
+ def paginate(options = {})
+ collection = options.delete(:collection)
+ options = { renderer: RemoteLinkPaginationHelper::LinkRenderer }.merge(options)
+ will_paginate(collection, options)
+ end
+
end
diff --git a/app/helpers/campaigns_helper.rb b/app/helpers/campaigns_helper.rb
index af16b0eba1..6785a8d405 100644
--- a/app/helpers/campaigns_helper.rb
+++ b/app/helpers/campaigns_helper.rb
@@ -32,5 +32,5 @@ def campaign_summary(campaign)
metrics = render :file => "campaigns/_metrics.html.haml", :locals => { :campaign => campaign }
"#{t(campaign.status)}, " << [ status, metrics ].map { |str| strip_tags(str) }.join(' ').gsub("\n", '')
end
-end
+end
diff --git a/app/helpers/contact_groups_helper.rb b/app/helpers/contact_groups_helper.rb
index 9082d40b6e..c3be853cdf 100644
--- a/app/helpers/contact_groups_helper.rb
+++ b/app/helpers/contact_groups_helper.rb
@@ -20,13 +20,14 @@ module ContactGroupsHelper
# Sidebar checkbox control for filtering accounts by category.
#----------------------------------------------------------------------------
def contact_group_category_checbox(category, count)
- checked = (session[:accounts_filter] ? session[:accounts_filter].split(",").include?(category.to_s) : count.to_i > 0)
- onclick = remote_function(
- :url => { :action => :filter },
- :with => h(%Q/"category=" + $$("input[name='category[]']").findAll(function (el) { return el.checked }).pluck("value")/),
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ checked = (session[:contact_groups_filter] ? session[:contact_groups_filter].split(",").include?(category.to_s) : count.to_i > 0)
+ url = url_for(:controller => :contact_groups, :action => :filter)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {category: this.value, checked: this.checked}, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
check_box_tag("category[]", category, checked, :id => category, :onclick => onclick)
end
diff --git a/app/helpers/contacts_helper.rb b/app/helpers/contacts_helper.rb
index d34e086499..45dfca6839 100644
--- a/app/helpers/contacts_helper.rb
+++ b/app/helpers/contacts_helper.rb
@@ -10,12 +10,13 @@ module ContactsHelper
def contact_folder_checbox(folder, count)
id = (folder == "other") ? "other" : folder.id
checked = (session[:contacts_filter] ? session[:contacts_filter].split(",").include?(id.to_s) : count.to_i > 0)
- onclick = remote_function(
- :url => { :controller => :contacts, :action => :filter },
- :with => h(%Q/"folder=" + $$("input[name='folder[]']").findAll(function (el) { return el.checked }).pluck("value")/),
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ url = url_for(:controller => :contacts, :action => :filter)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {folder: this.value, checked: this.checked}, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
check_box_tag("folder[]", id, checked, :id => id, :onclick => onclick)
end
@@ -25,12 +26,13 @@ def contact_folder_checbox(folder, count)
def user_contact_checbox(user, count)
id = (user == "other") ? "other" : user.id
checked = (session[:contacts_user_filter] ? session[:contacts_user_filter].split(",").include?(id.to_s) : count.to_i > 0)
- onclick = remote_function(
- :url => { :controller => :contacts, :action => :filter },
- :with => h(%Q/"user=" + $$("input[name='user[]']").findAll(function (el) { return el.checked }).pluck("value")/),
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ url = url_for(:controller => :contacts, :action => :filter)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {user: this.value, checked: this.checked}, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
check_box_tag("user[]", id, checked, :id => id, :onclick => onclick)
end
@@ -46,24 +48,28 @@ def label_user_select(user, text)
end
def contact_user_checbox_select(text, ids = [], html_class = "filter_label")
- onclick = remote_function(
- :url => { :controller => :contacts, :action => :filter },
- :with => h(%Q/"user=" + $$("input[name='user[]']").findAll(function (el) { el.checked = ((#{ids}.indexOf(el.value) >= 0) ? true : false); return el.checked; }).pluck("value")/),
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ url = url_for(:controller => :contacts, :action => :filter)
+ onclick = %Q{
+ $('#loading').show();
+ $("input[name='user[]']").each(function () { this.checked = ((#{ids.to_json}.indexOf(this.value) >= 0) ? true : false); });
+ $.post('#{url}', {users: #{ids.to_json}}, function () {
+ $('#loading').hide();
+ });
+ }
label_tag(text.to_sym, text, :onclick => onclick, :class => html_class)
end
def contact_folder_checbox_select(text, ids = [], html_class = "filter_label")
- onclick = remote_function(
- :url => { :controller => :contacts, :action => :filter },
- :with => h(%Q/"folder=" + $$("input[name='folder[]']").findAll(function (el) { el.checked = ((#{ids}.indexOf(el.value) >= 0) ? true : false); return el.checked; }).pluck("value")/),
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ url = url_for(:controller => :contacts, :action => :filter)
+ onclick = %Q{
+ $('#loading').show();
+ $("input[name='folder[]']").each(function () { this.checked = ((#{ids.to_json}.indexOf(this.value) >= 0) ? true : false); });
+ $.post('#{url}', {folders: #{ids.to_json}}, function () {
+ $('#loading').hide();
+ });
+ }
label_tag(text.to_sym, text, :onclick => onclick, :class => html_class)
end
@@ -141,27 +147,26 @@ def contact_template_jscript(template, weekly_emails=[], supporter_emails=[])
# seems that prototype update event is required...
script = "
- $j('\#account_id').val(#{Account.find_by_name(template).id});
- Event.fire($(\"account_id\"), \"liszt:updated\");
- $j('\#account_id').trigger(\"change\");
+ $('\#account_id').val(#{Account.find_by_name(template).id}).trigger(\"liszt:updated\");
+ $('\#account_id').trigger(\"change\");
"
# clear all subscriptions
weekly_checkboxes.each do |box|
- script = script + "$j('\#contact_cf_weekly_emails_#{box}').prop(\"checked\", false);"
+ script = script + "$('\#contact_cf_weekly_emails_#{box}').prop(\"checked\", false);"
end
supporter_checkboxes.each do |box|
- script = script + "$j('\#contact_cf_supporter_emails_#{box}').prop(\"checked\", false);"
+ script = script + "$('\#contact_cf_supporter_emails_#{box}').prop(\"checked\", false);"
end
# subscribe according to template
weekly_emails.each do |email|
- script = script + "$j('\#contact_cf_weekly_emails_#{email}').prop(\"checked\", true);"
+ script = script + "$('\#contact_cf_weekly_emails_#{email}').prop(\"checked\", true);"
end
supporter_emails.each do |email|
- script = script + "$j('\#contact_cf_supporter_emails_#{email}').prop(\"checked\", true);"
+ script = script + "$('\#contact_cf_supporter_emails_#{email}').prop(\"checked\", true);"
end
script
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index f72a52d3fb..bf40d23860 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -20,13 +20,24 @@ module EventsHelper
#----------------------------------------------------------------------------
def link_to_mark(contact, event)
#onclick = %Q/$("#{dom_id(contact, :mark)}").style.textDecoration="line-through";/
- onclick = remote_function(:url => mark_event_instance_path(event), :method => :put, :with => "'contact_id=#{contact.id}'")
+ url = url_for(:controller => :event_instances, :action => :mark)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {contact_id: this.name.split('_').pop() }, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
end
#----------------------------------------------------------------------------
def link_to_unmark(contact, event)
- #onclick = %Q/$("#{dom_id(contact, :mark)}").style.textDecoration="line-through";/
- onclick = remote_function(:url => unmark_event_instance_path(event), :method => :put, :with => "'contact_id=#{contact.id}'")
+ url = url_for(:controller => :event_instances, :action => :unmark)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {contact_id: this.name.split('_').pop() }, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
end
def attendance_section(related, assets)
@@ -48,12 +59,13 @@ def attendance_section(related, assets)
#----------------------------------------------------------------------------
def event_category_checbox(category, count)
checked = (session[:events_filter] ? session[:events_filter].split(",").include?(category.to_s) : count.to_i > 0)
- onclick = remote_function(
- :url => { :action => :filter },
- :with => h(%Q/"category=" + $$("input[name='category[]']").findAll(function (el) { return el.checked }).pluck("value")/),
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ url = url_for(:controller => :events, :action => :filter)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {category: this.value, checked: this.checked}, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
check_box_tag("category[]", category, checked, :id => category, :onclick => onclick)
end
diff --git a/app/helpers/leads_helper.rb b/app/helpers/leads_helper.rb
index 573a024ef7..86dd43d6ee 100755
--- a/app/helpers/leads_helper.rb
+++ b/app/helpers/leads_helper.rb
@@ -31,9 +31,9 @@ def link_to_reject(lead)
def confirm_reject(lead)
question = %(#{t(:reject_lead_confirm)} )
yes = link_to(t(:yes_button), reject_lead_path(lead), :method => :put)
- no = link_to_function(t(:no_button), "jQuery('#menu').html(jQuery('#confirm').html());")
- text = "jQuery('#confirm').html( jQuery('#menu').html() );\n"
- text << "jQuery('#menu').html('#{question} #{yes} : #{no}');"
+ no = link_to_function(t(:no_button), "$('#menu').html($('#confirm').html());")
+ text = "$('#confirm').html( $('#menu').html() );\n"
+ text << "$('#menu').html('#{question} #{yes} : #{no}');"
text.html_safe
end
@@ -53,16 +53,6 @@ def get_lead_default_permissions_intro(access)
end
end
- # Returns default permissions intro for leads.
- #----------------------------------------------------------------------------
- def get_lead_default_permissions_intro(access)
- case access
- when "Private" then t(:lead_permissions_intro_private, t(:opportunity_small))
- when "Public" then t(:lead_permissions_intro_public, t(:opportunity_small))
- when "Shared" then t(:lead_permissions_intro_shared, t(:opportunity_small))
- end
- end
-
# Do not offer :converted status choice if we are creating a new lead or
# editing existing lead that hasn't been converted before.
#----------------------------------------------------------------------------
@@ -93,4 +83,3 @@ def lead_summary(lead)
summary.join(', ')
end
end
-
diff --git a/app/helpers/mandrill_emails_helper.rb b/app/helpers/mandrill_emails_helper.rb
index d036911103..6293aec33b 100644
--- a/app/helpers/mandrill_emails_helper.rb
+++ b/app/helpers/mandrill_emails_helper.rb
@@ -20,13 +20,14 @@ module MandrillEmailsHelper
# Sidebar checkbox control for filtering accounts by category.
#----------------------------------------------------------------------------
def mandrill_email_category_checbox(category, count)
- checked = (session[:accounts_filter] ? session[:accounts_filter].split(",").include?(category.to_s) : count.to_i > 0)
- onclick = remote_function(
- :url => { :action => :filter },
- :with => h(%Q/"category=" + $$("input[name='category[]']").findAll(function (el) { return el.checked }).pluck("value")/),
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ checked = (session[:mandrill_emails_filter] ? session[:mandrill_emails_filter].split(",").include?(category.to_s) : count.to_i > 0)
+ url = url_for(:action => :filter)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {category: this.value, checked: this.checked}, function () {
+ $('#loading').hide();
+ });
+ }.html_safe
check_box_tag("category[]", category, checked, :id => category, :onclick => onclick)
end
end
diff --git a/app/helpers/opportunities_helper.rb b/app/helpers/opportunities_helper.rb
index cb2a98204b..af6e59f06d 100644
--- a/app/helpers/opportunities_helper.rb
+++ b/app/helpers/opportunities_helper.rb
@@ -30,5 +30,19 @@ def opportunity_summary(opportunity)
end
summary.compact.join(', ')
end
-end
+ # Generates a select list with the first 25 campaigns
+ # and prepends the currently selected campaign, if any.
+ #----------------------------------------------------------------------------
+ def opportunity_campaign_select(options = {})
+ options[:selected] ||= @opportunity.campaign_id || 0
+ selected_campaign = Campaign.find_by_id(options[:selected])
+ campaigns = ([selected_campaign] + Campaign.my.order(:name).limit(25)).compact.uniq
+ collection_select :opportunity, :campaign_id, campaigns, :id, :name, options,
+ {:"data-placeholder" => t(:select_a_campaign),
+ :"data-url" => auto_complete_campaigns_path(format: 'json'),
+ :style => "width:330px; display:none;",
+ :class => 'ajax_chosen' }
+ end
+
+end
diff --git a/app/helpers/remote_link_pagination_helper.rb b/app/helpers/remote_link_pagination_helper.rb
new file mode 100644
index 0000000000..31205bfaa2
--- /dev/null
+++ b/app/helpers/remote_link_pagination_helper.rb
@@ -0,0 +1,8 @@
+module RemoteLinkPaginationHelper
+ class LinkRenderer < WillPaginate::ActionView::LinkRenderer
+ def link(text, target, attributes = {})
+ attributes['data-remote'] = true
+ super
+ end
+ end
+end
diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb
index 05d108e7b1..3c328eb666 100755
--- a/app/helpers/tags_helper.rb
+++ b/app/helpers/tags_helper.rb
@@ -28,12 +28,4 @@ def tags_for_dashboard(model)
end.html_safe
end
- # Generate tag links for the asset landing page (shown on a sidebar).
- #----------------------------------------------------------------------------
- def tags_for_show(model)
- model.tag_list.inject([]) do |arr, tag|
- arr << link_to(tag, url_for(:action => "tagged", :id => tag), :title => tag)
- end.join(" ").html_safe
- end
-
end
diff --git a/app/helpers/tasks_helper.rb b/app/helpers/tasks_helper.rb
index fd24a96fbd..403e3a42de 100644
--- a/app/helpers/tasks_helper.rb
+++ b/app/helpers/tasks_helper.rb
@@ -11,12 +11,13 @@ module TasksHelper
def task_filter_checkbox(view, filter, count)
name = "filter_by_task_#{view}"
checked = (session[name] ? session[name].split(",").include?(filter.to_s) : count > 0)
- onclick = remote_function(
- :url => { :action => :filter, :view => view },
- :with => "'filter='+this.value+'&checked='+this.checked",
- :loading => "$('loading').show()",
- :complete => "$('loading').hide()"
- )
+ url = url_for(:action => :filter, :view => view)
+ onclick = %Q{
+ $('#loading').show();
+ $.post('#{url}', {filter: this.value, checked: this.checked}, function () {
+ $('#loading').hide();
+ });
+ }
check_box_tag("filters[]", filter, checked, :onclick => onclick, :id => "filters_#{filter.to_s.underscore}")
end
@@ -45,8 +46,8 @@ def link_to_task_delete(task, bucket)
#----------------------------------------------------------------------------
def link_to_task_complete(pending, bucket)
- onclick = %Q/$("#{dom_id(pending, :name)}").style.textDecoration="line-through";/
- onclick << remote_function(:url => complete_task_path(pending), :method => :put, :with => "'bucket=#{bucket}'")
+ onclick = %Q{$("##{dom_id(pending, :name)}").css({textDecoration: "line-through"});}
+ onclick << %Q{$.ajax("#{complete_task_path(pending)}", {type: "PUT", data: {bucket: "#{bucket}"}});}
end
# Task summary for RSS/ATOM feed.
@@ -79,8 +80,8 @@ def task_summary(task)
#----------------------------------------------------------------------------
def hide_task_and_possibly_bucket(task, bucket)
- text = "jQuery('##{dom_id(task)}').remove();\n"
- text << "jQuery('#list_#{h bucket.to_s}').fadeOut({ duration:500 });\n" if Task.bucket_empty?(bucket, current_user, @view)
+ text = "$('##{dom_id(task)}').remove();\n"
+ text << "$('#list_#{h bucket.to_s}').fadeOut({ duration:500 });\n" if Task.bucket_empty?(bucket, current_user, @view)
text.html_safe
end
@@ -88,21 +89,21 @@ def hide_task_and_possibly_bucket(task, bucket)
def replace_content(task, bucket = nil)
partial = (task.assigned_to && task.assigned_to != current_user.id) ? "assigned" : "pending"
html = render(:partial => "tasks/#{partial}", :collection => [ task ], :locals => { :bucket => bucket })
- text = "jQuery('##{dom_id(task)}').html('#{ j html }');\n".html_safe
+ text = "$('##{dom_id(task)}').html('#{ j html }');\n".html_safe
end
#----------------------------------------------------------------------------
def insert_content(task, bucket, view)
- text = "jQuery('#list_#{bucket}').show();\n".html_safe
+ text = "$('#list_#{bucket}').show();\n".html_safe
html = render(:partial => view, :collection => [ task ], :locals => { :bucket => bucket })
- text << "jQuery('##{h bucket.to_s}').prepend('#{ j html }');\n".html_safe
- text << "jQuery('##{dom_id(task)}').effect('highlight', { duration:1500 });\n".html_safe
+ text << "$('##{h bucket.to_s}').prepend('#{ j html }');\n".html_safe
+ text << "$('##{dom_id(task)}').effect('highlight', { duration:1500 });\n".html_safe
text
end
#----------------------------------------------------------------------------
def tasks_flash(message)
- text = "jQuery('#flash').html('#{ message }');\n"
+ text = "$('#flash').html('#{ message }');\n"
text << "crm.flash('notice', true)\n"
text.html_safe
end
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index 24a16d038c..4fb1d47216 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -17,7 +17,7 @@ def sort_by_language
%Q[{ name: "#{language}", on_select: function() { #{redraw(:locale, [ locale, language ], url_for(:action => :redraw, :id => current_user))} } }]
end
end
-
+
def all_users
User.by_name
end
@@ -26,7 +26,8 @@ def user_select(asset, users, myself)
user_options = user_options_for_select(users, myself)
select(asset, :assigned_to, user_options,
{ :include_blank => t(:unassigned) },
- { :style => "width:160px" })
+ { :style => "width:160px",
+ :class => 'select2' })
end
def user_options_for_select(users, myself)
diff --git a/app/helpers/versions_helper.rb b/app/helpers/versions_helper.rb
index a66b1f125a..38ff71a86c 100644
--- a/app/helpers/versions_helper.rb
+++ b/app/helpers/versions_helper.rb
@@ -8,7 +8,7 @@ module VersionsHelper
# Parse the changes for each version
#----------------------------------------------------------------------------
def parse_version(attr_name, change)
- if attr_name =~ /^cf_/ and (field = CustomField.where(:name => attr_name).first).present?
+ if attr_name =~ /\Acf_/ and (field = CustomField.where(:name => attr_name).first).present?
label = field.label
first = field.render(change.first)
second = field.render(change.second)
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index 6b7e8b2808..0d61b7acba 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -38,5 +38,12 @@ def saasu_registration_error(entity, error_text)
:from => "Mojo "
end
-end
+ private
+
+ def from_address
+ from = Setting.smtp[:from]
+ !from.blank? ? from : "Fat Free CRM "
+ end
+
+end
diff --git a/app/models/entities/account.rb b/app/models/entities/account.rb
index 6d33a318ea..2b827b6e58 100644
--- a/app/models/entities/account.rb
+++ b/app/models/entities/account.rb
@@ -43,20 +43,20 @@ class Account < ActiveRecord::Base
accepts_nested_attributes_for :billing_address, :allow_destroy => true, :reject_if => proc {|attributes| Address.reject_address(attributes)}
accepts_nested_attributes_for :shipping_address, :allow_destroy => true, :reject_if => proc {|attributes| Address.reject_address(attributes)}
- scope :state, lambda { |filters|
+ scope :state, ->(filters) {
where('category IN (?)' + (filters.delete('other') ? ' OR category IS NULL' : ''), filters)
}
- scope :created_by, lambda { |user| where(:user_id => user.id) }
- scope :assigned_to, lambda { |user| where(:assigned_to => user.id) }
+ scope :created_by, ->(user) { where(:user_id => user.id) }
+ scope :assigned_to, ->(user) { where(:assigned_to => user.id) }
- scope :text_search, lambda { |query| search('name_or_email_cont' => query).result }
+ scope :text_search, ->(query) { search('name_or_email_cont' => query).result }
- scope :visible_on_dashboard, lambda { |user|
+ scope :visible_on_dashboard, ->(user) {
# Show accounts which either belong to the user and are unassigned, or are assigned to the user
where('(user_id = :user_id AND assigned_to IS NULL) OR assigned_to = :user_id', :user_id => user.id)
}
- scope :by_name, order(:name)
+ scope :by_name, -> { order(:name) }
uses_user_permissions
acts_as_commentable
@@ -71,8 +71,11 @@ class Account < ActiveRecord::Base
ransack_can_autocomplete
validates_presence_of :name, :message => :missing_account_name
- validates_uniqueness_of :name, :scope => :deleted_at if Setting.require_unique_account_names
+ validates_uniqueness_of :name, :scope => :deleted_at, :if => -> { Setting.require_unique_account_names }
+ validates :rating, :inclusion => { in: 0..5 }, allow_blank: true
+ validates :category, :inclusion => { in: Proc.new{ Setting.unroll(:account_category).map{|s| s.last.to_s} } }, allow_blank: true
validate :users_for_shared_access
+
before_save :nullify_blank_category
# Default values provided through class methods.
diff --git a/app/models/entities/account_contact.rb b/app/models/entities/account_contact.rb
index 944ba7a4dc..c44dc2a7af 100644
--- a/app/models/entities/account_contact.rb
+++ b/app/models/entities/account_contact.rb
@@ -21,7 +21,7 @@ class AccountContact < ActiveRecord::Base
has_paper_trail :meta => { :related => :contact }, :ignore => [ :id, :created_at, :updated_at, :contact_id ]
- validates :account_id, :presence => true
+ validates_presence_of :account_id
ActiveSupport.run_load_hooks(:fat_free_crm_account_contact, self)
end
diff --git a/app/models/entities/campaign.rb b/app/models/entities/campaign.rb
index 84d283e926..f7441dc9df 100644
--- a/app/models/entities/campaign.rb
+++ b/app/models/entities/campaign.rb
@@ -32,20 +32,20 @@
class Campaign < ActiveRecord::Base
belongs_to :user
belongs_to :assignee, :class_name => "User", :foreign_key => :assigned_to
- has_many :tasks, :as => :asset, :dependent => :destroy#, :order => 'created_at DESC'
+ has_many :tasks, :as => :asset, :dependent => :destroy
has_many :leads, :dependent => :destroy, :order => "id DESC"
has_many :opportunities, :dependent => :destroy, :order => "id DESC"
has_many :emails, :as => :mediator
serialize :subscribed_users, Set
- scope :state, lambda { |filters|
+ scope :state, ->(filters) {
where('status IN (?)' + (filters.delete('other') ? ' OR status IS NULL' : ''), filters)
}
- scope :created_by, lambda { |user| where('user_id = ?' , user.id) }
- scope :assigned_to, lambda { |user| where('assigned_to = ?', user.id) }
+ scope :created_by, ->(user) { where( user_id: user.id ) }
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
- scope :text_search, lambda { |query| search('name_cont' => query).result }
+ scope :text_search, ->(query) { search('name_cont' => query).result }
uses_user_permissions
acts_as_commentable
diff --git a/app/models/entities/contact.rb b/app/models/entities/contact.rb
index 92fce95adf..c2d00f59b4 100644
--- a/app/models/entities/contact.rb
+++ b/app/models/entities/contact.rb
@@ -40,12 +40,13 @@ class Contact < ActiveRecord::Base
belongs_to :user
belongs_to :lead
belongs_to :assignee, :class_name => "User", :foreign_key => :assigned_to
+ belongs_to :reporting_user, :class_name => "User", :foreign_key => :reports_to
has_one :account_contact, :dependent => :destroy
has_one :account, :through => :account_contact
has_many :registrations, :dependent => :destroy
has_many :contact_opportunities, :dependent => :destroy
has_many :opportunities, :through => :contact_opportunities, :uniq => true, :order => "opportunities.id DESC"
- has_many :tasks, :as => :asset, :dependent => :destroy#, :order => 'created_at DESC'
+ has_many :tasks, :as => :asset, :dependent => :destroy
has_one :business_address, :dependent => :destroy, :as => :addressable, :class_name => "Address", :conditions => "address_type = 'Business'"
has_many :addresses, :dependent => :destroy, :as => :addressable, :class_name => "Address" # advanced search uses this
has_many :emails, :as => :mediator
@@ -57,6 +58,8 @@ class Contact < ActiveRecord::Base
#contacts we really don't want to keep any trace of...
has_many :attendances, :dependent => :destroy
+ delegate :campaign, :to => :lead, :allow_nil => true
+
has_ransackable_associations %w(account opportunities tags activities emails addresses comments tasks contact_groups)
ransack_can_autocomplete
@@ -64,10 +67,10 @@ class Contact < ActiveRecord::Base
accepts_nested_attributes_for :business_address, :allow_destroy => true, :reject_if => proc {|attributes| Address.reject_address(attributes)}
- scope :created_by, lambda { |user| { :conditions => [ "user_id = ?", user.id ] } }
- scope :assigned_to, lambda { |user| { :conditions => ["assigned_to = ?", user.id ] } }
+ scope :created_by, ->(user) { where( user_id: user.id ) }
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
- scope :text_search, lambda { |query|
+ scope :text_search, ->(query) {
t = Contact.arel_table
# We can't always be sure that names are entered in the right order, so we must
# split the query into all possible first/last name permutations.
@@ -107,10 +110,10 @@ class Contact < ActiveRecord::Base
has_fields
exportable
- sortable :by => [ "first_name ASC", "last_name ASC", "created_at DESC", "updated_at DESC", "account_contacts.account_id DESC" ], :default => "created_at DESC"
+ sortable :by => [ "first_name ASC", "last_name ASC", "created_at DESC", "updated_at DESC" ], :default => "created_at DESC"
- validates_presence_of :first_name, :message => :missing_first_name if Setting.require_first_names
- validates_presence_of :last_name, :message => :missing_last_name if Setting.require_last_names
+ validates_presence_of :first_name, :message => :missing_first_name, :if => -> { Setting.require_first_names }
+ validates_presence_of :last_name, :message => :missing_last_name, :if => -> { Setting.require_last_names }
validate :users_for_shared_access
# Default values provided through class methods.
@@ -200,7 +203,6 @@ def update_with_account_and_permissions(params)
# Must set access before user_ids, because user_ids= method depends on access value.
self.access = params[:contact][:access] if params[:contact][:access]
self.attributes = params[:contact]
- #mailchimp_lists unless self.invalid?
self.save
end
diff --git a/app/models/entities/lead.rb b/app/models/entities/lead.rb
index 08cf420c44..56efc39e3e 100644
--- a/app/models/entities/lead.rb
+++ b/app/models/entities/lead.rb
@@ -41,7 +41,7 @@ class Lead < ActiveRecord::Base
belongs_to :campaign
belongs_to :assignee, :class_name => "User", :foreign_key => :assigned_to
has_one :contact, :dependent => :nullify # On destroy keep the contact, but nullify its lead_id
- has_many :tasks, :as => :asset, :dependent => :destroy#, :order => 'created_at DESC'
+ has_many :tasks, :as => :asset, :dependent => :destroy
has_one :business_address, :dependent => :destroy, :as => :addressable, :class_name => "Address", :conditions => "address_type='Business'"
has_many :addresses, :dependent => :destroy, :as => :addressable, :class_name => "Address" # advanced search uses this
has_many :emails, :as => :mediator
@@ -50,15 +50,15 @@ class Lead < ActiveRecord::Base
accepts_nested_attributes_for :business_address, :allow_destroy => true
- scope :state, lambda { |filters|
+ scope :state, ->(filters) {
where([ 'status IN (?)' + (filters.delete('other') ? ' OR status IS NULL' : ''), filters ])
}
- scope :converted, where(:status => 'converted')
- scope :for_campaign, lambda { |id| where('campaign_id = ?', id) }
- scope :created_by, lambda { |user| where('user_id = ?' , user.id) }
- scope :assigned_to, lambda { |user| where('assigned_to = ?' , user.id) }
+ scope :converted, -> { where( status: 'converted' ) }
+ scope :for_campaign, ->(id) { where( campaign_id: id ) }
+ scope :created_by, ->(user) { where( user_id: user.id ) }
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
- scope :text_search, lambda { |query| search('first_name_or_last_name_or_company_or_email_cont' => query).result }
+ scope :text_search, ->(query) { search('first_name_or_last_name_or_company_or_email_cont' => query).result }
uses_user_permissions
acts_as_commentable
@@ -72,8 +72,8 @@ class Lead < ActiveRecord::Base
has_ransackable_associations %w(contact campaign tasks tags activities emails addresses comments)
ransack_can_autocomplete
- validates_presence_of :first_name, :message => :missing_first_name if Setting.require_first_names
- validates_presence_of :last_name, :message => :missing_last_name if Setting.require_last_names
+ validates_presence_of :first_name, :message => :missing_first_name, :if => -> { Setting.require_first_names }
+ validates_presence_of :last_name, :message => :missing_last_name, :if => -> { Setting.require_last_names }
validate :users_for_shared_access
after_create :increment_leads_count
diff --git a/app/models/entities/opportunity.rb b/app/models/entities/opportunity.rb
index 50b0540de1..023c0d64ad 100644
--- a/app/models/entities/opportunity.rb
+++ b/app/models/entities/opportunity.rb
@@ -38,35 +38,33 @@ class Opportunity < ActiveRecord::Base
serialize :subscribed_users, Set
- scope :state, lambda { |filters|
+ scope :state, ->(filters) {
where('stage IN (?)' + (filters.delete('other') ? ' OR stage IS NULL' : ''), filters)
}
- scope :created_by, lambda { |user| where('user_id = ?', user.id) }
- scope :assigned_to, lambda { |user| where('assigned_to = ?', user.id) }
- scope :won, where("opportunities.stage = 'won'")
- scope :lost, where("opportunities.stage = 'lost'")
- scope :not_lost, where("opportunities.stage <> 'lost'")
- scope :pipeline, where("opportunities.stage IS NULL OR (opportunities.stage != 'won' AND opportunities.stage != 'lost')")
- scope :unassigned, where("opportunities.assigned_to IS NULL")
+ scope :created_by, ->(user) { where('user_id = ?', user.id) }
+ scope :assigned_to, ->(user) { where('assigned_to = ?', user.id) }
+ scope :won, -> { where("opportunities.stage = 'won'") }
+ scope :lost, -> { where("opportunities.stage = 'lost'") }
+ scope :not_lost, -> { where("opportunities.stage <> 'lost'") }
+ scope :pipeline, -> { where("opportunities.stage IS NULL OR (opportunities.stage != 'won' AND opportunities.stage != 'lost')") }
+ scope :unassigned, -> { where("opportunities.assigned_to IS NULL") }
# Search by name OR id
- scope :text_search, lambda { |query|
- # postgresql does not like to compare string to integer field
- if query =~ /^\d+$/
- query = query.gsub(/[^\w\s\-\.'\p{L}]/u, '').strip
+ scope :text_search, ->(query) {
+ if query =~ /\A\d+\z/
where('upper(name) LIKE upper(:name) OR opportunities.id = :id', :name => "%#{query}%", :id => query)
else
search('name_cont' => query).result
end
}
- scope :visible_on_dashboard, lambda { |user|
+ scope :visible_on_dashboard, ->(user) {
# Show opportunities which either belong to the user and are unassigned, or are assigned to the user and haven't been closed (won/lost)
where('(user_id = :user_id AND assigned_to IS NULL) OR assigned_to = :user_id', :user_id => user.id).where("opportunities.stage != 'won'").where("opportunities.stage != 'lost'")
}
- scope :by_closes_on, order(:closes_on)
- scope :by_amount, order('opportunities.amount DESC')
+ scope :by_closes_on, -> { order(:closes_on) }
+ scope :by_amount, -> { order('opportunities.amount DESC') }
uses_user_permissions
acts_as_commentable
@@ -80,17 +78,12 @@ class Opportunity < ActiveRecord::Base
has_ransackable_associations %w(account contacts tags campaign activities emails comments)
ransack_can_autocomplete
- validates :stage, :inclusion => { :in => Setting.unroll(:opportunity_stage).map{|s| s.last.to_s } }
+ validates :stage, :inclusion => { :in => Proc.new { Setting.unroll(:opportunity_stage).map{|s| s.last.to_s } } }
validates_presence_of :name, :message => :missing_opportunity_name
validates_numericality_of [ :probability, :amount, :discount ], :allow_nil => true
validate :users_for_shared_access
- # Validate presence of account_opportunity unless the opportunity is deleted [with has_paper_trail],
- # in which case the account_opportunity will still exist but will be in a deleted state.
- # validates :account_opportunity, :presence => true, :unless => Proc.new { |o| o.destroyed? }
- # TODO: Mike, what do you think about the above validation?
-
after_create :increment_opportunities_count
after_destroy :decrement_opportunities_count
diff --git a/app/models/fields/custom_field.rb b/app/models/fields/custom_field.rb
index d482d567c2..359a153910 100644
--- a/app/models/fields/custom_field.rb
+++ b/app/models/fields/custom_field.rb
@@ -49,6 +49,7 @@
class CustomField < Field
after_validation :update_column, :on => :update
before_create :add_column
+ after_create :add_ransack_translation
SAFE_DB_TRANSITIONS = {
:any => [['date', 'time', 'timestamp'], ['integer', 'float']],
@@ -129,6 +130,15 @@ def add_column
klass.serialize_custom_fields!
end
+ # Adds custom field translation for Ransack
+ def add_ransack_translation
+ I18n.backend.store_translations(Setting.locale.to_sym, {
+ ransack: {attributes: {klass.model_name.singular => {name => label}}}
+ })
+ # Reset Ransack cache
+ # Ransack::Helpers::FormBuilder.cached_searchable_attributes_for_base = {}
+ end
+
# Change database column type only if safe to do so
# Note: columns will never be renamed or destroyed
#------------------------------------------------------------------------------
diff --git a/app/models/fields/field.rb b/app/models/fields/field.rb
index d47c9dae90..9975be71d4 100644
--- a/app/models/fields/field.rb
+++ b/app/models/fields/field.rb
@@ -33,9 +33,9 @@ class Field < ActiveRecord::Base
belongs_to :field_group
- scope :core_fields, where(:type => 'CoreField')
- scope :custom_fields, where("type != 'CoreField'")
- scope :without_pairs, where(:pair_id => nil)
+ scope :core_fields, -> { where(:type => 'CoreField') }
+ scope :custom_fields, -> { where("type != 'CoreField'") }
+ scope :without_pairs, -> { where(:pair_id => nil) }
delegate :klass, :klass_name, :klass_name=, :to => :field_group
diff --git a/app/models/fields/field_group.rb b/app/models/fields/field_group.rb
index 841fcc29e0..75a40a318e 100644
--- a/app/models/fields/field_group.rb
+++ b/app/models/fields/field_group.rb
@@ -46,6 +46,7 @@ def label_i18n
end
private
+
# Can't delete default field group
def not_default_field_group
name != "custom_fields"
diff --git a/app/models/list.rb b/app/models/list.rb
index a83b9e21aa..e960f10b8b 100644
--- a/app/models/list.rb
+++ b/app/models/list.rb
@@ -5,10 +5,13 @@
#------------------------------------------------------------------------------
class List < ActiveRecord::Base
validates_presence_of :name
+ validates_presence_of :url
+ belongs_to :user
# Parses the controller from the url
def controller
- (url || "").sub(/^\//,'').split(/\/|\?/).first
+ (url || "").sub(/\A\//,'').split(/\/|\?/).first
end
+
ActiveSupport.run_load_hooks(:fat_free_crm_list, self)
end
diff --git a/app/models/observers/entity_observer.rb b/app/models/observers/entity_observer.rb
index e4bc560929..f903ad3623 100644
--- a/app/models/observers/entity_observer.rb
+++ b/app/models/observers/entity_observer.rb
@@ -19,8 +19,14 @@ def after_update(item)
private
def send_notification_to_assignee(item)
- #UserMailer.assigned_entity_notification(item, current_user).deliver if item.assignee.present? && current_user.present?
- UserMailer.delay.assigned_entity_notification(item, (current_user.present? ? current_user : User.find(1)) ) if item.assignee.present?
+ if item.assignee.present? && current_user.present? && can_send_email?
+ UserMailer.assigned_entity_notification(item, current_user).deliver
+ end
+ end
+
+ # Need to have a host set before email can be sent
+ def can_send_email?
+ Setting.host.present?
end
def current_user
@@ -32,4 +38,6 @@ def current_user
User.find_by_id(user_id_or_user.to_i)
end
end
+
+ ActiveSupport.run_load_hooks(:fat_free_crm_entity_observer, self)
end
diff --git a/app/models/observers/lead_observer.rb b/app/models/observers/lead_observer.rb
index 0f04c95dd8..dce8e20ebd 100644
--- a/app/models/observers/lead_observer.rb
+++ b/app/models/observers/lead_observer.rb
@@ -24,4 +24,6 @@ def after_update(item)
def log_activity(item, event)
item.send(item.class.versions_association_name).create(:event => event, :whodunnit => PaperTrail.whodunnit)
end
+
+ ActiveSupport.run_load_hooks(:fat_free_crm_lead_observer, self)
end
diff --git a/app/models/observers/opportunity_observer.rb b/app/models/observers/opportunity_observer.rb
index b227de3489..65d6518493 100644
--- a/app/models/observers/opportunity_observer.rb
+++ b/app/models/observers/opportunity_observer.rb
@@ -42,4 +42,6 @@ def log_activity(item, event)
def update_campaign_revenue(campaign, revenue)
campaign.update_attribute(:revenue, (campaign.revenue || 0) + revenue) if campaign
end
+
+ ActiveSupport.run_load_hooks(:fat_free_crm_opportunity_observer, self)
end
diff --git a/app/models/observers/task_observer.rb b/app/models/observers/task_observer.rb
index dc989c2808..5b4e72c771 100644
--- a/app/models/observers/task_observer.rb
+++ b/app/models/observers/task_observer.rb
@@ -26,4 +26,6 @@ def after_update(item)
def log_activity(item, event)
item.send(item.class.versions_association_name).create(:event => event, :whodunnit => PaperTrail.whodunnit)
end
+
+ ActiveSupport.run_load_hooks(:fat_free_crm_task_observer, self)
end
diff --git a/app/models/polymorphic/address.rb b/app/models/polymorphic/address.rb
index ebbc742ab9..b4d57e913b 100644
--- a/app/models/polymorphic/address.rb
+++ b/app/models/polymorphic/address.rb
@@ -28,9 +28,9 @@ class Address < ActiveRecord::Base
has_paper_trail :meta => { :related => :addressable }
- scope :business, :conditions => "address_type='Business'"
- scope :billing, :conditions => "address_type='Billing'"
- scope :shipping, :conditions => "address_type='Shipping'"
+ scope :business, -> { where("address_type='Business'") }
+ scope :billing, -> { where("address_type='Billing'") }
+ scope :shipping, -> { where("address_type='Shipping'") }
# Checks if the address is blank for both single and compound addresses.
#----------------------------------------------------------------------------
diff --git a/app/models/polymorphic/avatar.rb b/app/models/polymorphic/avatar.rb
index 2380e5ab4c..8cd35db111 100644
--- a/app/models/polymorphic/avatar.rb
+++ b/app/models/polymorphic/avatar.rb
@@ -45,7 +45,7 @@ def self.size_from_style!(options)
if options[:width] && options[:height]
options[:size] = [:width, :height].map{|d| options[d]}.join("x")
elsif Avatar::STYLES.keys.include?(options[:size])
- options[:size] = Avatar::STYLES[options[:size]].sub(/\#$/,'')
+ options[:size] = Avatar::STYLES[options[:size]].sub(/\#\z/,'')
end
options
end
diff --git a/app/models/polymorphic/task.rb b/app/models/polymorphic/task.rb
index 43a0fc52bb..9771bdc6f3 100644
--- a/app/models/polymorphic/task.rb
+++ b/app/models/polymorphic/task.rb
@@ -27,6 +27,7 @@
class Task < ActiveRecord::Base
attr_accessor :calendar
+ ALLOWED_VIEWS = %w(pending assigned completed)
belongs_to :user
belongs_to :assignee, :class_name => "User", :foreign_key => :assigned_to
@@ -37,30 +38,33 @@ class Task < ActiveRecord::Base
# Tasks created by the user for herself, or assigned to her by others. That's
# what gets shown on Tasks/Pending and Tasks/Completed pages.
- scope :my, lambda { |*args|
+ scope :my, ->(*args) {
options = args[0] || {}
- user_option = options[:user] || User.current_user
+ user_option = (options.is_a?(Hash) ? options[:user] : options) || User.current_user
includes(:assignee).
where('((user_id = ? OR user_id = 2) AND assigned_to IS NULL) OR assigned_to = ?', user_option, user_option).
order(options[:order] || 'name ASC').
limit(options[:limit]) # nil selects all records
}
+ scope :created_by, ->(user) { where( user_id: user.id ) }
+ scope :assigned_to, ->(user) { where( assigned_to: user.id ) }
+
# Tasks assigned by the user to others. That's what we see on Tasks/Assigned.
- scope :assigned_by, lambda { |user|
+ scope :assigned_by, ->(user) {
includes(:assignee).
where('user_id = ? AND assigned_to IS NOT NULL AND assigned_to != ?', user.id, user.id)
}
# Tasks created by the user or assigned to the user, i.e. the union of the two
# scopes above. That's the tasks the user is allowed to see and track.
- scope :tracked_by, lambda { |user|
+ scope :tracked_by, ->(user) {
includes(:assignee).
where('user_id = ? OR user_id = 2 OR assigned_to = ?', user.id, user.id)
}
- scope :visible_on_dashboard, lambda { |user|
- # Show tasks which either belong to the user and are unassigned, or are assigned to the user
+ # Show opportunities which either belong to the user and are unassigned, or are assigned to the user
+ scope :visible_on_dashboard, ->(user) {
where('(user_id = :user_id AND assigned_to IS NULL) OR assigned_to = :user_id', :user_id => user.id).where('completed_at IS NULL')
}
@@ -69,35 +73,37 @@ class Task < ActiveRecord::Base
where('user_id = 2 AND assigned_to IS NULL', :user_id => user.id).where('completed_at IS NULL')
}
- scope :by_due_at, order({
- "MySQL" => "due_at NOT NULL, due_at ASC",
- "PostgreSQL" => "due_at ASC NULLS FIRST"
- }[ActiveRecord::Base.connection.adapter_name] || :due_at)
+ scope :by_due_at, -> {
+ order({
+ "MySQL" => "due_at NOT NULL, due_at ASC",
+ "PostgreSQL" => "due_at ASC NULLS FIRST"
+ }[ActiveRecord::Base.connection.adapter_name] || :due_at)
+ }
# Status based scopes to be combined with the due date and completion time.
- scope :pending, where('completed_at IS NULL').order('tasks.due_at, tasks.id')
- scope :assigned, where('completed_at IS NULL AND assigned_to IS NOT NULL').order('tasks.due_at, tasks.id')
- scope :completed, where('completed_at IS NOT NULL').order('tasks.completed_at DESC')
+ scope :pending, -> { where('completed_at IS NULL').order('tasks.due_at, tasks.id') }
+ scope :assigned, -> { where('completed_at IS NULL AND assigned_to IS NOT NULL').order('tasks.due_at, tasks.id') }
+ scope :completed, -> { where('completed_at IS NOT NULL').order('tasks.completed_at DESC') }
# Due date scopes.
- scope :due_asap, lambda { where("due_at IS NULL AND bucket = 'due_asap'").order('tasks.id DESC') }
- scope :overdue, lambda { where('due_at IS NOT NULL AND due_at < ?', Time.zone.now.midnight.utc).order('tasks.id DESC') }
- scope :due_today, lambda { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc).order('tasks.id DESC') }
- scope :due_tomorrow, lambda { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc, Time.zone.now.midnight.tomorrow.utc + 1.day).order('tasks.id DESC') }
- scope :due_this_week, lambda { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc + 1.day, Time.zone.now.next_week.utc).order('tasks.id DESC') }
- scope :due_next_week, lambda { where('due_at >= ? AND due_at < ?', Time.zone.now.next_week.utc, Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC') }
- scope :due_later, lambda { where("(due_at IS NULL AND bucket = 'due_later') OR due_at >= ?", Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC') }
+ scope :due_asap, -> { where("due_at IS NULL AND bucket = 'due_asap'").order('tasks.id DESC') }
+ scope :overdue, -> { where('due_at IS NOT NULL AND due_at < ?', Time.zone.now.midnight.utc).order('tasks.id DESC') }
+ scope :due_today, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc).order('tasks.id DESC') }
+ scope :due_tomorrow, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc, Time.zone.now.midnight.tomorrow.utc + 1.day).order('tasks.id DESC') }
+ scope :due_this_week, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc + 1.day, Time.zone.now.next_week.utc).order('tasks.id DESC') }
+ scope :due_next_week, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.next_week.utc, Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC') }
+ scope :due_later, -> { where("(due_at IS NULL AND bucket = 'due_later') OR due_at >= ?", Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC') }
# Completion time scopes.
- scope :completed_today, lambda { where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc) }
- scope :completed_yesterday, lambda { where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.yesterday.utc, Time.zone.now.midnight.utc) }
- scope :completed_this_week, lambda { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc , Time.zone.now.midnight.yesterday.utc) }
- scope :completed_last_week, lambda { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc - 7.days, Time.zone.now.beginning_of_week.utc) }
- scope :completed_this_month, lambda { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_month.utc, Time.zone.now.beginning_of_week.utc - 7.days) }
- scope :completed_last_month, lambda { where('completed_at >= ? AND completed_at < ?', (Time.zone.now.beginning_of_month.utc - 1.day).beginning_of_month.utc, Time.zone.now.beginning_of_month.utc) }
-
- scope :text_search, lambda { |query|
+ scope :completed_today, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc) }
+ scope :completed_yesterday, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.yesterday.utc, Time.zone.now.midnight.utc) }
+ scope :completed_this_week, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc , Time.zone.now.midnight.yesterday.utc) }
+ scope :completed_last_week, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc - 7.days, Time.zone.now.beginning_of_week.utc) }
+ scope :completed_this_month, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_month.utc, Time.zone.now.beginning_of_week.utc - 7.days) }
+ scope :completed_last_month, -> { where('completed_at >= ? AND completed_at < ?', (Time.zone.now.beginning_of_month.utc - 1.day).beginning_of_month.utc, Time.zone.now.beginning_of_month.utc) }
+
+ scope :text_search, ->(query) {
query = query.gsub(/[^\w\s\-\.'\p{L}]/u, '').strip
where('upper(name) LIKE upper(?)', "%#{query}%")
}
@@ -171,6 +177,7 @@ def computed_bucket
# Returns list of tasks grouping them by due date as required by tasks/index.
#----------------------------------------------------------------------------
def self.find_all_grouped(user, view)
+ return {} unless ALLOWED_VIEWS.include?(view)
settings = (view == "completed" ? Setting.task_completed : Setting.task_bucket)
Hash[
settings.map do |key, value|
@@ -182,7 +189,7 @@ def self.find_all_grouped(user, view)
# Returns bucket if it's empty (i.e. we have to hide it), nil otherwise.
#----------------------------------------------------------------------------
def self.bucket_empty?(bucket, user, view = "pending")
- return false if bucket.blank?
+ return false if bucket.blank? or !ALLOWED_VIEWS.include?(view)
if view == "assigned"
assigned_by(user).send(bucket).pending.count
else
@@ -193,6 +200,7 @@ def self.bucket_empty?(bucket, user, view = "pending")
# Returns task totals for each of the views as needed by tasks sidebar.
#----------------------------------------------------------------------------
def self.totals(user, view = "pending")
+ return {} unless ALLOWED_VIEWS.include?(view)
settings = (view == "completed" ? Setting.task_completed : Setting.task_bucket)
settings.inject({ :all => 0 }) do |hash, key|
hash[key] = (view == "assigned" ? assigned_by(user).send(key).pending.count : my(user).send(key).send(view).count)
diff --git a/app/models/setting.rb b/app/models/setting.rb
index 332508ccc5..160a842bb5 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -71,7 +71,6 @@ def [](name)
end
end
-
# Set setting value
#-------------------------------------------------------------------
def []=(name, value)
@@ -82,7 +81,6 @@ def []=(name, value)
cache[name] = value
end
-
# Unrolls [ :one, :two ] settings array into [[ "One", :one ], [ "Two", :two ]]
# picking symbol translations from locale. If setting is not a symbol but
# string it gets copied without translation.
@@ -98,19 +96,12 @@ def database_and_table_exists?
table_exists? rescue false
end
-
# Loads settings from YAML files
def load_settings_from_yaml(file)
- begin
- YAML::ENGINE.yamler = 'syck' # remove this when files are converted to Psych
- settings = YAML.load_file(file)
- # Merge settings into current settings hash (recursively)
- @@yaml_settings.deep_merge!(settings)
- rescue Exception => ex
- puts "Settings couldn't be loaded from #{file}: #{ex.message}"
- end
- yaml_settings
+ settings = YAML.load_file(file)
+ @@yaml_settings.deep_merge!(settings)
end
+
end
ActiveSupport.run_load_hooks(:fat_free_crm_setting, self)
diff --git a/app/models/users/ability.rb b/app/models/users/ability.rb
index 6ee760c112..830e85fc03 100644
--- a/app/models/users/ability.rb
+++ b/app/models/users/ability.rb
@@ -9,15 +9,26 @@ class Ability
include CanCan::Ability
def initialize(user)
+
+ # handle signup
+ can(:create, User) if User.can_signup?
+
if user.present?
entities = [Event, EventInstance, Registration]
[Account, Campaign, Contact, Lead, Opportunity, ContactGroup, Attendance].each{|e| entities << e} unless user.groups.collect(&:name).include? "Conference Manager"
entities << MandrillEmail if user.mandrill?
-
- can :create, :all
- can :read, [User] # for search autocomplete
+
+ # User
+ can :manage, User, id: user.id # can do any action on themselves
+
+ # Tasks
+ can :create, Task
+ can :manage, Task, user: user.id
+ can :manage, Task, assigned_to: user.id
+
+ # Entities
can :manage, entities, :access => 'Public'
can :manage, entities + [Task], :user_id => user.id
can :manage, entities + [Task], :assigned_to => user.id
diff --git a/app/models/users/group.rb b/app/models/users/group.rb
index 6b2a997232..e493d4481b 100644
--- a/app/models/users/group.rb
+++ b/app/models/users/group.rb
@@ -11,10 +11,5 @@ class Group < ActiveRecord::Base
validates :name, :presence => true, :uniqueness => true
- # TODO: Fix chosen bug that makes this necessary
- def user_ids=(value)
- super value.join.split(',')
- end
-
ActiveSupport.run_load_hooks(:fat_free_crm_group, self)
end
diff --git a/app/models/users/user.rb b/app/models/users/user.rb
index a6725e5a81..3427775956 100644
--- a/app/models/users/user.rb
+++ b/app/models/users/user.rb
@@ -56,27 +56,27 @@ class User < ActiveRecord::Base
has_many :assigned_opportunities, :class_name => 'Opportunity', :foreign_key => 'assigned_to'
has_many :permissions, :dependent => :destroy
has_many :preferences, :dependent => :destroy
+ has_many :lists
has_and_belongs_to_many :groups
has_paper_trail :ignore => [:last_request_at, :perishable_token]
- # For some reason this does not play nice with has_paper_trail when set as default scope
- scope :by_id, order('id DESC')
- scope :except, lambda { |user| where('id != ?', user.id).by_name }
- scope :by_name, order('first_name, last_name, email')
+ scope :by_id, -> { order('id DESC') }
+ scope :except, ->(user) { where('id != ?', user.id).by_name }
+ scope :by_name, -> { order('first_name, last_name, email') }
- scope :text_search, lambda { |query|
+ scope :text_search, ->(query) {
query = query.gsub(/[^\w\s\-\.'\p{L}]/u, '').strip
where('upper(username) LIKE upper(:s) OR upper(first_name) LIKE upper(:s) OR upper(last_name) LIKE upper(:s)', :s => "%#{query}%")
}
- scope :my, lambda {
- accessible_by(User.current_ability)
- }
+ scope :my, -> { accessible_by(User.current_ability) }
- scope :have_assigned_opportunities, joins("INNER JOIN opportunities ON users.id = opportunities.assigned_to").
- where("opportunities.stage <> 'lost' AND opportunities.stage <> 'won'").
- select('DISTINCT(users.id), users.*')
+ scope :have_assigned_opportunities, -> {
+ joins("INNER JOIN opportunities ON users.id = opportunities.assigned_to")
+ .where("opportunities.stage <> 'lost' AND opportunities.stage <> 'won'")
+ .select('DISTINCT(users.id), users.*')
+ }
acts_as_authentic do |c|
c.session_class = Authentication
@@ -139,11 +139,12 @@ def set_single_access_token
self.single_access_token ||= update_attribute(:single_access_token, Authlogic::Random.friendly_token)
end
- # Massage value when using Chosen select box which gives values like ["", "1,2,3"]
- #----------------------------------------------------------------------------
- def group_ids=(value)
- value = value.join.split(',').map(&:to_i) if value.map{|v| v.to_s.include?(',')}.any?
- super(value)
+ def to_json(options = nil)
+ [name].to_json
+ end
+
+ def to_xml(options = nil)
+ [name].to_xml
end
private
@@ -163,7 +164,7 @@ def check_if_current_user
# Prevent deleting a user unless she has no artifacts left.
#----------------------------------------------------------------------------
def check_if_has_related_assets
- artifacts = %w(Account Campaign Lead Contact Opportunity Comment Event ContactGroup MandrillEmail EventInstance Registration).inject(0) do |sum, asset|
+ artifacts = %w(Account Campaign Lead Contact Opportunity Comment Event ContactGroup MandrillEmail EventInstance Registration Task).inject(0) do |sum, asset|
klass = asset.constantize
sum += klass.assigned_to(self).count if asset != "Comment"
sum += klass.created_by(self).count
@@ -179,6 +180,10 @@ def current_ability
Ability.new(User.current_user)
end
+ def can_signup?
+ [ :allowed, :needs_approval ].include? Setting.user_signup
+ end
+
end
ActiveSupport.run_load_hooks(:fat_free_crm_user, self)
diff --git a/app/views/accounts/_index_brief.html.haml b/app/views/accounts/_index_brief.html.haml
index 786385ffd5..33ff21178a 100644
--- a/app/views/accounts/_index_brief.html.haml
+++ b/app/views/accounts/_index_brief.html.haml
@@ -24,12 +24,12 @@
–
%tt
= account.location << ", " unless account.location.blank?
- - user_name = account.user_id == current_user.id ? t(:me) : account.user.try(:full_name)
+ - user_name = account.user.try(:full_name)
- if user_name
- = t(:added_by, :time_ago => time_ago_in_words(account.created_at), :user => user_name) << " | "
+ = t(:added_by, :time_ago => timeago(account.created_at), :user => h(user_name)).html_safe << " | "
- else
- = t(:added_ago, :value => time_ago_in_words(account.created_at)) << " | "
- = t('pluralize.contact', account.contacts.count) #<< " | "
+ = t(:added_ago, :value => timeago(account.created_at)).html_safe << " | "
+ = t('pluralize.contact', account.contacts.count) << " | "
-#= t('pluralize.opportunity', account.opportunities.count)
= hook(:account_bottom, self, :account => account)
diff --git a/app/views/accounts/_index_long.html.haml b/app/views/accounts/_index_long.html.haml
index cbee3546b0..15569e9be4 100644
--- a/app/views/accounts/_index_long.html.haml
+++ b/app/views/accounts/_index_long.html.haml
@@ -21,11 +21,11 @@
–
%tt
= account.location << ", " unless account.location.blank?
- - user_name = account.user_id == current_user.id ? t(:me) : account.user.try(:full_name)
+ - user_name = account.user.try(:full_name)
- if user_name
- = t(:added_by, :time_ago => time_ago_in_words(account.created_at), :user => user_name) << " | "
+ = t(:added_by, :time_ago => timeago(account.created_at), :user => h(user_name)).html_safe << " | "
- else
- = t(:added_ago, :value => time_ago_in_words(account.created_at)) << " | "
+ = t(:added_ago, :value => timeago(account.created_at)).html_safe << " | "
= t('pluralize.contact', account.contacts.count) << " | "
= t('pluralize.opportunity', account.opportunities.count)
diff --git a/app/views/accounts/create.js.haml b/app/views/accounts/create.js.haml
index bb136100c4..cffc8f8b6e 100644
--- a/app/views/accounts/create.js.haml
+++ b/app/views/accounts/create.js.haml
@@ -3,15 +3,15 @@
- create_id = "create_#{entity_name}" # create_account
- if @entity.valid?
- jQuery('##{create_id}_arrow').html(crm.COLLAPSED);
- jQuery('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
- jQuery('##{create_id}').slideUp(250);
- jQuery('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
+ $('##{create_id}_arrow').html(crm.COLLAPSED);
+ $('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
+ $('##{create_id}').slideUp(250);
+ $('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
= refresh_sidebar(:index, :filters)
- jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
crm.flick('empty', 'remove');
- else
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
- jQuery('##{create_id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').effect("shake", { duration:250, distance: 6 });
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/accounts/destroy.js.haml b/app/views/accounts/destroy.js.haml
index aa959f705a..5de988e236 100644
--- a/app/views/accounts/destroy.js.haml
+++ b/app/views/accounts/destroy.js.haml
@@ -1,6 +1,6 @@
- entity_name = controller.controller_name.singularize.underscore
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
+$('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
= refresh_sidebar(:index, :filters)
-jQuery('#paginate').replaceWith('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#paginate').replaceWith('#{ j render(:partial => "shared/paginate_with_per_page") }');
diff --git a/app/views/accounts/edit.js.haml b/app/views/accounts/edit.js.haml
index a767843d90..b32ba4d764 100644
--- a/app/views/accounts/edit.js.haml
+++ b/app/views/accounts/edit.js.haml
@@ -8,25 +8,25 @@
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
- else # Called from index page...
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- else # <---------------------------------------- Show [Edit] form.
- if params[:cancel].blank? # Called from index page...
- if @previous # Hide open [Edit] form if any.
- if @previous.is_a?(@entity.class)
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
- else
crm.flick('#{entity_name}_#{@previous}', 'remove');
-# Disable onMouseOver for the list item.
crm.highlight_off('#{id}');
-# Hide [Create] form if any.
- crm.hide_form('create_#{entity_name}')
+ crm.hide_form('create_#{entity_name}');
-# Show [Edit] form.
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').html('#{ j render(:partial => "edit") }');
- elsif params[:cancel].false? # Called from title of the landing page...
- jQuery('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
+ $('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', "#{t :edit} #{h @entity.name}");
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/accounts/index.js.haml b/app/views/accounts/index.js.haml
index 9b5aaae0f7..b93ec3887a 100644
--- a/app/views/accounts/index.js.haml
+++ b/app/views/accounts/index.js.haml
@@ -2,10 +2,10 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(@entities) }');
+ $('##{entities}').html('#{ j render(@entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
-jQuery('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
+$('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
diff --git a/app/views/accounts/index.xls.builder b/app/views/accounts/index.xls.builder
index 54dd307094..82ca7be23b 100644
--- a/app/views/accounts/index.xls.builder
+++ b/app/views/accounts/index.xls.builder
@@ -3,7 +3,8 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
unless @accounts.empty?
# Header.
xml.Row do
- heads = [I18n.t('user'),
+ heads = [I18n.t('id'),
+ I18n.t('user'),
I18n.t('assigned_to'),
I18n.t('name'),
I18n.t('email'),
@@ -24,12 +25,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
I18n.t('zipcode'),
I18n.t('country'),
I18n.t('address')]
-
+
# Append custom field labels to header
Account.fields.each do |field|
heads << field.label
end
-
+
heads.each do |head|
xml.Cell do
xml.Data head,
@@ -37,12 +38,13 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
end
end
end
-
+
# Account rows.
@accounts.each do |account|
xml.Row do
address = account.billing_address
- data = [account.user.try(:name),
+ data = [account.id,
+ account.user.try(:name),
account.assignee.try(:name),
account.name,
account.email,
@@ -63,12 +65,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
address.try(:zipcode),
address.try(:country),
address.try(:full_address)]
-
+
# Append custom field values.
Account.fields.each do |field|
data << account.send(field.name)
end
-
+
data.each do |value|
xml.Cell do
xml.Data value,
diff --git a/app/views/accounts/move_contact.js.haml b/app/views/accounts/move_contact.js.haml
index c5868c5782..82e63abcb3 100644
--- a/app/views/accounts/move_contact.js.haml
+++ b/app/views/accounts/move_contact.js.haml
@@ -1,5 +1,5 @@
- id = dom_id(@contact)
-jQuery('##{id}').replaceWith('#{ j render(:partial => "contacts/contact", :collection => [ @contact ]) }');
-jQuery('##{id}').effect("highlight", { duration:1500 });
+$('##{id}').replaceWith('#{ j render(:partial => "contacts/contact", :collection => [ @contact ]) }');
+$('##{id}').effect("highlight", { duration:1500 });
= refresh_sidebar_for(:contacts, :index, :filters)
\ No newline at end of file
diff --git a/app/views/accounts/new.js.haml b/app/views/accounts/new.js.haml
index 35918db5bc..3edcb8bb0b 100644
--- a/app/views/accounts/new.js.haml
+++ b/app/views/accounts/new.js.haml
@@ -5,7 +5,7 @@ crm.flick('empty', 'toggle');
crm.flip_form('#{create_id}');
- unless params[:cancel].true?
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
crm.set_title('#{create_id}', '#{ j t(create_id) }');
- else
crm.set_title('#{create_id}', '#{ j t(entity_name.pluralize) }');
diff --git a/app/views/accounts/show.js.haml b/app/views/accounts/show.js.haml
index faa94cf6cf..b7d5bc626e 100644
--- a/app/views/accounts/show.js.haml
+++ b/app/views/accounts/show.js.haml
@@ -1,5 +1,5 @@
- entity_name = controller.controller_name.singularize.underscore #account
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
+$('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
= raw generate_js_for_popups(@entity, :tasks, :contacts, :opportunities)
diff --git a/app/views/accounts/update.js.haml b/app/views/accounts/update.js.haml
index d174f80db1..d1b17294a7 100644
--- a/app/views/accounts/update.js.haml
+++ b/app/views/accounts/update.js.haml
@@ -8,10 +8,10 @@
crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
= refresh_sidebar(:show, :summary)
- else
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
= refresh_sidebar(:index, :filters)
- else
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
diff --git a/app/views/admin/field_groups/_field_group.html.haml b/app/views/admin/field_groups/_field_group.html.haml
index 0172ea439f..bb9b0051a3 100644
--- a/app/views/admin/field_groups/_field_group.html.haml
+++ b/app/views/admin/field_groups/_field_group.html.haml
@@ -17,11 +17,10 @@
.remote{ hidden.merge(:id => edit_form_id) }
- .list{ :id => dom_id(field_group, :fields) }
- - if (fields = field_group.fields.without_pairs).present?
- = render :partial => "admin/fields/field", :collection => fields
- - else
- .empty{:id => "empty_#{asset}_field_group_#{field_group.id}"}
+ .list
+ %ul{ :id => dom_id(field_group, :fields), :class => 'fields', 'data-sortable' => sort_admin_fields_path(:field_group_id => field_group.id), 'data-sortable-connect-with' => '.fields', 'data-sortable-handle' => '.handle' }
+ = render :partial => "admin/fields/field", :collection => field_group.fields.without_pairs
+ %li.empty
= t(:field_group_empty)
= link_to t(:create_field), '#', :class => 'create', 'data-for' => create_form_id
diff --git a/app/views/admin/field_groups/confirm.js.haml b/app/views/admin/field_groups/confirm.js.haml
index 0ba84a4d7c..913e48081c 100644
--- a/app/views/admin/field_groups/confirm.js.haml
+++ b/app/views/admin/field_groups/confirm.js.haml
@@ -1,7 +1,7 @@
- id = dom_id(@field_group, :confirm)
-if (jQuery('##{id}').size() > 0) {
+if ($('##{id}').size() > 0) {
crm.flick('#{id}', 'remove');
} else {
-jQuery('##{dom_id(@field_group)}').prepend('#{ j (render :partial => "confirm") }');
+$('##{dom_id(@field_group)}').prepend('#{ j (render :partial => "confirm") }');
}
diff --git a/app/views/admin/field_groups/create.js.haml b/app/views/admin/field_groups/create.js.haml
index ca96ce2697..357cafb228 100644
--- a/app/views/admin/field_groups/create.js.haml
+++ b/app/views/admin/field_groups/create.js.haml
@@ -4,17 +4,11 @@
- container_id = "#{asset}_field_groups"
- if @field_group.valid?
- jQuery('##{id}_arrow').html(crm.COLLAPSED);
- jQuery('##{id}').slideUp( { duration:250, complete: function() {jQuery(this).html('')} } );
- jQuery('##{container_id}').after('#{ j(render :partial => "field_group", :collection => [ @field_group ]) }');
-
- - group_list_ids = klass.field_groups.map {|field_group| dom_id(field_group, :fields)}
- - klass.field_groups.each do |field_group|
- jQuery('##{container_id}').after('#{ j(sortable_element(dom_id(field_group, :fields), :url => sort_admin_fields_path(:field_group_id => field_group.id), :containment => group_list_ids, :dropOnEmpty => true)) }');
-
- jQuery('##{container_id}').after('#{ j(sortable_element(container_id, :url => sort_admin_field_groups_path(:asset => asset), :tag => :div)) }');
- jQuery('##{dom_id(@field_group)}').effect('highlight', { duration:1500 });
+ $('##{id}_arrow').html(crm.COLLAPSED);
+ $('##{id}').slideUp( { duration:250, complete: function() {$(this).html('')} } );
+ $('##{container_id}').after('#{ j(render :partial => "field_group", :collection => [ @field_group ]) }');
+ $('##{dom_id(@field_group)}').effect('highlight', { duration:1500 });
- else
- jQuery('##{id}').html('#{ j render(:partial => "new") }');
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{id}').html('#{ j render(:partial => "new") }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
diff --git a/app/views/admin/field_groups/destroy.js.haml b/app/views/admin/field_groups/destroy.js.haml
index 75d536ac5f..d084fdb7be 100644
--- a/app/views/admin/field_groups/destroy.js.haml
+++ b/app/views/admin/field_groups/destroy.js.haml
@@ -1,9 +1,9 @@
- id = dom_id(@field_group)
- if @field_group.destroyed?
- jQuery('##{id}').css('background-color', '#ffe4e1').slideUp(250);
+ $('##{id}').css('background-color', '#ffe4e1').slideUp(250);
- else
- jQuery('##{id}').effect("shake", { distance:5 }, 250);
- jQuery('#flash').html('#{ j t(:msg_cant_delete_field_group) }');
+ $('##{id}').effect("shake", { distance:5 }, 250);
+ $('#flash').html('#{ j t(:msg_cant_delete_field_group) }');
crm.flash('warning');
- flash[:warning] = nil
diff --git a/app/views/admin/field_groups/edit.js.haml b/app/views/admin/field_groups/edit.js.haml
index 8346a19af7..bd8b4fba02 100644
--- a/app/views/admin/field_groups/edit.js.haml
+++ b/app/views/admin/field_groups/edit.js.haml
@@ -9,4 +9,4 @@
- else # <----------------------------------------- Show [Edit field_group] form.
crm.show_form('#{form_id}');
- jQuery('##{form_id}').html('#{ j render(:partial => "edit") }');
+ $('##{form_id}').html('#{ j render(:partial => "edit") }');
diff --git a/app/views/admin/field_groups/new.js.haml b/app/views/admin/field_groups/new.js.haml
index 0956239c52..17316f8cf6 100644
--- a/app/views/admin/field_groups/new.js.haml
+++ b/app/views/admin/field_groups/new.js.haml
@@ -5,4 +5,4 @@ crm.flick('empty', 'toggle');
crm.flip_form('#{id}');
- if params[:cancel] != "true"
- jQuery('##{id}').html('#{ j render(:partial => 'new') }');
+ $('##{id}').html('#{ j render(:partial => 'new') }');
diff --git a/app/views/admin/field_groups/update.js.haml b/app/views/admin/field_groups/update.js.haml
index 623645e0ba..f52d9d1b74 100644
--- a/app/views/admin/field_groups/update.js.haml
+++ b/app/views/admin/field_groups/update.js.haml
@@ -4,5 +4,5 @@
crm.flip_form('#{id}');
crm.set_title('#{dom_id(@field_group)}', '#{field_group_subtitle(@field_group)}');
- else
- jQuery('##{id}').html('#{ j render(:partial => 'edit') }');
- jQuery('##{id}').effect('shake', { distance:5 }, 250);
+ $('##{id}').html('#{ j render(:partial => 'edit') }');
+ $('##{id}').effect('shake', { distance:5 }, 250);
diff --git a/app/views/admin/fields/_field.html.haml b/app/views/admin/fields/_field.html.haml
index a894ac6da3..5916551455 100644
--- a/app/views/admin/fields/_field.html.haml
+++ b/app/views/admin/fields/_field.html.haml
@@ -11,7 +11,7 @@
%b= field.label
== (#{t("field_types.#{field.as}.title")})
- == added #{time_ago_in_words(field.created_at)} ago
+ = t(:added_ago, value: timeago(field.created_at)).html_safe
= hook(:field_bottom, self, :field => field)
.edit_field
diff --git a/app/views/admin/fields/_sort_by.html.haml b/app/views/admin/fields/_sort_by.html.haml
index 749b490c36..f5c5e971e3 100644
--- a/app/views/admin/fields/_sort_by.html.haml
+++ b/app/views/admin/fields/_sort_by.html.haml
@@ -3,8 +3,8 @@
:plain
new crm.Menu({
- trigger : "sort_by",
- fade : 0.5,
- appear : 0.5,
+ trigger : "#sort_by",
+ fade : 500,
+ appear : 500,
menu_items: [ #{sort_by_menu_items.join(",")} ]
});
diff --git a/app/views/admin/fields/create.js.haml b/app/views/admin/fields/create.js.haml
index 99c8952962..eb7fe1d576 100644
--- a/app/views/admin/fields/create.js.haml
+++ b/app/views/admin/fields/create.js.haml
@@ -5,13 +5,13 @@
- empty_field_id = "empty_opportunity_field_group_#{@field.field_group_id}"
- if @field.valid?
- jQuery("##{id}_arrow").html(crm.COLLAPSED)
- jQuery('##{create_field_id}').before('#{ j (render :partial => "field", :collection => [@field]) }')
- jQuery('##{create_field_id}').before('#{ j (sortable_element(container_id, :url => sort_admin_fields_path(:field_group_id => @field.field_group_id))) }')
- jQuery('##{custom_field_id}').effect("highlight", { duration:1500 });
- jQuery("##{create_field_id}").hide();
- jQuery("##{empty_field_id}").hide();
+ $("##{id}_arrow").html(crm.COLLAPSED)
+ $('##{container_id}').append('#{ j (render :partial => "field", :collection => [@field]) }')
+ $('##{custom_field_id}').effect("highlight", { duration:1500 });
+ $("##{create_field_id}").hide();
+ $("##{empty_field_id}").hide();
+ $('##{container_id}').sortable('reset');
- else
- jQuery('##{id}').html('#{ j render(:partial => "admin/fields/form", :locals => {:field_group_id => @field.field_group_id}) }')
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('##{id}').find('input[type="text"]').first().focus()
+ $('##{id}').html('#{ j render(:partial => "admin/fields/form", :locals => {:field_group_id => @field.field_group_id}) }')
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{id}').find('input[type="text"]').first().focus()
diff --git a/app/views/admin/fields/destroy.js.haml b/app/views/admin/fields/destroy.js.haml
index f16a2dc9fa..f6c396750b 100644
--- a/app/views/admin/fields/destroy.js.haml
+++ b/app/views/admin/fields/destroy.js.haml
@@ -1,8 +1,8 @@
- id = dom_id(@field)
- if @field.destroyed?
- jQuery('li##{id}').css('background-color', '#ffe4e1').slideUp(250);
+ $('li##{id}').css('background-color', '#ffe4e1').slideUp(250);
- else
- jQuery('li##{id}').effect("shake", { duration:250, distance: 6});
- jQuery('#flash').html('#{ j flash[:warning] }')
- jQuery(crm.flash('warning'))
+ $('li##{id}').effect("shake", { duration:250, distance: 6});
+ $('#flash').html('#{ j flash[:warning] }')
+ $(crm.flash('warning'))
- flash[:warning] = nil
diff --git a/app/views/admin/fields/edit.js.haml b/app/views/admin/fields/edit.js.haml
index b804955837..51bf058e78 100644
--- a/app/views/admin/fields/edit.js.haml
+++ b/app/views/admin/fields/edit.js.haml
@@ -1,3 +1,3 @@
- id = dom_id(@field)
-html = jQuery.parseHTML('#{j render(:partial => "admin/fields/form")}')
-jQuery('##{id}').find('.edit_field').replaceWith( html )
+html = $.parseHTML('#{j render(:partial => "admin/fields/form")}')
+$('##{id}').find('.edit_field').replaceWith( html )
diff --git a/app/views/admin/fields/index.html.haml b/app/views/admin/fields/index.html.haml
index cdc509e6cf..91eaa0941c 100644
--- a/app/views/admin/fields/index.html.haml
+++ b/app/views/admin/fields/index.html.haml
@@ -28,14 +28,7 @@
.title
= t(asset)
- - container_id = "#{asset}_field_groups"
- .list{ :id => container_id }
+ .list{ :id => "#{asset}_field_groups", 'data-sortable' => sort_admin_field_groups_path(:asset => asset) }
= render :partial => "admin/field_groups/field_group", :collection => klass.field_groups, :locals => {:asset => asset, :klass => klass}
- - group_list_ids = klass.field_groups.map {|field_group| dom_id(field_group, :fields)}
- - klass.field_groups.each do |field_group|
- = sortable_element(dom_id(field_group, :fields), :url => sort_admin_fields_path(:field_group_id => field_group.id), :containment => group_list_ids, :dropOnEmpty => true)
-
- = sortable_element(container_id, :url => sort_admin_field_groups_path(:asset => asset), :tag => :div)
-
.remote{ hidden.merge(:id => create_form_id) }
diff --git a/app/views/admin/fields/update.js.haml b/app/views/admin/fields/update.js.haml
index 8524a4e8c7..51ef4a7e2f 100644
--- a/app/views/admin/fields/update.js.haml
+++ b/app/views/admin/fields/update.js.haml
@@ -2,12 +2,12 @@
- container_id = "#{@field.klass_name.downcase}_field_groups"
- if @field.errors.empty?
- html = jQuery.parseHTML('#{ j (render :partial => "field", :collection => [@field]) }');
- jQuery('##{id}').replaceWith( html);
- jQuery('##{id}').effect("highlight", { duration:1000 });
- jQuery('##{container_id}').after('#{ j (sortable_element(container_id, :url => sort_admin_fields_path(:field_group_id => @field.field_group_id))) }');
+ html = $.parseHTML('#{ j (render :partial => "field", :collection => [@field]) }');
+ $('##{id}').replaceWith(html);
+ $('##{id}').effect("highlight", { duration:1000 });
+ $('##{container_id}').sortable('reset');
- else
- html = jQuery.parseHTML('#{ j(render :partial => "form") }');
- jQuery('##{id}').find('.edit_field').replaceWith( html );
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('##{id}').find('input[type="text"]').first().focus();
+ html = $.parseHTML('#{ j(render :partial => "form") }');
+ $('##{id}').find('.edit_field').replaceWith( html );
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{id}').find('input[type="text"]').first().focus();
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 60188c05a2..da6722aca2 100755
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -8,6 +8,4 @@
%td
.label.top.req #{t :users}:
%br
- = f.select :user_ids, User.all.map {|u| [u.full_name, u.id]}, {}, :multiple => true
- :javascript
- new Chosen($('group_user_ids'));
+ = f.select :user_ids, User.all.map {|u| [u.full_name, u.id]}, {}, :multiple => true, :class => 'select2'
diff --git a/app/views/admin/groups/create.js.haml b/app/views/admin/groups/create.js.haml
index 9a0059e603..091c67e0f9 100644
--- a/app/views/admin/groups/create.js.haml
+++ b/app/views/admin/groups/create.js.haml
@@ -1,10 +1,10 @@
- if @group.valid?
- jQuery('#create_group_arrow').html(crm.COLLAPSED);
- jQuery('#create_group_title').html('#{ j t(:groups) }');
- jQuery('#create_group').slideUp(250);
- jQuery('#groups').prepend('#{ j (render :partial => "group", :collection => [ @group ]) }');
- jQuery('##{dom_id(@group)}').effect("highlight", { duration:1500 });
+ $('#create_group_arrow').html(crm.COLLAPSED);
+ $('#create_group_title').html('#{ j t(:groups) }');
+ $('#create_group').slideUp(250);
+ $('#groups').prepend('#{ j (render :partial => "group", :collection => [ @group ]) }');
+ $('##{dom_id(@group)}').effect("highlight", { duration:1500 });
- else
- jQuery('#create_group').html('#{ j render(:partial => "new") }');
- jQuery('#create_group').effect("shake", { duration:250, distance: 6 });
- jQuery('#group_name').focus();
+ $('#create_group').html('#{ j render(:partial => "new") }');
+ $('#create_group').effect("shake", { duration:250, distance: 6 });
+ $('#group_name').focus();
diff --git a/app/views/admin/groups/destroy.js.haml b/app/views/admin/groups/destroy.js.haml
index 7b96cc0b9e..48ddd1ee1d 100644
--- a/app/views/admin/groups/destroy.js.haml
+++ b/app/views/admin/groups/destroy.js.haml
@@ -1,9 +1,9 @@
- id = dom_id(@group)
- if @group.destroyed?
- jQuery('##{id}').css('background-color', '#ffe4e1').slideUp(250);
+ $('##{id}').css('background-color', '#ffe4e1').slideUp(250);
- else
crm.flick("#{dom_id(@group, :confirm)}, 'remove')");
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#flash').html('#{ j flash[:warning] }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('#flash').html('#{ j flash[:warning] }');
crm.flash('warning');
- flash[:warning] = nil
diff --git a/app/views/admin/groups/edit.js.haml b/app/views/admin/groups/edit.js.haml
index 027461a89a..4b219601f3 100644
--- a/app/views/admin/groups/edit.js.haml
+++ b/app/views/admin/groups/edit.js.haml
@@ -1,7 +1,7 @@
- id = dom_id(@group)
- if params[:cancel].true? # <----------------- Hide [Edit Group]
- jQuery('##{id}').replaceWith('#{ j (render(:partial => "group", :collection => [ @group ])) }');
+ $('##{id}').replaceWith('#{ j (render(:partial => "group", :collection => [ @group ])) }');
- else # <---------------------------------------- Show [Edit Group] form.
@@ -10,5 +10,5 @@
-# Hide [Create Group] form if any.
crm.hide_form('create_group');
-# Show [Edit Group] form.
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('#group_name').focus();
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('#group_name').focus();
diff --git a/app/views/admin/groups/index.js.haml b/app/views/admin/groups/index.js.haml
index e0fd7b1498..1565362182 100644
--- a/app/views/admin/groups/index.js.haml
+++ b/app/views/admin/groups/index.js.haml
@@ -1,2 +1,2 @@
-jQuery('#groups').html('#{ j render(:partial => "admin/groups/group", :collection => @groups) }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate") }')
+$('#groups').html('#{ j render(:partial => "admin/groups/group", :collection => @groups) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate") }')
diff --git a/app/views/admin/groups/new.js.haml b/app/views/admin/groups/new.js.haml
index d9327cd9b0..081671ed16 100644
--- a/app/views/admin/groups/new.js.haml
+++ b/app/views/admin/groups/new.js.haml
@@ -1,8 +1,8 @@
crm.flip_form('create_group');
- unless params[:cancel].true?
- jQuery('#create_group').html('#{ j render(:partial => "new") }');
- jQuery('#empty').html('');
+ $('#create_group').html('#{ j render(:partial => "new") }');
+ $('#empty').html('');
crm.set_title('create_group', '#{t(:create_group)}');
- else
diff --git a/app/views/admin/groups/update.js.haml b/app/views/admin/groups/update.js.haml
index 871e07dffa..c223c1c946 100644
--- a/app/views/admin/groups/update.js.haml
+++ b/app/views/admin/groups/update.js.haml
@@ -1,9 +1,9 @@
- id = dom_id(@group)
- if @group.errors.empty?
- jQuery('##{id}').replaceWith('#{ j render(:partial => "group", :collection => [ @group ]) }')
- jQuery('##{id}').effect("highlight", { duration:1000 });
+ $('##{id}').replaceWith('#{ j render(:partial => "group", :collection => [ @group ]) }')
+ $('##{id}').effect("highlight", { duration:1000 });
- else
- jQuery('##{id}').html('#{j render(:partial => "edit") }')
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#group_name').focus()
+ $('##{id}').html('#{j render(:partial => "edit") }')
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('#group_name').focus()
diff --git a/app/views/admin/tags/confirm.js.haml b/app/views/admin/tags/confirm.js.haml
index f6bd8e370c..4e2ff2fc64 100644
--- a/app/views/admin/tags/confirm.js.haml
+++ b/app/views/admin/tags/confirm.js.haml
@@ -1,7 +1,7 @@
- id = dom_id(@tag, :confirm)
-if (jQuery('##{id}').size() > 0) {
+if ($('##{id}').size() > 0) {
crm.flick('#{id}', 'remove');
} else {
-jQuery('##{dom_id(@tag)}').prepend('#{ j (render :partial => "confirm") }');
+$('##{dom_id(@tag)}').prepend('#{ j (render :partial => "confirm") }');
}
diff --git a/app/views/admin/tags/create.js.haml b/app/views/admin/tags/create.js.haml
index 354d08e514..eeb4b3aeac 100644
--- a/app/views/admin/tags/create.js.haml
+++ b/app/views/admin/tags/create.js.haml
@@ -1,11 +1,11 @@
- if @tag.valid?
- jQuery('#create_tag_arrow').html(crm.COLLAPSED);
- jQuery('#create_tag_title').html('#{ j t(:tags) }');
- jQuery('#create_tag').slideUp(250);
- jQuery('#tags').prepend('#{ j (render :partial => "tag", :collection => [ @tag ]) }');
- jQuery('##{dom_id(@tag)}').effect("highlight", { duration:1500 });
+ $('#create_tag_arrow').html(crm.COLLAPSED);
+ $('#create_tag_title').html('#{ j t(:tags) }');
+ $('#create_tag').slideUp(250);
+ $('#tags').prepend('#{ j (render :partial => "tag", :collection => [ @tag ]) }');
+ $('##{dom_id(@tag)}').effect("highlight", { duration:1500 });
crm.flick('empty', 'remove');
- else
- jQuery('#create_tag').html('#{ j render(:partial => 'new') }');
- jQuery('#create_tag').effect("shake", { duration:250, distance: 6 });
- jQuery('#tag_name').focus();
+ $('#create_tag').html('#{ j render(:partial => 'new') }');
+ $('#create_tag').effect("shake", { duration:250, distance: 6 });
+ $('#tag_name').focus();
diff --git a/app/views/admin/tags/destroy.js.haml b/app/views/admin/tags/destroy.js.haml
index b5176da3df..13533734a5 100644
--- a/app/views/admin/tags/destroy.js.haml
+++ b/app/views/admin/tags/destroy.js.haml
@@ -1,10 +1,10 @@
- id = dom_id(@tag)
- if @tag.destroyed?
- jQuery('##{id}').css('background-color', '#ffe4e1').slideUp(250);
+ $('##{id}').css('background-color', '#ffe4e1').slideUp(250);
- else
crm.flick("#{dom_id(@tag, :confirm)}, 'remove')");
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#flash').html('#{ j flash[:warning] }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('#flash').html('#{ j flash[:warning] }');
crm.flash('warning');
- flash[:warning] = nil
diff --git a/app/views/admin/tags/edit.js.haml b/app/views/admin/tags/edit.js.haml
index 97f4706107..d65c08d20c 100644
--- a/app/views/admin/tags/edit.js.haml
+++ b/app/views/admin/tags/edit.js.haml
@@ -1,13 +1,13 @@
- id = dom_id(@tag)
- if params[:cancel].true? # <----------------- Hide [Edit Tag]
- jQuery('##{id}').replaceWith('#{ j render(:partial => "tag", :collection => [ @tag ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => "tag", :collection => [ @tag ]) }');
- else # <---------------------------------------- Show [Edit Tag] form.
- if @previous # Hide open [Edit Tag] form if any.
- if @previous.is_a?(Tag) # Previous tag still exists?
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => "tag", :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => "tag", :collection => [ @previous ]) }');
- else
crm.flick('tag_#{@previous}', 'remove');
@@ -16,5 +16,5 @@
-# Show [Edit Tag] form.
crm.highlight_off('#{id}');
crm.hide_form('create_tag');
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('#tag_name').focus();
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('#tag_name').focus();
diff --git a/app/views/admin/tags/new.js.haml b/app/views/admin/tags/new.js.haml
index c1ca4028b7..af9efa2ceb 100644
--- a/app/views/admin/tags/new.js.haml
+++ b/app/views/admin/tags/new.js.haml
@@ -1,7 +1,7 @@
crm.flip_form('create_tag');
- unless params[:cancel].true?
- jQuery('#create_tag').html('#{ j render(:partial => "new") }');
+ $('#create_tag').html('#{ j render(:partial => "new") }');
crm.set_title('create_tag', '#{t(:create_tag)}');
- else
crm.set_title('create_tag', '#{t(:tags)}');
diff --git a/app/views/admin/tags/update.js.haml b/app/views/admin/tags/update.js.haml
index c5715e4c8a..1eb45fb581 100644
--- a/app/views/admin/tags/update.js.haml
+++ b/app/views/admin/tags/update.js.haml
@@ -1,9 +1,9 @@
- id = dom_id(@tag)
- if @tag.errors.empty?
- jQuery('##{id}').replaceWith('#{ j render(:partial => "tag", :collection => [ @tag ]) }');
- jQuery('##{id}').effect('highlight', { duration: 1000 });
+ $('##{id}').replaceWith('#{ j render(:partial => "tag", :collection => [ @tag ]) }');
+ $('##{id}').effect('highlight', { duration: 1000 });
- else
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#tag_tagname').focus();
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('#tag_tagname').focus();
diff --git a/app/views/admin/users/_profile.html.haml b/app/views/admin/users/_profile.html.haml
index 61c9a17c38..2ca1ab9224 100644
--- a/app/views/admin/users/_profile.html.haml
+++ b/app/views/admin/users/_profile.html.haml
@@ -50,13 +50,11 @@
%td
.label #{t :company}:
= f.text_field :company
-
+
.subtitle #{t :group_memberships}
.section
%table
%tr
%td
.label #{t :groups}:
- = f.select :group_ids, Group.all.map {|g| [g.name, g.id]}, {}, :multiple => true
- :javascript
- new Chosen($('user_group_ids'));
+ = f.select :group_ids, Group.all.map {|g| [g.name, g.id]}, {}, :multiple => true, :class => 'select2'
diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml
index ece213fea8..3d4a27f4c9 100644
--- a/app/views/admin/users/_user.html.haml
+++ b/app/views/admin/users/_user.html.haml
@@ -40,7 +40,7 @@
- if user.awaits_approval?
%b.cool #{t :user_awaits_approval}
- elsif user.last_request_at
- %span.cool #{t(:last_seen, time_ago_in_words(user.last_request_at))}
+ %span.cool= t(:last_seen2, timeago(user.last_request_at)).html_safe
- else
%span.warn #{t :user_never_logged_in}
%dt{ :style => "padding: 2px 0px 0px 0px" }
diff --git a/app/views/admin/users/confirm.js.haml b/app/views/admin/users/confirm.js.haml
index 751826a9f4..24ef353080 100644
--- a/app/views/admin/users/confirm.js.haml
+++ b/app/views/admin/users/confirm.js.haml
@@ -1,7 +1,7 @@
- id = dom_id(@user, :confirm)
-if (jQuery('##{id}').size() > 0) {
+if ($('##{id}').size() > 0) {
crm.flick('#{id}', 'remove');
} else {
-jQuery('##{dom_id(@user)}').prepend('#{ j (render :partial => "confirm") }');
+$('##{dom_id(@user)}').prepend('#{ j (render :partial => "confirm") }');
}
diff --git a/app/views/admin/users/create.js.haml b/app/views/admin/users/create.js.haml
index cb614c1f4b..f7febcb0fc 100644
--- a/app/views/admin/users/create.js.haml
+++ b/app/views/admin/users/create.js.haml
@@ -1,10 +1,10 @@
- if @user.valid?
- jQuery('#create_user_arrow').html(crm.COLLAPSED);
- jQuery('#create_user_title').html('#{t(:users)}');
- jQuery('#create_user').slideUp(250);
- jQuery('#users').prepend('#{ j (render :partial => "user", :collection => [ @user ]) }');
- jQuery('##{dom_id(@user)}').effect("highlight", { duration:1500 });
+ $('#create_user_arrow').html(crm.COLLAPSED);
+ $('#create_user_title').html('#{t(:users)}');
+ $('#create_user').slideUp(250);
+ $('#users').prepend('#{ j (render :partial => "user", :collection => [ @user ]) }');
+ $('##{dom_id(@user)}').effect("highlight", { duration:1500 });
- else
- jQuery('#create_user').html('#{ j (render :partial => "new") }');
- jQuery('#create_user').effect("shake", { duration:250, distance: 6 });
- jQuery('#group_username').focus();
+ $('#create_user').html('#{ j (render :partial => "new") }');
+ $('#create_user').effect("shake", { duration:250, distance: 6 });
+ $('#group_username').focus();
diff --git a/app/views/admin/users/destroy.js.haml b/app/views/admin/users/destroy.js.haml
index 8af88a02bb..da8ceb219e 100644
--- a/app/views/admin/users/destroy.js.haml
+++ b/app/views/admin/users/destroy.js.haml
@@ -1,10 +1,10 @@
- id = dom_id(@user)
- if @user.destroyed?
- jQuery('##{id}').css('background-color', '#ffe4e1').slideUp(250).remove();
+ $('##{id}').css('background-color', '#ffe4e1').slideUp(250).remove();
- else
crm.flick('#{dom_id(@user, :confirm)}', 'remove');
- jQuery('##{id}').effect('shake', { duration:250, distance: 6 });
- jQuery('#flash').html('#{j flash[:warning]}');
+ $('##{id}').effect('shake', { duration:250, distance: 6 });
+ $('#flash').html('#{j flash[:warning]}');
crm.flash('warning');
- flash[:warning] = nil
diff --git a/app/views/admin/users/edit.js.haml b/app/views/admin/users/edit.js.haml
index ab653df359..2f393fd412 100644
--- a/app/views/admin/users/edit.js.haml
+++ b/app/views/admin/users/edit.js.haml
@@ -1,13 +1,13 @@
- id = dom_id(@user)
- if params[:cancel].true? # <----------------- Hide [Edit User]
- jQuery('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }');
- else # <---------------------------------------- Show [Edit User] form.
- if @previous # Hide open [Edit User] form if any.
- if @previous.is_a?(User) # Previous user still exists?
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => "user", :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => "user", :collection => [ @previous ]) }');
- else
crm.flick('user_#{@previous}', 'remove');
@@ -16,5 +16,5 @@
-# Show [Edit User] form.
crm.highlight_off('#{id}');
crm.hide_form('create_user');
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('#user_username').focus();
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('#user_username').focus();
diff --git a/app/views/admin/users/index.js.haml b/app/views/admin/users/index.js.haml
index e005cc2ca5..384470f5f2 100644
--- a/app/views/admin/users/index.js.haml
+++ b/app/views/admin/users/index.js.haml
@@ -1,2 +1,2 @@
-jQuery('#users').html('#{ j render(:partial => "admin/users/user", :collection => @users) }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate") }')
+$('#users').html('#{ j render(:partial => "admin/users/user", :collection => @users) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate") }')
diff --git a/app/views/admin/users/new.js.haml b/app/views/admin/users/new.js.haml
index 0704e4ea8d..eee9835ab4 100644
--- a/app/views/admin/users/new.js.haml
+++ b/app/views/admin/users/new.js.haml
@@ -1,8 +1,8 @@
crm.flip_form('create_user');
- unless params[:cancel].true?
- jQuery('#create_user').html('#{ j render(:partial => "new") }');
- jQuery('#empty').html('');
+ $('#create_user').html('#{ j render(:partial => "new") }');
+ $('#empty').html('');
crm.set_title('create_user', '#{t(:create_user)}');
- else
diff --git a/app/views/admin/users/reactivate.js.haml b/app/views/admin/users/reactivate.js.haml
index f039ce097f..6592b138bb 100644
--- a/app/views/admin/users/reactivate.js.haml
+++ b/app/views/admin/users/reactivate.js.haml
@@ -1,3 +1,3 @@
- id = dom_id(@user)
-jQuery('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }');
-jQuery('##{id}').effect("highlight", { duration:1000 });
+$('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }');
+$('##{id}').effect("highlight", { duration:1000 });
diff --git a/app/views/admin/users/suspend.js.haml b/app/views/admin/users/suspend.js.haml
index f039ce097f..6592b138bb 100644
--- a/app/views/admin/users/suspend.js.haml
+++ b/app/views/admin/users/suspend.js.haml
@@ -1,3 +1,3 @@
- id = dom_id(@user)
-jQuery('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }');
-jQuery('##{id}').effect("highlight", { duration:1000 });
+$('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }');
+$('##{id}').effect("highlight", { duration:1000 });
diff --git a/app/views/admin/users/update.js.haml b/app/views/admin/users/update.js.haml
index 6289f90f88..e5648081c6 100644
--- a/app/views/admin/users/update.js.haml
+++ b/app/views/admin/users/update.js.haml
@@ -1,9 +1,9 @@
- id = dom_id(@user)
- if @user.errors.empty?
- jQuery('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }')
- jQuery('##{id}').effect("highlight", { duration:1000 });
+ $('##{id}').replaceWith('#{ j render(:partial => "user", :collection => [ @user ]) }')
+ $('##{id}').effect("highlight", { duration:1000 });
- else
- jQuery('##{id}').html('#{j render(:partial => "edit") }')
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#user_username').focus()
+ $('##{id}').html('#{j render(:partial => "edit") }')
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('#user_username').focus()
diff --git a/app/views/campaigns/_status.html.haml b/app/views/campaigns/_status.html.haml
index 6032d01aca..550379788d 100644
--- a/app/views/campaigns/_status.html.haml
+++ b/app/views/campaigns/_status.html.haml
@@ -7,7 +7,7 @@
- if campaign.ends_on > Date.today
%span>= ", " + t(:finishes_in, distance_of_time_in_words(Date.today, campaign.ends_on))
- else
- %span.warn= "(" + t(:was_supposed_to_finish, campaign.starts_on.strftime('%b %e, %Y')) + ")"
+ %span.warn= "(" + t(:was_supposed_to_finish, campaign.ends_on.strftime('%b %e, %Y')) + ")"
- else
%span.warn> #{t :no_start_date}
- when :planned
diff --git a/app/views/campaigns/create.js.haml b/app/views/campaigns/create.js.haml
index 60579201ba..bbfe6e694a 100755
--- a/app/views/campaigns/create.js.haml
+++ b/app/views/campaigns/create.js.haml
@@ -3,18 +3,18 @@
- create_id = "create_#{entity_name}" # create_account
- if @entity.valid?
- jQuery('##{create_id}_arrow').html(crm.COLLAPSED);
- jQuery('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
- jQuery('##{create_id}').slideUp(250);
- jQuery('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
+ $('##{create_id}_arrow').html(crm.COLLAPSED);
+ $('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
+ $('##{create_id}').slideUp(250);
+ $('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
= refresh_sidebar(:index, :filters)
- jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
crm.flick('empty', 'remove');
- else
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
- jQuery('##{create_id}').effect("shake", { duration:250, distance: 6 });
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').effect("shake", { duration:250, distance: 6 });
- if @entity.errors[:name].blank? and @entity.errors[:ends_on].present?
- jQuery('#campaign_ends_on').focus();
+ $('#campaign_ends_on').focus();
- else
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/campaigns/destroy.js.haml b/app/views/campaigns/destroy.js.haml
index 2c211808fb..3d8089e3ab 100755
--- a/app/views/campaigns/destroy.js.haml
+++ b/app/views/campaigns/destroy.js.haml
@@ -1,6 +1,6 @@
- entity_name = controller.controller_name.singularize.underscore
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250)
+$('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250)
= refresh_sidebar(:index, :filters)
-jQuery('#paginate').replaceWith('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#paginate').replaceWith('#{ j render(:partial => "shared/paginate_with_per_page") }');
diff --git a/app/views/campaigns/edit.js.haml b/app/views/campaigns/edit.js.haml
index 779d54e1b4..c1f78d9ff2 100755
--- a/app/views/campaigns/edit.js.haml
+++ b/app/views/campaigns/edit.js.haml
@@ -8,26 +8,26 @@
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
- else # Called from index page...
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- else # <---------------------------------------- Show [Edit] form.
- if params[:cancel].blank? # Called from index page...
- if @previous # Hide open [Edit] form if any.
- if @previous.is_a?(@entity.class)
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
- else
crm.flick('#{entity_name}_#{@previous}', 'remove');
-# Disable onMouseOver for the list item.
crm.highlight_off('#{id}');
-# Hide [Create] form if any.
- crm.hide_form('create_#{entity_name}')
+ crm.hide_form('create_#{entity_name}');
-# Show [Edit] form.
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').html('#{ j render(:partial => "edit") }');
- elsif params[:cancel].false? # Called from title of the landing page...
- jQuery('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
+ $('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', "#{t :edit} #{h @entity.name}");
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
-
\ No newline at end of file
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
+
diff --git a/app/views/campaigns/index.js.haml b/app/views/campaigns/index.js.haml
index 9b5aaae0f7..b93ec3887a 100755
--- a/app/views/campaigns/index.js.haml
+++ b/app/views/campaigns/index.js.haml
@@ -2,10 +2,10 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(@entities) }');
+ $('##{entities}').html('#{ j render(@entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
-jQuery('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
+$('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
diff --git a/app/views/campaigns/index.xls.builder b/app/views/campaigns/index.xls.builder
index fa14f66b53..6f275f404c 100644
--- a/app/views/campaigns/index.xls.builder
+++ b/app/views/campaigns/index.xls.builder
@@ -3,7 +3,8 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_campaigns) do
unless @campaigns.empty?
# Header.
xml.Row do
- heads = [I18n.t('user'),
+ heads = [I18n.t('id'),
+ I18n.t('user'),
I18n.t('assigned_to'),
I18n.t('name'),
I18n.t('access'),
@@ -21,12 +22,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_campaigns) do
I18n.t('background_info'),
I18n.t('date_created'),
I18n.t('date_updated')]
-
+
# Append custom field labels to header
Campaign.fields.each do |field|
heads << field.label
end
-
+
heads.each do |head|
xml.Cell do
xml.Data head,
@@ -34,11 +35,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_campaigns) do
end
end
end
-
+
# Campaign rows.
@campaigns.each do |campaign|
xml.Row do
- data = [campaign.user.try(:name),
+ data = [campaign.id,
+ campaign.user.try(:name),
campaign.assignee.try(:name),
campaign.name,
campaign.access,
@@ -56,12 +58,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_campaigns) do
campaign.background_info,
campaign.created_at,
campaign.updated_at]
-
+
# Append custom field values.
Campaign.fields.each do |field|
data << campaign.send(field.name)
end
-
+
data.each do |value|
xml.Cell do
xml.Data value,
diff --git a/app/views/campaigns/new.js.haml b/app/views/campaigns/new.js.haml
index 35918db5bc..3edcb8bb0b 100755
--- a/app/views/campaigns/new.js.haml
+++ b/app/views/campaigns/new.js.haml
@@ -5,7 +5,7 @@ crm.flick('empty', 'toggle');
crm.flip_form('#{create_id}');
- unless params[:cancel].true?
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
crm.set_title('#{create_id}', '#{ j t(create_id) }');
- else
crm.set_title('#{create_id}', '#{ j t(entity_name.pluralize) }');
diff --git a/app/views/campaigns/show.js.haml b/app/views/campaigns/show.js.haml
index 0c2fc6d86c..99085292a2 100755
--- a/app/views/campaigns/show.js.haml
+++ b/app/views/campaigns/show.js.haml
@@ -1,5 +1,5 @@
- entity_name = controller.controller_name.singularize.underscore #account
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
+$('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
= raw generate_js_for_popups(@entity, :tasks, :leads, :opportunities)
diff --git a/app/views/campaigns/update.js.haml b/app/views/campaigns/update.js.haml
index 68b80a2449..62055d2738 100755
--- a/app/views/campaigns/update.js.haml
+++ b/app/views/campaigns/update.js.haml
@@ -8,13 +8,13 @@
crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
= refresh_sidebar(:show, :summary)
- else
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
= refresh_sidebar(:index, :filters)
- else
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
- if @campaign.errors[:name].blank? and @campaign.errors[:ends_on].present?
- jQuery('#campaign_ends_on').focus();
+ $('#campaign_ends_on').focus();
- else
- jQuery('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
+ $('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
diff --git a/app/views/comments/_comment.html.haml b/app/views/comments/_comment.html.haml
index f77a52e605..fdb558b3d0 100644
--- a/app/views/comments/_comment.html.haml
+++ b/app/views/comments/_comment.html.haml
@@ -14,8 +14,7 @@
%tt
- = link_to(comment.user.full_name, user_path(comment.user))
- added note #{t(:time_ago, distance_of_time_in_words(Time.now, comment.created_at))}
+ = t(:added_note, value: timeago(comment.created_at) ).html_safe
- if collapsable && can?(:read, commentable)
= " | "
= link_to_function(comment.collapsed? ? t(:more) : t(:less), "crm.flip_note_or_email(this, '#{t(:more)}', '#{t(:less)}')", :class => "toggle")
diff --git a/app/views/comments/_edit.html.haml b/app/views/comments/_edit.html.haml
index c1c23fb1e0..3536d391db 100644
--- a/app/views/comments/_edit.html.haml
+++ b/app/views/comments/_edit.html.haml
@@ -5,7 +5,7 @@
= hidden_field_tag "comment[commentable_id]", commentable.id
= hidden_field_tag "comment[commentable_type]", class_name.classify
= f.text_area :comment, :id => dom_id(@comment, :text)
- %div{:style => "padding:6px 0px 0px 40px;"}
+ .buttons
= f.submit t(:save_note)
#{t :or}
- = link_to(t(:cancel), edit_comment_path("#{class_name}_id" => commentable, :cancel => true), :remote => true)
+ = link_to(t(:cancel), edit_comment_path(@comment, "#{class_name}_id" => commentable.id, :cancel => true), :remote => true)
diff --git a/app/views/comments/_new.html.haml b/app/views/comments/_new.html.haml
index d5747a25c5..2524d2c2af 100644
--- a/app/views/comments/_new.html.haml
+++ b/app/views/comments/_new.html.haml
@@ -22,12 +22,13 @@
= hidden_field_tag "comment[commentable_id]", commentable.id, :id => "#{id_prefix}_comment_commentable_id"
= hidden_field_tag "comment[commentable_type]", class_name.classify, :id => "#{id_prefix}_comment_commentable_type"
= f.text_area :comment, :id => "#{id_prefix}_comment_comment"
- %div{:style => "padding:6px 0px 0px 40px;"}
+ .buttons
+ = image_tag("loading.gif", :size => :thumb, :class => "spinner", :style => "display: none;")
= f.submit t(:add_note), :id => "#{id_prefix}_comment_submit"
#{t :or}
- = link_to(t(:cancel), new_comment_path("#{class_name}_id" => commentable) + '&cancel=true', :remote => true)
+ = link_to(t(:cancel), '#', :class => 'cancel')
%div{ {:id => "#{id_prefix}_ask"}.merge(hidden_if(false))}
- = text_field_tag :post_new_note, t(:add_note_help), :onclick => remote_function(:url => new_comment_path("#{class_name}_id" => commentable), :method => :get), :id => "#{id_prefix}_post_new_note"
+ = text_field_tag :post_new_note, t(:add_note_help), :id => "#{id_prefix}_post_new_note"
- if notification_emails_configured? && class_name != "attendance"
= render :partial => "comments/subscription_links", :locals => {:entity => commentable}
diff --git a/app/views/comments/create.js.haml b/app/views/comments/create.js.haml
index 6d7fdbcb65..71fab60780 100644
--- a/app/views/comments/create.js.haml
+++ b/app/views/comments/create.js.haml
@@ -2,11 +2,13 @@
- id_prefix = "#{class_name}_#{@comment.commentable.id}"
- if @comment.valid?
- jQuery('##{id_prefix}_comment_new').after('#{ j (render :partial => "comment", :locals => { :comment => @comment }) }');
- jQuery('##{dom_id(@comment)}').effect("highlight", { duration:1500 });
- jQuery('##{id_prefix}_post').hide();
- jQuery('##{id_prefix}_ask').show();
+ $('##{id_prefix}_comment_new').after('#{ j (render :partial => "comment", :locals => { :comment => @comment }) }');
+ $('##{dom_id(@comment)}').effect("highlight", { duration:1500 });
+ $('##{id_prefix}_post').hide();
+ $('##{id_prefix}_ask').show();
-jQuery('##{id_prefix}_shown_notes').val('#{ j @comment.commentable.comment_ids.join(',') }');
-jQuery('##{id_prefix}_comment_comment').val('');
-jQuery('##{id_prefix}_comment_comment').focus();
+$('##{id_prefix}_shown_notes').val('#{ j @comment.commentable.comment_ids.join(',') }');
+$('##{id_prefix}_comment_comment').val('');
+$('##{id_prefix}_comment_comment').focus();
+$('##{id_prefix}_post').find('form [type=submit]').removeAttr("disabled")
+$('##{id_prefix}_post').find('.spinner').hide()
diff --git a/app/views/comments/destroy.js.haml b/app/views/comments/destroy.js.haml
index 8deb326299..23e9e4e77d 100644
--- a/app/views/comments/destroy.js.haml
+++ b/app/views/comments/destroy.js.haml
@@ -1,5 +1,5 @@
- class_name = @comment.commentable.class.name.downcase
- id_prefix = "#{class_name}_#{@comment.commentable.id}"
-jQuery('##{id_prefix}_shown_notes').val('#{ j @comment.commentable.comment_ids.join(',') }');
-jQuery('##{dom_id(@comment)}').css('background-color', '#ffe4e1').slideUp(250);
+$('##{id_prefix}_shown_notes').val('#{ j @comment.commentable.comment_ids.join(',') }');
+$('##{dom_id(@comment)}').css('background-color', '#ffe4e1').slideUp(250);
diff --git a/app/views/comments/edit.js.haml b/app/views/comments/edit.js.haml
index 5074787ecb..e90095c387 100644
--- a/app/views/comments/edit.js.haml
+++ b/app/views/comments/edit.js.haml
@@ -1,11 +1,11 @@
- id = dom_id(@comment)
- if params[:cancel].true? # <----------------- Hide [Edit Comment]
- jQuery('##{id}').replaceWith('#{ j render(:partial => "comment", :collection => [ @comment ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => "comment", :collection => [ @comment ]) }');
- else # <----------------------------------------- Show [Edit Comment] form.
-# Disable onMouseOver for the list item.
crm.highlight_off('#{id}');
- jQuery('##{id}').html('#{ j render(:partial => "edit", :locals => { :commentable => @comment.commentable }) }');
- jQuery('##{dom_id(@comment, :text)}').focus();
+ $('##{id}').html('#{ j render(:partial => "edit", :locals => { :commentable => @comment.commentable }) }');
+ $('##{dom_id(@comment, :text)}').focus();
diff --git a/app/views/comments/new.js.haml b/app/views/comments/new.js.haml
deleted file mode 100644
index 6eb52c0192..0000000000
--- a/app/views/comments/new.js.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-- id_prefix = "#{@commentable}_" + params["#{@commentable}_id"]
-
-
-- if session["#{@commentable}_new_comment"]
- jQuery('##{id_prefix}_ask').hide();
- jQuery('##{id_prefix}_post').show();
- jQuery('##{id_prefix}_comment_comment').focus();
-- else
- jQuery('##{id_prefix}_post').hide();
- jQuery('##{id_prefix}_ask').show();
-
-
-crm.textarea_user_autocomplete('#{id_prefix}_comment_comment');
diff --git a/app/views/comments/update.js.haml b/app/views/comments/update.js.haml
index b16646fa30..d8ed0ced34 100644
--- a/app/views/comments/update.js.haml
+++ b/app/views/comments/update.js.haml
@@ -1,9 +1,9 @@
- id = dom_id(@comment)
- if @comment.errors.empty?
- jQuery('##{id}').replaceWith('#{ j render(:partial => "comment", :collection => [ @comment ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => "comment", :collection => [ @comment ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
- else
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#comment_comment').focus();
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('#comment_comment').focus();
diff --git a/app/views/contact_groups/index.js.haml b/app/views/contact_groups/index.js.haml
index 9b5aaae0f7..b93ec3887a 100644
--- a/app/views/contact_groups/index.js.haml
+++ b/app/views/contact_groups/index.js.haml
@@ -2,10 +2,10 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(@entities) }');
+ $('##{entities}').html('#{ j render(@entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
-jQuery('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
+$('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
diff --git a/app/views/contacts/_contacts.html.haml b/app/views/contacts/_contacts.html.haml
index 8f3ab238e0..e9fdc92402 100644
--- a/app/views/contacts/_contacts.html.haml
+++ b/app/views/contacts/_contacts.html.haml
@@ -9,9 +9,14 @@
%span.ui-icon-delete
:javascript
- new Form.Element.Observer('query', 1.5, function(element, value) {
- crm.search_show(value, "#{object.class.name.tableize}", "#{object.id}", "contacts");
+ var searchTimeout;
+
+ $('#query').on('keydown', function(event) {
+ $el = $(event.target)
+ if (searchTimeout) clearTimeout(searchTimeout);
+ searchTimeout = setTimeout(function () { crm.search_show($el.val(), "#{object.class.name.tableize}", "#{object.id}", "contacts"); }, 500);
});
+
#search_results_count{:style => "display:inline; margin-left: 5px"}
= image_tag("loading.gif", :size => :thumb, :id => "loading", :style => "display: none;")
@@ -22,4 +27,4 @@
- contacts = object.contacts.paginate(:page => 1, :per_page => 50)
= render :partial => "contacts/contact", :collection => contacts, :locals => {:object => object}
-= will_paginate contacts, :id => 'contacts_pagination', :params => {:action => :contacts}
+= paginate( collection: contacts, id: 'contacts_pagination', params: { action: 'contacts' } )
diff --git a/app/views/contacts/_index_brief.html.haml b/app/views/contacts/_index_brief.html.haml
index b6c437c026..4fd5e89f95 100644
--- a/app/views/contacts/_index_brief.html.haml
+++ b/app/views/contacts/_index_brief.html.haml
@@ -1,6 +1,6 @@
- object = defined?(object) ? object : nil
- registration = (object.present? && object.class == Event) ? object.registrations.find_by_contact_id(contact.id) : nil
-%li.highlight[contact]
+%li.draggable.highlight[contact]
= avatar_for(contact, :size => "16x16")
%ul.tools
@@ -44,4 +44,4 @@
== #{t :referred_by_small} #{lead.referred_by}
= hook(:contact_bottom, self, :contact => contact)
-= draggable_element(dom_id(contact), :revert => true, :handle => "'gravatar'", :scroll => "window")
\ No newline at end of file
+-#= draggable_element(dom_id(contact), :revert => true, :handle => "'gravatar'", :scroll => "window")
\ No newline at end of file
diff --git a/app/views/contacts/_index_full.html.haml b/app/views/contacts/_index_full.html.haml
index 5a83372bc1..2cbde5ec79 100644
--- a/app/views/contacts/_index_full.html.haml
+++ b/app/views/contacts/_index_full.html.haml
@@ -1,4 +1,4 @@
-%li.highlight[contact]
+%li.draggable.highlight[contact]
= avatar_for(contact, :size => "30x30")
%ul.tools
@@ -52,7 +52,7 @@
= image_tag "/assets/sub-ttm.png", :size => "14x11" if contact.cf_supporter_emails.include? "TT Mail"
= image_tag "/assets/sub-pp.png", :size => "14x11" if contact.cf_supporter_emails.include? "Prayer Points"
|
- = t(:added_ago, time_ago_in_words(contact.created_at))
+ = t(:added_ago, value: timeago(contact.created_at)).html_safe
- if contact.tag_list.present?
%dt
.tags= tags_for_index(contact)
@@ -66,4 +66,4 @@
= render "entities/section_custom_fields", :entity => contact
= render "comments/new", :commentable => contact
= render :partial => "shared/timeline", :collection => (contact.comments + contact.emails).sort { |x, y| y.created_at <=> x.created_at }
-= draggable_element(dom_id(contact), :revert => true, :handle => "'gravatar'", :scroll => "window")
\ No newline at end of file
+-#= draggable_element(dom_id(contact), :revert => true, :handle => "'gravatar'", :scroll => "window")
\ No newline at end of file
diff --git a/app/views/contacts/_index_long.html.haml b/app/views/contacts/_index_long.html.haml
index 7fe5309475..9888ab60f9 100644
--- a/app/views/contacts/_index_long.html.haml
+++ b/app/views/contacts/_index_long.html.haml
@@ -1,6 +1,6 @@
- object = defined?(object) ? object : nil
- registration = (object.present? && object.class == Event) ? object.registrations.find_by_contact_id(contact.id) : nil
-%li.highlight[contact]
+%li.draggable.highlight[contact]
= avatar_for(contact, :size => "30x30")
%ul.tools
= hook(:contact_tools_before, self, :contact => contact)
@@ -64,7 +64,7 @@
- assigned = User.find(contact.assigned_to) unless contact.assigned_to.blank?
- if assigned.present?
= "[#{link_to assigned.first_name, assigned}] |".html_safe
- = t(:added_ago, time_ago_in_words(contact.created_at))
+ = t(:added_ago, value: timeago(contact.created_at)).html_safe
= hook(:contact_bottom, self, :contact => contact)
-= draggable_element(dom_id(contact), :revert => true, :handle => "'gravatar'", :scroll => "window")
\ No newline at end of file
+-#= draggable_element(dom_id(contact), :revert => true, :handle => "'gravatar'", :scroll => "window")
\ No newline at end of file
diff --git a/app/views/contacts/_section_general.html.haml b/app/views/contacts/_section_general.html.haml
index de35105597..c9381fd0cc 100644
--- a/app/views/contacts/_section_general.html.haml
+++ b/app/views/contacts/_section_general.html.haml
@@ -15,8 +15,9 @@
= col(t(:assigned_to), assigned_to_user ? link_to(assigned_to_user.name, url_for(assigned_to_user)) : "")
%tr
= col(t(:tags), contact.tag_list.map{|tag| content_tag(:span, tag, :class => "fbtag")}.join(' '))
-
+
-# Show custom fields that are in the default field group
- - custom_field_group = contact.field_groups.select{|f| f.name == 'custom_fields'}
- - fields = custom_field_group.first.fields.without_pairs
- = render("fields/group_view", :fields => fields, :entity => contact) if fields.any?
+ - custom_field_group = contact.field_groups.select{|f| f.name == 'custom_fields'}.first
+ - if custom_field_group.present?
+ - fields = custom_field_group.fields.without_pairs
+ = render("fields/group_view", :fields => fields, :entity => contact) unless fields.nil?
diff --git a/app/views/contacts/_sidebar_index.html.haml b/app/views/contacts/_sidebar_index.html.haml
index 3836d14794..de7d2a0fde 100644
--- a/app/views/contacts/_sidebar_index.html.haml
+++ b/app/views/contacts/_sidebar_index.html.haml
@@ -6,13 +6,12 @@
= contact_folder_checbox_select("[all]", Account.my.all.collect{|a| a.id.to_s} + ["other"], "filter_label head_link") + " " + contact_folder_checbox_select("[mine]", Account.find_all_by_assigned_to(current_user.id).collect{|a| a.id.to_s}, "filter_label head_link")
= hook(:index_contact_sidebar_bottom, self)
- Account.my.each do |key|
- .check_box[key]{:style => "border-bottom: 1px silver dotted;"}
+ .droppable.check_box[key]{:style => "border-bottom: 1px silver dotted;"}
%div{:style => "float:right;"}
= @folder_total[key]
= contact_folder_checbox(key, @folder_total[key])
= label_folder_select(key, t(key.name))
- -#= drop_receiving_element(dom_id(key), :hoverclass => "dropover", :onDrop => "function(drag, drop, event) { crm.move_contact_to_account(drag, drop); }")
- = drop_receiving_element(dom_id(key), :hoverclass => "dropover", :accept => "contact", :url => {:controller => :accounts, :action => "move_contact", :id => key.id}, :with => "'contact_id=' + (element.id.split('_').last())")
+ -#= drop_receiving_element(dom_id(key), :hoverclass => "dropover", :accept => "contact", :url => {:controller => :accounts, :action => "move_contact", :id => key.id}, :with => "'contact_id=' + (element.id.split('_').last())")
.check_box{:style => "border-bottom: 1px silver dotted;"}
%div{:style => "float:right;"}
@@ -32,13 +31,12 @@
%div{ :style => "display:inline; font-size: 9px;"}
= contact_user_checbox_select("[all]", User.all.collect{|u| u.id.to_s} + ["other"], "filter_label head_link") + " " + contact_user_checbox_select("[me]", [current_user.id.to_s], "filter_label head_link")
- User.all.each do |key|
- .check_box[key]{:style => "border-bottom: 1px silver dotted;"}
+ .droppable.check_box[key]{:style => "border-bottom: 1px silver dotted;"}
%div{:style => "float:right;"}
= @user_total[key]
= user_contact_checbox(key, @user_total[key])
= label_user_select(key, t(key.name))
- -#= drop_receiving_element(dom_id(key), :hoverclass => "dropover", :onDrop => "function(drag, drop, event) { crm.move_contact_to_account(drag, drop); }")
- = drop_receiving_element(dom_id(key), :hoverclass => "dropover", :accept => "contact", :url => {:controller => :users, :action => "assign_contact", :id => key.id}, :with => "'contact_id=' + (element.id.split('_').last())")
+ -#= drop_receiving_element(dom_id(key), :hoverclass => "dropover", :accept => "contact", :url => {:controller => :users, :action => "move_contact", :id => key.id}, :with => "'contact_id=' + (element.id.split('_').last())")
.check_box{:style => "border-bottom: 1px silver dotted;"}
%div{:style => "float:right;"}
diff --git a/app/views/contacts/create.js.haml b/app/views/contacts/create.js.haml
index 3a3bf4ddab..9606e37ea8 100644
--- a/app/views/contacts/create.js.haml
+++ b/app/views/contacts/create.js.haml
@@ -3,27 +3,27 @@
- create_id = "create_#{entity_name}"
- if @entity.valid?
- jQuery('##{create_id}_arrow').html(crm.COLLAPSED);
- jQuery('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
- jQuery('##{create_id}').slideUp(250);
+ $('##{create_id}_arrow').html(crm.COLLAPSED);
+ $('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
+ $('##{create_id}').slideUp(250);
- if called_from_landing_page? :event_instances
- jQuery('##{entity_name.pluralize}').prepend('#{ j render(:partial => "event_instances/contact", :collection => [ @entity ]) }');
+ $('##{entity_name.pluralize}').prepend('#{ j render(:partial => "event_instances/contact", :collection => [ @entity ]) }');
- else
- jQuery('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
+ $('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
- if called_from_index_page?
= refresh_sidebar(:index)
- jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
- else
- jQuery('#recently').html('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
crm.flick('empty', 'remove');
- if called_from_landing_page? :contact_groups
- jQuery('#email_group_link').html('#{mail_to(@current_user.email, "Email group", :bcc => @contact_group.email_addresses)} | ');
+ $('#email_group_link').html('#{mail_to(@current_user.email, "Email group", :bcc => @contact_group.email_addresses)} | ');
- else
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('##{create_id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('##{create_id}').effect("shake", { duration:250, distance: 6 });
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/contacts/destroy.js.haml b/app/views/contacts/destroy.js.haml
index cefe49ff2b..822982072f 100644
--- a/app/views/contacts/destroy.js.haml
+++ b/app/views/contacts/destroy.js.haml
@@ -1,12 +1,12 @@
- entity_name = controller.controller_name.singularize.underscore
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
+$('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
- else
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- if called_from_landing_page? :contact_groups
- jQuery('#email_group_link').html('#{mail_to(@current_user.email, "Email group", :bcc => @contact_group.email_addresses)} | ');
+ $('#email_group_link').html('#{mail_to(@current_user.email, "Email group", :bcc => @contact_group.email_addresses)} | ');
diff --git a/app/views/contacts/edit.js.haml b/app/views/contacts/edit.js.haml
index 1b73e93cb6..ac3ee0efc4 100644
--- a/app/views/contacts/edit.js.haml
+++ b/app/views/contacts/edit.js.haml
@@ -9,9 +9,9 @@
crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
- else # Called from index page...
- if called_from_landing_page? :event_instances
- jQuery('##{id}').replaceWith('#{ j render(:partial => "event_instances/contact", :collection => [ @entity ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => "event_instances/contact", :collection => [ @entity ]) }');
- else
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- else # <----------------------------------------- Show [Edit Contact] form.
@@ -19,7 +19,7 @@
- if params[:cancel].blank? # Called from contacts list item...
- if @previous # Hide open [Edit Contact] form if any.
- if @previous.is_a?(Contact)
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
- else
crm.flick('#{entity_name}_#{@previous}', 'remove');
-# Disable onMouseOver for the list item.
@@ -27,12 +27,12 @@
-# Hide [Create] form if any.
crm.hide_form('create_#{entity_name}');
-# Show [Edit] form.
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').html('#{ j render(:partial => "edit") }');
- elsif params[:cancel].false? # Called from title of the contact landing page...
- jQuery('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
+ $('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', "#{t :edit} #{h @entity.full_name}");
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/contacts/index.js.haml b/app/views/contacts/index.js.haml
index 9b5aaae0f7..b93ec3887a 100644
--- a/app/views/contacts/index.js.haml
+++ b/app/views/contacts/index.js.haml
@@ -2,10 +2,10 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(@entities) }');
+ $('##{entities}').html('#{ j render(@entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
-jQuery('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
+$('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
diff --git a/app/views/contacts/index.xls.builder b/app/views/contacts/index.xls.builder
index f10a6e2d17..d9df8a6bb4 100644
--- a/app/views/contacts/index.xls.builder
+++ b/app/views/contacts/index.xls.builder
@@ -3,7 +3,8 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_contacts) do
unless @contacts.empty?
# Header.
xml.Row do
- heads = [I18n.t('lead'),
+ heads = [I18n.t('id'),
+ I18n.t('lead'),
I18n.t('job_title'),
I18n.t('name'),
I18n.t('first_name'),
@@ -34,12 +35,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_contacts) do
I18n.t('zipcode'),
I18n.t('country'),
I18n.t('address')]
-
+
# Append custom field labels to header
Contact.fields.each do |field|
heads << field.label
end
-
+
heads.each do |head|
xml.Cell do
xml.Data head,
@@ -47,12 +48,13 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_contacts) do
end
end
end
-
+
# Contact rows.
@contacts.each do |contact|
xml.Row do
address = contact.business_address
- data = [contact.lead.try(:name),
+ data = [contact.id,
+ contact.lead.try(:name),
contact.title,
contact.name,
contact.first_name,
@@ -83,12 +85,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_contacts) do
address.try(:zipcode),
address.try(:country),
address.try(:full_address)]
-
+
# Append custom field values.
Contact.fields.each do |field|
data << contact.send(field.name)
end
-
+
data.each do |value|
xml.Cell do
xml.Data value,
diff --git a/app/views/contacts/new.js.haml b/app/views/contacts/new.js.haml
index f70129b0f1..afb9506052 100644
--- a/app/views/contacts/new.js.haml
+++ b/app/views/contacts/new.js.haml
@@ -5,7 +5,7 @@ crm.flick('empty', 'toggle');
crm.flip_form('#{create_id}');
- unless params[:cancel].true?
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
crm.set_title('#{create_id}', '#{ j t(create_id) }');
-# this function call is the only difference to normal new.js.haml
-# change default behaviour so that the select box is shown by default
diff --git a/app/views/contacts/show.js.haml b/app/views/contacts/show.js.haml
index 9de37976c9..3acbc11e24 100644
--- a/app/views/contacts/show.js.haml
+++ b/app/views/contacts/show.js.haml
@@ -1,5 +1,5 @@
- entity_name = controller.controller_name.singularize.underscore #account
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
+$('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
= raw generate_js_for_popups(@entity, :tasks, :opportunities)
diff --git a/app/views/contacts/update.js.haml b/app/views/contacts/update.js.haml
index 79dfa24ca3..5639b4989b 100644
--- a/app/views/contacts/update.js.haml
+++ b/app/views/contacts/update.js.haml
@@ -10,21 +10,21 @@
= refresh_sidebar(:show, :summary)
- else
- if called_from_landing_page? :event_instances
- jQuery('##{id}').replaceWith('#{ j render(:partial => "event_instances/contact", :collection => [ @entity ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => "event_instances/contact", :collection => [ @entity ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
- else
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
- if called_from_landing_page? :contact_groups
- jQuery('#email_group_link').html('#{mail_to(@current_user.email, "Email group", :bcc => @contact_group.email_addresses)} | ');
+ $('#email_group_link').html('#{mail_to(@current_user.email, "Email group", :bcc => @contact_group.email_addresses)} | ');
- if called_from_index_page?
= refresh_sidebar(:index)
- else
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- else
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').html('#{ j render(:partial => "edit") }');
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
diff --git a/app/views/emails/destroy.js.haml b/app/views/emails/destroy.js.haml
index b1cd2529fb..af915e892a 100644
--- a/app/views/emails/destroy.js.haml
+++ b/app/views/emails/destroy.js.haml
@@ -1,5 +1,5 @@
- class_name = @email.mediator.class.name.downcase
- id_prefix = "#{class_name}_#{@email.mediator.id}"
-jQuery('##{id_prefix}_shown_emails').val('#{ j @email.mediator.email_ids.join(',') }');
-jQuery('##{dom_id(@email)}').css('background-color', '#ffe4e1').slideUp(250);
+$('##{id_prefix}_shown_emails').val('#{ j @email.mediator.email_ids.join(',') }');
+$('##{dom_id(@email)}').css('background-color', '#ffe4e1').slideUp(250);
diff --git a/app/views/entities/_basic_search.html.haml b/app/views/entities/_basic_search.html.haml
index cd44fc931d..dc74562e00 100644
--- a/app/views/entities/_basic_search.html.haml
+++ b/app/views/entities/_basic_search.html.haml
@@ -10,16 +10,19 @@
%span.sorting_options
-# sort_by_displaying: Sort {{models}} by {{field}} displaying first name {{position}} last name.
= t(:sort_by, :models => t(:"#{controller_name}_small"), :field => link_to(current_sort_by, "#", :id => :sort_by)).html_safe
-
- :javascript
- new Form.Element.Observer('query', 1.5, function(element, value) {
- crm.search(value, '#{controller_name}');
- });
- :javascript
- new crm.Menu({
- trigger : "sort_by",
- fade : 0.5,
- appear : 0.5,
- menu_items: [ #{sort_by_menu_items.join(",")} ]
- });
+:javascript
+ var searchTimeout;
+
+ $('#query').on('keydown', function(event) {
+ $el = $(event.target)
+ if (searchTimeout) clearTimeout(searchTimeout);
+ searchTimeout = setTimeout(function () { crm.search($el.val(), '#{controller_name}'); }, 500);
+ });
+
+ new crm.Menu({
+ trigger : "#sort_by",
+ fade : 500,
+ appear : 500,
+ menu_items: [ #{sort_by_menu_items.join(",")} ]
+ });
diff --git a/app/views/entities/_permissions.html.haml b/app/views/entities/_permissions.html.haml
index 2ff1b9905b..14ea4362ba 100644
--- a/app/views/entities/_permissions.html.haml
+++ b/app/views/entities/_permissions.html.haml
@@ -1,7 +1,5 @@
- edit ||= false
--# model = entity.class.name.downcase
-- model = entity.class.name.underscore # needed for names with underscores
-
+- model = entity.class.name.underscore
- collapsed = session[:entity_permissions].nil?
= subtitle :entity_permissions, collapsed, t(:permissions)
.section
@@ -9,13 +7,13 @@
= get_default_permissions_intro(entity.access, t("#{model}_small")) unless edit
#entity_permissions{ hidden_if(collapsed) }
.radio_box
- = f.radio_button :access, "Private", :onclick => "$('people').hide()"
+ = f.radio_button :access, "Private", :onclick => "$('#people').hide()"
= f.label :access_private, t(:keep_private), :style => "cursor:pointer"
.radio_box
- = f.radio_button :access, "Public", :onclick => "$('people').hide()"
+ = f.radio_button :access, "Public", :onclick => "$('#people').hide()"
= f.label :access_public, t(:make_public), :style => "cursor:pointer"
.radio_box
- = f.radio_button :access, "Shared", :onclick => "$('people').show()"
+ = f.radio_button :access, "Shared", :onclick => "$('#people').show()"
= f.label :access_shared, t(:share_with), :style => "cursor:pointer"
#people{ hidden_if(entity.access != "Shared") }
@@ -24,20 +22,15 @@
%td
= f.label :user_ids, "#{t(:users)}:"
%br
- = f.select :user_ids, user_options, {}, :multiple => true
- :javascript
- new Chosen($('#{model}_user_ids'));
-
+ = f.select :user_ids, user_options, {}, :multiple => true, :class => 'select2'
%tr
%td
= f.label :group_ids, "#{t(:groups)}:"
%br
- = f.select :group_ids, group_options, {}, :multiple => true
- :javascript
- new Chosen($('#{model}_group_ids'));
+ = f.select :group_ids, group_options, {}, :multiple => true, :class => 'select2'
- if !edit and entity.is_a?(Lead)
.radio_box
- = f.radio_button :access, t(:campaign), :onclick => "$('people').hide(); $('lead_access_campaign').value = 'Campaign'", :disabled => true
+ = f.radio_button :access, t(:campaign), :onclick => "$('#people').hide(); $('#lead_access_campaign').val('Campaign');", :disabled => true
%font{ :id => :copy_permissions, :color => :grey }
= t(:copy_permissions, t(:campaign_small))
diff --git a/app/views/entities/attach.js.haml b/app/views/entities/attach.js.haml
index d88f7fa22d..58595540e6 100644
--- a/app/views/entities/attach.js.haml
+++ b/app/views/entities/attach.js.haml
@@ -8,7 +8,7 @@
- view = "pending"
- else
- view = "assigned"
- jQuery('#tasks').prepend('#{ j render(:partial => "tasks/#{view}", :collection => [ @attachment ], :locals => { :bucket => @attachment.computed_bucket }) }');
+ $('#tasks').prepend('#{ j render(:partial => "tasks/#{view}", :collection => [ @attachment ], :locals => { :bucket => @attachment.computed_bucket }) }');
- else
@@ -16,16 +16,16 @@
-# we want selecting attendees on this page to act like you've marked them as attended.
-# If they're already on the page, replace, checked and green background
-# otherwise, add to the top of the list, checked and green background
- if (jQuery('##{dom_id(@attachment)}').length > 0) {
- jQuery('##{dom_id(@attachment)}').replaceWith('#{ j render(:partial => "event_instances/#{partial}", :collection => [ @attachment ], :locals => {:object => @event_instance}) }');
+ if ($('##{dom_id(@attachment)}').length > 0) {
+ $('##{dom_id(@attachment)}').replaceWith('#{ j render(:partial => "event_instances/#{partial}", :collection => [ @attachment ], :locals => {:object => @event_instance}) }');
} else {
- jQuery('##{h params[:assets]}').prepend('#{ j render(:partial => "event_instances/#{partial}", :collection => [ @attachment ], :locals => {:object => @event_instance}) }');
+ $('##{h params[:assets]}').prepend('#{ j render(:partial => "event_instances/#{partial}", :collection => [ @attachment ], :locals => {:object => @event_instance}) }');
}
- else
- jQuery('##{h params[:assets]}').prepend('#{ j render(:partial => "#{params[:assets]}/#{partial}", :collection => [ @attachment ]) }');
+ $('##{h params[:assets]}').prepend('#{ j render(:partial => "#{params[:assets]}/#{partial}", :collection => [ @attachment ]) }');
- if called_from_landing_page?(:accounts)
= refresh_sidebar_for(:accounts, :show, :summary)
- elsif called_from_landing_page?(:campaigns)
= refresh_sidebar_for(:campaigns, :show, :summary)
-jQuery('##{partial}_#{h params[:asset_id]}').effect("highlight", { duration:1500 });
+$('##{partial}_#{h params[:asset_id]}').effect("highlight", { duration:1500 });
diff --git a/app/views/entities/contacts.js.haml b/app/views/entities/contacts.js.haml
index df45dd4b2e..2998682863 100755
--- a/app/views/entities/contacts.js.haml
+++ b/app/views/entities/contacts.js.haml
@@ -1,3 +1,3 @@
- contacts = entity.contacts.order('updated_at DESC').paginate(:page => params[:page], :per_page => 20)
-jQuery('#contacts').html('#{ j render(:partial => 'contacts/contact', :collection => contacts) }');
-jQuery('#contacts_pagination').html('#{ j will_paginate(contacts, :container => false, :params => {:action => :contacts}) }');
+$('#contacts').html('#{ j render(:partial => 'contacts/contact', :collection => contacts) }');
+$('#contacts_pagination').html('#{ j paginate(collection: contacts, container: false, params: { action: 'contacts' } ) }');
diff --git a/app/views/entities/discard.js.haml b/app/views/entities/discard.js.haml
index 5052cc003c..80b0eb7968 100644
--- a/app/views/entities/discard.js.haml
+++ b/app/views/entities/discard.js.haml
@@ -1,4 +1,4 @@
-jQuery('##{dom_id(@attachment)}').slideUp(250);
+$('##{dom_id(@attachment)}').slideUp(250);
- if called_from_landing_page?(:accounts)
= refresh_sidebar_for(:accounts, :show, :summary)
diff --git a/app/views/entities/leads.js.haml b/app/views/entities/leads.js.haml
index f833e96b29..e16ee2119d 100755
--- a/app/views/entities/leads.js.haml
+++ b/app/views/entities/leads.js.haml
@@ -1,3 +1,3 @@
- leads = entity.leads.order('updated_at DESC').paginate(:page => params[:page], :per_page => 20)
-jQuery('#leads').html('#{ j render(:partial => 'leads/lead', :collection => leads) }');
-jQuery('#leads_pagination').replaceWith('#{ j will_paginate(leads, :container => false, :params => {:action => :leads}) }');
+$('#leads').html('#{ j render(:partial => 'leads/lead', :collection => leads) }');
+$('#leads_pagination').html('#{ j paginate(collection: leads, container: false, params: { action: 'leads' } ) }');
diff --git a/app/views/entities/opportunities.js.haml b/app/views/entities/opportunities.js.haml
index 20b3b7bd33..426c7f673d 100755
--- a/app/views/entities/opportunities.js.haml
+++ b/app/views/entities/opportunities.js.haml
@@ -1,3 +1,3 @@
- opportunities = entity.opportunities.order('updated_at DESC').paginate(:page => params[:page], :per_page => 20)
-jQuery('#opportunities').html('#{ j render(:partial => 'opportunities/opportunity', :collection => opportunities) }');
-jQuery('#opportunities_pagination').html('#{ j will_paginate(opportunities, :container => false, :params => {:action => :opportunities}) }');
+$('#opportunities').html('#{ j render(:partial => 'opportunities/opportunity', :collection => opportunities) }');
+$('#opportunities_pagination').html('#{ j paginate(collection: opportunities, container: false, params: { action: 'opportunities' } ) }');
diff --git a/app/views/entities/subscription_update.js.haml b/app/views/entities/subscription_update.js.haml
index 91d1503507..29ab2583bf 100644
--- a/app/views/entities/subscription_update.js.haml
+++ b/app/views/entities/subscription_update.js.haml
@@ -1,4 +1,4 @@
- class_name = entity.class.name.underscore
- id = "#{class_name}_#{entity.id}_subscribe"
-jQuery('##{id}').html('#{ j render(:partial => "comments/subscription_links", :locals => {:entity => entity}) }');
+$('##{id}').html('#{ j render(:partial => "comments/subscription_links", :locals => {:entity => entity}) }');
diff --git a/app/views/entities/versions.js.haml b/app/views/entities/versions.js.haml
index 6d16a8b6e7..29e07754ca 100644
--- a/app/views/entities/versions.js.haml
+++ b/app/views/entities/versions.js.haml
@@ -1,3 +1,3 @@
- versions = Version.history(entity).paginate(:page => params[:page], :per_page => 20)
-jQuery('#versions .list').html('#{ j(render :partial => 'versions/version', :collection => versions) }')
-jQuery('#versions_pagination').html('#{ j will_paginate(versions, :container => false, :params => {:action => :versions}) }')
+$('#versions .list').html('#{ j(render :partial => 'versions/version', :collection => versions) }')
+$('#versions_pagination').html('#{ j paginate(collection: versions, container: false, params: { action: 'versions' } ) }')
diff --git a/app/views/event_instances/_contact.html.haml b/app/views/event_instances/_contact.html.haml
index 741053e25b..9434d8ad23 100644
--- a/app/views/event_instances/_contact.html.haml
+++ b/app/views/event_instances/_contact.html.haml
@@ -6,8 +6,8 @@
%ul.tools
-#= hook(:contact_tools_before, self, :contact => contact)
- - if can?(:update, contact)
- = link_to_edit(contact, :related => "event_instance_#{@event_instance.id}")
+ -# if can?(:update, contact)
+ -# = link_to_edit(contact, :related => "event_instance_#{@event_instance.id}")
-# - if can?(:destroy, contact)
-# = link_to_delete(contact)
diff --git a/app/views/event_instances/_top_section.html.haml b/app/views/event_instances/_top_section.html.haml
index 7c692d7624..a21b796629 100644
--- a/app/views/event_instances/_top_section.html.haml
+++ b/app/views/event_instances/_top_section.html.haml
@@ -8,9 +8,14 @@
- tfmt = '%I:%M%P'
%td(colspan="5")
.datetime
- %p.datepair
+ %p.datepair{"data-language" => "javascript"}
= e.text_field :calendar_start_date, :style => "width:90px;", :autocomplete => :off, :class => 'date start'
- = e.text_field :calendar_start_time, :style => "width:90px;", :autocomplete => :off, :class => 'time start'
+ = e.text_field :calendar_start_time, :style => "width:90px;", :autocomplete => :off, :class => 'time start ui-timepicker-input'
= " ".html_safe + 'to' +" ".html_safe
- = e.text_field :calendar_end_time, :style => "width:90px;", :autocomplete => :off, :class => 'time end'
- = e.text_field :calendar_end_date, :style => "width:90px;", :autocomplete => :off, :class => 'date end'
\ No newline at end of file
+ = e.text_field :calendar_end_time, :style => "width:90px;", :autocomplete => :off, :class => 'time end ui-timepicker-input'
+ = e.text_field :calendar_end_date, :style => "width:90px;", :autocomplete => :off, :class => 'date end'
+
+:javascript
+ $( document ).ready(function() {
+ attachDate();
+ });
\ No newline at end of file
diff --git a/app/views/event_instances/_top_section_single.html.haml b/app/views/event_instances/_top_section_single.html.haml
index bbd4207418..53fb3411c2 100644
--- a/app/views/event_instances/_top_section_single.html.haml
+++ b/app/views/event_instances/_top_section_single.html.haml
@@ -11,9 +11,14 @@
- tfmt = '%I:%M%P'
%td(colspan="5")
.datetime
- %p.datepair
+ %p.datepair{"data-language" => "javascript"}
= f.text_field :calendar_start_date, :style => "width:90px;", :autocomplete => :off, :class => 'date start', :value => @event_instance.starts_at_date
- = f.text_field :calendar_start_time, :style => "width:90px;", :autocomplete => :off, :class => 'time start', :value => @event_instance.starts_at_time
+ = f.text_field :calendar_start_time, :style => "width:90px;", :autocomplete => :off, :class => 'time start ui-timepicker-input', :value => @event_instance.starts_at_time
= " ".html_safe + 'to' +" ".html_safe
- = f.text_field :calendar_end_time, :style => "width:90px;", :autocomplete => :off, :class => 'time end', :value => @event_instance.ends_at_time
- = f.text_field :calendar_end_date, :style => "width:90px;", :autocomplete => :off, :class => 'date end', :value => @event_instance.ends_at_date
\ No newline at end of file
+ = f.text_field :calendar_end_time, :style => "width:90px;", :autocomplete => :off, :class => 'time end ui-timepicker-input', :value => @event_instance.ends_at_time
+ = f.text_field :calendar_end_date, :style => "width:90px;", :autocomplete => :off, :class => 'date end', :value => @event_instance.ends_at_date
+
+:javascript
+ $( document ).ready(function() {
+ attachDate();
+ });
\ No newline at end of file
diff --git a/app/views/events/_top_section.html.haml b/app/views/events/_top_section.html.haml
index e6a2f0a2ac..3f06526ae7 100644
--- a/app/views/events/_top_section.html.haml
+++ b/app/views/events/_top_section.html.haml
@@ -18,7 +18,7 @@
%td
.label
= "Each week during "
- = select_tag :repeat_pattern, options_for_select([["Semester 1 (Adelaide)","S1-adl"],["Semester 2 (Adelaide)","S2-adl"],["Semester 1 (UniSa)","S1-usa"],["Semester 2 (UniSA)","S2-usa"]]), :style => "width:90px;display:inline;"
+ = select_tag :repeat_pattern, options_for_select([["Semester 1 (Adelaide)","S1-adl"],["Semester 2 (Adelaide)","S2-adl"],["Semester 1 (UniSa)","S1-usa"],["Semester 2 (UniSA)","S2-usa"]]), class: "select2", style: "display:inline"
%tr
%td
.label
@@ -31,15 +31,15 @@
%td= spacer
%td
.label #{t :category}:
- = f.select :category, Setting.unroll(:event_category), { :selected => (@event.category || "other").to_sym, :include_blank => t(:other) }, { :style => "width:160px" }
+ = f.select :category, Setting.unroll(:event_category), { :selected => (@event.category || "other").to_sym, :include_blank => t(:other) }, { class: "select2", :style => "width:160px" }
%tr
%td
.label #{t :semester}:
- = f.select :semester, [["1","1"],["2","2"]], {} , {:style => "width:160px"}
+ = f.select :semester, [["1","1"],["2","2"]], {} , {class: "select2", :style => "width:160px"}
%td= spacer
%td
.label #{t :contact_group}:
- = f.select :contact_group_id, ContactGroup.all.map{ |cg| [cg.name, cg.id]}, { :selected => (@contact_group ? @contact_group.id : "None"), :include_blank => t(:none) }, { :style => "width:160px", :class => 'chzn-select' }
+ = f.select :contact_group_id, ContactGroup.all.map{ |cg| [cg.name, cg.id]}, { :selected => (@contact_group ? @contact_group.id : "None"), :include_blank => t(:none) }, { :style => "width:160px", :class => 'select2' }
- if Setting.background_info && Setting.background_info.include?(:event)
%tr
%td(colspan="5")
diff --git a/app/views/events/index.js.haml b/app/views/events/index.js.haml
index bd1ae51a20..2136135b09 100644
--- a/app/views/events/index.js.haml
+++ b/app/views/events/index.js.haml
@@ -2,9 +2,9 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(:partial => "event", :collection => @entities) }');
+ $('##{entities}').html('#{ j render(:partial => "event", :collection => @entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
\ No newline at end of file
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
\ No newline at end of file
diff --git a/app/views/fields/group.js.erb b/app/views/fields/group.js.erb
index 8a67e8d2c7..e27be41871 100644
--- a/app/views/fields/group.js.erb
+++ b/app/views/fields/group.js.erb
@@ -1,3 +1,3 @@
<%= simple_fields_for(@asset) do |f| %>
- jQuery('#field_groups').append('<%= j render(:partial => 'fields/group', :locals => {:f => f, :field_group => @field_group, :fields => @field_group.fields}) %>')
+ $('#field_groups').append('<%= j render(:partial => 'fields/group', :locals => {:f => f, :field_group => @field_group, :fields => @field_group.fields}) %>')
<% end %>
diff --git a/app/views/home/_account.html.haml b/app/views/home/_account.html.haml
index 4fa7e63f8d..27ff582a31 100644
--- a/app/views/home/_account.html.haml
+++ b/app/views/home/_account.html.haml
@@ -10,11 +10,11 @@
–
%tt
= account.location << ", " unless account.location.blank?
- - user_name = account.user_id == current_user.id ? t(:me) : account.user.try(:full_name)
+ - user_name = account.user.try(:full_name)
- if user_name
- = t(:added_by, :time_ago => time_ago_in_words(account.created_at), :user => user_name)
+ = t(:added_by, :time_ago => timeago(account.created_at), :user => h(user_name)).html_safe
- else
- = t(:added_ago, :value => time_ago_in_words(account.created_at))
+ = t(:added_ago, :value => timeago(account.created_at)).html_safe
- unless current_user.preference[:accounts_index_view] == "accounts_index_brief"
%dt
diff --git a/app/views/home/_assets_menu.html.haml b/app/views/home/_assets_menu.html.haml
index 017c82b80e..6551f9c5af 100644
--- a/app/views/home/_assets_menu.html.haml
+++ b/app/views/home/_assets_menu.html.haml
@@ -1,7 +1,7 @@
:plain
new crm.Menu({
- trigger : "asset",
- fade : 0.5,
- appear : 0.5,
+ trigger : "#asset",
+ fade : 500,
+ appear : 500,
menu_items: [ #{sort_by_assets.join(",")} ]
});
diff --git a/app/views/home/_duration_menu.html.haml b/app/views/home/_duration_menu.html.haml
index 8b7cfec0f0..5fd41fbb96 100644
--- a/app/views/home/_duration_menu.html.haml
+++ b/app/views/home/_duration_menu.html.haml
@@ -1,8 +1,8 @@
:plain
new crm.Menu({
- trigger : "duration",
- fade : 0.5,
- appear : 0.5,
+ trigger : "#duration",
+ fade : 500,
+ appear : 500,
width : 165,
menu_items: [ #{sort_by_duration.join(",")} ]
});
diff --git a/app/views/home/_events_menu.html.haml b/app/views/home/_events_menu.html.haml
index 0c1fd01a19..2dc4b02e4d 100644
--- a/app/views/home/_events_menu.html.haml
+++ b/app/views/home/_events_menu.html.haml
@@ -1,8 +1,8 @@
:plain
new crm.Menu({
- trigger : "event",
- fade : 0.5,
- appear : 0.5,
+ trigger : "#event",
+ fade : 500,
+ appear : 500,
menu_items: [ #{sort_by_events.join(",")} ]
});
diff --git a/app/views/home/_opportunity.html.haml b/app/views/home/_opportunity.html.haml
index 9cc028aad1..0fa7bb10e1 100644
--- a/app/views/home/_opportunity.html.haml
+++ b/app/views/home/_opportunity.html.haml
@@ -10,11 +10,11 @@
== #{t :from} #{link_to(h(opportunity.account.name), account_path(opportunity.account))}
%tt
–
- - user_name = opportunity.user_id == current_user.id ? t(:me) : opportunity.user.try(:full_name)
+ - user_name = opportunity.user.try(:full_name)
- if user_name
- = t(:added_by, :time_ago => time_ago_in_words(opportunity.created_at), :user => user_name)
+ = t(:added_by, :time_ago => timeago(opportunity.created_at), :user => h(user_name)).html_safe
- else
- = t(:added_ago, :value => time_ago_in_words(opportunity.created_at))
+ = t(:added_ago, :value => timeago(opportunity.created_at)).html_safe
- unless current_user.preference[:opportunities_index_view] == "opportunities_index_brief"
%dt
%b= number_to_currency(opportunity.weighted_amount, :precision => 0) + " | "
diff --git a/app/views/home/_options.html.haml b/app/views/home/_options.html.haml
index 3268f2d786..c899bbc038 100644
--- a/app/views/home/_options.html.haml
+++ b/app/views/home/_options.html.haml
@@ -4,7 +4,6 @@
-# activity_options: Show %{models} %{action_type} performed by %{user} in the past %{period}
= t(:activity_options, :models => link_to(t(@asset).singularize.downcase, "#", :id => :asset), :action_type => link_to(t(@action + "_past_participle").downcase, "#", :id => :event), :user => link_to(t(@user), "#", :id => :user), :period => link_to(t(@duration).downcase, "#", :id => :duration)).html_safe
-%p
%script
= render "assets_menu"
diff --git a/app/views/home/_users_menu.html.haml b/app/views/home/_users_menu.html.haml
index a35c8f96f4..38e993056f 100644
--- a/app/views/home/_users_menu.html.haml
+++ b/app/views/home/_users_menu.html.haml
@@ -1,8 +1,8 @@
:plain
new crm.Menu({
- trigger : "user",
- fade : 0.5,
- appear : 0.5,
+ trigger : "#user",
+ fade : 500,
+ appear : 500,
width : 180,
menu_items: [ #{sort_by_users.join(",")} ]
});
diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml
index 6c37c39718..0606fd86e1 100644
--- a/app/views/home/index.html.haml
+++ b/app/views/home/index.html.haml
@@ -54,8 +54,5 @@
#{t :no_activity_records}
- #export= render "shared/export"
-/
- Check out HTML source to view the output of the hook if you have sample plugin installed
- http://github.com/michaeldv/crm_sample_plugin/tree/master
- = hook(:home_view, self, :hello => "world!", :welcome => "home")
+
+#export= render "shared/export"
diff --git a/app/views/home/index.js.haml b/app/views/home/index.js.haml
index d956eda786..d99e67221c 100644
--- a/app/views/home/index.js.haml
+++ b/app/views/home/index.js.haml
@@ -1,7 +1,7 @@
- unless @activities.blank?
- jQuery('#activities').html('#{ j render(:partial => "activity", :collection => @activities) }');
+ $('#activities').html('#{ j render(:partial => "activity", :collection => @activities) }');
- else
- jQuery('#activities').html('#{ j t(:no_activity_records) }');
+ $('#activities').html('#{ j t(:no_activity_records) }');
--# jQuery('#paginate').html('#{ j render(:partial => "shared/paginate") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
+-# $('#paginate').html('#{ j render(:partial => "shared/paginate") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
diff --git a/app/views/home/options.js.haml b/app/views/home/options.js.haml
index 6d244b179e..309ee80c6e 100644
--- a/app/views/home/options.js.haml
+++ b/app/views/home/options.js.haml
@@ -1,7 +1,7 @@
crm.flip_form('options');
- unless params[:cancel].true?
- jQuery('#options').html('#{ j render(:partial => "options") }');
+ $('#options').html('#{ j render(:partial => "options") }');
crm.set_title('title', '#{ j t(:recent_activity_options) }');
- else
crm.set_title('title', '#{ j t(:recent_activity) }');
diff --git a/app/views/layouts/_about.html.haml b/app/views/layouts/_about.html.haml
index 9853fa5304..da38638a20 100644
--- a/app/views/layouts/_about.html.haml
+++ b/app/views/layouts/_about.html.haml
@@ -1,7 +1,7 @@
#about{ hidden }
%h3
#{t :about_ffc_version}
- %span.cool== v#{FatFreeCRM::VERSION}
+ %span.cool== v#{FatFreeCRM::VERSION::STRING}
== (#{ActiveRecord::Base.connection.adapter_name.downcase})
%p
#{t :about_thank_you}
@@ -9,8 +9,8 @@
#{t :about_ffc_resources}:
%ul{:style => "margin: 0px 0px 0px 15px"}
%li== » #{link_to t(:about_home_page), "http://www.fatfreecrm.com", :"data-popup" => true}
- %li== » #{link_to t(:about_project_page), "http://github.com/michaeldv/fat_free_crm/tree/master", :"data-popup" => true}
- %li== » #{link_to t(:about_features), "http://fatfreecrm.lighthouseapp.com", :"data-popup" => true}
+ %li== » #{link_to t(:about_project_page), "http://github.com/fatfreecrm/fat_free_crm/tree/master", :"data-popup" => true}
+ %li== » #{link_to t(:about_features), "http://github.com/fatfreecrm/fat_free_crm/issues", :"data-popup" => true}
%li== » #{link_to t(:about_twitter), "http://twitter.com/fatfreecrm", :"data-popup" => true}
%li== » #{link_to t(:about_user_group), "http://groups.google.com/group/fat-free-crm-users", :"data-popup" => true}
%li== » #{link_to t(:about_dev_group), "http://groups.google.com/group/fat-free-crm-dev", :"data-popup" => true}
diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml
index e0b04552e3..57399f6124 100644
--- a/app/views/layouts/_footer.html.haml
+++ b/app/views/layouts/_footer.html.haml
@@ -1,13 +1,9 @@
#footer
Powered by #{link_to "Fat Free CRM", "http://www.fatfreecrm.com", :"data-popup" => true }
v#{FatFreeCRM::VERSION::STRING} © 2008-#{Date.today.year} by Michael Dvorkin and contributors.
- \|
- = image_tag "iconset_attribution.png"
- Icons from the
- = link_to 'Gentleface Mono Icon Set', "http://gentleface.com/free_icon_set.html"
- unless tabless_layout?
\|
- = link_to(t(:about_ffc), "#", :title => t(:about_ffc), :onclick => "Modalbox.show($('about'), { title: this.title }); return false;")
+ = link_to(t(:about_ffc), "#", :title => t(:about_ffc), :onclick => "$('#about').dialog({ title: this.title, modal: true }); return false;")
%br
= render "layouts/about"
diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml
index 99a1187205..dd5dd5c9f3 100644
--- a/app/views/layouts/_header.html.haml
+++ b/app/views/layouts/_header.html.haml
@@ -15,7 +15,7 @@
- else
= link_to(t(:login), login_path) << " |"
= link_to(t(:sign_up), signup_path) << " |" if can_signup?
- = link_to(t(:about), "#", :title => t(:about_ffc), :onclick => "Modalbox.show($('about'), { title: this.title }); return false;")
+ = link_to(t(:about), "#", :title => t(:about_ffc), :onclick => "$('#about').dialog({ title: this.title, modal: true }); return false;")
%h3
-#= image_tag 'alpaca__r147276291.gif'
-#= image_tag 'logo.png'
diff --git a/app/views/layouts/_jumpbox.html.haml b/app/views/layouts/_jumpbox.html.haml
index 5cda222ad4..b0620807e6 100644
--- a/app/views/layouts/_jumpbox.html.haml
+++ b/app/views/layouts/_jumpbox.html.haml
@@ -1,28 +1,30 @@
- current_auto_complete = session[:auto_complete] || :contacts
= content_for(:javascript_epilogue) do
:plain
- document.observe("dom:loaded", function() {
- new crm.Popup({
- trigger : "jumper",
- target : "jumpbox",
- under : "welcome",
- appear : 0.3,
- fade : 0.3,
- before_show : function() {
- $("jumper").className = "selected";
- $("jumpbox_label").innerHTML = ""
- $("jumpbox_label").hide();
- $("jumpbox_menu").show();
- crm.auto_complete("#{current_auto_complete}");
- },
- after_show : function() {
- $("auto_complete_query").focus();
- },
- after_hide : function() {
- $("jumper").className = "";
- }
+ (function ($) {
+ $(function() {
+ new crm.Popup({
+ trigger : "#jumper",
+ target : "#jumpbox",
+ under : "#welcome",
+ appear : 300,
+ fade : 300,
+ before_show : function() {
+ $("#jumper").addClass("selected");
+ $("#jumpbox_label").html("");
+ $("#jumpbox_label").hide();
+ $("#jumpbox_menu").show();
+ crm.auto_complete("#{current_auto_complete}");
+ },
+ after_show : function() {
+ $("#auto_complete_query").focus();
+ },
+ after_hide : function() {
+ $("#jumper").removeClass("selected");
+ }
+ });
});
- });
+ })($);
#jumpbox{ hidden }
%span#jumpbox_menu= jumpbox(current_auto_complete)
diff --git a/app/views/layouts/_sidebar.html.haml b/app/views/layouts/_sidebar.html.haml
index b628548316..a7554eb63c 100644
--- a/app/views/layouts/_sidebar.html.haml
+++ b/app/views/layouts/_sidebar.html.haml
@@ -8,5 +8,5 @@
= render sidebar
- rescue MissingTemplate
-= render "lists/sidebar"
+= render "lists/lists"
= render "shared/recently"
diff --git a/app/views/layouts/_tabbed.html.haml b/app/views/layouts/_tabbed.html.haml
index c1f8acfc0d..47ebcec6cd 100644
--- a/app/views/layouts/_tabbed.html.haml
+++ b/app/views/layouts/_tabbed.html.haml
@@ -7,10 +7,7 @@
-unless (tab[:text] == :tab_mandrill && !mandrill) || (conference_manager_hidden.include?(tab[:text]) && conference)
%li
= link_to(tab[:url], :class => tab[:active] ? "active" : nil) do
- - unless request.fullpath.include?("/admin")
- - img_base_path = "tab_icons/#{tab[:text].to_s.downcase.sub(/^tab_/, '')}"
- - if Rails.application.assets.find_asset("#{img_base_path}.png")
- = image_tag("#{img_base_path}#{tab[:active] ? "_active" : ""}.png")
+ %i.fa{class: tab[:icon]}
= t(tab[:text])
= show_flash
diff --git a/app/views/layouts/admin/application.html.haml b/app/views/layouts/admin/application.html.haml
old mode 100644
new mode 100755
index 63124a6cff..6e83bdad6b
--- a/app/views/layouts/admin/application.html.haml
+++ b/app/views/layouts/admin/application.html.haml
@@ -23,4 +23,3 @@
= "crm.base_url = '#{Setting.base_url}';" unless Setting.base_url.blank?
= get_browser_timezone_offset
= yield :javascript_epilogue
-
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index c05255839a..3fc3af5b8a 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -23,19 +23,22 @@
= hook(:javascript_includes, self)
:javascript
- #{yield :javascript}
- var _ffcrm_users = [
- #{User.all.map{|u| "\"#{u.full_name} (@#{u.username})\"" }.join(",\n")}
- ];
-
+ crm.language = "#{I18n.locale}"
window.controller = "#{controller.controller_name}"
-
+
+ - if current_user.present?
+ :javascript
+ #{yield :javascript}
+ var _ffcrm_users = [
+ #{User.all.map{|u| "\"#{u.full_name} (@#{u.username})\"" }.join(",\n")}
+ ];
+
%body
= render "layouts/header"
- - if tabless_layout?
+ - if tabless_layout?
= render "layouts/tabless"
- elsif mobile_device?
= render 'layouts/mobile'
diff --git a/app/views/leads/_contact.html.haml b/app/views/leads/_contact.html.haml
index 5f3b6412db..f054f12967 100644
--- a/app/views/leads/_contact.html.haml
+++ b/app/views/leads/_contact.html.haml
@@ -33,6 +33,3 @@
.check_box
= f.check_box :do_not_call, {}, true
#{t :do_not_call}
-
-
-
diff --git a/app/views/leads/_convert_permissions.html.haml b/app/views/leads/_convert_permissions.html.haml
index b9256534e8..26b0f702fc 100644
--- a/app/views/leads/_convert_permissions.html.haml
+++ b/app/views/leads/_convert_permissions.html.haml
@@ -5,16 +5,16 @@
= t(:convert_lead_permissions_intro)
#lead_convert_permissions{ hidden_if(collapsed) }
.radio_box
- = radio_button_tag "access", "Lead", true, :onclick => "$('people').hide(); $('account_access').value = $('opportunity_access').value = 'Lead'"
+ = radio_button_tag "access", "Lead", true, :onclick => "$('#people').hide(); $('#account_access').val('Lead'); $('#opportunity_access').val('Lead');"
= label :access, :Lead, t(:copy_permissions, t(:lead_small)), :style => "cursor:pointer"
.radio_box
- = radio_button_tag "access", "Private", false, :onclick => "$('people').hide(); $('account_access').value = $('opportunity_access').value = 'Private'"
+ = radio_button_tag "access", "Private", false, :onclick => "$('#people').hide(); $('#account_access').val('Private'); $('#opportunity_access').val('Private');"
= label :access, :Private, t(:keep_private), :style => "cursor:pointer"
.radio_box
- = radio_button_tag "access", "Public", false, :onclick => "$('people').hide(); $('account_access').value = $('opportunity_access').value = 'Public'"
+ = radio_button_tag "access", "Public", false, :onclick => "$('#people').hide(); $('#account_access').val('Public'); $('#opportunity_access').val('Public');"
= label :access, :Public, t(:make_public), :style => "cursor:pointer"
.radio_box
- = radio_button_tag "access", "Shared", false, :onclick => "$('people').show(); $('account_access').value = $('opportunity_access').value = 'Shared'"
+ = radio_button_tag "access", "Shared", false, :onclick => "$('#people').show(); $('#account_access').val('Shared'); $('#opportunity_access').val('Shared');"
= label :access, :Shared, t(:share_with), :style => "cursor:pointer"
#people{ hidden_if(@lead.access != "Shared") }
@@ -24,13 +24,8 @@
= label_tag :lead_user_ids, "#{t(:users)}:"
%br
= select :lead, :user_ids, user_options, {}, :multiple => true
- :javascript
- new Chosen($('lead_user_ids'));
-
%tr
%td
= label_tag :lead_group_ids, "#{t(:groups)}:"
%br
= select :lead, :group_ids, group_options, {}, :multiple => true
- :javascript
- new Chosen($('lead_group_ids'));
diff --git a/app/views/leads/_index_long.html.haml b/app/views/leads/_index_long.html.haml
index 6bcff828aa..695d446d44 100644
--- a/app/views/leads/_index_long.html.haml
+++ b/app/views/leads/_index_long.html.haml
@@ -53,8 +53,8 @@
== #{t :mobile_small}:
%b= lead.mobile
|
- = t(:added_ago, time_ago_in_words(lead.created_at))
-
+ = t(:added_ago, value: timeago(lead.created_at)).html_safe
+
- if lead.tag_list.present?
%dt
.tags= tags_for_index(lead)
diff --git a/app/views/leads/_leads.html.haml b/app/views/leads/_leads.html.haml
index a58a47c063..dc7e47cb69 100644
--- a/app/views/leads/_leads.html.haml
+++ b/app/views/leads/_leads.html.haml
@@ -3,4 +3,4 @@
- leads = object.leads.order('updated_at desc').paginate(:page => 1, :per_page => 20)
= render :partial => "leads/lead", :collection => object.leads.paginate(:page => 1, :per_page => 20)
-= will_paginate leads, :id => 'leads_pagination', :params => {:action => :leads}
+= paginate( collection: leads, id: 'leads_pagination', params: { action: 'leads' } )
diff --git a/app/views/leads/convert.js.haml b/app/views/leads/convert.js.haml
index f5a8b0fdab..862cc029f6 100755
--- a/app/views/leads/convert.js.haml
+++ b/app/views/leads/convert.js.haml
@@ -8,14 +8,14 @@
crm.flip_form('convert_#{entity_name}');
crm.set_title('convert_#{entity_name}', '#{h @entity.full_name}');
- else # Called from index page...
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- else # <---------------------------------------- Show [Edit] form.
- if params[:cancel].blank? # Called from index page...
- if @previous # Hide open [Edit] form if any.
- if @previous.is_a?(@entity.class)
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
- else
crm.flick('#{entity_name}_#{@previous}', 'remove');
-# Disable onMouseOver for the list item.
@@ -23,13 +23,13 @@
-# Hide [Create] form if any.
crm.hide_form('create_#{entity_name}')
-# Show [Edit] form.
- jQuery('##{id}').html('#{ j render(:partial => "convert") }');
+ $('##{id}').html('#{ j render(:partial => "convert") }');
- elsif params[:cancel].false? # Called from title of the lead landing page...
- jQuery('#convert_#{entity_name}').html('#{ j render(:partial => "convert") }');
+ $('#convert_#{entity_name}').html('#{ j render(:partial => "convert") }');
crm.hide_form('edit_lead');
crm.flip_form('convert_#{entity_name}');
crm.set_title('convert_#{entity_name}', "#{t :convert} #{h @entity.full_name}");
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/leads/create.js.haml b/app/views/leads/create.js.haml
index e90a8f27f8..74cb7d67fd 100755
--- a/app/views/leads/create.js.haml
+++ b/app/views/leads/create.js.haml
@@ -3,19 +3,19 @@
- create_id = "create_#{entity_name}" # create_account
- if @entity.valid?
- jQuery('##{create_id}_arrow').html(crm.COLLAPSED);
- jQuery('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
- jQuery('##{create_id}').slideUp(250);
- jQuery('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
+ $('##{create_id}_arrow').html(crm.COLLAPSED);
+ $('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
+ $('##{create_id}').slideUp(250);
+ $('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
- elsif called_from_landing_page?("campaigns")
- @campaign.reload
= refresh_sidebar_for(:campaigns, :show, :summary)
crm.flick('empty', 'remove');
- else
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
- jQuery('##{create_id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').effect("shake", { duration:250, distance: 6 });
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/leads/destroy.js.haml b/app/views/leads/destroy.js.haml
index 518baae513..faf96eb57f 100755
--- a/app/views/leads/destroy.js.haml
+++ b/app/views/leads/destroy.js.haml
@@ -1,9 +1,9 @@
- entity_name = controller.controller_name.singularize.underscore
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
+$('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- jQuery('#paginate').replaceWith('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').replaceWith('#{ j render(:partial => "shared/paginate_with_per_page") }');
- elsif called_from_landing_page?("campaigns")
= refresh_sidebar_for(:campaigns, :show, :summary)
diff --git a/app/views/leads/edit.js.haml b/app/views/leads/edit.js.haml
index 62571bfbb6..cd8132de10 100755
--- a/app/views/leads/edit.js.haml
+++ b/app/views/leads/edit.js.haml
@@ -8,14 +8,14 @@
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', '#{h @entity.full_name}');
- else # Called from index page...
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- else # <---------------------------------------- Show [Edit] form.
- if params[:cancel].blank? # Called from index page...
- if @previous # Hide open [Edit] form if any.
- if @previous.is_a?(@entity.class)
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
- else
crm.flick('#{entity_name}_#{@previous}', 'remove');
-# Disable onMouseOver for the list item.
@@ -23,13 +23,13 @@
-# Hide [Create] form if any.
crm.hide_form('create_#{entity_name}');
-# Show [Edit] form.
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').html('#{ j render(:partial => "edit") }');
- elsif params[:cancel].false? # Called from title of the landing page...
- jQuery('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
+ $('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
- unless %w(converted rejected).include? @entity.status
crm.hide_form('convert_lead');
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', "#{t :edit} #{h @entity.full_name}");
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/leads/index.js.haml b/app/views/leads/index.js.haml
index 9b5aaae0f7..b93ec3887a 100755
--- a/app/views/leads/index.js.haml
+++ b/app/views/leads/index.js.haml
@@ -2,10 +2,10 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(@entities) }');
+ $('##{entities}').html('#{ j render(@entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
-jQuery('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
+$('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
diff --git a/app/views/leads/index.xls.builder b/app/views/leads/index.xls.builder
index e9850dc4b3..f028717fe7 100644
--- a/app/views/leads/index.xls.builder
+++ b/app/views/leads/index.xls.builder
@@ -3,7 +3,8 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_leads) do
unless @leads.empty?
# Header.
xml.Row do
- heads = [I18n.t('user'),
+ heads = [I18n.t('id'),
+ I18n.t('user'),
I18n.t('campaign'),
I18n.t('job_title'),
I18n.t('name'),
@@ -33,12 +34,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_leads) do
I18n.t('zipcode'),
I18n.t('country'),
I18n.t('address')]
-
+
# Append custom field labels to header
Lead.fields.each do |field|
heads << field.label
end
-
+
heads.each do |head|
xml.Cell do
xml.Data head,
@@ -46,12 +47,13 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_leads) do
end
end
end
-
+
# Lead rows.
@leads.each do |lead|
xml.Row do
address = lead.business_address
- data = [lead.user.try(:name),
+ data = [lead.id,
+ lead.user.try(:name),
lead.campaign.try(:name),
lead.title,
lead.name,
@@ -81,12 +83,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_leads) do
address.try(:zipcode),
address.try(:country),
address.try(:full_address)]
-
+
# Append custom field values.
Lead.fields.each do |field|
data << lead.send(field.name)
end
-
+
data.each do |value|
xml.Cell do
xml.Data value,
diff --git a/app/views/leads/new.js.haml b/app/views/leads/new.js.haml
index 35918db5bc..3edcb8bb0b 100755
--- a/app/views/leads/new.js.haml
+++ b/app/views/leads/new.js.haml
@@ -5,7 +5,7 @@ crm.flick('empty', 'toggle');
crm.flip_form('#{create_id}');
- unless params[:cancel].true?
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
crm.set_title('#{create_id}', '#{ j t(create_id) }');
- else
crm.set_title('#{create_id}', '#{ j t(entity_name.pluralize) }');
diff --git a/app/views/leads/promote.js.haml b/app/views/leads/promote.js.haml
index 35c1e42081..b74020870a 100755
--- a/app/views/leads/promote.js.haml
+++ b/app/views/leads/promote.js.haml
@@ -8,19 +8,19 @@
crm.set_title('convert_#{entity_name}', '#{h @entity.full_name}');
= refresh_sidebar(:show, :summary)
- else
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- elsif called_from_landing_page?("campaigns")
= refresh_sidebar_for(:campaigns, :show, :summary)
- if @opportunity.id # Make sure the opportunity has been saved.
- jQuery('#opportunities').prepend('#{ j render(:partial => "opportunities/opportunity", :collection => [ @opportunity ]) }');
+ $('#opportunities').prepend('#{ j render(:partial => "opportunities/opportunity", :collection => [ @opportunity ]) }');
- else
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- else
- jQuery('##{id}').html('#{ j render(:partial => "convert") }');
+ $('##{id}').html('#{ j render(:partial => "convert") }');
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
diff --git a/app/views/leads/reject.js.haml b/app/views/leads/reject.js.haml
index a023de6ddd..3ce08a3b73 100755
--- a/app/views/leads/reject.js.haml
+++ b/app/views/leads/reject.js.haml
@@ -2,8 +2,8 @@
- @entity = instance_variable_get("@#{entity_name}")
- id = dom_id(@entity)
-jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
-jQuery('##{id}').effect("highlight", { duration:1500 });
+$('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+$('##{id}').effect("highlight", { duration:1500 });
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- elsif called_from_landing_page?("campaigns")
diff --git a/app/views/leads/show.js.haml b/app/views/leads/show.js.haml
index b07c9264f2..80794bb309 100755
--- a/app/views/leads/show.js.haml
+++ b/app/views/leads/show.js.haml
@@ -1,5 +1,5 @@
- entity_name = controller.controller_name.singularize.underscore #account
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
+$('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
= raw generate_js_for_popups(@entity, :tasks)
diff --git a/app/views/leads/update.js.haml b/app/views/leads/update.js.haml
index ee2aaa6cf9..277e587177 100755
--- a/app/views/leads/update.js.haml
+++ b/app/views/leads/update.js.haml
@@ -8,19 +8,19 @@
crm.set_title('edit_#{entity_name}', '#{h @entity.full_name}');
= refresh_sidebar(:show, :summary)
- else
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- elsif called_from_landing_page?("campaigns")
= refresh_sidebar_for(:campaigns, :show, :summary)
- else
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- else
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
- if @entity.errors[:first_name].blank? and entity.errors[:last_name].present?
- jQuery('#lead_last_name').focus();
+ $('#lead_last_name').focus();
- else
- jQuery('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
+ $('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
diff --git a/app/views/lists/_lists.html.haml b/app/views/lists/_lists.html.haml
new file mode 100644
index 0000000000..dda55241d1
--- /dev/null
+++ b/app/views/lists/_lists.html.haml
@@ -0,0 +1,6 @@
+- @global_lists = List.where(:user_id => nil)
+- @personal_lists = List.where(:user_id => current_user.id)
+
+#lists
+ = render "lists/sidebar", lists: @global_lists
+ = render "lists/sidebar", lists: @personal_lists, personal: true
diff --git a/app/views/lists/_sidebar.html.haml b/app/views/lists/_sidebar.html.haml
index 716105335c..fdd196039e 100644
--- a/app/views/lists/_sidebar.html.haml
+++ b/app/views/lists/_sidebar.html.haml
@@ -1,25 +1,29 @@
-- @lists = List.all
-- @list = List.new
-.panel#lists
- .caption #{t :lists}
+- personal ||= false
+- caption = personal ? :personal_lists : :global_lists
+
+.panel.lists
+ .caption #{t caption}
%ul
- - if @lists.none? || @current_user.groups.collect(&:name).include?("Conference Manager")
+ - if lists.none? || @current_user.groups.collect(&:name).include?("Conference Manager")
%div #{t :no_saved_lists}
- else
- - @lists.sort.each_with_index do |list, i|
- %li[list]{ :class => i < @lists.size - 1 ? "" : "last" }
- %dt= link_to(truncate(list.name, :length => 25), list.url, :title => list.name)
- %tt= link_to(image_tag("/assets/tab_icons/#{list.controller}_active.png", :"data-controller" => list.controller), url_for(list), :method => :delete, :confirm => 'Are you sure?', :remote => true, :class => "list_icon delete_on_hover")
+ - lists.sort.each_with_index do |item, i|
+ %li[item]{ :class => i < lists.size - 1 ? "" : "last" }
+ %dt= link_to(truncate(item.name, :length => 25), h(item.url), :title => item.name)
+ %tt
+ = link_to(url_for(item), :method => :delete, :confirm => t(:confirm_delete, value: 'list'), :remote => true, :class => "list_icon delete_on_hover") do
+ %i.fa{:"data-controller" => item.controller, class: get_icon(item.controller)}
- .show_lists_save_form{ hidden_if(!params[:q]) }
+ .list_save{ hidden_if(!params[:q]) }
= link_to(t(:make_current_view_list), '#')
- .save_list{ hidden }
- = simple_form_for(@list, :html => one_submit_only, :remote => true) do |f|
+ .list_form{ hidden }
+ = simple_form_for(List.new, :remote => true) do |f|
= f.text_field :name, :size => 25
- = image_tag("/assets/info_tiny.png", :title => t(:list_name_info), :class => "input_info")
+ = image_tag(asset_path('info_tiny.png'), :title => t(:list_name_info), class: "input_info")
= f.hidden_field :url
+ %input{:type => "hidden", :name => "is_global", :value => (personal ? 0 : 1) }
%div
- = f.submit(t(:save), :id => "save_list", :style => "vertical-align: bottom;")
+ = f.submit( t(:save) )
#{t :or}
- = link_to(t(:cancel), '#', :class => "hide_lists_save_form")
+ = link_to(t(:cancel), '#', :class => "cancel")
diff --git a/app/views/lists/create.js.haml b/app/views/lists/create.js.haml
index dcc2f27447..a1d5effa46 100644
--- a/app/views/lists/create.js.haml
+++ b/app/views/lists/create.js.haml
@@ -1,8 +1,9 @@
- if @list.valid?
- jQuery('#lists').replaceWith('#{ j render(:partial => "lists/sidebar") }');
- jQuery('.show_lists_save_form').show();
+ $('#lists').replaceWith('#{ j render(partial: "lists/lists") }');
+ $('.list_save').show();
- else # Couldn't create the saved list -- validation failed.
- jQuery('#new_list').effect("shake", { duration:250, distance: 6 });
- jQuery('#list_name').focus();
- jQuery('#save_list').enable();
+ $form = $('.lists .list_form:visible')
+ $form.effect("shake", { duration:250, distance: 6 });
+ $form.find("[name='list[name]']").focus();
+ $form.find("[type=submit]").prop('disabled', false);
diff --git a/app/views/lists/destroy.js.haml b/app/views/lists/destroy.js.haml
index b66ee3ea53..82dadfc585 100644
--- a/app/views/lists/destroy.js.haml
+++ b/app/views/lists/destroy.js.haml
@@ -1 +1 @@
-jQuery('##{dom_id(@list)}').css('background-color', '#ffe4e1').slideUp();
+$('##{dom_id(@list)}').css('background-color', '#ffe4e1').slideUp();
diff --git a/app/views/mandrill_emails/_edit.html.haml b/app/views/mandrill_emails/_edit.html.haml
index e506b867ed..6f136c7461 100644
--- a/app/views/mandrill_emails/_edit.html.haml
+++ b/app/views/mandrill_emails/_edit.html.haml
@@ -1,6 +1,6 @@
.remote
= simple_form_for(@mandrill_email, :html => one_submit_only(:mandrill_email), :remote => true) do |f|
- = link_to_close edit_contact_group_path(@mandrill_email)
+ = link_to_close edit_mandrill_email_path(@mandrill_email)
= f.hidden_field :user_id
= f.error_messages :object_name => t('mandrill_email')
diff --git a/app/views/mandrill_emails/filter.js.haml b/app/views/mandrill_emails/filter.js.haml
new file mode 100644
index 0000000000..3a67e38c5d
--- /dev/null
+++ b/app/views/mandrill_emails/filter.js.haml
@@ -0,0 +1,9 @@
+- entities = controller.controller_name # mandrill_emails
+- @entities = instance_variable_get("@#{entities}")
+
+- if @entities.any?
+ $('##{entities}').html('#{ j render(@entities) }');
+- else
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
\ No newline at end of file
diff --git a/app/views/mandrill_emails/index.js.haml b/app/views/mandrill_emails/index.js.haml
index b00593d439..3a67e38c5d 100644
--- a/app/views/mandrill_emails/index.js.haml
+++ b/app/views/mandrill_emails/index.js.haml
@@ -2,8 +2,8 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(@entities) }');
+ $('##{entities}').html('#{ j render(@entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
\ No newline at end of file
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
\ No newline at end of file
diff --git a/app/views/opportunities/_edit.html.haml b/app/views/opportunities/_edit.html.haml
index fe825b0008..6f8b5949c2 100644
--- a/app/views/opportunities/_edit.html.haml
+++ b/app/views/opportunities/_edit.html.haml
@@ -12,6 +12,6 @@
= render "entities/permissions", :f => f, :edit => true, :entity => @opportunity
.buttonbar
- = f.submit t(:save_opportunity), :onclick => %/$("account_assigned_to").value = $F("opportunity_assigned_to");/
+ = f.submit t(:save_opportunity), :onclick => %/$("#account_assigned_to").val($("#opportunity_assigned_to").val());/
#{t :or}
= link_to_cancel edit_opportunity_path(@opportunity)
diff --git a/app/views/opportunities/_index_brief.html.haml b/app/views/opportunities/_index_brief.html.haml
index e4dce97614..a71e5351f0 100644
--- a/app/views/opportunities/_index_brief.html.haml
+++ b/app/views/opportunities/_index_brief.html.haml
@@ -20,10 +20,10 @@
== #{t :from} #{link_to_if can?(:read, account), account.name, account_path(account)}
%tt
–
- - user_name = opportunity.user_id == current_user.id ? t(:me) : opportunity.user.try(:full_name)
+ - user_name = opportunity.user.try(:full_name)
- if user_name
- = t(:added_by, :time_ago => time_ago_in_words(opportunity.created_at), :user => user_name)
+ = t(:added_by, :time_ago => timeago(opportunity.created_at), :user => h(user_name)).html_safe
- else
- = t(:added_ago, :value => time_ago_in_words(opportunity.created_at))
+ = t(:added_ago, :value => timeago(opportunity.created_at)).html_safe
= hook(:opportunity_bottom, self, :opportunity => opportunity)
diff --git a/app/views/opportunities/_index_long.html.haml b/app/views/opportunities/_index_long.html.haml
index da10115ede..b9eb06fe21 100644
--- a/app/views/opportunities/_index_long.html.haml
+++ b/app/views/opportunities/_index_long.html.haml
@@ -20,11 +20,11 @@
== #{t :from} #{link_to_if can?(:read, account), account.name, account_path(account)}
%tt
–
- - user_name = opportunity.user_id == current_user.id ? t(:me) : opportunity.user.try(:full_name)
+ - user_name = opportunity.user.try(:full_name)
- if user_name
- = t(:added_by, :time_ago => time_ago_in_words(opportunity.created_at), :user => user_name)
+ = t(:added_by, :time_ago => timeago(opportunity.created_at), :user => h(user_name)).html_safe
- else
- = t(:added_ago, :value => time_ago_in_words(opportunity.created_at))
+ = t(:added_ago, :value => timeago(opportunity.created_at)).html_safe
%dt
%b= number_to_currency(opportunity.weighted_amount, :precision => 0) + " | "
diff --git a/app/views/opportunities/_new.html.haml b/app/views/opportunities/_new.html.haml
index 3d1fdb2cbe..45679d92f0 100644
--- a/app/views/opportunities/_new.html.haml
+++ b/app/views/opportunities/_new.html.haml
@@ -2,7 +2,6 @@
= link_to_close new_opportunity_path
= f.hidden_field :user_id
= hidden_field_tag "contact", "#{@contact.id if @contact}"
- = hidden_field_tag "campaign", "#{@campaign.id if @campaign}"
= f.error_messages :object_name => t('opportunity')
@@ -13,6 +12,6 @@
= render "entities/permissions", :f => f, :entity => @opportunity
.buttonbar
- = f.submit t(:create_opportunity), :onclick => %/$("account_assigned_to").value = $F("opportunity_assigned_to"); if ($("account_id").visible()) { $("account_id").enable(); }/
+ = f.submit t(:create_opportunity), :onclick => %/$("#account_assigned_to").val($("#opportunity_assigned_to").val()); if ($("#account_id").css('display') != 'none') { $("#account_id").enable(); }/
#{t :or}
= link_to_cancel new_opportunity_path
diff --git a/app/views/opportunities/_opportunities.html.haml b/app/views/opportunities/_opportunities.html.haml
index 43f04cbf6d..dbc40f0487 100644
--- a/app/views/opportunities/_opportunities.html.haml
+++ b/app/views/opportunities/_opportunities.html.haml
@@ -3,4 +3,4 @@
- opportunities = object.opportunities.order('updated_at desc').paginate(:page => 1, :per_page => 20)
= render :partial => "opportunities/opportunity", :collection => opportunities
-= will_paginate opportunities, :id => 'opportunities_pagination', :params => {:action => :opportunities}
+= paginate( collection: opportunities, id: 'opportunities_pagination', params: { action: 'opportunities' } )
diff --git a/app/views/opportunities/_top_section.html.haml b/app/views/opportunities/_top_section.html.haml
index 828bbbed38..70f188dde4 100644
--- a/app/views/opportunities/_top_section.html.haml
+++ b/app/views/opportunities/_top_section.html.haml
@@ -43,6 +43,10 @@
%td
.label.req #{t :assigned_to}:
= user_select(:opportunity, all_users, current_user)
+ %tr
+ %td
+ .label #{t :campaign}:
+ = opportunity_campaign_select( selected: (@campaign.try(:id) || @opportunity.campaign_id), include_blank: true )
- if Setting.background_info && Setting.background_info.include?(:opportunity)
%tr
diff --git a/app/views/opportunities/contacts.js.haml b/app/views/opportunities/contacts.js.haml
index c39fc2555f..77cb23f8b8 100755
--- a/app/views/opportunities/contacts.js.haml
+++ b/app/views/opportunities/contacts.js.haml
@@ -1,3 +1,3 @@
- @contacts = @opportunity.contacts.paginate(:page => params[:page], :per_page => 20)
-jQuery('#contacts').html('#{ j render(:partial => 'contacts/contact', :collection => @contacts) }');
-jQuery('#contacts_pagination').replaceWith('#{ j will_paginate(@contacts, :id => :contacts_pagination, :params => {:action => :contacts}) }');
+$('#contacts').html('#{ j render(:partial => 'contacts/contact', :collection => @contacts) }');
+$('#contacts_pagination').replaceWith('#{ j paginate(collection: @contacts, id: 'contacts_pagination', params: { action: 'contacts' } ) }');
diff --git a/app/views/opportunities/create.js.haml b/app/views/opportunities/create.js.haml
index 4c0a04f7bf..b63ad95da6 100644
--- a/app/views/opportunities/create.js.haml
+++ b/app/views/opportunities/create.js.haml
@@ -3,15 +3,15 @@
- create_id = "create_#{entity_name}"
- if @entity.valid?
- jQuery('##{create_id}_arrow').html(crm.COLLAPSED);
- jQuery('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
- jQuery('##{create_id}').slideUp(250);
- jQuery('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
+ $('##{create_id}_arrow').html(crm.COLLAPSED);
+ $('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
+ $('##{create_id}').slideUp(250);
+ $('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
- elsif called_from_landing_page?("accounts") # Opportunity created on Account landing page: refresh Account summary.
- @account.reload
= refresh_sidebar_for(:accounts, :show, :summary)
@@ -19,11 +19,11 @@
- @campaign.reload
= refresh_sidebar_for(:campaigns, :show, :summary)
- else # Opportunity created on Contact landing page: refresh recent items list.
- jQuery('#recently').html('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
crm.flick('empty', 'remove');
- else
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('##{create_id}').effect("shake", { duration:250, distance: 6 });
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('##{create_id}').effect("shake", { duration:250, distance: 6 });
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/opportunities/destroy.js.haml b/app/views/opportunities/destroy.js.haml
index 32f84bc33d..eed49bde96 100644
--- a/app/views/opportunities/destroy.js.haml
+++ b/app/views/opportunities/destroy.js.haml
@@ -1,13 +1,13 @@
- entity_name = controller.controller_name.singularize.underscore
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
+$('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+ $('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
- elsif called_from_landing_page?("accounts")
= refresh_sidebar_for(:accounts, :show, :summary)
- elsif called_from_landing_page?("campaigns")
= refresh_sidebar_for(:campaigns, :show, :summary)
- else
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
diff --git a/app/views/opportunities/edit.js.haml b/app/views/opportunities/edit.js.haml
index c1b079b755..13ca415771 100644
--- a/app/views/opportunities/edit.js.haml
+++ b/app/views/opportunities/edit.js.haml
@@ -8,14 +8,14 @@
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
- else # Called from index page...
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- else # <----------------------------------------- Show requested [Edit Opportunity] form.
- if params[:cancel].blank? # Called from opportunities list item...
- if @previous # Hide open [Edit Opportunity] form if any.
- if @previous.is_a?(Opportunity)
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
- else
crm.flick('#{entity_name}_#{@previous}', 'remove');
@@ -24,12 +24,12 @@
-# Hide [Create] form if any.
crm.hide_form('create_#{entity_name}');
-# Show [Edit] form.
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').html('#{ j render(:partial => "edit") }');
- elsif params[:cancel].false? # Called from title of the opportunity landing page...
- jQuery('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
+ $('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
crm.flip_form('edit_#{entity_name}');
crm.set_title('edit_#{entity_name}', "#{t :edit} #{h @opportunity.name}");
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
+ $('#new_#{entity_name} input[type!=hidden]').first().focus();
diff --git a/app/views/opportunities/index.js.haml b/app/views/opportunities/index.js.haml
index 9b5aaae0f7..b93ec3887a 100644
--- a/app/views/opportunities/index.js.haml
+++ b/app/views/opportunities/index.js.haml
@@ -2,10 +2,10 @@
- @entities = instance_variable_get("@#{entities}")
- if @entities.any?
- jQuery('##{entities}').html('#{ j render(@entities) }');
+ $('##{entities}').html('#{ j render(@entities) }');
- else
- jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
+ $('##{entities}').html('#{ j render(:partial => "shared/empty") }');
-jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
-jQuery('#export').html('#{ j render(:partial => "shared/export") }');
-jQuery('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
+$('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
+$('#export').html('#{ j render(:partial => "shared/export") }');
+$('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
diff --git a/app/views/opportunities/index.xls.builder b/app/views/opportunities/index.xls.builder
index 43301d4291..9782b4ef1b 100644
--- a/app/views/opportunities/index.xls.builder
+++ b/app/views/opportunities/index.xls.builder
@@ -3,7 +3,8 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_opportunities) do
unless @opportunities.empty?
# Header.
xml.Row do
- heads = [I18n.t('user'),
+ heads = [I18n.t('id'),
+ I18n.t('user'),
I18n.t('campaign'),
I18n.t('assigned_to'),
I18n.t('account'),
@@ -18,12 +19,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_opportunities) do
I18n.t('option_closes_on'),
I18n.t('date_created'),
I18n.t('date_updated')]
-
+
# Append custom field labels to header
Opportunity.fields.each do |field|
heads << field.label
end
-
+
heads.each do |head|
xml.Cell do
xml.Data head,
@@ -31,11 +32,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_opportunities) do
end
end
end
-
+
# Opportunity rows.
@opportunities.each do |opportunity|
xml.Row do
- data = [opportunity.user.try(:name),
+ data = [opportunity.id,
+ opportunity.user.try(:name),
opportunity.campaign.try(:name),
opportunity.assignee.try(:name),
opportunity.account.try(:name),
@@ -50,12 +52,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_opportunities) do
opportunity.closes_on,
opportunity.created_at,
opportunity.updated_at]
-
+
# Append custom field values.
Opportunity.fields.each do |field|
data << opportunity.send(field.name)
end
-
+
data.each do |value|
xml.Cell do
xml.Data value,
diff --git a/app/views/opportunities/new.js.haml b/app/views/opportunities/new.js.haml
index ae30884c2d..de2e999fbd 100644
--- a/app/views/opportunities/new.js.haml
+++ b/app/views/opportunities/new.js.haml
@@ -5,7 +5,7 @@ crm.flick('empty', 'toggle');
crm.flip_form('#{create_id}');
- unless params[:cancel].true?
- jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
+ $('##{create_id}').html('#{ j render(:partial => "new") }');
crm.set_title('#{create_id}', '#{ j t(create_id) }');
-# this function call is the only difference to normal new.js.haml
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
diff --git a/app/views/opportunities/show.js.haml b/app/views/opportunities/show.js.haml
index bdc0cf5e4b..c0bcf6c2c2 100644
--- a/app/views/opportunities/show.js.haml
+++ b/app/views/opportunities/show.js.haml
@@ -1,5 +1,5 @@
- entity_name = controller.controller_name.singularize.underscore #account
- @entity = instance_variable_get("@#{entity_name}")
-jQuery('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
+$('#main').html('#{ j (render :template => "#{entity_name.pluralize}/show.html", entity_name => @entity) }');
= raw generate_js_for_popups(@entity, :tasks, :contacts)
diff --git a/app/views/opportunities/update.js.haml b/app/views/opportunities/update.js.haml
index 8e4de12032..d3e4f5eb4e 100644
--- a/app/views/opportunities/update.js.haml
+++ b/app/views/opportunities/update.js.haml
@@ -8,8 +8,8 @@
crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
= refresh_sidebar(:show, :summary)
- else
- jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
- jQuery('##{id}').effect("highlight", { duration:1500 });
+ $('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
+ $('##{id}').effect("highlight", { duration:1500 });
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
- elsif called_from_landing_page?(:accounts)
@@ -17,9 +17,9 @@
- elsif called_from_landing_page?(:campaigns)
= refresh_sidebar_for(:campaigns, :show, :summary)
- else
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- else
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
+ $('##{id}').html('#{ j render(:partial => "edit") }');
crm.create_or_select_account(#{ request.referer =~ /\/accounts\// || @account.id.blank? });
- jQuery('##{id}').effect("shake", { duration:250, distance: 6 });
- jQuery('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
+ $('##{id}').effect("shake", { duration:250, distance: 6 });
+ $('##{dom_id(@entity, :edit)} input[type!=hidden]').first().focus();
diff --git a/app/views/shared/_address.html.haml b/app/views/shared/_address.html.haml
index 2f6913549a..db95f0a2bb 100644
--- a/app/views/shared/_address.html.haml
+++ b/app/views/shared/_address.html.haml
@@ -41,4 +41,4 @@
= address_field(a, address, :zipcode, "width:80px;")
%td= spacer
%td
- = a.country_select(:country, priority_countries, { :include_blank => "" }, {:"data-placeholder" => t(:select_a_country), :style => "width:150px; margin-top:6px"})
+ = a.country_select(:country, priority_countries, { :include_blank => "" }, {:"data-placeholder" => t(:select_a_country), :style => "width:150px; margin-top:6px", :class => 'select2'})
diff --git a/app/views/shared/_comment.html.haml b/app/views/shared/_comment.html.haml
index 9a37907a4e..1ae1765a56 100644
--- a/app/views/shared/_comment.html.haml
+++ b/app/views/shared/_comment.html.haml
@@ -7,5 +7,5 @@
.indentslim
= link_to comment.user.full_name, user_path(comment.user)
- %tt= t(:time_ago, distance_of_time_in_words(Time.now, comment.created_at))
+ %tt= timeago(comment.created_at).html_safe
%dt= auto_link(simple_format comment.comment).html_safe
diff --git a/app/views/shared/_inline_styles.html.haml b/app/views/shared/_inline_styles.html.haml
index 58a680b765..cc1d003c61 100644
--- a/app/views/shared/_inline_styles.html.haml
+++ b/app/views/shared/_inline_styles.html.haml
@@ -47,5 +47,5 @@
li.user .active { background: lightgreen; }
li.user .signed_up { background: lightsalmon; }
- = hook(:inline_styles, self)
+ = hook(:inline_styles, self, local_assigns)
diff --git a/app/views/shared/_naming.html.haml b/app/views/shared/_naming.html.haml
index e7d0b75436..f56d02fc52 100644
--- a/app/views/shared/_naming.html.haml
+++ b/app/views/shared/_naming.html.haml
@@ -2,8 +2,8 @@
:plain
new crm.Menu({
- trigger : "naming",
- fade : 0.5,
- appear : 0.5,
+ trigger : "#naming",
+ fade : 500,
+ appear : 500,
menu_items: [ #{naming_menu_items.join(",")} ]
});
diff --git a/app/views/shared/_paginate.haml b/app/views/shared/_paginate.haml
index cd9a27327c..7dabbd95bc 100644
--- a/app/views/shared/_paginate.haml
+++ b/app/views/shared/_paginate.haml
@@ -1 +1,2 @@
-= will_paginate :params => {:action => :index}
+= image_tag("loading.gif", size: 'thumb', class: "spinner", style: "display: none;")
+= paginate
diff --git a/app/views/shared/_paginate_with_per_page.html.haml b/app/views/shared/_paginate_with_per_page.html.haml
index 3953cf91ca..ea55c23421 100644
--- a/app/views/shared/_paginate_with_per_page.html.haml
+++ b/app/views/shared/_paginate_with_per_page.html.haml
@@ -1,14 +1,12 @@
+= image_tag("loading.gif", size: 'thumb', class: "spinner", style: "display: none;")
+= paginate
-= will_paginate :params => {:action => :index}
+.per_page_options
+ %span.per_page_label
+ = t('entities_per_page', :entity => t(controller_name))
-- entities = instance_variable_get("@#{controller_name}")
-- if entities.count > @per_page.to_i
- .per_page_options
- %span.per_page_label
- = t('entities_per_page', :entity => t(controller_name))
-
- - [ 10, 20, 30, 50, 200 ].each do |count|
- - if count == @per_page.to_i
- %em.current= count
- - else
- = link_to count, send("redraw_#{controller.controller_name}_path", :per_page => count, :query => params[:query], :q => params[:q])
+ - [ 10, 20, 30, 50 ].each do |count|
+ - if count == @per_page.to_i
+ %em.current= count
+ - else
+ = link_to count, send("redraw_#{controller.controller_name}_path", per_page: count, query: params[:query], q: params[:q]), remote: true
diff --git a/app/views/shared/_search.html.haml b/app/views/shared/_search.html.haml
index 28adf03baa..e213506473 100644
--- a/app/views/shared/_search.html.haml
+++ b/app/views/shared/_search.html.haml
@@ -4,8 +4,12 @@
%h4 #{t(:search_assets, t(controller.controller_name + "_small"))}
%div{ :style => "margin: 0px 0px 6px 0px" }
= text_field_tag('query', @current_query, :size => 23)
-
+
:javascript
- new Form.Element.Observer('query', 1.5, function(element, value) {
- crm.search(value, '#{path}')
+ var searchTimeout;
+
+ $('#query').on('keydown', function(event) {
+ $el = $(event.target)
+ if (searchTimeout) clearTimeout(searchTimeout);
+ searchTimeout = setTimeout(function () { crm.search($el.val(), '#{path}'); }, 500);
});
diff --git a/app/views/shared/_select_popup.html.haml b/app/views/shared/_select_popup.html.haml
index e145e65b37..9bb6ae8160 100644
--- a/app/views/shared/_select_popup.html.haml
+++ b/app/views/shared/_select_popup.html.haml
@@ -2,20 +2,18 @@
:plain
new crm.Popup({
- trigger : "select_#{singular}",
- target : "jumpbox",
- under : "select_#{singular}",
- appear : 0.3,
- fade : 0.3,
+ trigger : "#select_#{singular}",
+ target : "#jumpbox",
+ under : "#select_#{singular}",
+ appear : 300,
+ fade : 300,
before_show : function() {
- $("jumpbox_menu").hide();
- $("jumpbox_label").innerHTML = "#{t(popup)}:"
- $("jumpbox_label").show();
- crm.auto_complete("#{popup}", "#{related.class.to_s.tableize}/#{related.id}");
+ $("#jumpbox_menu").hide();
+ $("#jumpbox_label").html("#{t(popup)}:");
+ $("#jumpbox_label").show();
+ crm.auto_complete("#{popup}", "#{related.class.to_s.underscore.downcase.pluralize}/#{related.id}");
},
after_show : function() {
- $("auto_complete_query").focus();
- },
- after_hide : function() {
+ $("#auto_complete_query").focus();
}
});
diff --git a/app/views/tasks/complete.js.haml b/app/views/tasks/complete.js.haml
index e7ffb45792..e7596726e2 100644
--- a/app/views/tasks/complete.js.haml
+++ b/app/views/tasks/complete.js.haml
@@ -1,14 +1,14 @@
- if called_from_index_page? # Completing from pending tasks view -- fade out task partial and update sidebar.
- jQuery('##{dom_id(@task, :tools)}').hide();
- jQuery('##{dom_id(@task)}').fadeOut({ duration:500 });
+ $('##{dom_id(@task, :tools)}').hide();
+ $('##{dom_id(@task)}').fadeOut({ duration:500 });
- if @empty_bucket
- jQuery('#list_#{@empty_bucket}').fadeOut({ duration:500 });
+ $('#list_#{@empty_bucket}').fadeOut({ duration:500 });
= refresh_sidebar(:index, :filters)
- else # Completing from the Asset page -- replace task partial with completed one.
- jQuery('##{dom_id(@task)}').hide();
- jQuery('##{dom_id(@task)}').html('#{ j render(:partial => "tasks/completed", :collection => [ @task ], :locals => { :bucket => nil }) }');
- jQuery('##{dom_id(@task)}').fadeIn({ duration:500 });
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('##{dom_id(@task)}').hide();
+ $('##{dom_id(@task)}').html('#{ j render(:partial => "tasks/completed", :collection => [ @task ], :locals => { :bucket => nil }) }');
+ $('##{dom_id(@task)}').fadeIn({ duration:500 });
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
diff --git a/app/views/tasks/create.js.haml b/app/views/tasks/create.js.haml
index d05281dad9..865a3c164c 100644
--- a/app/views/tasks/create.js.haml
+++ b/app/views/tasks/create.js.haml
@@ -1,39 +1,39 @@
- if @task.valid?
- jQuery('#create_task_arrow').html(crm.COLLAPSED);
- jQuery('#create_task').slideUp(250);
+ $('#create_task_arrow').html(crm.COLLAPSED);
+ $('#create_task').slideUp(250);
- if called_from_index_page? # "Classic" [Create Task] form requested from the Tasks page.
- jQuery('#title').html('#{ j (@view == "assigned" ? t(:assigned_tasks) : t(:tasks)) }');
+ $('#title').html('#{ j (@view == "assigned" ? t(:assigned_tasks) : t(:tasks)) }');
-# Show flash if assigned to somebody else from the [Pending Tasks] page.
- if @view == "pending" && @task.assigned_to && @task.assigned_to != current_user.id
- jQuery('#flash').html('#{j t(:task_created)} #{j t(:task_assigned_to, @task.assignee.full_name)} (#{j link_to(t(:view_assigned_tasks), url_for(:view => "assigned"))}).');
+ $('#flash').html('#{j t(:task_created)} #{j t(:task_assigned_to, @task.assignee.full_name)} (#{j link_to(t(:view_assigned_tasks), url_for(:view => "assigned"))}).');
crm.flash('notice', true);
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- # Show flash if assigned to current user from the [Assigned Tasks] page.
- elsif @view == "assigned" && @task.assigned_to.blank?
- jQuery('#flash').html('#{j t(:task_created)} (#{j link_to(t(:view_pending_tasks), tasks_url)}).');
+ $('#flash').html('#{j t(:task_created)} (#{j link_to(t(:view_pending_tasks), tasks_url)}).');
crm.flash('notice', true);
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- else # Show newly created task by inserting its div into appropriate bucket; then update tasks sidebar.
- bucket = @task.computed_bucket
- jQuery('#list_#{bucket}').show();
- jQuery('##{bucket}').before('#{ j render(:partial => @view, :collection => [ @task ], :locals => { :bucket => bucket }) }');
- jQuery('##{dom_id(@task)}').effect("highlight", { duration:1500 });
+ $('#list_#{bucket}').show();
+ $('##{bucket}').before('#{ j render(:partial => @view, :collection => [ @task ], :locals => { :bucket => bucket }) }');
+ $('##{dom_id(@task)}').effect("highlight", { duration:1500 });
= refresh_sidebar(:index, :filters)
crm.flick('empty', 'remove');
- else # Inline [Create Task] form reqested from any of the core asset landing pages.
- jQuery('#create_task_title').html('#{ j t(:tasks) }');
+ $('#create_task_title').html('#{ j t(:tasks) }');
- partial = (@task.assigned_to && @task.assigned_to != current_user.id) ? "assigned" : "pending"
- jQuery('#tasks').prepend('#{ j render(:partial => "tasks/#{partial}", :collection => [@task], :locals => { :bucket => nil }) }');
- jQuery('##{dom_id(@task)}').effect("highlight", { duration:1500 });
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#tasks').prepend('#{ j render(:partial => "tasks/#{partial}", :collection => [@task], :locals => { :bucket => nil }) }');
+ $('##{dom_id(@task)}').effect("highlight", { duration:1500 });
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- else # Couldn't create the task -- validation failed.
- jQuery('#create_task').effect("shake", { duration:250, distance: 6 });
- jQuery('#task_name').focus();
- jQuery('#new_task input[type=submit]').enable();
+ $('#create_task').effect("shake", { duration:250, distance: 6 });
+ $('#task_name').focus();
+ $('#new_task input[type=submit]').enable();
diff --git a/app/views/tasks/destroy.js.haml b/app/views/tasks/destroy.js.haml
index a53be78cad..d029332798 100644
--- a/app/views/tasks/destroy.js.haml
+++ b/app/views/tasks/destroy.js.haml
@@ -1,7 +1,7 @@
-jQuery('##{dom_id(@task)}').slideUp(250);
+$('##{dom_id(@task)}').slideUp(250);
- if @empty_bucket
- jQuery('#list_#{@empty_bucket}').fadeOut({ duration:500 });
+ $('#list_#{@empty_bucket}').fadeOut({ duration:500 });
- if called_from_index_page?
= refresh_sidebar(:index, :filters)
diff --git a/app/views/tasks/discard.js.haml b/app/views/tasks/discard.js.haml
index b3fc08796a..e978faa6e3 100644
--- a/app/views/tasks/discard.js.haml
+++ b/app/views/tasks/discard.js.haml
@@ -1 +1 @@
-jQuery('##{dom_id(@task)}').slideUp(250);
+$('##{dom_id(@task)}').slideUp(250);
diff --git a/app/views/tasks/edit.js.haml b/app/views/tasks/edit.js.haml
index f5e9ca97a1..5c2e2f967e 100644
--- a/app/views/tasks/edit.js.haml
+++ b/app/views/tasks/edit.js.haml
@@ -3,7 +3,7 @@
- if params[:cancel].true? # <----------------- Hide [Edit Task]
- partial = (@task.assigned_to && @task.assigned_to != current_user.id) ? "assigned" : "pending"
- jQuery('##{id}').html('#{ j render(:partial => partial, :collection => [ @task ], :locals => { :bucket => @task.bucket }) }');
+ $('##{id}').html('#{ j render(:partial => partial, :collection => [ @task ], :locals => { :bucket => @task.bucket }) }');
- else # <---------------------------------------- Show [Edit Task] form.
@@ -14,7 +14,7 @@
- if @previous
- if @previous.is_a?(Task)
- partial = (@previous.assigned_to && @previous.assigned_to != current_user.id) ? "assigned" : "pending"
- jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => partial, :collection => [ @previous ], :locals => { :bucket => nil }) }');
+ $('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => partial, :collection => [ @previous ], :locals => { :bucket => nil }) }');
- else
crm.flick('task_#{@previous}', 'remove');
@@ -22,5 +22,5 @@
crm.highlight_off('#{id}');
-# Show [Edit Task] form.
- jQuery('##{id}').html('#{ j render(:partial => "edit") }');
- jQuery('#task_name').focus();
+ $('##{id}').html('#{ j render(:partial => "edit") }');
+ $('#task_name').focus();
diff --git a/app/views/tasks/filter.js.haml b/app/views/tasks/filter.js.haml
index f76d9e79f4..f4e0e34b33 100644
--- a/app/views/tasks/filter.js.haml
+++ b/app/views/tasks/filter.js.haml
@@ -1,4 +1,4 @@
- if params[:checked] == 'true'
- jQuery('#list_#{j params[:filter]}').show();
+ $('#list_#{j params[:filter]}').show();
- else
- jQuery('#list_#{j params[:filter]}').hide();
+ $('#list_#{j params[:filter]}').hide();
diff --git a/app/views/tasks/index.xls.builder b/app/views/tasks/index.xls.builder
index ddeb1f260a..136db35bc2 100644
--- a/app/views/tasks/index.xls.builder
+++ b/app/views/tasks/index.xls.builder
@@ -3,7 +3,8 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_tasks) do
unless @tasks.empty?
# Header.
xml.Row do
- heads = %w{name
+ heads = %w{id
+ name
due
date_created
date_updated
@@ -12,7 +13,7 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_tasks) do
assigned_to
category
background_info}
-
+
heads.each do |head|
xml.Cell do
xml.Data I18n.t(head),
@@ -20,11 +21,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_tasks) do
end
end
end
-
+
# Rows.
@tasks.map(&:second).flatten.each do |task|
xml.Row do
- data = [task.name,
+ data = [task.id,
+ task.name,
I18n.t(task.computed_bucket),
task.created_at,
task.updated_at,
@@ -33,7 +35,7 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_tasks) do
task.assignee.try(:name),
task.category,
task.background_info]
-
+
data.each do |value|
xml.Cell do
xml.Data value,
diff --git a/app/views/tasks/new.js.haml b/app/views/tasks/new.js.haml
index c8826befd5..669a2c06c6 100644
--- a/app/views/tasks/new.js.haml
+++ b/app/views/tasks/new.js.haml
@@ -2,7 +2,7 @@ crm.flick('empty', 'toggle');
crm.flip_form('create_task');
- unless params[:cancel].true?
- jQuery('#create_task').html('#{ j render(:partial => "new") }');
+ $('#create_task').html('#{ j render(:partial => "new") }');
crm.set_title('create_task', '#{j t(:create_task) }');
- else
crm.set_title('create_task', '#{ @view == "assigned" ? t(:assigned_tasks) : t(:tasks) }');
diff --git a/app/views/tasks/update.js.haml b/app/views/tasks/update.js.haml
index 7f885479ca..e43b3749c9 100644
--- a/app/views/tasks/update.js.haml
+++ b/app/views/tasks/update.js.haml
@@ -4,7 +4,7 @@
-# If it's not Tasks tab then we just reload appropriate
-# partial with the new task, and update recent items.
= replace_content(@task)
- jQuery('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
+ $('#recently').replaceWith('#{ j render(:partial => "shared/recently") }');
- else
- if @task.assigned_to != @task_before_update.assigned_to
= reassign(@task)
@@ -14,6 +14,6 @@
= replace_content(@task, @task.bucket)
- else # Errors
- jQuery('##{dom_id(@task)}').effect("shake", { duration:250, distance: 6 });
- jQuery('#task_name').focus();
- jQuery('#task_submit').enable();
+ $('##{dom_id(@task)}').effect("shake", { duration:250, distance: 6 });
+ $('#task_name').focus();
+ $('#task_submit').enable();
diff --git a/app/views/users/_avatar.html.haml b/app/views/users/_avatar.html.haml
index a35d610878..1d5fb0cb0e 100644
--- a/app/views/users/_avatar.html.haml
+++ b/app/views/users/_avatar.html.haml
@@ -1,5 +1,5 @@
.remote
- = form_for(@user, :url => upload_avatar_user_path(@user, :format => "js"), :html => { :multipart => true, :target => "uploading", :onsubmit => "$('user_avatar_submit').disabled = true" }) do |f|
+ = form_for(@user, :url => upload_avatar_user_path(@user, :format => "js"), :html => { :multipart => true, :target => "uploading", :onsubmit => "$('#user_avatar_submit').disabled = true" }) do |f|
= link_to_close avatar_user_path(@user)
= error_messages_for :avatar, :object => @user.avatar, :object_name => t('avatar')
diff --git a/app/views/users/_languages.html.haml b/app/views/users/_languages.html.haml
index 9d2febd7b9..d8ccf2771b 100644
--- a/app/views/users/_languages.html.haml
+++ b/app/views/users/_languages.html.haml
@@ -1,9 +1,9 @@
:plain
new crm.Menu({
- trigger : "locale",
+ trigger : "#locale",
align : "right",
- appear : 0.5,
- fade : 0.5,
+ appear : 500,
+ fade : 500,
width : 160,
menu_items: [ #{sort_by_language.join(",")} ]
});
diff --git a/app/views/users/avatar.js.haml b/app/views/users/avatar.js.haml
index a47b6ed146..08c52fd2db 100644
--- a/app/views/users/avatar.js.haml
+++ b/app/views/users/avatar.js.haml
@@ -2,7 +2,7 @@
crm.flip_form('upload_avatar');
crm.set_title('upload_avatar', '#{j t(:my_profile)}');
- else
- jQuery('#upload_avatar').html('#{ j render(:partial => "avatar") }');
+ $('#upload_avatar').html('#{ j render(:partial => "avatar") }');
crm.hide_form('edit_profile');
crm.hide_form('change_password');
crm.flip_form('upload_avatar');
diff --git a/app/views/users/change_password.js.haml b/app/views/users/change_password.js.haml
index e9ca015ff3..3267175781 100644
--- a/app/views/users/change_password.js.haml
+++ b/app/views/users/change_password.js.haml
@@ -1,13 +1,13 @@
- if @user.errors.empty?
crm.flip_form('change_password');
crm.set_title('change_password', '#{ j t(:my_profile) }');
- jQuery('#flash').html('#{ j flash[:notice] }');
+ $('#flash').html('#{ j flash[:notice] }');
crm.flash('notice')
- flash[:notice] = nil
- else
- jQuery('#change_password').html('#{ j render(:partial => "password") }');
- jQuery('#change_password').effect("shake", { duration:250, distance: 6 });
+ $('#change_password').html('#{ j render(:partial => "password") }');
+ $('#change_password').effect("shake", { duration:250, distance: 6 });
- if @user.errors[:current_password].present?
- jQuery('#current_password').focus();
+ $('#current_password').focus();
- else
- jQuery('#user_password').focus();
+ $('#user_password').focus();
diff --git a/app/views/users/edit.js.haml b/app/views/users/edit.js.haml
index f7e79c218a..1d49688c47 100644
--- a/app/views/users/edit.js.haml
+++ b/app/views/users/edit.js.haml
@@ -2,7 +2,7 @@
crm.flip_form('edit_profile');
crm.set_title('edit_profile', '#{ j t(:my_profile) }');
- else
- jQuery('#edit_profile').html('#{ j render(:partial => "profile") }');
+ $('#edit_profile').html('#{ j render(:partial => "profile") }');
crm.hide_form('upload_avatar');
crm.hide_form('change_password');
crm.flip_form('edit_profile');
diff --git a/app/views/users/move_contact.js.haml b/app/views/users/move_contact.js.haml
new file mode 100644
index 0000000000..82e63abcb3
--- /dev/null
+++ b/app/views/users/move_contact.js.haml
@@ -0,0 +1,5 @@
+- id = dom_id(@contact)
+
+$('##{id}').replaceWith('#{ j render(:partial => "contacts/contact", :collection => [ @contact ]) }');
+$('##{id}').effect("highlight", { duration:1500 });
+= refresh_sidebar_for(:contacts, :index, :filters)
\ No newline at end of file
diff --git a/app/views/users/password.js.haml b/app/views/users/password.js.haml
index 55766e5854..adc421334b 100644
--- a/app/views/users/password.js.haml
+++ b/app/views/users/password.js.haml
@@ -2,9 +2,9 @@
crm.flip_form('change_password');
crm.set_title('change_password', '#{t(:my_profile)}');
- else
- jQuery('#change_password').html('#{ j render(:partial => "password") }');
+ $('#change_password').html('#{ j render(:partial => "password") }');
crm.hide_form('edit_profile');
crm.hide_form('upload_avatar');
crm.flip_form('change_password');
crm.set_title('change_password', '#{t(:change_password)}');
- jQuery('#current_password').focus();
+ $('#current_password').focus();
diff --git a/app/views/users/update.js.haml b/app/views/users/update.js.haml
index 04037fa6be..42058ce339 100644
--- a/app/views/users/update.js.haml
+++ b/app/views/users/update.js.haml
@@ -1,9 +1,9 @@
- if @user.errors.empty?
crm.flip_form('edit_profile');
crm.set_title('edit_profile', '#{j t(:my_profile)}');
- jQuery('#welcome_username').html('#{j current_user.name}');
- jQuery('#profile').html('#{ j render(:partial => "user") }');
+ $('#welcome_username').html('#{j current_user.name}');
+ $('#profile').html('#{ j render(:partial => "user") }');
- else
- jQuery('#edit_profile').html('#{ j render(:partial => "profile") }');
- jQuery('#edit_profile').effect("shake", { duration:250, distance: 6 });
- jQuery('#user_email').focus();
+ $('#edit_profile').html('#{ j render(:partial => "profile") }');
+ $('#edit_profile').effect("shake", { duration:250, distance: 6 });
+ $('#user_email').focus();
diff --git a/app/views/users/upload_avatar.js.haml b/app/views/users/upload_avatar.js.haml
index d5fd12665b..c8b6bdf012 100644
--- a/app/views/users/upload_avatar.js.haml
+++ b/app/views/users/upload_avatar.js.haml
@@ -1,7 +1,7 @@
- if @user.avatar.nil? || @user.avatar.errors.empty?
crm.flip_form('upload_avatar');
crm.set_title('upload_avatar', '#{j t(:my_profile)}');
- jQuery('#profile').html('#{ j render(:partial => "user") }');
+ $('#profile').html('#{ j render(:partial => "user") }');
- else
- jQuery('#upload_avatar').html('#{ j render(:partial => "avatar") }');
- jQuery('#upload_avatar').effect("shake", { duration:250, distance: 6 });
+ $('#upload_avatar').html('#{ j render(:partial => "avatar") }');
+ $('#upload_avatar').effect("shake", { duration:250, distance: 6 });
diff --git a/app/views/versions/_version.html.haml b/app/views/versions/_version.html.haml
index f9f8603572..5638630567 100644
--- a/app/views/versions/_version.html.haml
+++ b/app/views/versions/_version.html.haml
@@ -10,7 +10,7 @@
= t('version.' + version.event, :item => item_type, :by => user_name, :default => version.event)
- else
= auto_link(version.event).html_safe
- %small= t('time_ago', time_ago_in_words(version.created_at))
+ %small= timeago(version.created_at).html_safe
%tt
- version.changeset.each do |attr_name, change|
- label, first, second = parse_version(attr_name, change)
diff --git a/app/views/versions/_versions.html.haml b/app/views/versions/_versions.html.haml
index 0f8d596206..43d19ef4a0 100755
--- a/app/views/versions/_versions.html.haml
+++ b/app/views/versions/_versions.html.haml
@@ -8,4 +8,4 @@
- versions = Version.history(object).paginate(:page => 1, :per_page => 20)
= render :partial => "versions/version", :collection => versions
- = will_paginate versions, :id => 'versions_pagination', :params => {:action => :versions}
+ = paginate( collection: versions, id: 'versions_pagination', params: { action: 'versions' } )
diff --git a/config/application.rb b/config/application.rb
index 7fbf05a713..31fa507d5a 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -6,9 +6,6 @@
require File.expand_path('../boot', __FILE__)
require 'rubygems'
-require 'yaml'
-YAML::ENGINE.yamler = 'syck'
-
require 'rails/all'
if defined?(Bundler)
@@ -31,7 +28,7 @@ class Application < Rails::Application
config.autoload_paths += Dir[Rails.root.join("app/models/**")] +
Dir[Rails.root.join("app/controllers/entities")]
- # Prevent Field class from being reloading more than once as this clears registered customfields
+ # Prevent Field class from being reloaded more than once as this clears registered customfields
config.autoload_once_paths += [File.expand_path("../app/models/fields/field.rb", __FILE__)]
# Activate observers that should always be running.
@@ -72,7 +69,7 @@ class Application < Rails::Application
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
- config.filter_parameters += [:password]
+ config.filter_parameters += [:password, :password_hash, :password_salt, :password_confirmation]
# Use SQL instead of Active Record's schema dumper when creating the database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
diff --git a/config/environments/development.rb b/config/environments/development.rb
index cb38f49471..1286f1ba15 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -17,8 +17,6 @@
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
- #config.action_mailer.default_url_options = { :host => 'mojo.dyndns-server.com' }
-
config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
@@ -29,6 +27,9 @@
config.action_controller.perform_caching = false
config.cache_store = :dalli_store, 'localhost:11211'
CacheDigests::TemplateDigestor.cache = ActiveSupport::Cache::NullStore.new
+
+ config.action_mailer.delivery_method = :file
+
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = true
diff --git a/config/environments/production.rb b/config/environments/production.rb
index eff73e06a6..fbcf98b357 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -10,14 +10,13 @@
# Code is not reloaded between requests
config.cache_classes = true
- # Full error reports are enabled, since this is an internal application.
- config.consider_all_requests_local = true
- # Caching is turned on
+ # Full error reports are disabled and caching is turned on.
+ config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.cache_store = :dalli_store, 'localhost:11211'
# Disable Rails's static asset server (Apache or nginx will already do this)
- config.serve_static_assets = false
+ config.serve_static_assets = true
# Compress JavaScripts and CSS
config.assets.compress = true
diff --git a/config/environments/staging.rb b/config/environments/staging.rb
index 67a11cfc89..43e03d3970 100644
--- a/config/environments/staging.rb
+++ b/config/environments/staging.rb
@@ -3,17 +3,62 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-if defined?(FatFreeCRM::Application)
- require FatFreeCRM.root.join('config', 'environments', 'production')
- FatFreeCRM::Application.configure do
- # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
- # the I18n.default_locale when a translation can not be found)
- config.i18n.fallbacks = false
-
- # See everything in the log (default is :info)
- config.log_level = :debug
-
- # Full error reports
- config.consider_all_requests_local = true
- end
+
+FatFreeCRM::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # Code is not reloaded between requests
+ config.cache_classes = true
+
+ # Full error reports are disabled and caching is turned on.
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = true
+
+ # Disable Rails's static asset server (Apache or nginx will already do this)
+ config.serve_static_assets = true
+
+ # Compress JavaScripts and CSS
+ config.assets.compress = true
+
+ # Don't fallback to assets pipeline if a precompiled asset is missed
+ config.assets.compile = false
+
+ # Generate digests for assets URLs
+ config.assets.digest = true
+
+ # Defaults to Rails.root.join("public/assets")
+ # config.assets.manifest = YOUR_PATH
+
+ # Specifies the header that your server uses for sending files
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ # config.force_ssl = true
+
+ # See everything in the log (default is :info)
+ config.log_level = :debug
+
+ # Use a different logger for distributed setups
+ # config.logger = SyslogLogger.new
+
+ # Use a different cache store in production
+ # config.cache_store = :mem_cache_store
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
+ # config.assets.precompile += %w( search.js )
+ config.assets.precompile += ['print.css', 'jquery_ui_datepicker/*.js']
+
+ # Enable threaded mode
+ # config.threadsafe!
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation can not be found)
+ config.i18n.fallbacks = true
+
+ # Send deprecation notices to registered listeners
+ config.active_support.deprecation = :notify
end
diff --git a/config/initializers/custom_field_ransack_translations.rb b/config/initializers/custom_field_ransack_translations.rb
new file mode 100644
index 0000000000..1972a869cb
--- /dev/null
+++ b/config/initializers/custom_field_ransack_translations.rb
@@ -0,0 +1,15 @@
+# Load field names for custom fields, for Ransack search
+if Setting.database_and_table_exists?
+ Rails.application.config.after_initialize do
+ I18n.backend.load_translations
+
+ translations = {ransack: { attributes: {}}}
+ CustomField.find_each do |custom_field|
+ model_key = custom_field.klass.model_name.singular
+ translations[:ransack][:attributes][model_key] ||= {}
+ translations[:ransack][:attributes][model_key][custom_field.name] = custom_field.label
+ end
+
+ I18n.backend.store_translations(Setting.locale.to_sym, translations)
+ end
+end
\ No newline at end of file
diff --git a/config/initializers/locale.rb b/config/initializers/locale.rb
index 791ab0321f..05aa39af6e 100644
--- a/config/initializers/locale.rb
+++ b/config/initializers/locale.rb
@@ -3,6 +3,16 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
+
# Set default locale from Settings
+# defer setting the locale until all I18n locales have been initialized
+#------------------------------------------------------------------------------
+
+# Turn off until https://github.com/rails/rails/issues/13164 is fixed
+I18n.config.enforce_available_locales = false
+Rails.application.config.i18n.fallbacks = true
-I18n.default_locale = Setting.locale
+FatFreeCRM.application.config.after_initialize do
+ I18n.default_locale = Setting.locale
+ I18n.fallbacks[:en] = [:"en-US"]
+end
diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb
index a37b91d9ab..4fa77d8d5c 100644
--- a/config/initializers/secret_token.rb
+++ b/config/initializers/secret_token.rb
@@ -3,16 +3,23 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
+
# Be sure to restart your server when you modify this file.
-# Your secret key for verifying the integrity of signed cookies.
+# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
+
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
+# You can use `rake secret` to generate a secure secret key.
-# PLEASE NOTE: This secret token must be changed in your fork of Fat Free CRM.
-# This problem is mitigated when running Fat Free CRM as a Rails Engine.
+# Make sure your secret_key_base is kept private
+# if you're sharing your code publicly.
-if defined?(FatFreeCRM::Application)
- FatFreeCRM::Application.config.secret_token = '51aa366864a80316a85cff0d3762347f4ae3d029d548bef034d56e82b1a2ffac5353ee6719d9b64e4354e2a0b1a901679f46a851c360a2ea377188e4b196b6b6'
+#
+# We should setup a secret token if FFCRM is running in application mode but NOT in engine mode.
+# This functionality has been extracted to lib so it can be tested.
+if FatFreeCRM.application?
+ require 'fat_free_crm/secret_token_generator'
+ FatFreeCRM::SecretTokenGenerator.setup!
end
diff --git a/config/initializers/views.rb b/config/initializers/views.rb
index 00b043d771..706f93ad4e 100644
--- a/config/initializers/views.rb
+++ b/config/initializers/views.rb
@@ -7,55 +7,55 @@
# Register the views that FatFreeCRM provides
#------------------------------------------------------------------------------
-[ {:name => 'contacts_index_brief', :title => 'Brief format', :icon => 'brief.png',
+[ {:name => 'contacts_index_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['contacts'], :actions => ['index'], :template => 'contacts/index_brief'},
- {:name => 'contacts_index_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'contacts_index_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['contacts'], :actions => ['index'], :template => 'contacts/index_long'}, # default index view
- {:name => 'contacts_index_full', :title => 'Full format', :icon => 'full.png',
+ {:name => 'contacts_index_full', :title => 'Full format', :icon => 'fa-list-alt',
:controllers => ['contacts'], :actions => ['index'], :template => 'contacts/index_full'},
- {:name => 'contacts_show_normal', :title => 'Normal format', :icon => 'long.png',
+ {:name => 'contacts_show_normal', :title => 'Normal format', :icon => 'fa-list',
:controllers => ['contacts'], :actions => ['show'], :template => nil}, # default show view
- {:name => 'opportunities_index_brief', :title => 'Brief format', :icon => 'brief.png',
+ {:name => 'opportunities_index_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['opportunities'], :actions => ['index'], :template => 'opportunities/index_brief'},
- {:name => 'opportunities_index_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'opportunities_index_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['opportunities'], :actions => ['index'], :template => 'opportunities/index_long'}, # default
- {:name => 'opportunities_show_normal', :title => 'Normal format', :icon => 'long.png',
+ {:name => 'opportunities_show_normal', :title => 'Normal format', :icon => 'fa-list',
:controllers => ['opportunities'], :actions => ['show'], :template => nil}, # default show view
-
- {:name => 'accounts_index_brief', :title => 'Brief format', :icon => 'brief.png',
+
+ {:name => 'accounts_index_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['accounts'], :actions => ['index'], :template => 'accounts/index_brief'}, # default
- {:name => 'accounts_index_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'accounts_index_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['accounts'], :actions => ['index'], :template => 'accounts/index_long'}, # default
# {:name => 'accounts_show_normal', :title => 'Normal format', :icon => 'long.png',
# :controllers => ['accounts'], :actions => ['show'], :template => 'contacts/index_brief'}, # default show view
- {:name => 'accounts_show_brief', :title => 'Brief format', :icon => 'brief.png',
+ {:name => 'accounts_show_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['accounts'], :actions => ['show'], :template => 'contacts/index_brief'}, # default show view
- {:name => 'accounts_show_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'accounts_show_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['accounts'], :actions => ['show'], :template => 'contacts/index_long'}, # default show view
- {:name => 'leads_index_brief', :title => 'Brief format', :icon => 'brief.png',
+ {:name => 'leads_index_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['leads'], :actions => ['index'], :template => 'leads/index_brief'}, # default
- {:name => 'leads_index_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'leads_index_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['leads'], :actions => ['index'], :template => 'leads/index_long'},
- {:name => 'leads_show_normal', :title => 'Normal format', :icon => 'long.png',
+ {:name => 'leads_show_normal', :title => 'Normal format', :icon => 'fa-list',
:controllers => ['leads'], :actions => ['show'], :template => nil}, # default show view
-
- {:name => 'campaigns_index_brief', :title => 'Brief format', :icon => 'brief.png',
+
+ {:name => 'campaigns_index_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['campaigns'], :actions => ['index'], :template => 'campaigns/index_brief'}, # default
- {:name => 'campaigns_index_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'campaigns_index_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['campaigns'], :actions => ['index'], :template => 'campaigns/index_long'},
- {:name => 'campaigns_show_normal', :title => 'Normal format', :icon => 'long.png',
+ {:name => 'campaigns_show_normal', :title => 'Normal format', :icon => 'fa-list',
:controllers => ['campaigns'], :actions => ['show'], :template => nil}, # default show view
- {:name => 'contact_groups_show_brief', :title => 'Brief format', :icon => 'brief.png',
+ {:name => 'contact_groups_show_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['contact_groups'], :actions => ['show'], :template => 'contacts/index_brief'}, # default
- {:name => 'contact_groups_show_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'contact_groups_show_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['contact_groups'], :actions => ['show'], :template => 'contacts/index_long'},
- {:name => 'events_show_brief', :title => 'Brief format', :icon => 'brief.png',
+ {:name => 'events_show_brief', :title => 'Brief format', :icon => 'fa-bars',
:controllers => ['events'], :actions => ['show'], :template => 'contacts/index_brief'}, # default
- {:name => 'events_show_long', :title => 'Long format', :icon => 'long.png',
+ {:name => 'events_show_long', :title => 'Long format', :icon => 'fa-list',
:controllers => ['events'], :actions => ['show'], :template => 'contacts/index_long'},
].each {|view| FatFreeCRM::ViewFactory.new(view)}
diff --git a/config/locales/cz.yml b/config/locales/cz.yml
index 708afefcac..f2d2d8564c 100644
--- a/config/locales/cz.yml
+++ b/config/locales/cz.yml
@@ -1,213 +1,247 @@
-# Czech translations for Ruby on Rails (inspired by the Slovak localization - thanx to Jozef Fulop)
-# by Jozef Chmel (chmel@jchsoft.cz)
-
+---
cz:
- # Date
- date:
- formats:
- default: "%d.%m.%Y"
- short: "%d %b"
- long: "%d. %B %Y"
- rfc822: "%e %b %Y"
- compact: "%y%m%d"
-
- day_names: [Neděle, Pondělí, Úterý, Středa, Čtvrtek, Pátek, Sobota]
- abbr_day_names: [Ne, Po, Út, St, Čt, Pá, So]
-
- month_names: [~, Leden, Únor, Březen, Duben, Květen, Červen, Červenec, Srpen, Září, Říjen, Listopad, Prosinec]
- abbr_month_names: [~, Led, Úno, Bře, Dub, Kvě, Čvn, Čvc, Srp, Zář, Říj, Lis, Pro]
- order: [ day, month, year]
-
- # Time
- time:
- formats:
- default: "%a %d. %B %Y %H:%M %z"
- short: "%d.%m. %H:%M"
- long: "%A %d. %B %Y %H:%M"
- am: "dopoledne"
- pm: "odpoledne"
-
- # ActiveSupport
- support:
- array:
- words_connector: ", "
- two_words_connector: " a "
- last_word_connector: " a "
- select:
- prompt: "Prosím vyberte si."
-
- # Numbers
- number:
- format:
- precision: 3
- separator: "."
- delimiter: ","
- significant: false
- strip_insignificant_zeros: false
-
- currency:
- format:
- unit: "Kč"
- precision: 2
- format: "%n %u"
- separator: ","
- delimiter: " "
- significant: false
- strip_insignificant_zeros: false
-
- percentage:
- format:
- delimiter: ""
-
- precision:
- format:
- delimiter: ""
-
- human:
- format:
- precision: 1
- delimiter: ""
- significant: false
- strip_insignificant_zeros: false
-
- storage_units:
- format: "%n %u"
- units:
- byte:
- other: "B"
- one: "B"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
- decimal_units:
- format: "%n %u"
- units:
- unit: ""
- thousand: Tisíc
- million: Milión
- billion: Miliarda
- trillion: Trilión
- quadrillion: Quadrilión
-
- # Distance of time ... helper
- datetime:
- prompts:
- second: "Sekunda"
- minute: "Minuta"
- hour: "Hodina"
- day: "Den"
- month: "Měsíc"
- year: "Rok"
- distance_in_words:
- half_a_minute: 'půl minutou'
- less_than_x_seconds:
- one: 'asi před sekundou'
- other: 'asi před %{count} sekundami'
- x_seconds:
- one: 'sekundou'
- other: '%{count} sekundami'
- less_than_x_minutes:
- one: 'před necelou minutou'
- other: 'před ani ne %{count} minutami'
- x_minutes:
- one: 'minutou'
- other: '%{count} minutami'
- about_x_hours:
- one: 'asi hodinou'
- other: 'asi %{count} hodin'
- x_days:
- one: '24 hodin'
- other: '%{count} dny'
- about_x_months:
- one: 'asi měsícem'
- other: 'asi %{count} měsíci'
- x_months:
- one: 'měsícem'
- other: '%{count} měsíci'
- about_x_years:
- one: 'asi rokem'
- other: 'asi %{count} roky'
- over_x_years:
- one: 'před víc jak rokem'
- other: 'víc jak %{count} roky'
- almost_x_years:
- one: "téměř rokem"
- other: "téměř %{count} roky"
-
- helpers:
- select:
- prompt: "Prosím vyberte si"
-
- submit:
- create: 'Vytvořit %{model}'
- update: 'Aktualizovat %{model}'
- submit: 'Uložit %{model}'
- user_exercise_sollution:
- create: 'Zkontrolovat test'
- update: 'Zkontrolovat up'
- submit: 'Zkontrolovat su'
-
- destroy:
- title: "Mázání"
- areyousure: "Jste si jistý, že chcete smazat tuto položku?"
- delete: "Smazat"
- keep: "Zachovat"
- publish:
- title: "Publikace"
- areyousure: "Jste si jistý, že chcete publikovat tento test?"
-
+ date:
+ formats:
+ default: ! '%d.%m.%Y'
+ short: ! '%d %b'
+ long: ! '%d. %B %Y'
+ rfc822: ! '%e %b %Y'
+ compact: ! '%y%m%d'
+ day_names:
+ - Neděle
+ - Pondělí
+ - Úterý
+ - Středa
+ - Čtvrtek
+ - Pátek
+ - Sobota
+ abbr_day_names:
+ - Ne
+ - Po
+ - Út
+ - St
+ - Čt
+ - Pá
+ - So
+ month_names:
+ -
+ - Leden
+ - Únor
+ - Březen
+ - Duben
+ - Květen
+ - Červen
+ - Červenec
+ - Srpen
+ - Září
+ - Říjen
+ - Listopad
+ - Prosinec
+ abbr_month_names:
+ -
+ - Led
+ - Úno
+ - Bře
+ - Dub
+ - Kvě
+ - Čvn
+ - Čvc
+ - Srp
+ - Zář
+ - Říj
+ - Lis
+ - Pro
+ order:
+ - day
+ - month
+ - year
+ time:
+ formats:
+ default: ! '%a %d. %B %Y %H:%M %z'
+ short: ! '%d.%m. %H:%M'
+ long: ! '%A %d. %B %Y %H:%M'
+ am: dopoledne
+ pm: odpoledne
+ support:
+ array:
+ words_connector: ! ', '
+ two_words_connector: ! ' a '
+ last_word_connector: ! ' a '
+ select:
+ prompt: Prosím vyberte si.
+ number:
+ format:
+ precision: 3
+ separator: .
+ delimiter: ! ','
+ significant: false
+ strip_insignificant_zeros: false
+ currency:
+ format:
+ unit: Kč
+ precision: 2
+ format: ! '%n %u'
+ separator: ! ','
+ delimiter: ! ' '
+ significant: false
+ strip_insignificant_zeros: false
+ percentage:
+ format:
+ delimiter: ''
+ precision:
+ format:
+ delimiter: ''
+ human:
+ format:
+ precision: 1
+ delimiter: ''
+ significant: false
+ strip_insignificant_zeros: false
+ storage_units:
+ format: ! '%n %u'
+ units:
+ byte:
+ other: B
+ one: B
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
+ decimal_units:
+ format: ! '%n %u'
+ units:
+ unit: ''
+ thousand: Tisíc
+ million: Milión
+ billion: Miliarda
+ trillion: Trilión
+ quadrillion: Quadrilión
+ datetime:
+ prompts:
+ second: Sekunda
+ minute: Minuta
+ hour: Hodina
+ day: Den
+ month: Měsíc
+ year: Rok
+ distance_in_words:
+ half_a_minute: půl minutou
+ less_than_x_seconds:
+ one: asi před sekundou
+ other: asi před %{count} sekundami
+ x_seconds:
+ one: sekundou
+ other: ! '%{count} sekundami'
+ less_than_x_minutes:
+ one: před necelou minutou
+ other: před ani ne %{count} minutami
+ x_minutes:
+ one: minutou
+ other: ! '%{count} minutami'
+ about_x_hours:
+ one: asi hodinou
+ other: asi %{count} hodin
+ x_days:
+ one: 24 hodin
+ other: ! '%{count} dny'
+ about_x_months:
+ one: asi měsícem
+ other: asi %{count} měsíci
+ x_months:
+ one: měsícem
+ other: ! '%{count} měsíci'
+ about_x_years:
+ one: asi rokem
+ other: asi %{count} roky
+ over_x_years:
+ one: před víc jak rokem
+ other: víc jak %{count} roky
+ almost_x_years:
+ one: téměř rokem
+ other: téměř %{count} roky
+ helpers:
+ select:
+ prompt: Prosím vyberte si
+ submit:
+ create: Vytvořit %{model}
+ update: Aktualizovat %{model}
+ submit: Uložit %{model}
+ user_exercise_sollution:
+ create: Zkontrolovat test
+ update: Zkontrolovat up
+ submit: Zkontrolovat su
+ destroy:
+ title: Mázání
+ areyousure: Jste si jistý, že chcete smazat tuto položku?
+ delete: Smazat
+ keep: Zachovat
+ publish:
+ title: Publikace
+ areyousure: Jste si jistý, že chcete publikovat tento test?
+ errors:
+ format: ! 'Položka: ''%{attribute}'', %{message}.'
+ messages:
+ inclusion: není v seznamu povolených hodnot
+ exclusion: je vyhrazeno pro jiný účel
+ invalid: není dobře vyplněn
+ confirmation: nebylo potvrzeno
+ accepted: musí být potvrzeno
+ empty: nesmí být prázdný/é
+ blank: je třeba vyplnit
+ too_long: je příliš dlouhá/ý (max. %{count} znaků)
+ too_short: je příliš krátký/á (min. %{count} znaků)
+ wrong_length: nemá správnou délku (očekáváno %{count} znaků)
+ taken: již databáze obsahuje
+ not_a_number: není číslo
+ not_an_integer: není je celé číslo
+ greater_than: musí být větší než %{count}
+ greater_than_or_equal_to: musí být větší nebo rovno %{count}
+ equal_to: musí být rovno %{count}
+ less_than: musí být méně než %{count}
+ less_than_or_equal_to: musí být méně nebo rovno %{count}
+ odd: musí být liché číslo
+ even: musí být sudé číslo
+ activerecord:
errors:
- format: "Položka: '%{attribute}', %{message}."
- messages: &errors_messages
- inclusion: "není v seznamu povolených hodnot"
- exclusion: "je vyhrazeno pro jiný účel"
- invalid: "není dobře vyplněn"
- confirmation: "nebylo potvrzeno"
- accepted: "musí být potvrzeno"
- empty: "nesmí být prázdný/é"
- blank: "je třeba vyplnit"
- too_long: "je příliš dlouhá/ý (max. %{count} znaků)"
- too_short: "je příliš krátký/á (min. %{count} znaků)"
- wrong_length: "nemá správnou délku (očekáváno %{count} znaků)"
- taken: "již databáze obsahuje"
- not_a_number: "není číslo"
- not_an_integer: "není je celé číslo"
- greater_than: "musí být větší než %{count}"
- greater_than_or_equal_to: "musí být větší nebo rovno %{count}"
- equal_to: "musí být rovno %{count}"
- less_than: "musí být méně než %{count}"
- less_than_or_equal_to: "musí být méně nebo rovno %{count}"
- odd: "musí být liché číslo"
- even: "musí být sudé číslo"
-
- # ActiveRecord validation messages
- activerecord:
- errors:
- template:
- header:
- one: "Změny na %{model} nebyly uložené. Vyskytla se 1 chyba"
- other: "Změny na %{model} nebyly uložené. Vyskytlo se %{count} chyb"
- body: "Vyskytly se problémy na následujících položkách:"
-
- messages:
- taken: "jste už použili"
- record_invalid: "Validáce byla neuspešná: %{errors}"
- <<: *errors_messages
-
- full_messages:
- format: "%{attribute} %{message}"
-
- models:
- attachment:
- attributes:
- file:
- carrierwave_processing_error: "Chyba při zpracování uploadu souboru (carrierwave)"
-
- activemodel:
- errors:
- template:
- header:
- one: "Při ukládání objektu %{model} došlo k chybám a nebylo jej možné uložit"
- other: "Při ukládání objektu %{model} došlo ke %{count} chybám a nebylo možné jej uložit"
- body: "Následující pole obsahují chybně vyplněné údaje:"
+ template:
+ header:
+ one: Změny na %{model} nebyly uložené. Vyskytla se 1 chyba
+ other: Změny na %{model} nebyly uložené. Vyskytlo se %{count} chyb
+ body: ! 'Vyskytly se problémy na následujících položkách:'
+ messages:
+ inclusion: není v seznamu povolených hodnot
+ exclusion: je vyhrazeno pro jiný účel
+ invalid: není dobře vyplněn
+ confirmation: nebylo potvrzeno
+ accepted: musí být potvrzeno
+ empty: nesmí být prázdný/é
+ blank: je třeba vyplnit
+ too_long: je příliš dlouhá/ý (max. %{count} znaků)
+ too_short: je příliš krátký/á (min. %{count} znaků)
+ wrong_length: nemá správnou délku (očekáváno %{count} znaků)
+ taken: jste už použili
+ not_a_number: není číslo
+ not_an_integer: není je celé číslo
+ greater_than: musí být větší než %{count}
+ greater_than_or_equal_to: musí být větší nebo rovno %{count}
+ equal_to: musí být rovno %{count}
+ less_than: musí být méně než %{count}
+ less_than_or_equal_to: musí být méně nebo rovno %{count}
+ odd: musí být liché číslo
+ even: musí být sudé číslo
+ record_invalid: ! 'Validáce byla neuspešná: %{errors}'
+ full_messages:
+ format: ! '%{attribute} %{message}'
+ models:
+ attachment:
+ attributes:
+ file:
+ carrierwave_processing_error: Chyba při zpracování uploadu souboru (carrierwave)
+ activemodel:
+ errors:
+ template:
+ header:
+ one: Při ukládání objektu %{model} došlo k chybám a nebylo jej možné uložit
+ other: Při ukládání objektu %{model} došlo ke %{count} chybám a nebylo možné
+ jej uložit
+ body: ! 'Následující pole obsahují chybně vyplněné údaje:'
diff --git a/config/locales/cz_fat_free_crm.yml b/config/locales/cz_fat_free_crm.yml
index 8367cb8e95..6f89747ff9 100644
--- a/config/locales/cz_fat_free_crm.yml
+++ b/config/locales/cz_fat_free_crm.yml
@@ -1,20 +1,18 @@
+# Czech translations for Ruby on Rails (inspired by the Slovak localization - thanx to Jozef Fulop)
+# by Jozef Chmel (chmel@jchsoft.cz)
+
+---
cz:
language: Český (CZ)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Vše
at: v
here: zde
- no_button: 'Ne'
+ no_button: Ne
not_implemented: Čeká na vytvoření.
or: nebo
- select_none: '-- nic --'
- select_blank: '-- vyber --'
- yes_button: 'Ano'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- nic --
+ select_blank: -- vyber --
+ yes_button: Ano
tab_dashboard: Hlavní panel
tab_tasks: Úkoly
tab_campaigns: Kampaně
@@ -22,30 +20,25 @@ cz:
tab_accounts: Klienti
tab_contacts: Kontakty
tab_opportunities: Příležitosti
-
admin_tab_users: Uživatelé
admin_tab_fields: Pole
admin_tab_settings: Nastavení
admin_tab_plugins: Pluginy
-
affiliate: Pobočka
competitor: Konkurent
customer: Zákazník
partner: Partner
reseller: Přeprodejce
vendor: Prodejce
-
planned: Naplánováno
started: Odstartováno
on_hold: V čekání
completed: Hotovo
called_off: Odřeknuté
-
new: Nové
contacted: Kontaktované
converted: Převedené
rejected: Odmítnuté
-
cold_call: První zavolání
conference: Konference
online: Online Marketing
@@ -54,7 +47,6 @@ cz:
web: Website
word_of_mouth: O čem se mluví
other: Ostatní
-
prospecting: Průzkum
analysis: Analýza
presentation: Prezentace
@@ -63,16 +55,13 @@ cz:
final_review: Závěrečné hodnocení
won: Uzavřené/Výhra
lost: Uzavřené/Prohra
-
call: Volání
email: Email
follow_up: Pokračování
lunch: Oběd
meeting: Schůzka
money: Peníze
- presentation: Prezentace
trip: Cesta
-
overdue: Opožděný
due_asap: Co nejdříve
due_today: Dnes
@@ -81,24 +70,17 @@ cz:
due_next_week: Příští týden
due_later: Někdy později
due_specific_date: V konkrétní datum...
-
completed_today: Dnes
completed_yesterday: Vřera
completed_last_week: Minulý týden
completed_this_month: Tento měsíc
completed_last_month: Minulý měsíc
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: Jedna hodina
one_day: Jeden den
two_days: Dva dny
one_week: Jeden týden
two_weeks: Dva týdny
one_month: Jeden měsíc
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -111,74 +93,71 @@ cz:
account:
attributes:
name:
- missing_account_name: "^Zadejte jméno klienta."
+ missing_account_name: ^Zadejte jméno klienta.
access:
- share_account: "^Určete uživatele pro sdílení klienta.."
+ share_account: ^Určete uživatele pro sdílení klienta..
campaign:
attributes:
name:
- missing_campaign_name: "^Zadejte jméno kampaně."
+ missing_campaign_name: ^Zadejte jméno kampaně.
ends_on:
- dates_not_in_sequence: "^Ujistěte se, že počáteční datum je před konečným."
+ dates_not_in_sequence: ^Ujistěte se, že počáteční datum je před konečným.
access:
- share_campaign: "^Určete uživatele pro sdílení kampaně."
+ share_campaign: ^Určete uživatele pro sdílení kampaně.
contact:
attributes:
first_name:
- missing_first_name: "^Zadejte jméno."
+ missing_first_name: ^Zadejte jméno.
last_name:
- missing_last_name: "^Zadejte příjmení."
+ missing_last_name: ^Zadejte příjmení.
access:
- share_contact: "^Určete uživatele pro sdílení kontaktu."
+ share_contact: ^Určete uživatele pro sdílení kontaktu.
lead:
attributes:
first_name:
- missing_first_name: "^Zadejte jméno."
+ missing_first_name: ^Zadejte jméno.
last_name:
- missing_last_name: "^Zadejte příjmení."
+ missing_last_name: ^Zadejte příjmení.
access:
- share_lead: "^Určete uživatele pro sdílení s lead."
+ share_lead: ^Určete uživatele pro sdílení s lead.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Zadejte název příležitosti."
+ missing_opportunity_name: ^Zadejte název příležitosti.
access:
- share_opportunity: "^Určete uživatele pro sdílení příležitosti."
+ share_opportunity: ^Určete uživatele pro sdílení příležitosti.
task:
attributes:
name:
- missing_task_name: "^Zadejte název úkolu."
+ missing_task_name: ^Zadejte název úkolu.
calendar:
- invalid_date: "^Zadejte platné datum."
+ invalid_date: ^Zadejte platné datum.
user:
attributes:
username:
- missing_username: "^Zadejte jméno uživatele."
- username_taken: "^Takový uživatel již existuje."
+ missing_username: ^Zadejte jméno uživatele.
+ username_taken: ^Takový uživatel již existuje.
email:
- missing_email: "^Zadejte email."
- email_in_use: "^Uživatel s tímto emailem je již v systému zaveden."
-
+ missing_email: ^Zadejte email.
+ email_in_use: ^Uživatel s tímto emailem je již v systému zaveden.
msg_account_suspended: Uživateslský účet byl pozastaven.
password_reset_instruction: instrukce resetování hesla
-
- # Controllers.
- #----------------------------------------------------------------------------
msg_account_created: Váš účet byl vytvořen a čeká na schválení administrátorem.
msg_account_not_approved: Váš účet ještě nebyl schválen.
- msg_asset_deleted: "%{value} byl smazán."
+ msg_asset_deleted: ! '%{value} byl smazán.'
msg_asset_not_available: Toto %{value} již není dostupné.
msg_asset_not_authorized: Nejste autorizován prohlížet %{value}.
- msg_assets_not_available: %{value} není dostupné.
- msg_asset_rejected: "%{value} byla odmítnuta."
- msg_bad_image_file: "^Nahrávaný obrázek je příliš velký - upravte velikost."
- msg_cant_create_related: "Nelze vytvořit %{asset} pokud %{related} již není dostupný."
- msg_cant_delete_user: "^Nelze smazat uživatele pokud %{value} pokud je připárována položka aktivní."
- msg_cant_do: "Nelze %{action} na %{asset} pokud tento již není dostupný."
+ msg_assets_not_available: ! '%{value} není dostupné.'
+ msg_asset_rejected: ! '%{value} byla odmítnuta.'
+ msg_bad_image_file: ^Nahrávaný obrázek je příliš velký - upravte velikost.
+ msg_cant_create_related: Nelze vytvořit %{asset} pokud %{related} již není dostupný.
+ msg_cant_delete_user: ^Nelze smazat uživatele pokud %{value} pokud je připárována
+ položka aktivní.
+ msg_cant_do: Nelze %{action} na %{asset} pokud tento již není dostupný.
msg_email_not_found: Uživatel s tímto emailem není v sytému zadán.
msg_enter_new_password: Zadejte heslo.
msg_goodbye: Byl jste odhlášen. Díky za použití Fat Free CRM!
- msg_invalid_password: "^Zadejte správne aktální heslo"
+ msg_invalid_password: ^Zadejte správne aktální heslo
msg_invalig_login: Špatné jméno nebo heslo.
msg_last_login: Váše poslední přihlášení bylo %{value}.
msg_login_needed: Pro přístup k této stránce musíte být přihlášen.
@@ -186,14 +165,12 @@ cz:
msg_password_changed: Vaše heslo byl změněno.
msg_password_not_changed: Vaše heslo nebylo změněno.
msg_password_updated: Vaše heslo byl úspěšne upraveno.
- msg_pwd_instructions_sent: Instrukce pro přenastavení hesla vám byly zaslány na email.
+ msg_pwd_instructions_sent: Instrukce pro přenastavení hesla vám byly zaslány na
+ email.
msg_require_admin: Pro přístup k této stránce musíte být přihlášen jako administrátor.
msg_successful_signup: Registrace byla úspěšná. Vítejte ve Fat Free CRM!
msg_welcome: Vítejte ve Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": hodnota zvýhodnění
+ option_amount*probability: hodnota zvýhodnění
activity_options: Zobraz %{models} %{action_type} uživatelem %{user} za období %{period}.
all_users: všichni uživatelé
option_after: po
@@ -227,10 +204,8 @@ cz:
email_past_participle: email
show_per_page: Zobraz %{number} %{models} za stránku užívající %{fmt} format.
sort_by: Setřiď %{models} podle %{field}.
- sort_by_displaying: Setřiď %{models} podle %{field} zobrazující jméno %{position} příjmení.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Setřiď %{models} podle %{field} zobrazující jméno %{position}
+ příjmení.
aim: AOL IM
already_signed_up: Již registrováný?
alt_email: Alternativní email
@@ -240,12 +215,12 @@ cz:
contact_info: Kontaktní informace
current_password: Aktuální heslo
edit_profile: Upravit profil
- # email: Email # <-- Already defined as the task type if Settings.
first_name: Jméno
google: Google IM
gravatar_help: Neznáte Gravatars? Více o Gravatars
image_file: Soubor obráku
- image_help: Obrázek který nahrajete bude automaticky převeden na velikost 75 x 75 pixelů. Podporované formáty jsou GIF, JPG, and PNG.
+ image_help: Obrázek který nahrajete bude automaticky převeden na velikost 75 x 75
+ pixelů. Podporované formáty jsou GIF, JPG, and PNG.
job_title: Popis
last_name: Příjmění
login_now_link: Přihlašte se!
@@ -266,17 +241,11 @@ cz:
user: Uživatel
username: Uživatelské jméno
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Zapomenuté heslo
login: Přihlásit
no_account: Nemá účet?
remember_me: Pamatovat si mě
sign_up_now: Registrovat teď!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: Klient
account_small: klient
account_summary: Výpis klienta
@@ -304,9 +273,6 @@ cz:
shipping_address: Doručovací adresa
total_accounts: Celkem klientů
website: Webstránka
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Aktuální
actual_performance: Aktuální výkonnost
budget: Rozpočet
@@ -321,7 +287,7 @@ cz:
campaigns_small: kampaně
conversion: Konverze
conversion_label: Konverze (%)
- conversion_number: "%{value} konverze"
+ conversion_number: ! '%{value} konverze'
create_campaign: Vytvořit kampaň
end_date: Koncové datum
finished_on: hotovo na %{value}
@@ -329,11 +295,13 @@ cz:
no_start_date: nebyl určeno počáteční datum
number_of_leads: Možných klientů
objectives: Cíle
- objectives_help: Zadejte cílový počet budoucích možných klientů, poměr konverze z možných klientů do příležitostí, cílová tržba a rozpočet kampaně. Tato čísla pomohou určit výkonost kampaně.
+ objectives_help: Zadejte cílový počet budoucích možných klientů, poměr konverze
+ z možných klientů do příležitostí, cílová tržba a rozpočet kampaně. Tato čísla
+ pomohou určit výkonost kampaně.
objectives_small: cíle kampaně
revenue: tržba
revenue_label: Tržba (CZK)
- revenue_number: "%{value} tržba"
+ revenue_number: ! '%{value} tržba'
save_campaign: Uložit kampaň
start_date: Počáteční datum
started_ago: spuštěno před %{value}
@@ -344,9 +312,6 @@ cz:
was_supposed_to_finish: má být dokončeno za %{value}
was_supposed_to_start: má začít v %{time_ago} před %{start_date}
was_supposed_to_start_in: má začít v %{starts_in} a %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Jiné
blog: Web/Blog
contact: Kontakt
@@ -356,37 +321,44 @@ cz:
contacts_small: kontakty
create_contact: Vytvořit kontakt
department: Oddělení
- department_small: '%{value} oddělení'
+ department_small: ! '%{value} oddělení'
do_not_call: Nevolat
extra_info: Extra informace
extra_info_small: extra informace
facebook: Facebook
linked_in: LinkedIn
myself: Já osobně
- permissions_intro_private: Standardně budete mít přístup k %{value}. Oprávnění můžete změnit později.
- permissions_intro_public: Standardně budou mít všichni uživatelé přístup k %{value}. Oprávnění můžete změnit později.
- permissions_intro_shared: Standardně budou mít vybraní uživatelé přístup k %{value}. Oprávnění můžete změnit později.
+ permissions_intro_private: Standardně budete mít přístup k %{value}. Oprávnění můžete
+ změnit později.
+ permissions_intro_public: Standardně budou mít všichni uživatelé přístup k %{value}.
+ Oprávnění můžete změnit později.
+ permissions_intro_shared: Standardně budou mít vybraní uživatelé přístup k %{value}.
+ Oprávnění můžete změnit později.
referred_by: Dodal
referred_by_small: dodal
save_contact: uložit kontakt
twitter: Twitter
web_presence: Webstránky
web_presence_small: webstránky
- works_at: "%{job_title} v %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} v %{company}'
convert: Konvertovat
convert_lead: Konvertovat možného klienta
- convert_lead_permissions_intro: Oprávnění kontaktu budou přenesena. Oprávnění můžete změnit později.
- convert_lead_text: Zkonvertováním možného klienta %{value} vznikne kontkat pripojený na existujícího nebo nového klienta. Status možného klienta bude nastaven na konvertovaný.
+ convert_lead_permissions_intro: Oprávnění kontaktu budou přenesena. Oprávnění můžete
+ změnit později.
+ convert_lead_text: Zkonvertováním možného klienta %{value} vznikne kontkat pripojený
+ na existujícího nebo nového klienta. Status možného klienta bude nastaven na konvertovaný.
create_lead: Přidat možného klienta
- create_opp_for_contact: Můžete automaticky vytvořit příležitost pro kontkat %{value} tím že určíte jméno, aktuální stádium, očekávaný čas ukončení, prodejní pravděpodobnost, objem nabídky, a nabídnutý rabat.
+ create_opp_for_contact: Můžete automaticky vytvořit příležitost pro kontkat %{value}
+ tím že určíte jméno, aktuální stádium, očekávaný čas ukončení, prodejní pravděpodobnost,
+ objem nabídky, a nabídnutý rabat.
lead: Možný klient
lead_info_small: kontakt možného klienta
- lead_permissions_intro_private: Standardně budou oprávnění zkopírována z kampaně nebo jako soukromá. Oprávnění můžete změnit později.
- lead_permissions_intro_public: Standardně budou oprávnění zkopírována z kampaně nebo jako veřejná. Oprávnění můžete změnit později.
- lead_permissions_intro_shared: Standardně budou oprávnění zkopírována z kampaně nebo sdílená s určenými uživateli. Oprávnění můžete změnit později.
+ lead_permissions_intro_private: Standardně budou oprávnění zkopírována z kampaně
+ nebo jako soukromá. Oprávnění můžete změnit později.
+ lead_permissions_intro_public: Standardně budou oprávnění zkopírována z kampaně
+ nebo jako veřejná. Oprávnění můžete změnit později.
+ lead_permissions_intro_shared: Standardně budou oprávnění zkopírována z kampaně
+ nebo sdílená s určenými uživateli. Oprávnění můžete změnit později.
lead_small: možný klient
lead_status_small: stav možného klienta
lead_summary: Souhrn možného klienta
@@ -401,9 +373,6 @@ cz:
source: Zdroj
status: Stav
total_leads: Celkem možných klientů
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Množství
close_date: Datum uzavření
closed_ago_on: uzavřeno před %{time_ago} v %{date}
@@ -425,7 +394,7 @@ cz:
opportunity: Příležitost
opportunity_small: příležitost
opportunity_summary: Letmý náhled na příležitost
- opportunity_summary_text: "%{amount} s rabatem %{discount} a %{probability} pravděpodobností"
+ opportunity_summary_text: ! '%{amount} s rabatem %{discount} a %{probability} pravděpodobností'
past_due: zpoždění, očekávaný datum ukončení byl před %{value}
probability: Pravděpodobnost
probability_number: a %{value} pravděpodobnosti
@@ -433,9 +402,6 @@ cz:
stage: Stadium
total_opportunities: Celkem příležitostí
weighted_amount: Množství přízně
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
task: Úkol
task_small: úkol
tasks: Úkoly
@@ -451,13 +417,13 @@ cz:
due: kdy
feel_free: Směle můžete
move_to: přesunout do
- no_tasks: "Nemáte žádné %{value} úkoly"
+ no_tasks: Nemáte žádné %{value} úkoly
no_tasks_pending: nevyřízené
no_tasks_assigned: přiřazené
no_tasks_completed: hotové
pending_tab: Nevyřízené
pending_tasks: Nevyřízené úkoly
- related: 'k:'
+ related: ! 'k:'
save_task: Uložit úkol
task_assigned: Úkol byl přiřazen k %{value}
task_assigned_to: a přiřazen k %{value}
@@ -472,14 +438,9 @@ cz:
task_from: Z %{value}
task_overdue: zpozdění, v důsledku
task_pending: Úkol byl převeden do dosud nevyřízených
- task_small: úkol
- tasks: Úkoly
total_tasks: Celkem %{value}
view_assigned_tasks: zobrazit přiřazené úkoly
view_pending_tasks: zobrazit nevyřízené úkoly
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: zkomentoval
action_completed: dokončil
action_created: vytvořil
@@ -501,9 +462,6 @@ cz:
subject_lead: Možný klient
subject_opportunity: Příležitost
subject_task: Úkol
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Přidat poznámku
save_note: Uložit poznámku
add_note_help: Přidat novou poznámku...
@@ -515,15 +473,15 @@ cz:
close_form: Zavřít formulář
confirm_delete: Jste si jitstý že chcete smazat %{value}?
copy_permissions: Kopírovat %{value} oprávnění
- could_not_find: "Nenalezeny žádné záznamy. Zde lze "
- could_not_find_matching: "Nemohu nalézt odpovídající %{value}"
+ could_not_find: ! 'Nenalezeny žádné záznamy. Zde lze '
+ could_not_find_matching: Nemohu nalézt odpovídající %{value}
create_new: vytvořit
create_a_new: vytvořit
select_existing: vyber existující
delete: Smazat
discard: Vyřadit
edit: Upravit
- items_total: '%{count} celkem.'
+ items_total: ! '%{count} celkem.'
less: Méně...
me: mnou
more: více...
@@ -540,11 +498,11 @@ cz:
select_task: Vyber úkol
select_opportunity: Vyber příležitost
search_assets: Vyhledat %{value}
- time_ago: "před %{value}"
+ time_ago: před %{value}
background_info: Pozadí
address: Addresa
- street1: Ulice 1 # NEW
- street2: Ulice 2 # NEW
+ street1: Ulice 1
+ street2: Ulice 2
city: Obec
zipcode: PSČ
state: Stát
@@ -553,9 +511,6 @@ cz:
collapse_all: Sbalit vše
expanded: Rozvinutý
collapsed: Sbalený
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: O webu
about_dev_group: Diskuzní skupina pro vývojáře
about_features: Vlastnosti a chyby
@@ -564,34 +519,24 @@ cz:
about_ffc_version: verze Fat Free CRM
about_home_page: Domácí stránka
about_project_page: Stránka projektu
- about_thank_you: Díky že používíte Fat Free CRM! Vážímwe si vašeho businesu a doufáme že jste spokojeni s naším software.
+ about_thank_you: Díky že používíte Fat Free CRM! Vážímwe si vašeho businesu a doufáme
+ že jste spokojeni s naším software.
about_twitter: Zprávy z Twitteru
about_user_group: Diskutní skupina pro uživatele
admin: Admin.
logout: Odhlásit
quick_find: Rychlé hledání
welcome: Vítejte
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Úprava komentáře
show: Zobrazit
update: Upravit
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Zadejte vaše nové heslo a potvrďte jej.
- password_intro: Zadejte váš email a následně vám budou zaslány instrukce pro obnovu hesla.
+ password_intro: Zadejte váš email a následně vám budou zaslány instrukce pro obnovu
+ hesla.
reset_password: Obnovit heslo
update_password_and_login: Aktualizujte přihlašovací jméno a heslo
-
- # Views -> Admin
- #----------------------------------------------------------------------------
back_to_crm: Zpět na Fat Free CRM
crm_admin_page: Fat Free CRM Administrace
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Schválit
create_user: Vytvořit uživatele
last_seen: naposledy viděn před %{value}
@@ -604,7 +549,7 @@ cz:
user_awaits_approval: čeka na schválení
user_confirm_delete: Uživatel může být smazan, pokud nemá žádné návaznosti.
user_is_admin: Uživatel je Administrator
- user_never_logged_in: "Ještě se nepřihlásil"
+ user_never_logged_in: Ještě se nepřihlásil
user_signed_up: Regisrován
user_signed_up_on: registrován %{value}
user_since: uživatelm od %{value}
@@ -612,74 +557,53 @@ cz:
user_suspended_on: pozastaven na %{value}
users: Uživatelé
users_small: uživatelé
-
- # Export.
- #----------------------------------------------------------------------------
to_xls: Export do Excelu
to_csv: Export do CSV formátu (včetně smazaných záznamů)
to_rss: RSS feed
to_atom: Atom feed
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - přidaný email - %{subject}
dropbox_notification_intro: Úspěšně přidaný email jste odeslal do dropboxu
dropbox_notification_to: Přidáno do
subject: Předmět
body: Tělo
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 komentář'
- other: '%{count} komentářů'
+ one: 1 komentář
+ other: ! '%{count} komentářů'
contact:
- one: '1 kontakt'
- other: '%{count} kontaktů'
+ one: 1 kontakt
+ other: ! '%{count} kontaktů'
opportunity:
- one: '1 příležitost'
- other: '%{count} příležitostí'
+ one: 1 příležitost
+ other: ! '%{count} příležitostí'
lead:
- one: '1 možný klient'
- other: '%{count} možných klientů'
+ one: 1 možný klient
+ other: ! '%{count} možných klientů'
day:
- one: '1 den'
- other: '%{count} dní'
+ one: 1 den
+ other: ! '%{count} dní'
login:
- one: '1 přihlášení'
- other: '%{count} přihlášení'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 přihlášení
+ other: ! '%{count} přihlášení'
date:
formats:
- mmddyyyy: "%Y-%m-%d"
- mmdd: "%e %b"
- mmddyy: "%e %b, %Y"
-
+ mmddyyyy: ! '%Y-%m-%d'
+ mmdd: ! '%e %b'
+ mmddyy: ! '%e %b, %Y'
time:
formats:
- mmddhhss: "%e %b v %H:%M"
- mmddyyyy_hhmm: "%Y-%m-%d %H:%M"
-
- # will_paginate translations copied for 'en-US'
- #----------------------------------------------------------------------------
+ mmddhhss: ! '%e %b v %H:%M'
+ mmddyyyy_hhmm: ! '%Y-%m-%d %H:%M'
will_paginate:
previous_label: Předchozí
next_label: Další
- page_gap: "…"
-
+ page_gap: ! '…'
page_entries_info:
single_page:
- zero: "Žádní %{plural} nenalezeni"
- one: "Zobrazen 1 %{name}"
- other: "Zobrazeni %{count} %{plural}"
-
- multi_page: "Zobrazeni %{plural} %{from} - %{to} z %{total} celkem"
-
- # Views -> Admin -> Custom Fields
- #----------------------------------------------------------------------------
+ zero: Žádní %{plural} nenalezeni
+ one: Zobrazen 1 %{name}
+ other: Zobrazeni %{count} %{plural}
+ multi_page: Zobrazeni %{plural} %{from} - %{to} z %{total} celkem
custom_fields: Uživatelská pole
create_custom_field: Vytvořit uživatelské pole
create_new_custom_field_for: Vytvořit nové uživatelské pole pro %{klass_name}
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 1adf7728e8..3844d97d7f 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -3,121 +3,155 @@
# contributors:
# - Alexander Dreher - http://github.com/alexdreher - Rails 3 update
+---
de:
date:
formats:
- default: "%d.%m.%Y"
- short: "%e. %b"
- long: "%e. %B %Y"
- only_day: "%e"
-
- day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag]
- abbr_day_names: [So, Mo, Di, Mi, Do, Fr, Sa]
- month_names: [~, Jänner, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember]
- abbr_month_names: [~, Jän, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez]
+ default: ! '%d.%m.%Y'
+ short: ! '%e. %b'
+ long: ! '%e. %B %Y'
+ only_day: ! '%e'
+ day_names:
+ - Sonntag
+ - Montag
+ - Dienstag
+ - Mittwoch
+ - Donnerstag
+ - Freitag
+ - Samstag
+ abbr_day_names:
+ - So
+ - Mo
+ - Di
+ - Mi
+ - Do
+ - Fr
+ - Sa
+ month_names:
+ -
+ - Jänner
+ - Februar
+ - März
+ - April
+ - Mai
+ - Juni
+ - Juli
+ - August
+ - September
+ - Oktober
+ - November
+ - Dezember
+ abbr_month_names:
+ -
+ - Jän
+ - Feb
+ - Mär
+ - Apr
+ - Mai
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Okt
+ - Nov
+ - Dez
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%A, %d. %B %Y, %H:%M Uhr"
- short: "%d. %B, %H:%M Uhr"
- long: "%A, %d. %B %Y, %H:%M Uhr"
- time: "%H:%M"
-
- am: "vormittags"
- pm: "nachmittags"
-
+ default: ! '%A, %d. %B %Y, %H:%M Uhr'
+ short: ! '%d. %B, %H:%M Uhr'
+ long: ! '%A, %d. %B %Y, %H:%M Uhr'
+ time: ! '%H:%M'
+ am: vormittags
+ pm: nachmittags
datetime:
distance_in_words:
- half_a_minute: 'eine halbe Minute'
+ half_a_minute: eine halbe Minute
less_than_x_seconds:
- one: 'weniger als eine Sekunde'
- other: 'weniger als %{count} Sekunden'
+ one: weniger als eine Sekunde
+ other: weniger als %{count} Sekunden
x_seconds:
- one: 'eine Sekunde'
- other: '%{count} Sekunden'
+ one: eine Sekunde
+ other: ! '%{count} Sekunden'
less_than_x_minutes:
- one: 'weniger als eine Minute'
- other: 'weniger als %{count} Minuten'
+ one: weniger als eine Minute
+ other: weniger als %{count} Minuten
x_minutes:
- one: 'eine Minute'
- other: '%{count} Minuten'
+ one: eine Minute
+ other: ! '%{count} Minuten'
about_x_hours:
- one: 'etwa eine Stunde'
- other: 'etwa %{count} Stunden'
+ one: etwa eine Stunde
+ other: etwa %{count} Stunden
x_days:
- one: 'ein Tag'
- other: '%{count} Tage'
+ one: ein Tag
+ other: ! '%{count} Tage'
about_x_months:
- one: 'etwa ein Monat'
- other: 'etwa %{count} Monate'
+ one: etwa ein Monat
+ other: etwa %{count} Monate
x_months:
- one: 'ein Monat'
- other: '%{count} Monate'
+ one: ein Monat
+ other: ! '%{count} Monate'
almost_x_years:
- one: 'fast ein Jahr'
- other: 'fast %{count} Jahre'
+ one: fast ein Jahr
+ other: fast %{count} Jahre
about_x_years:
- one: 'etwa ein Jahr'
- other: 'etwa %{count} Jahre'
+ one: etwa ein Jahr
+ other: etwa %{count} Jahre
over_x_years:
- one: 'mehr als ein Jahr'
- other: 'mehr als %{count} Jahre'
+ one: mehr als ein Jahr
+ other: mehr als %{count} Jahre
prompts:
- second: "Sekunden"
- minute: "Minuten"
- hour: "Stunden"
- day: "Tag"
- month: "Monat"
- year: "Jahr"
-
+ second: Sekunden
+ minute: Minuten
+ hour: Stunden
+ day: Tag
+ month: Monat
+ year: Jahr
number:
format:
precision: 2
- separator: ','
- delimiter: '.'
+ separator: ! ','
+ delimiter: .
significant: false
strip_insignificant_zeros: false
currency:
format:
- unit: '€'
- format: '%n%u'
- separator: ","
- delimiter: ""
+ unit: €
+ format: ! '%n%u'
+ separator: ! ','
+ delimiter: ''
precision: 2
significant: false
strip_insignificant_zeros: false
percentage:
format:
- delimiter: ""
+ delimiter: ''
precision:
format:
- delimiter: ""
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 1
significant: true
strip_insignificant_zeros: true
storage_units:
- # Storage units output formatting.
- # %u is the storage unit, %n is the number (default: 2 MB)
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
+ unit: ''
thousand: Tausend
million: Millionen
billion:
@@ -127,67 +161,77 @@ de:
quadrillion:
one: Billiarde
others: Billiarden
-
support:
array:
- words_connector: ", "
- two_words_connector: " und "
- last_word_connector: " und "
+ words_connector: ! ', '
+ two_words_connector: ! ' und '
+ last_word_connector: ! ' und '
select:
- prompt: "Bitte wählen:"
-
+ prompt: ! 'Bitte wählen:'
activemodel:
errors:
template:
header:
- one: "Konnte %{model} nicht speichern: ein Fehler."
- other: "Konnte %{model} nicht speichern: %{count} Fehler."
- body: "Bitte überprüfen Sie die folgenden Felder:"
+ one: ! 'Konnte %{model} nicht speichern: ein Fehler.'
+ other: ! 'Konnte %{model} nicht speichern: %{count} Fehler.'
+ body: ! 'Bitte überprüfen Sie die folgenden Felder:'
helpers:
select:
- prompt: "Bitte wählen"
-
+ prompt: Bitte wählen
submit:
- create: '%{model} erstellen'
- update: '%{model} aktualisieren'
- submit: '%{model} speichern'
-
+ create: ! '%{model} erstellen'
+ update: ! '%{model} aktualisieren'
+ submit: ! '%{model} speichern'
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "ist kein gültiger Wert"
- exclusion: "ist nicht verfügbar"
- invalid: "ist nicht gültig"
- confirmation: "stimmt nicht mit der Bestätigung überein"
- accepted: "muss akzeptiert werden"
- empty: "muss ausgefüllt werden"
- blank: "muss ausgefüllt werden"
- too_long: "ist zu lang (nicht mehr als %{count} Zeichen)"
- too_short: "ist zu kurz (nicht weniger als %{count} Zeichen)"
- wrong_length: "hat die falsche Länge (muss genau %{count} Zeichen haben)"
- not_a_number: "ist keine Zahl"
- greater_than: "muss größer als %{count} sein"
- greater_than_or_equal_to: "muss größer oder gleich %{count} sein"
- equal_to: "muss genau %{count} sein"
- less_than: "muss kleiner als %{count} sein"
- less_than_or_equal_to: "muss kleiner oder gleich %{count} sein"
- odd: "muss ungerade sein"
- even: "muss gerade sein"
- not_an_integer: "muss ganzzahlig sein"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: ist kein gültiger Wert
+ exclusion: ist nicht verfügbar
+ invalid: ist nicht gültig
+ confirmation: stimmt nicht mit der Bestätigung überein
+ accepted: muss akzeptiert werden
+ empty: muss ausgefüllt werden
+ blank: muss ausgefüllt werden
+ too_long: ist zu lang (nicht mehr als %{count} Zeichen)
+ too_short: ist zu kurz (nicht weniger als %{count} Zeichen)
+ wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben)
+ not_a_number: ist keine Zahl
+ greater_than: muss größer als %{count} sein
+ greater_than_or_equal_to: muss größer oder gleich %{count} sein
+ equal_to: muss genau %{count} sein
+ less_than: muss kleiner als %{count} sein
+ less_than_or_equal_to: muss kleiner oder gleich %{count} sein
+ odd: muss ungerade sein
+ even: muss gerade sein
+ not_an_integer: muss ganzzahlig sein
activerecord:
errors:
template:
header:
- one: "Konnte %{model} nicht speichern: ein Fehler."
- other: "Konnte %{model} nicht speichern: %{count} Fehler."
- body: "Bitte überprüfen Sie die folgenden Felder:"
-
+ one: ! 'Konnte %{model} nicht speichern: ein Fehler.'
+ other: ! 'Konnte %{model} nicht speichern: %{count} Fehler.'
+ body: ! 'Bitte überprüfen Sie die folgenden Felder:'
messages:
- taken: "ist bereits vergeben"
- record_invalid: "Gültigkeitsprüfung ist fehlgeschlagen: %{errors}"
- <<: *errors_messages
-
+ inclusion: ist kein gültiger Wert
+ exclusion: ist nicht verfügbar
+ invalid: ist nicht gültig
+ confirmation: stimmt nicht mit der Bestätigung überein
+ accepted: muss akzeptiert werden
+ empty: muss ausgefüllt werden
+ blank: muss ausgefüllt werden
+ too_long: ist zu lang (nicht mehr als %{count} Zeichen)
+ too_short: ist zu kurz (nicht weniger als %{count} Zeichen)
+ wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben)
+ not_a_number: ist keine Zahl
+ greater_than: muss größer als %{count} sein
+ greater_than_or_equal_to: muss größer oder gleich %{count} sein
+ equal_to: muss genau %{count} sein
+ less_than: muss kleiner als %{count} sein
+ less_than_or_equal_to: muss kleiner oder gleich %{count} sein
+ odd: muss ungerade sein
+ even: muss gerade sein
+ not_an_integer: muss ganzzahlig sein
+ taken: ist bereits vergeben
+ record_invalid: ! 'Gültigkeitsprüfung ist fehlgeschlagen: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/de_fat_free_crm.yml b/config/locales/de_fat_free_crm.yml
index 2695767530..24ab38bd04 100644
--- a/config/locales/de_fat_free_crm.yml
+++ b/config/locales/de_fat_free_crm.yml
@@ -1,812 +1,841 @@
+---
de:
- all: "Alle"
- contact_info: "Kontaktinformation"
- leads: "Anfragen"
- task_created: "Die Aufgabe wurde angelegt"
- about_home_page: "Home-Page"
- msg_login_needed: "Sie müssen angemeldet sein, um diese Seite zu sehen."
- user_since: "Benutzer seit %{value}"
- objectives_help: "Bitte geben Sie die Anzahl erwarteter Anfragen an, die erwartete Lead-Chance-Konversionsrate, Zielumsatz, und das Kampagnenbudget. Diese Angaben ermöglichen die Kontrolle der Kampagneneffizienz."
- option_closes_on: "Abschlussdatum"
- follow_up: "Wiedervorlage"
- no_discount: "ohne Rabatt"
- probability_number: "und %{value} Wahrscheinlichkeit"
- msg_invalig_login: "Ungültiger Benutzername oder Passwort."
- same_as_billing: "wie Rechnungsadresse"
- msg_account_not_approved: "Ihr Profil wurde noch nicht freigegeben."
- presentation: "Präsentation"
- activities: "Aktivitäten"
- fax: "Fax"
- account: "Firma"
- all_events_past_participle: "Aktivitäten"
- facebook: "Facebook"
- one_month: "Ein Monat"
- one_week: "Eine Woche"
- completed_this_month: "Diesen Monat"
- web_presence_small: "Web-Präsenz"
- list: "Liste"
- no_tasks: "Sie haben keine Aufgaben, die %{value} sind"
- lead_status_small: "Anfrage-Status"
- account_summary: "Accountübersicht"
- restrict_by_tag_info: "Nur markierte %{assets} zeigen"
- password_confirmation: "Bestätige das Password"
- admin_fields_info: "Benutzerdefinierte Felder werden in Gruppen angezeigt.\\nErstelle eine neue Feldgruppe, oder füge Felder zu einer der unteren Gruppen hinzu. \\nDu kannst die Reihenfolge per drag & drop ändern oder die Felder zwischen den Gruppen bewegen."
- was_supposed_to_start: "angenommener Beginn vor %{time_ago} am %{start_date}"
- due_later: "Bald fällig"
- action_destroy: "gelöscht"
- msg_require_admin: "Sie müssen Administrator sein, um auf die Seite zu zugreifen."
- budget: "Budget"
- could_not_find: "Konnte %{value} nicht finden. Feel free to"
- leads_small: "Anfragen"
- final_review: "Abschlussprüf."
- closed_ago_on: "erledigt vor %{time_ago} am %{date}"
- subject_opportunity: "Chance"
- create_account: "Account anlegen"
- recent_activity: "Letzte Aktivitäten"
- tag_small: "markiere"
- background_info: "Hintergrund-Informationen"
- conversion_number: "%{value} Konversion"
- yes_button: "Ja"
+ all: Alle
+ contact_info: Kontaktinformation
+ leads: Anfragen
+ task_created: Die Aufgabe wurde angelegt
+ about_home_page: Home-Page
+ msg_login_needed: Sie müssen angemeldet sein, um diese Seite zu sehen.
+ user_since: Benutzer seit %{value}
+ objectives_help: Bitte geben Sie die Anzahl erwarteter Anfragen an, die erwartete
+ Lead-Chance-Konversionsrate, Zielumsatz, und das Kampagnenbudget. Diese Angaben
+ ermöglichen die Kontrolle der Kampagneneffizienz.
+ option_closes_on: Abschlussdatum
+ follow_up: Wiedervorlage
+ no_discount: ohne Rabatt
+ probability_number: und %{value} Wahrscheinlichkeit
+ msg_invalig_login: Ungültiger Benutzername oder Passwort.
+ same_as_billing: wie Rechnungsadresse
+ msg_account_not_approved: Ihr Profil wurde noch nicht freigegeben.
+ presentation: Präsentation
+ activities: Aktivitäten
+ fax: Fax
+ account: Firma
+ all_events_past_participle: Aktivitäten
+ facebook: Facebook
+ one_month: Ein Monat
+ one_week: Eine Woche
+ completed_this_month: Diesen Monat
+ web_presence_small: Web-Präsenz
+ list: Liste
+ no_tasks: Sie haben keine Aufgaben, die %{value} sind
+ lead_status_small: Anfrage-Status
+ account_summary: Accountübersicht
+ restrict_by_tag_info: Nur markierte %{assets} zeigen
+ password_confirmation: Bestätige das Password
+ admin_fields_info: Benutzerdefinierte Felder werden in Gruppen angezeigt.\nErstelle
+ eine neue Feldgruppe, oder füge Felder zu einer der unteren Gruppen hinzu. \nDu
+ kannst die Reihenfolge per drag & drop ändern oder die Felder zwischen den Gruppen
+ bewegen.
+ was_supposed_to_start: angenommener Beginn vor %{time_ago} am %{start_date}
+ due_later: Bald fällig
+ action_destroy: gelöscht
+ msg_require_admin: Sie müssen Administrator sein, um auf die Seite zu zugreifen.
+ budget: Budget
+ could_not_find: Konnte %{value} nicht finden. Feel free to
+ leads_small: Anfragen
+ final_review: Abschlussprüf.
+ closed_ago_on: erledigt vor %{time_ago} am %{date}
+ subject_opportunity: Chance
+ create_account: Account anlegen
+ recent_activity: Letzte Aktivitäten
+ tag_small: markiere
+ background_info: Hintergrund-Informationen
+ conversion_number: ! '%{value} Konversion'
+ yes_button: Ja
version:
- create: "%{item} erstellt von %{by}"
- update: "%{item} geändert von %{by}"
- destroy: "%{item} gelöscht von %{by}"
- set_html: "%{attr} auf %{to} geändert"
- unset_html: "%{attr} nicht definiert"
- change_html: "%{attr} wurde von %{from} zu %{to} geändert"
- anonymous: "anonym"
- password_reset_instruction: "Anleitung zum Zurücksetzen des Passwortes"
- new: "Neu"
- select_existing: "wähle Vorhandene aus"
- upload_picture: "Bild hochladen"
- body: "Körper"
- tags: "Tags"
- street1: "Adresszeile 1"
- street2: "Adresszeile 2"
- shipping_address: "Lieferadresse"
- here: "hier"
- select_task: "Wähle Aufgabe aus"
- action_rejected: "abgelehnt"
- logout: "Logout"
- referred_by: "erwähnt von"
- address: "Adresse"
- sign_up: "Registrieren"
- about_ffc: "Über Fat Free CRM"
- convert: "Umwandeln"
- msg_asset_not_available: "%{value} ist nicht länger verfügbar."
- admin_tab_tags: "Markierungen"
- about_twitter: "Twitter updates"
- copy_permissions: "Kopiere %{value} Zugriffsregeln"
- task_assigned: "Die Aufgabe wurde %{value} zugeordnet"
- amount: "Betrag"
- referred_by_small: "erwähnt von"
- make_public: "für alle sichtbar"
- options: "Optionen"
- starts_today: "beginnt heute!"
- option_brief: "kurz"
- tasks: "Aufgabe"
- campaign: "Kampagne"
- option_target_leads: "target Anfragen"
- create_user: "Erstelle Benutzer"
- opportunities: "Chancen"
- accounts_small: "accounts"
- msg_account_suspended: "Das Benutzerkonto wurde abgelehnt."
- permissions_intro_public: "Standardmäßig haben alle Benutzer Zugriff auf den %{value}. Sie können die Zugriffsregeln für den %{value} auch später ändern."
- assigned_tasks: "zugeordnete Aufgaben"
- objectives: "Ziele"
- field_group_unrestricted: "Diese Gruppe gilt für alle %{assets}"
- lead_info_small: "Anfragekontakt"
- call: "Anruf"
- due_asap: "So schnell wie möglich"
- action_completed: "erledigt"
- start_date: "Startdatum"
- msg_last_login: "Sie waren zuletzt abgemeldet am %{value}."
- more: "Mehr..."
- option_last_name: "Nachname"
- end_date: "Enddatum"
- started: "Begonnen"
- admin_tab_plugins: "Plugins"
- company: "Firma"
- to_rss: "RSS feed"
- yahoo: "Yahoo IM"
- phone: "Telefon"
- one_day: "Ein Tag"
- personal_information: "Persönliche Information"
- save_opportunity: "Chance sichern"
- opportunity_small: "Chancen"
- me: "mir"
- none: "Kein(e)"
- field_group_tag_restriction: "Diese Gruppe gilt für %{assets} markiert mit \"%{tag}"
- option_updated_at: "Änderungsdatum"
- keep_private: "nur für mich sichtbar"
- select_none: "-- Kein(e) --"
- about_ffc_version: "Fat Free CRM version"
- budget_label: "Budget (€)"
- currency: "(€)"
- close_date: "Abschlussdatum"
- login_now_link: "Login!"
- user_signed_up_on: "Angemeldet am %{value}"
- on_hold: "Warteschleife"
- gravatar_help: "Gravatar ist nicht bekannt? Lern mehr über Gravatar"
- msg_asset_deleted: "%{value} wurde gelöscht."
- advanced_search_group_first: "Ergebnisse zeigen, bei denen %{combinator} des Folgenden übereinstimmen"
- action_view: "gesehen"
- reject: "Ablehnen"
- use_gravatar: "Gravatar verwenden"
- profile: "Profil"
- edit_field_group: "Editiere Gruppe"
- contacts_options: "Kontakt-Einstellungen"
- contacts_small: "Kontakte"
- save_user: "Benutzer sichern"
- actual_performance: "Aktuelle Leistung"
+ create: ! '%{item} erstellt von %{by}'
+ update: ! '%{item} geändert von %{by}'
+ destroy: ! '%{item} gelöscht von %{by}'
+ set_html: ! '%{attr} auf %{to} geändert'
+ unset_html: ! '%{attr} nicht definiert'
+ change_html: ! '%{attr} wurde von %{from} zu %{to} geändert'
+ anonymous: anonym
+ password_reset_instruction: Anleitung zum Zurücksetzen des Passwortes
+ new: Neu
+ select_existing: wähle Vorhandene aus
+ upload_picture: Bild hochladen
+ body: Körper
+ tags: Tags
+ street1: Adresszeile 1
+ street2: Adresszeile 2
+ shipping_address: Lieferadresse
+ here: hier
+ select_task: Wähle Aufgabe aus
+ action_rejected: abgelehnt
+ logout: Logout
+ referred_by: erwähnt von
+ address: Adresse
+ sign_up: Registrieren
+ about_ffc: Über Fat Free CRM
+ convert: Umwandeln
+ msg_asset_not_available: ! '%{value} ist nicht länger verfügbar.'
+ admin_tab_tags: Markierungen
+ about_twitter: Twitter updates
+ copy_permissions: Kopiere %{value} Zugriffsregeln
+ task_assigned: Die Aufgabe wurde %{value} zugeordnet
+ amount: Betrag
+ referred_by_small: erwähnt von
+ make_public: für alle sichtbar
+ options: Optionen
+ starts_today: beginnt heute!
+ option_brief: kurz
+ tasks: Aufgabe
+ campaign: Kampagne
+ option_target_leads: target Anfragen
+ create_user: Erstelle Benutzer
+ opportunities: Chancen
+ accounts_small: accounts
+ msg_account_suspended: Das Benutzerkonto wurde abgelehnt.
+ permissions_intro_public: Standardmäßig haben alle Benutzer Zugriff auf den %{value}.
+ Sie können die Zugriffsregeln für den %{value} auch später ändern.
+ assigned_tasks: zugeordnete Aufgaben
+ objectives: Ziele
+ field_group_unrestricted: Diese Gruppe gilt für alle %{assets}
+ lead_info_small: Anfragekontakt
+ call: Anruf
+ due_asap: So schnell wie möglich
+ action_completed: erledigt
+ start_date: Startdatum
+ msg_last_login: Sie waren zuletzt abgemeldet am %{value}.
+ more: Mehr...
+ option_last_name: Nachname
+ end_date: Enddatum
+ started: Begonnen
+ admin_tab_plugins: Plugins
+ company: Firma
+ to_rss: RSS feed
+ yahoo: Yahoo IM
+ phone: Telefon
+ one_day: Ein Tag
+ personal_information: Persönliche Information
+ save_opportunity: Chance sichern
+ opportunity_small: Chancen
+ me: mir
+ none: Kein(e)
+ field_group_tag_restriction: Diese Gruppe gilt für %{assets} markiert mit "%{tag}
+ option_updated_at: Änderungsdatum
+ keep_private: nur für mich sichtbar
+ select_none: -- Kein(e) --
+ about_ffc_version: Fat Free CRM version
+ budget_label: Budget (€)
+ currency: (€)
+ close_date: Abschlussdatum
+ login_now_link: Login!
+ user_signed_up_on: Angemeldet am %{value}
+ on_hold: Warteschleife
+ gravatar_help: Gravatar ist nicht bekannt? Lern mehr über Gravatar
+ msg_asset_deleted: ! '%{value} wurde gelöscht.'
+ advanced_search_group_first: Ergebnisse zeigen, bei denen %{combinator} des Folgenden
+ übereinstimmen
+ action_view: gesehen
+ reject: Ablehnen
+ use_gravatar: Gravatar verwenden
+ profile: Profil
+ edit_field_group: Editiere Gruppe
+ contacts_options: Kontakt-Einstellungen
+ contacts_small: Kontakte
+ save_user: Benutzer sichern
+ actual_performance: Aktuelle Leistung
date:
formats:
- mmddyy: " %e. %b %Y"
- mmddyyyy: "%d %B %Y"
- mmdd: " %e. %b"
- prospecting: "Neukunde"
- convert_lead: "Anfrage umwandeln"
- save_note: "Notiz sichern"
- task_due_in: "fällig in %{value}"
- reseller: "Multiplikator"
- opportunities_small: "Chancen"
- no_activity_records: "Keine Aktivitäten gefunden."
- reject_lead_confirm: "Sind Sie sicher, diese Anfrage abzulehnen?"
- tagged: "Markiert"
- msg_cant_do: "Kann %{asset} nicht %{action}, da es nicht mehr verfügbar ist."
- extra_info_small: "zusätzliche Kontaktdaten"
- completed_today: "Heute"
- customer: "Kunde"
- user_active: "Aktiv"
- update_password_and_login: "Passwort ändern und Login"
- task_assigned_to: "und %{value} zugeordnet"
- completed_yesterday: "Gestern"
- completed_tab: "Erledigt"
- create_task_small: "erstellen Sie eine neue Aufgabe"
- linked_in: "LinkedIn"
- pipeline: "Pipeline"
- option_amount*probability: "gewichteter Betrag"
+ mmddyy: ! ' %e. %b %Y'
+ mmddyyyy: ! '%d %B %Y'
+ mmdd: ! ' %e. %b'
+ prospecting: Neukunde
+ convert_lead: Anfrage umwandeln
+ save_note: Notiz sichern
+ task_due_in: fällig in %{value}
+ reseller: Multiplikator
+ opportunities_small: Chancen
+ no_activity_records: Keine Aktivitäten gefunden.
+ reject_lead_confirm: Sind Sie sicher, diese Anfrage abzulehnen?
+ tagged: Markiert
+ msg_cant_do: Kann %{asset} nicht %{action}, da es nicht mehr verfügbar ist.
+ extra_info_small: zusätzliche Kontaktdaten
+ completed_today: Heute
+ customer: Kunde
+ user_active: Aktiv
+ update_password_and_login: Passwort ändern und Login
+ task_assigned_to: und %{value} zugeordnet
+ completed_yesterday: Gestern
+ completed_tab: Erledigt
+ create_task_small: erstellen Sie eine neue Aufgabe
+ linked_in: LinkedIn
+ pipeline: Pipeline
+ option_amount*probability: gewichteter Betrag
views:
admin:
plugins:
- version: "Version"
- description: "Beschreibung"
- author: "Autor"
- msg_pwd_instructions_sent: "Die Anleitung zum Zurücksetzen des Passwortes wurde Ihnen zugeschickt. Prüfen Sie Ihre Mail."
- discount_number: "mit %{value} Rabatt"
- lunch: "Mittag"
- to_atom: "Atom feed"
- option_all_users: "Alle Benutzer"
- option_amount: "Betrag"
- password_intro: "Bitte geben Sie Ihre E-Mailadresse an, wir senden Ihnen die Anleitung zum Zurücksetzen des Passwortes."
+ version: Version
+ description: Beschreibung
+ author: Autor
+ msg_pwd_instructions_sent: Die Anleitung zum Zurücksetzen des Passwortes wurde Ihnen
+ zugeschickt. Prüfen Sie Ihre Mail.
+ discount_number: mit %{value} Rabatt
+ lunch: Mittag
+ to_atom: Atom feed
+ option_all_users: Alle Benutzer
+ option_amount: Betrag
+ password_intro: Bitte geben Sie Ihre E-Mailadresse an, wir senden Ihnen die Anleitung
+ zum Zurücksetzen des Passwortes.
simple_form:
- yes: "Ja"
+ true: Ja
required:
- text: "notwendig"
- mark: "*"
+ text: notwendig
+ mark: ! '*'
error_notification:
- default_message: "Es wurden ein paar Fehler gefunden. Bitte üperprüfen Sie Ihre Eingaben:"
- no: "Nein"
- permissions: "Zugriffsregeln"
- no_match: "Kein %{value} Treffer"
- name: "Name"
- closing_date: "Abschlussdatum ist %{value}"
- no_recent_items: "Es gibt hier noch nichts zum Anzeigen."
- affiliate: "Verbundenes Unternehmen"
- last_seen: "zuletzt eingeloggt vor %{value}"
- status: "Status"
- dropbox_notification_to: "Hinzugefügt zu"
- related: "re:"
- msg_welcome: "Willkommen bei Fat Free CRM!"
- msg_bad_image_file: "^Konnte das angegebene Bild nicht hochladen oder zu zuschneiden."
- save_lead: "Anfrage sichern"
- custom_fields: "Benutzerdefinierte Felder"
- category: "Kategorie"
- create_lead: "Erstelle Anfrage"
- advanced_search_add_condition: "Setze einen Filter"
- due_tomorrow: "Morgen"
- forgot_password: "Passwort vergessen?"
- was_supposed_to_start_in: "angenommener Beginn in %{starts_in} am %{start_date}"
- activity_options: "Zeige %{models} Aktivitäten, die %{user} in der/den letzten %{period} unternommen hat."
- job_title: "Titel"
- completed_last_month: "Letzter Monat"
- campaigns: "Kampagnen"
- advanced_search_submit: "Suche"
- past_due: "überfällig, war vor %{value} fällig"
- destroy_past_participle: "Löschungen"
- create_field: "Erstelle Feld"
- account_small: "Firma"
- started_ago: "Gestartet vor %{value}"
- language: "Deutsch"
- task_from: "Von %{value}"
+ default_message: ! 'Es wurden ein paar Fehler gefunden. Bitte üperprüfen Sie
+ Ihre Eingaben:'
+ false: Nein
+ permissions: Zugriffsregeln
+ no_match: Kein %{value} Treffer
+ name: Name
+ closing_date: Abschlussdatum ist %{value}
+ no_recent_items: Es gibt hier noch nichts zum Anzeigen.
+ affiliate: Verbundenes Unternehmen
+ last_seen: zuletzt eingeloggt vor %{value}
+ status: Status
+ dropbox_notification_to: Hinzugefügt zu
+ related: ! 're:'
+ msg_welcome: Willkommen bei Fat Free CRM!
+ msg_bad_image_file: ^Konnte das angegebene Bild nicht hochladen oder zu zuschneiden.
+ save_lead: Anfrage sichern
+ custom_fields: Benutzerdefinierte Felder
+ category: Kategorie
+ create_lead: Erstelle Anfrage
+ advanced_search_add_condition: Setze einen Filter
+ due_tomorrow: Morgen
+ forgot_password: Passwort vergessen?
+ was_supposed_to_start_in: angenommener Beginn in %{starts_in} am %{start_date}
+ activity_options: Zeige %{models} Aktivitäten, die %{user} in der/den letzten %{period}
+ unternommen hat.
+ job_title: Titel
+ completed_last_month: Letzter Monat
+ campaigns: Kampagnen
+ advanced_search_submit: Suche
+ past_due: überfällig, war vor %{value} fällig
+ destroy_past_participle: Löschungen
+ create_field: Erstelle Feld
+ account_small: Firma
+ started_ago: Gestartet vor %{value}
+ language: Deutsch
+ task_from: Von %{value}
activerecord:
errors:
models:
account:
attributes:
access:
- share_account: "^Bitte geben Sie die Benutzer an, mit denen Sie an dieser Firma arbeiten."
+ share_account: ^Bitte geben Sie die Benutzer an, mit denen Sie an dieser
+ Firma arbeiten.
name:
- missing_account_name: "^Bitte geben Sie den Firmennamen an."
+ missing_account_name: ^Bitte geben Sie den Firmennamen an.
task:
attributes:
calendar:
- invalid_date: "^Bitte geben Sie ein gültiges Datum an."
+ invalid_date: ^Bitte geben Sie ein gültiges Datum an.
name:
- missing_task_name: "^Bitte geben Sie eine Aufgabenbezeichnung an."
+ missing_task_name: ^Bitte geben Sie eine Aufgabenbezeichnung an.
campaign:
attributes:
access:
- share_campaign: "^Bitte geben Sie die Benutzer an, mit denen Sie an dieser Kampagne arbeiten."
+ share_campaign: ^Bitte geben Sie die Benutzer an, mit denen Sie an dieser
+ Kampagne arbeiten.
ends_on:
- dates_not_in_sequence: "^Bitte stellen Sie sicher, dass das Enddatum der Kampagne nach dem Startdatum liegt."
+ dates_not_in_sequence: ^Bitte stellen Sie sicher, dass das Enddatum
+ der Kampagne nach dem Startdatum liegt.
name:
- missing_campaign_name: "^Bitte geben Sie den Namen der Kampagne an."
+ missing_campaign_name: ^Bitte geben Sie den Namen der Kampagne an.
lead:
attributes:
access:
- share_lead: "^Bitte geben Sie die Benutzer an, mit denen Sie an dieser Kundenanfrage arbeiten."
+ share_lead: ^Bitte geben Sie die Benutzer an, mit denen Sie an dieser
+ Kundenanfrage arbeiten.
first_name:
- missing_first_name: "^Bitte geben Sie den Vornamen an."
+ missing_first_name: ^Bitte geben Sie den Vornamen an.
last_name:
- missing_last_name: "^Bitte geben Sie den Nachnamen an."
+ missing_last_name: ^Bitte geben Sie den Nachnamen an.
authentication:
attributes:
password_field:
- is_not_valid: "ist nicht gültig"
+ is_not_valid: ist nicht gültig
login_field:
- is_not_valid: "ist nicht gültig"
+ is_not_valid: ist nicht gültig
contact:
attributes:
access:
- share_contact: "^Bitte geben Sie die Benutzer an, mit denen Sie an diesem Kontakt arbeiten."
+ share_contact: ^Bitte geben Sie die Benutzer an, mit denen Sie an diesem
+ Kontakt arbeiten.
first_name:
- missing_first_name: "^Bitte geben Sie den Vornamen an."
+ missing_first_name: ^Bitte geben Sie den Vornamen an.
last_name:
- missing_last_name: "^Bitte geben Sie den Nachnamen an."
+ missing_last_name: ^Bitte geben Sie den Nachnamen an.
user:
attributes:
username:
- missing_username: "^Bitte geben Sie einen Benutzernamen an."
- username_taken: "^Dieser Benutzername ist schon vergeben."
+ missing_username: ^Bitte geben Sie einen Benutzernamen an.
+ username_taken: ^Dieser Benutzername ist schon vergeben.
email:
- missing_email: "^Bitte geben Sie eine Mailadresse an."
- email_in_use: "^Es gibt schon einen Benutzer mit dieser Mailadresse."
+ missing_email: ^Bitte geben Sie eine Mailadresse an.
+ email_in_use: ^Es gibt schon einen Benutzer mit dieser Mailadresse.
opportunity:
attributes:
access:
- share_opportunity: "^Bitte geben Sie die Benutzer an, mit denen Sie an dieser Chance arbeiten."
+ share_opportunity: ^Bitte geben Sie die Benutzer an, mit denen Sie an
+ dieser Chance arbeiten.
name:
- missing_opportunity_name: "^Bitte geben Sie die Bezeichnung der Chance an."
+ missing_opportunity_name: ^Bitte geben Sie die Bezeichnung der Chance
+ an.
custom_field:
- required: "^%{field} muss vorhanden sein."
- maxlength: "^%{field} ist zu lang."
- endbeforestart: "^%{field} kann nicht enden bevor es beginnt."
-
+ required: ^%{field} muss vorhanden sein.
+ maxlength: ^%{field} ist zu lang.
+ endbeforestart: ^%{field} kann nicht enden bevor es beginnt.
attribute_options:
opportunity:
stage:
- prospecting: "Untersuchen"
- analysis: "Analyse"
- presentation: "Präsentation"
- proposal: "Angebot"
- negotiation: "Verhandlung"
- final_review: "Finale Überprüfung"
- won: "Geschlossen/Gewonnen"
- lost: "Geschlossen/Verloren"
- feel_free: "Seien Sie so frei und"
- one_hour: "Eine Stunde"
- change_password: "Passwort ändern"
- user: "Benutzer"
- msg_goodbye: "Sie wurden abgemeldet. Danke, dass Sie Fat Free CRM! benutzt haben."
- option_leads_count: "aktuelle Anfragen"
- suspend: "Sperren"
- task_completed_ago: "vor %{value} erledigt"
- probability: "Wahrscheinlk."
- revenue: "Umsatz"
- save_account: "Konto sichern"
- all_users: "alle Benutzer"
- city: "Stadt"
- pending_tab: "Wartend"
- sort_by_displaying: "Sortiere %{models} nach %{field}, Vorname wird %{position} dem Nachnamen angezeigt."
- lead_permissions_intro_public: "Standardmäßig werden die Zugriffsregeln aus der Kampagne kopiert oder auf öffentlich gesetzt. Dies kann auch später durchgeführt werden."
- msg_password_not_changed: "Ihr Passwort wurde nicht geändert."
- user_never_logged_in: "hat sich bisher nicht eingeloggt"
- completed_tasks: "erledigte Aufgaben"
- due_next_week: "Nächste Woche"
- billing_address: "Rechnungsadresse"
- open_in_window: "Öffne %{value} in einem neuen Fenster"
- subject_task: "Aufgabe"
- completed: "Erledigt"
- rejected: "Abgelehnt"
- msg_password_changed: "Ihr Passwort wurde geändert."
+ prospecting: Untersuchen
+ analysis: Analyse
+ presentation: Präsentation
+ proposal: Angebot
+ negotiation: Verhandlung
+ final_review: Finale Überprüfung
+ won: Geschlossen/Gewonnen
+ lost: Geschlossen/Verloren
+ feel_free: Seien Sie so frei und
+ one_hour: Eine Stunde
+ change_password: Passwort ändern
+ user: Benutzer
+ msg_goodbye: Sie wurden abgemeldet. Danke, dass Sie Fat Free CRM! benutzt haben.
+ option_leads_count: aktuelle Anfragen
+ suspend: Sperren
+ task_completed_ago: vor %{value} erledigt
+ probability: Wahrscheinlk.
+ revenue: Umsatz
+ save_account: Konto sichern
+ all_users: alle Benutzer
+ city: Stadt
+ pending_tab: Wartend
+ sort_by_displaying: Sortiere %{models} nach %{field}, Vorname wird %{position} dem
+ Nachnamen angezeigt.
+ lead_permissions_intro_public: Standardmäßig werden die Zugriffsregeln aus der Kampagne
+ kopiert oder auf öffentlich gesetzt. Dies kann auch später durchgeführt werden.
+ msg_password_not_changed: Ihr Passwort wurde nicht geändert.
+ user_never_logged_in: hat sich bisher nicht eingeloggt
+ completed_tasks: erledigte Aufgaben
+ due_next_week: Nächste Woche
+ billing_address: Rechnungsadresse
+ open_in_window: Öffne %{value} in einem neuen Fenster
+ subject_task: Aufgabe
+ completed: Erledigt
+ rejected: Abgelehnt
+ msg_password_changed: Ihr Passwort wurde geändert.
pluralize:
comment:
- other: "%{count} Kommentare"
- one: "1 Kommentar"
+ other: ! '%{count} Kommentare'
+ one: 1 Kommentar
contact:
- other: "%{count} Kontakte"
- one: "1 Kontakt"
+ other: ! '%{count} Kontakte'
+ one: 1 Kontakt
lead:
- other: "%{count} Anfragen"
- one: "1 Anfrage"
+ other: ! '%{count} Anfragen'
+ one: 1 Anfrage
login:
- other: "%{count} logins"
- one: "1 Login"
+ other: ! '%{count} logins'
+ one: 1 Login
opportunity:
- other: "%{count} Chancen"
- one: "1 Chance"
+ other: ! '%{count} Chancen'
+ one: 1 Chance
day:
- other: "%{count} Tage"
- one: "1 Tag"
- profile_language: "Sprache"
- target: "Ziel"
- msg_cant_delete_field_group: "Gruppe konnte nicht gelöscht werden."
- user_signed_up: "Angemeldet"
- tab_campaigns: "Kampagnen"
- make_current_view_list: "Erstelle Liste aus aktueller Ansicht"
- no_closing_date: "kein erwartetes Abschlussdatum"
- about_user_group: "Diskussionsgruppe für Benutzer"
- create_contact: "Erstelle Kontakt"
- msg_logout_needed: "Sie müssen abgemeldet sein, um diese Seite zu sehen."
- view_past_participle: "Ansichten"
- msg_email_not_found: "Es wurde kein Benutzer mit der Mailadresse gefunden."
- msg_enter_new_password: "Bitte geben Sie ein neues Passwort ein."
- self: "Selbst generiert"
- list_name_info: "Wenn Du den Namen einer bestehenden Liste wählst, wird diese Liste mit deinen aktuellen Einstellungen überschrieben."
- msg_account_created: "Ihr Account wurde angelegt und wartet auf die Freigabe durch den Systemadministrator."
- contact: "Kontakt"
+ other: ! '%{count} Tage'
+ one: 1 Tag
+ profile_language: Sprache
+ target: Ziel
+ msg_cant_delete_field_group: Gruppe konnte nicht gelöscht werden.
+ user_signed_up: Angemeldet
+ tab_campaigns: Kampagnen
+ make_current_view_list: Erstelle Liste aus aktueller Ansicht
+ no_closing_date: kein erwartetes Abschlussdatum
+ about_user_group: Diskussionsgruppe für Benutzer
+ create_contact: Erstelle Kontakt
+ msg_logout_needed: Sie müssen abgemeldet sein, um diese Seite zu sehen.
+ view_past_participle: Ansichten
+ msg_email_not_found: Es wurde kein Benutzer mit der Mailadresse gefunden.
+ msg_enter_new_password: Bitte geben Sie ein neues Passwort ein.
+ self: Selbst generiert
+ list_name_info: Wenn Du den Namen einer bestehenden Liste wählst, wird diese Liste
+ mit deinen aktuellen Einstellungen überschrieben.
+ msg_account_created: Ihr Account wurde angelegt und wartet auf die Freigabe durch
+ den Systemadministrator.
+ contact: Kontakt
ransack:
predicates:
- gt: "ist größer als"
- cont: "enthält"
- matches: "entspricht"
- does_not_match: "entspricht nicht"
- not_cont: "enthält nicht"
- not_null: "ist nicht Null"
- lt: "ist weniger als"
- blank: "ist leer"
- not_eq: "ist nicht"
- null: "ist Null"
- eq: "ist"
- present: "ist vorhanden"
- online: "Online Marketing"
- collapsed: "Ausgeblendet"
- advanced_search: "Erweiterte Suche"
- basic_search: "Einfache Suche"
- msg_password_updated: "Passwort wurde erfolgreich geändert."
- admin_tab_settings: "Settings"
- current_password: "Aktuelles Passwort"
- lists: "Listen"
- accounts_advanced_search: "Erweiterte Accountsuche"
- option_revenue: "aktueller Umsatz"
- total_opportunities: "Anzahl Chancen"
- mobile: "Mobiltelefon"
- image_help: "Das hochgeladene Bild wird automatisch auf eine Größe von 75 x 75 Pixels berechnet. Unterstützte Formate sind GIF, JPG, und PNG."
- view_pending_tasks: "ausstehende Aufgaben anzeigen"
- about_features: "Features und Fehler"
- finished_on: "beendet am %{value}"
- assigned_to: "Zugeordnet zu"
- date_created: "Erstellungsdatum"
- subject_campaign: "Kampagne"
- no_account: "Sie haben noch keinen Benutzer?"
- rating: "Rating"
- last_name: "Nachname"
- option_rating: "Rating"
- collapse_all: "Alles ausblenden"
- contacted: "Kontaktiert"
- show: "Zeige"
- date_updated: "Änderungsdatum"
- total_campaigns: "Anzahl Kampagnen"
- msg_cant_create_related: "Kann %{asset} nicht erstellen, da %{related} nicht länger verfügbar ist."
- to_xls: "Exportiere ins Excel"
- campaigns_options: "Kampagnen-Einstellungen"
- subject_lead: "Anfrage"
- option_company: "Firma"
- opportunities_options: "Chance-Einstellungen"
- finishes_in: "beendet in %{value}"
- less: "Weniger..."
- expected_to_close: "Abschluss erwartet in %{time} am %{date}"
- select_a_country: "Wähle ein Land aus"
- msg_assets_not_available: "%{value} sind nicht verfügbar."
- confirm_password_intro: "Bitte geben Sie Ihr neues Passwort ein und bestätigen es."
- assigned_tab: "Zugeordnet"
- tab_leads: "Anfragen"
- save_campaign: "Kampagne sichern"
- move_to: "verschiebe auf"
- add_note: "Notiz anfügen"
- edit_profile: "Profil bearbeiten"
- field_group_confirm_delete: "Exportiere als Comma-separiertes Dateiformat (inklusive gelöschte Datensätze)"
- campaign_and_leads: "Kampagne und zugehörige Anfragen"
+ gt: ist größer als
+ cont: enthält
+ matches: entspricht
+ does_not_match: entspricht nicht
+ not_cont: enthält nicht
+ not_null: ist nicht Null
+ lt: ist weniger als
+ blank: ist leer
+ not_eq: ist nicht
+ ! '': ist Null
+ eq: ist
+ present: ist vorhanden
+ online: Online Marketing
+ collapsed: Ausgeblendet
+ advanced_search: Erweiterte Suche
+ basic_search: Einfache Suche
+ msg_password_updated: Passwort wurde erfolgreich geändert.
+ admin_tab_settings: Settings
+ current_password: Aktuelles Passwort
+ lists: Listen
+ accounts_advanced_search: Erweiterte Accountsuche
+ option_revenue: aktueller Umsatz
+ total_opportunities: Anzahl Chancen
+ mobile: Mobiltelefon
+ image_help: Das hochgeladene Bild wird automatisch auf eine Größe von 75 x 75 Pixels
+ berechnet. Unterstützte Formate sind GIF, JPG, und PNG.
+ view_pending_tasks: ausstehende Aufgaben anzeigen
+ about_features: Features und Fehler
+ finished_on: beendet am %{value}
+ assigned_to: Zugeordnet zu
+ date_created: Erstellungsdatum
+ subject_campaign: Kampagne
+ no_account: Sie haben noch keinen Benutzer?
+ rating: Rating
+ last_name: Nachname
+ option_rating: Rating
+ collapse_all: Alles ausblenden
+ contacted: Kontaktiert
+ show: Zeige
+ date_updated: Änderungsdatum
+ total_campaigns: Anzahl Kampagnen
+ msg_cant_create_related: Kann %{asset} nicht erstellen, da %{related} nicht länger
+ verfügbar ist.
+ to_xls: Exportiere ins Excel
+ campaigns_options: Kampagnen-Einstellungen
+ subject_lead: Anfrage
+ option_company: Firma
+ opportunities_options: Chance-Einstellungen
+ finishes_in: beendet in %{value}
+ less: Weniger...
+ expected_to_close: Abschluss erwartet in %{time} am %{date}
+ select_a_country: Wähle ein Land aus
+ msg_assets_not_available: ! '%{value} sind nicht verfügbar.'
+ confirm_password_intro: Bitte geben Sie Ihr neues Passwort ein und bestätigen es.
+ assigned_tab: Zugeordnet
+ tab_leads: Anfragen
+ save_campaign: Kampagne sichern
+ move_to: verschiebe auf
+ add_note: Notiz anfügen
+ edit_profile: Profil bearbeiten
+ field_group_confirm_delete: Exportiere als Comma-separiertes Dateiformat (inklusive
+ gelöschte Datensätze)
+ campaign_and_leads: Kampagne und zugehörige Anfragen
comment_notification:
- reply_instructions: "Sie können auf dieses e-Mail antworten um ein Kommentar hinzuzufügen, oder zeigen Sie %{entity} in Ihrem Browser an."
- intro: "%{user_full_name} kommentierte %{entity_type}: %{entity_name}"
- my_profile: "Mein Profil"
- add_note_help: "Neue Notiz hinzufügen..."
- select_contact: "Wähle einen Kontakt aus"
- create_field_group: "Erstelle Gruppe."
- create_opportunity: "Erstelle Chance"
- revenue_label: "Umsatz (€)"
- about_project_page: "Projekt-Page"
- tab_dashboard: "Dashboard"
- weighted_amount: "Gewichteter Betrag"
- lead_permissions_intro_shared: "Standardmäßig werden die Zugriffsregeln aus der Kampagne kopiert oder wird vom angegebenen Benutzer übernommen. Dies kann auch später durchgeführt werden."
- completed_last_week: "Letzte Woche"
- department_small: "%{value} Abteilung"
- subject: "Angelegenheit"
- cold_call: "Cold Call"
- label: "Beschriftung"
- state: "Bundesland"
- won: "Erfolg"
- admin_tab_users: "Benutzer"
- no_saved_lists: "Keine gespeicherten Listen"
- days_late: "Verspätet um"
- email: "Email"
- tab_contacts: "Kontakte"
- campaign_small: "Kampagne"
- number_of_leads: "Anzahl der Anfragen"
- mail_to: "Mail an %{value}"
- sign_up_button: "Registrieren"
- campaigns_small: "Kampagnen"
- convert_lead_permissions_intro: "Die Zugriffsregeln des Kontakts werden von der Anfrage übernommen. Sie können die Zugriffsregeln auch später ändern."
- referral: "Empfehlungen"
- admin: "Admin"
- country: "Land"
- objectives_small: "Kamagnen-Ziele"
- planned: "Geplant"
- confirm_delete: "Sie wollen wirklich %{value} löschen?"
- closes_today: "Abschluss heute erwartet!"
- login: "Login"
- approve: "Genehmige"
- negotiation: "Vertrag"
- option_before: "vor"
- convert_lead_text: "Mit der Umwandlung wird %{value} zu einem Kontakt, der mit einem existierenden oder neu zu erstellenden account verbunden wird. Der Anfrage-Status wird automatisch auf umgewandelt geändert."
- subscribe_via_email: "Anmeldung via e-Mail"
- items_total: "%{count} total."
- already_signed_up: "Schon registriert?"
- works_at: "%{job_title} bei %{company}"
- cancel: "Abbrechen"
- subject_user: "Benutzer"
- sign_up_now: "Registrieren Sie sich jetzt!"
- select_opportunity: "Wähle eine Chance aus"
- contact_small: "Kontakt"
- conference: "Konferenz"
- tab_accounts: "Firmen"
- save_profile: "Profil sichern"
- due: "Fällig"
- create_new: "erstelle neu(e)"
- revenue_number: "%{value} Umsatz"
- total_leads: "Anzahl der Anfragen"
- proposal: "Angebot"
- do_not_call: "Nicht anrufen"
- meeting: "Meeting"
- opportunity_summary: "Chancen auf einen Blick"
- username: "Benutzername"
- option_created_at: "Erstellungsdatum"
- users_small: "Benutzer"
- custom_field_options: "Passe die Feldoptionen an"
- about_ffc_resources: "Fat Free CRM Ressourcen (Links öffnen ein neues Fenster)"
- task_due_later: "demnächst fällig"
- myself: "mir"
- mobile_small: "Mobiltelefon"
- expanded: "Erweitert"
- alt_email: "Alternative Email"
- create_past_participle: "Zuletzt erstellte Datensätze"
- sort_by: "Sortiere %{models} nach %{field}"
- aim: "AOL IM"
- update_past_participle: "Aktualisierungen"
- called_off: "Abgesagt"
- task_due_today: "heute fällig"
- converted: "Umgewandelt"
- disable_email_subscriptions: "Deaktiviere e-Mail Benachrichtigungen"
- total_accounts: "Alle Accounts"
- dropbox_notification_intro: "Die e-Mail wurde erfolgreich hinzugefügt, welche an die Dropbox geschickt wurde"
- msg_successful_signup: "Erfolgreiche Anmeldung. Willkommen bei Fat Free CRM!"
- following_users_will_be_notified: "Die folgenden Benutzer werden mittels e-Mail benachrichtigt"
- skype: "Skype"
- partner: "Partner"
- n_a: "N/A"
- extra_info: "Zusatzinformation"
- option_all: "alle"
- new_password: "Neues Passwort"
- two_weeks: "Zwei Wochen"
- campaign_summary: "Kampagnen-Zusammenfassung"
- permissions_intro_shared: "Standardmäßig haben nur ausgewählte Benutzer Zugriff auf den %{value}. Sie können die Zugriffsregeln für den %{value} auch später ändern."
- save_task: "Aufgabe sichern"
- option_target_revenue: "Zielumsatz"
- please_retry: "Versuchen Sie eine andere Abfrage."
- show_per_page: "Zeige %{number} %{models} pro Seite in %{fmt}-Format."
- admin_tab_fields: "Benutzerdefinierte Felder"
- user_suspended_on: "Gesperrt am %{value}"
- conversion: "Konversion"
- due_today: "Heute fällig"
- option_probability: "Wahrscheinlichkeit"
- select_blank: "-- Auswahl --"
- action_reassigned: "neu zugeordnet"
- opportunity: "Chancen"
- total_tasks: "Anzahl %{value}"
- to_csv: "Exportiere als Excel-kompatibles Dateiformat (.csv) inklusive gelöschte Datensätze"
- task: "Aufgaben"
- analysis: "Analyse"
- not_implemented: "Noch nicht implementiert."
- tag_with_taggings_confirm_delete: "Wenn dieser Tag gelöscht wird, wird er von %{value} Einträgen entfernt."
- search_assets: "Suche %{value}"
- task_completed_by: "vor %{time_ago} von %{user} erledigt"
- comment: "Kommentar"
- advanced_search_remove_condition: "Entferne Filter"
- user_admin: "Admin"
- permissions_intro_private: "Standardmäßig haben nur Sie Zugriff auf den %{value}. Sie können die Zugriffsregeln für den %{value} auch später ändern."
- money: "Geld"
- zipcode: "Postleitzahl"
- action_rescheduled: "neu geplant"
- leads_options: "Anfrage-Einstellungen"
- due_this_week: "Diese Woche"
- select_an_account: "Wähle einen Account aus"
- about_thank_you: "Danke, dass Sie Fat Free CRM benutzen! Wir schätzen Ihre Hilfe und hoffen, Sie finden Gefallen an der Software."
- web: "Website"
- accounts_options: "Firmen-Optionen"
- crm_admin_page: "Fat Free CRM Administration"
- tab_tasks: "Aufgaben"
- blog: "Website/Blog"
- source: "Quelle"
- option_after: "nach"
- task_overdue: "zu spät, war fällig am"
- alt_email_small: "Andere"
- vendor: "Verkäufer"
- user_awaits_approval: "Genehmigung erforderlich"
- field_group_tags: "Gruppen mit diesem Tag"
- save_field: "Speichere Feld"
- phone_toll_free: "kostenloses Telefon"
- task_due_now: "jetzt fällig"
- password: "Passwort"
- recent_items: "Aktuelle Änderungen"
- image_file: "Bilddatei"
- about_dev_group: "Diskussionsgruppe für Entwickler"
- lost: "Verloren"
- expand_all: "Alles anzeigen"
- back_to_crm: "Back to Fat Free CRM"
- option_long: "lang"
- edit: "Bearbeiten"
- no_button: "Nein"
- msg_asset_not_authorized: "You are not authorized to view this %{value}."
- task_completed: "erledigt"
- google: "Google IM"
- twitter: "Twitter"
- back: "Zurück"
- subject_email: "Email zu"
- share_with: "für folgende Personen sichtbar"
- first_name: "Vorname"
- competitor: "Mitbewerber"
- lead: "Anfrage"
- contacts: "Kontakte"
- advanced_search_add_group: "Füge eine Filtergruppe hinzu"
- save_tag: "Speichere Tag"
- conversion_label: "Konversion (%)"
- no_tasks_assigned: "zugeordnet"
- select_or_create_tags: "Wähle einige Markierungen aus oder erstelle eine neue Markierung durch Drücken der \"enter\"-Taste."
- phone_small: "Telefon"
- user_suspended: "Gesperrt"
- added_by: "hinzugefügt vor %{time_ago} durch %{user}"
- avatar: "Avatar"
- campaign_targets: "Kampagnen-Ziele"
- msg_asset_rejected: "%{value} wurde abgelehnt."
- pending_tasks: "ausstehende Aufgaben"
- discount: "Rabatt"
- tab_opportunities: "Chancen"
- from: "von"
- time_ago: "vor %{value}"
- stage: "Ebene"
- about: "Über"
- actual: "Aktuell"
- opportunity_summary_text: "%{amount} mit %{discount} Rabatt und %{probability} Wahrscheinlichkeit"
- close_form: "Abschlussformular"
- option_starts_on: "Startdatum"
- discard: "Discard"
- or: "oder"
- two_days: "Zwei Tagen"
- subject_comment: "Kommentar zu"
- could_not_find_matching: "Konnte %{value} nicht finden - passend zu"
- action_won: "gewonnen"
- accounts: "Firmen"
- create_opp_for_contact: "Optional können Sie eine Chance erstellen für %{value} unter Angabe des Namen, aktueller Stand, geschätztes Abschlußdatum, Erfolgswahrscheinlichkeit, Auftragswert und dem angebotenen Rabatt."
- restrict_by_tag: "Schränke anhand des Tags ein"
- reactivate: "Reaktivieren"
- action_update: "aktualisiert"
- notifications_tooltip: "Wenn ein Kommentar hinzugefügt wird, werden alle Abonnenten mittels e-Mail benachrichtigt"
- option_first_name: "Vorname"
- msg_invalid_password: "^Bitte geben Sie Ihr gültiges Passwort ein."
- user_confirm_delete: "Ein Benutzer kann nur gelöscht werden, wenn ihm nichts mehr zugeordnet ist."
- select_lead: "Wähle eine Anfrage aus"
- lead_permissions_intro_private: "Standardmäßig werden die Zugriffsregeln aus der Kampagne kopiert oder auf privat gesetzt. Dies kann auch später durchgeführt werden."
- remember_me: "Erinnere mich"
- edit_comment: "Kommentar bearbeiten"
- no_tasks_pending: "wartend"
- lead_summary: "Anfrage-Zusammenfassung"
- task_small: "Aufgabe"
- assign_to: "Ordne zu"
- due_specific_date: "An bestimmten Datum..."
- versions: "History"
- tasks_small: "Aufgaben"
- create_task: "Erstelle Aufgabe"
- reset_password: "Passwort zurücksetzen"
- view_assigned_tasks: "zugeordnete Aufgaben anzeigen"
- action_create: "erstellt"
- was_supposed_to_finish: "angenommenes Ende am %{value}"
- subject_address: "address on"
- msg_cant_delete_tag: "Konnte '%{value}' nicht löschen, weil es mit Gruppen assoziiert ist. "
- no_start_date: "kein Startdatum angegeben"
- delete: "Löschen"
- website: "Website"
- create_tag: "Tag erstellen"
- save_contact: "Kontakt sichern"
- word_of_mouth: "Mundpropaganda"
- intro: "Sie können die Informationen für %{value} später ändern."
- at: "bei"
- option_ends_on: "Enddatum"
- recent_activity_options: "Letzte Aktivitäten Einstellungen"
- trip: "Trip"
- user_is_admin: "Der Benutzer ist Administrator"
- days_left: "Tage verfügbar"
- option_name: "Name"
- no_tasks_completed: "vollständig"
- other: "Andere"
- advanced_search_group_rest: "...and where %{combinator} of the following match"
- department: "Abteilung"
- field_types:
- tel: "Telefon Nummer"
- string: "Kurze Antwort"
- url: "URL"
- text: "Lange Antwort"
- decimal: "Nummer (Decimal)"
- float: "Nummer (Floating Point)"
- check_boxes: "Checkbox Liste"
- datetime: "Datum & Uhrzeit"
- multiselect: "Multi Auswahl"
- boolean: "Checkbox"
- radio: "Radio Buttons (Einzelauswahl)"
- date: "Datum"
- integer: "Nummer (Integer)"
- email: "Email Adresse"
- select: "Auswahl Liste (Select List)"
- save_field_group: "Gruppe speichern"
- subject_account: "account"
- create_a_new: "neu erstellen"
- dropbox_notification_subject: "dropbox - Email hinzugefügt - %{subject}"
- quick_find: "Suche"
- users: "Benutzer"
- task_pending: "Aufgabe wurde in die Warteschlange bewegt"
- welcome: "Willkommen"
- update: "Ändern"
- will_paginate:
- page_gap: "…"
- page_entries_info:
- single_page:
- zero: "Keine %{plural} gefunden"
- other: "Zeigt alle %{count} %{plural}"
- one: "Zeigt 1 %{name} an"
- multi_page: "Es werden %{from} - %{to} %{plural} von insgesamt %{total} angezeigt"
- next_label: "Weiter →"
- previous_label: "← Zurück"
- added_ago: "hinzugefügt vor %{value}"
- create_campaign: "Erstelle Kampagne"
- field_group_empty: "Es gibt keine Felder in dieser Gruppe."
- msg_cant_delete_user: "^Kann den Benutzer nicht löschen, da %{value} noch aktive Anlagen hat."
- edit_note: "Notiz bearbeiten"
- web_presence: "Web-Präsenz"
- lead_small: "Anfragen"
- time:
- formats:
- mmddhhss: "%e %b %l:%M%p"
- mmddyyyy_hhmm: "%d %B %Y %H:%M"
- starts_in: "beginnt in %{value}"
- subject_contact: "Kontakt"
- overdue: "Verspätet, war fällig am"
- access: "Zugang"
- born_on: "Geboren am"
- reports_to: "Berichtet an"
- my_tasks: "Meine Aufgaben"
- my_opportunities: "Meine Chancen"
- my_accounts: "Meine Firmen"
- no_task_records: "Sie haben keine Aufgaben"
- no_opportunity_records: "Sie haben keine Chancen"
- no_account_records: "Sie haben keine Firmen"
- target_revenue: "Target revenue"
- target_conversion: "Ziel Konversion"
- account_with_title_department: "%{title}, %{department} bei %{account}"
- account_with_title: "%{title} bei %{account}"
- lead_statuses: "Anfragen Status"
- account_categories: "Firmen Kategorien"
- opportunity_stages: "Chancen Abschnitte"
- search_results_count:
- one: "Suche ergab %{count} Treffer."
- other: "Suche ergab %{count} Treffer."
- entities_per_page: "%{entity} pro Seite:"
- tab_team: "Team"
- admin_tab_groups: "Gruppen"
- contacts_index_long: "Langes Format"
- contacts_index_brief: "Kurzes Format"
- contacts_index_full: "Ganzes Format"
- opportunities_index_normal: "Normales Format"
- accounts_index_normal: "Normales Format"
- leads_index_normal: "Normales Format"
- campaigns_index_normal: "Normales Format"
- account_id: "Firma"
- campaign_statuses: "Kampagne Status"
- unassigned: "Nicht zugeordnet"
- general_info: "Allgemeine Informationen"
- show_general_info_small: "Zeige allgemeine Informationen zu diesem Kontakt"
- show_extra_info_small: "Zeige zusätzliche Informationen zu diesem Kontakt"
- tag_details: "%{tag} Einzelheiten"
- show_tag_info_small: "Zeige %{tag} Informationen zu diesem Kontakt."
- shared_with_everyone: "Mit jedem teilen"
- title: "Titel"
- subscriptions: "Beitreten"
- show_status_info_small: "Zeige Status Informationen zu dieser Anfrage."
- show_contact_info_small: "Zeige Kontakt Informationen zu dieser Anfrage."
- closes_on: "Geschlossen am"
- unassigned_opportunities: "Nicht zugeteilte Chancen"
- no_opportunities_found: "Es gibt derzeit keine abgelaufenen Chancen"
- tag_list: "Tags"
- action_create_comment: "- "%{comment}""
- not_showing_hidden_entities: "%{count} versteckte %{entity} werden nicht angezeigt."
- comment_intro: "Sie können Kommentare später hinzufügen."
- create_group: "Erstelle Gruppe"
- save_group: "Speichere Gruppe"
- group_members: "Teilnehmer"
- groups: "Gruppen"
- groups_small: "Gruppen"
- group_small: "Gruppe"
- confirm_group_delete: "Wollen Sie wirklich diese Gruppe löschen? Sie wird noch von %{count} Einheiten referenziert."
- group_memberships: "Gruppen Zugehörigkeit"
- account_contact_id: "Firmen id"
- account_contact_name: "Firmen Name"
- user_id: "Benutzer id"
- created_at: "Erstellt am"
- updated_at: "Geändert am"
- to_perm: "Link"
- admin_fields_info2: "Es wird empfohlen den Server neu zu starten, nachdem kundenspezifische Felder hinzugefügt oder entfernt wurden."
-
+ reply_instructions: Sie können auf dieses e-Mail antworten um ein Kommentar hinzuzufügen,
+ oder zeigen Sie %{entity} in Ihrem Browser an.
+ intro: ! '%{user_full_name} kommentierte %{entity_type}: %{entity_name}'
+ my_profile: Mein Profil
+ add_note_help: Neue Notiz hinzufügen...
+ select_contact: Wähle einen Kontakt aus
+ create_field_group: Erstelle Gruppe.
+ create_opportunity: Erstelle Chance
+ revenue_label: Umsatz (€)
+ about_project_page: Projekt-Page
+ tab_dashboard: Dashboard
+ weighted_amount: Gewichteter Betrag
+ lead_permissions_intro_shared: Standardmäßig werden die Zugriffsregeln aus der Kampagne
+ kopiert oder wird vom angegebenen Benutzer übernommen. Dies kann auch später durchgeführt
+ werden.
+ completed_last_week: Letzte Woche
+ department_small: ! '%{value} Abteilung'
+ subject: Angelegenheit
+ cold_call: Cold Call
+ label: Beschriftung
+ state: Bundesland
+ won: Erfolg
+ admin_tab_users: Benutzer
+ no_saved_lists: Keine gespeicherten Listen
+ days_late: Verspätet um
+ email: Email
+ tab_contacts: Kontakte
+ campaign_small: Kampagne
+ number_of_leads: Anzahl der Anfragen
+ mail_to: Mail an %{value}
+ sign_up_button: Registrieren
+ campaigns_small: Kampagnen
+ convert_lead_permissions_intro: Die Zugriffsregeln des Kontakts werden von der Anfrage
+ übernommen. Sie können die Zugriffsregeln auch später ändern.
+ referral: Empfehlungen
+ admin: Admin
+ country: Land
+ objectives_small: Kamagnen-Ziele
+ planned: Geplant
+ confirm_delete: Sie wollen wirklich %{value} löschen?
+ closes_today: Abschluss heute erwartet!
+ login: Login
+ approve: Genehmige
+ negotiation: Vertrag
+ option_before: vor
+ convert_lead_text: Mit der Umwandlung wird %{value} zu einem Kontakt, der mit einem
+ existierenden oder neu zu erstellenden account verbunden wird. Der Anfrage-Status
+ wird automatisch auf umgewandelt geändert.
+ subscribe_via_email: Anmeldung via e-Mail
+ items_total: ! '%{count} total.'
+ already_signed_up: Schon registriert?
+ works_at: ! '%{job_title} bei %{company}'
+ cancel: Abbrechen
+ subject_user: Benutzer
+ sign_up_now: Registrieren Sie sich jetzt!
+ select_opportunity: Wähle eine Chance aus
+ contact_small: Kontakt
+ conference: Konferenz
+ tab_accounts: Firmen
+ save_profile: Profil sichern
+ due: Fällig
+ create_new: erstelle neu(e)
+ revenue_number: ! '%{value} Umsatz'
+ total_leads: Anzahl der Anfragen
+ proposal: Angebot
+ do_not_call: Nicht anrufen
+ meeting: Meeting
+ opportunity_summary: Chancen auf einen Blick
+ username: Benutzername
+ option_created_at: Erstellungsdatum
+ users_small: Benutzer
+ custom_field_options: Passe die Feldoptionen an
+ about_ffc_resources: Fat Free CRM Ressourcen (Links öffnen ein neues Fenster)
+ task_due_later: demnächst fällig
+ myself: mir
+ mobile_small: Mobiltelefon
+ expanded: Erweitert
+ alt_email: Alternative Email
+ create_past_participle: Zuletzt erstellte Datensätze
+ sort_by: Sortiere %{models} nach %{field}
+ aim: AOL IM
+ update_past_participle: Aktualisierungen
+ called_off: Abgesagt
+ task_due_today: heute fällig
+ converted: Umgewandelt
+ disable_email_subscriptions: Deaktiviere e-Mail Benachrichtigungen
+ total_accounts: Alle Accounts
+ dropbox_notification_intro: Die e-Mail wurde erfolgreich hinzugefügt, welche an
+ die Dropbox geschickt wurde
+ msg_successful_signup: Erfolgreiche Anmeldung. Willkommen bei Fat Free CRM!
+ following_users_will_be_notified: Die folgenden Benutzer werden mittels e-Mail benachrichtigt
+ skype: Skype
+ partner: Partner
+ n_a: N/A
+ extra_info: Zusatzinformation
+ option_all: alle
+ new_password: Neues Passwort
+ two_weeks: Zwei Wochen
+ campaign_summary: Kampagnen-Zusammenfassung
+ permissions_intro_shared: Standardmäßig haben nur ausgewählte Benutzer Zugriff auf
+ den %{value}. Sie können die Zugriffsregeln für den %{value} auch später ändern.
+ save_task: Aufgabe sichern
+ option_target_revenue: Zielumsatz
+ please_retry: Versuchen Sie eine andere Abfrage.
+ show_per_page: Zeige %{number} %{models} pro Seite in %{fmt}-Format.
+ admin_tab_fields: Benutzerdefinierte Felder
+ user_suspended_on: Gesperrt am %{value}
+ conversion: Konversion
+ due_today: Heute fällig
+ option_probability: Wahrscheinlichkeit
+ select_blank: -- Auswahl --
+ action_reassigned: neu zugeordnet
+ opportunity: Chancen
+ total_tasks: Anzahl %{value}
+ to_csv: Exportiere als Excel-kompatibles Dateiformat (.csv) inklusive gelöschte
+ Datensätze
+ task: Aufgaben
+ analysis: Analyse
+ not_implemented: Noch nicht implementiert.
+ tag_with_taggings_confirm_delete: Wenn dieser Tag gelöscht wird, wird er von %{value}
+ Einträgen entfernt.
+ search_assets: Suche %{value}
+ task_completed_by: vor %{time_ago} von %{user} erledigt
+ comment: Kommentar
+ advanced_search_remove_condition: Entferne Filter
+ user_admin: Admin
+ permissions_intro_private: Standardmäßig haben nur Sie Zugriff auf den %{value}.
+ Sie können die Zugriffsregeln für den %{value} auch später ändern.
+ money: Geld
+ zipcode: Postleitzahl
+ action_rescheduled: neu geplant
+ leads_options: Anfrage-Einstellungen
+ due_this_week: Diese Woche
+ select_an_account: Wähle einen Account aus
+ about_thank_you: Danke, dass Sie Fat Free CRM benutzen! Wir schätzen Ihre Hilfe
+ und hoffen, Sie finden Gefallen an der Software.
+ web: Website
+ accounts_options: Firmen-Optionen
+ crm_admin_page: Fat Free CRM Administration
+ tab_tasks: Aufgaben
+ blog: Website/Blog
+ source: Quelle
+ option_after: nach
+ task_overdue: zu spät, war fällig am
+ alt_email_small: Andere
+ vendor: Verkäufer
+ user_awaits_approval: Genehmigung erforderlich
+ field_group_tags: Gruppen mit diesem Tag
+ save_field: Speichere Feld
+ phone_toll_free: kostenloses Telefon
+ task_due_now: jetzt fällig
+ password: Passwort
+ recent_items: Aktuelle Änderungen
+ image_file: Bilddatei
+ about_dev_group: Diskussionsgruppe für Entwickler
+ lost: Verloren
+ expand_all: Alles anzeigen
+ back_to_crm: Back to Fat Free CRM
+ option_long: lang
+ edit: Bearbeiten
+ no_button: Nein
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
+ task_completed: erledigt
+ google: Google IM
+ twitter: Twitter
+ back: Zurück
+ subject_email: Email zu
+ share_with: für folgende Personen sichtbar
+ first_name: Vorname
+ competitor: Mitbewerber
+ lead: Anfrage
+ contacts: Kontakte
+ advanced_search_add_group: Füge eine Filtergruppe hinzu
+ save_tag: Speichere Tag
+ conversion_label: Konversion (%)
+ no_tasks_assigned: zugeordnet
+ select_or_create_tags: Wähle einige Markierungen aus oder erstelle eine neue Markierung
+ durch Drücken der "enter"-Taste.
+ phone_small: Telefon
+ user_suspended: Gesperrt
+ added_by: hinzugefügt vor %{time_ago} durch %{user}
+ avatar: Avatar
+ campaign_targets: Kampagnen-Ziele
+ msg_asset_rejected: ! '%{value} wurde abgelehnt.'
+ pending_tasks: ausstehende Aufgaben
+ discount: Rabatt
+ tab_opportunities: Chancen
+ from: von
+ time_ago: vor %{value}
+ stage: Ebene
+ about: Über
+ actual: Aktuell
+ opportunity_summary_text: ! '%{amount} mit %{discount} Rabatt und %{probability}
+ Wahrscheinlichkeit'
+ close_form: Abschlussformular
+ option_starts_on: Startdatum
+ discard: Discard
+ or: oder
+ two_days: Zwei Tagen
+ subject_comment: Kommentar zu
+ could_not_find_matching: Konnte %{value} nicht finden - passend zu
+ action_won: gewonnen
+ accounts: Firmen
+ create_opp_for_contact: Optional können Sie eine Chance erstellen für %{value} unter
+ Angabe des Namen, aktueller Stand, geschätztes Abschlußdatum, Erfolgswahrscheinlichkeit,
+ Auftragswert und dem angebotenen Rabatt.
+ restrict_by_tag: Schränke anhand des Tags ein
+ reactivate: Reaktivieren
+ action_update: aktualisiert
+ notifications_tooltip: Wenn ein Kommentar hinzugefügt wird, werden alle Abonnenten
+ mittels e-Mail benachrichtigt
+ option_first_name: Vorname
+ msg_invalid_password: ^Bitte geben Sie Ihr gültiges Passwort ein.
+ user_confirm_delete: Ein Benutzer kann nur gelöscht werden, wenn ihm nichts mehr
+ zugeordnet ist.
+ select_lead: Wähle eine Anfrage aus
+ lead_permissions_intro_private: Standardmäßig werden die Zugriffsregeln aus der
+ Kampagne kopiert oder auf privat gesetzt. Dies kann auch später durchgeführt werden.
+ remember_me: Erinnere mich
+ edit_comment: Kommentar bearbeiten
+ no_tasks_pending: wartend
+ lead_summary: Anfrage-Zusammenfassung
+ task_small: Aufgabe
+ assign_to: Ordne zu
+ due_specific_date: An bestimmten Datum...
+ versions: History
+ tasks_small: Aufgaben
+ create_task: Erstelle Aufgabe
+ reset_password: Passwort zurücksetzen
+ view_assigned_tasks: zugeordnete Aufgaben anzeigen
+ action_create: erstellt
+ was_supposed_to_finish: angenommenes Ende am %{value}
+ subject_address: address on
+ msg_cant_delete_tag: ! 'Konnte ''%{value}'' nicht löschen, weil es mit Gruppen assoziiert
+ ist. '
+ no_start_date: kein Startdatum angegeben
+ delete: Löschen
+ website: Website
+ create_tag: Tag erstellen
+ save_contact: Kontakt sichern
+ word_of_mouth: Mundpropaganda
+ intro: Sie können die Informationen für %{value} später ändern.
+ at: bei
+ option_ends_on: Enddatum
+ recent_activity_options: Letzte Aktivitäten Einstellungen
+ trip: Trip
+ user_is_admin: Der Benutzer ist Administrator
+ days_left: Tage verfügbar
+ option_name: Name
+ no_tasks_completed: vollständig
+ other: Andere
+ advanced_search_group_rest: ! '...and where %{combinator} of the following match'
+ department: Abteilung
field_types:
string:
- title: "Kurze Antwort"
+ title: Kurze Antwort
text:
- title: "Lange Antwort"
+ title: Lange Antwort
select:
- title: "Auswahlliste"
+ title: Auswahlliste
multiselect:
- title: "Mehrfachauswahlliste"
+ title: Mehrfachauswahlliste
radio:
- title: "Radio Buttons"
+ title: Radio Buttons
boolean:
- title: "Checkbox"
+ title: Checkbox
check_boxes:
- title: "Checkbox Liste"
+ title: Checkbox Liste
date:
- title: "Datum"
+ title: Datum
date_pair:
- title: "Datum Paar"
+ title: Datum Paar
datetime:
- title: "Datum & Zeit"
+ title: Datum & Zeit
datetime_pair:
- title: "Datum & Zeit Paar"
+ title: Datum & Zeit Paar
email:
- title: "Email Adresse"
+ title: Email Adresse
url:
- title: "URL"
+ title: URL
tel:
- title: "Telefonnummer"
+ title: Telefonnummer
decimal:
- title: "Nummer (Dezimal)"
+ title: Nummer (Dezimal)
integer:
- title: "Nummer (Ganzzahl)"
+ title: Nummer (Ganzzahl)
float:
- title: "Nummer (Gleitzahl)"
-
+ title: Nummer (Gleitzahl)
+ save_field_group: Gruppe speichern
+ subject_account: account
+ create_a_new: neu erstellen
+ dropbox_notification_subject: dropbox - Email hinzugefügt - %{subject}
+ quick_find: Suche
+ users: Benutzer
+ task_pending: Aufgabe wurde in die Warteschlange bewegt
+ welcome: Willkommen
+ update: Ändern
+ will_paginate:
+ page_gap: ! '…'
+ page_entries_info:
+ single_page:
+ zero: Keine %{plural} gefunden
+ other: Zeigt alle %{count} %{plural}
+ one: Zeigt 1 %{name} an
+ multi_page: Es werden %{from} - %{to} %{plural} von insgesamt %{total} angezeigt
+ next_label: Weiter →
+ previous_label: ! '← Zurück'
+ added_ago: hinzugefügt vor %{value}
+ create_campaign: Erstelle Kampagne
+ field_group_empty: Es gibt keine Felder in dieser Gruppe.
+ msg_cant_delete_user: ^Kann den Benutzer nicht löschen, da %{value} noch aktive
+ Anlagen hat.
+ edit_note: Notiz bearbeiten
+ web_presence: Web-Präsenz
+ lead_small: Anfragen
+ time:
+ formats:
+ mmddhhss: ! '%e %b %l:%M%p'
+ mmddyyyy_hhmm: ! '%d %B %Y %H:%M'
+ starts_in: beginnt in %{value}
+ subject_contact: Kontakt
+ overdue: Verspätet, war fällig am
+ access: Zugang
+ born_on: Geboren am
+ reports_to: Berichtet an
+ my_tasks: Meine Aufgaben
+ my_opportunities: Meine Chancen
+ my_accounts: Meine Firmen
+ no_task_records: Sie haben keine Aufgaben
+ no_opportunity_records: Sie haben keine Chancen
+ no_account_records: Sie haben keine Firmen
+ target_revenue: Target revenue
+ target_conversion: Ziel Konversion
+ account_with_title_department: ! '%{title}, %{department} bei %{account}'
+ account_with_title: ! '%{title} bei %{account}'
+ lead_statuses: Anfragen Status
+ account_categories: Firmen Kategorien
+ opportunity_stages: Chancen Abschnitte
+ search_results_count:
+ one: Suche ergab %{count} Treffer.
+ other: Suche ergab %{count} Treffer.
+ entities_per_page: ! '%{entity} pro Seite:'
+ tab_team: Team
+ admin_tab_groups: Gruppen
+ contacts_index_long: Langes Format
+ contacts_index_brief: Kurzes Format
+ contacts_index_full: Ganzes Format
+ opportunities_index_normal: Normales Format
+ accounts_index_normal: Normales Format
+ leads_index_normal: Normales Format
+ campaigns_index_normal: Normales Format
+ account_id: Firma
+ campaign_statuses: Kampagne Status
+ unassigned: Nicht zugeordnet
+ general_info: Allgemeine Informationen
+ show_general_info_small: Zeige allgemeine Informationen zu diesem Kontakt
+ show_extra_info_small: Zeige zusätzliche Informationen zu diesem Kontakt
+ tag_details: ! '%{tag} Einzelheiten'
+ show_tag_info_small: Zeige %{tag} Informationen zu diesem Kontakt.
+ shared_with_everyone: Mit jedem teilen
+ title: Titel
+ subscriptions: Beitreten
+ show_status_info_small: Zeige Status Informationen zu dieser Anfrage.
+ show_contact_info_small: Zeige Kontakt Informationen zu dieser Anfrage.
+ closes_on: Geschlossen am
+ unassigned_opportunities: Nicht zugeteilte Chancen
+ no_opportunities_found: Es gibt derzeit keine abgelaufenen Chancen
+ tag_list: Tags
+ action_create_comment: ! '- "%{comment}"'
+ not_showing_hidden_entities: ! '%{count} versteckte %{entity} werden nicht angezeigt.'
+ comment_intro: Sie können Kommentare später hinzufügen.
+ create_group: Erstelle Gruppe
+ save_group: Speichere Gruppe
+ group_members: Teilnehmer
+ groups: Gruppen
+ groups_small: Gruppen
+ group_small: Gruppe
+ confirm_group_delete: Wollen Sie wirklich diese Gruppe löschen? Sie wird noch von
+ %{count} Einheiten referenziert.
+ group_memberships: Gruppen Zugehörigkeit
+ account_contact_id: Firmen id
+ account_contact_name: Firmen Name
+ user_id: Benutzer id
+ created_at: Erstellt am
+ updated_at: Geändert am
+ to_perm: Link
+ admin_fields_info2: Es wird empfohlen den Server neu zu starten, nachdem kundenspezifische
+ Felder hinzugefügt oder entfernt wurden.
pair:
- start: "Start"
- end: "Ende"
- from_to: "Von %{from} bis %{to}"
- from_only: "Von %{from}"
- to_only: "Bis %{to}"
-
- contact_summary: "Kontakt-Zusammenfassung"
+ start: Start
+ end: Ende
+ from_to: Von %{from} bis %{to}
+ from_only: Von %{from}
+ to_only: Bis %{to}
+ contact_summary: Kontakt-Zusammenfassung
diff --git a/config/locales/de_ransack.yml b/config/locales/de_ransack.yml
new file mode 100644
index 0000000000..1a852a3098
--- /dev/null
+++ b/config/locales/de_ransack.yml
@@ -0,0 +1,91 @@
+---
+de:
+ ransack:
+ search: suche
+ predicate: aussage
+ and: und
+ or: oder
+ any: mindestens eins
+ all: alle
+ combinator: kombinator
+ attribute: attribut
+ value: wert
+ condition: bedingung
+ sort: sortieren
+ asc: aufsteigend
+ desc: absteigend
+ submit: Suche
+ add_group: Füge eine Gruppe von Filtern hinzu
+ group_first: Zeige Ergebnisse von %{combinator} für die folgenden Treffer
+ group_rest: ! '...und %{combinator} für die folgenden Treffer'
+ add_condition: Füge einen Filter hinzu
+ remove_condition: Entferne einen Filter
+ predicates:
+ eq: entspricht
+ eq_any: entspricht einem
+ eq_all: entspricht allen
+ not_eq: entspricht nicht
+ not_eq_any: entspricht mindestens einem nicht
+ not_eq_all: entspricht allen nicht
+ matches: trifft zu
+ matches_any: trifft bei mindestens einem zu
+ matches_all: trifft bei allen zu
+ does_not_match: trifft nicht zu
+ does_not_match_any: trifft bei mindestens einem nicht zu
+ does_not_match_all: trifft bei keinem zu
+ lt: weniger als
+ lt_any: mindestens eins kleiner
+ lt_all: alle kleiner
+ lteq: kleiner oder gleich
+ lteq_any: mindestens eines kleiner oder gleich
+ lteq_all: alle kleiner oder gleich
+ gt: größer als
+ gt_any: mindestens eines größer
+ gt_all: alle größer
+ gteq: größer oder gleich
+ gteq_any: mindestens eines größer oder gleich
+ gteq_all: alle größer oder gleich
+ in: ist innerhalb
+ in_any: ist innerhalb von einem
+ in_all: ist innerhalb von allen
+ not_in: ist nicht enthalten
+ not_in_any: ist in einem nicht enthalten
+ not_in_all: ist in allen nicht enthalten
+ cont: enthält
+ cont_any: enthält einen
+ cont_all: enthält alle
+ not_cont: beinhaltet nicht
+ not_cont_any: beinhaltet mindestens eine nicht
+ not_cont_all: beinhaltet alle nicht
+ start: beginnt mit
+ start_any: mindestens eines beginnt mit
+ start_all: alle beginnen mit
+ not_start: beginnt nicht mit
+ not_start_any: mindestens eines beginnt nicht mit
+ not_start_all: alle beginnen nicht mit
+ end: endet mit
+ end_any: mindestens eines endet mit
+ end_all: alle enden mit
+ not_end: endet nicht mit
+ not_end_any: mindestens eines endet nicht mit
+ not_end_all: alle enden nicht mit
+ 'true': ist wahr
+ 'false': ist falsch
+ present: existiert
+ blank: ist leer
+ 'null': ist null
+ not_null: ist nicht null
+ alt:
+ date:
+ lt: ist bevor
+ lt_any: mindestens eines ist bevor
+ lt_all: alle sind bevor
+ lteq: ist bevor oder am
+ lteq_any: mindestens eines ist bevor oder am
+ lteq_all: alle sind bevor oder am
+ gt: ist nach
+ gt_any: mindestens eines ist nach
+ gt_all: alle sind nach
+ gteq: ist danach oder am
+ gteq_any: mindestens eines ist danach oder am
+ gteq_all: alle sind danach oder am
diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml
index 5bf1212c93..a44d80ec62 100644
--- a/config/locales/en-GB.yml
+++ b/config/locales/en-GB.yml
@@ -1,180 +1,219 @@
-# GB English translations for Ruby on Rails
-
-"en-GB":
+---
+en-GB:
date:
formats:
- default: "%d-%m-%Y"
- short: "%d %b"
- long: "%d %B, %Y"
-
- day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
- abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
-
- month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
- abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
+ default: ! '%d-%m-%Y'
+ short: ! '%d %b'
+ long: ! '%d %B, %Y'
+ day_names:
+ - Sunday
+ - Monday
+ - Tuesday
+ - Wednesday
+ - Thursday
+ - Friday
+ - Saturday
+ abbr_day_names:
+ - Sun
+ - Mon
+ - Tue
+ - Wed
+ - Thu
+ - Fri
+ - Sat
+ month_names:
+ -
+ - January
+ - February
+ - March
+ - April
+ - May
+ - June
+ - July
+ - August
+ - September
+ - October
+ - November
+ - December
+ abbr_month_names:
+ -
+ - Jan
+ - Feb
+ - Mar
+ - Apr
+ - May
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Oct
+ - Nov
+ - Dec
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%a, %d %b %Y %H:%M:%S %z"
- short: "%d %b %H:%M"
- long: "%d %B, %Y %H:%M"
- am: "am"
- pm: "pm"
-
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ short: ! '%d %b %H:%M'
+ long: ! '%d %B, %Y %H:%M'
+ am: am
+ pm: pm
support:
array:
- words_connector: ", "
- two_words_connector: " and "
- last_word_connector: ", and "
-
+ words_connector: ! ', '
+ two_words_connector: ! ' and '
+ last_word_connector: ! ', and '
select:
- prompt: "Please select"
-
+ prompt: Please select
number:
format:
- separator: "."
- delimiter: ","
+ separator: .
+ delimiter: ! ','
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: "%u%n"
- unit: "£"
- separator: "."
- delimiter: ","
+ format: ! '%u%n'
+ unit: £
+ separator: .
+ delimiter: ! ','
precision: 2
significant: false
strip_insignificant_zeros: false
-
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
+ unit: ''
thousand: Thousand
million: Million
billion: Billion
trillion: Trillion
quadrillion: Quadrillion
-
datetime:
distance_in_words:
- half_a_minute: "half a minute"
+ half_a_minute: half a minute
less_than_x_seconds:
- one: "less than 1 second"
- other: "less than %{count} seconds"
+ one: less than 1 second
+ other: less than %{count} seconds
x_seconds:
- one: "1 second"
- other: "%{count} seconds"
+ one: 1 second
+ other: ! '%{count} seconds'
less_than_x_minutes:
- one: "less than a minute"
- other: "less than %{count} minutes"
+ one: less than a minute
+ other: less than %{count} minutes
x_minutes:
- one: "1 minute"
- other: "%{count} minutes"
+ one: 1 minute
+ other: ! '%{count} minutes'
about_x_hours:
- one: "about 1 hour"
- other: "about %{count} hours"
+ one: about 1 hour
+ other: about %{count} hours
x_days:
- one: "1 day"
- other: "%{count} days"
+ one: 1 day
+ other: ! '%{count} days'
about_x_months:
- one: "about 1 month"
- other: "about %{count} months"
+ one: about 1 month
+ other: about %{count} months
x_months:
- one: "1 month"
- other: "%{count} months"
+ one: 1 month
+ other: ! '%{count} months'
about_x_years:
- one: "about 1 year"
- other: "about %{count} years"
+ one: about 1 year
+ other: about %{count} years
over_x_years:
- one: "over 1 year"
- other: "over %{count} years"
+ one: over 1 year
+ other: over %{count} years
almost_x_years:
- one: "almost 1 year"
- other: "almost %{count} years"
+ one: almost 1 year
+ other: almost %{count} years
prompts:
- year: "Year"
- month: "Month"
- day: "Day"
- hour: "Hour"
- minute: "Minute"
- second: "Seconds"
-
+ year: Year
+ month: Month
+ day: Day
+ hour: Hour
+ minute: Minute
+ second: Seconds
helpers:
select:
- prompt: "Please select"
-
+ prompt: Please select
submit:
- create: 'Create %{model}'
- update: 'Update %{model}'
- submit: 'Save %{model}'
-
+ create: Create %{model}
+ update: Update %{model}
+ submit: Save %{model}
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "is not included in the list"
- exclusion: "is reserved"
- invalid: "is invalid"
- confirmation: "doesn't match confirmation"
- accepted: "must be accepted"
- empty: "can't be empty"
- blank: "can't be blank"
- too_long: "is too long (maximum is %{count} characters)"
- too_short: "is too short (minimum is %{count} characters)"
- wrong_length: "is the wrong length (should be %{count} characters)"
- not_a_number: "is not a number"
- not_an_integer: "must be an integer"
- greater_than: "must be greater than %{count}"
- greater_than_or_equal_to: "must be greater than or equal to %{count}"
- equal_to: "must be equal to %{count}"
- less_than: "must be less than %{count}"
- less_than_or_equal_to: "must be less than or equal to %{count}"
- odd: "must be odd"
- even: "must be even"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: is not included in the list
+ exclusion: is reserved
+ invalid: is invalid
+ confirmation: doesn't match confirmation
+ accepted: must be accepted
+ empty: can't be empty
+ blank: can't be blank
+ too_long: is too long (maximum is %{count} characters)
+ too_short: is too short (minimum is %{count} characters)
+ wrong_length: is the wrong length (should be %{count} characters)
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ equal_to: must be equal to %{count}
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ odd: must be odd
+ even: must be even
activerecord:
errors:
template:
header:
- one: "1 error prohibited this %{model} from being saved"
- other: "%{count} errors prohibited this %{model} from being saved"
- body: "There were problems with the following fields:"
-
+ one: 1 error prohibited this %{model} from being saved
+ other: ! '%{count} errors prohibited this %{model} from being saved'
+ body: ! 'There were problems with the following fields:'
messages:
- taken: "has already been taken"
- record_invalid: "Validation failed: %{errors}"
- <<: *errors_messages
-
+ inclusion: is not included in the list
+ exclusion: is reserved
+ invalid: is invalid
+ confirmation: doesn't match confirmation
+ accepted: must be accepted
+ empty: can't be empty
+ blank: can't be blank
+ too_long: is too long (maximum is %{count} characters)
+ too_short: is too short (minimum is %{count} characters)
+ wrong_length: is the wrong length (should be %{count} characters)
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ equal_to: must be equal to %{count}
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ odd: must be odd
+ even: must be even
+ taken: has already been taken
+ record_invalid: ! 'Validation failed: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/en-GB_fat_free_crm.yml b/config/locales/en-GB_fat_free_crm.yml
index 8fc71e8479..68ff63ea8f 100644
--- a/config/locales/en-GB_fat_free_crm.yml
+++ b/config/locales/en-GB_fat_free_crm.yml
@@ -1,20 +1,15 @@
+---
en-GB:
language: English (UK)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: All
at: at
here: here
no_button: 'No'
not_implemented: Not implemented yet.
or: or
- select_none: '-- None --'
- select_blank: '-- Select --'
+ select_none: -- None --
+ select_blank: -- Select --
yes_button: 'Yes'
-
- # Settings.
- #----------------------------------------------------------------------------
tab_dashboard: Dashboard
tab_tasks: Tasks
tab_campaigns: Campaigns
@@ -23,32 +18,27 @@ en-GB:
tab_contacts: Contacts
tab_opportunities: Opportunities
tab_team: Team
-
admin_tab_groups: Groups
admin_tab_users: Users
admin_tab_fields: Custom Fields
admin_tab_tags: Tags
admin_tab_settings: Settings
admin_tab_plugins: Plugins
-
affiliate: Affiliate
competitor: Competitor
customer: Customer
partner: Partner
reseller: Reseller
vendor: Vendor
-
planned: Planned
started: Started
on_hold: On Hold
completed: Completed
called_off: Called Off
-
new: New
contacted: Contacted
converted: Converted
rejected: Rejected
-
cold_call: Cold Call
conference: Conference
online: Online Marketing
@@ -57,7 +47,6 @@ en-GB:
web: Website
word_of_mouth: Word of Mouth
other: Other
-
prospecting: Prospecting
analysis: Analysis
presentation: Presentation
@@ -66,16 +55,13 @@ en-GB:
final_review: Final Review
won: Closed/Won
lost: Closed/Lost
-
call: Call
email: Email
follow_up: Follow-up
lunch: Lunch
meeting: Meeting
money: Money
- presentation: Presentation
trip: Trip
-
overdue: Overdue
due_asap: As Soon As Possible
due_today: Today
@@ -84,24 +70,17 @@ en-GB:
due_next_week: Next Week
due_later: Sometime Later
due_specific_date: On Specific Date...
-
completed_today: Today
completed_yesterday: Yesterday
completed_last_week: Last week
completed_this_month: This month
completed_last_month: Last month
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: One Hour
one_day: One Day
two_days: Two Days
one_week: One Week
two_weeks: Two Weeks
one_month: One Month
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -114,74 +93,74 @@ en-GB:
account:
attributes:
name:
- missing_account_name: "^Please specify account name."
+ missing_account_name: ^Please specify account name.
access:
- share_account: "^Please specify users to share the account with."
+ share_account: ^Please specify users to share the account with.
campaign:
attributes:
name:
- missing_campaign_name: "^Please specify campaign name."
+ missing_campaign_name: ^Please specify campaign name.
ends_on:
- dates_not_in_sequence: "^Please make sure the campaign end date is after the start date."
+ dates_not_in_sequence: ^Please make sure the campaign end date is after
+ the start date.
access:
- share_campaign: "^Please specify users to share the campaign with."
+ share_campaign: ^Please specify users to share the campaign with.
contact:
attributes:
first_name:
- missing_first_name: "^Please specify first name."
+ missing_first_name: ^Please specify first name.
last_name:
- missing_last_name: "^Please specify last name."
+ missing_last_name: ^Please specify last name.
access:
- share_contact: "^Please specify users to share the contact with."
+ share_contact: ^Please specify users to share the contact with.
lead:
attributes:
first_name:
- missing_first_name: "^Please specify first name."
+ missing_first_name: ^Please specify first name.
last_name:
- missing_last_name: "^Please specify last name."
+ missing_last_name: ^Please specify last name.
access:
- share_lead: "^Please specify users to share the lead with."
+ share_lead: ^Please specify users to share the lead with.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Please specify opportunity name."
+ missing_opportunity_name: ^Please specify opportunity name.
access:
- share_opportunity: "^Please specify users to share the opportunity with."
+ share_opportunity: ^Please specify users to share the opportunity with.
task:
attributes:
name:
- missing_task_name: "^Please specify task name."
+ missing_task_name: ^Please specify task name.
calendar:
- invalid_date: "^Please specify valid date."
+ invalid_date: ^Please specify valid date.
user:
attributes:
username:
- missing_username: "^Please specify username."
- username_taken: "^This username is already taken."
+ missing_username: ^Please specify username.
+ username_taken: ^This username is already taken.
email:
- missing_email: "^Please specify email address."
- email_in_use: "^There is another user with the same email."
-
+ missing_email: ^Please specify email address.
+ email_in_use: ^There is another user with the same email.
msg_account_suspended: User account has been suspended.
password_reset_instruction: password reset instructions
-
- # Controllers.
- #----------------------------------------------------------------------------
- msg_account_created: Your account has been created and is awaiting approval by the system administrator.
+ msg_account_created: Your account has been created and is awaiting approval by the
+ system administrator.
msg_account_not_approved: Your account has not been approved yet.
- msg_asset_deleted: "%{value} has been deleted."
+ msg_asset_deleted: ! '%{value} has been deleted.'
msg_asset_not_available: This %{value} is no longer available.
msg_asset_not_authorized: You are not authorized to view this %{value}.
msg_assets_not_available: The %{value} are not available.
- msg_asset_rejected: "%{value} has been rejected."
- msg_bad_image_file: "^Could't upload or resize the image file you specified."
- msg_cant_create_related: "Can't create the %{asset} since the %{related} is no longer available."
- msg_cant_delete_user: "^Couldn't delete the user since %{value} has related assets present."
- msg_cant_do: "Can't %{action} the %{asset} since it's no longer available."
+ msg_asset_rejected: ! '%{value} has been rejected.'
+ msg_bad_image_file: ^Could't upload or resize the image file you specified.
+ msg_cant_create_related: Can't create the %{asset} since the %{related} is no longer
+ available.
+ msg_cant_delete_user: ^Couldn't delete the user since %{value} has related assets
+ present.
+ msg_cant_do: Can't %{action} the %{asset} since it's no longer available.
msg_email_not_found: No user was found with that email address.
msg_enter_new_password: Please enter your new password.
msg_goodbye: You have been logged out. Thank you for using Fat Free CRM!
- msg_invalid_password: "^Please specify valid current password"
+ msg_invalid_password: ^Please specify valid current password
msg_invalig_login: Invalid username or password.
msg_last_login: Your last login was on %{value}.
msg_login_needed: You must be logged in to access this page.
@@ -189,15 +168,14 @@ en-GB:
msg_password_changed: Your password has been changed.
msg_password_not_changed: Your password has not been changed.
msg_password_updated: Password was successfully updated.
- msg_pwd_instructions_sent: Instructions to reset your password have been sent to you. Please check your email.
+ msg_pwd_instructions_sent: Instructions to reset your password have been sent to
+ you. Please check your email.
msg_require_admin: You must be Administrator to access this page.
msg_successful_signup: Successful signup, welcome to Fat Free CRM!
msg_welcome: Welcome to Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": weighted amount
- activity_options: Show %{models} %{action_type} performed by %{user} in the past %{period}.
+ option_amount*probability: weighted amount
+ activity_options: Show %{models} %{action_type} performed by %{user} in the past
+ %{period}.
all_users: all users
option_after: after
option_all: all
@@ -223,10 +201,8 @@ en-GB:
option_updated_at: date updated
show_per_page: Show %{number} %{models} per page using %{fmt} format.
sort_by: Sort %{models} by %{field}.
- sort_by_displaying: Sort %{models} by %{field} displaying first name %{position} last name.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Sort %{models} by %{field} displaying first name %{position}
+ last name.
aim: AOL IM
already_signed_up: Already signed up?
alt_email: Alternative email
@@ -236,12 +212,12 @@ en-GB:
contact_info: Contact Information
current_password: Current password
edit_profile: Edit Profile
- # email: Email # <-- Already defined as the task type if Settings.
first_name: First name
google: Google IM
gravatar_help: Not familiar with Gravatars? Learn about Gravatars
image_file: Image file
- image_help: The image file you upload will be automatically resized to 75 x 75 pixels. Supported formats are GIF, JPG, and PNG.
+ image_help: The image file you upload will be automatically resized to 75 x 75 pixels.
+ Supported formats are GIF, JPG, and PNG.
job_title: Title
last_name: Last name
login_now_link: Login Now!
@@ -266,17 +242,11 @@ en-GB:
reports_to: Reports to
access: Access
contacts_account: Contact's account
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Forgot Password
login: Login
no_account: Do not have an account?
remember_me: Remember Me
sign_up_now: Sign Up Now!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: Account
select_an_account: Select an Account
account_small: account
@@ -305,9 +275,6 @@ en-GB:
shipping_address: Shipping address
total_accounts: Total Accounts
website: Website
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Actual
actual_performance: Actual Performance
budget: Budget
@@ -322,7 +289,7 @@ en-GB:
campaigns_small: campaigns
conversion: Conversion
conversion_label: Conversion (%)
- conversion_number: "%{value} conversion"
+ conversion_number: ! '%{value} conversion'
create_campaign: Create Campaign
end_date: End date
finished_on: completed on %{value}
@@ -330,11 +297,13 @@ en-GB:
no_start_date: no start date specified
number_of_leads: Number of leads
objectives: Objectives
- objectives_help: Please specify target number of leads, expected leads-to-opportunities conversion ratio, target revenue, and campaign budget. These numbers will let you track actual campaign performance.
+ objectives_help: Please specify target number of leads, expected leads-to-opportunities
+ conversion ratio, target revenue, and campaign budget. These numbers will let
+ you track actual campaign performance.
objectives_small: campaign objectives
revenue: Revenue
revenue_label: Revenue (£)
- revenue_number: "%{value} in revenue"
+ revenue_number: ! '%{value} in revenue'
save_campaign: Save Campaign
start_date: Start date
started_ago: started %{value} ago
@@ -345,9 +314,6 @@ en-GB:
was_supposed_to_finish: was supposed to finish on %{value}
was_supposed_to_start: was supposed to start %{time_ago} ago on %{start_date}
was_supposed_to_start_in: was supposed to start in %{starts_in} on %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Other
blog: Website/Blog
contact: Contact
@@ -357,16 +323,19 @@ en-GB:
contacts_small: contacts
create_contact: Create Contact
department: Department
- department_small: '%{value} department'
+ department_small: ! '%{value} department'
do_not_call: Do not call
extra_info: Extra Information
extra_info_small: extra contact
facebook: Facebook
linked_in: LinkedIn
myself: Myself
- permissions_intro_private: By default only you will have access to the %{value}. You can change permissions later.
- permissions_intro_public: By default all users will have access to the %{value}. You can change permissions later.
- permissions_intro_shared: By default only the selected users will have access to the %{value}. You can change permissions later.
+ permissions_intro_private: By default only you will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_public: By default all users will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_shared: By default only the selected users will have access to
+ the %{value}. You can change permissions later.
referred_by: Referred by
referred_by_small: referred by
save_contact: Save Contact
@@ -374,21 +343,26 @@ en-GB:
unassigned: Unassigned
web_presence: Web Presence
web_presence_small: web presence
- works_at: "%{job_title} at %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} at %{company}'
convert: Convert
convert_lead: Convert Lead
- convert_lead_permissions_intro: Contact permissions will be copied from the lead being converted. You can change contact permissions later.
- convert_lead_text: By converting the lead %{value} will become a contact associated with the existing or newly created account. Lead status will be automatically set to converted.
+ convert_lead_permissions_intro: Contact permissions will be copied from the lead
+ being converted. You can change contact permissions later.
+ convert_lead_text: By converting the lead %{value} will become a contact associated
+ with the existing or newly created account. Lead status will be automatically
+ set to converted.
create_lead: Create Lead
- create_opp_for_contact: You can optionally create an opportunity for the %{value} contact by specifying the name, current stage, estimated closing date, sale probability, amount of the deal, and the discount offered.
+ create_opp_for_contact: You can optionally create an opportunity for the %{value}
+ contact by specifying the name, current stage, estimated closing date, sale probability,
+ amount of the deal, and the discount offered.
lead: Lead
lead_info_small: lead contact
- lead_permissions_intro_private: By default permissions will be copied from the campaign or set to private. You can change lead permissions later.
- lead_permissions_intro_public: By default permissions will be copied from the campaign or set to public. You can change lead permissions later.
- lead_permissions_intro_shared: By default permissions will be copied from the campaign or shared with the specified users. You can change lead permissions later.
+ lead_permissions_intro_private: By default permissions will be copied from the campaign
+ or set to private. You can change lead permissions later.
+ lead_permissions_intro_public: By default permissions will be copied from the campaign
+ or set to public. You can change lead permissions later.
+ lead_permissions_intro_shared: By default permissions will be copied from the campaign
+ or shared with the specified users. You can change lead permissions later.
lead_small: lead
lead_status_small: lead status
lead_summary: Lead Summary
@@ -403,9 +377,6 @@ en-GB:
source: Source
status: Status
total_leads: Total Leads
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Amount
close_date: Close date
closed_ago_on: closed %{time_ago} ago on %{date}
@@ -427,7 +398,8 @@ en-GB:
opportunity: Opportunity
opportunity_small: opportunity
opportunity_summary: Opportunity At a Glance
- opportunity_summary_text: "%{amount} with %{discount} discount and %{probability} probability"
+ opportunity_summary_text: ! '%{amount} with %{discount} discount and %{probability}
+ probability'
past_due: past due, was expected to close %{value} ago
probability: Probability
probability_number: and %{value} probability
@@ -435,9 +407,6 @@ en-GB:
stage: Stage
total_opportunities: Total Opportunities
weighted_amount: Weighted amount
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
task: Task
task_small: task
tasks: Tasks
@@ -453,13 +422,13 @@ en-GB:
due: Due
feel_free: Feel free to
move_to: move to
- no_tasks: "You don't have any %{value} tasks"
+ no_tasks: You don't have any %{value} tasks
no_tasks_pending: pending
no_tasks_assigned: assigned
no_tasks_completed: completed
pending_tab: Pending
pending_tasks: Pending Tasks
- related: 're:'
+ related: ! 're:'
save_task: Save Task
task_assigned: The task has been assigned to %{value}
task_assigned_to: and assigned to %{value}
@@ -474,19 +443,11 @@ en-GB:
task_from: From %{value}
task_overdue: late, was due on
task_pending: The task has been moved to pending tasks
- task_small: task
- tasks: Tasks
total_tasks: Total %{value}
view_assigned_tasks: view assigned tasks
view_pending_tasks: view pending tasks
-
- # Views -> Team.
- #----------------------------------------------------------------------------
unassigned_opportunities: Unassigned Opportunities
no_opportunities_found: There are currently no outstanding opportunities.
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_completed: completed
action_create: created
action_destroy: deleted
@@ -515,7 +476,6 @@ en-GB:
update_past_participle: Updates
destroy_past_participle: Deletions
all_events_past_participle: Activities
-
my_tasks: My Tasks
no_task_records: You have no tasks.
my_opportunities: My Opportunities
@@ -523,30 +483,27 @@ en-GB:
my_accounts: My Accounts
no_account_records: You have no accounts
not_showing_hidden_entities: Not showing %{count} hidden %{entity}.
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Add Note
save_note: Save Note
add_note_help: Add a new note...
edit_note: Edit Note
- added_ago: added %{value} ago
- added_by: added %{time_ago} ago by %{user}
+ added_ago: added %{value}
+ added_by: added %{time_ago} by %{user}
back: Back
cancel: Cancel
close_form: Close form
comment_intro: You can add comments later.
confirm_delete: Are you sure you want to delete this %{value}?
copy_permissions: Copy %{value} permissions
- could_not_find: "Couldn't find any %{value}. Feel free to"
- could_not_find_matching: "Couldn't find any %{value} matching"
+ could_not_find: Couldn't find any %{value}. Feel free to
+ could_not_find_matching: Couldn't find any %{value} matching
create_new: create new
create_a_new: create a new
select_existing: select existing
delete: Delete
discard: Discard
edit: Edit
- items_total: '%{count} total.'
+ items_total: ! '%{count} total.'
less: Less...
me: me
more: More...
@@ -563,11 +520,11 @@ en-GB:
select_task: Select Task
select_opportunity: Select Opportunity
search_assets: Search %{value}
- time_ago: "%{value} ago"
+ time_ago: ! '%{value} ago'
background_info: Background
address: Address
- street1: Street 1 # NEW
- street2: Street 2 # NEW
+ street1: Street 1
+ street2: Street 2
city: City
zipcode: Post Code
state: County
@@ -577,9 +534,6 @@ en-GB:
collapse_all: Collapse all
expanded: Expanded
collapsed: Collapsed
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: About
about_dev_group: Discussion group for developers
about_features: Features and bugs
@@ -588,24 +542,22 @@ en-GB:
about_ffc_version: Fat Free CRM version
about_home_page: Home page
about_project_page: Project page
- about_thank_you: Thank you for using Fat Free CRM! We appreciate your business and hope you enjoy using the software.
+ about_thank_you: Thank you for using Fat Free CRM! We appreciate your business and
+ hope you enjoy using the software.
about_twitter: Twitter commit updates
about_user_group: Discussion group for users
admin: Admin
logout: Logout
quick_find: Quick find
welcome: Welcome
-
- # Views -> Advanced Search.
accounts_advanced_search: Accounts Advanced search
advanced_search: Advanced search
advanced_search_submit: Search
advanced_search_add_group: Add a group of filters
advanced_search_group_first: Show results where %{combinator} of the following match
- advanced_search_group_rest: ...and where %{combinator} of the following match
+ advanced_search_group_rest: ! '...and where %{combinator} of the following match'
advanced_search_add_condition: Add a filter
advanced_search_remove_condition: Remove filter
-
ransack:
predicates:
eq: is
@@ -618,11 +570,8 @@ en-GB:
not_cont: doesn't contain
blank: is blank
present: is present
- "null": is null
+ 'null': is null
not_null: is not null
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
comment: Comment
edit_comment: Editing comment
show: Show
@@ -631,38 +580,26 @@ en-GB:
notifications_tooltip: Subscribers will receive new comments via email
subscribe_via_email: Subscribe via email
disable_email_subscriptions: Disable email subscription
-
- # Views -> Emails.
- #----------------------------------------------------------------------------
- email: Email
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
+ added_note: added note %{value}
confirm_password_intro: Please type your new password and then confirm it.
- password_intro: Please specify your email address, and the instructions to reset your password will be sent to you.
+ password_intro: Please specify your email address, and the instructions to reset
+ your password will be sent to you.
reset_password: Reset Password
update_password_and_login: Update Password and Login
-
- # Views -> Admin
- #----------------------------------------------------------------------------
back_to_crm: Back to Fat Free CRM
crm_admin_page: Fat Free CRM Administration
-
- # Views -> Admin -> Groups
- #----------------------------------------------------------------------------
create_group: Create Group
save_group: Save Group
group_members: members
groups: Groups
groups_small: groups
group_small: group
- confirm_group_delete: Are you sure you wish to delete this group? There are %{count} items that still reference it.
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
+ confirm_group_delete: Are you sure you wish to delete this group? There are %{count}
+ items that still reference it.
approve: Approve
create_user: Create User
last_seen: last seen %{value} ago
+ last_seen2: last seen %{value}
personal_information: Personal Information
reactivate: Reactivate
save_user: Save User
@@ -672,7 +609,7 @@ en-GB:
user_awaits_approval: awaits your approval
user_confirm_delete: A user can only be deleted if no related assets are left behind.
user_is_admin: The user is Administrator
- user_never_logged_in: "hasn't logged in yet"
+ user_never_logged_in: hasn't logged in yet
user_signed_up: Signed Up
user_signed_up_on: signed up on %{value}
user_since: user since %{value}
@@ -680,100 +617,72 @@ en-GB:
user_suspended_on: suspended on %{value}
users: Users
users_small: users
-
- # Views -> Versions
- #----------------------------------------------------------------------------
versions: History
version:
- create: %{item} created by %{by}
- update: %{item} modified by %{by}
- destroy: %{item} destroyed by %{by}
- set_html: %{attr} set to %{to}
- unset_html: %{attr} unset
- change_html: %{attr} changed from %{from} to %{to}
+ create: ! '%{item} created by %{by}'
+ update: ! '%{item} modified by %{by}'
+ destroy: ! '%{item} destroyed by %{by}'
+ set_html: ! '%{attr} set to %{to}'
+ unset_html: ! '%{attr} unset'
+ change_html: ! '%{attr} changed from %{from} to %{to}'
anonymous: anonymous
-
- # Export.
- #----------------------------------------------------------------------------
to_xls: Export to Excel
to_csv: Export to comma-delimited file format (including deleted records)
to_rss: RSS feed
to_atom: Atom feed
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - Added email - %{subject}
dropbox_notification_intro: Succesfully added the email you sent to dropbox
dropbox_notification_to: Added to
subject: Subject
body: Body
-
- # Comment Inbox
- #----------------------------------------------------------------------------
comment_notification:
- intro: "%{user_full_name} commented on %{entity_type}: %{entity_name}"
- reply_instructions: "Reply to this email directly to add a new comment, or view the %{entity} online"
-
- # Lists
- #----------------------------------------------------------------------------
+ intro: ! '%{user_full_name} commented on %{entity_type}: %{entity_name}'
+ reply_instructions: Reply to this email directly to add a new comment, or view
+ the %{entity} online
lists: Lists
list: List
no_saved_lists: No saved lists
make_current_view_list: Make current view a list
- list_name_info: If you use the name of an existing list, you will overwrite that list with your current settings
-
- # Pluralizations.
- #----------------------------------------------------------------------------
+ list_name_info: If you use the name of an existing list, you will overwrite that
+ list with your current settings
pluralize:
comment:
- one: '1 comment'
- other: '%{count} comments'
+ one: 1 comment
+ other: ! '%{count} comments'
contact:
- one: '1 contact'
- other: '%{count} contacts'
+ one: 1 contact
+ other: ! '%{count} contacts'
opportunity:
- one: '1 opportunity'
- other: '%{count} opportunities'
+ one: 1 opportunity
+ other: ! '%{count} opportunities'
lead:
- one: '1 lead'
- other: '%{count} leads'
+ one: 1 lead
+ other: ! '%{count} leads'
day:
- one: '1 day'
- other: '%{count} days'
+ one: 1 day
+ other: ! '%{count} days'
login:
- one: '1 login'
- other: '%{count} logins'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 login
+ other: ! '%{count} logins'
date:
formats:
- mmddyyyy: "%Y-%m-%d"
- mmdd: "%e %b"
- mmddyy: "%e %b, %Y"
-
+ mmddyyyy: ! '%Y-%m-%d'
+ mmdd: ! '%e %b'
+ mmddyy: ! '%e %b, %Y'
time:
formats:
- mmddhhss: "%e %b at %l:%M%p"
- mmddyyyy_hhmm: "%e %b %Y at %l:%M%p"
-
- # will_paginate translations copied from 'en-US'
- #----------------------------------------------------------------------------
+ mmddhhss: ! '%e %b at %l:%M%p'
+ mmddyyyy_hhmm: ! '%e %b %Y at %l:%M%p'
will_paginate:
- previous_label: "← Previous"
- next_label: "Next →"
- page_gap: "…"
+ previous_label: ! '← Previous'
+ next_label: Next →
+ page_gap: ! '…'
page_entries_info:
single_page:
- zero: "No %{plural} found"
- one: "Displaying 1 %{name}"
- other: "Displaying all %{count} %{plural}"
-
- multi_page: "Displaying %{plural} %{from} - %{to} of %{total} in total"
-
-
- # Views -> Admin -> Custom Fields
- #----------------------------------------------------------------------------
+ zero: No %{plural} found
+ one: Displaying 1 %{name}
+ other: Displaying all %{count} %{plural}
+ multi_page: Displaying %{plural} %{from} - %{to} of %{total} in total
label: Label
custom_fields: Custom Fields
custom_field_options: Custom Field Options
@@ -782,105 +691,78 @@ en-GB:
create_field_group: Create field group
edit_field_group: Edit field group
save_field_group: Save field group
-
field_group_empty: There are no fields in this group.
-
select_or_create_tags: Select some tags, or create a new tag by pressing 'enter'.
-
restrict_by_tag: Restrict by Tag
restrict_by_tag_info: Only show fields for %{assets} that are tagged with
field_group_tag_restriction: This field group applies to %{assets} tagged with "%{tag}"
field_group_unrestricted: This field group applies to all %{assets}
- field_group_confirm_delete: If a field group is deleted, any fields will be moved to the default field group.
+ field_group_confirm_delete: If a field group is deleted, any fields will be moved
+ to the default field group.
msg_cant_delete_field_group: Field Group could not be deleted.
+ admin_fields_info: ! 'Custom fields are displayed in groups.
- admin_fields_info: |
- Custom fields are displayed in groups.
Create a new field group, or add fields to one of the groups below.
- You can drag and drop fields to change their display order or move them between field groups.
- # Views -> Admin -> Tags
- #----------------------------------------------------------------------------
+ You can drag and drop fields to change their display order or move them between
+ field groups.
+
+'
tags: Tags
tag_small: tag
tagged: Tagged
create_tag: Create Tag
save_tag: Save Tag
field_group_tags: Field Groups shown for this Tag
- tag_with_taggings_confirm_delete: "If this tag is deleted, it will be removed from %{value} records."
- msg_cant_delete_tag: "Couldn't delete '%{value}' since it has associated Field Groups."
-
-
- # Views -> Admin -> Plugins
- #----------------------------------------------------------------------------
+ tag_with_taggings_confirm_delete: If this tag is deleted, it will be removed from
+ %{value} records.
+ msg_cant_delete_tag: Couldn't delete '%{value}' since it has associated Field Groups.
views:
admin:
plugins:
author: Author
version: Version
description: Description
-
-
- # Simple Form translations
- #----------------------------------------------------------------------------
simple_form:
- "yes": 'Yes'
- "no": 'No'
+ 'yes': 'Yes'
+ 'no': 'No'
required:
- text: 'required'
- mark: '*'
- # You can uncomment the line below if you need to overwrite the whole required html.
- # When using html, text and mark won't be used.
- # html: '* '
+ text: required
+ mark: ! '*'
error_notification:
- default_message: "Some errors were found, please take a look:"
- # Labels and hints examples
- # labels:
- # password: 'Password'
- # user:
- # new:
- # email: 'E-mail para efetuar o sign in.'
- # edit:
- # email: 'E-mail.'
- # hints:
- # username: 'User name to sign in.'
- # password: 'No special characters, please.'
-
-
- # Form field types
- #----------------------------------------------------------------------------
+ default_message: ! 'Some errors were found, please take a look:'
field_types:
string:
- title: Short Answer
+ title: Short Answer
text:
- title: Long Answer
+ title: Long Answer
select:
- title: Select List
- multiselect:
- title: Multi Select
+ title: Select List
+ multiselect:
+ title: Multi Select
radio:
- title: Radio Buttons
+ title: Radio Buttons
boolean:
- title: Checkbox
+ title: Checkbox
check_boxes:
- title: Checkbox List
+ title: Checkbox List
date:
- title: Date
+ title: Date
date_pair:
- title: Date Pair
+ title: Date Pair
datetime:
- title: Date & Time
+ title: Date & Time
datetime_pair:
- title: Date & Time Pair
+ title: Date & Time Pair
email:
- title: Email Address
+ title: Email Address
url:
- title: URL
+ title: URL
tel:
- title: Phone Number
+ title: Phone Number
decimal:
- title: Number (Decimal)
+ title: Number (Decimal)
integer:
- title: Number (Integer)
+ title: Number (Integer)
float:
- title: Number (Floating Point)
+ title: Number (Floating Point)
diff --git a/config/locales/en-US.yml b/config/locales/en-US.yml
index 645aefdc3b..b22cbad588 100644
--- a/config/locales/en-US.yml
+++ b/config/locales/en-US.yml
@@ -1,182 +1,219 @@
-# US English translations for Ruby on Rails
-#
-# Use this as the base for the locale file of your language.
-
-"en-US":
+---
+en-US:
date:
formats:
- default: "%Y-%m-%d"
- short: "%b %d"
- long: "%B %d, %Y"
-
- day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
- abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
-
- month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
- abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
+ default: ! '%Y-%m-%d'
+ short: ! '%b %d'
+ long: ! '%B %d, %Y'
+ day_names:
+ - Sunday
+ - Monday
+ - Tuesday
+ - Wednesday
+ - Thursday
+ - Friday
+ - Saturday
+ abbr_day_names:
+ - Sun
+ - Mon
+ - Tue
+ - Wed
+ - Thu
+ - Fri
+ - Sat
+ month_names:
+ -
+ - January
+ - February
+ - March
+ - April
+ - May
+ - June
+ - July
+ - August
+ - September
+ - October
+ - November
+ - December
+ abbr_month_names:
+ -
+ - Jan
+ - Feb
+ - Mar
+ - Apr
+ - May
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Oct
+ - Nov
+ - Dec
order:
- - :year
- - :month
- - :day
-
+ - :year
+ - :month
+ - :day
time:
formats:
- default: "%a, %d %b %Y %H:%M:%S %z"
- short: "%d %b %H:%M"
- long: "%B %d, %Y %H:%M"
- am: "am"
- pm: "pm"
-
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ short: ! '%d %b %H:%M'
+ long: ! '%B %d, %Y %H:%M'
+ am: am
+ pm: pm
support:
array:
- words_connector: ", "
- two_words_connector: " and "
- last_word_connector: ", and "
-
+ words_connector: ! ', '
+ two_words_connector: ! ' and '
+ last_word_connector: ! ', and '
select:
- prompt: "Please select"
-
+ prompt: Please select
number:
format:
- separator: "."
- delimiter: ","
+ separator: .
+ delimiter: ! ','
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: "%u%n"
- unit: "$"
- separator: "."
- delimiter: ","
+ format: ! '%u%n'
+ unit: $
+ separator: .
+ delimiter: ! ','
precision: 2
significant: false
strip_insignificant_zeros: false
-
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
+ unit: ''
thousand: Thousand
million: Million
billion: Billion
trillion: Trillion
quadrillion: Quadrillion
-
datetime:
distance_in_words:
- half_a_minute: "half a minute"
+ half_a_minute: half a minute
less_than_x_seconds:
- one: "less than 1 second"
- other: "less than %{count} seconds"
+ one: less than 1 second
+ other: less than %{count} seconds
x_seconds:
- one: "1 second"
- other: "%{count} seconds"
+ one: 1 second
+ other: ! '%{count} seconds'
less_than_x_minutes:
- one: "less than a minute"
- other: "less than %{count} minutes"
+ one: less than a minute
+ other: less than %{count} minutes
x_minutes:
- one: "1 minute"
- other: "%{count} minutes"
+ one: 1 minute
+ other: ! '%{count} minutes'
about_x_hours:
- one: "about 1 hour"
- other: "about %{count} hours"
+ one: about 1 hour
+ other: about %{count} hours
x_days:
- one: "1 day"
- other: "%{count} days"
+ one: 1 day
+ other: ! '%{count} days'
about_x_months:
- one: "about 1 month"
- other: "about %{count} months"
+ one: about 1 month
+ other: about %{count} months
x_months:
- one: "1 month"
- other: "%{count} months"
+ one: 1 month
+ other: ! '%{count} months'
about_x_years:
- one: "about 1 year"
- other: "about %{count} years"
+ one: about 1 year
+ other: about %{count} years
over_x_years:
- one: "over 1 year"
- other: "over %{count} years"
+ one: over 1 year
+ other: over %{count} years
almost_x_years:
- one: "almost 1 year"
- other: "almost %{count} years"
+ one: almost 1 year
+ other: almost %{count} years
prompts:
- year: "Year"
- month: "Month"
- day: "Day"
- hour: "Hour"
- minute: "Minute"
- second: "Seconds"
-
+ year: Year
+ month: Month
+ day: Day
+ hour: Hour
+ minute: Minute
+ second: Seconds
helpers:
select:
- prompt: "Please select"
-
+ prompt: Please select
submit:
- create: 'Create %{model}'
- update: 'Update %{model}'
- submit: 'Save %{model}'
-
+ create: Create %{model}
+ update: Update %{model}
+ submit: Save %{model}
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "is not included in the list"
- exclusion: "is reserved"
- invalid: "is invalid"
- confirmation: "doesn't match confirmation"
- accepted: "must be accepted"
- empty: "can't be empty"
- blank: "can't be blank"
- too_long: "is too long (maximum is %{count} characters)"
- too_short: "is too short (minimum is %{count} characters)"
- wrong_length: "is the wrong length (should be %{count} characters)"
- not_a_number: "is not a number"
- not_an_integer: "must be an integer"
- greater_than: "must be greater than %{count}"
- greater_than_or_equal_to: "must be greater than or equal to %{count}"
- equal_to: "must be equal to %{count}"
- less_than: "must be less than %{count}"
- less_than_or_equal_to: "must be less than or equal to %{count}"
- odd: "must be odd"
- even: "must be even"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: is not included in the list
+ exclusion: is reserved
+ invalid: is invalid
+ confirmation: doesn't match confirmation
+ accepted: must be accepted
+ empty: can't be empty
+ blank: can't be blank
+ too_long: is too long (maximum is %{count} characters)
+ too_short: is too short (minimum is %{count} characters)
+ wrong_length: is the wrong length (should be %{count} characters)
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ equal_to: must be equal to %{count}
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ odd: must be odd
+ even: must be even
activerecord:
errors:
template:
header:
- one: "1 error prohibited this %{model} from being saved"
- other: "%{count} errors prohibited this %{model} from being saved"
- body: "There were problems with the following fields:"
-
+ one: 1 error prohibited this %{model} from being saved
+ other: ! '%{count} errors prohibited this %{model} from being saved'
+ body: ! 'There were problems with the following fields:'
messages:
- taken: "has already been taken"
- record_invalid: "Validation failed: %{errors}"
- <<: *errors_messages
-
+ inclusion: is not included in the list
+ exclusion: is reserved
+ invalid: is invalid
+ confirmation: doesn't match confirmation
+ accepted: must be accepted
+ empty: can't be empty
+ blank: can't be blank
+ too_long: is too long (maximum is %{count} characters)
+ too_short: is too short (minimum is %{count} characters)
+ wrong_length: is the wrong length (should be %{count} characters)
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ equal_to: must be equal to %{count}
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ odd: must be odd
+ even: must be even
+ taken: has already been taken
+ record_invalid: ! 'Validation failed: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/en-US_fat_free_crm.yml b/config/locales/en-US_fat_free_crm.yml
index 023b74973b..fa9decfcb3 100644
--- a/config/locales/en-US_fat_free_crm.yml
+++ b/config/locales/en-US_fat_free_crm.yml
@@ -1,16 +1,18 @@
+---
en-US:
language: English
# Generic terms.
#----------------------------------------------------------------------------
+ id: Id
all: All
at: at
here: here
no_button: 'No'
not_implemented: Not implemented yet.
or: or
- select_none: '-- None --'
- select_blank: '-- Select --'
+ select_none: -- None --
+ select_blank: -- Select --
yes_button: 'Yes'
@@ -28,6 +30,7 @@ en-US:
tab_mandrill: Mandrill Emails
tab_contact_groups: Groups
+ tab_team: Team
admin_tab_groups: Groups
admin_tab_users: Users
admin_tab_fields: Custom Fields
@@ -52,12 +55,10 @@ en-US:
on_hold: On Hold
completed: Completed
called_off: Called Off
-
new: New
contacted: Contacted
converted: Converted
rejected: Rejected
-
cold_call: Cold Call
conference: Conference
online: Online Marketing
@@ -66,7 +67,6 @@ en-US:
web: Website
word_of_mouth: Word of Mouth
other: Other
-
prospecting: Prospecting
analysis: Analysis
presentation: Presentation
@@ -75,16 +75,13 @@ en-US:
final_review: Final Review
won: Closed/Won
lost: Closed/Lost
-
call: Call
email: Email
follow_up: Follow-up
lunch: Lunch
meeting: Meeting
money: Money
- presentation: Presentation
trip: Trip
-
overdue: Overdue
due_asap: As Soon As Possible
due_today: Today
@@ -93,7 +90,6 @@ en-US:
due_next_week: Next Week
due_later: Sometime Later
due_specific_date: On Specific Date...
-
completed_today: Today
completed_yesterday: Yesterday
completed_last_week: Last week
@@ -117,9 +113,9 @@ en-US:
mandrill_email:
attributes:
message_subject:
- missing_subject: "^You need to provide a subject for this message"
+ missing_subject: ^You need to provide a subject for this message
from_address:
- missing_sender: "^You need to provide a from address for this message"
+ missing_sender: ^You need to provide a from address for this message
authentication:
attributes:
login_field:
@@ -129,58 +125,57 @@ en-US:
account:
attributes:
name:
- missing_account_name: "^Please specify folder name."
+ missing_account_name: ^Please specify folder name.
access:
- share_account: "^Please specify users to share the folder with."
+ share_account: ^Please specify users to share the folder with.
campaign:
attributes:
name:
- missing_campaign_name: "^Please specify campaign name."
+ missing_campaign_name: ^Please specify campaign name.
ends_on:
- dates_not_in_sequence: "^Please make sure the campaign end date is after the start date."
+ dates_not_in_sequence: ^Please make sure the campaign end date is after the start date.
access:
- share_campaign: "^Please specify users to share the campaign with."
+ share_campaign: ^Please specify users to share the campaign with.
contact:
attributes:
first_name:
- missing_first_name: "^Please specify first name."
+ missing_first_name: ^Please specify first name.
last_name:
- missing_last_name: "^Please specify last name."
+ missing_last_name: ^Please specify last name.
access:
- share_contact: "^Please specify users to share the contact with."
+ share_contact: ^Please specify users to share the contact with.
lead:
attributes:
first_name:
- missing_first_name: "^Please specify first name."
+ missing_first_name: ^Please specify first name.
last_name:
- missing_last_name: "^Please specify last name."
+ missing_last_name: ^Please specify last name.
access:
- share_lead: "^Please specify users to share the lead with."
+ share_lead: ^Please specify users to share the lead with.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Please specify opportunity name."
+ missing_opportunity_name: ^Please specify opportunity name.
access:
- share_opportunity: "^Please specify users to share the opportunity with."
+ share_opportunity: ^Please specify users to share the opportunity with.
task:
attributes:
name:
- missing_task_name: "^Please specify task name."
+ missing_task_name: ^Please specify task name.
calendar:
- invalid_date: "^Please specify valid date."
+ invalid_date: ^Please specify valid date.
user:
attributes:
username:
- missing_username: "^Please specify username."
- username_taken: "^This username is already taken."
+ missing_username: ^Please specify username.
+ username_taken: ^This username is already taken.
email:
- missing_email: "^Please specify email address."
- email_in_use: "^There is another user with the same email."
+ missing_email: ^Please specify email address.
+ email_in_use: ^There is another user with the same email.
custom_field:
- required: "^%{field} is required."
- maxlength: "^%{field} is too long."
- endbeforestart: "^%{field} cannot end before it begins."
-
+ required: ^%{field} is required.
+ maxlength: ^%{field} is too long.
+ endbeforestart: ^%{field} cannot end before it begins.
attribute_options:
opportunity:
stage:
@@ -192,27 +187,38 @@ en-US:
final_review: Final Review
won: Closed/Won
lost: Closed/Lost
+ account:
+ rating:
+ "0": "-"
+ "1": "★"
+ "2": "★★"
+ "3": "★★★"
+ "4": "★★★★"
+ "5": "★★★★★"
msg_account_suspended: User account has been suspended.
password_reset_instruction: password reset instructions
# Controllers.
#----------------------------------------------------------------------------
- msg_account_created: Your account has been created and is awaiting approval by the system administrator.
+ msg_account_created: Your account has been created and is awaiting approval by the
+ system administrator.
msg_account_not_approved: Your account has not been approved yet.
- msg_asset_deleted: "%{value} has been deleted."
+ msg_asset_deleted: ! '%{value} has been deleted.'
msg_asset_not_available: This %{value} is no longer available.
- msg_asset_not_authorized: You are not authorized to view this %{value}.
+ msg_not_authorized: You are not authorized to take this action.
msg_assets_not_available: The %{value} are not available.
- msg_asset_rejected: "%{value} has been rejected."
- msg_bad_image_file: "^Could't upload or resize the image file you specified."
- msg_cant_create_related: "Can't create the %{asset} since the %{related} is no longer available."
- msg_cant_delete_user: "^Couldn't delete the user since %{value} has related assets present."
- msg_cant_do: "Can't %{action} the %{asset} since it's no longer available."
+ msg_asset_rejected: ! '%{value} has been rejected.'
+ msg_bad_image_file: ^Could't upload or resize the image file you specified.
+ msg_cant_create_related: Can't create the %{asset} since the %{related} is no longer
+ available.
+ msg_cant_delete_user: ^Couldn't delete the user since %{value} has related assets
+ present.
+ msg_cant_do: Can't %{action} the %{asset} since it's no longer available.
msg_email_not_found: No user was found with that email address.
msg_enter_new_password: Please enter your new password.
msg_goodbye: You have been logged out. Thank you for using Mojo!
- msg_invalid_password: "^Please specify valid current password"
+ msg_invalid_password: ^Please specify valid current password
msg_invalig_login: Invalid username or password.
msg_last_login: Your last login was on %{value}.
msg_login_needed: You must be logged in to access this page.
@@ -220,15 +226,17 @@ en-US:
msg_password_changed: Your password has been changed.
msg_password_not_changed: Your password has not been changed.
msg_password_updated: Password was successfully updated.
- msg_pwd_instructions_sent: Instructions to reset your password have been sent to you. Please check your email.
+ msg_pwd_instructions_sent: Instructions to reset your password have been sent to
+ you. Please check your email.
msg_require_admin: You must be Administrator to access this page.
msg_successful_signup: Successful signup, welcome to Fat Free CRM!
msg_welcome: Welcome to Mojo!
# Options.
#----------------------------------------------------------------------------
- "option_amount*probability": weighted amount
- activity_options: Show %{models} %{action_type} performed by %{user} in the past %{period}.
+ option_amount*probability: weighted amount
+ activity_options: Show %{models} %{action_type} performed by %{user} in the past
+ %{period}.
all_users: all users
option_after: after
option_all: all
@@ -255,10 +263,9 @@ en-US:
option_updated_at: date updated
show_per_page: Show %{number} %{models} per page using %{fmt} format.
sort_by: Sort by %{field}
- sort_by_displaying: Sort %{models} by %{field} displaying first name %{position} last name.
- entities_per_page: "%{entity} per page:"
-
- # Views -> Switcher
+ sort_by_displaying: Sort %{models} by %{field} displaying first name %{position}
+ last name.
+ entities_per_page: ! '%{entity} per page:'
contacts_index_long: Long format
contacts_index_brief: Brief format
contacts_index_full: Full format
@@ -278,12 +285,12 @@ en-US:
contact_info: Contact Information
current_password: Current password
edit_profile: Edit Profile
- # email: Email # <-- Already defined as the task type if Settings.
first_name: First name
google: Google IM
gravatar_help: Not familiar with Gravatars? Learn about Gravatars
image_file: Image file
- image_help: The image file you upload will be automatically resized to 75 x 75 pixels. Supported formats are GIF, JPG, and PNG.
+ image_help: The image file you upload will be automatically resized to 75 x 75 pixels.
+ Supported formats are GIF, JPG, and PNG.
job_title: Title
last_name: Last name
login_now_link: Login Now!
@@ -391,8 +398,8 @@ en-US:
shipping_address: Shipping address
total_accounts: Total Folders
website: Website
- account_with_title_department: %{title}, %{department} at %{account}
- account_with_title: %{title} at %{account}
+ account_with_title_department: ! '%{title}, %{department} at %{account}'
+ account_with_title: ! '%{title} at %{account}'
# Views -> Campaigns.
#----------------------------------------------------------------------------
@@ -411,7 +418,7 @@ en-US:
campaigns_small: campaigns
conversion: Conversion
conversion_label: Conversion (%)
- conversion_number: "%{value} conversion"
+ conversion_number: ! '%{value} conversion'
target_conversion: Targe conversion
create_campaign: Create Campaign
end_date: End date
@@ -420,11 +427,13 @@ en-US:
no_start_date: no start date specified
number_of_leads: Number of leads
objectives: Objectives
- objectives_help: Please specify target number of leads, expected leads-to-opportunities conversion ratio, target revenue, and campaign budget. These numbers will let you track actual campaign performance.
+ objectives_help: Please specify target number of leads, expected leads-to-opportunities
+ conversion ratio, target revenue, and campaign budget. These numbers will let
+ you track actual campaign performance.
objectives_small: campaign objectives
revenue: Revenue
revenue_label: Revenue ($)
- revenue_number: "%{value} in revenue"
+ revenue_number: ! '%{value} in revenue'
save_campaign: Save Campaign
start_date: Start date
started_ago: started %{value} ago
@@ -435,6 +444,7 @@ en-US:
was_supposed_to_finish: was supposed to finish on %{value}
was_supposed_to_start: was supposed to start %{time_ago} ago on %{start_date}
was_supposed_to_start_in: was supposed to start in %{starts_in} on %{start_date}
+ select_a_campaign: Select a campaign
# Views -> MandrillEmails.
#----------------------------------------------------------------------------
@@ -462,29 +472,31 @@ en-US:
contact_summary: Contact Summary
create_contact: Create Contact
department: Department
- department_small: '%{value} department'
+ department_small: ! '%{value} department'
do_not_call: Do not call
extra_info: Extra Information
extra_info_small: extra contact
facebook: Facebook
linked_in: LinkedIn
myself: Myself
- permissions_intro_private: By default only you will have access to the %{value}. You can change permissions later.
- permissions_intro_public: By default all users will have access to the %{value}. You can change permissions later.
- permissions_intro_shared: By default only the selected users will have access to the %{value}. You can change permissions later.
+ permissions_intro_private: By default only you will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_public: By default all users will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_shared: By default only the selected users will have access to
+ the %{value}. You can change permissions later.
referred_by: Referred by
referred_by_small: referred by
save_contact: Save Contact
- skype: Skype
twitter: Twitter
unassigned: Unassigned
web_presence: Web Presence
web_presence_small: web presence
- works_at: "%{job_title} at %{company}"
+ works_at: ! '%{job_title} at %{company}'
general_info: General Information
show_general_info_small: Show general information for this contact.
show_extra_info_small: Show extra information for this contact.
- tag_details: %{tag} Details
+ tag_details: ! '%{tag} Details'
show_tag_info_small: Show %{tag} information for this contact.
shared_with_everyone: Shared with everyone
title: Title
@@ -495,15 +507,23 @@ en-US:
#----------------------------------------------------------------------------
convert: Convert
convert_lead: Convert Lead
- convert_lead_permissions_intro: Contact permissions will be copied from the lead being converted. You can change contact permissions later.
- convert_lead_text: By converting the lead %{value} will become a contact associated with the existing or newly created account. Lead status will be automatically set to converted.
+ convert_lead_permissions_intro: Contact permissions will be copied from the lead
+ being converted. You can change contact permissions later.
+ convert_lead_text: By converting the lead %{value} will become a contact associated
+ with the existing or newly created account. Lead status will be automatically
+ set to converted.
create_lead: Create Lead
- create_opp_for_contact: You can optionally create an opportunity for the %{value} contact by specifying the name, current stage, estimated closing date, sale probability, amount of the deal, and the discount offered.
+ create_opp_for_contact: You can optionally create an opportunity for the %{value}
+ contact by specifying the name, current stage, estimated closing date, sale probability,
+ amount of the deal, and the discount offered.
lead: Lead
lead_info_small: lead contact
- lead_permissions_intro_private: By default permissions will be copied from the campaign or set to private. You can change lead permissions later.
- lead_permissions_intro_public: By default permissions will be copied from the campaign or set to public. You can change lead permissions later.
- lead_permissions_intro_shared: By default permissions will be copied from the campaign or shared with the specified users. You can change lead permissions later.
+ lead_permissions_intro_private: By default permissions will be copied from the campaign
+ or set to private. You can change lead permissions later.
+ lead_permissions_intro_public: By default permissions will be copied from the campaign
+ or set to public. You can change lead permissions later.
+ lead_permissions_intro_shared: By default permissions will be copied from the campaign
+ or shared with the specified users. You can change lead permissions later.
lead_small: lead
lead_status_small: lead status
lead_summary: Lead Summary
@@ -547,7 +567,8 @@ en-US:
opportunity_small: opportunity
opportunity_stages: Opportunity Stages
opportunity_summary: Opportunity At a Glance
- opportunity_summary_text: "%{amount} with %{discount} discount and %{probability} probability"
+ opportunity_summary_text: ! '%{amount} with %{discount} discount and %{probability}
+ probability'
past_due: past due, was expected to close %{value} ago
probability: Probability
probability_number: and %{value} probability
@@ -573,13 +594,13 @@ en-US:
due: Due
feel_free: Feel free to
move_to: move to
- no_tasks: "You don't have any %{value} tasks"
+ no_tasks: You don't have any %{value} tasks
no_tasks_pending: pending
no_tasks_assigned: assigned
no_tasks_completed: completed
pending_tab: Pending
pending_tasks: Pending Tasks
- related: 're:'
+ related: ! 're:'
save_task: Save Task
task_assigned: The task has been assigned to %{value}
task_assigned_to: and assigned to %{value}
@@ -641,8 +662,7 @@ en-US:
update_past_participle: Updates
destroy_past_participle: Deletions
all_events_past_participle: Activities
- action_create_comment: "- "%{comment}""
-
+ action_create_comment: ! '- "%{comment}"'
my_tasks: My Tasks
no_task_records: You have no tasks.
my_opportunities: My Opportunities
@@ -657,23 +677,23 @@ en-US:
save_note: Save Note
add_note_help: Add a new note...
edit_note: Edit Note
- added_ago: added %{value} ago
- added_by: added %{time_ago} ago by %{user}
+ added_ago: added %{value}
+ added_by: added %{time_ago} by %{user}
back: Back
cancel: Cancel
close_form: Close form
comment_intro: You can add comments later.
confirm_delete: Are you sure you want to delete this %{value}?
copy_permissions: Copy %{value} permissions
- could_not_find: "Couldn't find any %{value}. Feel free to"
- could_not_find_matching: "Couldn't find any %{value} matching"
+ could_not_find: Couldn't find any %{value}. Feel free to
+ could_not_find_matching: Couldn't find any %{value} matching
create_new: create new
create_a_new: create a new
select_existing: select existing
delete: Delete
discard: Discard
edit: Edit
- items_total: '%{count} total.'
+ items_total: ! '%{count} total.'
less: Show Less
me: me
more: Show More
@@ -690,11 +710,11 @@ en-US:
select_task: Select Task
select_opportunity: Select Opportunity
search_assets: Search %{value}
- time_ago: "%{value} ago"
+ time_ago: ! '%{value} ago'
background_info: Background
address: Address
- street1: Street 1 # NEW
- street2: Street 2 # NEW
+ street1: Street 1
+ street2: Street 2
city: City
zipcode: Zip Code
state: State
@@ -715,7 +735,8 @@ en-US:
about_ffc_version: Fat Free CRM version
about_home_page: Home page
about_project_page: Project page
- about_thank_you: Thank you for using Fat Free CRM! We appreciate your business and hope you enjoy using the software.
+ about_thank_you: Thank you for using Fat Free CRM! We appreciate your business and
+ hope you enjoy using the software.
about_twitter: Twitter commit updates
about_user_group: Discussion group for users
admin: Admin
@@ -741,15 +762,16 @@ en-US:
notifications_tooltip: Subscribers will receive new comments via email
subscribe_via_email: Subscribe via email
disable_email_subscriptions: Disable email subscription
+ added_note: added note %{value}
# Views -> Emails.
#----------------------------------------------------------------------------
- email: Email
# Views -> Passwords.
#----------------------------------------------------------------------------
confirm_password_intro: Please type your new password and then confirm it.
- password_intro: Please specify your email address, and the instructions to reset your password will be sent to you.
+ password_intro: Please specify your email address, and the instructions to reset
+ your password will be sent to you.
reset_password: Reset Password
update_password_and_login: Update Password and Login
@@ -770,9 +792,12 @@ en-US:
# Views -> Admin -> Users
#----------------------------------------------------------------------------
+ confirm_group_delete: Are you sure you wish to delete this group? There are %{count}
+ items that still reference it.
approve: Approve
create_user: Create User
last_seen: last seen %{value} ago
+ last_seen2: last seen %{value}
personal_information: Personal Information
group_memberships: Group Memberships
reactivate: Reactivate
@@ -783,7 +808,7 @@ en-US:
user_awaits_approval: awaits your approval
user_confirm_delete: A user can only be deleted if no related assets are left behind.
user_is_admin: The user is Administrator
- user_never_logged_in: "hasn't logged in yet"
+ user_never_logged_in: hasn't logged in yet
user_signed_up: Signed Up
user_signed_up_on: signed up on %{value}
user_since: user since %{value}
@@ -796,12 +821,12 @@ en-US:
#----------------------------------------------------------------------------
versions: History
version:
- create: %{item} created by %{by}
- update: %{item} modified by %{by}
- destroy: %{item} destroyed by %{by}
- set_html: %{attr} set to %{to}
- unset_html: %{attr} unset
- change_html: %{attr} changed from %{from} to %{to}
+ create: ! '%{item} created by %{by}'
+ update: ! '%{item} modified by %{by}'
+ destroy: ! '%{item} destroyed by %{by}'
+ set_html: ! '%{attr} set to %{to}'
+ unset_html: ! '%{attr} unset'
+ change_html: ! '%{attr} changed from %{from} to %{to}'
anonymous: anonymous
# Contact -> Attendance History
@@ -831,67 +856,66 @@ en-US:
# Comment Inbox
#----------------------------------------------------------------------------
comment_notification:
- intro: "%{user_full_name} commented on %{entity_type}: %{entity_name}"
- reply_instructions: "Reply to this email directly to add a new comment, or view the %{entity} online"
+ intro: ! '%{user_full_name} commented on %{entity_type}: %{entity_name}'
+ reply_instructions: Reply to this email directly to add a new comment, or view
+ the %{entity} online
# Lists
#----------------------------------------------------------------------------
- lists: Saved Searches
+ global_lists: Global lists
+ personal_lists: My lists
list: List
- no_saved_lists: No saved searches
- make_current_view_list: Make current view a saved search
- list_name_info: If you use the name of an existing list, you will overwrite that list with your current settings
+ no_saved_lists: No saved lists
+ make_current_view_list: Make current view a list
+ list_name_info: If you use the name of an existing list, you will overwrite that
+ list with your current settings
# Pluralizations.
#----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment'
- other: '%{count} comments'
+ one: 1 comment
+ other: ! '%{count} comments'
contact:
- one: '1 contact'
- other: '%{count} contacts'
+ one: 1 contact
+ other: ! '%{count} contacts'
opportunity:
- one: '1 opportunity'
- other: '%{count} opportunities'
+ one: 1 opportunity
+ other: ! '%{count} opportunities'
lead:
- one: '1 lead'
- other: '%{count} leads'
+ one: 1 lead
+ other: ! '%{count} leads'
day:
- one: '1 day'
- other: '%{count} days'
+ one: 1 day
+ other: ! '%{count} days'
login:
- one: '1 login'
- other: '%{count} logins'
+ one: 1 login
+ other: ! '%{count} logins'
# Custom date/time formats.
#----------------------------------------------------------------------------
date:
formats:
- mmddyyyy: "%m/%d/%Y"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%m/%d/%Y'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%b %e at %l:%M%p"
- mmddyyyy_hhmm: "%e %b %Y at %l:%M%p"
+ mmddhhss: ! '%b %e at %l:%M%p'
+ mmddyyyy_hhmm: ! '%e %b %Y at %l:%M%p'
# will_paginate translations copied for 'en-US'
#----------------------------------------------------------------------------
will_paginate:
- previous_label: "← Previous"
- next_label: "Next →"
- page_gap: "…"
-
+ previous_label: ! '← Previous'
+ next_label: Next →
+ page_gap: ! '…'
page_entries_info:
single_page:
- zero: "No %{plural} found"
- one: "Displaying 1 %{name}"
- other: "Displaying all %{count} %{plural}"
-
- multi_page: "Displaying %{plural} %{from} - %{to} of %{total} in total"
-
+ zero: No %{plural} found
+ one: Displaying 1 %{name}
+ other: Displaying all %{count} %{plural}
+ multi_page: Displaying %{plural} %{from} - %{to} of %{total} in total
# Views -> Admin -> Custom Fields
#----------------------------------------------------------------------------
@@ -903,40 +927,41 @@ en-US:
create_field_group: Create field group
edit_field_group: Edit field group
save_field_group: Save field group
-
field_group_empty: There are no fields in this group.
-
select_or_create_tags: Select some tags, or create a new tag by pressing 'enter'.
-
- restrict_by_tag: 'Restrict by Tag:'
+ restrict_by_tag: ! 'Restrict by Tag:'
restrict_by_tag_info: (Only show fields for %{assets} that are tagged with the following)
field_group_tag_restriction: This field group applies to %{assets} tagged with "%{tag}"
field_group_unrestricted: This field group applies to all %{assets}
- field_group_confirm_delete: If a field group is deleted, any fields will be moved to the default field group.
+ field_group_confirm_delete: If a field group is deleted, any fields will be moved
+ to the default field group.
msg_cant_delete_field_group: Field Group could not be deleted.
+ admin_fields_info: ! 'Custom fields are displayed in groups.
- admin_fields_info: |
- Custom fields are displayed in groups.
Create a new field group, or add fields to one of the groups below.
- You can drag and drop fields to change their display order or move them between field groups.
- admin_fields_info2: |
- It is strongly recommended you restart your server after adding or removing any custom field.
+ You can drag and drop fields to change their display order or move them between
+ field groups.
+'
# Views -> Admin -> Tags
#----------------------------------------------------------------------------
+ admin_fields_info2: ! 'It is strongly recommended you restart your server after
+ adding or removing any custom field.
+
+'
tags: Tags
tag_small: tag
tagged: Tagged
create_tag: Create Tag
save_tag: Save Tag
field_group_tags: Field Groups shown for this Tag
- tag_with_taggings_confirm_delete: "If this tag is deleted, it will be removed from %{value} records."
- msg_cant_delete_tag: "Couldn't delete '%{value}' since it has associated Field Groups."
-
# Views -> Admin -> Plugins
#----------------------------------------------------------------------------
+ tag_with_taggings_confirm_delete: If this tag is deleted, it will be removed from
+ %{value} records.
+ msg_cant_delete_tag: Couldn't delete '%{value}' since it has associated Field Groups.
views:
admin:
plugins:
@@ -950,67 +975,54 @@ en-US:
yes: 'Yes'
no: 'No'
required:
- text: 'required'
- mark: '*'
+ text: required
+ mark: ! '*'
# You can uncomment the line below if you need to overwrite the whole required html.
# When using html, text and mark won't be used.
# html: '* '
error_notification:
- default_message: "Some errors were found, please take a look:"
- # Labels and hints examples
- # labels:
- # password: 'Password'
- # user:
- # new:
- # email: 'E-mail para efetuar o sign in.'
- # edit:
- # email: 'E-mail.'
- # hints:
- # username: 'User name to sign in.'
- # password: 'No special characters, please.'
-
+ default_message: ! 'Some errors were found, please take a look:'
# Form field types
#----------------------------------------------------------------------------
field_types:
string:
- title: Short Answer
+ title: Short Answer
text:
- title: Long Answer
+ title: Long Answer
select:
- title: Select List
+ title: Select List
multiselect:
- title: Multi Select
+ title: Multi Select
radio:
- title: Radio Buttons
+ title: Radio Buttons
boolean:
- title: Checkbox
+ title: Checkbox
check_boxes:
- title: Checkbox List
+ title: Checkbox List
date:
- title: Date
+ title: Date
date_pair:
- title: Date Pair
+ title: Date Pair
datetime:
- title: Date & Time
+ title: Date & Time
datetime_pair:
- title: Date & Time Pair
+ title: Date & Time Pair
email:
- title: Email Address
+ title: Email Address
url:
- title: URL
+ title: URL
tel:
- title: Phone Number
+ title: Phone Number
decimal:
- title: Number (Decimal)
+ title: Number (Decimal)
integer:
- title: Number (Integer)
+ title: Number (Integer)
float:
- title: Number (Floating Point)
-
+ title: Number (Floating Point)
pair:
- start: Start
- end: End
- from_to: From %{from} to %{to}
- from_only: From %{from}
- to_only: Until %{to}
+ start: Start
+ end: End
+ from_to: From %{from} to %{to}
+ from_only: From %{from}
+ to_only: Until %{to}
diff --git a/config/locales/en-US_ransack.yml b/config/locales/en-US_ransack.yml
index ed5ac1ef28..40525c7c1d 100644
--- a/config/locales/en-US_ransack.yml
+++ b/config/locales/en-US_ransack.yml
@@ -1,92 +1,91 @@
+---
en-US:
ransack:
- search: "search"
- predicate: "predicate"
- and: "and"
- or: "or"
- any: "any"
- all: "all"
- combinator: "combinator"
- attribute: "attribute"
- value: "value"
- condition: "condition"
- sort: "sort"
- asc: "ascending"
- desc: "descending"
-
+ search: search
+ predicate: predicate
+ and: and
+ or: or
+ any: any
+ all: all
+ combinator: combinator
+ attribute: attribute
+ value: value
+ condition: condition
+ sort: sort
+ asc: ascending
+ desc: descending
submit: Search
add_group: Add a group of filters
group_first: Show results where %{combinator} of the following match
- group_rest: ...and where %{combinator} of the following match
+ group_rest: ! '...and where %{combinator} of the following match'
add_condition: Add a filter
remove_condition: Remove filter
-
predicates:
- eq: "is"
- eq_any: "is any"
- eq_all: "is all"
- not_eq: "is not"
- not_eq_any: "is not any"
- not_eq_all: "is not all"
- matches: "matches"
- matches_any: "matches any"
- matches_all: "matches all"
- does_not_match: "doesn't match"
- does_not_match_any: "doesn't match any"
- does_not_match_all: "doesn't match all"
- lt: "less than"
- lt_any: "less than any"
- lt_all: "less than all"
- lteq: "less than or equal to"
- lteq_any: "less than or equal to any"
- lteq_all: "less than or equal to all"
- gt: "greater than"
- gt_any: "greater than any"
- gt_all: "greater than all"
- gteq: "greater than or equal to"
- gteq_any: "greater than or equal to any"
- gteq_all: "greater than or equal to all"
- in: "is in"
- in_any: "is in any"
- in_all: "is in all"
- not_in: "is not in"
- not_in_any: "is not in any"
- not_in_all: "is not in all"
- cont: "contains"
- cont_any: "contains any"
- cont_all: "contains all"
- not_cont: "doesn't contain"
- not_cont_any: "doesn't contain any"
- not_cont_all: "doesn't contain all"
- start: "starts with"
- start_any: "starts with any"
- start_all: "starts with all"
- not_start: "doesn't start with"
- not_start_any: "doesn't start with any"
- not_start_all: "doesn't start with all"
- end: "ends with"
- end_any: "ends with any"
- end_all: "ends with all"
- not_end: "doesn't end with"
- not_end_any: "doesn't end with any"
- not_end_all: "doesn't end with all"
- 'true': "is true"
- 'false': "is false"
- present: "is present"
- blank: "is blank"
- 'null': "is null"
- not_null: "is not null"
+ eq: is
+ eq_any: is any
+ eq_all: is all
+ not_eq: is not
+ not_eq_any: is not any
+ not_eq_all: is not all
+ matches: matches
+ matches_any: matches any
+ matches_all: matches all
+ does_not_match: doesn't match
+ does_not_match_any: doesn't match any
+ does_not_match_all: doesn't match all
+ lt: is less than
+ lt_any: is less than any
+ lt_all: is less than all
+ lteq: is less than or equal to
+ lteq_any: is less than or equal to any
+ lteq_all: is less than or equal to all
+ gt: is greater than
+ gt_any: is greater than any
+ gt_all: is greater than all
+ gteq: is greater than or equal to
+ gteq_any: is greater than or equal to any
+ gteq_all: is greater than or equal to all
+ in: is in
+ in_any: is in any
+ in_all: is in all
+ not_in: is not in
+ not_in_any: is not in any
+ not_in_all: is not in all
+ cont: contains
+ cont_any: contains any
+ cont_all: contains all
+ not_cont: doesn't contain
+ not_cont_any: doesn't contain any
+ not_cont_all: doesn't contain all
+ start: starts with
+ start_any: starts with any
+ start_all: starts with all
+ not_start: doesn't start with
+ not_start_any: doesn't start with any
+ not_start_all: doesn't start with all
+ end: ends with
+ end_any: ends with any
+ end_all: ends with all
+ not_end: doesn't end with
+ not_end_any: doesn't end with any
+ not_end_all: doesn't end with all
+ 'true': is true
+ 'false': is false
+ present: is present
+ blank: is blank
+ 'null': is null
+ not_null: is not null
alt:
date:
- lt: "is before"
- lt_any: "is before any"
- lt_all: "is before all"
- lteq: "is before or on"
- lteq_any: "is before or on any"
- lteq_all: "is before or on all"
- gt: "is after"
- gt_any: "is after any"
- gt_all: "is after all"
- gteq: "is after or on"
- gteq_any: "is after or on any"
- gteq_all: "is after or on all"
\ No newline at end of file
+ lt: is before
+ lt_any: is before any
+ lt_all: is before all
+ lteq: is before or on
+ lteq_any: is before or on any
+ lteq_all: is before or on all
+ gt: is after
+ gt_any: is after any
+ gt_all: is after all
+ gteq: is after or on
+ gteq_any: is after or on any
+ gteq_all: is after or on all
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 970975d90f..61b776a9f9 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -3,182 +3,223 @@
# contributors:
# - Tsutomu Kuroda - http://github.com/kuroda (t-kuroda@oiax.jp)
-"es":
+---
+es:
date:
formats:
- default: "%d/%m/%Y"
- short: "%d de %b"
- long: "%d de %B de %Y"
-
- day_names: [Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado]
- abbr_day_names: [Dom, Lun, Mar, Mie, Jue, Vie, Sab]
-
- month_names: [~, Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Septiembre, Octubre, Noviembre, Diciembre]
- abbr_month_names: [~, Ene, Feb, Mar, Abr, May, Jun, Jul, Ago, Sep, Oct, Nov, Dic]
+ default: ! '%d/%m/%Y'
+ short: ! '%d de %b'
+ long: ! '%d de %B de %Y'
+ day_names:
+ - Domingo
+ - Lunes
+ - Martes
+ - Miércoles
+ - Jueves
+ - Viernes
+ - Sábado
+ abbr_day_names:
+ - Dom
+ - Lun
+ - Mar
+ - Mie
+ - Jue
+ - Vie
+ - Sab
+ month_names:
+ -
+ - Enero
+ - Febrero
+ - Marzo
+ - Abril
+ - Mayo
+ - Junio
+ - Julio
+ - Agosto
+ - Septiembre
+ - Octubre
+ - Noviembre
+ - Diciembre
+ abbr_month_names:
+ -
+ - Ene
+ - Feb
+ - Mar
+ - Abr
+ - May
+ - Jun
+ - Jul
+ - Ago
+ - Sep
+ - Oct
+ - Nov
+ - Dic
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%A, %d de %B de %Y %H:%M:%S %z"
- short: "%d de %b %H:%M"
- long: "%d de %B de %Y %H:%M"
- am: "am"
- pm: "pm"
-
+ default: ! '%A, %d de %B de %Y %H:%M:%S %z'
+ short: ! '%d de %b %H:%M'
+ long: ! '%d de %B de %Y %H:%M'
+ am: am
+ pm: pm
support:
array:
- words_connector: ", "
- two_words_connector: " y "
- last_word_connector: ", y "
-
+ words_connector: ! ', '
+ two_words_connector: ! ' y '
+ last_word_connector: ! ', y '
select:
- prompt: "Por favor seleccione"
-
+ prompt: Por favor seleccione
number:
format:
- separator: "."
- delimiter: ","
+ separator: .
+ delimiter: ! ','
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: "%n %u"
- unit: "€"
- separator: "."
- delimiter: ","
+ format: ! '%n %u'
+ unit: €
+ separator: .
+ delimiter: ! ','
precision: 2
significant: false
strip_insignificant_zeros: false
-
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 1
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
- thousand: "Mil"
- million: "Millón"
- billion: "Mil millones"
- trillion: "Trillón"
- quadrillion: "Cuatrillón"
-
+ unit: ''
+ thousand: Mil
+ million: Millón
+ billion: Mil millones
+ trillion: Trillón
+ quadrillion: Cuatrillón
datetime:
distance_in_words:
- half_a_minute: "medio minuto"
+ half_a_minute: medio minuto
less_than_x_seconds:
- one: "menos de 1 segundo"
- other: "menos de %{count} segundos"
+ one: menos de 1 segundo
+ other: menos de %{count} segundos
x_seconds:
- one: "1 segundo"
- other: "%{count} segundos"
+ one: 1 segundo
+ other: ! '%{count} segundos'
less_than_x_minutes:
- one: "menos de 1 minuto"
- other: "menos de %{count} minutos"
+ one: menos de 1 minuto
+ other: menos de %{count} minutos
x_minutes:
- one: "1 minuto"
- other: "%{count} minutos"
+ one: 1 minuto
+ other: ! '%{count} minutos'
about_x_hours:
- one: "alrededor de 1 hora"
- other: "alrededor de %{count} horas"
+ one: alrededor de 1 hora
+ other: alrededor de %{count} horas
x_days:
- one: "1 día"
- other: "%{count} días"
+ one: 1 día
+ other: ! '%{count} días'
about_x_months:
- one: "alrededor de 1 mes"
- other: "alrededor de %{count} meses"
+ one: alrededor de 1 mes
+ other: alrededor de %{count} meses
x_months:
- one: "1 mes"
- other: "%{count} meses"
+ one: 1 mes
+ other: ! '%{count} meses'
about_x_years:
- one: "alrededor de 1 año"
- other: "alrededor de %{count} años"
+ one: alrededor de 1 año
+ other: alrededor de %{count} años
over_x_years:
- one: "más de 1 año"
- other: "más de %{count} años"
+ one: más de 1 año
+ other: más de %{count} años
almost_x_years:
- one: "casi 1 año"
- other: "casi %{count} años"
+ one: casi 1 año
+ other: casi %{count} años
prompts:
- year: "Año"
- month: "Mes"
- day: "Día"
- hour: "Hora"
- minute: "Minutos"
- second: "Segundos"
-
+ year: Año
+ month: Mes
+ day: Día
+ hour: Hora
+ minute: Minutos
+ second: Segundos
helpers:
select:
- prompt: "Por favor seleccione"
-
+ prompt: Por favor seleccione
submit:
- create: 'Crear %{model}'
- update: 'Actualizar %{model}'
- submit: 'Guardar %{model}'
-
+ create: Crear %{model}
+ update: Actualizar %{model}
+ submit: Guardar %{model}
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "no está incluido en la lista"
- exclusion: "está reservado"
- invalid: "no es válido"
- confirmation: "no coincide con la confirmación"
- accepted: "debe ser aceptado"
- empty: "no puede estar vacío"
- blank: "no puede estar en blanco"
- too_long: "es demasiado largo (%{count} caracteres máximo)"
- too_short: "es demasiado corto (%{count} caracteres mínimo)"
- wrong_length: "no tiene la longitud correcta (%{count} caracteres exactos)"
- not_a_number: "no es un número"
- not_an_integer: "debe ser un entero"
- greater_than: "debe ser mayor que %{count}"
- greater_than_or_equal_to: "debe ser mayor que o igual a %{count}"
- equal_to: "debe ser igual a %{count}"
- less_than: "debe ser menor que %{count}"
- less_than_or_equal_to: "debe ser menor que o igual a %{count}"
- odd: "debe ser impar"
- even: "debe ser par"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: no está incluido en la lista
+ exclusion: está reservado
+ invalid: no es válido
+ confirmation: no coincide con la confirmación
+ accepted: debe ser aceptado
+ empty: no puede estar vacío
+ blank: no puede estar en blanco
+ too_long: es demasiado largo (%{count} caracteres máximo)
+ too_short: es demasiado corto (%{count} caracteres mínimo)
+ wrong_length: no tiene la longitud correcta (%{count} caracteres exactos)
+ not_a_number: no es un número
+ not_an_integer: debe ser un entero
+ greater_than: debe ser mayor que %{count}
+ greater_than_or_equal_to: debe ser mayor que o igual a %{count}
+ equal_to: debe ser igual a %{count}
+ less_than: debe ser menor que %{count}
+ less_than_or_equal_to: debe ser menor que o igual a %{count}
+ odd: debe ser impar
+ even: debe ser par
activerecord:
errors:
template:
header:
- one: "No se pudo guardar este/a %{model} porque se encontró 1 error"
- other: "No se pudo guardar este/a %{model} porque se encontraron %{count} errores"
- # The variable :count is also available
- body: "Se encontraron problemas con los siguientes campos:"
-
+ one: No se pudo guardar este/a %{model} porque se encontró 1 error
+ other: No se pudo guardar este/a %{model} porque se encontraron %{count}
+ errores
+ body: ! 'Se encontraron problemas con los siguientes campos:'
messages:
- taken: "ya está en uso"
- record_invalid: "La validación falló: %{errors}"
- <<: *errors_messages
-
+ inclusion: no está incluido en la lista
+ exclusion: está reservado
+ invalid: no es válido
+ confirmation: no coincide con la confirmación
+ accepted: debe ser aceptado
+ empty: no puede estar vacío
+ blank: no puede estar en blanco
+ too_long: es demasiado largo (%{count} caracteres máximo)
+ too_short: es demasiado corto (%{count} caracteres mínimo)
+ wrong_length: no tiene la longitud correcta (%{count} caracteres exactos)
+ not_a_number: no es un número
+ not_an_integer: debe ser un entero
+ greater_than: debe ser mayor que %{count}
+ greater_than_or_equal_to: debe ser mayor que o igual a %{count}
+ equal_to: debe ser igual a %{count}
+ less_than: debe ser menor que %{count}
+ less_than_or_equal_to: debe ser menor que o igual a %{count}
+ odd: debe ser impar
+ even: debe ser par
+ taken: ya está en uso
+ record_invalid: ! 'La validación falló: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/es_fat_free_crm.yml b/config/locales/es_fat_free_crm.yml
index d54e7d70a8..5e7b45604c 100644
--- a/config/locales/es_fat_free_crm.yml
+++ b/config/locales/es_fat_free_crm.yml
@@ -1,23 +1,15 @@
-# Spanish translation of fat free crm
-# by Beatriz Garcia Parrilla (beatriztranslations.com)
-
-"es":
+---
+es:
language: Español (España)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: todas
at: a
here: aquí
no_button: 'No'
not_implemented: Aún no ejecutado.
or: o
- select_none: '-- Ninguna --'
- select_blank: '-- Seleccionar --'
- yes_button: 'Sí'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- Ninguna --
+ select_blank: -- Seleccionar --
+ yes_button: Sí
tab_dashboard: Inicio
tab_tasks: Tareas
tab_campaigns: Campañas
@@ -25,51 +17,42 @@
tab_accounts: Cuentas
tab_contacts: Contactos
tab_opportunities: Oportunidades
-
admin_tab_users: Usuarios
admin_tab_settings: Configuración
admin_tab_plugins: Complementos
-
users_small: usuarios
-
planned: Planificada
started: Iniciada
on_hold: Aplazada
completed: Completada
called_off: Cancelada
-
new: Nueva
contacted: Contactada
converted: Transformada
rejected: Rechazada
-
- cold_call: Llamada publicitaria
+ cold_call: Llamada publicitaria
conference: Conferencia
online: Venta en línea
referral: Referencia
- self: Propia
+ self: Propia
web: Sitio web
- word_of_mouth: Boca a boca
+ word_of_mouth: Boca a boca
other: Otra
-
- prospecting: Sondeo
- analysis: Análisis
+ prospecting: Sondeo
+ analysis: Análisis
presentation: Presentación
proposal: Propuesta
negotiation: Negociación
final_review: Revisión Definitiva
won: Cerrada/Conseguida
lost: Cerrada/Perdida
-
call: Llamada
email: Correo electrónico
follow_up: Seguimiento
lunch: Almuerzo
meeting: Reunión
- money: Dinero
- presentation: Presentación
+ money: Dinero
trip: Viaje
-
overdue: Atrasada
due_asap: Cuanto antes
due_today: Hoy
@@ -77,25 +60,18 @@
due_this_week: Ésta semana
due_next_week: Próxima semana
due_later: En el futuro
- due_specific_date: En Fecha Específica... # ?!
-
+ due_specific_date: En Fecha Específica...
completed_today: Hoy
completed_yesterday: Ayer
completed_last_week: La semana pasada
completed_this_month: Éste mes
completed_last_month: El mes pasado
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: la última hora
one_day: el último día
two_days: los últimos dos días
one_week: la última semana
two_weeks: las últimas dos semanas
one_month: el último mes
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -108,83 +84,86 @@
account:
attributes:
name:
- missing_account_name: "^Dé un nombre a la cuenta, por favor."
+ missing_account_name: ^Dé un nombre a la cuenta, por favor.
access:
- share_account: "^Especifique con qué usuarios quiere compartir ésta cuenta, por favor."
+ share_account: ^Especifique con qué usuarios quiere compartir ésta cuenta,
+ por favor.
campaign:
attributes:
name:
- missing_campaign_name: "^Dé un nombre a la campaña, por favor."
+ missing_campaign_name: ^Dé un nombre a la campaña, por favor.
ends_on:
- dates_not_in_sequence: "^Asegúrese de que la fecha de finalización de la campaña es posterior a la fecha de inicio, por favor."
+ dates_not_in_sequence: ^Asegúrese de que la fecha de finalización de
+ la campaña es posterior a la fecha de inicio, por favor.
access:
- share_campaign: "^Especifique con qué usuarios quiere compartir ésta campaña, por favor."
+ share_campaign: ^Especifique con qué usuarios quiere compartir ésta
+ campaña, por favor.
contact:
attributes:
first_name:
- missing_first_name: "^Introduzca el nombre, por favor."
+ missing_first_name: ^Introduzca el nombre, por favor.
last_name:
- missing_last_name: "^Introduzca los apellidos, por favor."
+ missing_last_name: ^Introduzca los apellidos, por favor.
access:
- share_contact: "^Especifique con qué usuarios quiere compartir éste contacto, por favor."
+ share_contact: ^Especifique con qué usuarios quiere compartir éste contacto,
+ por favor.
lead:
attributes:
first_name:
- missing_first_name: "^Introduzca el nombre, por favor."
+ missing_first_name: ^Introduzca el nombre, por favor.
last_name:
- missing_last_name: "^Introduzca los apellidos, por favor."
+ missing_last_name: ^Introduzca los apellidos, por favor.
access:
- share_lead: "^Especifique con qué usuarios quiere compartir éste iniciativa, por favor."
+ share_lead: ^Especifique con qué usuarios quiere compartir éste iniciativa,
+ por favor.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Dé un nombre a ésta oportunidad, por favor."
+ missing_opportunity_name: ^Dé un nombre a ésta oportunidad, por favor.
access:
- share_opportunity: "^Especifique con qué usuarios quiere compartir éste oportunidad, por favor."
+ share_opportunity: ^Especifique con qué usuarios quiere compartir éste
+ oportunidad, por favor.
task:
attributes:
name:
- missing_task_name: "^Dé un nombre a ésta tarea, por favor."
+ missing_task_name: ^Dé un nombre a ésta tarea, por favor.
calendar:
- invalid_date: "^Introduzca una fecha correcta, por favor."
+ invalid_date: ^Introduzca una fecha correcta, por favor.
user:
attributes:
username:
- missing_username: "^Introduzca un nombre de usuario, por favor."
- username_taken: "^Este nombre de usuario ya está siendo usado."
+ missing_username: ^Introduzca un nombre de usuario, por favor.
+ username_taken: ^Este nombre de usuario ya está siendo usado.
email:
- missing_email: "^Introduzca su dirección de correo electrónico, por favor."
- email_in_use: "^Hay otro usuario con ésta misma dirección de correo electrónico."
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ missing_email: ^Introduzca su dirección de correo electrónico, por favor.
+ email_in_use: ^Hay otro usuario con ésta misma dirección de correo electrónico.
errors:
template:
header:
- one: "No se pudo guardar este/a %{model} porque se encontró 1 error"
- other: "No se pudo guardar este/a %{model} porque se encontraron %{count} errores"
- body: "Se encontraron problemas con los siguientes campos:"
-
+ one: No se pudo guardar este/a %{model} porque se encontró 1 error
+ other: No se pudo guardar este/a %{model} porque se encontraron %{count} errores
+ body: ! 'Se encontraron problemas con los siguientes campos:'
msg_account_suspended: Esta cuenta de usuario ha sido suspendida.
password_reset_instruction: Instrucciones para restaurar la contraseña
-
- # Controllers.
- #----------------------------------------------------------------------------
- msg_account_created: Su cuenta ha sido creada y está pendiente de aprobación por el administrador del sistema.
+ msg_account_created: Su cuenta ha sido creada y está pendiente de aprobación por
+ el administrador del sistema.
msg_account_not_approved: Su cuenta no ha sido aprobada todavía.
- msg_asset_deleted: "Se ha eliminado %{value}."
+ msg_asset_deleted: Se ha eliminado %{value}.
msg_asset_not_available: Ésta %{value} ya no está disponible.
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
msg_assets_not_available: La %{value} no está disponible.
- msg_asset_rejected: "Se ha rechazado %{value}."
- msg_bad_image_file: "^No se pudo cargar o cambiar el tamaño del archivo de imagen especificado."
- msg_cant_create_related: "No se puede crear la %{asset} por ya no estar disponible la %{related}"
- msg_cant_delete_user: "^No se pudo eliminar el usuario porque %{value} tiene recursos relacionados."
- msg_cant_do: "No se puede %{action} la %{asset} por ya no estar disponible."
+ msg_asset_rejected: Se ha rechazado %{value}.
+ msg_bad_image_file: ^No se pudo cargar o cambiar el tamaño del archivo de imagen
+ especificado.
+ msg_cant_create_related: No se puede crear la %{asset} por ya no estar disponible
+ la %{related}
+ msg_cant_delete_user: ^No se pudo eliminar el usuario porque %{value} tiene recursos
+ relacionados.
+ msg_cant_do: No se puede %{action} la %{asset} por ya no estar disponible.
msg_email_not_found: No se han encontrado usuarios con esa dirección de correo electrónico.
msg_enter_new_password: Por favor, introduzca su nueva contraseña, .
msg_goodbye: La sesión se ha cerrado. ¡Gracias por utilizar Fat Free CRM!
- msg_invalid_password: "^Por favor, introduzca correctamente su contraseña"
+ msg_invalid_password: ^Por favor, introduzca correctamente su contraseña
msg_invalig_login: Nombre de usuario o contraseña no válida.
msg_last_login: Su última conexión fue el %{value}.
msg_login_needed: Debe iniciar sesión para acceder a ésta página.
@@ -192,14 +171,12 @@
msg_password_changed: Su contraseña ha sido modificada.
msg_password_not_changed: Su contraseña no ha sido modificada.
msg_password_updated: Contraseña modificada con éxito.
- msg_pwd_instructions_sent: Se le han enviado las instrucciones para restaurar su contraseña. Por favor, revise su correo electrónico.
+ msg_pwd_instructions_sent: Se le han enviado las instrucciones para restaurar su
+ contraseña. Por favor, revise su correo electrónico.
msg_require_admin: Debe ser administrador para acceder a ésta página.
msg_successful_signup: Registro realizado con éxito, ¡Bienvenido/a a Fat Free CRM!
msg_welcome: ¡Bienvenido/a to Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": valor ponderado
+ option_amount*probability: valor ponderado
activity_options: Mostrar %{models} las actividades realizadas por %{user} en %{period}.
all_users: todos los usuarios
option_after: después de
@@ -214,22 +191,20 @@
option_ends_on: fecha de finalización
option_first_name: nombre
option_last_name: apellidos
- option_leads_count: iniciativas reales
+ option_leads_count: iniciativas reales
option_long: largo
option_name: nombre
option_probability: probabilidad
option_rating: valoración
option_revenue: ingresos reales
option_starts_on: fecha de inicio
- option_target_leads: iniciativas planeadas
- option_target_revenue: ingresos planeados
+ option_target_leads: iniciativas planeadas
+ option_target_revenue: ingresos planeados
option_updated_at: fecha de modificación
show_per_page: Mostrar %{number} %{models} por página utilizando el formato %{fmt}.
sort_by: Ordenar %{models} por %{field}.
- sort_by_displaying: Ordenar %{models} por %{field} mostrando el nombre %{position} los apellidos.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Ordenar %{models} por %{field} mostrando el nombre %{position}
+ los apellidos.
aim: AOL IM
already_signed_up: ¿Ya se ha registrado?
alt_email: Dirección de correo electrónico alternativa
@@ -239,17 +214,17 @@
contact_info: Información de Contacto
current_password: Contraseña actual
edit_profile: Editar Perfil
- # email: Correo electrónico # <-- Already defined as the task type if Settings.
first_name: Nombre
google: Google IM
gravatar_help: ¿No sabe qué son Gravatars? Conózcalos
image_file: Imagen de archivo
- image_help: El tamaño de la imagen que cargue se reajustará automáticamente a 75 x 75 píxeles. Los formatos soportados son GIF, JPG y PNG.
+ image_help: El tamaño de la imagen que cargue se reajustará automáticamente a 75
+ x 75 píxeles. Los formatos soportados son GIF, JPG y PNG.
job_title: Profesión
last_name: Apellidos
login_now_link: ¡Inicie sesión!
mobile: Teléfono móvil
- my_profile: Mi perfil
+ my_profile: Mi perfil
new_password: Nueva contraseña
password: Contraseña
password_confirmation: Confirmar contraseña
@@ -265,17 +240,11 @@
user: Usuario
username: Nombre de usuario
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: ¿Ha olvidado la contraseña
login: Iniciar sesión
no_account: ¿No tiene una cuenta?
remember_me: Recordar mis datos
sign_up_now: ¡Regístrese!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: Cuenta
account_small: cuenta
accounts: Cuentas
@@ -292,7 +261,7 @@
open_in_window: Abrir %{value} en una ventana nueva
mail_to: Correo electrónico a %{value}
phone_small: teléfono
- phone_toll_free: Llamada gratuita
+ phone_toll_free: Llamada gratuita
keep_private: Uso privado, no compartir con otros
make_public: Compartir con todos
same_as_billing: la misma que la de facturación
@@ -300,9 +269,6 @@
share_with: Compartir con las siguientes personas
shipping_address: Dirección de envío
website: Sitio web
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Real
actual_performance: Rendimiento Real
budget: Presupuesto
@@ -315,9 +281,9 @@
campaigns: Campañas
campaigns_options: Opciones de Campaña
campaigns_small: campañas
- conversion: Transformación
+ conversion: Transformación
conversion_label: Transformación (%)
- conversion_number: "Transformación %{value} "
+ conversion_number: ! 'Transformación %{value} '
create_campaign: Crear Campaña
end_date: Fecha de finalización
finished_on: completada el %{value}
@@ -325,23 +291,23 @@
no_start_date: fecha de inicio sin determinar
number_of_leads: Número de iniciativas
objectives: Objetivos
- objectives_help: Por favor, introduzca el número de iniciativas planeadas, la proporción prevista de las transformaciones de iniciativas a oportunidades, los ingresos planeados y el presupuesto de la campaña. Éstas cifras le permitirán mantenerse al tanto de los resultados reales de la campaña.
+ objectives_help: Por favor, introduzca el número de iniciativas planeadas, la proporción
+ prevista de las transformaciones de iniciativas a oportunidades, los ingresos
+ planeados y el presupuesto de la campaña. Éstas cifras le permitirán mantenerse
+ al tanto de los resultados reales de la campaña.
objectives_small: objetivos de la campaña
revenue: Ingresos
revenue_label: Ingresos (€)
- revenue_number: "%{value} de ingresos"
+ revenue_number: ! '%{value} de ingresos'
save_campaign: Guardar Campaña
start_date: Fecha de inicio
- started_ago: comenzó hace %{value}
+ started_ago: comenzó hace %{value}
starts_in: comienza en %{value}
starts_today: ¡comienza hoy!
target: Objetivo
total_campaigns: Total Campañas
- was_supposed_to_finish: finalización prevista el %{value}
+ was_supposed_to_finish: finalización prevista el %{value}
was_supposed_to_start: was supposed to start %{time_ago} ago on %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Otra
blog: Sitio web/blog
contact: Contacto
@@ -351,37 +317,48 @@
contacts_small: contactos
create_contact: Crear contacto
department: Departamento
- department_small: 'Departamento de %{value}'
+ department_small: Departamento de %{value}
do_not_call: No llamar por teléfono
extra_info: Información adicional
- extra_info_small: éste contacto
+ extra_info_small: éste contacto
facebook: Facebook
linked_in: LinkedIn
myself: Mí
- permissions_intro_private: Por defecto sólo usted tendrá acceso a %{value}. Puede cambiar los permisos más tarde.
- permissions_intro_public: Por defecto todos los usuarios tendrán acceso a %{value}. Puede cambiar los permisos más tarde.
- permissions_intro_shared: Por defecto sólo los usuarios seleccionados tendrán acceso a %{value}. Puede cambiar los permisos más tarde.
+ permissions_intro_private: Por defecto sólo usted tendrá acceso a %{value}. Puede
+ cambiar los permisos más tarde.
+ permissions_intro_public: Por defecto todos los usuarios tendrán acceso a %{value}.
+ Puede cambiar los permisos más tarde.
+ permissions_intro_shared: Por defecto sólo los usuarios seleccionados tendrán acceso
+ a %{value}. Puede cambiar los permisos más tarde.
referred_by: Referencias
referred_by_small: referencias
save_contact: Guardar contacto
twitter: Twitter
web_presence: Presencia en internet
web_presence_small: presencia en internet
- works_at: "%{job_title} en %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} en %{company}'
convert: Transformar
convert_lead: Transformar Iniciativa
- convert_lead_permissions_intro: Los permisos del Contacto se copiarán de la iniciativa transformada. Puede cambiar los permisos del contacto más tarde.
- convert_lead_text: Al transformar la iniciativa %{value} ésta se convertirá en un contacto asociado con una cuenta existente o con una cuenta nueva. El estado de la iniciativa cambiará automáticamente a iniciativa transformada.
+ convert_lead_permissions_intro: Los permisos del Contacto se copiarán de la iniciativa
+ transformada. Puede cambiar los permisos del contacto más tarde.
+ convert_lead_text: Al transformar la iniciativa %{value} ésta se convertirá en un
+ contacto asociado con una cuenta existente o con una cuenta nueva. El estado de
+ la iniciativa cambiará automáticamente a iniciativa transformada.
create_lead: Crear iniciativa
- create_opp_for_contact: De forma opcional puede crear una oportunidad para el contacto %{value} atribuyéndole un nombre, su estado actual, una fecha de cierre estimada, la probabilidad de ventas, valor de la transacción y descuento ofertado.
+ create_opp_for_contact: De forma opcional puede crear una oportunidad para el contacto
+ %{value} atribuyéndole un nombre, su estado actual, una fecha de cierre estimada,
+ la probabilidad de ventas, valor de la transacción y descuento ofertado.
lead: Iniciativa
lead_info_small: contacto de iniciativa
- lead_permissions_intro_private: Por defecto los permisos se copiarán de la campaña o estarán configurados de forma privada. Puede cambiar los permisos de la iniciativa más tarde.
- lead_permissions_intro_public: Por defecto los permisos se copiarán de la campaña o estarán configurados de forma pública. Puede cambiar los permisos de la iniciativa más tarde.
- lead_permissions_intro_shared: Por defecto los permisos se copiarán de la campaña o estarán compartidos con los usuarios seleccionados. Puede cambiar los permisos de la iniciativa más tarde.
+ lead_permissions_intro_private: Por defecto los permisos se copiarán de la campaña
+ o estarán configurados de forma privada. Puede cambiar los permisos de la iniciativa
+ más tarde.
+ lead_permissions_intro_public: Por defecto los permisos se copiarán de la campaña
+ o estarán configurados de forma pública. Puede cambiar los permisos de la iniciativa
+ más tarde.
+ lead_permissions_intro_shared: Por defecto los permisos se copiarán de la campaña
+ o estarán compartidos con los usuarios seleccionados. Puede cambiar los permisos
+ de la iniciativa más tarde.
lead_small: iniciativa
lead_status_small: estado de la iniciativa
lead_summary: Resumen de iniciativas
@@ -396,9 +373,6 @@
source: Fuente
status: Estado
total_leads: Total Iniciativas
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Cantidad
close_date: Fecha de cierre
closed_ago_on: cerrada hace %{time_ago} el %{date}
@@ -413,24 +387,22 @@
expected_to_close: cierre previsto dentro de %{time} el %{date}
from: desde
no_closing_date: sin fecha de cierre prevista
- no_discount: sin descuento
+ no_discount: sin descuento
opportunities: Oportunidades
opportunities_options: Opciones de Oportunidades
opportunities_small: oportunidades
opportunity: Oportunidad
opportunity_small: oportunidad
opportunity_summary: Oportunidad de un vistazo
- opportunity_summary_text: "%{amount} con %{discount} de descuento y %{probability} de probabilidad"
- past_due: plazo cumplido, cierre previsto hace %{value}
+ opportunity_summary_text: ! '%{amount} con %{discount} de descuento y %{probability}
+ de probabilidad'
+ past_due: plazo cumplido, cierre previsto hace %{value}
probability: Probabilidad
probability_number: y %{value} de probabilidad
save_opportunity: Guardar Oportunidad
stage: Estado
total_opportunities: Total Oportunidades
weighted_amount: Cantidad ponderada
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: Encargar a
assigned_tab: Encargadas
assigned_tasks: Tareas encargadas
@@ -439,46 +411,43 @@
completed_tasks: Tareas completadas
create_task: Crear tarea
create_task_small: crear una nueva tarea
- due: Fecha límite
+ due: Fecha límite
feel_free: Puede
move_to: mover a
- no_tasks: "No tiene tareas %{value}"
- no_tasks_pending: pending # TODO
- no_tasks_assigned: assigned # TODO
- no_tasks_completed: completed # TODO
+ no_tasks: No tiene tareas %{value}
+ no_tasks_pending: pending
+ no_tasks_assigned: assigned
+ no_tasks_completed: completed
pending_tab: Pendientes
pending_tasks: Tareas Pendientes
- related: 're:'
+ related: ! 're:'
save_task: Guardar Tarea
task_assigned: La tarea ha sido encargada a %{value}
task_assigned_to: y encargada a %{value}
task_completed: completada
- task_completed_ago: completada hace %{value}
+ task_completed_ago: completada hace %{value}
task_completed_by: completada %{time_ago} por %{user}
task_created: La tarea ha sido creada
- task_due_in: finalización prevista en %{value}
+ task_due_in: finalización prevista en %{value}
task_due_later: finaliza pronto
task_due_now: finaliza ahora
task_due_today: finaliza hoy
- task_from: De %{value}
+ task_from: De %{value}
task_overdue: fuera de plazo, finalizaba el
task_pending: La tarea se ha movido a tareas pendientes
task_small: tarea
tasks: Tareas
- total_tasks: "Total %{value}"
+ total_tasks: Total %{value}
view_assigned_tasks: ver las tareas encargadas
view_pending_tasks: ver las tareas pendientes
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: añadió nota a
action_completed: completó
action_created: creó
action_deleted: eliminó
- action_email: exchanged emails with # TODO
+ action_email: exchanged emails with
action_reassigned: reasignó
action_rejected: rechazó
- action_rescheduled: modificó fecha de finalización de
+ action_rescheduled: modificó fecha de finalización de
action_updated: actualizó
action_viewed: vió
action_won: conseguida
@@ -491,31 +460,28 @@
subject_lead: iniciativa
subject_opportunity: oportunidad
subject_task: tarea
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Añadir Nota
save_note: Guardar Nota
add_note_help: Añadir una nueva nota...
- edit_note: Editar Nota
+ edit_note: Editar Nota
added_ago: añadida hace %{value}
- added_by: añadida hace %{time_ago} por %{user}
+ added_by: añadida hace %{time_ago} por %{user}
back: atrás
cancel: Cancelar
close_form: cerrar formulario
confirm_delete: ¿Está seguro de que quiere eliminar éste %{value}?
copy_permissions: Copiar %{value} permisos
- could_not_find: "No se encontraron %{value}."
- could_not_find_matching: "No se pudo encontrar coincidencia con %{value}"
+ could_not_find: No se encontraron %{value}.
+ could_not_find_matching: No se pudo encontrar coincidencia con %{value}
create_new: Crear
select_existing: seleccione existentes
delete: Eliminar
- discard: Discard # TODO
+ discard: Discard
edit: Editar
- items_total: 'total %{count}.'
- less: Less... # TODO
+ items_total: total %{count}.
+ less: Less...
me: mí
- more: More... # TODO
+ more: More...
n_a: N/A
name: Nombre
no_match: No coincidencia con %{value}
@@ -525,21 +491,19 @@
please_retry: Por favor, pruebe con otra consulta
recent_items: Elementos recientes
search_assets: Buscar %{value}
- time_ago: "hace %{value}"
+ time_ago: hace %{value}
background_info: Información relevante
address: Dirección
city: Ciudad
zipcode: Código postal
state: Estado/Región
- country: País
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
+ country: País
about: Sobre
about_dev_group: Grupo de debate para programadores
about_features: Funciones y errores
about_ffc: Sobre Fat Free CRM
- about_ffc_resources: Recursos de Fat Free CRM (los enlaces se abren en una ventana nueva)
+ about_ffc_resources: Recursos de Fat Free CRM (los enlaces se abren en una ventana
+ nueva)
about_ffc_version: Versión Fat Free CRM
about_home_page: Página del producto
about_project_page: Página del proyecto
@@ -550,31 +514,19 @@
logout: Cerrar sesión
quick_find: Búsqueda rápida
welcome: Bienvenido/a
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Nota modificada
show: Mostrar
update: Actualizar
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Por favor, introduzca su nueva contraseña y confírmela.
- password_intro: Por favor, introduzca su dirección de correo electrónico y se le enviarán las instruciones para restaurar su contraseña.
+ password_intro: Por favor, introduzca su dirección de correo electrónico y se le
+ enviarán las instruciones para restaurar su contraseña.
reset_password: Restaurar contraseña
update_password_and_login: Modificar contraseña y nombre de usuario
-
- # Views -> Admin
- #----------------------------------------------------------------------------
- # TODO
back_to_crm: Back to Fat Free CRM
crm_admin_page: Fat Free CRM Administration
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Aprobar
create_user: Crear usuario
- last_seen: visto por última vez hace %{value}
+ last_seen: visto por última vez hace %{value}
personal_information: Información personal
reactivate: Reactivar
save_user: Guardar Usuario
@@ -582,55 +534,45 @@
user_active: Activar
user_admin: Admin
user_awaits_approval: pendiente de aprobación
- user_confirm_delete: Sólo se puede eliminar un usuario si no tiene recursos relacionados pendientes.
+ user_confirm_delete: Sólo se puede eliminar un usuario si no tiene recursos relacionados
+ pendientes.
user_is_admin: El usuario es el Administrador
- user_never_logged_in: "hasn't logged in yet"
+ user_never_logged_in: hasn't logged in yet
user_signed_up: Registrado
user_signed_up_on: registrado el %{value}
user_since: usuario desde %{value}
user_suspended: Suspendido
user_suspended_on: suspendido el %{value}
users: Usuarios
- users_small: usuarios
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - Añadido email - %{subject}
dropbox_notification_intro: Se ha añadido el email que envió al dropbox
dropbox_notification_to: Añadido a
subject: Asunto
body: Cuerpo
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment' # TODO
- other: '%{count} comments' # TODO
- contact:
- one: '1 contacto'
- other: '%{count} contactos'
+ one: 1 comment
+ other: ! '%{count} comments'
+ contact:
+ one: 1 contacto
+ other: ! '%{count} contactos'
opportunity:
- one: '1 opportunidad'
- other: '%{count} opportunidades'
+ one: 1 opportunidad
+ other: ! '%{count} opportunidades'
lead:
- one: '1 iniciativa'
- other: '%{count} iniciativas'
+ one: 1 iniciativa
+ other: ! '%{count} iniciativas'
day:
- one: '1 día'
- other: '%{count} días'
+ one: 1 día
+ other: ! '%{count} días'
login:
- one: '1 conexión'
- other: '%{count} conexiones'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 conexión
+ other: ! '%{count} conexiones'
date:
formats:
- mmddyyyy: "%m/%d/%Y"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%m/%d/%Y'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%b %e at %l:%M%p"
+ mmddhhss: ! '%b %e at %l:%M%p'
diff --git a/config/locales/fr-CA.yml b/config/locales/fr-CA.yml
index 50157f9286..8ddc4b85f1 100644
--- a/config/locales/fr-CA.yml
+++ b/config/locales/fr-CA.yml
@@ -1,187 +1,224 @@
-# French translations for Ruby on Rails
-# by Christian Lescuyer (christian@flyingcoders.com)
-# contributors:
-# - Sebastien Grosjean - ZenCocoon.com
-# - Bruno Michel - http://github.com/nono
-# - Tsutomu Kuroda - http://github.com/kuroda (t-kuroda@oiax.jp)
-#
-# French Canadian adjustments
-# by Serafim Junior Dos Santos Fagundes
-
+---
fr-CA:
date:
formats:
- default: "%Y-%m-%d"
- short: "%y-%m-%d"
- long: "%d %B %Y"
- day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
- abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam]
- month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre]
- abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.]
+ default: ! '%Y-%m-%d'
+ short: ! '%y-%m-%d'
+ long: ! '%d %B %Y'
+ day_names:
+ - dimanche
+ - lundi
+ - mardi
+ - mercredi
+ - jeudi
+ - vendredi
+ - samedi
+ abbr_day_names:
+ - dim
+ - lun
+ - mar
+ - mer
+ - jeu
+ - ven
+ - sam
+ month_names:
+ -
+ - janvier
+ - février
+ - mars
+ - avril
+ - mai
+ - juin
+ - juillet
+ - août
+ - septembre
+ - octobre
+ - novembre
+ - décembre
+ abbr_month_names:
+ -
+ - jan.
+ - fév.
+ - mar.
+ - avr.
+ - mai
+ - juin
+ - juil.
+ - août
+ - sept.
+ - oct.
+ - nov.
+ - déc.
order:
- - :year
- - :month
- - :day
-
+ - :year
+ - :month
+ - :day
time:
formats:
- default: "%H:%M:%S"
- short: "%H:%M"
- long: "%A %d %B %Y %H:%M"
- am: 'am'
- pm: 'pm'
-
+ default: ! '%H:%M:%S'
+ short: ! '%H:%M'
+ long: ! '%A %d %B %Y %H:%M'
+ am: am
+ pm: pm
datetime:
distance_in_words:
- half_a_minute: "une demi-minute"
+ half_a_minute: une demi-minute
less_than_x_seconds:
- zero: "moins d'une seconde"
- one: "moins d'une seconde"
- other: "moins de %{count} secondes"
+ zero: moins d'une seconde
+ one: moins d'une seconde
+ other: moins de %{count} secondes
x_seconds:
- one: "1 seconde"
- other: "%{count} secondes"
+ one: 1 seconde
+ other: ! '%{count} secondes'
less_than_x_minutes:
- zero: "moins d'une minute"
- one: "moins d'une minute"
- other: "moins de %{count} minutes"
+ zero: moins d'une minute
+ one: moins d'une minute
+ other: moins de %{count} minutes
x_minutes:
- one: "1 minute"
- other: "%{count} minutes"
+ one: 1 minute
+ other: ! '%{count} minutes'
about_x_hours:
- one: "environ une heure"
- other: "environ %{count} heures"
+ one: environ une heure
+ other: environ %{count} heures
x_days:
- one: "1 jour"
- other: "%{count} jours"
+ one: 1 jour
+ other: ! '%{count} jours'
about_x_months:
- one: "environ un mois"
- other: "environ %{count} mois"
+ one: environ un mois
+ other: environ %{count} mois
x_months:
- one: "1 mois"
- other: "%{count} mois"
+ one: 1 mois
+ other: ! '%{count} mois'
about_x_years:
- one: "environ un an"
- other: "environ %{count} ans"
+ one: environ un an
+ other: environ %{count} ans
over_x_years:
- one: "plus d'un an"
- other: "plus de %{count} ans"
+ one: plus d'un an
+ other: plus de %{count} ans
almost_x_years:
- one: "presqu'un an"
- other: "presque %{count} ans"
+ one: presqu'un an
+ other: presque %{count} ans
prompts:
- year: "Année"
- month: "Mois"
- day: "Jour"
- hour: "Heure"
- minute: "Minute"
- second: "Seconde"
-
+ year: Année
+ month: Mois
+ day: Jour
+ hour: Heure
+ minute: Minute
+ second: Seconde
number:
format:
- separator: ","
- delimiter: " "
+ separator: ! ','
+ delimiter: ! ' '
precision: 3
significant: false
strip_insignificant_zeros: false
currency:
format:
- format: "%n %u"
- unit: "$"
- separator: ","
- delimiter: " "
+ format: ! '%n %u'
+ unit: $
+ separator: ! ','
+ delimiter: ! ' '
precision: 2
significant: false
strip_insignificant_zeros: false
percentage:
format:
- delimiter: ""
+ delimiter: ''
precision:
format:
- delimiter: ""
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 2
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Octet"
- other: "Octets"
- kb: "ko"
- mb: "Mo"
- gb: "Go"
- tb: "To"
+ one: Octet
+ other: Octets
+ kb: ko
+ mb: Mo
+ gb: Go
+ tb: To
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
- thousand: "Millier"
- million: "Million"
- billion: "Milliard"
- trillion: "Mille milliard"
- quadrillion: "Million de milliards"
-
+ unit: ''
+ thousand: Millier
+ million: Million
+ billion: Milliard
+ trillion: Mille milliard
+ quadrillion: Million de milliards
support:
array:
- words_connector: ", "
- two_words_connector: " et "
- last_word_connector: " et "
+ words_connector: ! ', '
+ two_words_connector: ! ' et '
+ last_word_connector: ! ' et '
select:
- prompt: "Veuillez sélectionner"
-
+ prompt: Veuillez sélectionner
helpers:
select:
- prompt: "Veuillez sélectionner"
+ prompt: Veuillez sélectionner
submit:
- create: "Créer un %{model}"
- update: "Modifier ce %{model}"
- submit: "Enregistrer ce %{model}"
-
+ create: Créer un %{model}
+ update: Modifier ce %{model}
+ submit: Enregistrer ce %{model}
errors:
- template: &errors_template
- header:
- one: "Impossible d'enregistrer ce %{model} : 1 erreur"
- other: "Impossible d'enregistrer ce %{model} : %{count} erreurs"
- body: "Veuillez vérifier les champs suivants : "
-
+ format: Le %{attribute} %{message}
+ messages:
+ inclusion: n'est pas inclus(e) dans la liste
+ exclusion: n'est pas disponible
+ invalid: n'est pas valide
+ confirmation: ne concorde pas avec la confirmation
+ accepted: doit être accepté(e)
+ empty: doit être rempli(e)
+ blank: doit être rempli(e)
+ too_long: est trop long (pas plus de %{count} caractères)
+ too_short: est trop court (au moins %{count} caractères)
+ wrong_length: ne fait pas la bonne longueur (doit comporter %{count} caractères)
+ not_a_number: n'est pas un nombre
+ not_an_integer: doit être un nombre entier
+ greater_than: doit être supérieur à %{count}
+ greater_than_or_equal_to: doit être supérieur ou égal à %{count}
+ equal_to: doit être égal à %{count}
+ less_than: doit être inférieur à %{count}
+ less_than_or_equal_to: doit être inférieur ou égal à %{count}
+ odd: doit être impair
+ even: doit être pair
attributes:
- created_at: "Créé le"
- updated_at: "Modifié le"
-
- errors:
- format: "Le %{attribute} %{message}"
- messages: &errors_messages
- inclusion: "n'est pas inclus(e) dans la liste"
- exclusion: "n'est pas disponible"
- invalid: "n'est pas valide"
- confirmation: "ne concorde pas avec la confirmation"
- accepted: "doit être accepté(e)"
- empty: "doit être rempli(e)"
- blank: "doit être rempli(e)"
- too_long: "est trop long (pas plus de %{count} caractères)"
- too_short: "est trop court (au moins %{count} caractères)"
- wrong_length: "ne fait pas la bonne longueur (doit comporter %{count} caractères)"
- not_a_number: "n'est pas un nombre"
- not_an_integer: "doit être un nombre entier"
- greater_than: "doit être supérieur à %{count}"
- greater_than_or_equal_to: "doit être supérieur ou égal à %{count}"
- equal_to: "doit être égal à %{count}"
- less_than: "doit être inférieur à %{count}"
- less_than_or_equal_to: "doit être inférieur ou égal à %{count}"
- odd: "doit être impair"
- even: "doit être pair"
-
+ created_at: Créé le
+ updated_at: Modifié le
activerecord:
errors:
messages:
- taken: "n'est pas disponible"
- record_invalid: "La validation a échoué : %{errors}"
- <<: *errors_messages
+ inclusion: n'est pas inclus(e) dans la liste
+ exclusion: n'est pas disponible
+ invalid: n'est pas valide
+ confirmation: ne concorde pas avec la confirmation
+ accepted: doit être accepté(e)
+ empty: doit être rempli(e)
+ blank: doit être rempli(e)
+ too_long: est trop long (pas plus de %{count} caractères)
+ too_short: est trop court (au moins %{count} caractères)
+ wrong_length: ne fait pas la bonne longueur (doit comporter %{count} caractères)
+ not_a_number: n'est pas un nombre
+ not_an_integer: doit être un nombre entier
+ greater_than: doit être supérieur à %{count}
+ greater_than_or_equal_to: doit être supérieur ou égal à %{count}
+ equal_to: doit être égal à %{count}
+ less_than: doit être inférieur à %{count}
+ less_than_or_equal_to: doit être inférieur ou égal à %{count}
+ odd: doit être impair
+ even: doit être pair
+ taken: n'est pas disponible
+ record_invalid: ! 'La validation a échoué : %{errors}'
template:
- <<: *errors_template
+ header:
+ one: ! 'Impossible d''enregistrer ce %{model} : 1 erreur'
+ other: ! 'Impossible d''enregistrer ce %{model} : %{count} erreurs'
+ body: ! 'Veuillez vérifier les champs suivants : '
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/fr-CA_fat_free_crm.yml b/config/locales/fr-CA_fat_free_crm.yml
index 3d377d72ab..a761c03778 100644
--- a/config/locales/fr-CA_fat_free_crm.yml
+++ b/config/locales/fr-CA_fat_free_crm.yml
@@ -5,46 +5,37 @@
# French Canadian adjustments
# by Serafim Junior Dos Santos Fagundes
+---
fr-CA:
language: Français (Canadien)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Tous
at: à
here: ici
- no_button: 'Non'
+ no_button: Non
not_implemented: Pas encore implémenté.
or: ou
- select_none: '-- Aucun --'
- select_blank: '-- Selectionnez --'
- yes_button: 'Oui'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- Aucun --
+ select_blank: -- Selectionnez --
+ yes_button: Oui
tab_dashboard: Résumé
- tab_tasks: Tâches
+ tab_tasks: Tâches
tab_campaigns: Campagnes
tab_leads: Pistes
tab_accounts: Comptes
tab_contacts: Contacts
tab_opportunities: Opportunités
-
admin_tab_users: Utilisateurs
admin_tab_settings: Paramètres
admin_tab_plugins: Plugins
-
planned: Planifié
started: Démarré
on_hold: En attente
completed: Complétée
called_off: Abandonné
-
new: Nouveau
contacted: Contacté
converted: Converti
rejected: Rejeté
-
cold_call: Appel entrant
conference: Conférence
online: Online Marketing
@@ -53,7 +44,6 @@ fr-CA:
web: Website
word_of_mouth: Bouche à oreille
other: Autre
-
prospecting: Prospection
analysis: Analyse
presentation: Présentation
@@ -62,7 +52,6 @@ fr-CA:
final_review: Examen final
won: Clôturé/Gagné
lost: Clôture/Perdu
-
call: Appel
email: E-mail
follow_up: Relance
@@ -70,138 +59,125 @@ fr-CA:
meeting: Réunion
money: Argent
trip: Voyage
-
overdue: Délai expiré
due_asap: Dès que possible
- due_today: "Aujourd'hui"
+ due_today: Aujourd'hui
due_tomorrow: Demain
due_this_week: Cette semaine
due_next_week: La semaine prochaine
due_later: Plus tard
due_specific_date: A date précise...
-
- completed_today: "Ajourd'hui"
+ completed_today: Ajourd'hui
completed_yesterday: Hier
completed_last_week: La semaine dernière
completed_this_month: Ce mois
completed_last_month: Le mois dernier
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: Une heure
one_day: Un jour
two_days: Deux jours
one_week: Une semaine
two_weeks: Deux semaines
one_month: Un mois
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
authentication:
attributes:
login_field:
- is_not_valid: "n'est pas valide"
+ is_not_valid: n'est pas valide
password_field:
- is_not_valid: "n'est pas valide"
+ is_not_valid: n'est pas valide
account:
attributes:
name:
- missing_account_name: "^Vérifiez le nom de compte."
+ missing_account_name: ^Vérifiez le nom de compte.
access:
- share_account: "^Spécifiez un utilisateur avec qui partager le compte."
+ share_account: ^Spécifiez un utilisateur avec qui partager le compte.
campaign:
attributes:
name:
- missing_campaign_name: "^Précisez un nom de campagne."
+ missing_campaign_name: ^Précisez un nom de campagne.
ends_on:
- dates_not_in_sequence: "^Vérifiez que la date de fin de campagne soit avant la date de début."
+ dates_not_in_sequence: ^Vérifiez que la date de fin de campagne soit
+ avant la date de début.
access:
- share_campaign: "^Préciser un utilisateur avec qui partager la campagne."
+ share_campaign: ^Préciser un utilisateur avec qui partager la campagne.
contact:
attributes:
first_name:
- missing_first_name: "^Précisez le prénom"
+ missing_first_name: ^Précisez le prénom
last_name:
- missing_last_name: "^Précisez le nom."
+ missing_last_name: ^Précisez le nom.
access:
- share_contact: "^Précisez avec quel utilisateur partager le contact."
+ share_contact: ^Précisez avec quel utilisateur partager le contact.
lead:
attributes:
first_name:
- missing_first_name: "^Précisez le prénom"
+ missing_first_name: ^Précisez le prénom
last_name:
- missing_last_name: "^Précisez le nom."
+ missing_last_name: ^Précisez le nom.
access:
- share_lead: "^Précisez avec quel utilisateur partager la piste."
+ share_lead: ^Précisez avec quel utilisateur partager la piste.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Spécifiez un nom d'opportunité."
+ missing_opportunity_name: ^Spécifiez un nom d'opportunité.
access:
- share_opportunity: "^Précisez avec quel utilisateur partager l'opportunité."
+ share_opportunity: ^Précisez avec quel utilisateur partager l'opportunité.
task:
attributes:
name:
- missing_task_name: "^Précisez le nom de la tâche."
+ missing_task_name: ^Précisez le nom de la tâche.
calendar:
- invalid_date: "^Précisez une date valide"
+ invalid_date: ^Précisez une date valide
user:
attributes:
username:
- missing_username: "^Précisez un nom d'utilisateur."
- username_taken: "^Ce nom d'utilisateur est déjà pris"
+ missing_username: ^Précisez un nom d'utilisateur.
+ username_taken: ^Ce nom d'utilisateur est déjà pris
email:
- missing_email: "^Précisez une adresse e-mail"
- email_in_use: "^Un utilisateur existe déjà avec cette adresse."
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ missing_email: ^Précisez une adresse e-mail
+ email_in_use: ^Un utilisateur existe déjà avec cette adresse.
errors:
template:
header:
- one: "Impossible d'enregistrer ce %{model} : 1 erreur"
- other: "Impossible d'enregistrer ce %{model} : %{count} erreurs"
- body: "Veuillez vérifier les champs suivants : "
-
+ one: ! 'Impossible d''enregistrer ce %{model} : 1 erreur'
+ other: ! 'Impossible d''enregistrer ce %{model} : %{count} erreurs'
+ body: ! 'Veuillez vérifier les champs suivants : '
msg_account_suspended: Ce compte utilisateur a été suspendu.
password_reset_instruction: instruction de reinitialisation du mot de passe
-
- # Controllers.
- #----------------------------------------------------------------------------
- msg_account_created: "Votre compte a été créé, il est en attente d'approbation par l'administrateur"
- msg_account_not_approved: "Votre compte n'à pas encore été approuvé"
- msg_asset_deleted: "%{value} à été supprimé"
- msg_asset_not_available: "Ce %{value} n'est plus disponible."
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
- msg_assets_not_available: "Les %{value} ne sont pas disponibles."
- msg_asset_rejected: "%{value} à été rejetée."
- msg_bad_image_file: "^Nous n'avons pu télécharger ou redimensionner votre image."
- msg_cant_create_related: "Impossible de crée le %{asset} puisque le %{related} n'est plus disponnible."
- msg_cant_delete_user: "^Impossible de supprimer car %{value} a des objets présents."
- msg_cant_do: "Impossible de %{action} le %{asset} puisqu'il n'est plus disponible."
- msg_email_not_found: "Aucun utilisateur ne correspond a cette adresse"
+ msg_account_created: Votre compte a été créé, il est en attente d'approbation par
+ l'administrateur
+ msg_account_not_approved: Votre compte n'à pas encore été approuvé
+ msg_asset_deleted: ! '%{value} à été supprimé'
+ msg_asset_not_available: Ce %{value} n'est plus disponible.
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
+ msg_assets_not_available: Les %{value} ne sont pas disponibles.
+ msg_asset_rejected: ! '%{value} à été rejetée.'
+ msg_bad_image_file: ^Nous n'avons pu télécharger ou redimensionner votre image.
+ msg_cant_create_related: Impossible de crée le %{asset} puisque le %{related} n'est
+ plus disponnible.
+ msg_cant_delete_user: ^Impossible de supprimer car %{value} a des objets présents.
+ msg_cant_do: Impossible de %{action} le %{asset} puisqu'il n'est plus disponible.
+ msg_email_not_found: Aucun utilisateur ne correspond a cette adresse
msg_enter_new_password: Saisissez votre nouveau mot de passe.
- msg_goodbye: "Vous avez été déconnecté, merci d'utiliser Fat Free CRM!"
- msg_invalid_password: "^Saisissez votre mot de passe actuel"
+ msg_goodbye: Vous avez été déconnecté, merci d'utiliser Fat Free CRM!
+ msg_invalid_password: ^Saisissez votre mot de passe actuel
msg_invalig_login: Utilisateur ou mot de passe non valide.
- msg_last_login: "Votre dernière connection était le %{value}."
+ msg_last_login: Votre dernière connection était le %{value}.
msg_login_needed: Vous devez être connecté pour accéder a cette page.
msg_logout_needed: Vous devez être déconnecté pour accéder a cette page.
- msg_password_changed: "Votre mot de passe a été modifié"
- msg_password_not_changed: "Votre mot de passe n'a pas été modifié"
+ msg_password_changed: Votre mot de passe a été modifié
+ msg_password_not_changed: Votre mot de passe n'a pas été modifié
msg_password_updated: Modification de mot de passe réussie.
- msg_pwd_instructions_sent: "Les instruction de modification de mot de passe vous on été envoyées. Vérifiez vos e-mails"
- msg_require_admin: Vous devez être administrateur pour accéder a cette page
+ msg_pwd_instructions_sent: Les instruction de modification de mot de passe vous
+ on été envoyées. Vérifiez vos e-mails
+ msg_require_admin: Vous devez être administrateur pour accéder a cette page
msg_successful_signup: Enregistrement réussi. Bienvenu dans Fat Free CRM
- msg_welcome: Bienvenu dans Fat Free CRM
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": Montant pondéré
- activity_options: Voir les actions %{models} effectuées par %{user} dans les derniers %{period}.
+ msg_welcome: Bienvenu dans Fat Free CRM
+ option_amount*probability: Montant pondéré
+ activity_options: Voir les actions %{models} effectuées par %{user} dans les derniers
+ %{period}.
all_users: tous les utilisateurs
option_after: après
option_all: tous
@@ -225,12 +201,10 @@ fr-CA:
option_target_leads: pistes cibles
option_target_revenue: revenus cibles
option_updated_at: date de modification
- show_per_page: Voir %{number} %{models} par page au format %{fmt}.
+ show_per_page: Voir %{number} %{models} par page au format %{fmt}.
sort_by: Trier %{models} par %{field}.
- sort_by_displaying: Trier %{models} par %{field} afficher le prénom %{position} le nom.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Trier %{models} par %{field} afficher le prénom %{position}
+ le nom.
aim: AOL IM
already_signed_up: Déjà enregistré?
alt_email: e-mail secondaire
@@ -240,12 +214,12 @@ fr-CA:
contact_info: Informations de contact
current_password: Mot de passe actuel
edit_profile: Modifier le profile
- # email: E-mail # <-- Already defined as the task type if Settings.
first_name: Prénom
google: Google IM
gravatar_help: Vous ne connaissez pas Gravatar? Informations sur Gravatar
image_file: Fichier image
- image_help: "L'image que vous envoyez sera redimensionnée à 75 x 75 pixels. Les formats supportés sont GIF, JPEG et PNG."
+ image_help: L'image que vous envoyez sera redimensionnée à 75 x 75 pixels. Les formats
+ supportés sont GIF, JPEG et PNG.
job_title: Titre/Fonction
last_name: Nom
login_now_link: Connectez vous maintenant!
@@ -264,19 +238,13 @@ fr-CA:
upload_picture: Envoyez une image
use_gravatar: Utilisez Gravatar
user: Utilisateur
- username: "Nom d'utilisateur"
+ username: Nom d'utilisateur
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Mot de passe oublié
login: Connection
no_account: Vous ne possédez pas de compte?
remember_me: Se souvenir de moi
- sign_up_now: "S'enregistrer maintenant!"
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
+ sign_up_now: S'enregistrer maintenant!
account: Compte
account_small: compte
accounts: Comptes
@@ -300,9 +268,6 @@ fr-CA:
share_with: Partager avec les personnes suivantes
shipping_address: Adresse de livraison
website: Site Web
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Actuel
actual_performance: Performance Actuelle
budget: Budget
@@ -317,7 +282,7 @@ fr-CA:
campaigns_small: campagnes
conversion: Conversion
conversion_label: Conversion (%)
- conversion_number: "%{value} conversion"
+ conversion_number: ! '%{value} conversion'
create_campaign: Créer une Campagne
end_date: Date de fin
finished_on: terminé le %{value}
@@ -325,23 +290,22 @@ fr-CA:
no_start_date: pas de date de début spécifiée
number_of_leads: Nombre de pistes
objectives: Objectifs
- objectives_help: "Spécifiez un objectif en nombre de pistes, taux de conversion de pistes/opportunités, revenu espéré et budget. Ces valeurs seront utilisées lors de l'évaluation des performances de la campagne"
+ objectives_help: Spécifiez un objectif en nombre de pistes, taux de conversion de
+ pistes/opportunités, revenu espéré et budget. Ces valeurs seront utilisées lors
+ de l'évaluation des performances de la campagne
objectives_small: objectifs de la campagne
revenue: Revenu
revenue_label: Revenu ($)
- revenue_number: "%{value} pour revenu"
+ revenue_number: ! '%{value} pour revenu'
save_campaign: Enregistrer la campagne
start_date: Date de début
started_ago: démarré il y a %{value}
starts_in: démarré dans %{value}
- starts_today: "démarre aujourd'hui!"
+ starts_today: démarre aujourd'hui!
target: Cible
total_campaigns: Total des Campagnes
was_supposed_to_finish: présumée se terminer le %{value}
was_supposed_to_start: était supposée démarrer il y a %{time_ago} le %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
address: Adresse
alt_email_small: Autre
blog: Site Web/Blog
@@ -352,37 +316,47 @@ fr-CA:
contacts_small: contacts
create_contact: Créer un Contact
department: Département
- department_small: 'département %{value} '
+ department_small: ! 'département %{value} '
do_not_call: ne pas appeler
extra_info: Informations supplémentaires
extra_info_small: contact supplémentaire
facebook: Facebook
linked_in: LinkedIn
myself: Moi-même
- permissions_intro_private: Par défaut vous seul aurez accès à %{value}. Vous pouvez modifier les permissions ultérieurement.
- permissions_intro_public: Par défaut tous les utilisateurs auront accès à %{value}. Vous pouvez modifier les permissions ultérieurement.
- permissions_intro_shared: Par défaut seul les utilisateurs sélectionnés auront accès à %{value}. Vous pouvez modifier les permissions ultérieurement.
+ permissions_intro_private: Par défaut vous seul aurez accès à %{value}. Vous pouvez
+ modifier les permissions ultérieurement.
+ permissions_intro_public: Par défaut tous les utilisateurs auront accès à %{value}.
+ Vous pouvez modifier les permissions ultérieurement.
+ permissions_intro_shared: Par défaut seul les utilisateurs sélectionnés auront accès
+ à %{value}. Vous pouvez modifier les permissions ultérieurement.
referred_by: Référencé par
referred_by_small: référence par
save_contact: Enregistrer le contact
twitter: Twitter
- web_presence: Présence Web
- web_presence_small: présence web
- works_at: "%{job_title} chez %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ web_presence: Présence Web
+ web_presence_small: présence web
+ works_at: ! '%{job_title} chez %{company}'
convert: Convertir
convert_lead: Convertir la piste
- convert_lead_permissions_intro: Les permissions du contact seront dupliquées depuis la piste. Vous pouvez modifier les permissions du contact ultérieurement.
- convert_lead_text: En convertissant la piste %{value} il/elle deviendras un contact associé a un compte existant ou nouvellement créé. Le statut de la piste sera automatiquement positionné à converti.
+ convert_lead_permissions_intro: Les permissions du contact seront dupliquées depuis
+ la piste. Vous pouvez modifier les permissions du contact ultérieurement.
+ convert_lead_text: En convertissant la piste %{value} il/elle deviendras un contact
+ associé a un compte existant ou nouvellement créé. Le statut de la piste sera
+ automatiquement positionné à converti.
create_lead: Créer une piste
- create_opp_for_contact: "Vous pouvez éventuellement créer une opportunité pour le contact %{value} en spécifiant le nom, l'étape courante, la date de clôture estimée, la probabilité de vente, le montant de l'affaire, la remise offerte."
+ create_opp_for_contact: Vous pouvez éventuellement créer une opportunité pour le
+ contact %{value} en spécifiant le nom, l'étape courante, la date de clôture estimée,
+ la probabilité de vente, le montant de l'affaire, la remise offerte.
lead: Piste
lead_info_small: contact de la piste
- lead_permissions_intro_private: Par défaut les permissions seront dupliquée depuis la campagne ou positionnées sur privé. Vous pouvez modifier les permissions ultérieurement.
- lead_permissions_intro_public: Par défaut les permissions seront dupliquée depuis la campagne ou positionnées sur publique. Vous pouvez modifier les permissions ultérieurement.
- lead_permissions_intro_shared: Par défaut les permissions seront dupliquée depuis la campagne ou partagées avec les utilisateurs spécifiés. Vous pouvez modifier les permissions ultérieurement.
+ lead_permissions_intro_private: Par défaut les permissions seront dupliquée depuis
+ la campagne ou positionnées sur privé. Vous pouvez modifier les permissions ultérieurement.
+ lead_permissions_intro_public: Par défaut les permissions seront dupliquée depuis
+ la campagne ou positionnées sur publique. Vous pouvez modifier les permissions
+ ultérieurement.
+ lead_permissions_intro_shared: Par défaut les permissions seront dupliquée depuis
+ la campagne ou partagées avec les utilisateurs spécifiés. Vous pouvez modifier
+ les permissions ultérieurement.
lead_small: piste
lead_status_small: statut de la piste
lead_summary: Résumé de la piste
@@ -397,13 +371,10 @@ fr-CA:
source: Source
status: Statut
total_leads: Total des pistes
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Montant
close_date: Date de clôture
closed_ago_on: clôturé il y à%{time_ago} le %{date}
- closes_today: "doit être clôturé aujourd'hui!"
+ closes_today: doit être clôturé aujourd'hui!
closing_date: la date de clôture est %{value}
create_opportunity: Créer une opportunité
currency: ($)
@@ -421,17 +392,15 @@ fr-CA:
opportunity: Opportunité
opportunity_small: opportunité
opportunity_summary: Opportunité At a Glance
- opportunity_summary_text: "%{amount} avec %{discount} de remise et %{probability} de probabilité"
- past_due: en retard, devais être clôturé il y a %{value}.
+ opportunity_summary_text: ! '%{amount} avec %{discount} de remise et %{probability}
+ de probabilité'
+ past_due: en retard, devais être clôturé il y a %{value}.
probability: Probabilité
probability_number: et %{value} de probabilité
- save_opportunity: "Enregistrer l'opportunité"
+ save_opportunity: Enregistrer l'opportunité
stage: Etape
total_opportunities: Total des opportunités
weighted_amount: Montant pondéré
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: Assigner à
assigned_tab: Assigné
assigned_tasks: Tâches assignées
@@ -443,13 +412,13 @@ fr-CA:
due: A faire
feel_free: N'hésitez pas à
move_to: aller à
- no_tasks: "Vous n'avez aucune tâche %{value} "
+ no_tasks: ! 'Vous n''avez aucune tâche %{value} '
no_tasks_pending: en attente
no_tasks_assigned: assignée
no_tasks_completed: complétée
pending_tab: En attente
pending_tasks: Taches en attente
- related: 're:'
+ related: ! 're:'
save_task: Enregistrer la tâche
task_assigned: La tâche à été assignée à %{value}
task_assigned_to: et assignée à %{value}
@@ -460,7 +429,7 @@ fr-CA:
task_due_in: échéance dans %{value}
task_due_later: a faire bientôt
task_due_now: échoit maintenant
- task_due_today: "échoit aujourd'hui"
+ task_due_today: échoit aujourd'hui
task_from: De %{value}
task_overdue: en retard, échoyait le
task_pending: La tâche à été mise en attente.
@@ -469,9 +438,6 @@ fr-CA:
total_tasks: Total %{value}
view_assigned_tasks: voir les tâches assignées
view_pending_tasks: voir les tâches en attente
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: commenté le
action_completed: Complété
action_created: créé
@@ -492,138 +458,112 @@ fr-CA:
subject_lead: piste
subject_opportunity: opportunité
subject_task: tache
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Ajouter une note
save_note: Enregistrer la note
add_note_help: Ajouter une nouvelle note...
added_ago: ajoutée il y à %{value}
- added_by: ajoutée il y à %{time_ago} par %{user}
+ added_by: ajoutée il y à %{time_ago} par %{user}
back: Retour
cancel: Annuler
close_form: Fermer le formulaire
- confirm_delete: "Êtes-vous certain de vouloir supprimer ceci : %{value}?"
- copy_permissions: Copier les permissions de %{value}
- could_not_find: "%{value} N'a pas été trouvé. N'hésitez pas à "
- could_not_find_matching: "Aucun(e) %{value} n'a été trouvé correspondant à"
+ confirm_delete: ! 'Êtes-vous certain de vouloir supprimer ceci : %{value}?'
+ copy_permissions: Copier les permissions de %{value}
+ could_not_find: ! '%{value} N''a pas été trouvé. N''hésitez pas à '
+ could_not_find_matching: Aucun(e) %{value} n'a été trouvé correspondant à
create_new: créer un(e)
select_existing: sélectionnez
delete: Supprimer
discard: Rejeter
edit: Modifier
- items_total: '%{count} total.'
+ items_total: ! '%{count} total.'
less: Moins...
me: moi
more: Plus...
n_a: N/A
name: Nom
no_match: Acun(e) %{value} ne correspond
- no_recent_items: "Il n'y rien de récent à afficher"
+ no_recent_items: Il n'y rien de récent à afficher
options: Options
permissions: Permissions
please_retry: tentez une autre requête.
recent_items: Objets récents
search_assets: Recherche de %{value}
- time_ago: "il y à %{value}"
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
+ time_ago: il y à %{value}
about: A propos
about_dev_group: Groupe de discussion développeur
about_features: Fonctionnalités et bugs
about_ffc: A propos Fat Free CRM
about_ffc_resources: Ressources Fat Free CRM (Nouvelle fenêtre)
about_ffc_version: Fat Free CRM version
- about_home_page: "Page d'accueil"
+ about_home_page: Page d'accueil
about_project_page: Page du projet
- about_thank_you: "Merci d'utiliser Fat Free CRM!"
+ about_thank_you: Merci d'utiliser Fat Free CRM!
about_twitter: Twitter commit updates
about_user_group: Discussion group for users
admin: Admin
logout: Déconnection
quick_find: Recherche rapide
welcome: Bienvenu
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Edition de commentaire
show: Voir
update: Modifier
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Saisissez votre nouveau mot de passe et sa confirmation.
- password_intro: Précisez votre adresse e-mail, et les instructions pour les réinitialiser vous seront communiquées.
+ password_intro: Précisez votre adresse e-mail, et les instructions pour les réinitialiser
+ vous seront communiquées.
reset_password: Ré-initialisation du mot de passe
- update_password_and_login: "Modification de l'identifiant et du mot de passe"
-
- # Views -> Admin
- #----------------------------------------------------------------------------
+ update_password_and_login: Modification de l'identifiant et du mot de passe
back_to_crm: Retour à Fat Free CRM
crm_admin_page: Administration Fat Free CRM
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Approuver
create_user: Créer un utilisateur
last_seen: vu pour la dernière fois il y à %{value}
personal_information: Informations personnelles
reactivate: Réactiver
- save_user: "Enregistrer l'utilisateur"
+ save_user: Enregistrer l'utilisateur
suspend: Suspendre
user_active: Actif
user_admin: Admin
user_awaits_approval: en attente de votre approbation
- user_confirm_delete: Un utilisateur ne peut être supprimé que si aucun objet lui appartenant existent toujours.
- user_is_admin: "L'utilisateur est administrateur"
- user_never_logged_in: "ne s'est pas encore connecté"
+ user_confirm_delete: Un utilisateur ne peut être supprimé que si aucun objet lui
+ appartenant existent toujours.
+ user_is_admin: L'utilisateur est administrateur
+ user_never_logged_in: ne s'est pas encore connecté
user_signed_up: Est enregistré
- user_signed_up_on: "s'est enregistré le %{value}"
+ user_signed_up_on: s'est enregistré le %{value}
user_since: utilisateur depuis %{value}
user_suspended: Suspendu
user_suspended_on: suspendu le %{value}
users: Utilisateurs
users_small: utilisateurs
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - Ajouté email - %{subject}
dropbox_notification_intro: D'ajouter l'email que vous avez envoyé à la sélection
dropbox_notification_to: Ajoutés aux
subject: Sujet
body: Corps
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment' # TODO
- other: '%{count} comments' # TODO
- contact:
- one: '1 contact'
- other: '%{count} contacts'
+ one: 1 comment
+ other: ! '%{count} comments'
+ contact:
+ one: 1 contact
+ other: ! '%{count} contacts'
opportunity:
- one: '1 opportunité'
- other: '%{count} opportunités'
+ one: 1 opportunité
+ other: ! '%{count} opportunités'
lead:
- one: '1 piste'
- other: '%{count} pistes'
+ one: 1 piste
+ other: ! '%{count} pistes'
day:
- one: '1 jour'
- other: '%{count} jours'
+ one: 1 jour
+ other: ! '%{count} jours'
login:
- one: '1 identifiant'
- other: '%{count} identifiants'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 identifiant
+ other: ! '%{count} identifiants'
date:
formats:
- mmddyyyy: "%d/%m/%Y"
- mmdd: "%e %b"
- mmddyy: "%e %b, %Y"
-
+ mmddyyyy: ! '%d/%m/%Y'
+ mmdd: ! '%e %b'
+ mmddyy: ! '%e %b, %Y'
time:
formats:
- mmddhhss: "%e %b à %l:%M%p"
+ mmddhhss: ! '%e %b à %l:%M%p'
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 643edc5cb9..f68bfecee1 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -1,182 +1,227 @@
-# French translations for Ruby on Rails
-# by Christian Lescuyer (christian@flyingcoders.com)
-# contributors:
-# - Sebastien Grosjean - ZenCocoon.com
-# - Bruno Michel - http://github.com/nono
-# - Tsutomu Kuroda - http://github.com/kuroda (t-kuroda@oiax.jp)
-
+---
fr:
date:
formats:
- default: "%d/%m/%Y"
- short: "%e %b"
- long: "%e %B %Y"
- day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
- abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam]
- month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre]
- abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.]
+ default: ! '%d/%m/%Y'
+ short: ! '%e %b'
+ long: ! '%e %B %Y'
+ day_names:
+ - dimanche
+ - lundi
+ - mardi
+ - mercredi
+ - jeudi
+ - vendredi
+ - samedi
+ abbr_day_names:
+ - dim
+ - lun
+ - mar
+ - mer
+ - jeu
+ - ven
+ - sam
+ month_names:
+ -
+ - janvier
+ - février
+ - mars
+ - avril
+ - mai
+ - juin
+ - juillet
+ - août
+ - septembre
+ - octobre
+ - novembre
+ - décembre
+ abbr_month_names:
+ -
+ - jan.
+ - fév.
+ - mar.
+ - avr.
+ - mai
+ - juin
+ - juil.
+ - août
+ - sept.
+ - oct.
+ - nov.
+ - déc.
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%d %B %Y %H:%M:%S"
- short: "%d %b %H:%M"
- long: "%A %d %B %Y %H:%M"
- am: 'am'
- pm: 'pm'
-
+ default: ! '%d %B %Y %H:%M:%S'
+ short: ! '%d %b %H:%M'
+ long: ! '%A %d %B %Y %H:%M'
+ am: am
+ pm: pm
datetime:
distance_in_words:
- half_a_minute: "une demi-minute"
+ half_a_minute: une demi-minute
less_than_x_seconds:
- zero: "moins d'une seconde"
- one: "moins d'une seconde"
- other: "moins de %{count} secondes"
+ zero: moins d'une seconde
+ one: moins d'une seconde
+ other: moins de %{count} secondes
x_seconds:
- one: "1 seconde"
- other: "%{count} secondes"
+ one: 1 seconde
+ other: ! '%{count} secondes'
less_than_x_minutes:
- zero: "moins d'une minute"
- one: "moins d'une minute"
- other: "moins de %{count} minutes"
+ zero: moins d'une minute
+ one: moins d'une minute
+ other: moins de %{count} minutes
x_minutes:
- one: "1 minute"
- other: "%{count} minutes"
+ one: 1 minute
+ other: ! '%{count} minutes'
about_x_hours:
- one: "environ une heure"
- other: "environ %{count} heures"
+ one: environ une heure
+ other: environ %{count} heures
x_days:
- one: "1 jour"
- other: "%{count} jours"
+ one: 1 jour
+ other: ! '%{count} jours'
about_x_months:
- one: "environ un mois"
- other: "environ %{count} mois"
+ one: environ un mois
+ other: environ %{count} mois
x_months:
- one: "1 mois"
- other: "%{count} mois"
+ one: 1 mois
+ other: ! '%{count} mois'
about_x_years:
- one: "environ un an"
- other: "environ %{count} ans"
+ one: environ un an
+ other: environ %{count} ans
over_x_years:
- one: "plus d'un an"
- other: "plus de %{count} ans"
+ one: plus d'un an
+ other: plus de %{count} ans
almost_x_years:
- one: "presqu'un an"
- other: "presque %{count} ans"
+ one: presqu'un an
+ other: presque %{count} ans
prompts:
- year: "Année"
- month: "Mois"
- day: "Jour"
- hour: "Heure"
- minute: "Minute"
- second: "Seconde"
-
+ year: Année
+ month: Mois
+ day: Jour
+ hour: Heure
+ minute: Minute
+ second: Seconde
number:
format:
- separator: ","
- delimiter: " "
+ separator: ! ','
+ delimiter: ! ' '
precision: 3
significant: false
strip_insignificant_zeros: false
currency:
format:
- format: "%n %u"
- unit: "€"
- separator: ","
- delimiter: " "
+ format: ! '%n %u'
+ unit: €
+ separator: ! ','
+ delimiter: ! ' '
precision: 2
significant: false
strip_insignificant_zeros: false
percentage:
format:
- delimiter: ""
+ delimiter: ''
precision:
format:
- delimiter: ""
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 2
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "octet"
- other: "octets"
- kb: "ko"
- mb: "Mo"
- gb: "Go"
- tb: "To"
+ one: octet
+ other: octets
+ kb: ko
+ mb: Mo
+ gb: Go
+ tb: To
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
- thousand: "millier"
- million: "million"
- billion: "milliard"
- trillion: "billion"
- quadrillion: "million de milliards"
-
+ unit: ''
+ thousand: millier
+ million: million
+ billion: milliard
+ trillion: billion
+ quadrillion: million de milliards
support:
array:
- words_connector: ", "
- two_words_connector: " et "
- last_word_connector: " et "
+ words_connector: ! ', '
+ two_words_connector: ! ' et '
+ last_word_connector: ! ' et '
select:
- prompt: "Veuillez sélectionner"
-
+ prompt: Veuillez sélectionner
helpers:
select:
- prompt: "Veuillez sélectionner"
+ prompt: Veuillez sélectionner
submit:
- create: "Créer un %{model}"
- update: "Modifier ce %{model}"
- submit: "Enregistrer ce %{model}"
-
+ create: Créer un %{model}
+ update: Modifier ce %{model}
+ submit: Enregistrer ce %{model}
attributes:
- created_at: "Créé le"
- updated_at: "Modifié le"
-
+ created_at: Créé le
+ updated_at: Modifié le
errors:
- format: "Le %{attribute} %{message}"
- messages: &errors_messages
- inclusion: "n'est pas inclus(e) dans la liste"
- exclusion: "n'est pas disponible"
- invalid: "n'est pas valide"
- confirmation: "ne concorde pas avec la confirmation"
- accepted: "doit être accepté(e)"
- empty: "doit être rempli(e)"
- blank: "doit être rempli(e)"
- too_long: "est trop long (pas plus de %{count} caractères)"
- too_short: "est trop court (au moins %{count} caractères)"
- wrong_length: "ne fait pas la bonne longueur (doit comporter %{count} caractères)"
- not_a_number: "n'est pas un nombre"
- not_an_integer: "doit être un nombre entier"
- greater_than: "doit être supérieur à %{count}"
- greater_than_or_equal_to: "doit être supérieur ou égal à %{count}"
- equal_to: "doit être égal à %{count}"
- less_than: "doit être inférieur à %{count}"
- less_than_or_equal_to: "doit être inférieur ou égal à %{count}"
- odd: "doit être impair"
- even: "doit être pair"
- template: &errors_template
- header:
- one: "Impossible d'enregistrer ce %{model} : 1 erreur"
- other: "Impossible d'enregistrer ce %{model} : %{count} erreurs"
- body: "Veuillez vérifier les champs suivants : "
-
+ format: Le %{attribute} %{message}
+ messages:
+ inclusion: n'est pas inclus(e) dans la liste
+ exclusion: n'est pas disponible
+ invalid: n'est pas valide
+ confirmation: ne concorde pas avec la confirmation
+ accepted: doit être accepté(e)
+ empty: doit être rempli(e)
+ blank: doit être rempli(e)
+ too_long: est trop long (pas plus de %{count} caractères)
+ too_short: est trop court (au moins %{count} caractères)
+ wrong_length: ne fait pas la bonne longueur (doit comporter %{count} caractères)
+ not_a_number: n'est pas un nombre
+ not_an_integer: doit être un nombre entier
+ greater_than: doit être supérieur à %{count}
+ greater_than_or_equal_to: doit être supérieur ou égal à %{count}
+ equal_to: doit être égal à %{count}
+ less_than: doit être inférieur à %{count}
+ less_than_or_equal_to: doit être inférieur ou égal à %{count}
+ odd: doit être impair
+ even: doit être pair
+ template:
+ header: &73570860
+ one: ! 'Impossible d''enregistrer ce %{model} : 1 erreur'
+ other: ! 'Impossible d''enregistrer ce %{model} : %{count} erreurs'
+ body: ! 'Veuillez vérifier les champs suivants : '
activerecord:
errors:
messages:
- taken: "n'est pas disponible"
- record_invalid: "La validation a échoué : %{errors}"
- <<: *errors_messages
+ inclusion: n'est pas inclus(e) dans la liste
+ exclusion: n'est pas disponible
+ invalid: n'est pas valide
+ confirmation: ne concorde pas avec la confirmation
+ accepted: doit être accepté(e)
+ empty: doit être rempli(e)
+ blank: doit être rempli(e)
+ too_long: est trop long (pas plus de %{count} caractères)
+ too_short: est trop court (au moins %{count} caractères)
+ wrong_length: ne fait pas la bonne longueur (doit comporter %{count} caractères)
+ not_a_number: n'est pas un nombre
+ not_an_integer: doit être un nombre entier
+ greater_than: doit être supérieur à %{count}
+ greater_than_or_equal_to: doit être supérieur ou égal à %{count}
+ equal_to: doit être égal à %{count}
+ less_than: doit être inférieur à %{count}
+ less_than_or_equal_to: doit être inférieur ou égal à %{count}
+ odd: doit être impair
+ even: doit être pair
+ taken: n'est pas disponible
+ record_invalid: ! 'La validation a échoué : %{errors}'
template:
- <<: *errors_template
+ header: *73570860
+ body: ! 'Veuillez vérifier les champs suivants : '
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/fr_fat_free_crm.yml b/config/locales/fr_fat_free_crm.yml
index 6224d8cd85..5da0371020 100644
--- a/config/locales/fr_fat_free_crm.yml
+++ b/config/locales/fr_fat_free_crm.yml
@@ -4,24 +4,18 @@
# Updated by David Keita aka ManInGA
# maninga@gmail.com
+---
fr:
language: Français
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Tous
at: à
here: ici
- no_button: 'Non'
+ no_button: Non
not_implemented: Pas encore implémenté.
or: ou
- select_none: '-- Aucun --'
- select_blank: '-- Sélectionnez --'
- yes_button: 'Oui'
-
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- Aucun --
+ select_blank: -- Sélectionnez --
+ yes_button: Oui
tab_dashboard: Tableau de bord
tab_tasks: Tâches
tab_campaigns: Campagnes
@@ -29,31 +23,26 @@ fr:
tab_accounts: Comptes
tab_contacts: Contacts
tab_opportunities: Opportunités
-
admin_tab_users: Utilisateurs
admin_tab_fields: Champs Personnalisés
admin_tab_tags: Tags
admin_tab_settings: Paramètres
admin_tab_plugins: Plugins
-
affiliate: Affilié
competitor: Concurrent
customer: Client
partner: Partenaire adm
reseller: Revendeur
vendor: Vendeur
-
planned: Planifié
started: Démarré
on_hold: En attente
completed: Complétée
called_off: Abandonné
-
new: Nouvelle
contacted: Contactée
converted: Convertie
rejected: Rejetée
-
cold_call: Appel entrant
conference: Conférence
online: Marketing web
@@ -62,7 +51,6 @@ fr:
web: Website
word_of_mouth: Bouche à oreille
other: Autre
-
prospecting: Prospection
analysis: Analyse
presentation: Présentation
@@ -71,138 +59,127 @@ fr:
final_review: Examen final
won: Clôturée/Gagnée
lost: Clôturée/Perdue
-
call: Appel
email: E-mail
follow_up: Suivi
lunch: Dîner
meeting: Réunion
money: Finance
- presentation: Présentation
trip: Voyage
-
overdue: Délai expiré
due_asap: Dès que possible
- due_today: "Aujourd'hui"
+ due_today: Aujourd'hui
due_tomorrow: Demain
due_this_week: Cette semaine
due_next_week: La semaine prochaine
due_later: Plus tard
due_specific_date: A la date précise...
-
- completed_today: "Ajourd'hui"
+ completed_today: Ajourd'hui
completed_yesterday: Hier
completed_last_week: La semaine dernière
completed_this_month: Ce mois
completed_last_month: Le mois dernier
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: Une heure
one_day: Un jour
two_days: Deux jours
one_week: Une semaine
two_weeks: Deux semaines
one_month: Un mois
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
authentication:
attributes:
login_field:
- is_not_valid: "n'est pas valide"
+ is_not_valid: n'est pas valide
password_field:
- is_not_valid: "n'est pas valide"
+ is_not_valid: n'est pas valide
account:
attributes:
name:
- missing_account_name: "^Vérifiez le nom de compte."
+ missing_account_name: ^Vérifiez le nom de compte.
access:
- share_account: "^Spécifiez un utilisateur avec qui partager le compte."
+ share_account: ^Spécifiez un utilisateur avec qui partager le compte.
campaign:
attributes:
name:
- missing_campaign_name: "^Précisez un nom de campagne."
+ missing_campaign_name: ^Précisez un nom de campagne.
ends_on:
- dates_not_in_sequence: "^Vérifiez que la date de fin de campagne soit avant la date de début."
+ dates_not_in_sequence: ^Vérifiez que la date de fin de campagne soit
+ avant la date de début.
access:
- share_campaign: "^Préciser un utilisateur avec qui partager la campagne."
+ share_campaign: ^Préciser un utilisateur avec qui partager la campagne.
contact:
attributes:
first_name:
- missing_first_name: "^Précisez le prénom"
+ missing_first_name: ^Précisez le prénom
last_name:
- missing_last_name: "^Précisez le nom."
+ missing_last_name: ^Précisez le nom.
access:
- share_contact: "^Précisez avec quel utilisateur partager le contact."
+ share_contact: ^Précisez avec quel utilisateur partager le contact.
lead:
attributes:
first_name:
- missing_first_name: "^Précisez le prénom"
+ missing_first_name: ^Précisez le prénom
last_name:
- missing_last_name: "^Précisez le nom."
+ missing_last_name: ^Précisez le nom.
access:
- share_lead: "^Précisez avec quel utilisateur partager la piste."
+ share_lead: ^Précisez avec quel utilisateur partager la piste.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Spécifiez un nom d'opportunité."
+ missing_opportunity_name: ^Spécifiez un nom d'opportunité.
access:
- share_opportunity: "^Précisez avec quel utilisateur partager l'opportunité."
+ share_opportunity: ^Précisez avec quel utilisateur partager l'opportunité.
task:
attributes:
name:
- missing_task_name: "^Précisez le nom de la tâche."
+ missing_task_name: ^Précisez le nom de la tâche.
calendar:
- invalid_date: "^Précisez une date valide"
+ invalid_date: ^Précisez une date valide
user:
attributes:
username:
- missing_username: "^Précisez un nom d'utilisateur."
- username_taken: "^Ce nom d'utilisateur est déjà pris"
+ missing_username: ^Précisez un nom d'utilisateur.
+ username_taken: ^Ce nom d'utilisateur est déjà pris
email:
- missing_email: "^Précisez une adresse e-mail"
- email_in_use: "^Un utilisateur existe déjà avec cette adresse."
-
+ missing_email: ^Précisez une adresse e-mail
+ email_in_use: ^Un utilisateur existe déjà avec cette adresse.
msg_account_suspended: Ce compte utilisateur a été suspendu.
password_reset_instruction: instructions de réinitialisation du mot de passe
-
- # Controllers.
- #----------------------------------------------------------------------------
- msg_account_created: "Votre compte a été créé, il est en attente d'approbation par l'administrateur"
- msg_account_not_approved: "Votre compte n'à pas encore été approuvé"
- msg_asset_deleted: "%{value} à été supprimé"
- msg_asset_not_available: "Ce %{value} n'est plus disponible."
- msg_asset_not_authorized: "Vous n'êtes pas autorisé à accéder à ce/cette %{value}."
- msg_assets_not_available: "Les %{value} ne sont pas disponibles."
- msg_asset_rejected: "%{value} à été rejetée."
- msg_bad_image_file: "^Nous n'avons pas pu télécharger ou redimensionner votre image."
- msg_cant_create_related: "Impossible de crée le %{asset} puisque le %{related} n'est plus disponnible."
- msg_cant_delete_user: "^Impossible de supprimer l'utilisateur car %{value} a des objets liés encore présents."
- msg_cant_do: "Impossible de %{action} le %{asset} puisqu'il n'est plus disponible."
- msg_email_not_found: "Aucun utilisateur ne correspond a cette adresse"
+ msg_account_created: Votre compte a été créé, il est en attente d'approbation par
+ l'administrateur
+ msg_account_not_approved: Votre compte n'à pas encore été approuvé
+ msg_asset_deleted: ! '%{value} à été supprimé'
+ msg_asset_not_available: Ce %{value} n'est plus disponible.
+ msg_asset_not_authorized: Vous n'êtes pas autorisé à accéder à ce/cette %{value}.
+ msg_assets_not_available: Les %{value} ne sont pas disponibles.
+ msg_asset_rejected: ! '%{value} à été rejetée.'
+ msg_bad_image_file: ^Nous n'avons pas pu télécharger ou redimensionner votre image.
+ msg_cant_create_related: Impossible de crée le %{asset} puisque le %{related} n'est
+ plus disponnible.
+ msg_cant_delete_user: ^Impossible de supprimer l'utilisateur car %{value} a des
+ objets liés encore présents.
+ msg_cant_do: Impossible de %{action} le %{asset} puisqu'il n'est plus disponible.
+ msg_email_not_found: Aucun utilisateur ne correspond a cette adresse
msg_enter_new_password: Saisissez votre nouveau mot de passe.
- msg_goodbye: "Vous avez été déconnecté, merci d'utiliser Fat Free CRM!"
- msg_invalid_password: "^Saisissez votre mot de passe actuel"
+ msg_goodbye: Vous avez été déconnecté, merci d'utiliser Fat Free CRM!
+ msg_invalid_password: ^Saisissez votre mot de passe actuel
msg_invalig_login: Utilisateur ou mot de passe non valide.
- msg_last_login: "Votre dernière connection était le %{value}."
+ msg_last_login: Votre dernière connection était le %{value}.
msg_login_needed: Vous devez être connecté pour accéder a cette page.
msg_logout_needed: Vous devez être déconnecté pour accéder a cette page.
- msg_password_changed: "Votre mot de passe a été modifié"
- msg_password_not_changed: "Votre mot de passe n'a pas été modifié"
+ msg_password_changed: Votre mot de passe a été modifié
+ msg_password_not_changed: Votre mot de passe n'a pas été modifié
msg_password_updated: Modification de mot de passe réussie.
- msg_pwd_instructions_sent: "Les instruction de modification de mot de passe vous on été envoyées. Vérifiez vos e-mails"
+ msg_pwd_instructions_sent: Les instruction de modification de mot de passe vous
+ on été envoyées. Vérifiez vos e-mails
msg_require_admin: Vous devez être administrateur pour accéder a cette page
msg_successful_signup: Enregistrement réussi. Bienvenu dans Fat Free CRM
- msg_welcome: Bienvenue dans Fat Free CRM
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": Montant pondéré
- activity_options: Voir les %{action_type} %{models} effectuées par %{user} dans les derniers %{period}.
+ msg_welcome: Bienvenue dans Fat Free CRM
+ option_amount*probability: Montant pondéré
+ activity_options: Voir les %{action_type} %{models} effectuées par %{user} dans
+ les derniers %{period}.
all_users: tous les utilisateurs
option_after: après
option_all: tous
@@ -228,10 +205,8 @@ fr:
option_updated_at: date de modification
show_per_page: Voir %{number} %{models} par page au format %{fmt}.
sort_by: Trier les %{models} par %{field}.
- sort_by_displaying: Trier les %{models} par %{field} et afficher le prénom %{position} le nom.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Trier les %{models} par %{field} et afficher le prénom %{position}
+ le nom.
aim: AOL IM
already_signed_up: Déjà inscrit?
alt_email: e-mail secondaire
@@ -241,12 +216,12 @@ fr:
contact_info: Informations de contact
current_password: Mot de passe actuel
edit_profile: Modifier le profil
- # email: E-mail # <-- Already defined as the task type if Settings.
first_name: Prénom
google: Google IM
gravatar_help: Vous ne connaissez pas Gravatar? Informations sur Gravatar
image_file: Fichier image
- image_help: "L'image que vous envoyez sera redimensionnée à 75 x 75 pixels. Les formats supportés sont GIF, JPEG et PNG."
+ image_help: L'image que vous envoyez sera redimensionnée à 75 x 75 pixels. Les formats
+ supportés sont GIF, JPEG et PNG.
job_title: Titre/Fonction
last_name: Nom
login_now_link: Connectez vous maintenant!
@@ -265,19 +240,13 @@ fr:
upload_picture: Envoyez une image
use_gravatar: Utilisez Gravatar
user: Utilisateur
- username: "Nom d'utilisateur"
+ username: Nom d'utilisateur
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Mot de passe oublié
login: Se connecter
- no_account: "Vous n'avez pas de compte?"
+ no_account: Vous n'avez pas de compte?
remember_me: Se souvenir de moi
- sign_up_now: "Créez le maintenant!"
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
+ sign_up_now: Créez le maintenant!
account: Compte
select_an_account: Sélectionner un compte
account_small: compte
@@ -306,9 +275,6 @@ fr:
shipping_address: Adresse de livraison
total_accounts: Total des comptes
website: Site web
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Etat actuel
actual_performance: Performance Actuelle
budget: Budget
@@ -323,7 +289,7 @@ fr:
campaigns_small: campagnes
conversion: Conversion
conversion_label: Conversion (%)
- conversion_number: "%{value} de conversion"
+ conversion_number: ! '%{value} de conversion'
create_campaign: Créer une Campagne
end_date: Date de fin
finished_on: terminée le %{value}
@@ -331,24 +297,22 @@ fr:
no_start_date: pas de date de début spécifiée
number_of_leads: Nombre de pistes
objectives: Objectifs
- objectives_help: "Spécifiez un objectif en nombre de pistes, taux de conversion de pistes/opportunités, revenu espéré et budget. Ces valeurs seront utilisées lors de l'évaluation des performances de la campagne"
+ objectives_help: Spécifiez un objectif en nombre de pistes, taux de conversion de
+ pistes/opportunités, revenu espéré et budget. Ces valeurs seront utilisées lors
+ de l'évaluation des performances de la campagne
objectives_small: objectifs de la campagne
revenue: Revenu
revenue_label: Revenu (€)
- revenue_number: "%{value} pour revenu"
+ revenue_number: ! '%{value} pour revenu'
save_campaign: Enregistrer la campagne
start_date: Date de début
started_ago: démarré il y a %{value}
starts_in: démarré dans %{value}
- starts_today: "démarre aujourd'hui!"
+ starts_today: démarre aujourd'hui!
target: Prévisionnel
total_campaigns: Total des Campagnes
was_supposed_to_finish: présumée se terminer le %{value}
was_supposed_to_start: était supposée démarrer il y a %{time_ago} le %{start_date}
- #was_supposed_to_start_in: was supposed to start in %{starts_in} on %{start_date} # Not in use in the project
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Autre
blog: Site Web/Blog
contact: Contact
@@ -358,38 +322,47 @@ fr:
contacts_small: contacts
create_contact: Créer un Contact
department: Département
- department_small: 'département %{value} '
+ department_small: ! 'département %{value} '
do_not_call: ne pas appeler
extra_info: Informations supplémentaires
extra_info_small: infos supplémentaires
facebook: Facebook
linked_in: LinkedIn
myself: Moi-même
- permissions_intro_private: Par défaut vous seul aurez accès à %{value}. Vous pouvez modifier les permissions ultérieurement.
- permissions_intro_public: Par défaut tous les utilisateurs auront accès à %{value}. Vous pouvez modifier les permissions ultérieurement.
- permissions_intro_shared: Par défaut seul les utilisateurs sélectionnés auront accès à %{value}. Vous pouvez modifier les permissions ultérieurement.
+ permissions_intro_private: Par défaut vous seul aurez accès à %{value}. Vous pouvez
+ modifier les permissions ultérieurement.
+ permissions_intro_public: Par défaut tous les utilisateurs auront accès à %{value}.
+ Vous pouvez modifier les permissions ultérieurement.
+ permissions_intro_shared: Par défaut seul les utilisateurs sélectionnés auront accès
+ à %{value}. Vous pouvez modifier les permissions ultérieurement.
referred_by: Référencé par
referred_by_small: référence par
save_contact: Enregistrer le contact
- skype: Skype
twitter: Twitter
web_presence: Présence Web
- web_presence_small: présence web
- works_at: "%{job_title} chez %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ web_presence_small: présence web
+ works_at: ! '%{job_title} chez %{company}'
convert: Convertir
convert_lead: Convertir la piste
- convert_lead_permissions_intro: Les permissions du contact seront dupliquées depuis la piste. Vous pouvez modifier les permissions du contact ultérieurement.
- convert_lead_text: En convertissant la piste %{value} il/elle deviendra un contact associé à un compte existant ou nouvellement créé. Le statut de la piste sera automatiquement positionné à converti.
+ convert_lead_permissions_intro: Les permissions du contact seront dupliquées depuis
+ la piste. Vous pouvez modifier les permissions du contact ultérieurement.
+ convert_lead_text: En convertissant la piste %{value} il/elle deviendra un contact
+ associé à un compte existant ou nouvellement créé. Le statut de la piste sera
+ automatiquement positionné à converti.
create_lead: Créer une piste
- create_opp_for_contact: "Vous pouvez éventuellement créer une opportunité pour le contact %{value} en spécifiant le nom, l'étape courante, la date de clôture estimée, la probabilité de vente, le montant de l'affaire, la remise offerte."
+ create_opp_for_contact: Vous pouvez éventuellement créer une opportunité pour le
+ contact %{value} en spécifiant le nom, l'étape courante, la date de clôture estimée,
+ la probabilité de vente, le montant de l'affaire, la remise offerte.
lead: Piste
lead_info_small: contact de la piste
- lead_permissions_intro_private: Par défaut les permissions seront dupliquée depuis la campagne ou positionnées sur privé. Vous pouvez modifier les permissions ultérieurement.
- lead_permissions_intro_public: Par défaut les permissions seront dupliquée depuis la campagne ou positionnées sur publique. Vous pouvez modifier les permissions ultérieurement.
- lead_permissions_intro_shared: Par défaut les permissions seront dupliquée depuis la campagne ou partagées avec les utilisateurs spécifiés. Vous pouvez modifier les permissions ultérieurement.
+ lead_permissions_intro_private: Par défaut les permissions seront dupliquée depuis
+ la campagne ou positionnées sur privé. Vous pouvez modifier les permissions ultérieurement.
+ lead_permissions_intro_public: Par défaut les permissions seront dupliquée depuis
+ la campagne ou positionnées sur publique. Vous pouvez modifier les permissions
+ ultérieurement.
+ lead_permissions_intro_shared: Par défaut les permissions seront dupliquée depuis
+ la campagne ou partagées avec les utilisateurs spécifiés. Vous pouvez modifier
+ les permissions ultérieurement.
lead_small: piste
lead_status_small: statut de la piste
lead_summary: Résumé de la piste
@@ -404,13 +377,10 @@ fr:
source: Source
status: Statut
total_leads: Total des pistes
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Montant
close_date: Date de clôture
closed_ago_on: clôturé il y à %{time_ago} le %{date}
- closes_today: "doit être clôturé aujourd'hui!"
+ closes_today: doit être clôturé aujourd'hui!
closing_date: la date de clôture est %{value}
create_opportunity: Créer une opportunité
currency: (€)
@@ -427,18 +397,16 @@ fr:
opportunities_small: opportunités
opportunity: Opportunité
opportunity_small: opportunité
- opportunity_summary: "Coup d'oeil sur l'opportunité"
- opportunity_summary_text: "%{amount} avec %{discount} de remise et %{probability} de probabilité"
+ opportunity_summary: Coup d'oeil sur l'opportunité
+ opportunity_summary_text: ! '%{amount} avec %{discount} de remise et %{probability}
+ de probabilité'
past_due: en retard, devait être clôturé il y a %{value}
probability: Probabilité
probability_number: et %{value} de probabilité
- save_opportunity: "Enregistrer l'opportunité"
+ save_opportunity: Enregistrer l'opportunité
stage: Etape
total_opportunities: Total des opportunités
weighted_amount: Montant pondéré
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
task: Tâche
task_small: tâche
tasks: Tâches
@@ -454,13 +422,13 @@ fr:
due: A faire
feel_free: N'hésitez pas à
move_to: aller à
- no_tasks: "Vous n'avez aucune tâche %{value}"
+ no_tasks: Vous n'avez aucune tâche %{value}
no_tasks_pending: en attente
no_tasks_assigned: assignée
no_tasks_completed: complétée
pending_tab: En attente
pending_tasks: Tâches en attente
- related: 're:'
+ related: ! 're:'
save_task: Enregistrer la tâche
task_assigned: La tâche à été assignée à %{value}
task_assigned_to: et assignée à %{value}
@@ -471,16 +439,13 @@ fr:
task_due_in: échéance dans %{value}
task_due_later: à faire bientôt
task_due_now: à faire maintenant
- task_due_today: "à faire aujourd'hui"
+ task_due_today: à faire aujourd'hui
task_from: De %{value}
task_overdue: en retard, échéance prévue le
task_pending: La tâche à été mise en attente
total_tasks: Total des %{value}
view_assigned_tasks: voir les tâches assignées
view_pending_tasks: voir les tâches en attente
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: a commenté le/la
action_completed: a complété le/la
action_created: a créé le/la
@@ -502,16 +467,13 @@ fr:
subject_lead: piste
subject_opportunity: opportunité
subject_task: tâche
- created_past_participle: "Création d'enregistrements"
+ created_past_participle: Création d'enregistrements
commented_past_participle: Commentaires
viewed_past_participle: Consultations
updated_past_participle: Modifications
deleted_past_participle: Supressions
email_past_participle: Emails
all_events_past_participle: Activités
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Ajouter une note
save_note: Enregistrer la note
add_note_help: Ajouter une nouvelle note...
@@ -521,24 +483,24 @@ fr:
back: Retour
cancel: Annuler
close_form: Fermer le formulaire
- confirm_delete: "Êtes-vous certain de vouloir supprimer ceci : %{value}?"
+ confirm_delete: ! 'Êtes-vous certain de vouloir supprimer ceci : %{value}?'
copy_permissions: Copier les permissions de %{value}
- could_not_find: "Aucun(e) %{value} n'a été trouvé(e). N'hésitez pas à "
- could_not_find_matching: "Aucun(e) %{value} n'a été trouvé(e) correspondant à"
+ could_not_find: ! 'Aucun(e) %{value} n''a été trouvé(e). N''hésitez pas à '
+ could_not_find_matching: Aucun(e) %{value} n'a été trouvé(e) correspondant à
create_new: créer un(e)
create_a_new: créer un(e)
select_existing: sélectionnez un(e)
delete: Supprimer
discard: Abandonner
edit: Modifier
- items_total: '%{count} total.'
+ items_total: ! '%{count} total.'
less: Moins...
me: moi
more: Plus...
n_a: N/R
name: Nom
no_match: Aucun(e) %{value} ne correspond
- no_recent_items: "Il n'y rien de récent à afficher pour l'instant."
+ no_recent_items: Il n'y rien de récent à afficher pour l'instant.
options: Options
permissions: Permissions
please_retry: essayez une autre requête.
@@ -548,11 +510,11 @@ fr:
select_task: Choisir une tâche
select_opportunity: Choisir une opportunité
search_assets: Recherche de %{value}
- time_ago: "il y a %{value}"
+ time_ago: il y a %{value}
background_info: Informations
address: Adresse
- street1: Rue 1 # NEW
- street2: Rue 2 # NEW
+ street1: Rue 1
+ street2: Rue 2
city: Ville
zipcode: Code postal
state: Région
@@ -562,35 +524,31 @@ fr:
collapse_all: Tout replier
expanded: déplier
collapsed: replier
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: A propos
about_dev_group: Groupe de discussion pour les développeurs
about_features: Fonctionnalités et bugs
about_ffc: A propos de Fat Free CRM
about_ffc_resources: Ressources pour Fat Free CRM (Nouvelle fenêtre)
about_ffc_version: version de Fat Free CRM
- about_home_page: "Page d'accueil"
+ about_home_page: Page d'accueil
about_project_page: Page du projet
- about_thank_you: "Merci d'utiliser Fat Free CRM!"
+ about_thank_you: Merci d'utiliser Fat Free CRM!
about_twitter: mises à jours sur Twitter
about_user_group: Groupe de discussion pour les utilisateurs
admin: Administration
logout: Se déconnecter
quick_find: Recherche rapide
welcome: Bienvenue
-
- # Views -> Advanced Search.
accounts_advanced_search: Recherche avancée des comptes
advanced_search: Recherche avancée
advanced_search_submit: Rechercher
advanced_search_add_group: Ajouter un groupe de filtres
- advanced_search_group_first: Afficher les enregistrement quand %{combinator} du/des critère(s) suivant(s) correspond(ent)
- advanced_search_group_rest: ...et quand %{combinator} du/des critère(s) suivant(s) correspond(ent)
+ advanced_search_group_first: Afficher les enregistrement quand %{combinator} du/des
+ critère(s) suivant(s) correspond(ent)
+ advanced_search_group_rest: ! '...et quand %{combinator} du/des critère(s) suivant(s)
+ correspond(ent)'
advanced_search_add_condition: Ajouter un filtre
advanced_search_remove_condition: Supprimer un filtre
-
ransack:
predicates:
eq: est égal à
@@ -603,139 +561,101 @@ fr:
not_cont: ne contient pas
blank: est vide
present: est présent
- "null": est nul
+ 'null': est nul
not_null: est non nul
-
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Edition de commentaire
show: Voir
update: Modifier
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Saisissez votre nouveau mot de passe et sa confirmation.
- password_intro: Précisez votre adresse e-mail, et les instructions pour les réinitialiser vous seront communiquées.
+ password_intro: Précisez votre adresse e-mail, et les instructions pour les réinitialiser
+ vous seront communiquées.
reset_password: Ré-initialisation du mot de passe
- update_password_and_login: "Modification de l'identifiant et du mot de passe"
-
- # Views -> Admin
- #----------------------------------------------------------------------------
+ update_password_and_login: Modification de l'identifiant et du mot de passe
back_to_crm: Retour à Fat Free CRM
crm_admin_page: Administration de Fat Free CRM
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Approuver
create_user: Créer un utilisateur
last_seen: vu pour la dernière fois il y a %{value}
personal_information: Informations complémentaires
reactivate: Réactiver
- save_user: "Enregistrer l'utilisateur"
+ save_user: Enregistrer l'utilisateur
suspend: Suspendre
user_active: Actif
user_admin: Admin
user_awaits_approval: en attente de votre approbation
- user_confirm_delete: Un utilisateur ne peut être supprimé que si aucun objet lui appartenant existent toujours.
- user_is_admin: "L'utilisateur est administrateur"
- user_never_logged_in: "ne s'est pas encore connecté"
+ user_confirm_delete: Un utilisateur ne peut être supprimé que si aucun objet lui
+ appartenant existent toujours.
+ user_is_admin: L'utilisateur est administrateur
+ user_never_logged_in: ne s'est pas encore connecté
user_signed_up: est enregistré
- user_signed_up_on: "s'est enregistré le %{value}"
+ user_signed_up_on: s'est enregistré le %{value}
user_since: utilisateur depuis le %{value}
user_suspended: Suspendu
user_suspended_on: suspendu le %{value}
users: Utilisateurs
users_small: utilisateurs
-
- # Views -> Versions
- #----------------------------------------------------------------------------
versions: Historique
version:
create: Créé par %{by} il y a %{item}.
update: Modifié par %{by} il y a %{item}.
destroy: Détruit par %{by} il y a %{item}.
- set: %{attr} renseigné %{to}
- unset: %{attr} supprimé
- change: %{attr} changé de %{from} à %{to}
+ set: ! '%{attr} renseigné %{to}'
+ unset: ! '%{attr} supprimé'
+ change: ! '%{attr} changé de %{from} à %{to}'
anonymous: anonyme
-
- # Export.
- #----------------------------------------------------------------------------
to_xls: Exporter au format Excel
to_csv: Exporter au format CSV (enregistrements supprimés inclus)
to_rss: fil RSS
to_atom: fil Atom
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - Email ajouté - %{subject}
- dropbox_notification_intro: "a ajouté l'email que vous avez envoyé à la dropbox"
+ dropbox_notification_intro: a ajouté l'email que vous avez envoyé à la dropbox
dropbox_notification_to: ajoutés aux
subject: Sujet
body: Corps
-
- # Lists
- #----------------------------------------------------------------------------
lists: Listes
list: Liste
no_saved_lists: Liste non sauvegardée
make_current_view_list: Faire de la vue courante une liste
- list_name_info: Si vous utilisez le nom d'une liste existante vous écraserez cette liste avec vos paramètres courants
-
- # Pluralizations.
- #----------------------------------------------------------------------------
+ list_name_info: Si vous utilisez le nom d'une liste existante vous écraserez cette
+ liste avec vos paramètres courants
pluralize:
comment:
- one: '1 commentaire'
- other: '%{count} commentaires'
+ one: 1 commentaire
+ other: ! '%{count} commentaires'
contact:
- one: '1 contact'
- other: '%{count} contacts'
+ one: 1 contact
+ other: ! '%{count} contacts'
opportunity:
- one: '1 opportunité'
- other: '%{count} opportunités'
+ one: 1 opportunité
+ other: ! '%{count} opportunités'
lead:
- one: '1 piste'
- other: '%{count} pistes'
+ one: 1 piste
+ other: ! '%{count} pistes'
day:
- one: '1 jour'
- other: '%{count} jours'
+ one: 1 jour
+ other: ! '%{count} jours'
login:
- one: '1 identifiant'
- other: '%{count} identifiants'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 identifiant
+ other: ! '%{count} identifiants'
date:
formats:
- mmddyyyy: "%d/%m/%Y"
- mmdd: "%e %b"
- mmddyy: "%e %b %Y"
-
+ mmddyyyy: ! '%d/%m/%Y'
+ mmdd: ! '%e %b'
+ mmddyy: ! '%e %b %Y'
time:
formats:
- mmddhhss: "%b %e à %H:%M%"
- mmddyyyy_hhmm: "%d/%m/%Y à %H:%M"
-
- # will_paginate translations copied for 'fr'
- #----------------------------------------------------------------------------
+ mmddhhss: ! '%b %e à %H:%M%'
+ mmddyyyy_hhmm: ! '%d/%m/%Y à %H:%M'
will_paginate:
- previous_label: "← Précédent"
- next_label: "Suivant →"
- page_gap: "…"
-
+ previous_label: ! '← Précédent'
+ next_label: Suivant →
+ page_gap: ! '…'
page_entries_info:
single_page:
- zero: "Aucun(e) %{name} trouvé"
- one: "Affichage de 1 %{name}"
- other: "Affichage de %{count} %{plural}"
-
- multi_page: "Affichage des %{plural} %{from} à %{to} de %{total} au total"
-
-
- # Views -> Admin -> Custom Fields
- #----------------------------------------------------------------------------
+ zero: Aucun(e) %{name} trouvé
+ one: Affichage de 1 %{name}
+ other: Affichage de %{count} %{plural}
+ multi_page: Affichage des %{plural} %{from} à %{to} de %{total} au total
label: Etiquette
custom_fields: Champs personnalisés
custom_field_options: Options des champs personnalisés
@@ -744,94 +664,71 @@ fr:
create_field_group: Créer une section (groupe de champs)
edit_field_group: Editer la section
save_field_group: enregistrer la section
-
- field_group_empty: "Il n'y a aucun champ dans cette section"
-
- select_or_create_tags: "Sélectionner un tag ou créez un nouveau tag en validant par la touche entrée."
-
+ field_group_empty: Il n'y a aucun champ dans cette section
+ select_or_create_tags: Sélectionner un tag ou créez un nouveau tag en validant par
+ la touche entrée.
restrict_by_tag: Restriction par tag
- restrict_by_tag_info: Cette section ne sera visible que pour les %{assets} qui seront taggé(e)s"
- field_group_tag_restriction: Cette section est visible pour les %{assets} qui sont taggé(e)s "%{tag}"
- field_group_unrestricted: "Cette section est visible pour l'ensemble des %{assets}"
- field_group_confirm_delete: Quand une section est supprimée, tous les champs personnalisés sont déplacés vers la section par défaut.
+ restrict_by_tag_info: Cette section ne sera visible que pour les %{assets} qui seront
+ taggé(e)s"
+ field_group_tag_restriction: Cette section est visible pour les %{assets} qui sont
+ taggé(e)s "%{tag}"
+ field_group_unrestricted: Cette section est visible pour l'ensemble des %{assets}
+ field_group_confirm_delete: Quand une section est supprimée, tous les champs personnalisés
+ sont déplacés vers la section par défaut.
msg_cant_delete_field_group: Cette section ne peut pas être supprimée.
+ admin_fields_info: ! 'Les champs personnalisés sont affichés dans des sections.
- admin_fields_info: |
- Les champs personnalisés sont affichés dans des sections.
- Créez d'abord une nouvelle section, ou ajoutez les champs dans une section existante ci-dessous.
- Vous pouvez faire glisser les champs pour ordonner leur présentation ou les faire changer de section.
+ Créez d''abord une nouvelle section, ou ajoutez les champs dans une section existante
+ ci-dessous.
- # Views -> Admin -> Tags
- #----------------------------------------------------------------------------
+ Vous pouvez faire glisser les champs pour ordonner leur présentation ou les faire
+ changer de section.
+
+'
tags: Tags
tag_small: tag
tagged: taggé(es)
create_tag: Créer un tag
save_tag: Enregistrer le tag
field_group_tags: Sections visibles pour ce tag
- tag_with_taggings_confirm_delete: "En supprimant ce tag, il sera supprimé de %{value} enregistrements."
- msg_cant_delete_tag: "Impossible de supprimer '%{value}' car il est associé à au moins une section."
-
-
- # Views -> Admin -> Plugins
- #----------------------------------------------------------------------------
+ tag_with_taggings_confirm_delete: En supprimant ce tag, il sera supprimé de %{value}
+ enregistrements.
+ msg_cant_delete_tag: Impossible de supprimer '%{value}' car il est associé à au
+ moins une section.
views:
admin:
plugins:
author: Auteur
version: Version
description: Description
-
- # Simple Form translations
- #----------------------------------------------------------------------------
simple_form:
- "yes": 'Oui'
- "no": 'Non'
+ 'yes': Oui
+ 'no': Non
required:
- text: 'required'
- mark: '*'
- # You can uncomment the line below if you need to overwrite the whole required html.
- # When using html, text and mark won't be used.
- # html: '* '
+ text: required
+ mark: ! '*'
error_notification:
- default_message: "Votre demande ne peut aboutir, les erreurs suivantes se sont déclenchées:"
- # Labels and hints examples
- # labels:
- # password: 'Password'
- # user:
- # new:
- # email: 'E-mail para efetuar o sign in.'
- # edit:
- # email: 'E-mail.'
- # hints:
- # username: 'User name to sign in.'
- # password: 'No special characters, please.'
-
-
- # Form field types
- #----------------------------------------------------------------------------
+ default_message: ! 'Votre demande ne peut aboutir, les erreurs suivantes se
+ sont déclenchées:'
field_types:
- string: Texte court
- text: Texte long
- select: Liste de sélection
+ string: Texte court
+ text: Texte long
+ select: Liste de sélection
multiselect: Liste de sélection (multiple)
- radio: Boutons radios
- boolean: Case à cocher
+ radio: Boutons radios
+ boolean: Case à cocher
check_boxes: Liste de cases à cocher
- date: Date
- datetime: Date et heure
- email: Adresse email
- url: URL
- tel: Numéro de téléphone
- decimal: Nombre décimal
- integer: Nombre entier
- float: Nombre flottant
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ date: Date
+ datetime: Date et heure
+ email: Adresse email
+ url: URL
+ tel: Numéro de téléphone
+ decimal: Nombre décimal
+ integer: Nombre entier
+ float: Nombre flottant
errors:
template:
header:
- one: "Impossible d'enregistrer ce %{model} : 1 erreur"
- other: "Impossible d'enregistrer ce %{model} : %{count} erreurs"
- body: "Veuillez vérifier les champs suivants : "
+ one: ! 'Impossible d''enregistrer ce %{model} : 1 erreur'
+ other: ! 'Impossible d''enregistrer ce %{model} : %{count} erreurs'
+ body: ! 'Veuillez vérifier les champs suivants : '
diff --git a/config/locales/it.yml b/config/locales/it.yml
index f7470848fc..4b496461b5 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -1,183 +1,219 @@
-# IT translations for Ruby on Rails
-#
-# Use this as the base for the locale file of your language.
-
-"it":
+---
+it:
date:
formats:
- default: "%Y-%m-%d"
- short: "%b %d"
- long: "%B %d, %Y"
-
- day_names: [Domenica, Lunedi', Martedi', Mercoledi', Giovedi', Venerdi', Sabato]
- abbr_day_names: [Dom, Lun, Mar, Mer, Gio, Ven, Sab]
-
- month_names: [~, Gennaio, Febbraio, Marzo, Aprile, Maggio, Giugno, Luglio, Agosto, Settembre, Ottobre, Novembre, Dicembre]
- abbr_month_names: [~, Gen, Feb, Mar, Apr, Mag, Giu, Lug, Aug, Set, Ott, Nov, Dic]
+ default: ! '%Y-%m-%d'
+ short: ! '%b %d'
+ long: ! '%B %d, %Y'
+ day_names:
+ - Domenica
+ - Lunedi'
+ - Martedi'
+ - Mercoledi'
+ - Giovedi'
+ - Venerdi'
+ - Sabato
+ abbr_day_names:
+ - Dom
+ - Lun
+ - Mar
+ - Mer
+ - Gio
+ - Ven
+ - Sab
+ month_names:
+ -
+ - Gennaio
+ - Febbraio
+ - Marzo
+ - Aprile
+ - Maggio
+ - Giugno
+ - Luglio
+ - Agosto
+ - Settembre
+ - Ottobre
+ - Novembre
+ - Dicembre
+ abbr_month_names:
+ -
+ - Gen
+ - Feb
+ - Mar
+ - Apr
+ - Mag
+ - Giu
+ - Lug
+ - Aug
+ - Set
+ - Ott
+ - Nov
+ - Dic
order:
- - :year
- - :month
- - :day
-
+ - :year
+ - :month
+ - :day
time:
formats:
- default: "%a, %d %b %Y %H:%M:%S %z"
- short: "%d %b %H:%M"
- long: "%B %d, %Y %H:%M"
- am: "am"
- pm: "pm"
-
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ short: ! '%d %b %H:%M'
+ long: ! '%B %d, %Y %H:%M'
+ am: am
+ pm: pm
support:
array:
- words_connector: ", "
- two_words_connector: " e "
- last_word_connector: ", e "
-
+ words_connector: ! ', '
+ two_words_connector: ! ' e '
+ last_word_connector: ! ', e '
select:
- prompt: "Per favore selezionare"
-
+ prompt: Per favore selezionare
number:
format:
- separator: "."
- delimiter: ","
+ separator: .
+ delimiter: ! ','
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: "%u%n"
- unit: "$"
- separator: "."
- delimiter: ","
+ format: ! '%u%n'
+ unit: $
+ separator: .
+ delimiter: ! ','
precision: 2
significant: false
strip_insignificant_zeros: false
-
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
+ unit: ''
thousand: Migliaia
million: Milioni
billion: Miliardi
trillion: Biliardi
quadrillion: Triliardi
-
datetime:
distance_in_words:
- half_a_minute: "mezzo minuto"
+ half_a_minute: mezzo minuto
less_than_x_seconds:
- one: "meno di 1 secondo"
- other: "meno di %{count} secondi"
+ one: meno di 1 secondo
+ other: meno di %{count} secondi
x_seconds:
- one: "1 secondo"
- other: "%{count} secondi"
+ one: 1 secondo
+ other: ! '%{count} secondi'
less_than_x_minutes:
- one: "meno di un minuto"
- other: "meno di %{count} minuti"
+ one: meno di un minuto
+ other: meno di %{count} minuti
x_minutes:
- one: "1 minuto"
- other: "%{count} minuti"
+ one: 1 minuto
+ other: ! '%{count} minuti'
about_x_hours:
- one: "circa 1 ora"
- other: "circa %{count} ore"
+ one: circa 1 ora
+ other: circa %{count} ore
x_days:
- one: "1 giorno"
- other: "%{count} giorni"
+ one: 1 giorno
+ other: ! '%{count} giorni'
about_x_months:
- one: "circa 1 mese"
- other: "circa %{count} mesi"
+ one: circa 1 mese
+ other: circa %{count} mesi
x_months:
- one: "1 mese"
- other: "%{count} mesi"
+ one: 1 mese
+ other: ! '%{count} mesi'
about_x_years:
- one: "circa 1 anno"
- other: "circa %{count} anni"
+ one: circa 1 anno
+ other: circa %{count} anni
over_x_years:
- one: "oltre 1 anno"
- other: "oltre %{count} anni"
+ one: oltre 1 anno
+ other: oltre %{count} anni
almost_x_years:
- one: "quasi 1 anno"
- other: "quasi %{count} anni"
+ one: quasi 1 anno
+ other: quasi %{count} anni
prompts:
- year: "Anno"
- month: "Mese"
- day: "Giorno"
- hour: "Ora"
- minute: "Minuto"
- second: "Secondo"
-
+ year: Anno
+ month: Mese
+ day: Giorno
+ hour: Ora
+ minute: Minuto
+ second: Secondo
helpers:
select:
- prompt: "Per favore selezionare"
-
+ prompt: Per favore selezionare
submit:
- create: 'Creato %{model}'
- update: 'Aggiornato %{model}'
- submit: 'Salvato %{model}'
-
+ create: Creato %{model}
+ update: Aggiornato %{model}
+ submit: Salvato %{model}
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "non incluso nell'elenco"
- exclusion: "e' riservato"
- invalid: "non e' valido"
- confirmation: "non corrisponde alla conferma"
- accepted: "deve essere accettato"
- empty: "non puo' essere vuoto"
- blank: "non puo' essere nullo"
- too_long: "e' troppo lungo (massimo sono %{count} caratteri)"
- too_short: "e' troppo corto (minimo sono %{count} caratteri)"
- wrong_length: "ha una lunghezza errata (dovrebbe essere %{count} caratteri)"
- not_a_number: "non e' un numero"
- not_an_integer: "deve essere un intero"
- greater_than: "deve essere piu' grande di %{count}"
- greater_than_or_equal_to: "deve essere piu' grande o uguale a %{count}"
- equal_to: "deve essere uguale a %{count}"
- less_than: "deve essere minore di %{count}"
- less_than_or_equal_to: "deve essere minore o uguale a %{count}"
- odd: "deve essere dispari"
- even: "deve essere pari"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: non incluso nell'elenco
+ exclusion: e' riservato
+ invalid: non e' valido
+ confirmation: non corrisponde alla conferma
+ accepted: deve essere accettato
+ empty: non puo' essere vuoto
+ blank: non puo' essere nullo
+ too_long: e' troppo lungo (massimo sono %{count} caratteri)
+ too_short: e' troppo corto (minimo sono %{count} caratteri)
+ wrong_length: ha una lunghezza errata (dovrebbe essere %{count} caratteri)
+ not_a_number: non e' un numero
+ not_an_integer: deve essere un intero
+ greater_than: deve essere piu' grande di %{count}
+ greater_than_or_equal_to: deve essere piu' grande o uguale a %{count}
+ equal_to: deve essere uguale a %{count}
+ less_than: deve essere minore di %{count}
+ less_than_or_equal_to: deve essere minore o uguale a %{count}
+ odd: deve essere dispari
+ even: deve essere pari
activerecord:
errors:
template:
header:
- one: "1 errore impedisce a questo %{model} da essere salvato"
- other: "%{count} errori impediscono a questo %{model} da essere salvato"
- body: "Ci sono stati problemi con i seguenti campi:"
-
+ one: 1 errore impedisce a questo %{model} da essere salvato
+ other: ! '%{count} errori impediscono a questo %{model} da essere salvato'
+ body: ! 'Ci sono stati problemi con i seguenti campi:'
messages:
- taken: "e' gia' stato preso"
- record_invalid: "Validazione fallita: %{errors}"
- <<: *errors_messages
-
+ inclusion: non incluso nell'elenco
+ exclusion: e' riservato
+ invalid: non e' valido
+ confirmation: non corrisponde alla conferma
+ accepted: deve essere accettato
+ empty: non puo' essere vuoto
+ blank: non puo' essere nullo
+ too_long: e' troppo lungo (massimo sono %{count} caratteri)
+ too_short: e' troppo corto (minimo sono %{count} caratteri)
+ wrong_length: ha una lunghezza errata (dovrebbe essere %{count} caratteri)
+ not_a_number: non e' un numero
+ not_an_integer: deve essere un intero
+ greater_than: deve essere piu' grande di %{count}
+ greater_than_or_equal_to: deve essere piu' grande o uguale a %{count}
+ equal_to: deve essere uguale a %{count}
+ less_than: deve essere minore di %{count}
+ less_than_or_equal_to: deve essere minore o uguale a %{count}
+ odd: deve essere dispari
+ even: deve essere pari
+ taken: e' gia' stato preso
+ record_invalid: ! 'Validazione fallita: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
-
\ No newline at end of file
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/it_fat_free_crm.yml b/config/locales/it_fat_free_crm.yml
index b1d2670d65..8393faba6d 100644
--- a/config/locales/it_fat_free_crm.yml
+++ b/config/locales/it_fat_free_crm.yml
@@ -1,21 +1,15 @@
+---
it:
language: Italian
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Tutti
at: presso
here: qui
no_button: 'No'
not_implemented: Non ancora implementato.
or: o
- select_none: '-- Nessuno --'
- select_blank: '-- Seleziona --'
- yes_button: 'Si'
-
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- Nessuno --
+ select_blank: -- Seleziona --
+ yes_button: Si
tab_dashboard: Cruscotto
tab_tasks: Lavori
tab_campaigns: Campagne
@@ -23,29 +17,24 @@ it:
tab_accounts: Conto
tab_contacts: Contatti
tab_opportunities: Opportunita'
-
admin_tab_users: Utenti
admin_tab_settings: Impostazioni
admin_tab_plugins: Plugins
-
affiliate: Affiliato
competitor: Concorrente
customer: Cliente
partner: Partner
reseller: Rivenditore
vendor: Venditore
-
planned: Pianificato
started: Iniziato
on_hold: Trattenuto
completed: Completato
called_off: Fernato
-
new: Nuovo
contacted: Contattato
converted: Convertito
rejected: Respinto
-
cold_call: Chiamata a freddo
conference: Conferenza
online: Online Marketing
@@ -54,7 +43,6 @@ it:
web: Website
word_of_mouth: Passaparola
other: Altro
-
prospecting: Prospetto
analysis: Analisi
presentation: Presentazione
@@ -63,16 +51,13 @@ it:
final_review: Controllo finale
won: Chiuso/Vinto
lost: Chiuso/Perso
-
call: Chiamata
email: Email
follow_up: Seguito
lunch: Pranzo
meeting: Incontro
money: Soldi
- presentation: Presentazione
trip: Viaggio
-
overdue: Scaduto
due_asap: Prima possibile
due_today: Oggi
@@ -81,24 +66,17 @@ it:
due_next_week: Prossima settimana
due_later: Piu' tardi
due_specific_date: Il giorno indicato...
-
completed_today: Oggi
completed_yesterday: Ieri
completed_last_week: Scorsa settimana
completed_this_month: Questo mese
completed_last_month: Scorso mese
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: Un'ora
one_day: Un giorno
two_days: Due giorni
one_week: Una settimana
two_weeks: Due settimane
one_month: Un mese
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -111,74 +89,75 @@ it:
account:
attributes:
name:
- missing_account_name: "^Specificare il nome del conto."
+ missing_account_name: ^Specificare il nome del conto.
access:
- share_account: "^Specificare gli utenti con cui condividere il conto."
+ share_account: ^Specificare gli utenti con cui condividere il conto.
campaign:
attributes:
name:
- missing_campaign_name: "^Specificare il nome della campagna."
+ missing_campaign_name: ^Specificare il nome della campagna.
ends_on:
- dates_not_in_sequence: "^Controllare che la data finale della campagna sia successiva a quella iniziale."
+ dates_not_in_sequence: ^Controllare che la data finale della campagna
+ sia successiva a quella iniziale.
access:
- share_campaign: "^Specificare gli utenti con cui condividere la campagna."
+ share_campaign: ^Specificare gli utenti con cui condividere la campagna.
contact:
attributes:
first_name:
- missing_first_name: "^Specificare il nome."
+ missing_first_name: ^Specificare il nome.
last_name:
- missing_last_name: "^Specificare il cognome."
+ missing_last_name: ^Specificare il cognome.
access:
- share_contact: "^Specificare gli utenti con cui contdividere il contatto."
+ share_contact: ^Specificare gli utenti con cui contdividere il contatto.
lead:
attributes:
first_name:
- missing_first_name: "^Specificare il nome."
+ missing_first_name: ^Specificare il nome.
last_name:
- missing_last_name: "^Specificare il cognome."
+ missing_last_name: ^Specificare il cognome.
access:
- share_lead: "^Specificare gli utenti con cui condividere il potenziale."
+ share_lead: ^Specificare gli utenti con cui condividere il potenziale.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Specificare il nome dell'opportunita'."
+ missing_opportunity_name: ^Specificare il nome dell'opportunita'.
access:
- share_opportunity: "^Specificare gli utenti con cui condividere l'opportunita'."
+ share_opportunity: ^Specificare gli utenti con cui condividere l'opportunita'.
task:
attributes:
name:
- missing_task_name: "^Specificare il nome del lavoro."
+ missing_task_name: ^Specificare il nome del lavoro.
calendar:
- invalid_date: "^Specificare una data valida."
+ invalid_date: ^Specificare una data valida.
user:
attributes:
username:
- missing_username: "^Specificare il nome utente."
- username_taken: "^Questo nome utente e' gia' assegnato."
+ missing_username: ^Specificare il nome utente.
+ username_taken: ^Questo nome utente e' gia' assegnato.
email:
- missing_email: "^Specificare l'indirizzo email."
- email_in_use: "^C'e' un altro utente con la stessa email."
-
+ missing_email: ^Specificare l'indirizzo email.
+ email_in_use: ^C'e' un altro utente con la stessa email.
msg_account_suspended: Questo utente e' stato sospeso.
password_reset_instruction: istruzioni per il reset della password
-
- # Controllers.
- #----------------------------------------------------------------------------
- msg_account_created: Il tuo account e' stato creato ed e' in attesa di approvazione dall'amministratore.
+ msg_account_created: Il tuo account e' stato creato ed e' in attesa di approvazione
+ dall'amministratore.
msg_account_not_approved: Il tuo account non e' ancora stato approvato.
- msg_asset_deleted: "%{value} e' stato eliminato."
+ msg_asset_deleted: ! '%{value} e'' stato eliminato.'
msg_asset_not_available: Questo %{value} non e' piu' valido.
msg_asset_not_authorized: Non sei autorizzato a vedere questo %{value}.
msg_assets_not_available: I %{value} non sono disponibili.
- msg_asset_rejected: "%{value} e' stato respinto."
- msg_bad_image_file: "^Impossibile caricare o ridimensionare il file con l'immagine specificata."
- msg_cant_create_related: "Non e' possibile creare %{asset} finche' %{related} non e' piu' disponibile."
- msg_cant_delete_user: "^Non e' possibilie eliminare l'utente finche' %{value} sono presenti elementi assegnati."
- msg_cant_do: "Can't %{action} the %{asset} since it's no longer available."
+ msg_asset_rejected: ! '%{value} e'' stato respinto.'
+ msg_bad_image_file: ^Impossibile caricare o ridimensionare il file con l'immagine
+ specificata.
+ msg_cant_create_related: Non e' possibile creare %{asset} finche' %{related} non
+ e' piu' disponibile.
+ msg_cant_delete_user: ^Non e' possibilie eliminare l'utente finche' %{value} sono
+ presenti elementi assegnati.
+ msg_cant_do: Can't %{action} the %{asset} since it's no longer available.
msg_email_not_found: Non e' stato trovato alcun utente con questa email.
msg_enter_new_password: Per favore insersci la tua nuova password.
msg_goodbye: Ti sei sconnesso. Grazie per aver usato Fat Free CRM!
- msg_invalid_password: "^Specifica la tua password corrente"
+ msg_invalid_password: ^Specifica la tua password corrente
msg_invalig_login: username o password non valida.
msg_last_login: il tuo ultimo login risale al %{value}.
msg_login_needed: Devi essere connesso per accedere a questa pagina.
@@ -186,15 +165,14 @@ it:
msg_password_changed: La tua password e' stata modificata.
msg_password_not_changed: La tua password non e' stata modificata.
msg_password_updated: Password aggiornata con successo.
- msg_pwd_instructions_sent: Ti sono state inviate le istruzioni per resettare la tua password. Per favore controlla la tua email.
+ msg_pwd_instructions_sent: Ti sono state inviate le istruzioni per resettare la
+ tua password. Per favore controlla la tua email.
msg_require_admin: Devi essere un Amministratore per accedere a questa pagina.
msg_successful_signup: Registrazione con successo, benvenuto a Fat Free CRM!
msg_welcome: Benvenuto a Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": ammonotare pesato
- activity_options: Mostra %{models} %{action_type} eseguito da %{user} nel passato %{period}.
+ option_amount*probability: ammonotare pesato
+ activity_options: Mostra %{models} %{action_type} eseguito da %{user} nel passato
+ %{period}.
all_users: tutti gli utenti
option_after: dopo
option_all: tutti
@@ -221,9 +199,6 @@ it:
show_per_page: Mostra %{number} %{models} per pagina usando %{fmt} formato.
sort_by: Ordina %{models} per %{field}.
sort_by_displaying: Ordina %{models} per %{field} mostrando nome %{position} cognome
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
aim: AOL IM
already_signed_up: Gia' iscritto?
alt_email: Email alternativa
@@ -233,12 +208,12 @@ it:
contact_info: Informazioni Contatto
current_password: Password attuale
edit_profile: Modifica Profilo
- # email: Email # <-- Already defined as the task type if Settings.
first_name: Nome
google: Google IM
gravatar_help: Non conosci Gravatars? Acquisisci informazioni riguardo Gravatars
image_file: File immagine
- image_help: Il file immagine che hai caricato sara' ridimensionato a 75 x 75 pixels. Formati supportati sono GIF, JPG e PNG.
+ image_help: Il file immagine che hai caricato sara' ridimensionato a 75 x 75 pixels.
+ Formati supportati sono GIF, JPG e PNG.
job_title: Titolo
last_name: Cognome
login_now_link: Connettiti ora!
@@ -259,17 +234,11 @@ it:
user: Utente
username: Username
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Password dimenticata
login: Login
no_account: Hai un account?
remember_me: Ricordami
sign_up_now: Registrati Ora!
-
- # Views -> Conti.
- #----------------------------------------------------------------------------
account: Conto
account_small: conto
account_summary: Sommario Conto
@@ -297,9 +266,6 @@ it:
shipping_address: Indirizzo spedizione
total_accounts: Totale Conti
website: Website
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Attuale
actual_performance: Performance attuale
budget: Budget
@@ -314,7 +280,7 @@ it:
campaigns_small: campagne
conversion: Conversione
conversion_label: Conversione (%)
- conversion_number: "%{value} conversione"
+ conversion_number: ! '%{value} conversione'
create_campaign: Crea Campagna
end_date: Data finale
finished_on: completato il %{value}
@@ -322,11 +288,14 @@ it:
no_start_date: data iniziale non specificata
number_of_leads: Numero di Potenziali
objectives: Obiettivi
- objectives_help: Per favore indica il numero di potenziali obiettivo, eccetto la percentuale di conversione verso le opportunita', gettito obiettivo, e il budget della campagna. Questi numeri ti consentiranno di tracciare le performance della campagna.
+ objectives_help: Per favore indica il numero di potenziali obiettivo, eccetto la
+ percentuale di conversione verso le opportunita', gettito obiettivo, e il budget
+ della campagna. Questi numeri ti consentiranno di tracciare le performance della
+ campagna.
objectives_small: obiettivi campagna
revenue: Gettito
revenue_label: Gettito (€)
- revenue_number: "%{value} in gettito"
+ revenue_number: ! '%{value} in gettito'
save_campaign: Salva Campagna
start_date: Data Iniziale
started_ago: iniziato %{value} fa
@@ -337,9 +306,6 @@ it:
was_supposed_to_finish: la conclusione era prevista per il %{value}
was_supposed_to_start: l'inizio era prevista %{time_ago} fa, il %{start_date}
was_supposed_to_start_in: l'inizio era prevista tra %{starts_in} il %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Altro
blog: Website/Blog
contact: Contatto
@@ -349,38 +315,46 @@ it:
contacts_small: contatti
create_contact: Crea Contatto
department: Dipartimento
- department_small: '%{value} dipartimento'
+ department_small: ! '%{value} dipartimento'
do_not_call: Non chiamare
extra_info: Informazioni Extra
extra_info_small: contatto extra
facebook: Facebook
linked_in: LinkedIn
myself: Me stesso
- permissions_intro_private: Di default solo tu avrai accesso a %{value}. Potrai cambiare i permessi piu' tardi.
- permissions_intro_public: Di default tutti gli utenti avranno accesso a %{value}. Potrai cambiare i permessi piu' tardi.
- permissions_intro_shared: Di default solo gli utenti selezionati avranno accesso a %{value}. Potrai cambiare i permessi piu' tardi.
+ permissions_intro_private: Di default solo tu avrai accesso a %{value}. Potrai cambiare
+ i permessi piu' tardi.
+ permissions_intro_public: Di default tutti gli utenti avranno accesso a %{value}.
+ Potrai cambiare i permessi piu' tardi.
+ permissions_intro_shared: Di default solo gli utenti selezionati avranno accesso
+ a %{value}. Potrai cambiare i permessi piu' tardi.
referred_by: Riferito da
referred_by_small: riferito da
save_contact: Salva Contatto
- skype: Skype
twitter: Twitter
web_presence: Presenza Web
web_presence_small: presenza web
- works_at: "%{job_title} presso %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} presso %{company}'
convert: Converti
convert_lead: Converti Potenziale
- convert_lead_permissions_intro: I permessi del contatto saranno copiati dalla conversione del potenziale. Potrai cambiare i permessi piu' tardi.
- convert_lead_text: Convertendo il potenziale %{value} verra' associato ad un contatto esistente oppure ad un nuovo contatto creato. Lo stato del potenziale sara' automaticamente inmpostato a Convertito.
+ convert_lead_permissions_intro: I permessi del contatto saranno copiati dalla conversione
+ del potenziale. Potrai cambiare i permessi piu' tardi.
+ convert_lead_text: Convertendo il potenziale %{value} verra' associato ad un contatto
+ esistente oppure ad un nuovo contatto creato. Lo stato del potenziale sara' automaticamente
+ inmpostato a Convertito.
create_lead: Crea potenziale
- create_opp_for_contact: E' possibile creare una opoortunita' per il %{value} contatto attraverso l'indicazione del nome, stato corrente, data chiusura stimata, probabilita' vendita, ammontare dell'affare e sconto offerto.
+ create_opp_for_contact: E' possibile creare una opoortunita' per il %{value} contatto
+ attraverso l'indicazione del nome, stato corrente, data chiusura stimata, probabilita'
+ vendita, ammontare dell'affare e sconto offerto.
lead: Potenziale
lead_info_small: contatti potenziale
- lead_permissions_intro_private: Di default i permessi saranno copiati dalla campagna o impostati a privato. Potrai cambiare i permessi del potenziale piu' tardi.
- lead_permissions_intro_public: Di default i permessi saranno copiati dalla campagna o impostati a pubblico. Potrai cambiare i permessi del potenziale piu' tardi.
- lead_permissions_intro_shared: Di default i permessi saranno copiati dalla campagna o condivisi con gli utenti specificati. Potrai cambiare i permessi del potenziale piu' tardi.
+ lead_permissions_intro_private: Di default i permessi saranno copiati dalla campagna
+ o impostati a privato. Potrai cambiare i permessi del potenziale piu' tardi.
+ lead_permissions_intro_public: Di default i permessi saranno copiati dalla campagna
+ o impostati a pubblico. Potrai cambiare i permessi del potenziale piu' tardi.
+ lead_permissions_intro_shared: Di default i permessi saranno copiati dalla campagna
+ o condivisi con gli utenti specificati. Potrai cambiare i permessi del potenziale
+ piu' tardi.
lead_small: potenziale
lead_status_small: stato del potenziale
lead_summary: Sommario del Potenziale
@@ -395,9 +369,6 @@ it:
source: Sorgente
status: Stato
total_leads: Potenziali Totali
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Importo
close_date: Data chiusura
closed_ago_on: chiuso %{time_ago} fa, il %{date}
@@ -419,7 +390,7 @@ it:
opportunity: Opportunita'
opportunity_small: opportunita'
opportunity_summary: Opportunita' a colpo d'occhio
- opportunity_summary_text: "%{amount} con %{discount} sconto e %{probability} probabilita'"
+ opportunity_summary_text: ! '%{amount} con %{discount} sconto e %{probability} probabilita'''
past_due: scadenza superata, era previsto concludersi %{value} fa
probability: Probabilita'
probability_number: e %{value} probabilita'
@@ -427,9 +398,6 @@ it:
stage: Punto
total_opportunities: Totale Opportunita'
weighted_amount: Importo pesato
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: Assegnato a
assigned_tab: Assegnato
assigned_tasks: Lavori Assegnati
@@ -441,13 +409,13 @@ it:
due: Scadenza
feel_free: Liberi di
move_to: spostare a
- no_tasks: "Non hai lavori %{value}"
+ no_tasks: Non hai lavori %{value}
no_tasks_pending: in attesa
no_tasks_assigned: assegnati
no_tasks_completed: completati
pending_tab: In attesa
pending_tasks: Lavori in attesa
- related: 'ref:'
+ related: ! 'ref:'
save_task: Salva Lavoro
task_assigned: Il lavoro e' stato assegnato a %{value}
task_assigned_to: e assegnato a %{value}
@@ -467,9 +435,6 @@ it:
total_tasks: Totale %{value}
view_assigned_tasks: vedi i lavori assegnati
view_pending_tasks: vedi i lavori pendenti
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: commentato il
action_completed: completato
action_created: creato
@@ -491,9 +456,6 @@ it:
subject_lead: potenziale
subject_opportunity: opportunita'
subject_task: lavoro
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Aggiungi Nota
save_note: Salva Nota
add_note_help: Aggiungi una nuova nota...
@@ -505,15 +467,15 @@ it:
close_form: Modello chisura
confirm_delete: Sei sicuro di voler eliminare questo %{value}?
copy_permissions: Copia %{value} permessi
- could_not_find: "Non e' stato possibile trovare alcun/a %{value}. Ti e' possibile"
- could_not_find_matching: "Non e' stato trovato alcuna corrispondenza con %{value}"
+ could_not_find: Non e' stato possibile trovare alcun/a %{value}. Ti e' possibile
+ could_not_find_matching: Non e' stato trovato alcuna corrispondenza con %{value}
create_new: crea nuovo
create_a_new: creare nuovo/a
select_existing: seleziona esistente
delete: Elimina
discard: Rimuovi
edit: Modifica
- items_total: '%{count} totali.'
+ items_total: ! '%{count} totali.'
less: Meno...
me: me
more: Piu'...
@@ -530,11 +492,11 @@ it:
select_task: Seleziona Lavoro
select_opportunity: Seleziona Opportunita'
search_assets: Cerca %{value}
- time_ago: "%{value} fa"
+ time_ago: ! '%{value} fa'
background_info: Informazioni background
address: Indirizzo
- street1: Via 1 # NUOVO
- street2: Via 2 # NUOVO
+ street1: Via 1
+ street2: Via 2
city: Citta'
zipcode: CAP
state: Stato
@@ -543,9 +505,6 @@ it:
collapse_all: Raggruppa tutti
expanded: Espandi
collapsed: Raggruppa
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: Info
about_dev_group: Gruppo di discussione per gli sviluppatori
about_features: Caratteristiche e bug
@@ -554,34 +513,24 @@ it:
about_ffc_version: Fat Free CRM versione
about_home_page: Home page
about_project_page: Pagina del Progetto
- about_thank_you: Grazie per usare Fat Free CRM! Appreziamo il tuo business e speriamo ti sia gradito l'uso di questo programma.
+ about_thank_you: Grazie per usare Fat Free CRM! Appreziamo il tuo business e speriamo
+ ti sia gradito l'uso di questo programma.
about_twitter: Aggiornamenti Twitter delle modifiche
about_user_group: Gruppo di discussione per gli utenti
admin: Amministrazione
logout: Logout
quick_find: Ricerca veloce
welcome: Benvenuto
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Modificando commento
show: Mostra
update: Aggiorna
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Per favore digita la tua password e la conferma.
- password_intro: Specifica il tuo indirizzo email, e le istruzioni per resettare la password ti saranno inviate.
+ password_intro: Specifica il tuo indirizzo email, e le istruzioni per resettare
+ la password ti saranno inviate.
reset_password: Resetta Password
update_password_and_login: Aggiorna Password e Login
-
- # Views -> Admin
- #----------------------------------------------------------------------------
back_to_crm: Ritorna a Fat Free CRM
crm_admin_page: Fat Free CRM Amministrazione
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Approva
create_user: Utente creato
last_seen: ultima visita %{value} fa
@@ -592,9 +541,10 @@ it:
user_active: Attivo
user_admin: Admin
user_awaits_approval: in attesa di approvazione
- user_confirm_delete: Un utente puo' essere cancellato se non ha assests assegnati lasciati indietro.
+ user_confirm_delete: Un utente puo' essere cancellato se non ha assests assegnati
+ lasciati indietro.
user_is_admin: L'utente e' Amministratore
- user_never_logged_in: "non si e' ancora collegato"
+ user_never_logged_in: non si e' ancora collegato
user_signed_up: Iscritto
user_signed_up_on: iscritto il %{value}
user_since: utente dal %{value}
@@ -602,53 +552,40 @@ it:
user_suspended_on: sospeso il %{value}
users: Utenti
users_small: utenti
-
- # Export.
- #----------------------------------------------------------------------------
to_xls: Esporta a Excel
to_csv: Esporta al formato file delimitato da virgole (inclusi i record cancellati)
to_rss: RSS feed
to_atom: Atom feed
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - Aggiunta email - %{subject}
dropbox_notification_intro: Email inviata a dropbox aggiunta con successo
dropbox_notification_to: Aggiunto a
subject: Oggetto
body: Corpo
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 commento'
- other: '%{count} commenti'
+ one: 1 commento
+ other: ! '%{count} commenti'
contact:
- one: '1 contatto'
- other: '%{count} contatti'
+ one: 1 contatto
+ other: ! '%{count} contatti'
opportunity:
- one: '1 opportunity'
- other: '%{count} opportunita'''
+ one: 1 opportunity
+ other: ! '%{count} opportunita'''
lead:
- one: '1 potenziale'
- other: '%{count} potenziali'
+ one: 1 potenziale
+ other: ! '%{count} potenziali'
day:
- one: '1 giorno'
- other: '%{count} giorni'
+ one: 1 giorno
+ other: ! '%{count} giorni'
login:
- one: '1 login'
- other: '%{count} logins'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 login
+ other: ! '%{count} logins'
date:
formats:
- mmddyyyy: "%d/%m/%Y"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%d/%m/%Y'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%b %e at %l:%M%p"
- mmddyyyy_hhmm: "%d/%m/%Y %H:%M"
+ mmddhhss: ! '%b %e at %l:%M%p'
+ mmddyyyy_hhmm: ! '%d/%m/%Y %H:%M'
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 72951859f4..b8243f469b 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -1,188 +1,219 @@
-# Japanese translations for Ruby on Rails
-# by Akira Matsuda (ronnie@dio.jp)
-# AR error messages are basically taken from Ruby-GetText-Package. Thanks to Masao Mutoh.
-# contributors:
-# - Tsutomu Kuroda (t-kuroda@oiax.jp)
-
+---
ja:
date:
formats:
- default: "%Y/%m/%d"
- short: "%m/%d"
- long: "%Y年%m月%d日(%a)"
-
- day_names: [日曜日, 月曜日, 火曜日, 水曜日, 木曜日, 金曜日, 土曜日]
- abbr_day_names: [日, 月, 火, 水, 木, 金, 土]
-
- month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
- abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
-
+ default: ! '%Y/%m/%d'
+ short: ! '%m/%d'
+ long: ! '%Y年%m月%d日(%a)'
+ day_names:
+ - 日曜日
+ - 月曜日
+ - 火曜日
+ - 水曜日
+ - 木曜日
+ - 金曜日
+ - 土曜日
+ abbr_day_names:
+ - 日
+ - 月
+ - 火
+ - 水
+ - 木
+ - 金
+ - 土
+ month_names:
+ -
+ - 1月
+ - 2月
+ - 3月
+ - 4月
+ - 5月
+ - 6月
+ - 7月
+ - 8月
+ - 9月
+ - 10月
+ - 11月
+ - 12月
+ abbr_month_names:
+ -
+ - 1月
+ - 2月
+ - 3月
+ - 4月
+ - 5月
+ - 6月
+ - 7月
+ - 8月
+ - 9月
+ - 10月
+ - 11月
+ - 12月
order:
- - :year
- - :month
- - :day
-
+ - :year
+ - :month
+ - :day
time:
formats:
- default: "%Y/%m/%d %H:%M:%S"
- short: "%y/%m/%d %H:%M"
- long: "%Y年%m月%d日(%a) %H時%M分%S秒 %Z"
- am: "午前"
- pm: "午後"
-
+ default: ! '%Y/%m/%d %H:%M:%S'
+ short: ! '%y/%m/%d %H:%M'
+ long: ! '%Y年%m月%d日(%a) %H時%M分%S秒 %Z'
+ am: 午前
+ pm: 午後
support:
array:
- sentence_connector: "と"
+ sentence_connector: と
skip_last_comma: true
- words_connector: "と"
- two_words_connector: "と"
- last_word_connector: "と"
-
+ words_connector: と
+ two_words_connector: と
+ last_word_connector: と
select:
- prompt: "選択してください。"
-
+ prompt: 選択してください。
number:
format:
- separator: "."
- delimiter: ","
+ separator: .
+ delimiter: ! ','
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: "%n%u"
- unit: "円"
- separator: "."
- delimiter: ","
+ format: ! '%n%u'
+ unit: 円
+ separator: .
+ delimiter: ! ','
precision: 3
significant: false
strip_insignificant_zeros: false
-
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
-
storage_units:
- format: "%n%u"
+ format: ! '%n%u'
units:
- byte: "バイト"
- kb: "キロバイト"
- mb: "メガバイト"
- gb: "ギガバイト"
- tb: "テラバイト"
-
+ byte: バイト
+ kb: キロバイト
+ mb: メガバイト
+ gb: ギガバイト
+ tb: テラバイト
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
- thousand: "千"
- million: "百万"
- billion: "十億"
- trillion: "兆"
- quadrillion: "千兆"
-
+ unit: ''
+ thousand: 千
+ million: 百万
+ billion: 十億
+ trillion: 兆
+ quadrillion: 千兆
datetime:
distance_in_words:
- half_a_minute: "30秒前後"
+ half_a_minute: 30秒前後
less_than_x_seconds:
- one: "1秒以内"
- other: "%{count}秒以内"
+ one: 1秒以内
+ other: ! '%{count}秒以内'
x_seconds:
- one: "1秒"
- other: "%{count}秒"
+ one: 1秒
+ other: ! '%{count}秒'
less_than_x_minutes:
- one: "1分以内"
- other: "%{count}分以内"
+ one: 1分以内
+ other: ! '%{count}分以内'
x_minutes:
- one: "1分"
- other: "%{count}分"
+ one: 1分
+ other: ! '%{count}分'
about_x_hours:
- one: "約1時間"
- other: "約%{count}時間"
+ one: 約1時間
+ other: 約%{count}時間
x_days:
- one: "1日"
- other: "%{count}日"
+ one: 1日
+ other: ! '%{count}日'
about_x_months:
- one: "約1ヶ月"
- other: "約%{count}ヶ月"
+ one: 約1ヶ月
+ other: 約%{count}ヶ月
x_months:
- one: "1ヶ月"
- other: "%{count}ヶ月"
+ one: 1ヶ月
+ other: ! '%{count}ヶ月'
about_x_years:
- one: "約1年"
- other: "約%{count}年"
+ one: 約1年
+ other: 約%{count}年
over_x_years:
- one: "1年以上"
- other: "%{count}年以上"
+ one: 1年以上
+ other: ! '%{count}年以上'
almost_x_years:
- one: "1年弱"
- other: "%{count}年弱"
-
+ one: 1年弱
+ other: ! '%{count}年弱'
prompts:
- year: "年"
- month: "月"
- day: "日"
- hour: "時"
- minute: "分"
- second: "秒"
-
+ year: 年
+ month: 月
+ day: 日
+ hour: 時
+ minute: 分
+ second: 秒
helpers:
select:
- prompt: "選択してください。"
-
+ prompt: 選択してください。
submit:
- create: "登録する"
- update: "更新する"
- submit: "保存する"
-
+ create: 登録する
+ update: 更新する
+ submit: 保存する
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "は一覧にありません。"
- exclusion: "は予約されています。"
- invalid: "は不正な値です。"
- confirmation: "が一致しません。"
- accepted: "を受諾してください。"
- empty: "を入力してください。"
- blank: "を入力してください。"
- too_long: "は%{count}文字以内で入力してください。"
- too_short: "は%{count}文字以上で入力してください。"
- wrong_length: "は%{count}文字で入力してください。"
- not_a_number: "は数値で入力してください。"
- not_an_integer: "は整数で入力してください。"
- greater_than: "は%{count}より大きい値にしてください。"
- greater_than_or_equal_to: "は%{count}以上の値にしてください。"
- equal_to: "は%{count}にしてください。"
- less_than: "は%{count}より小さい値にしてください。"
- less_than_or_equal_to: "は%{count}以下の値にしてください。"
- odd: "は奇数にしてください。"
- even: "は偶数にしてください。"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: は一覧にありません。
+ exclusion: は予約されています。
+ invalid: は不正な値です。
+ confirmation: が一致しません。
+ accepted: を受諾してください。
+ empty: を入力してください。
+ blank: を入力してください。
+ too_long: は%{count}文字以内で入力してください。
+ too_short: は%{count}文字以上で入力してください。
+ wrong_length: は%{count}文字で入力してください。
+ not_a_number: は数値で入力してください。
+ not_an_integer: は整数で入力してください。
+ greater_than: は%{count}より大きい値にしてください。
+ greater_than_or_equal_to: は%{count}以上の値にしてください。
+ equal_to: は%{count}にしてください。
+ less_than: は%{count}より小さい値にしてください。
+ less_than_or_equal_to: は%{count}以下の値にしてください。
+ odd: は奇数にしてください。
+ even: は偶数にしてください。
activerecord:
errors:
template:
header:
- one: "%{model}にエラーが発生しました。"
- other: "%{model}に%{count}つのエラーが発生しました。"
- body: "次の項目を確認してください。"
-
+ one: ! '%{model}にエラーが発生しました。'
+ other: ! '%{model}に%{count}つのエラーが発生しました。'
+ body: 次の項目を確認してください。
messages:
- taken: "はすでに存在します。"
- record_invalid: "バリデーションに失敗しました。 %{errors}"
- <<: *errors_messages
-
+ inclusion: は一覧にありません。
+ exclusion: は予約されています。
+ invalid: は不正な値です。
+ confirmation: が一致しません。
+ accepted: を受諾してください。
+ empty: を入力してください。
+ blank: を入力してください。
+ too_long: は%{count}文字以内で入力してください。
+ too_short: は%{count}文字以上で入力してください。
+ wrong_length: は%{count}文字で入力してください。
+ not_a_number: は数値で入力してください。
+ not_an_integer: は整数で入力してください。
+ greater_than: は%{count}より大きい値にしてください。
+ greater_than_or_equal_to: は%{count}以上の値にしてください。
+ equal_to: は%{count}にしてください。
+ less_than: は%{count}より小さい値にしてください。
+ less_than_or_equal_to: は%{count}以下の値にしてください。
+ odd: は奇数にしてください。
+ even: は偶数にしてください。
+ taken: はすでに存在します。
+ record_invalid: バリデーションに失敗しました。 %{errors}
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/ja_fat_free_crm.yml b/config/locales/ja_fat_free_crm.yml
index 51057d9e9b..4db4abaeab 100644
--- a/config/locales/ja_fat_free_crm.yml
+++ b/config/locales/ja_fat_free_crm.yml
@@ -1,20 +1,15 @@
+---
ja:
language: Japanese
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: 全て
at: at
here: こちら
- no_button: 'いいえ'
+ no_button: いいえ
not_implemented: まだ未実装です。
or: または
- select_none: '-- なし --'
- select_blank: '-- 選択 --'
- yes_button: 'はい'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- なし --
+ select_blank: -- 選択 --
+ yes_button: はい
tab_dashboard: ダッシュボード
tab_tasks: タスク
tab_campaigns: キャンペーン
@@ -22,22 +17,18 @@ ja:
tab_accounts: 取引先
tab_contacts: 取引先責任者
tab_opportunities: 商談
-
admin_tab_users: ユーザ
admin_tab_settings: 管理設定
admin_tab_plugins: プラグイン
-
planned: 計画済
started: 開始済
on_hold: 保留中
completed: 完了
called_off: 中止
-
new: 新規
contacted: 連絡済
converted: コンバート済
rejected: 却下
-
cold_call: 勧誘電話
conference: 会議
online: オンラインマーケティング
@@ -46,25 +37,21 @@ ja:
web: Webサイト
word_of_mouth: Word of Mouth
other: その他
-
prospecting: 見込み
analysis: 分析
- presentation: プレゼンテーション
+ presentation: プレゼン
proposal: 提案
negotiation: 価格交渉
final_review: 最終交渉
won: 終/成立
lost: 終/失注
-
call: 電話
email: Eメール
follow_up: フォローアップ
lunch: 昼食会
meeting: 会議
money: Money
- presentation: プレゼン
trip: 出張
-
overdue: 期限切れ
due_asap: できるだけ早く
due_today: 今日中
@@ -73,24 +60,17 @@ ja:
due_next_week: 来週中
due_later: 今後いつか
due_specific_date: 指定日...
-
completed_today: 今日
completed_yesterday: 昨日
completed_last_week: 先週
completed_this_month: 今月
completed_last_month: 先月
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: 1時間
one_day: 1日
two_days: 2日
one_week: 1週間
two_weeks: 2週間
one_month: 1ヶ月
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -103,83 +83,77 @@ ja:
account:
attributes:
name:
- missing_account_name: "^取引先名を指定してください。"
+ missing_account_name: ^取引先名を指定してください。
access:
- share_account: "^Please specify users to share the account with."
+ share_account: ^Please specify users to share the account with.
campaign:
attributes:
name:
- missing_campaign_name: "^キャンペーン名を指定してください。"
+ missing_campaign_name: ^キャンペーン名を指定してください。
ends_on:
- dates_not_in_sequence: "^キャンペーンの終了日が開始日の後であることを確認してください。"
+ dates_not_in_sequence: ^キャンペーンの終了日が開始日の後であることを確認してください。
access:
- share_campaign: "^Please specify users to share the campaign with."
+ share_campaign: ^Please specify users to share the campaign with.
contact:
attributes:
first_name:
- missing_first_name: "^名を指定してください。"
+ missing_first_name: ^名を指定してください。
last_name:
- missing_last_name: "^姓を指定してください。"
+ missing_last_name: ^姓を指定してください。
access:
- share_contact: "^Please specify users to share the contact with."
+ share_contact: ^Please specify users to share the contact with.
lead:
attributes:
first_name:
- missing_first_name: "^名を指定してください。"
+ missing_first_name: ^名を指定してください。
last_name:
- missing_last_name: "^姓を指定してください。"
+ missing_last_name: ^姓を指定してください。
access:
- share_lead: "^Please specify users to share the lead with."
+ share_lead: ^Please specify users to share the lead with.
opportunity:
attributes:
name:
- missing_opportunity_name: "^商談名を指定してください。"
+ missing_opportunity_name: ^商談名を指定してください。
access:
- share_opportunity: "^Please specify users to share the opportunity with."
+ share_opportunity: ^Please specify users to share the opportunity with.
task:
attributes:
name:
- missing_task_name: "^タスク名を指定してください。"
+ missing_task_name: ^タスク名を指定してください。
calendar:
- invalid_date: "^正しい日付を指定してください。"
+ invalid_date: ^正しい日付を指定してください。
user:
attributes:
username:
- missing_username: "^ユーザ名を指定してください。"
- username_taken: "^このユーザ名は既に取得されています。"
+ missing_username: ^ユーザ名を指定してください。
+ username_taken: ^このユーザ名は既に取得されています。
email:
- missing_email: "^Eメールアドレスを指定してください。"
- email_in_use: "^同じEメールアドレスを持つ他のユーザがいます。"
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ missing_email: ^Eメールアドレスを指定してください。
+ email_in_use: ^同じEメールアドレスを持つ他のユーザがいます。
errors:
template:
header:
- one: "%{model}にエラーが発生しました。"
- other: "%{model}に%{count}つのエラーが発生しました。"
- body: "次の項目を確認してください。"
-
+ one: ! '%{model}にエラーが発生しました。'
+ other: ! '%{model}に%{count}つのエラーが発生しました。'
+ body: 次の項目を確認してください。
msg_account_suspended: User account has been suspended.
password_reset_instruction: password reset instructions
-
- # Controllers.
- #----------------------------------------------------------------------------
msg_account_created: あなたのアカウントは生成され、システム管理者の承認待ちです。
msg_account_not_approved: あなたのアカウントは承認されていません。
- msg_asset_deleted: "%{value} は削除されています。"
+ msg_asset_deleted: ! '%{value} は削除されています。'
msg_asset_not_available: この %{value} は、もはや存在しません。
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
- msg_assets_not_available: %{value} は存在しません。
- msg_asset_rejected: "%{value} は拒否されています。"
- msg_bad_image_file: "^指定されたファイルのアップデートもしくはリサイズができませんでした。"
- msg_cant_create_related: "%{related} がもはや存在しないため、 %{asset} を生成できません。"
- msg_cant_delete_user: "Couldn't delete the user since %{value} has related assets present."
- msg_cant_do: "Can't %{action} the %{asset} since it's no longer available."
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
+ msg_assets_not_available: ! '%{value} は存在しません。'
+ msg_asset_rejected: ! '%{value} は拒否されています。'
+ msg_bad_image_file: ^指定されたファイルのアップデートもしくはリサイズができませんでした。
+ msg_cant_create_related: ! '%{related} がもはや存在しないため、 %{asset} を生成できません。'
+ msg_cant_delete_user: Couldn't delete the user since %{value} has related assets
+ present.
+ msg_cant_do: Can't %{action} the %{asset} since it's no longer available.
msg_email_not_found: そのEメールアドレスを持つユーザが見つかりませんでした。
msg_enter_new_password: 新しいパスワードを入力してください。
msg_goodbye: ログアウトしました。 Fat Free CRM をご利用いただき、ありがとうございます!
- msg_invalid_password: "^Please specify valid current password"
+ msg_invalid_password: ^Please specify valid current password
msg_invalig_login: ユーザ名かパスワードが不正です。
msg_last_login: あなたの最終ログインは %{value} です。
msg_login_needed: このページへのアクセスにはログインが必要です。
@@ -191,10 +165,7 @@ ja:
msg_require_admin: このページへのアクセスは管理者でなければなりません。
msg_successful_signup: サインアップ成功です。 Fat Free CRM へようこそ!
msg_welcome: Fat Free CRM へようこそ!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": weighted amount
+ option_amount*probability: weighted amount
activity_options: Show %{models} activities performed by %{user} in the past %{period}.
all_users: 全ユーザ
option_after: 前
@@ -219,12 +190,9 @@ ja:
option_target_leads: target leads
option_target_revenue: target revenue
option_updated_at: 更新日
- show_per_page: "%{fmt}書式で1ページ%{number}件ずつ%{models}を表示。"
- sort_by: "%{field}で%{models}を並べ替える。"
- sort_by_displaying: "姓を名の%{position}に表示にして、%{field}で%{models}を並べ替える。"
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ show_per_page: ! '%{fmt}書式で1ページ%{number}件ずつ%{models}を表示。'
+ sort_by: ! '%{field}で%{models}を並べ替える。'
+ sort_by_displaying: 姓を名の%{position}に表示にして、%{field}で%{models}を並べ替える。
aim: AOL IM
already_signed_up: サインアップ済みですか?
alt_email: その他のEメール
@@ -234,12 +202,12 @@ ja:
contact_info: 連絡先情報
current_password: 現在のパスワード
edit_profile: プロフィール編集
- # email: Eメール # <-- Already defined as the task type if Settings.
first_name: 名
google: Google IM
gravatar_help: Gravatarsをご存知ない? Gravatarsについては
image_file: 画像ファイル
- image_help: アップロードされた画像ファイルは自動的に 75 x 75 ピクセルの大きさに調整されます。対応フォーマットは GIF, JPG, PNG です。
+ image_help: アップロードされた画像ファイルは自動的に 75 x 75 ピクセルの大きさに調整されます。対応フォーマットは GIF, JPG, PNG
+ です。
job_title: 役職
last_name: 姓
login_now_link: 今すぐログイン!
@@ -260,17 +228,11 @@ ja:
user: ユーザ
username: ユーザ名
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: パスワードを忘れた場合
login: ログイン
no_account: アカウントがない場合
remember_me: Remember Me
sign_up_now: 今すぐサインアップ!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: 取引先
account_small: 取引先
accounts: 取引先
@@ -282,10 +244,10 @@ ja:
date_created: 作成日
date_updated: 更新日
fax: FAX
- intro: "後で%{value}の情報を追加することができます。"
+ intro: 後で%{value}の情報を追加することができます。
mobile_small: 携帯電話
- open_in_window: "新しいウィンドウで%{value}を開く"
- mail_to: "%{value}へのメール"
+ open_in_window: 新しいウィンドウで%{value}を開く
+ mail_to: ! '%{value}へのメール'
phone_small: 電話
phone_toll_free: 通話無料
keep_private: 秘密扱いにして、他人と共有しない
@@ -295,9 +257,6 @@ ja:
share_with: 以下の人達と共有する
shipping_address: 発送先住所
website: Webサイト
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Actual
actual_performance: Actual Performance
budget: 予算
@@ -312,7 +271,7 @@ ja:
campaigns_small: キャンペーン
conversion: Conversion
conversion_label: Conversion (%)
- conversion_number: "%{value} conversion"
+ conversion_number: ! '%{value} conversion'
create_campaign: キャンペーンを作成
end_date: 終了日
finished_on: completed on %{value}
@@ -320,23 +279,22 @@ ja:
no_start_date: 開始日未設定
number_of_leads: Number of leads
objectives: Objectives
- objectives_help: Please specify target number of leads, expected leads-to-opportunities conversion ratio, target revenue, and campaign budget. These numbers will let you track actual campaign performance.
+ objectives_help: Please specify target number of leads, expected leads-to-opportunities
+ conversion ratio, target revenue, and campaign budget. These numbers will let
+ you track actual campaign performance.
objectives_small: campaign objectives
revenue: Revenue
revenue_label: Revenue ($)
- revenue_number: "%{value} in revenue"
+ revenue_number: ! '%{value} in revenue'
save_campaign: キャンペーンを保存
start_date: 開始日
- started_ago: %{value} 前に開始
+ started_ago: ! '%{value} 前に開始'
starts_in: starts in %{value}
starts_today: 本日開始!
target: Target
total_campaigns: キャンペーンの合計
was_supposed_to_finish: was supposed to finish on %{value}
was_supposed_to_start: was supposed to start %{time_ago} ago on %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: その他
blog: Webサイト/ブログ
contact: 取引先責任者
@@ -346,37 +304,42 @@ ja:
contacts_small: 取引先責任者
create_contact: 取引先責任者を作成
department: 部署
- department_small: '%{value}部署'
+ department_small: ! '%{value}部署'
do_not_call: 電話しない
extra_info: 追加情報
extra_info_small: 追加取引先責任者
facebook: Facebook
linked_in: LinkedIn
myself: 自分自身
- permissions_intro_private: "デフォルトでは、あなただけが%{value}にアクセスできます。パーミッションは後で変更することができます。"
- permissions_intro_public: "デフォルトでは、全ユーザが%{value}にアクセスできます。パーミッションは後で変更することができます。"
- permissions_intro_shared: "デフォルトでは、指定ユーザが%{value}にアクセスできます。パーミッションは後で変更することができます。"
+ permissions_intro_private: デフォルトでは、あなただけが%{value}にアクセスできます。パーミッションは後で変更することができます。
+ permissions_intro_public: デフォルトでは、全ユーザが%{value}にアクセスできます。パーミッションは後で変更することができます。
+ permissions_intro_shared: デフォルトでは、指定ユーザが%{value}にアクセスできます。パーミッションは後で変更することができます。
referred_by: Referred by
referred_by_small: referred by
save_contact: 取引先責任者を保存
twitter: Twitter
web_presence: Webサイト情報
web_presence_small: Webサイト
- works_at: "%{company} の %{job_title}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{company} の %{job_title}'
convert: コンバート
convert_lead: Convert Lead
- convert_lead_permissions_intro: Contact permissions will be copied from the lead being converted. You can change contact permissions later.
- convert_lead_text: By converting the lead %{value} will become a contact associated with the existing or newly created account. Lead status will be automatically set to converted.
+ convert_lead_permissions_intro: Contact permissions will be copied from the lead
+ being converted. You can change contact permissions later.
+ convert_lead_text: By converting the lead %{value} will become a contact associated
+ with the existing or newly created account. Lead status will be automatically
+ set to converted.
create_lead: リードを作成
- create_opp_for_contact: You can optionally create an opportunity for the %{value} contact by specifying the name, current stage, estimated closing date, sale probability, amount of the deal, and the discount offered.
+ create_opp_for_contact: You can optionally create an opportunity for the %{value}
+ contact by specifying the name, current stage, estimated closing date, sale probability,
+ amount of the deal, and the discount offered.
lead: リード
lead_info_small: リード連絡先
- lead_permissions_intro_private: By default permissions will be copied from the campaign or set to private. You can change lead permissions later.
- lead_permissions_intro_public: By default permissions will be copied from the campaign or set to public. You can change lead permissions later.
- lead_permissions_intro_shared: By default permissions will be copied from the campaign or shared with the specified users. You can change lead permissions later.
+ lead_permissions_intro_private: By default permissions will be copied from the campaign
+ or set to private. You can change lead permissions later.
+ lead_permissions_intro_public: By default permissions will be copied from the campaign
+ or set to public. You can change lead permissions later.
+ lead_permissions_intro_shared: By default permissions will be copied from the campaign
+ or shared with the specified users. You can change lead permissions later.
lead_small: リード
lead_status_small: リードステータス
lead_summary: Lead Summary
@@ -391,12 +354,9 @@ ja:
source: Source
status: Status
total_leads: リードの合計
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: 金額
close_date: 終了日
- closed_ago_on: "%{date}の%{time_ago}前に終了"
+ closed_ago_on: ! '%{date}の%{time_ago}前に終了'
closes_today: 本日終了の見込み
closing_date: 終了日は%{value}
create_opportunity: 商談を作成
@@ -404,8 +364,8 @@ ja:
days_late: Late by
days_left: Days left
discount: 値引き
- discount_number: "値引き%{value}"
- expected_to_close: "%{date}の%{time}に終了の見込み"
+ discount_number: 値引き%{value}
+ expected_to_close: ! '%{date}の%{time}に終了の見込み'
from: from
no_closing_date: 予測終了日なし
no_discount: 値引きなし
@@ -415,17 +375,14 @@ ja:
opportunity: 商談
opportunity_small: 商談
opportunity_summary: Opportunity At a Glance
- opportunity_summary_text: "%{amount} %{discount}値引きかつ確度%{probability}"
- past_due: "期限切れ、%{value}前に終了見込み"
+ opportunity_summary_text: ! '%{amount} %{discount}値引きかつ確度%{probability}'
+ past_due: 期限切れ、%{value}前に終了見込み
probability: 確度
- probability_number: "かつ確度%{value}"
+ probability_number: かつ確度%{value}
save_opportunity: 商談を保存
stage: Stage
total_opportunities: 商談の合計
weighted_amount: Weighted amount
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: 担当
assigned_tab: 担当
assigned_tasks: 担当タスク
@@ -437,19 +394,19 @@ ja:
due: 期日
feel_free: どうぞお気軽に
move_to: move to
- no_tasks: "%{value}のタスクはありません"
+ no_tasks: ! '%{value}のタスクはありません'
no_tasks_pending: 未完了
no_tasks_assigned: 担当
no_tasks_completed: 完了
pending_tab: 未完了
pending_tasks: 未完了タスク
- related: 're:'
+ related: ! 're:'
save_task: タスクを保存
task_assigned: The task has been assigned to %{value}
task_assigned_to: and assigned to %{value}
task_completed: 完了
- task_completed_ago: %{value} 前に完了
- task_completed_by: %{user} によって %{time_ago} 前に完了
+ task_completed_ago: ! '%{value} 前に完了'
+ task_completed_by: ! '%{user} によって %{time_ago} 前に完了'
task_created: タスクが作成されました
task_due_in: due in %{value}
task_due_later: due sometime soon
@@ -460,17 +417,14 @@ ja:
task_pending: The task has been moved to pending tasks
task_small: タスク
tasks: タスク
- total_tasks: "%{value}の合計"
+ total_tasks: ! '%{value}の合計'
view_assigned_tasks: 担当タスクを表示
view_pending_tasks: 見完了タスクを表示
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: コメントした
action_completed: 完了した
action_created: 作成した
action_deleted: 削除した
- action_email: exchanged emails with # TODO
+ action_email: exchanged emails with
action_reassigned: 再割り当てした
action_rejected: 拒否した
action_rescheduled: 再スケジュールした
@@ -486,31 +440,28 @@ ja:
subject_lead: リード
subject_opportunity: 商談
subject_task: タスク
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: ノートを追加
save_note: ノートを保存
add_note_help: 新しいノートを追加...
edit_note: ノートを編集
- added_ago: "%{value} 前に追加"
- added_by: "%{user} により %{time_ago} 前に追加"
+ added_ago: ! '%{value} 前に追加'
+ added_by: ! '%{user} により %{time_ago} 前に追加'
back: 戻る
cancel: キャンセル
close_form: フォームを閉じる
confirm_delete: この %{value} を削除しますか?
copy_permissions: Copy %{value} permissions
- could_not_find: "%{value}がありません。どうぞお気軽に"
- could_not_find_matching: "マッチする%{value}がありません。"
+ could_not_find: ! '%{value}がありません。どうぞお気軽に'
+ could_not_find_matching: マッチする%{value}がありません。
create_new: 新規作成してください -
select_existing: 既存から選択
delete: 削除
- discard: Discard # TODO
+ discard: Discard
edit: 編集
- items_total: '合計 %{count}'
- less: Less... # TODO
+ items_total: 合計 %{count}
+ less: Less...
me: 自分
- more: More... # TODO
+ more: More...
n_a: N/A
name: 名前
no_match: No %{value} match
@@ -519,8 +470,8 @@ ja:
permissions: パーミッション
please_retry: please try another query.
recent_items: 最近のアイテム
- search_assets: "%{value}を検索"
- time_ago: "%{value}前"
+ search_assets: ! '%{value}を検索'
+ time_ago: ! '%{value}前'
background_info: 背景
address: 住所
street1: 番地1
@@ -529,9 +480,6 @@ ja:
zipcode: 郵便番号
state: 都道府県
country: 国
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: About
about_dev_group: 開発者のためのディスカッショングループ
about_features: Features and bugs
@@ -540,38 +488,27 @@ ja:
about_ffc_version: Fat Free CRM バージョン
about_home_page: Home page
about_project_page: プロジェクトページ
- about_thank_you: Thank you for using Fat Free CRM! We appreciate your business and hope you enjoy using the software.
+ about_thank_you: Thank you for using Fat Free CRM! We appreciate your business and
+ hope you enjoy using the software.
about_twitter: Twitter commit updates
about_user_group: ユーザのためのディスカッショングループ
admin: 管理画面
logout: ログアウト
quick_find: Quick find
welcome: ようこそ
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: コメント編集中
show: 表示
update: 更新
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Please type your new password and then confirm it.
- password_intro: Please specify your email address, and the instructions to reset your password will be sent to you.
+ password_intro: Please specify your email address, and the instructions to reset
+ your password will be sent to you.
reset_password: Reset Password
update_password_and_login: Update Password and Login
-
- # Views -> Admin
- #----------------------------------------------------------------------------
- # TODO
back_to_crm: Fat Free CRM に戻る
crm_admin_page: Fat Free CRM 管理
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Approve
create_user: ユーザを作成
- last_seen: "最後に見たのは%{value}前"
+ last_seen: 最後に見たのは%{value}前
personal_information: 個人情報
reactivate: Reactivate
save_user: ユーザを保存
@@ -581,46 +518,39 @@ ja:
user_awaits_approval: awaits your approval
user_confirm_delete: A user can only be deleted if no related assets are left behind.
user_is_admin: このユーザは管理者
- user_never_logged_in: "hasn't logged in yet"
+ user_never_logged_in: hasn't logged in yet
user_signed_up: Signed Up
user_signed_up_on: signed up on %{value}
- user_since: "%{value}からのユーザ"
+ user_since: ! '%{value}からのユーザ'
user_suspended: Suspended
user_suspended_on: suspended on %{value}
users: ユーザ
users_small: ユーザ
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 件のコメント' # TODO
- other: '%{count} 件のコメント' # TODO
+ one: 1 件のコメント
+ other: ! '%{count} 件のコメント'
contact:
- one: '1 contact'
- other: '%{count} contacts'
+ one: 1 contact
+ other: ! '%{count} contacts'
opportunity:
- one: '1 件の商談'
- other: '%{count} 件の商談'
+ one: 1 件の商談
+ other: ! '%{count} 件の商談'
lead:
- one: '1 lead'
- other: '%{count} leads'
+ one: 1 lead
+ other: ! '%{count} leads'
day:
- one: '1 日'
- other: '%{count} 日'
+ one: 1 日
+ other: ! '%{count} 日'
login:
- one: '1 login'
- other: '%{count} logins'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 login
+ other: ! '%{count} logins'
date:
formats:
- mmddyyyy: "%Y/%m/%d"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%Y/%m/%d'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%b %e at %l:%M%p"
- mmddyyyy_hhmm: "%m/%d/%Y %l:%M %p"
+ mmddhhss: ! '%b %e at %l:%M%p'
+ mmddyyyy_hhmm: ! '%m/%d/%Y %l:%M %p'
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 55eceb57b5..f5b35ded93 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -1,194 +1,230 @@
-# Polish translations for Ruby on Rails
-# by Jacek Becela (jacek.becela@gmail.com, http://github.com/ncr)
-# Minor changes and adjustments for Rails 3 by Piotrek Okoński (http://github.com/pokonski)
-# Minor changes and adjustments by Paweł Chojnacki (https://github.com/chojnacki)
-
+---
pl:
date:
formats:
- default: "%d-%m-%Y"
- short: "%d %b"
- long: "%B %d, %Y"
-
- day_names: [niedziela, poniedziałek, wtorek, środa, czwartek, piątek, sobota]
- abbr_day_names: [nie, pon, wto, śro, czw, pia, sob]
-
- month_names: [~, styczeń, luty, marzec, kwiecień, maj, czerwiec, lipiec, sierpień, wrzesień, październik, listopad, grudzień]
- abbr_month_names: [~, sty, lut, mar, kwi, maj, cze, lip, sie, wrz, paź, lis, gru]
+ default: ! '%d-%m-%Y'
+ short: ! '%d %b'
+ long: ! '%B %d, %Y'
+ day_names:
+ - niedziela
+ - poniedziałek
+ - wtorek
+ - środa
+ - czwartek
+ - piątek
+ - sobota
+ abbr_day_names:
+ - nie
+ - pon
+ - wto
+ - śro
+ - czw
+ - pia
+ - sob
+ month_names:
+ -
+ - styczeń
+ - luty
+ - marzec
+ - kwiecień
+ - maj
+ - czerwiec
+ - lipiec
+ - sierpień
+ - wrzesień
+ - październik
+ - listopad
+ - grudzień
+ abbr_month_names:
+ -
+ - sty
+ - lut
+ - mar
+ - kwi
+ - maj
+ - cze
+ - lip
+ - sie
+ - wrz
+ - paź
+ - lis
+ - gru
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%a, %d %b %Y %H:%M:%S %z"
- short: "%d %b %H:%M"
- long: "%B %d, %Y %H:%M"
- am: "przed południem"
- pm: "po południu"
-
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ short: ! '%d %b %H:%M'
+ long: ! '%B %d, %Y %H:%M'
+ am: przed południem
+ pm: po południu
support:
array:
- words_connector: ", "
- two_words_connector: " i "
- last_word_connector: " oraz "
-
+ words_connector: ! ', '
+ two_words_connector: ! ' i '
+ last_word_connector: ! ' oraz '
select:
- prompt: "Proszę wybrać"
-
+ prompt: Proszę wybrać
number:
format:
- separator: ","
- delimiter: " "
+ separator: ! ','
+ delimiter: ! ' '
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: "%u %n"
- unit: "PLN"
- separator: ","
- delimiter: " "
+ format: ! '%u %n'
+ unit: PLN
+ separator: ! ','
+ delimiter: ! ' '
precision: 2
significant: false
strip_insignificant_zeros: true
-
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "bajt"
- other: "bajty"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: bajt
+ other: bajty
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
+ unit: ''
thousand: Tysiąc
million: Milion
billion: Miliard
trillion: Bilion
quadrillion: Biliard
-
datetime:
distance_in_words:
- half_a_minute: "pół minuty"
+ half_a_minute: pół minuty
less_than_x_seconds:
- one: "mniej niż sekundę"
- few: "mniej niż %{count} sekundy"
- other: "mniej niż %{count} sekund"
+ one: mniej niż sekundę
+ few: mniej niż %{count} sekundy
+ other: mniej niż %{count} sekund
x_seconds:
- one: "1 sekunda"
- few: "%{count} sekundy"
- other: "%{count} sekund"
+ one: 1 sekunda
+ few: ! '%{count} sekundy'
+ other: ! '%{count} sekund'
less_than_x_minutes:
- one: "mniej niż minutę"
- few: "mniej niż %{count} minuty"
- other: "mniej niż %{count} minut"
+ one: mniej niż minutę
+ few: mniej niż %{count} minuty
+ other: mniej niż %{count} minut
x_minutes:
- one: "1 minuta"
- few: "%{count} minuty"
- other: "%{count} minut"
+ one: 1 minuta
+ few: ! '%{count} minuty'
+ other: ! '%{count} minut'
about_x_hours:
- one: "około godziny"
- few: "około %{count} godziny"
- other: "około %{count} godzin"
+ one: około godziny
+ few: około %{count} godziny
+ other: około %{count} godzin
x_days:
- one: "1 dzień"
- few: "%{count} dni"
- other: "%{count} dni"
+ one: 1 dzień
+ few: ! '%{count} dni'
+ other: ! '%{count} dni'
about_x_months:
- one: "około miesiąca"
- few: "około %{count} miesiące"
- other: "około %{count} miesięcy"
+ one: około miesiąca
+ few: około %{count} miesiące
+ other: około %{count} miesięcy
x_months:
- one: "1 miesiąc"
- few: "%{count} miesiące"
- other: "%{count} miesięcy"
+ one: 1 miesiąc
+ few: ! '%{count} miesiące'
+ other: ! '%{count} miesięcy'
about_x_years:
- one: "około rok"
- few: "około %{count} lata"
- other: "około %{count} lat"
+ one: około rok
+ few: około %{count} lata
+ other: około %{count} lat
over_x_years:
- one: "ponad rok"
- few: "ponad %{count} lata"
- other: "ponad %{count} lat"
+ one: ponad rok
+ few: ponad %{count} lata
+ other: ponad %{count} lat
almost_x_years:
- one: "prawie rok"
- few: "prawie %{count} lata"
- other: "prawie %{count} lat"
+ one: prawie rok
+ few: prawie %{count} lata
+ other: prawie %{count} lat
prompts:
- year: "Rok"
- month: "Miesiąc"
- day: "Dzień"
- hour: "Godzina"
- minute: "Minuta"
- second: "Sekundy"
-
+ year: Rok
+ month: Miesiąc
+ day: Dzień
+ hour: Godzina
+ minute: Minuta
+ second: Sekundy
helpers:
select:
- prompt: "Proszę wybrać"
-
+ prompt: Proszę wybrać
submit:
- create: 'Utwórz %{model}'
- update: 'Aktualizuj %{model}'
- submit: 'Zapisz %{model}'
-
+ create: Utwórz %{model}
+ update: Aktualizuj %{model}
+ submit: Zapisz %{model}
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "nie znajduje się na liście dopuszczalnych wartości"
- exclusion: "jest zarezerwowane"
- invalid: "jest nieprawidłowe"
- confirmation: "nie zgadza się z potwierdzeniem"
- accepted: "musi zostać zaakceptowane"
- empty: "nie może być puste"
- blank: "nie może być puste"
- too_long: "jest za długie (maksymalnie %{count} znaków)"
- too_short: "jest za krótkie (przynajmniej %{count} znaków)"
- wrong_length: "ma nieprawidłową długość (powinna wynosić %{count} znaków)"
- not_a_number: "nie jest liczbą"
- not_an_integer: "musi być liczbą całkowitą"
- greater_than: "musi być większe od %{count}"
- greater_than_or_equal_to: "musi być większe lub równe %{count}"
- equal_to: "musi być równe %{count}"
- less_than: "musi być mniejsze od %{count}"
- less_than_or_equal_to: "musi być mniejsze lub równe %{count}"
- odd: "musi być nieparzyste"
- even: "musi być parzyste"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: nie znajduje się na liście dopuszczalnych wartości
+ exclusion: jest zarezerwowane
+ invalid: jest nieprawidłowe
+ confirmation: nie zgadza się z potwierdzeniem
+ accepted: musi zostać zaakceptowane
+ empty: nie może być puste
+ blank: nie może być puste
+ too_long: jest za długie (maksymalnie %{count} znaków)
+ too_short: jest za krótkie (przynajmniej %{count} znaków)
+ wrong_length: ma nieprawidłową długość (powinna wynosić %{count} znaków)
+ not_a_number: nie jest liczbą
+ not_an_integer: musi być liczbą całkowitą
+ greater_than: musi być większe od %{count}
+ greater_than_or_equal_to: musi być większe lub równe %{count}
+ equal_to: musi być równe %{count}
+ less_than: musi być mniejsze od %{count}
+ less_than_or_equal_to: musi być mniejsze lub równe %{count}
+ odd: musi być nieparzyste
+ even: musi być parzyste
activerecord:
errors:
template:
header:
- one: "%{model} nie został zachowany z powodu jednego błędu"
- other: "%{model} nie został zachowany z powodu %{count} błędów"
- body: "Błędy dotyczą następujących pól:"
-
+ one: ! '%{model} nie został zachowany z powodu jednego błędu'
+ other: ! '%{model} nie został zachowany z powodu %{count} błędów'
+ body: ! 'Błędy dotyczą następujących pól:'
messages:
- taken: "zostało już zajęte"
- record_invalid: "Negatywne sprawdzenie poprawności: %{errors}"
- <<: *errors_messages
-
+ inclusion: nie znajduje się na liście dopuszczalnych wartości
+ exclusion: jest zarezerwowane
+ invalid: jest nieprawidłowe
+ confirmation: nie zgadza się z potwierdzeniem
+ accepted: musi zostać zaakceptowane
+ empty: nie może być puste
+ blank: nie może być puste
+ too_long: jest za długie (maksymalnie %{count} znaków)
+ too_short: jest za krótkie (przynajmniej %{count} znaków)
+ wrong_length: ma nieprawidłową długość (powinna wynosić %{count} znaków)
+ not_a_number: nie jest liczbą
+ not_an_integer: musi być liczbą całkowitą
+ greater_than: musi być większe od %{count}
+ greater_than_or_equal_to: musi być większe lub równe %{count}
+ equal_to: musi być równe %{count}
+ less_than: musi być mniejsze od %{count}
+ less_than_or_equal_to: musi być mniejsze lub równe %{count}
+ odd: musi być nieparzyste
+ even: musi być parzyste
+ taken: zostało już zajęte
+ record_invalid: ! 'Negatywne sprawdzenie poprawności: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/pl_fat_free_crm.yml b/config/locales/pl_fat_free_crm.yml
index 9bbf009148..b434823ae1 100644
--- a/config/locales/pl_fat_free_crm.yml
+++ b/config/locales/pl_fat_free_crm.yml
@@ -1,21 +1,15 @@
+---
pl:
language: Polish (Polski)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Wszystko
at: /
here: tutaj
- no_button: 'Nie'
+ no_button: Nie
not_implemented: Nie zaimplementowane.
or: lub
- select_none: '-- Żaden --'
- select_none: '-- Żaden --'
- select_blank: '-- Wybierz --'
- yes_button: 'Tak'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- Żaden --
+ select_blank: -- Wybierz --
+ yes_button: Tak
tab_dashboard: Przegląd
tab_tasks: Zadania
tab_campaigns: Kampanie
@@ -23,22 +17,18 @@ pl:
tab_accounts: Klienci
tab_contacts: Kontakty
tab_opportunities: Szanse
-
admin_tab_users: Użytkownicy
admin_tab_settings: Ustawienia
admin_tab_plugins: Pluginy
-
planned: Planowane
started: Rozpoczęte
on_hold: Wstrzymane
completed: Zakończone
called_off: Odwołane
-
new: Nowi
contacted: Skontaktowani
converted: Pozyskani
rejected: Straceni
-
cold_call: Cold Call
conference: Konferencja
online: Online Marketing
@@ -46,9 +36,7 @@ pl:
self: Własny
web: WWW
word_of_mouth: Marketing szeptany
-
other: Inne
-
prospecting: Prospekt
analysis: Analiza
presentation: Prezentacja
@@ -57,16 +45,13 @@ pl:
final_review: Końcówka
won: Z/Wygrane
lost: Z/Stracone
-
call: Telefon
email: Email
follow_up: Follow-up
lunch: Lunch
meeting: Spotkanie
money: Pieniądze
- presentation: Prezentacja
trip: Podróż
-
overdue: Zaległe
due_asap: ASAP
due_today: Dziś
@@ -75,24 +60,17 @@ pl:
due_next_week: W nast. tygodniu
due_later: Później
due_specific_date: Na dany dzień...
-
completed_today: Dziś
completed_yesterday: Wczoraj
completed_last_week: W tym tygodniu
completed_this_month: W tym miesiącu
completed_last_month: W poprz. miesiącu
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: ostatnią godzinę
one_day: ostatni dzień
two_days: ostatnie dwa dni
one_week: ostatni tydzień
two_weeks: ostatnie dwa tygodnie
one_month: ostatni miesiąc
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -105,98 +83,92 @@ pl:
account:
attributes:
name:
- missing_account_name: "^Proszę podać nazwę klienta."
+ missing_account_name: ^Proszę podać nazwę klienta.
access:
- share_account: "^Proszę podać użytkowników mających dostęp do klienta."
+ share_account: ^Proszę podać użytkowników mających dostęp do klienta.
campaign:
attributes:
name:
- missing_campaign_name: "^Proszę podać nazwę kampanii."
+ missing_campaign_name: ^Proszę podać nazwę kampanii.
ends_on:
- dates_not_in_sequence: "^Data końca kampanii powinna być poźniejsza niż data rozpoczęcia."
+ dates_not_in_sequence: ^Data końca kampanii powinna być poźniejsza niż
+ data rozpoczęcia.
access:
- share_campaign: "^Proszę podać użytkowników mających dostęp do kampanii."
+ share_campaign: ^Proszę podać użytkowników mających dostęp do kampanii.
contact:
attributes:
first_name:
- missing_first_name: "^Proszę podać imię."
+ missing_first_name: ^Proszę podać imię.
last_name:
- missing_last_name: "^Proszę podać nazwisko."
+ missing_last_name: ^Proszę podać nazwisko.
access:
- share_contact: "^Proszę podać użytkowników mających dostęp do kontaktu."
+ share_contact: ^Proszę podać użytkowników mających dostęp do kontaktu.
lead:
attributes:
first_name:
- missing_first_name: "^Proszę podać imię."
+ missing_first_name: ^Proszę podać imię.
last_name:
- missing_last_name: "^Proszę podać nazwisko."
+ missing_last_name: ^Proszę podać nazwisko.
access:
- share_lead: "^Proszę podać użytkowników mających dostęp do leada."
+ share_lead: ^Proszę podać użytkowników mających dostęp do leada.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Proszę podać nazwę szansy."
+ missing_opportunity_name: ^Proszę podać nazwę szansy.
access:
- share_opportunity: "^Proszę podać użytkowników mających dostęp do szansy."
+ share_opportunity: ^Proszę podać użytkowników mających dostęp do szansy.
task:
attributes:
name:
- missing_task_name: "^Proszę podać nazwę zadania."
+ missing_task_name: ^Proszę podać nazwę zadania.
calendar:
- invalid_date: "^Proszę podać prawidłową datę."
+ invalid_date: ^Proszę podać prawidłową datę.
user:
attributes:
username:
- missing_username: "^Proszę podać nazwę uźytkownika."
- username_taken: "^Ten użytkownik juź istnieje."
+ missing_username: ^Proszę podać nazwę uźytkownika.
+ username_taken: ^Ten użytkownik juź istnieje.
email:
- missing_email: "^Proszę podać email."
- email_in_use: "^Istnieje już użytkownik z takim emailem."
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ missing_email: ^Proszę podać email.
+ email_in_use: ^Istnieje już użytkownik z takim emailem.
errors:
template:
header:
- one: "%{model} nie został zachowany z powodu jednego błędu"
- other: "%{model} nie został zachowany z powodu %{count} błędów"
- body: "Błędy dotyczą następujących pól:"
-
+ one: ! '%{model} nie został zachowany z powodu jednego błędu'
+ other: ! '%{model} nie został zachowany z powodu %{count} błędów'
+ body: ! 'Błędy dotyczą następujących pól:'
msg_account_suspended: Konto użytkownika zostało zawieszone.
password_reset_instruction: instrukcje odzyskania hasła
-
- # Controllers.
- #----------------------------------------------------------------------------
msg_account_created: Twoje konto zostało utworzone i oczekuje na akceptację administratora.
msg_account_not_approved: Twoje konto nie zostało jeszcze zaakceptowane.
- msg_asset_deleted: "Usunięto %{value}."
- msg_asset_not_available: "%{value} nie jest dostępne."
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
- msg_assets_not_available: "%{value} nie są dostępne."
- msg_asset_rejected: "%{value} został oznaczony jako Stracony."
- msg_bad_image_file: "^Nie można załadować ani zmienić rozmiaru obrazka."
- msg_cant_create_related: "Nie można utworzyć %{asset}, gdyż powiązane %{related} nie istnieje."
- msg_cant_delete_user: "^Nie można usunąć użytkownika %{value}, gdyż ma powiązane dane."
- msg_cant_do: "Nie można wykonać: %{action} %{asset}, gdyż nie istnieje."
+ msg_asset_deleted: Usunięto %{value}.
+ msg_asset_not_available: ! '%{value} nie jest dostępne.'
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
+ msg_assets_not_available: ! '%{value} nie są dostępne.'
+ msg_asset_rejected: ! '%{value} został oznaczony jako Stracony.'
+ msg_bad_image_file: ^Nie można załadować ani zmienić rozmiaru obrazka.
+ msg_cant_create_related: Nie można utworzyć %{asset}, gdyż powiązane %{related}
+ nie istnieje.
+ msg_cant_delete_user: ^Nie można usunąć użytkownika %{value}, gdyż ma powiązane
+ dane.
+ msg_cant_do: ! 'Nie można wykonać: %{action} %{asset}, gdyż nie istnieje.'
msg_email_not_found: Nie znaleziono użytkownika o tym adresie email.
msg_enter_new_password: Proszę wpisać nowe hasło.
msg_goodbye: Zostałeś wylogowany. Dziękujemy za używanie Fat Free CRM!
- msg_invalid_password: "^Proszę prawidłowo podać aktualne hasło"
+ msg_invalid_password: ^Proszę prawidłowo podać aktualne hasło
msg_invalig_login: Nieprawidłowy użytkownik lub hasło.
- msg_last_login: "Ostatnio zalogowany %{value}."
+ msg_last_login: Ostatnio zalogowany %{value}.
msg_login_needed: Musisz być zalogowany, by mieć dostęp do tej strony.
msg_logout_needed: Musisz być wylogowany, by mieć dostęp do tej strony.
msg_password_changed: Twoje hasło zostało zmienione.
msg_password_not_changed: Twoje hasło pozostało niezmienione.
msg_password_updated: Hasło zostało zaktualizowane.
- msg_pwd_instructions_sent: Instrukcja, jak odzyskać hasło zostały wysłane. Sprawdź Twoją skrzynkę emailową.
+ msg_pwd_instructions_sent: Instrukcja, jak odzyskać hasło zostały wysłane. Sprawdź
+ Twoją skrzynkę emailową.
msg_require_admin: Musisz być Administratorem, by otworzyć tę stronę.
msg_successful_signup: Rejestracja udana, witaj w Fat Free CRM!
msg_welcome: Witaj w Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": kwoty ważonej
+ option_amount*probability: kwoty ważonej
activity_options: Pokaż %{models} zmieniane przez %{user} przez %{period}.
all_users: wszystkich
option_after: po nazwisku
@@ -204,7 +176,7 @@ pl:
option_all_users: wszystkich
option_amount: kwoty
option_before: przed nazwiskiem
- option_brief: skróconym
+ option_brief: skróconym
option_closes_on: daty zamknięcia
option_company: firmy
option_created_at: daty utworzenia
@@ -221,12 +193,9 @@ pl:
option_target_leads: zakładanych leadów
option_target_revenue: zakładanej sprzedaży
option_updated_at: daty aktualizacji
- show_per_page: Pokaż %{number} %{models}/stronę w widoku %{fmt}.
+ show_per_page: Pokaż %{number} %{models}/stronę w widoku %{fmt}.
sort_by: Sortuj %{models} wg %{field}.
- sort_by_displaying: Sortuj %{models} wg %{field} wyświetlając imię %{position}.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Sortuj %{models} wg %{field} wyświetlając imię %{position}.
aim: AOL IM
already_signed_up: Już zarejestrowany?
alt_email: Alternatywny email
@@ -236,12 +205,12 @@ pl:
contact_info: Informacje kontaktowe
current_password: Aktualne hasło
edit_profile: Zmień dane
- # email: Email # <-- Already defined as the task type if Settings.
first_name: Imię
google: Google IM
gravatar_help: Nie wiesz, co to są gravatary? Dowiedz się
image_file: Obrazek
- image_help: Obrazek, który dołączysz, zostanie automatycznie dopasowany do wymiarów 75x75. Obrazek może być w formacie GIF, JPG lub PNG.
+ image_help: Obrazek, który dołączysz, zostanie automatycznie dopasowany do wymiarów
+ 75x75. Obrazek może być w formacie GIF, JPG lub PNG.
job_title: Stanowisko
last_name: Nazwisko
login_now_link: Zaloguj się!
@@ -262,19 +231,14 @@ pl:
user: Użytkownik
username: Nazwa użytkownika
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Zapomniałem hasła
login: Zaloguj
no_account: Czy posiadasz konto?
remember_me: Pamiętaj mnie na tym komputerze
sign_up_now: Zarejestruj się!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: Klient
- account_permissions_intro: Domyślnie tylko Ty będziesz miał dostęp do klienta. Można to zmienić później.
+ account_permissions_intro: Domyślnie tylko Ty będziesz miał dostęp do klienta. Można
+ to zmienić później.
account_small: klient
accounts: Klientów
accounts_options: Opcje
@@ -297,9 +261,6 @@ pl:
share_with: Udostępnij następującym użytkownikom
shipping_address: Adres wysyłki
website: Website
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Bieżące
actual_performance: Bieżący postęp
budget: Budżet
@@ -314,7 +275,7 @@ pl:
campaigns_small: kampanie
conversion: Konwersja
conversion_label: Konwersja (%)
- conversion_number: "%{value} konwersja"
+ conversion_number: ! '%{value} konwersja'
create_campaign: Dodaj kampanię
end_date: Data zakończenia
finished_on: zakończona %{value}
@@ -322,11 +283,13 @@ pl:
no_start_date: brak daty rozpoczęcia
number_of_leads: Liczba leadów
objectives: Cele
- objectives_help: Proszę podać planowaną liczbę leadów, oczekiwaną konwersję leads/szanse, planowaną sprzedaż otaz budżet kampanii. Te dane umoźliwią Ci śledzenie postępu kampanii.
+ objectives_help: Proszę podać planowaną liczbę leadów, oczekiwaną konwersję leads/szanse,
+ planowaną sprzedaż otaz budżet kampanii. Te dane umoźliwią Ci śledzenie postępu
+ kampanii.
objectives_small: cele kampanii
revenue: Sprzedaż
revenue_label: Sprzedaż (zł)
- revenue_number: "%{value} sprzedaży"
+ revenue_number: ! '%{value} sprzedaży'
save_campaign: Zapisz kampanię
start_date: Data rozpoczęcia
started_ago: rozpoczęta %{value} temu
@@ -336,9 +299,6 @@ pl:
total_campaigns: Wszystkich kampanii
was_supposed_to_finish: miała zakończyć się %{value}
was_supposed_to_start: miała rozpocząć się %{time_ago} temu %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Inny
blog: Website/Blog
contact: Kontakt
@@ -348,41 +308,45 @@ pl:
contacts_small: kontakty
create_contact: Dodaj kontakt
department: Dział
- department_small: '%{value} dział'
+ department_small: ! '%{value} dział'
do_not_call: Nie dzwonić
extra_info: Dodatkowe info
extra_info_small: dodatkowy kontakt
facebook: Facebook
linked_in: LinkedIn
myself: mnie
-
- permissions_intro_private: Domyślnie tylko Ty będziesz miał dostęp do %{value}. Można to poźniej zmienić.
- permissions_intro_public: Domyślnie wszyscy użytkownicy będą mieli dostęp do %{value}. Można to poźniej zmienić.
- permissions_intro_shared: Domyślnie tylko wybrani użytkownicy będą mieli dostęp do %{value}. Można to poźniej zmienić.
-
+ permissions_intro_private: Domyślnie tylko Ty będziesz miał dostęp do %{value}.
+ Można to poźniej zmienić.
+ permissions_intro_public: Domyślnie wszyscy użytkownicy będą mieli dostęp do %{value}.
+ Można to poźniej zmienić.
+ permissions_intro_shared: Domyślnie tylko wybrani użytkownicy będą mieli dostęp
+ do %{value}. Można to poźniej zmienić.
referred_by: Polecony przez
referred_by_small: polecony przez
save_contact: Zapisz kontakt
twitter: Twitter
web_presence: Web
web_presence_small: web
- works_at: "%{job_title} / %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} / %{company}'
convert: Konwertuj
convert_lead: Konwertuj lead
- convert_lead_permissions_intro: Ograniczenia dostępu będą skopiowane z leada. Moźesz zmienić to później.
- convert_lead_text: Po konwersji lead %{value} stanie się kontaktem powiązanym z istniejącym lub nowo utworzonym klientem. Status leada zostanie automatycznie ustawiony na Pozyskany.
+ convert_lead_permissions_intro: Ograniczenia dostępu będą skopiowane z leada. Moźesz
+ zmienić to później.
+ convert_lead_text: Po konwersji lead %{value} stanie się kontaktem powiązanym z
+ istniejącym lub nowo utworzonym klientem. Status leada zostanie automatycznie
+ ustawiony na Pozyskany.
create_lead: Dodaj lead
- create_opp_for_contact: Opcjonalnie możesz dodać szansę do %{value} podając nazwę, aktualną fazę, zakładaną datę zamknięcia, prawdopodobieństwo sprzedaży, kwotę sprzedaży i oferowany rabat.
+ create_opp_for_contact: Opcjonalnie możesz dodać szansę do %{value} podając nazwę,
+ aktualną fazę, zakładaną datę zamknięcia, prawdopodobieństwo sprzedaży, kwotę
+ sprzedaży i oferowany rabat.
lead: Lead
lead_info_small: lead
-
- lead_permissions_intro_private: Domyślnie prawa dostępu zostaną skopiowane z kampanii albo tylko Ty będziesz miał dostęp. Możesz zmienić to później.
- lead_permissions_intro_public: Domyślnie prawa dostępu zostaną skopiowane z kampanii albo wszyscy użytkownicy będą mieli dostęp. Możesz zmienić to później.
- lead_permissions_intro_shared: Domyślnie prawa dostępu zostaną skopiowane z kampanii albo tylko wybrani użytkownicy będą mieli dostęp. Możesz zmienić to później.
-
+ lead_permissions_intro_private: Domyślnie prawa dostępu zostaną skopiowane z kampanii
+ albo tylko Ty będziesz miał dostęp. Możesz zmienić to później.
+ lead_permissions_intro_public: Domyślnie prawa dostępu zostaną skopiowane z kampanii
+ albo wszyscy użytkownicy będą mieli dostęp. Możesz zmienić to później.
+ lead_permissions_intro_shared: Domyślnie prawa dostępu zostaną skopiowane z kampanii
+ albo tylko wybrani użytkownicy będą mieli dostęp. Możesz zmienić to później.
lead_small: lead
lead_status_small: status leada
lead_summary: Lead
@@ -397,20 +361,17 @@ pl:
source: Źródło
status: Status
total_leads: Leady razem
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Kwota
close_date: Data zamknięcia
closed_ago_on: zamknięta %{time_ago} temu, %{date}
closes_today: planowane zamknięcie - dziś!
- closing_date: "data zamknięcia: %{value}"
+ closing_date: ! 'data zamknięcia: %{value}'
create_opportunity: Dodaj szansę
currency: (zł)
days_late: Opóźniona o
days_left: Pozostało dni
discount: Rabat
- discount_number: "%{value} rabatu"
+ discount_number: ! '%{value} rabatu'
expected_to_close: planowane zamknięcie za %{time}, %{date}
from: od
no_closing_date: brak planowanej daty zamknięcia
@@ -421,7 +382,7 @@ pl:
opportunity: Szansa
opportunity_small: szansa
opportunity_summary: Szansa
- opportunity_summary_text: "%{amount} z %{discount} rabatu i %{probability} prawdopodobieństwem"
+ opportunity_summary_text: ! '%{amount} z %{discount} rabatu i %{probability} prawdopodobieństwem'
past_due: planowana data zakończenia minęła %{value} temu
probability: Prawdopodob.
probability_number: i %{value} prawdopodobieństwa
@@ -429,9 +390,6 @@ pl:
stage: Faza
total_opportunities: Szanse razem
weighted_amount: Kwota ważona
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: Przypisz do
assigned_tab: Przypisane
assigned_tasks: Przypisane zadania
@@ -443,13 +401,13 @@ pl:
due: Termin
feel_free: Możesz
move_to: przesuń na
- no_tasks: "Nie masz żadnych %{value} zadań"
+ no_tasks: Nie masz żadnych %{value} zadań
no_tasks_pending: otwartych
no_tasks_assigned: przypisanych
no_tasks_completed: zakończonych
pending_tab: Otwarte
pending_tasks: otwarte zadania
- related: 'pow.:'
+ related: ! 'pow.:'
save_task: Zapisz zadanie
task_assigned: Zadanie zostało przypisane do %{value}
task_assigned_to: i przypisane do %{value}
@@ -469,9 +427,6 @@ pl:
total_tasks: Razem %{value}
view_assigned_tasks: zobacz przypisane zadania
view_pending_tasks: zobacz otwarte zadania
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: skomentował/a
action_completed: ukończył/a
action_created: utworzył/a
@@ -492,9 +447,6 @@ pl:
subject_lead: lead
subject_opportunity: szansę
subject_task: zadanie
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Dodaj notatkę
save_note: Zapisz notatkę
add_note_help: Dodaj nową notatkę...
@@ -505,14 +457,14 @@ pl:
close_form: Zamknij formularz
confirm_delete: Czy jesteś pewien, że chcesz usunąć %{value}?
copy_permissions: Skopiuj prawa dostępu do %{value}
- could_not_find: "Nie znaleziono %{value}. Możesz"
- could_not_find_matching: "Nie znaleziono pasującego %{value}"
+ could_not_find: Nie znaleziono %{value}. Możesz
+ could_not_find_matching: Nie znaleziono pasującego %{value}
create_new: dodaj nowego
select_existing: wybierz istniejącego
delete: Usuń
discard: Anuluj
edit: Zmień
- items_total: '%{count} razem.'
+ items_total: ! '%{count} razem.'
less: Mniej...
me: mnie
more: Więcej...
@@ -525,16 +477,13 @@ pl:
please_retry: proszę spróbować innego wyszukania.
recent_items: Ostatnio oglądane
search_assets: Przeszukaj %{value}
- time_ago: "%{value} temu"
+ time_ago: ! '%{value} temu'
background_info: Informacje ogólne
address: Adres
city: Miasto
zipcode: Kod pocztowy
state: stan
country: kraj
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: O produkcie
about_dev_group: Forum dla programistów (pomóż ulepszać FFCRM!)
about_features: Zgłaszanie życzeń i błędów
@@ -543,35 +492,24 @@ pl:
about_ffc_version: Fat Free CRM wersja
about_home_page: Strona główna
about_project_page: Strona projektu
- about_thank_you: Dziękujemy za wybranie Fat Free CRM! Mamy nadzieję, że nasze oprogramowanie spełnia Twoje oczekiwania.
+ about_thank_you: Dziękujemy za wybranie Fat Free CRM! Mamy nadzieję, że nasze oprogramowanie
+ spełnia Twoje oczekiwania.
about_twitter: Informacje o aktualizacjach (Twitter)
about_user_group: Forum dla użytkowników
admin: Admin
logout: Wyloguj
quick_find: Szybkie szukanie
welcome: Witamy
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Aktualizacja komentarza
show: Pokaż
update: Aktualizuj
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Wpisz swoje hasło i potwierdź je w drugim polu.
- password_intro: Proszę podaj swój adres email, a instrukje dotyczące odzyskania konta zostaną tam wysłane.
+ password_intro: Proszę podaj swój adres email, a instrukje dotyczące odzyskania
+ konta zostaną tam wysłane.
reset_password: Odzyskaj hasło
update_password_and_login: Zmień hasło i/lub nazwę użytkownika
-
- # Views -> Admin
- #----------------------------------------------------------------------------
- # TODO
back_to_crm: Back to Fat Free CRM
crm_admin_page: Fat Free CRM Administration
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Akceptuj
create_user: Dodaj użytkownika
last_seen: ostatnio widziany %{value} temu
@@ -582,9 +520,10 @@ pl:
user_active: Aktywny
user_admin: Admin
user_awaits_approval: oczekuje na akceptację
- user_confirm_delete: Użytkownika można usunąć tylko wtedy, gdy nie ma powiązanych danych.
+ user_confirm_delete: Użytkownika można usunąć tylko wtedy, gdy nie ma powiązanych
+ danych.
user_is_admin: Użytkownik jest Adminem
- user_never_logged_in: "jeszcze się nie logował"
+ user_never_logged_in: jeszcze się nie logował
user_signed_up: Zarejestrowany
user_signed_up_on: zarejestrowany %{value}
user_since: użytkownik od %{value}
@@ -592,49 +531,39 @@ pl:
user_suspended_on: zawieszony %{value}
users: Użytkownicy
users_small: użytkowników
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - E-mail Dodano - %{subject}
dropbox_notification_intro: Pomyślnie dodane e-mail wysłanych do DropBox
dropbox_notification_to: Dodano do
subject: Temat
body: Ciało
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment' # TODO
- other: '%{count} comments' # TODO
- contact:
- one: '1 kontakt'
- few: '%{count} kontakty'
- other: '%{count} kontaktów'
+ one: 1 comment
+ other: ! '%{count} comments'
+ contact:
+ one: 1 kontakt
+ few: ! '%{count} kontakty'
+ other: ! '%{count} kontaktów'
opportunity:
- one: '1 szansa'
- few: '%{count} szanse'
- other: '%{count} szans'
+ one: 1 szansa
+ few: ! '%{count} szanse'
+ other: ! '%{count} szans'
lead:
- one: '1 lead'
- few: '%{count} leady'
- other: '%{count} leadów'
+ one: 1 lead
+ few: ! '%{count} leady'
+ other: ! '%{count} leadów'
day:
- one: '1 dzień'
- other: '%{count} dni'
+ one: 1 dzień
+ other: ! '%{count} dni'
login:
- one: '1 logowanie'
- few: '%{count} logowania'
- other: '%{count} logowań'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 logowanie
+ few: ! '%{count} logowania'
+ other: ! '%{count} logowań'
date:
formats:
- mmddyyyy: "%d.%m.%Y"
- mmdd: "%e %b"
- mmddyy: "%e %b %Y"
-
+ mmddyyyy: ! '%d.%m.%Y'
+ mmdd: ! '%e %b'
+ mmddyy: ! '%e %b %Y'
time:
formats:
- mmddhhss: "%e %b o %H:%M"
+ mmddhhss: ! '%e %b o %H:%M'
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 69355e5ce3..85bb04e7cc 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -1,90 +1,115 @@
-# encoding: UTF-8
-# pt-BR translations for Ruby on Rails
-"pt-BR":
- # formatos de data e hora
+---
+pt-BR:
date:
formats:
- default: "%d/%m/%Y"
- short: "%d de %B"
- long: "%d de %B de %Y"
-
- day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado]
- abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb]
-
- month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro]
- abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez]
+ default: ! '%d/%m/%Y'
+ short: ! '%d de %B'
+ long: ! '%d de %B de %Y'
+ day_names:
+ - Domingo
+ - Segunda
+ - Terça
+ - Quarta
+ - Quinta
+ - Sexta
+ - Sábado
+ abbr_day_names:
+ - Dom
+ - Seg
+ - Ter
+ - Qua
+ - Qui
+ - Sex
+ - Sáb
+ month_names:
+ -
+ - Janeiro
+ - Fevereiro
+ - Março
+ - Abril
+ - Maio
+ - Junho
+ - Julho
+ - Agosto
+ - Setembro
+ - Outubro
+ - Novembro
+ - Dezembro
+ abbr_month_names:
+ -
+ - Jan
+ - Fev
+ - Mar
+ - Abr
+ - Mai
+ - Jun
+ - Jul
+ - Ago
+ - Set
+ - Out
+ - Nov
+ - Dez
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%A, %d de %B de %Y, %H:%M h"
- short: "%d/%m, %H:%M h"
- long: "%A, %d de %B de %Y, %H:%M h"
+ default: ! '%A, %d de %B de %Y, %H:%M h'
+ short: ! '%d/%m, %H:%M h'
+ long: ! '%A, %d de %B de %Y, %H:%M h'
am: ''
pm: ''
-
- # Usado no Array.to_sentence
support:
array:
- words_connector: ", "
- two_words_connector: " e "
- last_word_connector: " e "
-
+ words_connector: ! ', '
+ two_words_connector: ! ' e '
+ last_word_connector: ! ' e '
select:
- prompt: "Por favor selecione"
-
+ prompt: Por favor selecione
number:
format:
- separator: ','
- delimiter: '.'
+ separator: ! ','
+ delimiter: .
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: '%u %n'
- unit: 'R$'
- separator: ','
- delimiter: '.'
+ format: ! '%u %n'
+ unit: R$
+ separator: ! ','
+ delimiter: .
precision: 2
significant: false
strip_insignificant_zeros: false
-
percentage:
format:
- delimiter: '.'
-
+ delimiter: .
precision:
format:
- delimiter: '.'
-
+ delimiter: .
human:
format:
- delimiter: '.'
+ delimiter: .
precision: 2
significant: true
strip_insignificant_zeros: true
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
- # number_to_human()
- # new in rails 3: please add to other locales
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
- thousand: "mil"
+ unit: ''
+ thousand: mil
million:
one: milhão
other: milhões
@@ -97,103 +122,111 @@
quadrillion:
one: quatrilhão
other: quatrilhões
-
- # distancia do tempo em palavras
datetime:
distance_in_words:
- half_a_minute: 'meio minuto'
+ half_a_minute: meio minuto
less_than_x_seconds:
- one: 'menos de 1 segundo'
- other: 'menos de %{count} segundos'
+ one: menos de 1 segundo
+ other: menos de %{count} segundos
x_seconds:
- one: '1 segundo'
- other: '%{count} segundos'
+ one: 1 segundo
+ other: ! '%{count} segundos'
less_than_x_minutes:
- one: 'menos de um minuto'
- other: 'menos de %{count} minutos'
+ one: menos de um minuto
+ other: menos de %{count} minutos
x_minutes:
- one: '1 minuto'
- other: '%{count} minutos'
+ one: 1 minuto
+ other: ! '%{count} minutos'
about_x_hours:
- one: 'aproximadamente 1 hora'
- other: 'aproximadamente %{count} horas'
+ one: aproximadamente 1 hora
+ other: aproximadamente %{count} horas
x_days:
- one: '1 dia'
- other: '%{count} dias'
+ one: 1 dia
+ other: ! '%{count} dias'
about_x_months:
- one: 'aproximadamente 1 mês'
- other: 'aproximadamente %{count} meses'
+ one: aproximadamente 1 mês
+ other: aproximadamente %{count} meses
x_months:
- one: '1 mês'
- other: '%{count} meses'
+ one: 1 mês
+ other: ! '%{count} meses'
about_x_years:
- one: 'aproximadamente 1 ano'
- other: 'aproximadamente %{count} anos'
+ one: aproximadamente 1 ano
+ other: aproximadamente %{count} anos
over_x_years:
- one: 'mais de 1 ano'
- other: 'mais de %{count} anos'
+ one: mais de 1 ano
+ other: mais de %{count} anos
almost_x_years:
- one: 'quase 1 ano'
- other: 'quase %{count} anos'
+ one: quase 1 ano
+ other: quase %{count} anos
prompts:
- year: "Ano"
- month: "Mês"
- day: "Dia"
- hour: "Hora"
- minute: "Minuto"
- second: "Segundo"
-
+ year: Ano
+ month: Mês
+ day: Dia
+ hour: Hora
+ minute: Minuto
+ second: Segundo
helpers:
select:
- prompt: "Por favor selecione"
-
+ prompt: Por favor selecione
submit:
- create: 'Criar %{model}'
- update: 'Atualizar %{model}'
- submit: 'Salvar %{model}'
-
+ create: Criar %{model}
+ update: Atualizar %{model}
+ submit: Salvar %{model}
errors:
- format: "%{attribute} %{message}"
-
+ format: ! '%{attribute} %{message}'
template:
header:
- one: "Não foi possível gravar %{model}: 1 erro"
- other: "Não foi possível gravar %{model}: %{count} erros."
- body: "Por favor, verifique o(s) seguinte(s) campo(s):"
-
- messages: &errors_messages
- inclusion: "não está incluído na lista"
- exclusion: "não está disponível"
- invalid: "não é válido"
- confirmation: "não está de acordo com a confirmação"
- accepted: "deve ser aceito"
- empty: "não pode ficar vazio"
- blank: "não pode ficar em branco"
- too_long: "é muito longo (máximo: %{count} caracteres)"
- too_short: "é muito curto (mínimo: %{count} caracteres)"
- wrong_length: "não possui o tamanho esperado (%{count} caracteres)"
- not_a_number: "não é um número"
- not_an_integer: "não é um número inteiro"
- greater_than: "deve ser maior que %{count}"
- greater_than_or_equal_to: "deve ser maior ou igual a %{count}"
- equal_to: "deve ser igual a %{count}"
- less_than: "deve ser menor que %{count}"
- less_than_or_equal_to: "deve ser menor ou igual a %{count}"
- odd: "deve ser ímpar"
- even: "deve ser par"
-
+ one: ! 'Não foi possível gravar %{model}: 1 erro'
+ other: ! 'Não foi possível gravar %{model}: %{count} erros.'
+ body: ! 'Por favor, verifique o(s) seguinte(s) campo(s):'
+ messages:
+ inclusion: não está incluído na lista
+ exclusion: não está disponível
+ invalid: não é válido
+ confirmation: não está de acordo com a confirmação
+ accepted: deve ser aceito
+ empty: não pode ficar vazio
+ blank: não pode ficar em branco
+ too_long: ! 'é muito longo (máximo: %{count} caracteres)'
+ too_short: ! 'é muito curto (mínimo: %{count} caracteres)'
+ wrong_length: não possui o tamanho esperado (%{count} caracteres)
+ not_a_number: não é um número
+ not_an_integer: não é um número inteiro
+ greater_than: deve ser maior que %{count}
+ greater_than_or_equal_to: deve ser maior ou igual a %{count}
+ equal_to: deve ser igual a %{count}
+ less_than: deve ser menor que %{count}
+ less_than_or_equal_to: deve ser menor ou igual a %{count}
+ odd: deve ser ímpar
+ even: deve ser par
activerecord:
errors:
template:
header:
- one: "Não foi possível gravar %{model}: 1 erro"
- other: "Não foi possível gravar %{model}: %{count} erros."
- body: "Por favor, verifique o(s) seguinte(s) campo(s):"
-
+ one: ! 'Não foi possível gravar %{model}: 1 erro'
+ other: ! 'Não foi possível gravar %{model}: %{count} erros.'
+ body: ! 'Por favor, verifique o(s) seguinte(s) campo(s):'
messages:
- taken: "já está em uso"
- record_invalid: "A validação falhou: %{errors}"
- <<: *errors_messages
-
+ inclusion: não está incluído na lista
+ exclusion: não está disponível
+ invalid: não é válido
+ confirmation: não está de acordo com a confirmação
+ accepted: deve ser aceito
+ empty: não pode ficar vazio
+ blank: não pode ficar em branco
+ too_long: ! 'é muito longo (máximo: %{count} caracteres)'
+ too_short: ! 'é muito curto (mínimo: %{count} caracteres)'
+ wrong_length: não possui o tamanho esperado (%{count} caracteres)
+ not_a_number: não é um número
+ not_an_integer: não é um número inteiro
+ greater_than: deve ser maior que %{count}
+ greater_than_or_equal_to: deve ser maior ou igual a %{count}
+ equal_to: deve ser igual a %{count}
+ less_than: deve ser menor que %{count}
+ less_than_or_equal_to: deve ser menor ou igual a %{count}
+ odd: deve ser ímpar
+ even: deve ser par
+ taken: já está em uso
+ record_invalid: ! 'A validação falhou: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
diff --git a/config/locales/pt-BR_fat_free_crm.yml b/config/locales/pt-BR_fat_free_crm.yml
index 6ac659b75f..d13ddfb0d4 100644
--- a/config/locales/pt-BR_fat_free_crm.yml
+++ b/config/locales/pt-BR_fat_free_crm.yml
@@ -1,20 +1,15 @@
+---
pt-BR:
language: Português do Brasil
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Tudo
at: at
here: aqui
- no_button: 'Não'
+ no_button: Não
not_implemented: Ainda não implementado.
or: ou
- select_blank: '-- Selecione --'
- select_none: '-- Nenhum --'
- yes_button: 'Sim'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_blank: -- Selecione --
+ select_none: -- Nenhum --
+ yes_button: Sim
tab_dashboard: Dashboard
tab_tasks: Tarefas
tab_campaigns: Campanhas
@@ -22,22 +17,18 @@ pt-BR:
tab_accounts: Contas
tab_contacts: Contatos
tab_opportunities: Oportunidades
-
admin_tab_users: Usuários
admin_tab_settings: Configurações
admin_tab_plugins: Plugins
-
planned: Planejado
started: Iniciado
on_hold: Em espera
completed: Terminado
called_off: Called Off
-
new: Novo
contacted: Contactado
converted: Convertido
rejected: Rejeitado
-
cold_call: Cold Call
conference: Conferência
online: Marketing Online
@@ -46,7 +37,6 @@ pt-BR:
web: Website
word_of_mouth: Boca-a-Boca
other: Outros
-
prospecting: Prospecção
analysis: Análise
presentation: Apresentação
@@ -55,16 +45,13 @@ pt-BR:
final_review: Revisão final
won: Fechado/Conquistado
lost: Fechado/Perdido
-
call: Ligação
email: Email
follow_up: Follow-up
lunch: Almoço
meeting: Encontro
money: Dinheiro
- presentation: Apresentação
trip: Viagem
-
overdue: Overdue
due_asap: Assim que possível
due_today: Hoje
@@ -72,25 +59,18 @@ pt-BR:
due_this_week: Esta semana
due_next_week: Próxima semana
due_later: Depois
- due_specific_date: Em Data Específica... # ?!
-
+ due_specific_date: Em Data Específica...
completed_today: Hoje
completed_yesterday: Ontem
completed_last_week: Semana passada
completed_this_month: Este mês
completed_last_month: Mês passado
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: Uma hora
one_day: Um dia
two_days: Dois dias
one_week: Uma semana
two_weeks: Duas semanas
one_month: Um mês
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -103,83 +83,86 @@ pt-BR:
account:
attributes:
name:
- missing_account_name: "^Por favor, informe um nome para a conta"
+ missing_account_name: ^Por favor, informe um nome para a conta
access:
- share_account: "^Por favor, informe usuários com quem desejas compartilhar esta conta."
+ share_account: ^Por favor, informe usuários com quem desejas compartilhar
+ esta conta.
campaign:
attributes:
name:
- missing_campaign_name: "^Por favor, informe uma node para a campanha."
+ missing_campaign_name: ^Por favor, informe uma node para a campanha.
ends_on:
- dates_not_in_sequence: "^Por favor, certifique-se que a data de término da campanha seja posterior a data de início."
+ dates_not_in_sequence: ^Por favor, certifique-se que a data de término
+ da campanha seja posterior a data de início.
access:
- share_campaign: "^Por favor, informe usuários com quem desejas compartilhar esta campanha."
+ share_campaign: ^Por favor, informe usuários com quem desejas compartilhar
+ esta campanha.
contact:
attributes:
first_name:
- missing_first_name: "^Por favor, informe o primeiro nome."
+ missing_first_name: ^Por favor, informe o primeiro nome.
last_name:
- missing_last_name: "^Por favor, informe o último nome."
+ missing_last_name: ^Por favor, informe o último nome.
access:
- share_contact: "^Por favor, informe usuários com quem desejas compartilhar este contato."
+ share_contact: ^Por favor, informe usuários com quem desejas compartilhar
+ este contato.
lead:
attributes:
first_name:
- missing_first_name: "^Por favor, informe o primeiro nome."
+ missing_first_name: ^Por favor, informe o primeiro nome.
last_name:
- missing_last_name: "^Por favor, informe o último nome."
+ missing_last_name: ^Por favor, informe o último nome.
access:
- share_lead: "^Por favor, informe usuários com quem desejas compartilhar este lead."
+ share_lead: ^Por favor, informe usuários com quem desejas compartilhar
+ este lead.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Por favor, informe um nome para a oportunidade."
+ missing_opportunity_name: ^Por favor, informe um nome para a oportunidade.
access:
- share_opportunity: "^Por favor, informe usuários com quem desejas compartilhar esta oportunidade."
+ share_opportunity: ^Por favor, informe usuários com quem desejas compartilhar
+ esta oportunidade.
task:
attributes:
name:
- missing_task_name: "^Por favor, informe um nome para a tarefa."
+ missing_task_name: ^Por favor, informe um nome para a tarefa.
calendar:
- invalid_date: "^Por favor, informe uma data válida."
+ invalid_date: ^Por favor, informe uma data válida.
user:
attributes:
username:
- missing_username: "^Por favor, informe o nome do usuário."
- username_taken: "^Este usuário já está sendo usado."
+ missing_username: ^Por favor, informe o nome do usuário.
+ username_taken: ^Este usuário já está sendo usado.
email:
- missing_email: "^Por favor, informe o e-mail."
- email_in_use: "^Já existe um usuário com este e-mail."
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ missing_email: ^Por favor, informe o e-mail.
+ email_in_use: ^Já existe um usuário com este e-mail.
errors:
template:
header:
- one: "Não foi possível gravar %{model}: 1 erro"
- other: "Não foi possível gravar %{model}: %{count} erros."
- body: "Por favor, verifique o(s) seguinte(s) campo(s):"
-
+ one: ! 'Não foi possível gravar %{model}: 1 erro'
+ other: ! 'Não foi possível gravar %{model}: %{count} erros.'
+ body: ! 'Por favor, verifique o(s) seguinte(s) campo(s):'
msg_account_suspended: A conta do usuário foi suspensa.
password_reset_instruction: Instruções de redefinição da senha
-
- # Controllers.
- #----------------------------------------------------------------------------
- msg_account_created: Sua conta foi criada e está aguardando a aprovação do administrador do sistema.
+ msg_account_created: Sua conta foi criada e está aguardando a aprovação do administrador
+ do sistema.
msg_account_not_approved: Sua conta ainda não foi aprovada.
- msg_asset_deleted: "%{value} foi removido."
+ msg_asset_deleted: ! '%{value} foi removido.'
msg_asset_not_available: Este(a) %{value} não está mais disponível.
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
msg_assets_not_available: Estes(as) %{value} não estão mais disponíveis.
- msg_asset_rejected: "%{value} foi rejeitado."
- msg_bad_image_file: "^Não foi possível enviar ou redimensionar a imagem que você escolheu."
- msg_cant_create_related: "Impossível criar %{asset} já que %{related} não está mais disponível."
- msg_cant_delete_user: "^Não foi possível remover o usuário já que %{value} tem relacionamentos ativos."
- msg_cant_do: "Impossível %{action} o %{asset} já que não está mais disponível."
+ msg_asset_rejected: ! '%{value} foi rejeitado.'
+ msg_bad_image_file: ^Não foi possível enviar ou redimensionar a imagem que você
+ escolheu.
+ msg_cant_create_related: Impossível criar %{asset} já que %{related} não está mais
+ disponível.
+ msg_cant_delete_user: ^Não foi possível remover o usuário já que %{value} tem relacionamentos
+ ativos.
+ msg_cant_do: Impossível %{action} o %{asset} já que não está mais disponível.
msg_email_not_found: Nenhum usuário encontrado com este e-mail.
msg_enter_new_password: Por favor, informe sua nova senha.
msg_goodbye: Você saiu do sistema. Obrigado por usar o Fat Free CRM!
- msg_invalid_password: "^Por favor informe uma senha válida"
+ msg_invalid_password: ^Por favor informe uma senha válida
msg_invalig_login: Usuário e senha inválida.
msg_last_login: Você entrou no sistema pela última vez em %{value}.
msg_login_needed: Você precisa entrar no sistema para acessar esta página.
@@ -187,15 +170,14 @@ pt-BR:
msg_password_changed: Sua senha mudou.
msg_password_not_changed: Sua senha não mudou.
msg_password_updated: A senha foi atualizada com sucesso.
- msg_pwd_instructions_sent: Instruções para redefinir a sua senha foram enviadas a você. Por favor, verifique seu e-mail.
+ msg_pwd_instructions_sent: Instruções para redefinir a sua senha foram enviadas
+ a você. Por favor, verifique seu e-mail.
msg_require_admin: É preciso ser um administrador para acessar esta página.
msg_successful_signup: Cadastrado com sucesso, bem vindo(a) ao Fat Free CRM!
msg_welcome: Bem vindo(a) ao Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": weighted amount
- activity_options: Exibir atividades em %{models} feitas por %{user} no(s) último(s) %{period}.
+ option_amount*probability: weighted amount
+ activity_options: Exibir atividades em %{models} feitas por %{user} no(s) último(s)
+ %{period}.
all_users: todos os usuários
option_after: depois
option_all: todos
@@ -219,12 +201,10 @@ pt-BR:
option_target_leads: leads alvo
option_target_revenue: receita alvo
option_updated_at: data de atualização
- show_per_page: Exibir %{number} %{models} por página usando o formato %{fmt}.
+ show_per_page: Exibir %{number} %{models} por página usando o formato %{fmt}.
sort_by: Sort %{models} by %{field}.
- sort_by_displaying: Ordenar %{models} por %{field} exibindo o primeiro nome %{position} do último nome.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Ordenar %{models} por %{field} exibindo o primeiro nome %{position}
+ do último nome.
aim: AOL IM
already_signed_up: Já é cadastrado?
alt_email: Email alternativo
@@ -234,12 +214,12 @@ pt-BR:
contact_info: Informações para contato
current_password: Senha atual
edit_profile: Editar perfil
- # email: Email # <-- Already defined as the task type if Settings.
first_name: Primeiro nome
google: Google IM
gravatar_help: Não conhece o Gravatar? Saiba mais sobre
image_file: Arquivo de imagem
- image_help: A imagem que você enviar será automaticamente redimensionada para 75 x 75 pixels. Os formatos suportados são GIF, JPG, and PNG.
+ image_help: A imagem que você enviar será automaticamente redimensionada para 75
+ x 75 pixels. Os formatos suportados são GIF, JPG, and PNG.
job_title: Título
last_name: Último nome
login_now_link: Entre agora!
@@ -260,19 +240,14 @@ pt-BR:
user: Usuário
username: Usuário
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Esqueceu a senha
login: Login
no_account: Não tem uma conta?
remember_me: Me lembrar
sign_up_now: Cadastre-se Agora!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: Conta
- account_permissions_intro: Por padrão, somente você terá acesso a conta. Você pode mudar as permissões da conta depois.
+ account_permissions_intro: Por padrão, somente você terá acesso a conta. Você pode
+ mudar as permissões da conta depois.
account_small: conta
accounts: Contas
accounts_options: Opções da conta
@@ -287,7 +262,7 @@ pt-BR:
mobile_small: celular
open_in_window: Abrir %{value} em uma nova janela
phone_small: telefone
- phone_toll_free: Toll-free phone
+ phone_toll_free: Toll-free phone
keep_private: manter privado, não compartilhar com os outros
make_public: Compartilhar com todos
same_as_billing: mesmo da cobrança
@@ -295,9 +270,6 @@ pt-BR:
share_with: Compartilhar somente com algumas pessoas
shipping_address: Endereço de entrega
website: Website
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Atual
actual_performance: Performance atual
budget: Orçamento
@@ -312,7 +284,7 @@ pt-BR:
campaigns_small: campanhas
conversion: Conversão
conversion_label: Conversão (%)
- conversion_number: "%{value} convertidos"
+ conversion_number: ! '%{value} convertidos'
create_campaign: Nova campanha
end_date: Data de término
finished_on: finalizado em %{value}
@@ -320,11 +292,13 @@ pt-BR:
no_start_date: data de início não informada
number_of_leads: Número de leads
objectives: Objetivos
- objectives_help: Please specify target number of leads, expected leads-to-opportunities conversion ratio, target revenue, and campaign budget. These numbers will let you track actual campaign performance.
+ objectives_help: Please specify target number of leads, expected leads-to-opportunities
+ conversion ratio, target revenue, and campaign budget. These numbers will let
+ you track actual campaign performance.
objectives_small: objetivos da campanha
revenue: Receita
revenue_label: Receita ($)
- revenue_number: "%{value} em receita"
+ revenue_number: ! '%{value} em receita'
save_campaign: Salvar campanha
start_date: Data de início
started_ago: iniciou há %{value} atrás
@@ -334,9 +308,6 @@ pt-BR:
total_campaigns: Total Campaigns
was_supposed_to_finish: deveria ter terminado a %{value}
was_supposed_to_start: deveria ter começado há %{time_ago} atrás em %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Outro
blog: Website/Blog
contact: Contato
@@ -346,41 +317,46 @@ pt-BR:
contacts_small: contatos
create_contact: Novo contato
department: Departamento
- department_small: '%{value} departamento'
+ department_small: ! '%{value} departamento'
do_not_call: Não ligar
extra_info: Informações exttra
extra_info_small: informação extra
facebook: Facebook
linked_in: LinkedIn
myself: Eu
-
- permissions_intro_private: Por padrão, somente você terá acesso em %{value}. Você pode mudar as permissões depois.
- permissions_intro_public: Por padrão, todos os usuários terão acesso em %{value}. Você pode mudar as permissões depois..
- permissions_intro_shared: Por padrão, somente os usuários selecionados terão acesso em %{value}. Você pode mudar as permissões depois..
-
+ permissions_intro_private: Por padrão, somente você terá acesso em %{value}. Você
+ pode mudar as permissões depois.
+ permissions_intro_public: Por padrão, todos os usuários terão acesso em %{value}.
+ Você pode mudar as permissões depois..
+ permissions_intro_shared: Por padrão, somente os usuários selecionados terão acesso
+ em %{value}. Você pode mudar as permissões depois..
referred_by: Referred by
referred_by_small: referred by
save_contact: Salvar contato
twitter: Twitter
web_presence: Web Presence
web_presence_small: web presence
- works_at: "%{job_title} na %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} na %{company}'
convert: Converter
convert_lead: Converter lead
- convert_lead_permissions_intro: Contact permissions will be copied from the lead being converted. You can change contact permissions later.
- convert_lead_text: By converting the lead %{value} will become a contact associated with the existing or newly created account. Lead status will be automatically set to converted.
+ convert_lead_permissions_intro: Contact permissions will be copied from the lead
+ being converted. You can change contact permissions later.
+ convert_lead_text: By converting the lead %{value} will become a contact associated
+ with the existing or newly created account. Lead status will be automatically
+ set to converted.
create_lead: Novo lead
- create_opp_for_contact: Você pode opcionalmente criar uma oportunidade para o contato %{value} especificando o nome, fase atual, data estimada de fechamento, probabilidade de venda, valor do acordo, e o desconto oferecido.
+ create_opp_for_contact: Você pode opcionalmente criar uma oportunidade para o contato
+ %{value} especificando o nome, fase atual, data estimada de fechamento, probabilidade
+ de venda, valor do acordo, e o desconto oferecido.
lead: Lead
lead_info_small: contato do lead
-
- lead_permissions_intro_private: Por padrão, as permissões seráo copiadas da campanha ou ficarão privadas. Você pode mudar as permissões do 'lead' depois.
- lead_permissions_intro_public: Por padrão, as permissões sérão copiadas do campanha ou ficarão públicas. Você pode mudar as permissões do 'lead' depois.
- lead_permissions_intro_shared: Por padrão, as permissões serão compiadas da campanha ou serão compartilhadas com os usuários especificados. Você pode mudar as permissões do 'lead' depois.
-
+ lead_permissions_intro_private: Por padrão, as permissões seráo copiadas da campanha
+ ou ficarão privadas. Você pode mudar as permissões do 'lead' depois.
+ lead_permissions_intro_public: Por padrão, as permissões sérão copiadas do campanha
+ ou ficarão públicas. Você pode mudar as permissões do 'lead' depois.
+ lead_permissions_intro_shared: Por padrão, as permissões serão compiadas da campanha
+ ou serão compartilhadas com os usuários especificados. Você pode mudar as permissões
+ do 'lead' depois.
lead_small: lead
lead_status_small: situação do lead
lead_summary: Lead Summary
@@ -395,9 +371,6 @@ pt-BR:
source: Origem
status: Situação
total_leads: Total de leads
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Valor
close_date: Close date
closed_ago_on: fechada há %{time_ago} atrás em %{date}
@@ -419,17 +392,15 @@ pt-BR:
opportunity: Oportunidade
opportunity_small: oportunidade
opportunity_summary: Oportunidade At a Glance
- opportunity_summary_text: "%{amount} com desconto de %{discount} e probabilidade de %{probability}"
+ opportunity_summary_text: ! '%{amount} com desconto de %{discount} e probabilidade
+ de %{probability}'
past_due: past due, was expected to close %{value} ago
probability: Probabilidade
- probability_number: e probabilidade de %{value}
+ probability_number: e probabilidade de %{value}
save_opportunity: Salvar oportunidade
stage: Fase
total_opportunities: Total Opportunities
weighted_amount: Weighted amount
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: Atribuida para
assigned_tab: Atribuída
assigned_tasks: Tarefas atribuídas
@@ -441,13 +412,13 @@ pt-BR:
due: Prazo
feel_free: Sinta-se livre para
move_to: mover para
- no_tasks: "Você não tem nenhum atividade %{value}"
+ no_tasks: Você não tem nenhum atividade %{value}
no_tasks_pending: pendente
no_tasks_assigned: atribuída
no_tasks_completed: terminada
pending_tab: Pendente
pending_tasks: Tarefas pendentes
- related: 're:'
+ related: ! 're:'
save_task: Salvar atividade
task_assigned: As tarefas foram atribuídas para %{value}
task_assigned_to: e artibuída para %{value}
@@ -467,9 +438,6 @@ pt-BR:
total_tasks: Total %{value}
view_assigned_tasks: ver tarefas atribuídas
view_pending_tasks: ver tarefas pendentes
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: comentada em
action_completed: terminado
action_created: criado
@@ -490,49 +458,43 @@ pt-BR:
subject_lead: lead
subject_opportunity: oportunidade
subject_task: tarefa
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Adicionar nota
save_note: Salvar nota
add_note_help: Adicionar nova nota...
added_ago: adicionado(a) há %{value} atrás
- added_by: adicionado(a) há %{time_ago} atrás por %{user}
+ added_by: adicionado(a) há %{time_ago} atrás por %{user}
back: Voltar
cancel: Cancelar
close_form: Fechar formulário
confirm_delete: Tem certeza que deseja remover este %{value}?
- copy_permissions: Copiar permissão %{value}
- could_not_find: "%{value} não encontrado. Sinta-se livre para"
- could_not_find_matching: "Couldn't find %{value} matching"
+ copy_permissions: Copiar permissão %{value}
+ could_not_find: ! '%{value} não encontrado. Sinta-se livre para'
+ could_not_find_matching: Couldn't find %{value} matching
create_new: cria um(a) novo(a)
select_existing: selecione existentes
delete: Remover
- discard: Discard # TODO
+ discard: Discard
edit: Editar
- items_total: '%{count} total.'
+ items_total: ! '%{count} total.'
less: Menos...
me: mim
more: Mais...
n_a: N/A
name: Nome
- no_match: 'No %{value} match'
+ no_match: No %{value} match
no_recent_items: Não existem itens recentes para exibir ainda.
options: Opções
permissions: Permissões
please_retry: favor tente outra consulta.
recent_items: Itens recentes
search_assets: Buscar %{value}
- time_ago: "há %{value} atrás"
+ time_ago: há %{value} atrás
background_info: Informações gerais
address: Endereço
city: Ciudade
zipcode: CEP
state: Membro/Região
country: Campo
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: Sobre
about_dev_group: Grupo de discussão para desenvolvedores
about_features: Funcionalidades e bugs
@@ -541,34 +503,24 @@ pt-BR:
about_ffc_version: Fat Free CRM versão
about_home_page: Home page
about_project_page: Página do projeto
- about_thank_you: Obrigado(a) por usar o Fat Free CRM! Nós apreciamos o seu negócio e esperamos que você goste de usar nosso software.
+ about_thank_you: Obrigado(a) por usar o Fat Free CRM! Nós apreciamos o seu negócio
+ e esperamos que você goste de usar nosso software.
about_twitter: Twitter
about_user_group: Grupo de discussão para usuários
admin: Admin
logout: Sair
quick_find: Busca rápida
welcome: Bem vindo(a)
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Editando comentário
show: Exibir
update: Atualizar
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Por favor, digite sua nova senha e então confirme-a.
- password_intro: Por favor, informe seu e-mail, e as instruções para redefinir a sua senha serão enviadas a você.
+ password_intro: Por favor, informe seu e-mail, e as instruções para redefinir a
+ sua senha serão enviadas a você.
reset_password: Redefnir senha
update_password_and_login: Atualizar senha e entrar.
-
- # Views -> Admin
- #----------------------------------------------------------------------------
back_to_crm: Voltar ao Fat Free CRM
crm_admin_page: Administração do Fat Free CRM
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Aprovar
create_user: Novo usuário
last_seen: entrou pela última vez há %{value} atrás
@@ -581,7 +533,7 @@ pt-BR:
user_awaits_approval: aguarda sua aprovação
user_confirm_delete: Um usuário só pode ser removido se não tiver relacionamentos.
user_is_admin: Este usuário é administrador
- user_never_logged_in: "ainda não entrou no sistema"
+ user_never_logged_in: ainda não entrou no sistema
user_signed_up: Cadastrar-se
user_signed_up_on: cadastrou-se em %{value}
user_since: usuário desde %{value}
@@ -589,45 +541,36 @@ pt-BR:
user_suspended_on: suspenso em %{value}
users: Usuários
users_small: usuários
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - E-mail Added - %{subject}
- dropbox_notification_intro: Adicionado com sucesso o e-mail que você enviou para dropbox
+ dropbox_notification_intro: Adicionado com sucesso o e-mail que você enviou para
+ dropbox
dropbox_notification_to: Adicionado a
subject: Assunto
body: Corpo
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment' # TODO
- other: '%{count} comments' # TODO
- contact:
- one: '1 contato'
- other: '%{count} contatos'
+ one: 1 comment
+ other: ! '%{count} comments'
+ contact:
+ one: 1 contato
+ other: ! '%{count} contatos'
opportunity:
- one: '1 oportunidade'
- other: '%{count} oportunidades'
+ one: 1 oportunidade
+ other: ! '%{count} oportunidades'
lead:
- one: '1 lead'
- other: '%{count} leads'
+ one: 1 lead
+ other: ! '%{count} leads'
day:
- one: '1 dia'
- other: '%{count} dias'
+ one: 1 dia
+ other: ! '%{count} dias'
login:
- one: '1 login'
- other: '%{count} logins'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 login
+ other: ! '%{count} logins'
date:
formats:
- mmddyyyy: "%m/%d/%Y"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%m/%d/%Y'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%b %e at %l:%M%p"
+ mmddhhss: ! '%b %e at %l:%M%p'
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 5f52626ae5..ad17b618cc 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -1,303 +1,326 @@
-# Russian localization for Ruby on Rails 2.2+
-# by Yaroslav Markin
-#
-# Be sure to check out "russian" gem (http://github.com/yaroslav/russian) for
-# full Russian language support in Rails (month names, pluralization, etc).
-# The following is an excerpt from that gem.
-#
-# Для полноценной поддержки русского языка (варианты названий месяцев,
-# плюрализация и так далее) в Rails 2.2 нужно использовать gem "russian"
-# (http://github.com/yaroslav/russian). Следующие данные -- выдержка их него, чтобы
-# была возможность минимальной локализации приложения на русский язык.
-
+---
ru:
date:
formats:
- default: "%d.%m.%Y"
- short: "%d %b"
- long: "%d %B %Y"
-
- day_names: [воскресенье, понедельник, вторник, среда, четверг, пятница, суббота]
- standalone_day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота]
- abbr_day_names: [Вс, Пн, Вт, Ср, Чт, Пт, Сб]
-
- month_names: [~, января, февраля, марта, апреля, мая, июня, июля, августа, сентября, октября, ноября, декабря]
- # see russian gem for info on "standalone" day names
- standalone_month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь]
- abbr_month_names: [~, янв., февр., марта, апр., мая, июня, июля, авг., сент., окт., нояб., дек.]
- standalone_abbr_month_names: [~, янв., февр., март, апр., май, июнь, июль, авг., сент., окт., нояб., дек.]
-
+ default: ! '%d.%m.%Y'
+ short: ! '%d %b'
+ long: ! '%d %B %Y'
+ day_names:
+ - воскресенье
+ - понедельник
+ - вторник
+ - среда
+ - четверг
+ - пятница
+ - суббота
+ standalone_day_names:
+ - Воскресенье
+ - Понедельник
+ - Вторник
+ - Среда
+ - Четверг
+ - Пятница
+ - Суббота
+ abbr_day_names:
+ - Вс
+ - Пн
+ - Вт
+ - Ср
+ - Чт
+ - Пт
+ - Сб
+ month_names:
+ -
+ - января
+ - февраля
+ - марта
+ - апреля
+ - мая
+ - июня
+ - июля
+ - августа
+ - сентября
+ - октября
+ - ноября
+ - декабря
+ standalone_month_names:
+ -
+ - Январь
+ - Февраль
+ - Март
+ - Апрель
+ - Май
+ - Июнь
+ - Июль
+ - Август
+ - Сентябрь
+ - Октябрь
+ - Ноябрь
+ - Декабрь
+ abbr_month_names:
+ -
+ - янв.
+ - февр.
+ - марта
+ - апр.
+ - мая
+ - июня
+ - июля
+ - авг.
+ - сент.
+ - окт.
+ - нояб.
+ - дек.
+ standalone_abbr_month_names:
+ -
+ - янв.
+ - февр.
+ - март
+ - апр.
+ - май
+ - июнь
+ - июль
+ - авг.
+ - сент.
+ - окт.
+ - нояб.
+ - дек.
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%a, %d %b %Y, %H:%M:%S %z"
- short: "%d %b, %H:%M"
- long: "%d %B %Y, %H:%M"
-
- am: "утра"
- pm: "вечера"
-
+ default: ! '%a, %d %b %Y, %H:%M:%S %z'
+ short: ! '%d %b, %H:%M'
+ long: ! '%d %B %Y, %H:%M'
+ am: утра
+ pm: вечера
number:
format:
- separator: "."
- delimiter: " "
+ separator: .
+ delimiter: ! ' '
precision: 3
significant: false
strip_insignificant_zeros: false
-
currency:
format:
- format: "%n %u"
- unit: "руб."
- separator: "."
- delimiter: " "
+ format: ! '%n %u'
+ unit: руб.
+ separator: .
+ delimiter: ! ' '
precision: 2
significant: false
strip_insignificant_zeros: false
-
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 1
significant: false
strip_insignificant_zeros: false
-
- # Rails 2.2
- # storage_units: [байт, КБ, МБ, ГБ, ТБ]
-
- # Rails 2.3
storage_units:
- # Storage units output formatting.
- # %u is the storage unit, %n is the number (default: 2 MB)
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "байт"
- few: "байта"
- many: "байт"
- other: "байта"
- kb: "КБ"
- mb: "МБ"
- gb: "ГБ"
- tb: "ТБ"
-
- # Rails 3
+ one: байт
+ few: байта
+ many: байт
+ other: байта
+ kb: КБ
+ mb: МБ
+ gb: ГБ
+ tb: ТБ
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
+ unit: ''
thousand:
- one: "Тысяча"
- few: "Тысяч"
- many: "Тысяч"
- other: "Тысяч"
+ one: Тысяча
+ few: Тысяч
+ many: Тысяч
+ other: Тысяч
million:
- one: "Миллион"
- few: "Миллионов"
- many: "Миллионов"
- other: "Миллионов"
+ one: Миллион
+ few: Миллионов
+ many: Миллионов
+ other: Миллионов
billion:
- one: "Миллиард"
- few: "Миллиардов"
- many: "Миллиардов"
- other: "Миллиардов"
+ one: Миллиард
+ few: Миллиардов
+ many: Миллиардов
+ other: Миллиардов
trillion:
- one: "Триллион"
- few: "Триллионов"
- many: "Триллионов"
- other: "Триллионов"
+ one: Триллион
+ few: Триллионов
+ many: Триллионов
+ other: Триллионов
quadrillion:
- one: "Квадриллион"
- few: "Квадриллионов"
- many: "Квадриллионов"
- other: "Квадриллионов"
-
+ one: Квадриллион
+ few: Квадриллионов
+ many: Квадриллионов
+ other: Квадриллионов
datetime:
distance_in_words:
- half_a_minute: "меньше минуты"
+ half_a_minute: меньше минуты
less_than_x_seconds:
- one: "меньше %{count} секунды"
- few: "меньше %{count} секунд"
- many: "меньше %{count} секунд"
- other: "меньше %{count} секунды"
+ one: меньше %{count} секунды
+ few: меньше %{count} секунд
+ many: меньше %{count} секунд
+ other: меньше %{count} секунды
x_seconds:
- one: "%{count} секунда"
- few: "%{count} секунды"
- many: "%{count} секунд"
- other: "%{count} секунды"
+ one: ! '%{count} секунда'
+ few: ! '%{count} секунды'
+ many: ! '%{count} секунд'
+ other: ! '%{count} секунды'
less_than_x_minutes:
- one: "меньше %{count} минуты"
- few: "меньше %{count} минут"
- many: "меньше %{count} минут"
- other: "меньше %{count} минуты"
+ one: меньше %{count} минуты
+ few: меньше %{count} минут
+ many: меньше %{count} минут
+ other: меньше %{count} минуты
x_minutes:
- one: "%{count} минуту"
- few: "%{count} минуты"
- many: "%{count} минут"
- other: "%{count} минуты"
+ one: ! '%{count} минуту'
+ few: ! '%{count} минуты'
+ many: ! '%{count} минут'
+ other: ! '%{count} минуты'
about_x_hours:
- one: "около %{count} часа"
- few: "около %{count} часов"
- many: "около %{count} часов"
- other: "около %{count} часа"
+ one: около %{count} часа
+ few: около %{count} часов
+ many: около %{count} часов
+ other: около %{count} часа
x_days:
- one: "%{count} день"
- few: "%{count} дня"
- many: "%{count} дней"
- other: "%{count} дня"
+ one: ! '%{count} день'
+ few: ! '%{count} дня'
+ many: ! '%{count} дней'
+ other: ! '%{count} дня'
about_x_months:
- one: "около %{count} месяца"
- few: "около %{count} месяцев"
- many: "около %{count} месяцев"
- other: "около %{count} месяца"
+ one: около %{count} месяца
+ few: около %{count} месяцев
+ many: около %{count} месяцев
+ other: около %{count} месяца
x_months:
- one: "%{count} месяц"
- few: "%{count} месяца"
- many: "%{count} месяцев"
- other: "%{count} месяца"
+ one: ! '%{count} месяц'
+ few: ! '%{count} месяца'
+ many: ! '%{count} месяцев'
+ other: ! '%{count} месяца'
about_x_years:
- one: "около %{count} года"
- few: "около %{count} лет"
- many: "около %{count} лет"
- other: "около %{count} лет"
+ one: около %{count} года
+ few: около %{count} лет
+ many: около %{count} лет
+ other: около %{count} лет
over_x_years:
- one: "больше %{count} года"
- few: "больше %{count} лет"
- many: "больше %{count} лет"
- other: "больше %{count} лет"
+ one: больше %{count} года
+ few: больше %{count} лет
+ many: больше %{count} лет
+ other: больше %{count} лет
almost_x_years:
- one: "почти 1 год"
- other: "почти %{count} лет"
-
+ one: почти 1 год
+ other: почти %{count} лет
prompts:
- year: "Год"
- month: "Месяц"
- day: "День"
- hour: "Часов"
- minute: "Минут"
- second: "Секунд"
-
+ year: Год
+ month: Месяц
+ day: День
+ hour: Часов
+ minute: Минут
+ second: Секунд
helpers:
select:
- # Default value for :prompt => true in FormOptionsHelper
- prompt: "Выберите: "
-
- # Default translation keys for submit FormHelper
+ prompt: ! 'Выберите: '
submit:
- create: 'Создать %{model}'
- update: 'Сохранить %{model}'
- submit: 'Сохранить %{model}'
-
- # In rails 3 errors is top-level namespace
+ create: Создать %{model}
+ update: Сохранить %{model}
+ submit: Сохранить %{model}
errors:
- format: "%{attribute} %{message}"
-
+ format: ! '%{attribute} %{message}'
messages:
- inclusion: "имеет непредусмотренное значение"
- exclusion: "имеет зарезервированное значение"
- invalid: "имеет неверное значение"
- confirmation: "не совпадает с подтверждением"
- accepted: "нужно подтвердить"
- empty: "не может быть пустым"
- blank: "не может быть пустым"
+ inclusion: имеет непредусмотренное значение
+ exclusion: имеет зарезервированное значение
+ invalid: имеет неверное значение
+ confirmation: не совпадает с подтверждением
+ accepted: нужно подтвердить
+ empty: не может быть пустым
+ blank: не может быть пустым
too_long:
- one: "слишком большой длины (не может быть больше чем %{count} символ)"
- few: "слишком большой длины (не может быть больше чем %{count} символа)"
- many: "слишком большой длины (не может быть больше чем %{count} символов)"
- other: "слишком большой длины (не может быть больше чем %{count} символа)"
+ one: слишком большой длины (не может быть больше чем %{count} символ)
+ few: слишком большой длины (не может быть больше чем %{count} символа)
+ many: слишком большой длины (не может быть больше чем %{count} символов)
+ other: слишком большой длины (не может быть больше чем %{count} символа)
too_short:
- one: "недостаточной длины (не может быть меньше %{count} символа)"
- few: "недостаточной длины (не может быть меньше %{count} символов)"
- many: "недостаточной длины (не может быть меньше %{count} символов)"
- other: "недостаточной длины (не может быть меньше %{count} символа)"
+ one: недостаточной длины (не может быть меньше %{count} символа)
+ few: недостаточной длины (не может быть меньше %{count} символов)
+ many: недостаточной длины (не может быть меньше %{count} символов)
+ other: недостаточной длины (не может быть меньше %{count} символа)
wrong_length:
- one: "неверной длины (может быть длиной ровно %{count} символ)"
- few: "неверной длины (может быть длиной ровно %{count} символа)"
- many: "неверной длины (может быть длиной ровно %{count} символов)"
- other: "неверной длины (может быть длиной ровно %{count} символа)"
- taken: "уже существует"
- not_a_number: "не является числом"
- not_an_integer: "не является целым числом"
- greater_than: "может иметь значение большее %{count}"
- greater_than_or_equal_to: "может иметь значение большее или равное %{count}"
- equal_to: "может иметь лишь значение, равное %{count}"
- less_than: "может иметь значение меньшее чем %{count}"
- less_than_or_equal_to: "может иметь значение меньшее или равное %{count}"
- odd: "может иметь лишь четное значение"
- even: "может иметь лишь нечетное значение"
- record_invalid: "Возникли ошибки: %{errors}"
-
+ one: неверной длины (может быть длиной ровно %{count} символ)
+ few: неверной длины (может быть длиной ровно %{count} символа)
+ many: неверной длины (может быть длиной ровно %{count} символов)
+ other: неверной длины (может быть длиной ровно %{count} символа)
+ taken: уже существует
+ not_a_number: не является числом
+ not_an_integer: не является целым числом
+ greater_than: может иметь значение большее %{count}
+ greater_than_or_equal_to: может иметь значение большее или равное %{count}
+ equal_to: может иметь лишь значение, равное %{count}
+ less_than: может иметь значение меньшее чем %{count}
+ less_than_or_equal_to: может иметь значение меньшее или равное %{count}
+ odd: может иметь лишь четное значение
+ even: может иметь лишь нечетное значение
+ record_invalid: ! 'Возникли ошибки: %{errors}'
activerecord:
errors:
template:
header:
- one: "%{model}: сохранение не удалось из-за %{count} ошибки"
- few: "%{model}: сохранение не удалось из-за %{count} ошибок"
- many: "%{model}: сохранение не удалось из-за %{count} ошибок"
- other: "%{model}: сохранение не удалось из-за %{count} ошибки"
-
- body: "Проблемы возникли со следующими полями:"
-
+ one: ! '%{model}: сохранение не удалось из-за %{count} ошибки'
+ few: ! '%{model}: сохранение не удалось из-за %{count} ошибок'
+ many: ! '%{model}: сохранение не удалось из-за %{count} ошибок'
+ other: ! '%{model}: сохранение не удалось из-за %{count} ошибки'
+ body: ! 'Проблемы возникли со следующими полями:'
messages:
- inclusion: "имеет непредусмотренное значение"
- exclusion: "имеет зарезервированное значение"
- invalid: "имеет неверное значение"
- confirmation: "не совпадает с подтверждением"
- accepted: "нужно подтвердить"
- empty: "не может быть пустым"
- blank: "не может быть пустым"
+ inclusion: имеет непредусмотренное значение
+ exclusion: имеет зарезервированное значение
+ invalid: имеет неверное значение
+ confirmation: не совпадает с подтверждением
+ accepted: нужно подтвердить
+ empty: не может быть пустым
+ blank: не может быть пустым
too_long:
- one: "слишком большой длины (не может быть больше чем %{count} символ)"
- few: "слишком большой длины (не может быть больше чем %{count} символа)"
- many: "слишком большой длины (не может быть больше чем %{count} символов)"
- other: "слишком большой длины (не может быть больше чем %{count} символа)"
+ one: слишком большой длины (не может быть больше чем %{count} символ)
+ few: слишком большой длины (не может быть больше чем %{count} символа)
+ many: слишком большой длины (не может быть больше чем %{count} символов)
+ other: слишком большой длины (не может быть больше чем %{count} символа)
too_short:
- one: "недостаточной длины (не может быть меньше %{count} символа)"
- few: "недостаточной длины (не может быть меньше %{count} символов)"
- many: "недостаточной длины (не может быть меньше %{count} символов)"
- other: "недостаточной длины (не может быть меньше %{count} символа)"
+ one: недостаточной длины (не может быть меньше %{count} символа)
+ few: недостаточной длины (не может быть меньше %{count} символов)
+ many: недостаточной длины (не может быть меньше %{count} символов)
+ other: недостаточной длины (не может быть меньше %{count} символа)
wrong_length:
- one: "неверной длины (может быть длиной ровно %{count} символ)"
- few: "неверной длины (может быть длиной ровно %{count} символа)"
- many: "неверной длины (может быть длиной ровно %{count} символов)"
- other: "неверной длины (может быть длиной ровно %{count} символа)"
- taken: "уже существует"
- not_a_number: "не является числом"
- greater_than: "может иметь значение большее %{count}"
- greater_than_or_equal_to: "может иметь значение большее или равное %{count}"
- equal_to: "может иметь лишь значение, равное %{count}"
- less_than: "может иметь значение меньшее чем %{count}"
- less_than_or_equal_to: "может иметь значение меньшее или равное %{count}"
- odd: "может иметь лишь четное значение"
- even: "может иметь лишь нечетное значение"
- record_invalid: "Возникли ошибки: %{errors}"
-
+ one: неверной длины (может быть длиной ровно %{count} символ)
+ few: неверной длины (может быть длиной ровно %{count} символа)
+ many: неверной длины (может быть длиной ровно %{count} символов)
+ other: неверной длины (может быть длиной ровно %{count} символа)
+ taken: уже существует
+ not_a_number: не является числом
+ greater_than: может иметь значение большее %{count}
+ greater_than_or_equal_to: может иметь значение большее или равное %{count}
+ equal_to: может иметь лишь значение, равное %{count}
+ less_than: может иметь значение меньшее чем %{count}
+ less_than_or_equal_to: может иметь значение меньшее или равное %{count}
+ odd: может иметь лишь четное значение
+ even: может иметь лишь нечетное значение
+ record_invalid: ! 'Возникли ошибки: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
-
-
+ format: ! '%{attribute} %{message}'
support:
select:
- prompt: "Выберите: "
-
+ prompt: ! 'Выберите: '
array:
- # Rails 2.2
- sentence_connector: "и"
+ sentence_connector: и
skip_last_comma: true
-
- # Rails 2.3
- words_connector: ", "
- two_words_connector: " и "
- last_word_connector: " и "
+ words_connector: ! ', '
+ two_words_connector: ! ' и '
+ last_word_connector: ! ' и '
diff --git a/config/locales/ru_fat_free_crm.yml b/config/locales/ru_fat_free_crm.yml
index 01278cd7c6..d3e00c2aa8 100644
--- a/config/locales/ru_fat_free_crm.yml
+++ b/config/locales/ru_fat_free_crm.yml
@@ -1,20 +1,15 @@
+---
ru:
language: Russian (Русский)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Все
at: в
here: здесь
- no_button: 'Нет'
+ no_button: Нет
not_implemented: Пока не поддерживается.
or: или
select_blank: -- Выберите --
select_none: -- Нет --
- yes_button: 'Да'
-
- # Settings.
- #----------------------------------------------------------------------------
+ yes_button: Да
tab_dashboard: Главная
tab_tasks: Задания
tab_campaigns: Маркетинг
@@ -22,22 +17,18 @@ ru:
tab_accounts: Контрагенты
tab_contacts: Контакты
tab_opportunities: Возможности
-
admin_tab_users: Пользователи
admin_tab_settings: Установки
admin_tab_plugins: Плагины
-
planned: В плане
started: Начата
on_hold: Остановлена
completed: Завершена
called_off: Прекращена
-
new: Новый
contacted: В работе
converted: Продвинут
rejected: Закрыт
-
cold_call: Холодный Звонок
conference: Конференция
online: Онлайн Маркетинг
@@ -46,7 +37,6 @@ ru:
web: Веб-сайт
word_of_mouth: Понаслышке
other: Другое
-
prospecting: Изучение
analysis: Анализ
presentation: Презентация
@@ -55,16 +45,13 @@ ru:
final_review: Утверждение
won: Выиграли
lost: Проиграли
-
call: Звонок
email: E-mail
follow_up: Доработка
lunch: Обед
meeting: Встреча
money: Деньги
- presentation: Презентация
trip: Поездка
-
overdue: Задержка
due_asap: Как можно скорее
due_today: Сегодня
@@ -73,24 +60,17 @@ ru:
due_next_week: На следующей неделе
due_later: Позже
due_specific_date: Конкретная дата
-
completed_today: Сегодня
completed_yesterday: Вчера
completed_last_week: На прошлой неделе
completed_this_month: В этом месяце
completed_last_month: В прошлом месяце
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: Один Час
one_day: Один День
two_days: Два Дня
one_week: Одна Неделя
two_weeks: Две Недели
one_month: Один Месяц
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -103,85 +83,85 @@ ru:
account:
attributes:
name:
- missing_account_name: "^Пожалуйста введите название контрагента."
+ missing_account_name: ^Пожалуйста введите название контрагента.
access:
- share_account: "^Пожалуйста укажите пользователей которым разрешен доступ к данному контрагенту."
+ share_account: ^Пожалуйста укажите пользователей которым разрешен доступ
+ к данному контрагенту.
campaign:
attributes:
name:
- missing_campaign_name: "^Пожалуйста введите название кампании."
+ missing_campaign_name: ^Пожалуйста введите название кампании.
ends_on:
- dates_not_in_sequence: "^Пожалуйста укажите дату окончания кампании после ее начала."
+ dates_not_in_sequence: ^Пожалуйста укажите дату окончания кампании после
+ ее начала.
access:
- share_campaign: "^Пожалуйста укажите пользователей которым разрешен доступ к данной кампании."
+ share_campaign: ^Пожалуйста укажите пользователей которым разрешен доступ
+ к данной кампании.
contact:
attributes:
first_name:
- missing_first_name: "^Пожалуйста введите имя."
+ missing_first_name: ^Пожалуйста введите имя.
last_name:
- missing_last_name: "^Пожалуйста введите фамилию."
+ missing_last_name: ^Пожалуйста введите фамилию.
access:
- share_contact: "^Пожалуйста укажите пользователей которым разрешен доступ к данному контакту."
+ share_contact: ^Пожалуйста укажите пользователей которым разрешен доступ
+ к данному контакту.
lead:
attributes:
first_name:
- missing_first_name: "^Пожалуйста введите имя."
+ missing_first_name: ^Пожалуйста введите имя.
last_name:
- missing_last_name: "^Пожалуйста введите фамилию."
+ missing_last_name: ^Пожалуйста введите фамилию.
access:
- share_lead: "^Пожалуйста укажите пользователей которым разрешен доступ к данному потенциальному клиенту."
+ share_lead: ^Пожалуйста укажите пользователей которым разрешен доступ
+ к данному потенциальному клиенту.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Пожалуйста введите название возможности."
+ missing_opportunity_name: ^Пожалуйста введите название возможности.
access:
- share_opportunity: "^Пожалуйста укажите пользователей которым разрешен доступ к данной возможности."
+ share_opportunity: ^Пожалуйста укажите пользователей которым разрешен
+ доступ к данной возможности.
task:
attributes:
name:
- missing_task_name: "^Пожалуйста введите название для задания."
+ missing_task_name: ^Пожалуйста введите название для задания.
calendar:
- invalid_date: "^Пожалуйста укажите правильную дату."
+ invalid_date: ^Пожалуйста укажите правильную дату.
user:
attributes:
username:
- missing_username: "^Пожалуйста введите имя пользователя."
- username_taken: "^Данное имя пользователя уже существует."
+ missing_username: ^Пожалуйста введите имя пользователя.
+ username_taken: ^Данное имя пользователя уже существует.
email:
- msg_missing_email: "^Пожалуйста введите e-mail адрес."
- email_in_use: "^Пользователь с данным e-mail адресом уже существует."
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ msg_missing_email: ^Пожалуйста введите e-mail адрес.
+ email_in_use: ^Пользователь с данным e-mail адресом уже существует.
errors:
template:
header:
- one: "%{model}: сохранение не удалось из-за %{count} ошибки"
- few: "%{model}: сохранение не удалось из-за %{count} ошибок"
- many: "%{model}: сохранение не удалось из-за %{count} ошибок"
- other: "%{model}: сохранение не удалось из-за %{count} ошибки"
- body: "Проблемы возникли со следующими полями:"
-
+ one: ! '%{model}: сохранение не удалось из-за %{count} ошибки'
+ few: ! '%{model}: сохранение не удалось из-за %{count} ошибок'
+ many: ! '%{model}: сохранение не удалось из-за %{count} ошибок'
+ other: ! '%{model}: сохранение не удалось из-за %{count} ошибки'
+ body: ! 'Проблемы возникли со следующими полями:'
msg_account_suspended: Пользователь заблокирован.
password_reset_instruction: инструкции по перемене пароля
-
- # Controllers.
- #----------------------------------------------------------------------------
msg_account_created: Ваш аккаунт создан и ожидает активации системным администратором.
msg_account_not_approved: Ваш аккаунт еще не активирован.
msg_asset_deleted: Этот %{value} был удален.
msg_asset_not_available: Этот %{value} более недоступен.
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
- msg_assets_not_available: Эти %{value} более недоступны.
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
+ msg_assets_not_available: Эти %{value} более недоступны.
msg_asset_rejected: Этот %{value} отклонен.
msg_bad_image_file: ^Ошибка при загрузке или изменении размера указанного изображения.
msg_cant_create_related: Невозвожно создать %{asset} так как %{related} более недоступен.
- msg_cant_delete_user: "^Невозможно удалить пользователя так как к %{value} привязаны объекты."
+ msg_cant_delete_user: ^Невозможно удалить пользователя так как к %{value} привязаны
+ объекты.
msg_cant_do: Нельзя %{action} %{asset}, его больше не существует.
msg_email_not_found: Пользователя с таким адресом не найдено.
msg_enter_new_password: Пожалуйста введите новый пароль.
msg_goodbye: Вы вышли. Спасибо за использование Fat Free CRM!
- msg_invalid_password: "^Введите правильный пароль."
+ msg_invalid_password: ^Введите правильный пароль.
msg_invalig_login: Неправильный логин или пароль.
msg_last_login: Последний раз Вы заходили %{value}.
msg_login_needed: Для доступа к этой странице нужно войти в систему.
@@ -189,15 +169,14 @@ ru:
msg_password_changed: Пароль изменен.
msg_password_not_changed: Пароль не был изменен.
msg_password_updated: Пароль успешно изменен.
- msg_pwd_instructions_sent: Инструкции по перемене пароля Вам высланы. Пожалуйста проверьте свою электронную почту.
+ msg_pwd_instructions_sent: Инструкции по перемене пароля Вам высланы. Пожалуйста
+ проверьте свою электронную почту.
msg_require_admin: Для доступа к этой странице нужны права Администратора
msg_successful_signup: Регистрация прошла успешно, добро пожаловать в Fat Free CRM!
msg_welcome: Добро пожаловать в Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": взвешенной сумме
- activity_options: "Показывать действия изменившие %{models} и произведенные %{user} за последние %{period}."
+ option_amount*probability: взвешенной сумме
+ activity_options: Показывать действия изменившие %{models} и произведенные %{user}
+ за последние %{period}.
all_users: Всеми Пользователями
option_after: после
option_all: все
@@ -223,10 +202,8 @@ ru:
option_updated_at: дате обновления
show_per_page: Показывать %{models} в %{fmt} формате по %{number} записей на странице.
sort_by: Сортировать %{models} по %{field}.
- sort_by_displaying: Сортировать %{models} по %{field} показывая имя %{position} фамилии.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Сортировать %{models} по %{field} показывая имя %{position}
+ фамилии.
aim: AOL IM
already_signed_up: Уже регистрировались?
alt_email: Альтернативный E-mail
@@ -236,12 +213,12 @@ ru:
contact_info: Контактная Информация
current_password: Текущий пароль
edit_profile: Изменить Профиль
- # email: E-mail # <-- Already defined as the task type if Settings.
first_name: Имя
google: Google IM
gravatar_help: Не знаете что такое Gravatar? Почитать про Gravatar
image_file: Файл с Изображением
- image_help: "Размер изображения будет автоматически изменен на 75 x 75 пикселей. Поддерживаются форматы: GIF, JPG и PNG."
+ image_help: ! 'Размер изображения будет автоматически изменен на 75 x 75 пикселей.
+ Поддерживаются форматы: GIF, JPG и PNG.'
job_title: Должность
last_name: Фамилия
login_now_link: Войти!
@@ -262,19 +239,14 @@ ru:
user: Пользователь
username: Логин
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Забыли пароль?
login: Вход
no_account: Не зарегистрированы?
remember_me: Запомнить
sign_up_now: Зарегистрироваться!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: Контрагент
- account_permissions_intro: По умолчанию только Вы будете иметь доступ к этому контрагенту. Права доступа можно будет изменить в любое время.
+ account_permissions_intro: По умолчанию только Вы будете иметь доступ к этому контрагенту.
+ Права доступа можно будет изменить в любое время.
account_small: контрагент
accounts: Контрагенты
accounts_options: Свойства списка контрагентов
@@ -297,9 +269,6 @@ ru:
share_with: Показывать перечисленным людям
shipping_address: Адрес получателя
website: Интернет-страница
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Фактически
actual_performance: Фактический Результат
budget: Бюджет
@@ -322,11 +291,14 @@ ru:
no_start_date: дата начала не указана
number_of_leads: Количество потенциальных клиентов
objectives: Цели
- objectives_help: Пожалуйста, введите ожидаемое количество потенциальных клиентов, планируемый коэффициент конверсии потенциальных клиентов в возможность, планируемый доход и бюджет рекламной кампании. Эти цифры позволят отследить фактическую эффективность кампании.
+ objectives_help: Пожалуйста, введите ожидаемое количество потенциальных клиентов,
+ планируемый коэффициент конверсии потенциальных клиентов в возможность, планируемый
+ доход и бюджет рекламной кампании. Эти цифры позволят отследить фактическую эффективность
+ кампании.
objectives_small: целях кампании
revenue: Доход
revenue_label: Доход (руб.)
- revenue_number: "%{value} дохода"
+ revenue_number: ! '%{value} дохода'
save_campaign: Сохранить Изменения
start_date: Дата начала
started_ago: начата %{value} назад
@@ -336,9 +308,6 @@ ru:
total_campaigns: Всего кампаний
was_supposed_to_finish: должна была закончиться %{value}
was_supposed_to_start: должна была начаться %{time_ago} назад %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Доп. e-mail
blog: Блог/Интернет-страница
contact: Контакт
@@ -355,37 +324,40 @@ ru:
facebook: Вконтакте
linked_in: Одноклассники
myself: Мне
-
- # TODO
- permissions_intro_private: By default only you will have access to the %{value}. You can change permissions later.
- permissions_intro_public: By default all users will have access to the %{value}. You can change permissions later.
- permissions_intro_shared: By default only the selected users will have access to the %{value}. You can change permissions later.
-
- permissions_intro: При создании только Вы получаете доступ к %{value}ам. Права доступа можно изменить в любое время.
+ permissions_intro_private: By default only you will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_public: By default all users will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_shared: By default only the selected users will have access to
+ the %{value}. You can change permissions later.
+ permissions_intro: При создании только Вы получаете доступ к %{value}ам. Права доступа
+ можно изменить в любое время.
referred_by: По рекомендации
referred_by_small: по рекомендации
save_contact: Сохранить Контакт
twitter: Twitter
web_presence: Профили в Сети
web_presence_small: профилях
- works_at: "%{job_title} в %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} в %{company}'
convert: Конверсия
convert_lead: Конвертировать потенциального клиента
- convert_lead_permissions_intro: Права доступа к контакту будут скопированы от карточки конвертируемого потенциального клиента. Позже вы сможете изменить права доступа.
- convert_lead_text: В результате конверсии потенциального клиента «%{value}», будет создан новый контакт привязанный к существующему или вновь созданному клиенту. Статус потенциального клиента автоматически изменится на конвертирован.
+ convert_lead_permissions_intro: Права доступа к контакту будут скопированы от карточки
+ конвертируемого потенциального клиента. Позже вы сможете изменить права доступа.
+ convert_lead_text: В результате конверсии потенциального клиента «%{value}»,
+ будет создан новый контакт привязанный к существующему или вновь созданному клиенту.
+ Статус потенциального клиента автоматически изменится на конвертирован.
create_lead: Создать потенциального клиента
- create_opp_for_contact: Вы можете создать возможность, привязанную к контакту «%{value}», введя в следующих полях название возможности, стадию, предполагаему дату завершения, вероятность продажи, сумма сделки и предлагаемую скидку.
+ create_opp_for_contact: Вы можете создать возможность, привязанную к контакту «%{value}»,
+ введя в следующих полях название возможности, стадию, предполагаему дату завершения,
+ вероятность продажи, сумма сделки и предлагаемую скидку.
lead: Потенциальный клиент
lead_info_small: Контактная информация потенциального клиента
-
- # TODO
- lead_permissions_intro_private: By default permissions will be copied from the campaign or set to private. You can change lead permissions later.
- lead_permissions_intro_public: By default permissions will be copied from the campaign or set to public. You can change lead permissions later.
- lead_permissions_intro_shared: By default permissions will be copied from the campaign or shared with the specified users. You can change lead permissions later.
-
+ lead_permissions_intro_private: By default permissions will be copied from the campaign
+ or set to private. You can change lead permissions later.
+ lead_permissions_intro_public: By default permissions will be copied from the campaign
+ or set to public. You can change lead permissions later.
+ lead_permissions_intro_shared: By default permissions will be copied from the campaign
+ or shared with the specified users. You can change lead permissions later.
lead_small: потенциальный клиент
lead_status_small: Статус потенциального клиента
lead_summary: Информация о потенциальном клиенте
@@ -395,14 +367,12 @@ ru:
none: Нет
rating: Оценка
reject: Закрыть
- reject_lead_confirm: Вы действительно хотите закрыть эту карточку потенциального клиента?
+ reject_lead_confirm: Вы действительно хотите закрыть эту карточку потенциального
+ клиента?
save_lead: Сохранить Потенциального клиента
source: Источник
status: Статус
total_leads: Всего потенциальных клиентов
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Сумма
close_date: Дата завершения
closed_ago_on: завершена %{time_ago} назад %{date}
@@ -424,7 +394,8 @@ ru:
opportunity: Возможность
opportunity_small: возможность
opportunity_summary: Краткая информация
- opportunity_summary_text: "%{amount} со скидкой %{discount} и вероятностью %{probability} процентов"
+ opportunity_summary_text: ! '%{amount} со скидкой %{discount} и вероятностью %{probability}
+ процентов'
past_due: просрочено, должно было завершено %{value} назад
probability: Вероятность
probability_number: и вероятностью %{value}
@@ -432,9 +403,6 @@ ru:
stage: Стадия
total_opportunities: Всего возможностей
weighted_amount: Взвешенная сумма
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: Поручить
assigned_tab: Порученные
assigned_tasks: Порученные Задания
@@ -460,26 +428,23 @@ ru:
task_completed_ago: завершено %{value} назад
task_completed_by: завершил(а) %{user} %{time_ago} назад
task_created: Задание добавлено
- task_due_in: "срок: через %{value}"
- task_due_later: "срок: скоро"
- task_due_now: "срок: сейчас"
- task_due_today: "срок: сегодня"
- task_from: "%{value} поручил(a)"
- task_overdue: "задержка, срок:"
+ task_due_in: ! 'срок: через %{value}'
+ task_due_later: ! 'срок: скоро'
+ task_due_now: ! 'срок: сейчас'
+ task_due_today: ! 'срок: сегодня'
+ task_from: ! '%{value} поручил(a)'
+ task_overdue: ! 'задержка, срок:'
task_pending: Это задание поставлено в очередь на выполнение
task_small: задание
tasks: Задания
- total_tasks: "%{value}, всего:"
+ total_tasks: ! '%{value}, всего:'
view_assigned_tasks: показать порученные задания
view_pending_tasks: показать задания на очереди
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: прокомментировал(а)
action_completed: завершил(а)
action_created: добавил(а)
action_deleted: удалил(а)
- action_email: exchanged emails with # TODO
+ action_email: exchanged emails with
action_reassigned: перепоручил(а)
action_rejected: закрыл(а)
action_rescheduled: перенес(ла)
@@ -495,14 +460,11 @@ ru:
subject_lead: наводку
subject_opportunity: перспективу
subject_task: задание
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Добавить Комментарий
save_note: Сохранить Комментарий
add_note_help: Добавить комментарий...
added_ago: добавлен %{value} назад
- added_by: "%{user} добавил(а) %{time_ago} назад"
+ added_by: ! '%{user} добавил(а) %{time_ago} назад'
back: Назад
cancel: Отменить
close_form: Закрыть
@@ -516,64 +478,53 @@ ru:
discard: Сбросить
edit: Изменить
items_total: Всего %{count}.
- less: Less... # TODO
+ less: Less...
me: я
- more: More... # TODO
- n_a: -
+ more: More...
+ n_a:
+ -
name: Название
- no_match: "%{value} не найдены"
+ no_match: ! '%{value} не найдены'
no_recent_items: Недавно просмотренных объектов не найдено.
options: Опции
permissions: Права Доступа
please_retry: попробуйте поискать что-нибудь другое.
recent_items: Недавние Объекты
search_assets: Поиск - %{value}
- ago: "%{value} назад"
+ ago: ! '%{value} назад'
background_info: Дополнительная информация
address: Адрес
city: деловой центр Лондона
zipcode: почтовый индекс
state: режим работы
country: страна
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: О программе
about_dev_group: Форум для разработчиков
about_features: Багтрекер
about_ffc: О программе Fat Free CRM
- about_ffc_resources: Полезные ресурсы по Fat Free CRM (ссылки открываются в новом окне)
+ about_ffc_resources: Полезные ресурсы по Fat Free CRM (ссылки открываются в новом
+ окне)
about_ffc_version: Fat Free CRM версия
about_home_page: Домашняя страница
about_project_page: Страница проекта
- about_thank_you: Спасибо что Вы пользуетесь Fat Free CRM! Мы ценим ваш бизнес и надеемся что Вам нравится наше приложение.
+ about_thank_you: Спасибо что Вы пользуетесь Fat Free CRM! Мы ценим ваш бизнес и
+ надеемся что Вам нравится наше приложение.
about_twitter: Следите за информацией в Twitter
about_user_group: Форум для пользователей
admin: Админ
logout: Выход
quick_find: Быстрый поиск
welcome: Добро пожаловать
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Изменить комментарий
show: Показать
update: Сохранить
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Введите новый пароль, и затем подтвердите его.
- password_intro: Введите адрес электронной почты, на который Вам выслать инструкции по перемене пароля.
+ password_intro: Введите адрес электронной почты, на который Вам выслать инструкции
+ по перемене пароля.
reset_password: Изменить Пароль
update_password_and_login: Изменить Пароль и Войти
-
- # Views -> Admin
- #----------------------------------------------------------------------------
back_to_crm: Назад к Fat Free CRM
crm_admin_page: Администрирование Fat Free CRM
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Подтвердить
create_user: Создать Пользователя
last_seen: последний визит %{value} назад
@@ -584,7 +535,8 @@ ru:
user_active: Активен
user_admin: Админ.
user_awaits_approval: ждет подтверждения
- user_confirm_delete: Пользователя можно удалить только в том случае, если к нему не привязаны никакие объекты.
+ user_confirm_delete: Пользователя можно удалить только в том случае, если к нему
+ не привязаны никакие объекты.
user_is_admin: Дать права Администратора
user_never_logged_in: еще не заходил(а)
user_signed_up: Зарегистрирован
@@ -594,59 +546,50 @@ ru:
user_suspended_on: заблокирован(а) %{value}
users: Пользователи
users_small: пользователи
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: dropbox - Добавлено электронной почты - %{subject}
- dropbox_notification_intro: Успешно добавлена электронной почты, который направлен Dropbox
+ dropbox_notification_intro: Успешно добавлена электронной почты, который направлен
+ Dropbox
dropbox_notification_to: В дополнение к
subject: Тема
body: Тело
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment' # TODO
- other: '%{count} comments' # TODO
+ one: 1 comment
+ other: ! '%{count} comments'
contact:
- zero: '0 контактов'
- one: '1 контакт'
- few: '%{count} контакта'
- many: '%{count} контактов'
- other: '%{count} контакта'
+ zero: 0 контактов
+ one: 1 контакт
+ few: ! '%{count} контакта'
+ many: ! '%{count} контактов'
+ other: ! '%{count} контакта'
opportunity:
- zero: '0 перспектив'
- one: '1 перспектива'
- few: '%{count} перспективы'
- many: '%{count} перспектив'
- other: '%{count} перспектив'
+ zero: 0 перспектив
+ one: 1 перспектива
+ few: ! '%{count} перспективы'
+ many: ! '%{count} перспектив'
+ other: ! '%{count} перспектив'
lead:
- zero: '0 потенциальных клиентов'
- one: '1 потенциальный клиент'
- few: '%{count} потенциальных клиентов'
- many: '%{count} потенциальных клиентов'
- other: '%{count} потенциальных клиентов'
+ zero: 0 потенциальных клиентов
+ one: 1 потенциальный клиент
+ few: ! '%{count} потенциальных клиентов'
+ many: ! '%{count} потенциальных клиентов'
+ other: ! '%{count} потенциальных клиентов'
day:
- zero: '0 дней'
- one: '%{count} день'
- few: '%{count} дня'
- many: '%{count} дней'
- other: '%{count} дней'
+ zero: 0 дней
+ one: ! '%{count} день'
+ few: ! '%{count} дня'
+ many: ! '%{count} дней'
+ other: ! '%{count} дней'
login:
- one: 'заходил(а) %{count} раз'
- few: 'заходил(а) %{count} раза'
- many: 'заходил(а) %{count} раз'
- other: 'заходил(а) %{count} раз'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: заходил(а) %{count} раз
+ few: заходил(а) %{count} раза
+ many: заходил(а) %{count} раз
+ other: заходил(а) %{count} раз
date:
formats:
- mmddyyyy: "%m/%d/%Y"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%m/%d/%Y'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%d %B в %H:%M"
+ mmddhhss: ! '%d %B в %H:%M'
diff --git a/config/locales/sv-SE.yml b/config/locales/sv-SE.yml
index ddc835fa3b..99768a3c28 100644
--- a/config/locales/sv-SE.yml
+++ b/config/locales/sv-SE.yml
@@ -1,232 +1,215 @@
-# Swedish translation.
-# By Johan Lundström (johanlunds@gmail.com) with parts taken from http://github.com/daniel/swe_rails.
-# With contributions by:
-# * Sven Dahlstrand (sven.dahlstrand@gmail.com)
-# * Henrik Nyh (henrik@nyh.se)
-# * Magnus Bergmark (magnus.bergmark@gmail.com)
-
-"sv-SE":
+---
+sv-SE:
number:
- # Used in number_with_delimiter()
- # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
format:
- # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
- separator: ","
- # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three)
- delimiter: " " # non-breaking space
- # Number of decimals after the separator (the number 1 with a precision of 2 gives: 1.00)
+ separator: ! ','
+ delimiter:
precision: 2
significant: false
strip_insignificant_zeros: false
-
- # Used in number_to_currency()
currency:
format:
- # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
- format: "%n %u"
- negative_format: "-%n %u"
- unit: "kr"
-
+ format: ! '%n %u'
+ negative_format: -%n %u
+ unit: kr
percentage:
format:
- delimiter: ""
-
+ delimiter: ''
precision:
format:
- delimiter: ""
-
- # Used in number_to_human_size()
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 1
-
storage_units:
- # Storage units output formatting.
- # %u is the storage unit, %n is the number (default: 2 MB)
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- unit: ""
- thousand: "Tusen"
- million: "Miljon"
- billion: "Miljard"
- trillion: "Biljon"
- quadrillion: "Triljon"
-
- # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
+ unit: ''
+ thousand: Tusen
+ million: Miljon
+ billion: Miljard
+ trillion: Biljon
+ quadrillion: Triljon
datetime:
distance_in_words:
- half_a_minute: "en halv minut"
+ half_a_minute: en halv minut
less_than_x_seconds:
- one: "mindre än en sekund"
- other: "mindre än %{count} sekunder"
+ one: mindre än en sekund
+ other: mindre än %{count} sekunder
x_seconds:
- one: "en sekund"
- other: "%{count} sekunder"
+ one: en sekund
+ other: ! '%{count} sekunder'
less_than_x_minutes:
- one: "mindre än en minut"
- other: "mindre än %{count} minuter"
+ one: mindre än en minut
+ other: mindre än %{count} minuter
x_minutes:
- one: "en minut"
- other: "%{count} minuter"
+ one: en minut
+ other: ! '%{count} minuter'
about_x_hours:
- one: "ungefär en timme"
- other: "ungefär %{count} timmar"
+ one: ungefär en timme
+ other: ungefär %{count} timmar
x_days:
- one: "en dag"
- other: "%{count} dagar"
+ one: en dag
+ other: ! '%{count} dagar'
about_x_months:
- one: "ungefär en månad"
- other: "ungefär %{count} månader"
+ one: ungefär en månad
+ other: ungefär %{count} månader
x_months:
- one: "en månad"
- other: "%{count} månader"
+ one: en månad
+ other: ! '%{count} månader'
about_x_years:
- one: "ungefär ett år"
- other: "ungefär %{count} år"
+ one: ungefär ett år
+ other: ungefär %{count} år
over_x_years:
- one: "mer än ett år"
- other: "mer än %{count} år"
+ one: mer än ett år
+ other: mer än %{count} år
almost_x_years:
- one: "nästan ett år"
- other: "nästan %{count} år"
-
+ one: nästan ett år
+ other: nästan %{count} år
prompts:
- year: "År"
- month: "Månad"
- day: "Dag"
- hour: "Timme"
- minute: "Minut"
- second: "Sekund"
-
+ year: År
+ month: Månad
+ day: Dag
+ hour: Timme
+ minute: Minut
+ second: Sekund
helpers:
select:
- prompt: "Välj"
-
+ prompt: Välj
submit:
- create: "Skapa %{model}"
- update: "Ändra %{model}"
- submit: "Spara %{model}"
-
+ create: Skapa %{model}
+ update: Ändra %{model}
+ submit: Spara %{model}
errors:
- format: "%{attribute} %{message}"
-
- messages: &errors_messages
- inclusion: "finns inte i listan"
- exclusion: "är reserverat"
- invalid: "är ogiltigt"
- confirmation: "stämmer inte överens"
- accepted: "måste vara accepterad"
- empty: "får ej vara tom"
- blank: "måste anges"
- too_long: "är för lång (maximum är %{count} tecken)"
- too_short: "är för kort (minimum är %{count} tecken)"
- wrong_length: "har fel längd (ska vara %{count} tecken)"
- taken: "har redan tagits"
- not_a_number: "är inte ett nummer"
- not_an_integer: "måste vara ett heltal"
- greater_than: "måste vara större än %{count}"
- greater_than_or_equal_to: "måste vara större än eller lika med %{count}"
- equal_to: "måste vara samma som"
- less_than: "måste vara mindre än %{count}"
- less_than_or_equal_to: "måste vara mindre än eller lika med %{count}"
- odd: "måste vara udda"
- even: "måste vara jämnt"
- record_invalid: "Ett fel uppstod: %{errors}"
-
+ format: ! '%{attribute} %{message}'
+ messages:
+ inclusion: finns inte i listan
+ exclusion: är reserverat
+ invalid: är ogiltigt
+ confirmation: stämmer inte överens
+ accepted: måste vara accepterad
+ empty: får ej vara tom
+ blank: måste anges
+ too_long: är för lång (maximum är %{count} tecken)
+ too_short: är för kort (minimum är %{count} tecken)
+ wrong_length: har fel längd (ska vara %{count} tecken)
+ taken: har redan tagits
+ not_a_number: är inte ett nummer
+ not_an_integer: måste vara ett heltal
+ greater_than: måste vara större än %{count}
+ greater_than_or_equal_to: måste vara större än eller lika med %{count}
+ equal_to: måste vara samma som
+ less_than: måste vara mindre än %{count}
+ less_than_or_equal_to: måste vara mindre än eller lika med %{count}
+ odd: måste vara udda
+ even: måste vara jämnt
+ record_invalid: ! 'Ett fel uppstod: %{errors}'
activerecord:
errors:
- # model.errors.full_messages format.
template:
header:
- one: "Ett fel förhindrade denna %{model} från att sparas"
- other: "%{count} fel förhindrade denna %{model} från att sparas"
- body: "Det var problem med följande fält:"
-
+ one: Ett fel förhindrade denna %{model} från att sparas
+ other: ! '%{count} fel förhindrade denna %{model} från att sparas'
+ body: ! 'Det var problem med följande fält:'
messages:
- taken: "är upptaget"
- record_invalid: "Validering misslyckades: %{errors}"
- <<: *errors_messages
-
+ inclusion: finns inte i listan
+ exclusion: är reserverat
+ invalid: är ogiltigt
+ confirmation: stämmer inte överens
+ accepted: måste vara accepterad
+ empty: får ej vara tom
+ blank: måste anges
+ too_long: är för lång (maximum är %{count} tecken)
+ too_short: är för kort (minimum är %{count} tecken)
+ wrong_length: har fel längd (ska vara %{count} tecken)
+ taken: är upptaget
+ not_a_number: är inte ett nummer
+ not_an_integer: måste vara ett heltal
+ greater_than: måste vara större än %{count}
+ greater_than_or_equal_to: måste vara större än eller lika med %{count}
+ equal_to: måste vara samma som
+ less_than: måste vara mindre än %{count}
+ less_than_or_equal_to: måste vara mindre än eller lika med %{count}
+ odd: måste vara udda
+ even: måste vara jämnt
+ record_invalid: ! 'Validering misslyckades: %{errors}'
full_messages:
- format: "%{attribute} %{message}"
-
- # The values :model, :attribute and :value are always available for interpolation
- # The value :count is available when applicable. Can be used for pluralization.
- # Append your own errors here or at the model/attributes scope.
-
- # You can define own errors for models or model attributes.
- # The values :model, :attribute and :value are always available for interpolation.
- #
- # For example,
- # models:
- # user:
- # blank: "This is a custom blank message for %{model}: %{attribute}"
- # attributes:
- # login:
- # blank: "This is a custom blank message for User login"
- # Will define custom blank validation message for User model and
- # custom blank validation message for login attribute of User model.
- # models:
-
- # Translate model names. Used in Model.human_name().
- #models:
- # For example,
- # user: "Dude"
- # will translate User model name to "Dude"
-
- # Translate model attribute names. Used in Model.human_attribute_name(attribute).
- #attributes:
- # For example,
- # user:
- # login: "Handle"
- # will translate User attribute "login" as "Handle"
-
+ format: ! '%{attribute} %{message}'
date:
formats:
- # Use the strftime parameters for formats.
- # When no format has been given, it uses default.
- # You can provide other formats here if you like!
- default: "%Y-%m-%d"
- short: "%e %b"
- long: "%e %B %Y"
-
- day_names: [söndag, måndag, tisdag, onsdag, torsdag, fredag, lördag]
- abbr_day_names: [sön, mån, tis, ons, tor, fre, lör]
-
- # Don't forget the nil at the beginning; there's no such thing as a 0th month
- month_names: [~, januari, februari, mars, april, maj, juni, juli, augusti, september, oktober, november, december]
- abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, dec]
- # Used in date_select and datime_select.
+ default: ! '%Y-%m-%d'
+ short: ! '%e %b'
+ long: ! '%e %B %Y'
+ day_names:
+ - söndag
+ - måndag
+ - tisdag
+ - onsdag
+ - torsdag
+ - fredag
+ - lördag
+ abbr_day_names:
+ - sön
+ - mån
+ - tis
+ - ons
+ - tor
+ - fre
+ - lör
+ month_names:
+ -
+ - januari
+ - februari
+ - mars
+ - april
+ - maj
+ - juni
+ - juli
+ - augusti
+ - september
+ - oktober
+ - november
+ - december
+ abbr_month_names:
+ -
+ - jan
+ - feb
+ - mar
+ - apr
+ - maj
+ - jun
+ - jul
+ - aug
+ - sep
+ - okt
+ - nov
+ - dec
order:
- - :day
- - :month
- - :year
-
+ - :day
+ - :month
+ - :year
time:
formats:
- default: "%a, %e %b %Y %H:%M:%S %z"
- short: "%e %b %H:%M"
- long: "%e %B %Y %H:%M"
- am: ""
- pm: ""
-
- # Used in array.to_sentence.
+ default: ! '%a, %e %b %Y %H:%M:%S %z'
+ short: ! '%e %b %H:%M'
+ long: ! '%e %B %Y %H:%M'
+ am: ''
+ pm: ''
support:
array:
- words_connector: ", "
- two_words_connector: " och "
- last_word_connector: " och "
+ words_connector: ! ', '
+ two_words_connector: ! ' och '
+ last_word_connector: ! ' och '
select:
- # default value for :prompt => true in FormOptionsHelper
- prompt: "Välj"
+ prompt: Välj
diff --git a/config/locales/sv-SE_fat_free_crm.yml b/config/locales/sv-SE_fat_free_crm.yml
index 0945a1976a..29e16154b1 100644
--- a/config/locales/sv-SE_fat_free_crm.yml
+++ b/config/locales/sv-SE_fat_free_crm.yml
@@ -1,23 +1,15 @@
-# Swedish (Sweden) translation of Fat Free Crm.
-# by Xug Haa (https://github.com/xughaa)
-#
+---
sv-SE:
language: Svenska (Sverige)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: Alla
at: vid
here: här
- no_button: 'Nej'
+ no_button: Nej
not_implemented: Ej implementerad.
or: eller
- select_none: '-- Ingen --'
- select_blank: '-- Välj --'
- yes_button: 'Ja'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- Ingen --
+ select_blank: -- Välj --
+ yes_button: Ja
tab_dashboard: Kontrollpanel
tab_tasks: Ärende
tab_campaigns: Kampanjer
@@ -25,22 +17,18 @@ sv-SE:
tab_accounts: Konton
tab_contacts: Kontakter
tab_opportunities: Affärer
-
admin_tab_users: Användare
admin_tab_settings: Inställningar
admin_tab_plugins: Tilläggsmoduler
-
planned: Planerad
started: Påbörjad
on_hold: På is
completed: Avslutad
called_off: Avvisad
-
new: Ny
contacted: Kontaktade
converted: Konverterad
rejected: Avslag
-
cold_call: Kallringning
conference: Konferans
online: Web-marknadsföring
@@ -49,7 +37,6 @@ sv-SE:
web: Hemsida
word_of_mouth: Mun till mun
other: Övrigt
-
prospecting: Prospektering
analysis: Analys
presentation: Presentation
@@ -58,16 +45,13 @@ sv-SE:
final_review: Besulttagande
won: Avslutad positiv
lost: Avslutad negativ
-
call: Samtal
email: E-post
follow_up: Uppföljning
lunch: Lunch
meeting: Möte
money: Betalning
- presentation: Presentation
trip: Resa
-
overdue: Förfallen
due_asap: Snarast möjligt
due_today: Idag
@@ -76,24 +60,17 @@ sv-SE:
due_next_week: Nästa vecka
due_later: Senare
due_specific_date: Fast datum...
-
completed_today: Idag
completed_yesterday: Igår
completed_last_week: Förra veckan
completed_this_month: Denna månaden
completed_last_month: Förra månaden
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: En timma
one_day: En dag
two_days: Två dagar
one_week: En vecka
two_weeks: Två veckor
one_month: En månad
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -106,89 +83,86 @@ sv-SE:
account:
attributes:
name:
- missing_account_name: "^Ange ett kontonamn."
+ missing_account_name: ^Ange ett kontonamn.
access:
- share_account: "^Ange användarna som du vill dela kontot med."
+ share_account: ^Ange användarna som du vill dela kontot med.
campaign:
attributes:
name:
- missing_campaign_name: "^Ange namnet på kampanjen."
+ missing_campaign_name: ^Ange namnet på kampanjen.
ends_on:
- dates_not_in_sequence: "^Kampanjens slutdatum måste vara senare än startdatumet."
+ dates_not_in_sequence: ^Kampanjens slutdatum måste vara senare än startdatumet.
access:
- share_campaign: "^Ange användarna som du vil dela kampanjen med."
+ share_campaign: ^Ange användarna som du vil dela kampanjen med.
contact:
attributes:
first_name:
- missing_first_name: "^Ange förnamn."
+ missing_first_name: ^Ange förnamn.
last_name:
- missing_last_name: "^Ange efternamn."
+ missing_last_name: ^Ange efternamn.
access:
- share_contact: "^Ange användarna som du vill dela kontakten med."
+ share_contact: ^Ange användarna som du vill dela kontakten med.
lead:
attributes:
first_name:
- missing_first_name: "^Ange förnamn."
+ missing_first_name: ^Ange förnamn.
last_name:
- missing_last_name: "^Ange efternamn."
+ missing_last_name: ^Ange efternamn.
access:
- share_lead: "^Ange användarna som du vill dela leaden med."
+ share_lead: ^Ange användarna som du vill dela leaden med.
opportunity:
attributes:
name:
- missing_opportunity_name: "^Ange namnet på affären."
+ missing_opportunity_name: ^Ange namnet på affären.
access:
- share_opportunity: "^Ange användarna som du vill dela affären med."
+ share_opportunity: ^Ange användarna som du vill dela affären med.
task:
attributes:
name:
- missing_task_name: "^Ange namnet på ärendet."
+ missing_task_name: ^Ange namnet på ärendet.
calendar:
- invalid_date: "^Ange ett giltigt datum."
+ invalid_date: ^Ange ett giltigt datum.
user:
attributes:
username:
- missing_username: "^Ange användarnamn."
- username_taken: "^Detta användarnamn är redan taget."
+ missing_username: ^Ange användarnamn.
+ username_taken: ^Detta användarnamn är redan taget.
email:
- missing_email: "^Ange e-postadress."
- email_in_use: "^Det finns redan en användare med samma e-postadress."
-
- msg_account_suspended: "Användarkontot har spärrats."
- password_reset_instruction: "Instruktioner för återställandet av lösenordet."
-
- # Controllers.
- #----------------------------------------------------------------------------
- msg_account_created: "Ditt användarkonto har skapats och skall godkännas av systemadministratorn."
- msg_account_not_approved: "Ditt användarkonto har ej blivit godkännt ännu."
- msg_asset_deleted: "%{value} har tagits bort."
- msg_asset_not_available: "%{value} är ej längre tillgänglig/t."
- msg_assets_not_available: "%{value} är ej tillgängliga."
- msg_asset_rejected: "%{value} har avvisats."
- msg_bad_image_file: "^Omöjligt att ladda upp eller ändra storleken på bilden."
- msg_cant_create_related: "Omöjligt att skapa %{asset} därför att %{related} är ej längre tillgänglig/t."
- msg_cant_delete_user: "^Omöjligt att ta bort användaren därför att %{value} äger relaterad information."
- msg_cant_do: "Omöjligt att %{action} %{asset} eftersom den/det ej längre är tillgänglig/t."
- msg_email_not_found: "Ingen användare hittades med den angivna e-postadressen."
- msg_enter_new_password: "Ange ditt nya lösenord."
- msg_goodbye: "Du har loggats ut. Tack för att du använder detta program."
- msg_invalid_password: "^Ange ett giltigt lösenord."
- msg_invalig_login: "Ogiltigt användarnamn eller lösenord."
- msg_last_login: "Din senaste inloggning var den %{value}."
- msg_login_needed: "Du måste vara inloggad för att ha tillgång till denna sida."
- msg_logout_needed: "Du måste vara utloggad för att ha tillgång till denna sida."
- msg_password_changed: "Ditt lösenord har ändrats."
- msg_password_not_changed: "Ditt lösenord har inte ändrats."
- msg_password_updated: "Lösenordet har uppdaterats."
- msg_pwd_instructions_sent: "Instruktioner för att återställa ditt lösenord har skickats till dig. V.g. kontrollera din e-post."
- msg_require_admin: "Du måste ha administratorrättigheter för att ha tillgång till denna sida."
- msg_successful_signup: "Du är nu registrerad. Välkommen!"
+ missing_email: ^Ange e-postadress.
+ email_in_use: ^Det finns redan en användare med samma e-postadress.
+ msg_account_suspended: Användarkontot har spärrats.
+ password_reset_instruction: Instruktioner för återställandet av lösenordet.
+ msg_account_created: Ditt användarkonto har skapats och skall godkännas av systemadministratorn.
+ msg_account_not_approved: Ditt användarkonto har ej blivit godkännt ännu.
+ msg_asset_deleted: ! '%{value} har tagits bort.'
+ msg_asset_not_available: ! '%{value} är ej längre tillgänglig/t.'
+ msg_assets_not_available: ! '%{value} är ej tillgängliga.'
+ msg_asset_rejected: ! '%{value} har avvisats.'
+ msg_bad_image_file: ^Omöjligt att ladda upp eller ändra storleken på bilden.
+ msg_cant_create_related: Omöjligt att skapa %{asset} därför att %{related} är ej
+ längre tillgänglig/t.
+ msg_cant_delete_user: ^Omöjligt att ta bort användaren därför att %{value} äger
+ relaterad information.
+ msg_cant_do: Omöjligt att %{action} %{asset} eftersom den/det ej längre är tillgänglig/t.
+ msg_email_not_found: Ingen användare hittades med den angivna e-postadressen.
+ msg_enter_new_password: Ange ditt nya lösenord.
+ msg_goodbye: Du har loggats ut. Tack för att du använder detta program.
+ msg_invalid_password: ^Ange ett giltigt lösenord.
+ msg_invalig_login: Ogiltigt användarnamn eller lösenord.
+ msg_last_login: Din senaste inloggning var den %{value}.
+ msg_login_needed: Du måste vara inloggad för att ha tillgång till denna sida.
+ msg_logout_needed: Du måste vara utloggad för att ha tillgång till denna sida.
+ msg_password_changed: Ditt lösenord har ändrats.
+ msg_password_not_changed: Ditt lösenord har inte ändrats.
+ msg_password_updated: Lösenordet har uppdaterats.
+ msg_pwd_instructions_sent: Instruktioner för att återställa ditt lösenord har skickats
+ till dig. V.g. kontrollera din e-post.
+ msg_require_admin: Du måste ha administratorrättigheter för att ha tillgång till
+ denna sida.
+ msg_successful_signup: Du är nu registrerad. Välkommen!
msg_welcome: Välkommen!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": beräknat belopp
- activity_options: "Visa %{models} aktiviteterna utförda av %{user} under %{period}."
+ option_amount*probability: beräknat belopp
+ activity_options: Visa %{models} aktiviteterna utförda av %{user} under %{period}.
all_users: alla användare
option_after: efter
option_all: alla
@@ -214,10 +188,7 @@ sv-SE:
option_updated_at: datum uppdaterad
show_per_page: Visa %{number} %{models} per sida med formatet %{format}.
sort_by: Sortera %{models} på %{field}.
- sort_by_displaying: "Sortera %{models} på %{field} och visa förnamn %{position} efternamn."
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: Sortera %{models} på %{field} och visa förnamn %{position} efternamn.
aim: AOL IM
already_signed_up: Är du redan registrerad?
alt_email: Alternativ e-post
@@ -226,12 +197,12 @@ sv-SE:
contact_info: Kontakt information
current_password: Aktuellt lösenord
edit_profile: Ändra profil
- # email: E-post # <-- Already defined as the task type if Settings.
first_name: Förnamn
google: Google IM
gravatar_help: Känner du inte till Gravatars? Lär dig om Gravatars
image_file: Bildfil
- image_help: Bildfilen som du laddar upp kommer automatiskt att ändras till storlek 75 x 75 pixlar. Godkända format är GIF, JPG och PNG.
+ image_help: Bildfilen som du laddar upp kommer automatiskt att ändras till storlek
+ 75 x 75 pixlar. Godkända format är GIF, JPG och PNG.
job_title: Titel
last_name: Efternamn
login_now_link: Logga in nu!
@@ -252,17 +223,11 @@ sv-SE:
user: Användare
username: Användarnamn
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: Glömt lösenord
login: Logga in
no_account: Har du inget konto?
remember_me: Kom i håg mig
sign_up_now: Registrera dig nu!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
account: Konto
account_small: konto
accounts: konton
@@ -287,9 +252,6 @@ sv-SE:
share_with: Dela med följande personer
shipping_address: Leveransadress
website: Hemsida
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: Faktisk
actual_performance: Faktisk prestanda
budget: Budget
@@ -304,7 +266,7 @@ sv-SE:
campaigns_small: kampanjer
conversion: Konvertering
conversion_label: Konvertering (%)
- conversion_number: "%{value} konverterinsgrad"
+ conversion_number: ! '%{value} konverterinsgrad'
create_campaign: Skapa kampanj
end_date: Slutdatum
finished_on: avslutad %{value}
@@ -312,11 +274,13 @@ sv-SE:
no_start_date: startdatum ej angiven
number_of_leads: Antal leads
objectives: Målsättning
- objectives_help: Ange förväntade antal leads, förväntad konverteringsgrad, förväntade intäkter och kampanjbudget. Dessa siffror tillåter dig att övervaka kampanjens faktiska prestanda.
+ objectives_help: Ange förväntade antal leads, förväntad konverteringsgrad, förväntade
+ intäkter och kampanjbudget. Dessa siffror tillåter dig att övervaka kampanjens
+ faktiska prestanda.
objectives_small: campaign objectives
revenue: Intäkter
revenue_label: Intäkter (kr)
- revenue_number: "%{value} intäkter"
+ revenue_number: ! '%{value} intäkter'
save_campaign: Spara kampanj
start_date: Startdatum
started_ago: startade för %{value} sedan
@@ -327,9 +291,6 @@ sv-SE:
was_supposed_to_finish: skulle ha varit avslutad %{value}
was_supposed_to_start: skulle ha varit påbörjad för %{time_ago} sedan, dvs %{start_date}
was_supposed_to_start_in: påbörjas om %{starts_in}, dvs %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: Alternativ
blog: Hemsida/Blog
contact: Kontakt
@@ -339,37 +300,48 @@ sv-SE:
contacts_small: kontakter
create_contact: Skapa kontakt
department: Avdelning
- department_small: '%{value} avdelning'
+ department_small: ! '%{value} avdelning'
do_not_call: Ring ej
extra_info: Övrig
extra_info_small: övrig
facebook: Facebook
linked_in: LinkedIn
myself: Mig själv
- permissions_intro_private: Normalt har endast du tillgång till %{value}. Du kan ändra rättigheterna senare.
- permissions_intro_public: Normalt har alla användare tillgång till %{value}. Du kan ändra rättigheterna senare.
- permissions_intro_shared: Normalt har endast utvalda användare tillgågn till %{value}. Du kan ändra rättigheterna senare.
+ permissions_intro_private: Normalt har endast du tillgång till %{value}. Du kan
+ ändra rättigheterna senare.
+ permissions_intro_public: Normalt har alla användare tillgång till %{value}. Du
+ kan ändra rättigheterna senare.
+ permissions_intro_shared: Normalt har endast utvalda användare tillgågn till %{value}.
+ Du kan ändra rättigheterna senare.
referred_by: Refererad av
referred_by_small: refererad av
save_contact: Spara kontakt
twitter: Twitter
web_presence: Webadresser
web_presence_small: webadresser
- works_at: "%{job_title} på %{company}"
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
+ works_at: ! '%{job_title} på %{company}'
convert: Konvertera
convert_lead: Konvertera Lead
- convert_lead_permissions_intro: Kontakträttigheterna kopieras från leaden som konverteras. Du kan ändra rättigheterna senare.
- convert_lead_text: Genoma att konvertera leaden %{value}, så förvandlas leaden till en kontakt associerad med ett befintligt eller nyskapat konto. Statusen kommer att ändras automatiskt till konverterad.
+ convert_lead_permissions_intro: Kontakträttigheterna kopieras från leaden som konverteras.
+ Du kan ändra rättigheterna senare.
+ convert_lead_text: Genoma att konvertera leaden %{value}, så förvandlas leaden till
+ en kontakt associerad med ett befintligt eller nyskapat konto. Statusen kommer
+ att ändras automatiskt till konverterad.
create_lead: Skapa lead
- create_opp_for_contact: Du kan välja att skapa en affär med kontakten %{value} genom att namnge affären och ange nuvarande skede, beräknat avslutningsdatum, försäljningssannolikhet, affärens belopp, och erbjuden rabatt.
+ create_opp_for_contact: Du kan välja att skapa en affär med kontakten %{value} genom
+ att namnge affären och ange nuvarande skede, beräknat avslutningsdatum, försäljningssannolikhet,
+ affärens belopp, och erbjuden rabatt.
lead: Lead
lead_info_small: lead kontakt
- lead_permissions_intro_private: Normalt kommer rättigheterna att bli kopierade från kampanjen eller så blir de privata rättigheter. Du kan ändra rättigherna på leaden senare.
- lead_permissions_intro_public: Normalt kommer rättigheterna att bli kopierade från kampanjen eller så blir de publika rättigheter. Du kan ändra rättigheterna på leaden senare.
- lead_permissions_intro_shared: Normalt kommer rättigheterna att bli kopierade från kampanjen eller så blir de delade rättigheter med specificerade användare. Du kan ändra rättigheterna på leaden senare.
+ lead_permissions_intro_private: Normalt kommer rättigheterna att bli kopierade från
+ kampanjen eller så blir de privata rättigheter. Du kan ändra rättigherna på leaden
+ senare.
+ lead_permissions_intro_public: Normalt kommer rättigheterna att bli kopierade från
+ kampanjen eller så blir de publika rättigheter. Du kan ändra rättigheterna på
+ leaden senare.
+ lead_permissions_intro_shared: Normalt kommer rättigheterna att bli kopierade från
+ kampanjen eller så blir de delade rättigheter med specificerade användare. Du
+ kan ändra rättigheterna på leaden senare.
lead_small: lead
lead_status_small: lead status
lead_summary: Lead översikt
@@ -384,9 +356,6 @@ sv-SE:
source: Källa
status: Status
total_leads: Totala Leads
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: Belopp
close_date: Slutdatum
closed_ago_on: avslutad %{time_ago} sedan, dvs. %{date}
@@ -408,7 +377,7 @@ sv-SE:
opportunity: Affär
opportunity_small: affär
opportunity_summary: Affärsöversikt
- opportunity_summary_text: "%{amount} med rabatt %{discount} och sannolikhet %{probability}"
+ opportunity_summary_text: ! '%{amount} med rabatt %{discount} och sannolikhet %{probability}'
past_due: förfallen, skulle ha varit avslutad %{value} sedan
probability: Sannolikhet
probability_number: och sannolikhet %{value}
@@ -416,9 +385,6 @@ sv-SE:
stage: Skede
total_opportunities: Totala Affärer
weighted_amount: Beräknat belopp
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: Tilldela till
assigned_tab: Tilldelade
assigned_tasks: Tilldelade Ärenden
@@ -430,13 +396,13 @@ sv-SE:
due: Förfaller
feel_free: Tveka inte att
move_to: flytta till
- no_tasks: "Du har inga ärenden %{value}"
+ no_tasks: Du har inga ärenden %{value}
no_tasks_pending: på Kö
no_tasks_assigned: tilldelade
no_tasks_completed: utförda
pending_tab: På kö
pending_tasks: Ärenden på kö
- related: 'SV:'
+ related: ! 'SV:'
save_task: Spara ärendet
task_assigned: Ärendet har tilldelats till %{value}
task_assigned_to: och tilldelats till %{value}
@@ -456,20 +422,17 @@ sv-SE:
total_tasks: Antal %{value}
view_assigned_tasks: visa tilldelade ärenden
view_pending_tasks: visa ärenden på kö
-
- # Views -> Home.
- #----------------------------------------------------------------------------
- action_commented: "har kommenterat:"
+ action_commented: ! 'har kommenterat:'
action_completed: utförd
- action_created: "har skapat:"
- action_deleted: "har tagit bort:"
- action_email: "har utväxlat e-post med:"
- action_reassigned: "vidare tilldelat:"
- action_rejected: "har avvisat:"
- action_rescheduled: "har omplanerat:"
- action_updated: "har uppdaterat:"
- action_viewed: "har undersökt:"
- action_won: "har vunnit:"
+ action_created: ! 'har skapat:'
+ action_deleted: ! 'har tagit bort:'
+ action_email: ! 'har utväxlat e-post med:'
+ action_reassigned: ! 'vidare tilldelat:'
+ action_rejected: ! 'har avvisat:'
+ action_rescheduled: ! 'har omplanerat:'
+ action_updated: ! 'har uppdaterat:'
+ action_viewed: ! 'har undersökt:'
+ action_won: ! 'har vunnit:'
no_activity_records: Aktivitet poster saknas.
recent_activity: Senaste aktiviteter
recent_activity_options: Aktivitetsalternativ
@@ -479,9 +442,6 @@ sv-SE:
subject_lead: lead
subject_opportunity: affär
subject_task: ärende
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: Lägg till anteckning
save_note: Spara anteckning
add_note_help: Lägg till en ny antekning...
@@ -493,20 +453,20 @@ sv-SE:
close_form: Stäng sidan
confirm_delete: Är du säker på att du vill ta bort denna/detta %{value}?
copy_permissions: Kopiera %{value} rättigheter
- could_not_find: "Kunde inte hitta: %{value}. Tveka inte att"
- could_not_find_matching: "Inga %{value} hittades som matchade"
+ could_not_find: ! 'Kunde inte hitta: %{value}. Tveka inte att'
+ could_not_find_matching: Inga %{value} hittades som matchade
create_new: skapa nytt
select_existing: välj befintligt
delete: Ta bort
discard: Kasta bort
edit: Ändra
- items_total: 'totalt: %{count}.'
+ items_total: ! 'totalt: %{count}.'
less: Mindre...
me: mig
more: Mera...
n_a: saknas
name: Namn
- no_match: "Inga %{value} hittades som matchade"
+ no_match: Inga %{value} hittades som matchade
no_recent_items: Det finns inga nya poster att visa ännu.
options: Alternativ
permissions: Rättigheter
@@ -517,18 +477,15 @@ sv-SE:
select_task: Välj ärende
select_opportunity: Välj affär
search_assets: Sök %{value}
- time_ago: "%{value} sedan"
+ time_ago: ! '%{value} sedan'
background_info: Bakgrund
address: Adress
- street1: Rad 1 # NEW
- street2: Rad 2 # NEW
+ street1: Rad 1
+ street2: Rad 2
city: Ort
zipcode: Postkod
state: Stat/region
country: Land
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: Om
about_dev_group: Diskussionsgrupp för utvecklare
about_features: Funktioner och buggar
@@ -544,27 +501,16 @@ sv-SE:
logout: Logga ut
quick_find: Snabbsökning
welcome: Välkommen
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: Ändra kommentar
show: Visa
update: Uppdatera
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: Skriv ditt nya lösenord och bekräfta det.
- password_intro: Ange din e-postadress och instruktioner för att återställa ditt lösenord kommer att skickas til dig.
+ password_intro: Ange din e-postadress och instruktioner för att återställa ditt
+ lösenord kommer att skickas til dig.
reset_password: Återställ lösenord
update_password_and_login: Uppdatera lösenord och inloggingsuppgifter
-
- # Views -> Admin
- #----------------------------------------------------------------------------
back_to_crm: Tillbaks till huvudprogrammet
crm_admin_page: Administration
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: Godkänn
create_user: Skapa användare
last_seen: senast inloggad %{value} sedan
@@ -575,9 +521,10 @@ sv-SE:
user_active: Aktiv
user_admin: Administrator
user_awaits_approval: inväntar godkännandet
- user_confirm_delete: En användare får tas bort endast om det inte finns relaterad kvarstående information.
+ user_confirm_delete: En användare får tas bort endast om det inte finns relaterad
+ kvarstående information.
user_is_admin: Användaren är administrator
- user_never_logged_in: "har inte loggat in ännu"
+ user_never_logged_in: har inte loggat in ännu
user_signed_up: Registrerad
user_signed_up_on: registrerade %{value}
user_since: användare sedan %{value}
@@ -585,44 +532,33 @@ sv-SE:
user_suspended_on: avstängd %{value}
users: Användare
users_small: användare
-
- # Dropbox.
- #----------------------------------------------------------------------------
dropbox_notification_subject: Dropbox - e-postadress tillagd - %{subject}
dropbox_notification_intro: E-postmeddelandet har lagts till i Dropbox
dropbox_notification_to: Lagts till
subject: Ämne
body: Text
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
contact:
- one: '1 kontakt'
- other: '%{count} kontakter'
+ one: 1 kontakt
+ other: ! '%{count} kontakter'
opportunity:
- one: '1 affär'
- other: '%{count} affärer'
+ one: 1 affär
+ other: ! '%{count} affärer'
lead:
- one: '1 lead'
- other: '%{count} leads'
+ one: 1 lead
+ other: ! '%{count} leads'
day:
- one: '1 dag'
- other: '%{count} dagar'
+ one: 1 dag
+ other: ! '%{count} dagar'
login:
- one: '1 inloggning'
- other: '%{count} inloggningar'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 inloggning
+ other: ! '%{count} inloggningar'
date:
formats:
- mmddyyyy: "%Y-%m-%d"
- mmdd: "%b %e"
- mmddyy: "%B %e, %Y"
-
-
+ mmddyyyy: ! '%Y-%m-%d'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%B %e, %Y'
time:
formats:
- mmddhhss: "%b %e, kl %H:%M"
- mmddyyyy_hhmm: "%m/%d/%Y %l:%M %p"
+ mmddhhss: ! '%b %e, kl %H:%M'
+ mmddyyyy_hhmm: ! '%m/%d/%Y %l:%M %p'
diff --git a/config/locales/th_fat_free_crm.yml b/config/locales/th_fat_free_crm.yml
index bb12af60ed..537269d96f 100644
--- a/config/locales/th_fat_free_crm.yml
+++ b/config/locales/th_fat_free_crm.yml
@@ -1,20 +1,15 @@
+---
th:
language: Thai (ไทย)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: ทั้งหมด
at: ที่
here: ที่นี่
- no_button: 'ไม่ใช่'
+ no_button: ไม่ใช่
not_implemented: อยู่ระหว่างการพัฒนา.
or: หรือ
- select_blank: '-- เลือก --'
- select_none: '-- ว่าง --'
- yes_button: 'ใช่'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_blank: -- เลือก --
+ select_none: -- ว่าง --
+ yes_button: ใช่
tab_dashboard: สรุปงาน
tab_tasks: ภารกิจ
tab_campaigns: แคมเปญ
@@ -22,22 +17,18 @@ th:
tab_accounts: ลูกค้า
tab_contacts: รายชื่อติดต่อ
tab_opportunities: โอกาสปิดการขาย
-
admin_tab_users: รายชื่อผู้ใช้
admin_tab_settings: ตั้งค่า
admin_tab_plugins: ส่วนเสริม
-
planned: วางแผน
started: เริ่มต้น
on_hold: ระงับ
completed: เสร็จสมบูรณ์
called_off: เรียกว่าปิด
-
new: สร้าง
contacted: เป็นผู้ติดต่อ
converted: แปลงแล้ว
rejected: ปฏิเสธ
-
cold_call: สุ่มโทร
conference: สัมนา
online: การตลาดออนไลท์
@@ -46,7 +37,6 @@ th:
web: เว๊บไซต์
word_of_mouth: บอกต่อ
other: อื่นๆ
-
prospecting: หวังจะได้เป็นลูกค้า
analysis: วิเคระห์
presentation: นำเสนอ
@@ -55,42 +45,32 @@ th:
final_review: ตรวจรอบสุดท้าย
won: ปิดมีกำไร
lost: ปิดขาดทุน
-
call: โทร
email: อีเมล์
follow_up: ติดตามงาน
lunch: ทานข้าว
meeting: ประชุม
money: เก็บเงิน
- presentation: นำเสนอ
trip: เดินทาง
-
- overdue: "เกินกำหนด"
- due_asap: "เร็วที่สุดเท่าที่เป็นไปได้"
- due_today: "วันนี้"
- due_tomorrow: "พรุ่งนี้"
- due_this_week: "อาทิตย์นี้"
- due_next_week: "อาทิตย์หน้า"
- due_later: "วันหลัง"
- due_specific_date: On Specific Date... # TODO
-
- completed_today: "วันนี้"
- completed_yesterday: "เมื่อวานนี้"
- completed_last_week: "อาทิตย์ก่อน"
- completed_this_month: "เดือนนี้"
- completed_last_month: "เดือนก่อน"
-
- # Models/Activity.
- #----------------------------------------------------------------------------
+ overdue: เกินกำหนด
+ due_asap: เร็วที่สุดเท่าที่เป็นไปได้
+ due_today: วันนี้
+ due_tomorrow: พรุ่งนี้
+ due_this_week: อาทิตย์นี้
+ due_next_week: อาทิตย์หน้า
+ due_later: วันหลัง
+ due_specific_date: On Specific Date...
+ completed_today: วันนี้
+ completed_yesterday: เมื่อวานนี้
+ completed_last_week: อาทิตย์ก่อน
+ completed_this_month: เดือนนี้
+ completed_last_month: เดือนก่อน
one_hour: หนึ่งชั่วโมง
one_day: หนึ่งวัน
two_days: สองวัน
one_week: หนึ่งสัปดาห์
two_weeks: สองสัปดาห์
one_month: หนึ่งเดือน
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -103,83 +83,76 @@ th:
account:
attributes:
name:
- missing_account_name: "^โปรดระบุบัญชีผู้ใช้."
+ missing_account_name: ^โปรดระบุบัญชีผู้ใช้.
access:
- share_account: "^โปรดระบุผู้ใช้ที่ต้องการใช้บัญชีร่วมกัน"
+ share_account: ^โปรดระบุผู้ใช้ที่ต้องการใช้บัญชีร่วมกัน
campaign:
attributes:
name:
- missing_campaign_name: "^โปรดระบุชื่อแคมเปญ"
+ missing_campaign_name: ^โปรดระบุชื่อแคมเปญ
ends_on:
- dates_not_in_sequence: "^โปรดตรวจสอบอีกครั้งว่าวันสิ้นสุดแคมเปญอยู่หลังจากวันเริ่มต้น."
+ dates_not_in_sequence: ^โปรดตรวจสอบอีกครั้งว่าวันสิ้นสุดแคมเปญอยู่หลังจากวันเริ่มต้น.
access:
- share_campaign: "^โปรดระบุผู้ใช้ที่ต้องการใช้แคมเปญร่วมกัน"
+ share_campaign: ^โปรดระบุผู้ใช้ที่ต้องการใช้แคมเปญร่วมกัน
contact:
attributes:
first_name:
- missing_first_name: "^โปรดระบุชื่อจริง"
+ missing_first_name: ^โปรดระบุชื่อจริง
last_name:
- missing_last_name: "^โปรดระบุนามสกุล"
+ missing_last_name: ^โปรดระบุนามสกุล
access:
- share_contact: "^โปรดระบุผู้ใช้ที่ต้องการใช้ที่อยู่ติดต่อร่วมกัน"
+ share_contact: ^โปรดระบุผู้ใช้ที่ต้องการใช้ที่อยู่ติดต่อร่วมกัน
lead:
attributes:
first_name:
- missing_first_name: "^โปรดระบุชื่อจริง"
+ missing_first_name: ^โปรดระบุชื่อจริง
last_name:
- missing_last_name: "^โปรดระบุนามสกุล"
+ missing_last_name: ^โปรดระบุนามสกุล
access:
- share_lead: "^โปรดระบุผู้ใช้ที่ต้องการใช้รายการผู้สนใจร่วมกัน"
+ share_lead: ^โปรดระบุผู้ใช้ที่ต้องการใช้รายการผู้สนใจร่วมกัน
opportunity:
attributes:
name:
- missing_opportunity_name: "^โปรดระบุชื่อของโอกาสปิดการขาย"
+ missing_opportunity_name: ^โปรดระบุชื่อของโอกาสปิดการขาย
access:
- share_opportunity: "^โปรดระบุผู้ใช้ที่ต้องการใช้โอกาสปิดการขายร่วมกัน"
+ share_opportunity: ^โปรดระบุผู้ใช้ที่ต้องการใช้โอกาสปิดการขายร่วมกัน
task:
attributes:
name:
- missing_task_name: "^โปรดระบุชื่อภาระกิจ"
+ missing_task_name: ^โปรดระบุชื่อภาระกิจ
calendar:
- invalid_date: "^โปรดระบุวันที่ให้ถูกต้อง"
+ invalid_date: ^โปรดระบุวันที่ให้ถูกต้อง
user:
attributes:
username:
- missing_username: "^โปรดระบุชื่อผู้ใช้"
- username_taken: "^ชื่อนี้ได้ถูกใช้แล้ว"
+ missing_username: ^โปรดระบุชื่อผู้ใช้
+ username_taken: ^ชื่อนี้ได้ถูกใช้แล้ว
email:
- missing_email: "^โปรดระบุอีเมล์ที่ใช้"
- email_in_use: "^มีผู้ใช้อื่นที่ใช้อีเมล์นี้แล้ว"
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ missing_email: ^โปรดระบุอีเมล์ที่ใช้
+ email_in_use: ^มีผู้ใช้อื่นที่ใช้อีเมล์นี้แล้ว
errors:
template:
header:
- one: "พบข้อผิดพลาด %{count} ประการ ทำให้ไม่สามารถบันทึก%{model}ได้"
- other: "พบข้อผิดพลาด %{count} ประการ ทำให้ไม่สามารถบันทึก%{model}ได้"
- body: "โปรดตรวจสอบข้อมูลในช่องต่อไปนี้:"
-
+ one: พบข้อผิดพลาด %{count} ประการ ทำให้ไม่สามารถบันทึก%{model}ได้
+ other: พบข้อผิดพลาด %{count} ประการ ทำให้ไม่สามารถบันทึก%{model}ได้
+ body: ! 'โปรดตรวจสอบข้อมูลในช่องต่อไปนี้:'
msg_account_suspended: บัญชีผู้ใช้ถูกระงับแล้ว.
password_reset_instruction: ขั้นตอนการตั้งค่ารหัสผ่าน
-
- # Controllers.
- #----------------------------------------------------------------------------
msg_account_created: บัญชีของคุณได้ถูกสร้างแล้ว และรอการอนุมัติโดยผู้ดูแลระบบ
msg_account_not_approved: บัญชีของคุณยังไม่ได้รับการอนุมัติ
- msg_asset_deleted: "%{value} ได้ถูกลบไปแล้ว"
+ msg_asset_deleted: ! '%{value} ได้ถูกลบไปแล้ว'
msg_asset_not_available: เอกสาร %{value} ไม่มีในระบบ
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
msg_assets_not_available: เอกสาร %{value} ไม่มีในระบบ.
- msg_asset_rejected: "%{value} ได้ถูกปฏิเสธแล้ว"
- msg_bad_image_file: "^ไม่สามารถอัปโหลดหรือเปลี่ยนขนาดของรูปภาพที่คุณระบุได้"
- msg_cant_create_related: "ไม่สามารถสร้าง%{asset}ได้ เพราะ%{related}ไม่มีในระบบ"
- msg_cant_delete_user: "^ไม่สามารถลบผู้ใช้ตั้งแต่ %{value} มีเอกสารที่อ้างอิงถึง"
- msg_cant_do: "ไม่สามารถ%{action}ของ%{asset} เพราะไม่มีเอกสารแล้ว"
+ msg_asset_rejected: ! '%{value} ได้ถูกปฏิเสธแล้ว'
+ msg_bad_image_file: ^ไม่สามารถอัปโหลดหรือเปลี่ยนขนาดของรูปภาพที่คุณระบุได้
+ msg_cant_create_related: ไม่สามารถสร้าง%{asset}ได้ เพราะ%{related}ไม่มีในระบบ
+ msg_cant_delete_user: ^ไม่สามารถลบผู้ใช้ตั้งแต่ %{value} มีเอกสารที่อ้างอิงถึง
+ msg_cant_do: ไม่สามารถ%{action}ของ%{asset} เพราะไม่มีเอกสารแล้ว
msg_email_not_found: ไม่มีผู้ใช้ที่ใช้อีเมล์นี้
msg_enter_new_password: โปรดใส่ระหัสผ่านตัวใหม่
msg_goodbye: คุณได้ออกจากระบบแล้ว ขอบคุณที่ใช้งานโปรแกรม Fat Free CRM
- msg_invalid_password: "^โปรดระบุรหัสผ่านตัวปัจจุบันให้ถูกต้อง"
+ msg_invalid_password: ^โปรดระบุรหัสผ่านตัวปัจจุบันให้ถูกต้อง
msg_invalig_login: ชื่อผู้ใช้ หรือ รหัสผ่าน ไม่ถูกต้อง
msg_last_login: ครั้งสุดท้านที่คุณเข้าสู่ระบบคือ %{value}.
msg_login_needed: คุณต้องเข้าสู่ระบบเพื่อเข้าหน้านี้
@@ -191,10 +164,7 @@ th:
msg_require_admin: คุณต้องเป็นผู้ดูแลระบบเพื่อเข้าหน้านี้
msg_successful_signup: สมัครสมาชิกเรียบร้อยแล้ว ยินดีต้อนรับสู่ Fat Free CRM
msg_welcome: ยินดีต้อนรับสู่ Fat Free CRM
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": จำนวนถ่วงน้ำหนัก
+ option_amount*probability: จำนวนถ่วงน้ำหนัก
activity_options: แสดง%{models}ที่เกิดขึ้น โดย%{user} ในช่วง%{period}ที่ผ่านมา.
all_users: ผู้ใช้ทุกคน
option_after: หลัง
@@ -222,9 +192,6 @@ th:
show_per_page: แสดง %{number} %{models} ต่อหนึ่งหน้า ในแบบ %{fmt}
sort_by: เรียงลำดับ%{models} โดย %{field}.
sort_by_displaying: เรียงลำดับ%{models} โดย %{field} แสดงชื่อจริง %{position} นามสกุล.
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
aim: AOL IM
already_signed_up: เป็นสมาชิกอยู่แล้ว
alt_email: อีเมล์ ทางเลือก
@@ -234,12 +201,12 @@ th:
contact_info: ข้อมูลใช้ในการติดต่อ
current_password: รหัสผ่านปัจจุบัน
edit_profile: แก้ไขโพรไฟล์
- # email: อีเมล์ # <-- Already defined as the task type if Settings.
first_name: ชื่อจริง
google: Google IM
gravatar_help: หากไม่เข้าใจ Gravatars ลองเรียนรูป Gravatars ได้
image_file: ไฟล์รูปภาพ
- image_help: หลังจากอัปโหลดจะถูกเปลี่ยนขนาดเป็น 75x75 pixels และ รูปภาพที่ใช้จะต้องเป็น GIF, JPG หรือ PNG เท่านั้น
+ image_help: หลังจากอัปโหลดจะถูกเปลี่ยนขนาดเป็น 75x75 pixels และ รูปภาพที่ใช้จะต้องเป็น
+ GIF, JPG หรือ PNG เท่านั้น
job_title: ตำแหน่ง
last_name: นามสกุล
login_now_link: เข้าสู่ระบบทันที !
@@ -260,19 +227,13 @@ th:
user: ผู้ใช้
username: ชื่อผู้ใช้
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: ลืมรหัสผ่าน
login: เข้าระบบ
no_account: ไม่มีชื่อในรายการสมาชิก
remember_me: จำฉันไว้
sign_up_now: สมัครสามาชิกได้เลย
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
accounts: รายการลูกค้า
- account_permissions_intro: "ในเบื่องต้น จะมีเฉพาะคุณที่สามารถเข้าถึงรายการได้ แต่คุณสามารถแก้เงื่อนไขได้ในภายหลัง"
+ account_permissions_intro: ในเบื่องต้น จะมีเฉพาะคุณที่สามารถเข้าถึงรายการได้ แต่คุณสามารถแก้เงื่อนไขได้ในภายหลัง
accounts_small: รายการลูกค้า
account: ลูกค้า
accounts_options: ตัวเลือกสำหรับลูกค้า
@@ -295,9 +256,6 @@ th:
share_with: กำหนดผู้ที่เห็นได้ดังต่อไปนี้
shipping_address: ที่อยู่สำหรับส่งของ
website: เว็บไซต์
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
actual: เกิดขึ้นจริง
actual_performance: ประสิทธิที่เกิดขึ้นจริง
budget: งบประมาณ
@@ -312,7 +270,7 @@ th:
campaigns_small: รายการแคมเปญ
conversion: การแปลง
conversion_label: แปลง (%)
- conversion_number: "แปลง %{value} ราย"
+ conversion_number: แปลง %{value} ราย
create_campaign: เพิ่มแคมเปญ
end_date: วันสิ้นสุด
finished_on: เสร็จสมบูรณ์ %{value}
@@ -320,11 +278,13 @@ th:
no_start_date: ไม่ระบุวันเริ่มต้น
number_of_leads: จำนวนผู้สนใจ
objectives: เป้าหมาย
- objectives_help: โปรดระบุจำนวนผู้สนใจ ค่าความคาดหวังที่จะแปลงจากผู้สนใจไปเป็นผู้มีโอกาสปิดการขาย รายได้ที่จะได้รับ และ งบประมาณที่ต้องใช้ ตัวเลขเหล่านี้จะช่วยให้คุณติดตามประสิทธิภาพจริงๆ ของโครงการ
+ objectives_help: โปรดระบุจำนวนผู้สนใจ ค่าความคาดหวังที่จะแปลงจากผู้สนใจไปเป็นผู้มีโอกาสปิดการขาย
+ รายได้ที่จะได้รับ และ งบประมาณที่ต้องใช้ ตัวเลขเหล่านี้จะช่วยให้คุณติดตามประสิทธิภาพจริงๆ
+ ของโครงการ
objectives_small: เป้าหมายของแคมเปญ
revenue: รายได้
revenue_label: รายได้ (฿)
- revenue_number: "รายได้ %{value}"
+ revenue_number: รายได้ %{value}
save_campaign: บันทึกแคมเปญ
start_date: วันเริ่มต้น
started_ago: เริ่มต้น%{value}ที่ผ่านมา
@@ -334,9 +294,6 @@ th:
total_campaigns: จำนวนแคมเปณ
was_supposed_to_finish: ควรจะเสร็จตั้งแต่ %{value}
was_supposed_to_start: ควรจะเสร็จตั้งแต่ %{time_ago} ที่ผ่านมา คือ %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: อื่นๆ
blog: website/blog
contact: ที่อยู่ติดต่อ
@@ -346,19 +303,19 @@ th:
contacts_small: ที่อยู่ติดต่อ
create_contact: เพิ่มผู้ติดต่อ
department: แผนก
- department_small: 'แผนก %{value}'
+ department_small: แผนก %{value}
do_not_call: ห้ามโทร
extra_info: ข้อมูลเพิ่มเติม
extra_info_small: ที่อยู่ติดต่อเพิ่มเติม
facebook: Facebook
linked_in: LinkedIn
myself: ตัวฉัน
-
- # TODO
- permissions_intro_private: By default only you will have access to the %{value}. You can change permissions later.
- permissions_intro_public: By default all users will have access to the %{value}. You can change permissions later.
- permissions_intro_shared: By default only the selected users will have access to the %{value}. You can change permissions later.
-
+ permissions_intro_private: By default only you will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_public: By default all users will have access to the %{value}.
+ You can change permissions later.
+ permissions_intro_shared: By default only the selected users will have access to
+ the %{value}. You can change permissions later.
permissions_intro: เบื้องต้นจะมีเฉพาะคุณเท่านั้นที่เห็น %{value} แต่สามารถเปลี่ยนได้ในภายหลัง
referred_by: แนะนำโดย
referred_by_small: แนะนำโดย
@@ -366,24 +323,23 @@ th:
twitter: Twitter
web_presence: ผ่านเว็บ
web_presence_small: ผ่านเว็บ
- contacts_options: กรองที่อยู่ติดต่อ
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
convert: แปลง
convert_lead: แปลงผู้สนใจ
- convert_lead_permissions_intro: สิทธิ์ของที่อยู่ติดต่อจะคัดลอกมาจากผู้สนใจเมื่อมีการแปลงเกิดขึ้น แต่สามารถเปลี่ยนได้ในภายหลัง
- convert_lead_text: การแปลงผู้สนใจ %{value} จะกลายที่อยู่ติดต่อใหม่ หรือใช้ที่อยู่ที่มีแล้ว หรือสร้างเพิ่มได้ อย่างไรก็ตามผู้สนใจจะถูกกำหนดสถานะเป็น แปลงแล้ว
+ convert_lead_permissions_intro: สิทธิ์ของที่อยู่ติดต่อจะคัดลอกมาจากผู้สนใจเมื่อมีการแปลงเกิดขึ้น
+ แต่สามารถเปลี่ยนได้ในภายหลัง
+ convert_lead_text: การแปลงผู้สนใจ %{value} จะกลายที่อยู่ติดต่อใหม่ หรือใช้ที่อยู่ที่มีแล้ว
+ หรือสร้างเพิ่มได้ อย่างไรก็ตามผู้สนใจจะถูกกำหนดสถานะเป็น แปลงแล้ว
create_lead: เพิ่มผู้สนใจ
- create_opp_for_contact: คุณสามารถสร้าง โอกาศปิดการขาย สำหรับ %{value} ผู้ติดต่อ โดยกำหนดชื่อ สถานะปัจจุบัน คาดการวันปิด โอกาสปิดการขาย มูลค่า และส่วนลด
+ create_opp_for_contact: คุณสามารถสร้าง โอกาศปิดการขาย สำหรับ %{value} ผู้ติดต่อ
+ โดยกำหนดชื่อ สถานะปัจจุบัน คาดการวันปิด โอกาสปิดการขาย มูลค่า และส่วนลด
lead: ผู้สนใจ
lead_info_small: ที่อยู่ผู้สนใจ
-
- # TODO
- lead_permissions_intro_private: By default permissions will be copied from the campaign or set to private. You can change lead permissions later.
- lead_permissions_intro_public: By default permissions will be copied from the campaign or set to public. You can change lead permissions later.
- lead_permissions_intro_shared: By default permissions will be copied from the campaign or shared with the specified users. You can change lead permissions later.
-
+ lead_permissions_intro_private: By default permissions will be copied from the campaign
+ or set to private. You can change lead permissions later.
+ lead_permissions_intro_public: By default permissions will be copied from the campaign
+ or set to public. You can change lead permissions later.
+ lead_permissions_intro_shared: By default permissions will be copied from the campaign
+ or shared with the specified users. You can change lead permissions later.
lead_small: ผู้สนใจ
lead_status_small: สถานะของผู้สนใจ
lead_summary: สรุปผู้สนใจ
@@ -398,9 +354,6 @@ th:
source: แหล่ง
status: สถานะ
total_leads: ผู้สนใจทั้งหมด
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: รวม
close_date: วันที่ปิด
closed_ago_on: ปิด %{time_ago} ที่ผ่านมา ตั้งแต่ %{date}
@@ -422,7 +375,8 @@ th:
opportunity: โอกาสปิดการขาย
opportunity_small: โอกาสปิดการขาย
opportunity_summary: สรุปโอกาสที่ได้อย่างรวดเร็ว
- opportunity_summary_text: "%{amount} โดยมีส่วนลด %{discount} และความน่าจะเป็น %{probability}"
+ opportunity_summary_text: ! '%{amount} โดยมีส่วนลด %{discount} และความน่าจะเป็น
+ %{probability}'
past_due: เลยกำหนด, คาดว่าจะปิดได้ %{value} ที่แล้ว
probability: ความน่าจะเป็น
probability_number: และมีความน่าจะเป็น %{value}
@@ -430,9 +384,6 @@ th:
stage: ระดับสถานะ
total_opportunities: โอกาสปิดการขายทั้งหมด
weighted_amount: จำนวนถ่วงน้ำหนัก
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: มอบหมายให้
assigned_tab: มอบหมาย
assigned_tasks: มอบหมายภารกิจแล้ว
@@ -444,13 +395,13 @@ th:
due: ครบกำหนด
feel_free: กรอกข้อมูลได้เลย
move_to: ย้ายไป
- no_tasks: "คุณไม่มีภารกิจ%{value}"
- no_tasks_pending: pending # TODO
- no_tasks_assigned: assigned # TODO
- no_tasks_completed: completed # TODO
+ no_tasks: คุณไม่มีภารกิจ%{value}
+ no_tasks_pending: pending
+ no_tasks_assigned: assigned
+ no_tasks_completed: completed
pending_tab: งานค้าง
pending_tasks: งานคงค้าง
- related: 're:'
+ related: ! 're:'
save_task: บันทึกภารกิจ
task_assigned: ภารกิจได้ถูกมอบหมายให้ %{value}
task_assigned_to: และได้มอบหมายให้ %{value}
@@ -470,20 +421,17 @@ th:
total_tasks: ทั้งหมด %{value}
view_assigned_tasks: ดูงานที่มอบหมายแล้ว
view_pending_tasks: ดูงานคงค้าง
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: ใส่คำแนะนำ
action_completed: เสร็จสมบูรณ์
action_created: สร้าง
action_deleted: ลบ
- action_email: exchanged emails with # TODO
+ action_email: exchanged emails with
action_reassigned: มอบหมายให้คนอื่น
action_rejected: ยกเลิกแล้ว
action_rescheduled: ใส่กำหนดการ
action_updated: แก้ไข
action_viewed: แสดง
- action_won: won # TODO
+ action_won: won
no_activity_records: ไม่พบบันทึกกิจกรรม
recent_activity: กิจกรรมล่าสุด
recent_activity_options: กิจกรรมล่าสุดเพิ่มเติม
@@ -493,11 +441,8 @@ th:
subject_lead: ผู้สนใจ
subject_opportunity: โอกาสปิดการขาย
subject_task: ภารกิจ
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: เพิ่มบันทึก
- save_note: Save Note # TODO
+ save_note: Save Note
add_note_help: Add a new note...
added_ago: สร้าง %{value} ที่ผ่านมา
added_by: สร้าง %{time_ago} ที่ผ่านมา โดย %{user}
@@ -506,17 +451,17 @@ th:
close_form: ปิดฟอร์ม
confirm_delete: คุณแน่ใจที่จะลบ%{value}หรือไม่
copy_permissions: คัดลอก%{value}สิทธิ์
- could_not_find: "ไม่พบ%{value} สามารถทดลอง"
- could_not_find_matching: "ไม่พบ%{value}ที่ตรงกับคำค้นหา"
+ could_not_find: ไม่พบ%{value} สามารถทดลอง
+ could_not_find_matching: ไม่พบ%{value}ที่ตรงกับคำค้นหา
create_new: สร้าง
- select_existing: select existing # TODO
+ select_existing: select existing
delete: ลบ
- discard: Discard # TODO
+ discard: Discard
edit: แก้ไข
- items_total: '%{count} ทั้งหมด'
- less: Less... # TODO
+ items_total: ! '%{count} ทั้งหมด'
+ less: Less...
me: ฉัน
- more: More... # TODO
+ more: More...
n_a: N/A
name: ชื่อ
no_match: ไม่มี%{value}ที่ตรงกับ
@@ -526,16 +471,13 @@ th:
please_retry: โปรดทดลองคำค้นหาอื่น
recent_items: เอกสารล่าสุด
search_assets: ค้นหา%{value}
- ago: "%{value}ที่ผ่านมา"
+ ago: ! '%{value}ที่ผ่านมา'
background_info: หลัง ข้อมูล
address: ที่อยู่
city: แถบค้าขายของลอนกดอน
zipcode: รหัส ไปรษณีย์
state: สภาพ
country: ประเทศ
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: เกี่ยวกับ
about_dev_group: แหล่งสนทนาของนักพัฒนา
about_features: คุณลักษณะ และข้อผิดพลาด
@@ -544,35 +486,23 @@ th:
about_ffc_version: Fat Free CRM เวอร์ชัน
about_home_page: หน้าแรก
about_project_page: หน้าโครงการ
- about_thank_you: ขอบคุณที่ใช้งาน Fat Free CRM! เรายินดีเป็นอย่างยิ่งกับธุรกิจของคุณ และหวังว่าคุณจะสนุกกับการใช้โปรแกรม
+ about_thank_you: ขอบคุณที่ใช้งาน Fat Free CRM! เรายินดีเป็นอย่างยิ่งกับธุรกิจของคุณ
+ และหวังว่าคุณจะสนุกกับการใช้โปรแกรม
about_twitter: ติดตามบน Twitter
about_user_group: แหล่งสนทนาของผู้ใช้
admin: ผู้ดูแลระบบ
logout: ออกจากระบบ
quick_find: หาด่วน
welcome: ยินดีต้อนรับ
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: แก้ไขข้อเสนอ
show: แสดง
update: ปรับปรุง
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: โปรดใส่รหัสผ่านใหม่ และกรอกรหัสอีกครั้งเพื่อความถูกต้อง
password_intro: โปรดระบุอีเมล์ของท่าน จากนั้นขั้นตอนการเปลี่ยนรหัสผ่านจะส่งถึงท่านผ่านทางอีเมล์
reset_password: เปลี่ยนรหัสผ่าน
update_password_and_login: ปรับปรุงรหัสผ่านและเข้าสู่ระบบ
-
- # Views -> Admin
- #----------------------------------------------------------------------------
- # TODO
back_to_crm: Back to Fat Free CRM
crm_admin_page: Fat Free CRM Administration
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: อนุมัติ
create_user: เพิ่มผู้ใช้
last_seen: ดูล่าสุด%{value}ที่ผ่านมา
@@ -585,53 +515,43 @@ th:
user_awaits_approval: รอการอนุมัติ
user_confirm_delete: จะลบผู้ใช้ได้ก็ต่อเมื่อไม่มีเอกสารใดเกี่ยวข้องกับผู้ใช้คนนั้นๆ
user_is_admin: ผู้ใช้คนนี้เป็นผู้ดูแลระบบ
- user_never_logged_in: "ไม่เคยเข้ามาในระบบ"
+ user_never_logged_in: ไม่เคยเข้ามาในระบบ
user_signed_up: สมัครสมาชิก
user_signed_up_on: สมัครสมาชิกตั้งแต่ %{value}
user_since: user since %{value}
user_suspended: ระงับผู้ใช้
user_suspended_on: ระงับตั้งแต่ %{value}
users: ผู้ใช้
- users_small: ผู้ใช้ # TODO
-
- # Dropbox.
- #----------------------------------------------------------------------------
+ users_small: ผู้ใช้
dropbox_notification_subject: dropbox - อีเมล์ เพิ่ม - %{subject}
dropbox_notification_intro: สำเร็จ เพิ่ม อีเมล ที่ คุณ ส่ง ไป dropbox
dropbox_notification_to: เพิ่ม ลง ใน
subject: สาขา วิชา
body: ร่างกาย
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment' # TODO
- other: '%{count} comments' # TODO
+ one: 1 comment
+ other: ! '%{count} comments'
contact:
- one: 'ผู้ติดต่อหนึ่งคน'
- other: '%{count} ผู้ติดต่อ'
+ one: ผู้ติดต่อหนึ่งคน
+ other: ! '%{count} ผู้ติดต่อ'
opportunity:
- one: 'โอกาศปิดการขายหนึ่งรายการ'
- other: '%{count} โอกาศปิดการขาย'
+ one: โอกาศปิดการขายหนึ่งรายการ
+ other: ! '%{count} โอกาศปิดการขาย'
lead:
- one: 'ผู้สนใจหนึ่งคน'
- other: '%{count} ผู้สนใจ'
+ one: ผู้สนใจหนึ่งคน
+ other: ! '%{count} ผู้สนใจ'
day:
- one: 'หนึ่งวัน'
- other: '%{count} วัน'
+ one: หนึ่งวัน
+ other: ! '%{count} วัน'
login:
- one: 'เข้าสู่ระบบหนึ่งครั้ง'
- other: 'เข้าสู่ระบบ %{count} ครั้ง'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: เข้าสู่ระบบหนึ่งครั้ง
+ other: เข้าสู่ระบบ %{count} ครั้ง
date:
formats:
- mmddyyyy: "%m/%d/%Y"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%m/%d/%Y'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%b %e at %l:%M%p"
+ mmddhhss: ! '%b %e at %l:%M%p'
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 27ea27a65f..66c822ceac 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -1,214 +1,241 @@
-# Chinese (China) translations for Ruby on Rails
-# by tsechingho (http://github.com/tsechingho)
-
+---
zh-CN:
date:
formats:
- default: "%Y-%m-%d"
- short: "%b%d日"
- long: "%Y年%b%d日"
- day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
- abbr_day_names: [日, 一, 二, 三, 四, 五, 六]
- month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]
- abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
+ default: ! '%Y-%m-%d'
+ short: ! '%b%d日'
+ long: ! '%Y年%b%d日'
+ day_names:
+ - 星期日
+ - 星期一
+ - 星期二
+ - 星期三
+ - 星期四
+ - 星期五
+ - 星期六
+ abbr_day_names:
+ - 日
+ - 一
+ - 二
+ - 三
+ - 四
+ - 五
+ - 六
+ month_names:
+ -
+ - 一月
+ - 二月
+ - 三月
+ - 四月
+ - 五月
+ - 六月
+ - 七月
+ - 八月
+ - 九月
+ - 十月
+ - 十一月
+ - 十二月
+ abbr_month_names:
+ -
+ - 1月
+ - 2月
+ - 3月
+ - 4月
+ - 5月
+ - 6月
+ - 7月
+ - 8月
+ - 9月
+ - 10月
+ - 11月
+ - 12月
order:
- - :year
- - :month
- - :day
-
+ - :year
+ - :month
+ - :day
time:
formats:
- default: "%Y年%b%d日 %A %H:%M:%S %Z"
- short: "%b%d日 %H:%M"
- long: "%Y年%b%d日 %H:%M"
- am: "上午"
- pm: "下午"
-
+ default: ! '%Y年%b%d日 %A %H:%M:%S %Z'
+ short: ! '%b%d日 %H:%M'
+ long: ! '%Y年%b%d日 %H:%M'
+ am: 上午
+ pm: 下午
datetime:
distance_in_words:
- half_a_minute: "半分钟"
+ half_a_minute: 半分钟
less_than_x_seconds:
- one: "不到一秒"
- other: "不到 %{count} 秒"
+ one: 不到一秒
+ other: 不到 %{count} 秒
x_seconds:
- one: "一秒"
- other: "%{count} 秒"
+ one: 一秒
+ other: ! '%{count} 秒'
less_than_x_minutes:
- one: "不到一分钟"
- other: "不到 %{count} 分钟"
+ one: 不到一分钟
+ other: 不到 %{count} 分钟
x_minutes:
- one: "一分钟"
- other: "%{count} 分钟"
+ one: 一分钟
+ other: ! '%{count} 分钟'
about_x_hours:
- one: "大约一小时"
- other: "大约 %{count} 小时"
+ one: 大约一小时
+ other: 大约 %{count} 小时
x_days:
- one: "一天"
- other: "%{count} 天"
+ one: 一天
+ other: ! '%{count} 天'
about_x_months:
- one: "大约一个月"
- other: "大约 %{count} 个月"
+ one: 大约一个月
+ other: 大约 %{count} 个月
x_months:
- one: "一个月"
- other: "%{count} 个月"
+ one: 一个月
+ other: ! '%{count} 个月'
about_x_years:
- one: "大约一年"
- other: "大约 %{count} 年"
+ one: 大约一年
+ other: 大约 %{count} 年
over_x_years:
- one: "一年多"
- other: "%{count} 年多"
+ one: 一年多
+ other: ! '%{count} 年多'
almost_x_years:
- one: "接近一年"
- other: "接近 %{count} 年"
+ one: 接近一年
+ other: 接近 %{count} 年
prompts:
- year: "年"
- month: "月"
- day: "日"
- hour: "时"
- minute: "分"
- second: "秒"
-
+ year: 年
+ month: 月
+ day: 日
+ hour: 时
+ minute: 分
+ second: 秒
number:
format:
- separator: "."
- delimiter: ","
+ separator: .
+ delimiter: ! ','
precision: 3
significant: false
strip_insignificant_zeros: false
currency:
format:
- format: "%u %n"
- unit: "CN¥"
- separator: "."
- delimiter: ","
+ format: ! '%u %n'
+ unit: CN¥
+ separator: .
+ delimiter: ! ','
precision: 2
significant: false
strip_insignificant_zeros: false
percentage:
format:
- delimiter: ""
+ delimiter: ''
precision:
format:
- delimiter: ""
+ delimiter: ''
human:
format:
- delimiter: ""
+ delimiter: ''
precision: 1
significant: false
strip_insignificant_zeros: false
storage_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
+ one: Byte
+ other: Bytes
+ kb: KB
+ mb: MB
+ gb: GB
+ tb: TB
decimal_units:
- format: "%n %u"
+ format: ! '%n %u'
units:
- # 10^-21 zepto, 10^-24 yocto
- atto: "渺" # 10^-18
- femto: "飞" # 10^-15 毫微微
- pico: "漠" # 10^-12 微微
- nano: "奈" # 10^-9 毫微
- micro: "微" # 10^-6
- mili: "毫" # 10^-3 milli
- centi: "厘" # 10^-2
- deci: "分" # 10^-1
- unit: ""
+ atto: 渺
+ femto: 飞
+ pico: 漠
+ nano: 奈
+ micro: 微
+ mili: 毫
+ centi: 厘
+ deci: 分
+ unit: ''
ten:
- one: "十"
- other: "十" # 10^1
- hundred: "百" # 10^2
- thousand: "千" # 10^3 kilo
- million: "百万" # 10^6 mega
- billion: "十亿" # 10^9 giga
- trillion: "兆" # 10^12 tera
- quadrillion: "千兆" # 10^15 peta
- # 10^18 exa, 10^21 zetta, 10^24 yotta
-
+ one: 十
+ other: 十
+ hundred: 百
+ thousand: 千
+ million: 百万
+ billion: 十亿
+ trillion: 兆
+ quadrillion: 千兆
support:
array:
- words_connector: ", "
- two_words_connector: " 和 "
- last_word_connector: ", 和 "
+ words_connector: ! ', '
+ two_words_connector: ! ' 和 '
+ last_word_connector: ! ', 和 '
select:
- prompt: "请选择"
-
+ prompt: 请选择
activerecord:
errors:
- template: # ~ 2.3.5 backward compatible
+ template:
header:
- one: "有 1 个错误发生导致「%{model}」无法被保存。"
- other: "有 %{count} 个错误发生导致「%{model}」无法被保存。"
- body: "如下字段出现错误:"
+ one: 有 1 个错误发生导致「%{model}」无法被保存。
+ other: 有 %{count} 个错误发生导致「%{model}」无法被保存。
+ body: 如下字段出现错误:
full_messages:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
messages:
- inclusion: "不包含于列表中"
- exclusion: "是保留关键字"
- invalid: "是无效的"
- confirmation: "与确认值不匹配"
- accepted: "必须是可被接受的"
- empty: "不能留空"
- blank: "不能为空字符"
- too_long: "过长(最长为 %{count} 个字符)"
- too_short: "过短(最短为 %{count} 个字符)"
- wrong_length: "长度非法(必须为 %{count} 个字符)"
- not_a_number: "不是数字"
- not_an_integer: "必须是整数"
- greater_than: "必须大于 %{count}"
- greater_than_or_equal_to: "必须大于或等于 %{count}"
- equal_to: "必须等于 %{count}"
- less_than: "必须小于 %{count}"
- less_than_or_equal_to: "必须小于或等于 %{count}"
- odd: "必须为单数"
- even: "必须为双数"
- taken: "已经被使用"
- record_invalid: "校验失败: %{errors}"
-
+ inclusion: 不包含于列表中
+ exclusion: 是保留关键字
+ invalid: 是无效的
+ confirmation: 与确认值不匹配
+ accepted: 必须是可被接受的
+ empty: 不能留空
+ blank: 不能为空字符
+ too_long: 过长(最长为 %{count} 个字符)
+ too_short: 过短(最短为 %{count} 个字符)
+ wrong_length: 长度非法(必须为 %{count} 个字符)
+ not_a_number: 不是数字
+ not_an_integer: 必须是整数
+ greater_than: 必须大于 %{count}
+ greater_than_or_equal_to: 必须大于或等于 %{count}
+ equal_to: 必须等于 %{count}
+ less_than: 必须小于 %{count}
+ less_than_or_equal_to: 必须小于或等于 %{count}
+ odd: 必须为单数
+ even: 必须为双数
+ taken: 已经被使用
+ record_invalid: ! '校验失败: %{errors}'
activemodel:
errors:
template:
header:
- one: "有 1 个错误发生导致「%{model}」无法被保存。"
- other: "有 %{count} 个错误发生导致「%{model}」无法被保存。"
- body: "如下字段出现错误:"
-
+ one: 有 1 个错误发生导致「%{model}」无法被保存。
+ other: 有 %{count} 个错误发生导致「%{model}」无法被保存。
+ body: 如下字段出现错误:
errors:
- format: "%{attribute} %{message}"
+ format: ! '%{attribute} %{message}'
messages:
- inclusion: "不包含于列表中"
- exclusion: "是保留关键字"
- invalid: "是无效的"
- confirmation: "与确认值不匹配"
- accepted: "必须是可被接受的"
- empty: "不能留空"
- blank: "不能为空字符"
- too_long: "过长(最长为 %{count} 个字符)"
- too_short: "过短(最短为 %{count} 个字符)"
- wrong_length: "长度非法(必须为 %{count} 个字符)"
- not_a_number: "不是数字"
- not_an_integer: "必须是整数"
- greater_than: "必须大于 %{count}"
- greater_than_or_equal_to: "必须大于或等于 %{count}"
- equal_to: "必须等于 %{count}"
- less_than: "必须小于 %{count}"
- less_than_or_equal_to: "必须小于或等于 %{count}"
- odd: "必须为单数"
- even: "必须为双数"
-
+ inclusion: 不包含于列表中
+ exclusion: 是保留关键字
+ invalid: 是无效的
+ confirmation: 与确认值不匹配
+ accepted: 必须是可被接受的
+ empty: 不能留空
+ blank: 不能为空字符
+ too_long: 过长(最长为 %{count} 个字符)
+ too_short: 过短(最短为 %{count} 个字符)
+ wrong_length: 长度非法(必须为 %{count} 个字符)
+ not_a_number: 不是数字
+ not_an_integer: 必须是整数
+ greater_than: 必须大于 %{count}
+ greater_than_or_equal_to: 必须大于或等于 %{count}
+ equal_to: 必须等于 %{count}
+ less_than: 必须小于 %{count}
+ less_than_or_equal_to: 必须小于或等于 %{count}
+ odd: 必须为单数
+ even: 必须为双数
helpers:
select:
- prompt: "请选择"
+ prompt: 请选择
submit:
- create: "新增%{model}"
- update: "更新%{model}"
- submit: "储存%{model}"
-
+ create: 新增%{model}
+ update: 更新%{model}
+ submit: 储存%{model}
will_paginate:
previous_label: 前页
next_label: 后页
diff --git a/config/locales/zh-CN_fat_free_crm.yml b/config/locales/zh-CN_fat_free_crm.yml
index 0488b5cf17..c039f3fa03 100644
--- a/config/locales/zh-CN_fat_free_crm.yml
+++ b/config/locales/zh-CN_fat_free_crm.yml
@@ -1,48 +1,39 @@
+---
zh-CN:
language: 中文(简体)
-
- # Generic terms.
- #----------------------------------------------------------------------------
all: 所有
at: 在
here: 这里
- no_button: '否'
+ no_button: 否
not_implemented: 未实现
or: 或
- select_none: '-- 无 --'
- select_blank: '-- 选择 --'
- yes_button: '是'
-
- # Settings.
- #----------------------------------------------------------------------------
+ select_none: -- 无 --
+ select_blank: -- 选择 --
+ yes_button: 是
tab_dashboard: 摘要
tab_tasks: 任务
tab_campaigns: 促销
- tab_leads: 线索
+ tab_leads: 线索
tab_accounts: 账号
tab_contacts: 联系人
tab_opportunities: 商机
-
admin_tab_users: 用户
admin_tab_settings: 设置
admin_tab_plugins: 插件
admin_tab_groups: 分组
admin_tab_fields: 区域
admin_tab_tags: 标记
-
planned: 计划
started: 已开始
on_hold: 搁置
completed: 完成
called_off: 取消
groups: 分组
-
new: 新建
contacted: 已联系
converted: 已转换
rejected: 已拒绝
-
- cold_call: 冷电话
+ cold_call: 冷电话
conference: 会议
online: 在线营销
referral: 转来
@@ -50,7 +41,6 @@ zh-CN:
web: 网站
word_of_mouth: 口头
other: 其它
-
prospecting: 展望
analysis: 分析
presentation: 演示
@@ -59,16 +49,13 @@ zh-CN:
final_review: 最后审查
won: 结束/赢
lost: 结束/输
-
call: 电话
email: Email
follow_up: 跟进
lunch: 午餐
meeting: 会议
money: 钱
- presentation: 演示
trip: 旅行
-
overdue: 逾期
due_asap: 尽快
due_today: 今天
@@ -77,24 +64,17 @@ zh-CN:
due_next_week: 下周
due_later: 以后
due_specific_date: 特定日期...
-
completed_today: 今天
completed_yesterday: 昨天
completed_last_week: 上周
completed_this_month: 本月
completed_last_month: 上月
-
- # Models/Activity.
- #----------------------------------------------------------------------------
one_hour: 1小时
one_day: 1天
two_days: 2天
one_week: 1周
two_weeks: 2周
one_month: 1月
-
- # Model Validations.
- #----------------------------------------------------------------------------
activerecord:
errors:
models:
@@ -107,83 +87,76 @@ zh-CN:
account:
attributes:
name:
- missing_account_name: "^请指定用户名"
+ missing_account_name: ^请指定用户名
access:
- share_account: "^请指定可以共享账号的用户"
+ share_account: ^请指定可以共享账号的用户
campaign:
attributes:
name:
- missing_campaign_name: "^请指定促销活动名称"
+ missing_campaign_name: ^请指定促销活动名称
ends_on:
- dates_not_in_sequence: "^请确认促销活动开始日期在结束日期之前"
+ dates_not_in_sequence: ^请确认促销活动开始日期在结束日期之前
access:
- share_campaign: "^请指定可以共享促销活动的用户"
+ share_campaign: ^请指定可以共享促销活动的用户
contact:
attributes:
first_name:
- missing_first_name: "^请指定用户的名"
+ missing_first_name: ^请指定用户的名
last_name:
- missing_last_name: "^请指定用户的姓"
+ missing_last_name: ^请指定用户的姓
access:
- share_contact: "^请指定可以共享联系人的用户"
+ share_contact: ^请指定可以共享联系人的用户
lead:
attributes:
first_name:
- missing_first_name: "^请指定用户的名"
+ missing_first_name: ^请指定用户的名
last_name:
- missing_last_name: "^请指定用户的姓"
+ missing_last_name: ^请指定用户的姓
access:
- share_lead: "^请指定可以共享Lead的用户"
+ share_lead: ^请指定可以共享Lead的用户
opportunity:
attributes:
name:
- missing_opportunity_name: "^请指定商机名称"
+ missing_opportunity_name: ^请指定商机名称
access:
- share_opportunity: "^请指定可以共享商机的用户"
+ share_opportunity: ^请指定可以共享商机的用户
task:
attributes:
name:
- missing_task_name: "^请指定任务名称"
+ missing_task_name: ^请指定任务名称
calendar:
- invalid_date: "^请指定合法日期"
+ invalid_date: ^请指定合法日期
user:
attributes:
username:
- missing_username: "^请指定用户名"
- username_taken: "^此用户名已有人使用"
+ missing_username: ^请指定用户名
+ username_taken: ^此用户名已有人使用
email:
- missing_email: "^请指定邮件地址"
- email_in_use: "^此邮件地址已经有人使用"
-
- # dynamic_form plugin translations.
- #----------------------------------------------------------------------------
+ missing_email: ^请指定邮件地址
+ email_in_use: ^此邮件地址已经有人使用
errors:
template:
header:
- one: "有 1 个错误发生导致「%{model}」无法被保存。"
- other: "有 %{count} 个错误发生导致「%{model}」无法被保存。"
- body: "如下字段出现错误:"
-
+ one: 有 1 个错误发生导致「%{model}」无法被保存。
+ other: 有 %{count} 个错误发生导致「%{model}」无法被保存。
+ body: 如下字段出现错误:
msg_account_suspended: 用户账号已暂停
password_reset_instruction: 密码重置方法
-
- # Controllers.
- #----------------------------------------------------------------------------
msg_account_created: 你的账号已经创建,正在等待管理员审核
msg_account_not_approved: 你的账号还未被批准
- msg_asset_deleted: "%{value} 已经被删除"
+ msg_asset_deleted: ! '%{value} 已经被删除'
msg_asset_not_available: 这个 %{value} 已不存在
- msg_asset_not_authorized: You are not authorized to view this %{value}. # TODO
+ msg_asset_not_authorized: You are not authorized to view this %{value}.
msg_assets_not_available: 这个 %{value} 不存在
- msg_asset_rejected: "%{value} 已被拒绝"
- msg_bad_image_file: "^^不能将此图片上传或改变大小"
- msg_cant_create_related: "不能创建 %{asset} 因为 %{related} 已不存在"
- msg_cant_delete_user: "^不能删除用户,因为 %{value} 有相关 assets 存在"
- msg_cant_do: "不能 %{action} %{asset} 因为它已经不存在"
+ msg_asset_rejected: ! '%{value} 已被拒绝'
+ msg_bad_image_file: ^^不能将此图片上传或改变大小
+ msg_cant_create_related: 不能创建 %{asset} 因为 %{related} 已不存在
+ msg_cant_delete_user: ^不能删除用户,因为 %{value} 有相关 assets 存在
+ msg_cant_do: 不能 %{action} %{asset} 因为它已经不存在
msg_email_not_found: 未找到用户使用此邮件地址
msg_enter_new_password: 请输入新密码
msg_goodbye: 您已退出,感谢您使用 Fat Free CRM!
- msg_invalid_password: "^^请输入正确密码"
+ msg_invalid_password: ^^请输入正确密码
msg_invalig_login: 用户名或密码错
msg_last_login: 您上次登录是在 %{value}.
msg_login_needed: 必须登录后才可使用本页
@@ -195,10 +168,7 @@ zh-CN:
msg_require_admin: 必须是管理员才能使用本页
msg_successful_signup: 成功申请,欢迎您使用 Fat Free CRM!
msg_welcome: 欢迎使用 Fat Free CRM!
-
- # Options.
- #----------------------------------------------------------------------------
- "option_amount*probability": weighted amount
+ option_amount*probability: weighted amount
activity_options: 显示 %{models} 行业由 %{user} 在过去 %{period}.
all_users: 所有用户
option_after: 之后
@@ -223,12 +193,9 @@ zh-CN:
option_target_leads: 目标线索
option_target_revenue: 目标收入
option_updated_at: 更新日期
- show_per_page: 显示 %{number} %{models} 每页使用 %{fmt} 格式
+ show_per_page: 显示 %{number} %{models} 每页使用 %{fmt} 格式
sort_by: 用 %{field} 排序 %{models}
- sort_by_displaying: 用 %{field} 排序 %{models},显示名 %{position} 姓
-
- # Views -> Profile.
- #----------------------------------------------------------------------------
+ sort_by_displaying: 用 %{field} 排序 %{models},显示名 %{position} 姓
aim: AOL IM
already_signed_up: 已申请?
alt_email: 另一个 email
@@ -238,7 +205,6 @@ zh-CN:
contact_info: 联系人信息
current_password: 旧密码
edit_profile: 编辑个人设置
- # email: Email # <-- Already defined as the task type if Settings.
first_name: 名
google: Google IM
gravatar_help: 不熟悉 Gravatars? 了解 Gravatars
@@ -264,18 +230,12 @@ zh-CN:
user: 用户
username: 用户名
yahoo: Yahoo IM
-
- # Views -> Authenticate.
- #----------------------------------------------------------------------------
forgot_password: 忘记密码
login: 登录
no_account: 没有账号?
remember_me: 记住我
sign_up_now: 现在申请!
-
- # Views -> Accounts.
- #----------------------------------------------------------------------------
- account: 账号
+ account: 账号
account_small: 短账号
accounts: 账号
accounts_options: 账号选项
@@ -286,9 +246,9 @@ zh-CN:
date_created: 创建日期
date_updated: 更新日期
fax: 传真
- intro: 可稍后添加%{value}
+ intro: 可稍后添加%{value}
mobile_small: 手机
- open_in_window: 在一个新窗口打开%{value}
+ open_in_window: 在一个新窗口打开%{value}
mail_to: 发邮件给%{value}
phone_small: 电话
phone_toll_free: 免费电话
@@ -302,10 +262,7 @@ zh-CN:
account_summary: 账号摘要
pipeline: 渠道
select_an_account: 选择账号
-
- # Views -> Campaigns.
- #----------------------------------------------------------------------------
- actual: 实际
+ actual: 实际
actual_performance: 实际效益
budget: 预算
budget_label: 预算(¥)
@@ -319,7 +276,7 @@ zh-CN:
campaigns_small: 促销
conversion: 转换
conversion_label: 转换比率(%)
- conversion_number: "%{value} 转换"
+ conversion_number: ! '%{value} 转换'
create_campaign: 创建促销
end_date: 结束日期
finished_on: 完成于 %{value}
@@ -331,7 +288,7 @@ zh-CN:
objectives_small: 战役目标
revenue: 收入
revenue_label: 收入(¥)
- revenue_number: "收入%{value}"
+ revenue_number: 收入%{value}
save_campaign: 保存促销
start_date: 开始日期
started_ago: 开始于 %{value} 之前
@@ -341,9 +298,6 @@ zh-CN:
total_campaigns: 促销总数
was_supposed_to_finish: 预计完成于 %{value}
was_supposed_to_start: 预计开始于 %{time_ago} 之前,在 %{start_date}
-
- # Views -> Contacts.
- #----------------------------------------------------------------------------
alt_email_small: 其它
blog: Website/Blog
contact: 联系人
@@ -353,14 +307,14 @@ zh-CN:
contacts_small: 联系人
create_contact: 创建联系人
department: 部门
- department_small: '%{value} 部门'
+ department_small: ! '%{value} 部门'
do_not_call: 不要打电话
extra_info: 更多信息
extra_info_small: 更多信息
facebook: Facebook
linked_in: LinkedIn
myself: 自己
- permissions_intro_private: 默认只有你对 %{value} 有权限。以后可修改。
+ permissions_intro_private: 默认只有你对 %{value} 有权限。以后可修改。
permissions_intro_public: 默认所有用户都对 %{value} 有权限。以后可修改。
permissions_intro_shared: 默认只有选定用户对 %{value} 有权限。以后可修改。
referred_by: 引用
@@ -369,7 +323,7 @@ zh-CN:
twitter: Twitter
web_presence: web
web_presence_small: web
- works_at: "%{job_title} 在 %{company}"
+ works_at: ! '%{job_title} 在 %{company}'
affiliate: 下属
competitor: 对手
customer: 顾客
@@ -380,9 +334,6 @@ zh-CN:
select_contact: 选择账号
select_a_country: 选择国家
comment_intro: 备注或简介
-
- # Views -> Leads.
- #----------------------------------------------------------------------------
convert: 转换
convert_lead: 转换线索
convert_lead_permissions_intro: 联系人权限将会从被转换的线索中复制。以后可修改。
@@ -408,9 +359,6 @@ zh-CN:
source: 源
status: 状态
total_leads: 线索总计
-
- # Views -> Opportunities.
- #----------------------------------------------------------------------------
amount: 金额
close_date: 结束日期
closed_ago_on: 结束于 %{time_ago} 之前,在 %{date}
@@ -432,7 +380,7 @@ zh-CN:
opportunity: 商机
opportunity_small: 商机
opportunity_summary: 商机摘要
- opportunity_summary_text: "%{amount} 有 %{discount} 折扣和 %{probability} 可能性"
+ opportunity_summary_text: ! '%{amount} 有 %{discount} 折扣和 %{probability} 可能性'
past_due: 超过预计, 预计结束于 %{value} 之前
probability: 可能性
probability_number: 有 %{value} 可能性
@@ -442,9 +390,6 @@ zh-CN:
weighted_amount: 权重数量
select_opportunity: 选择商机
Discard: 放弃
-
- # Views -> Tasks.
- #----------------------------------------------------------------------------
assign_to: 分配给
assigned_tab: 已分配
assigned_tasks: 已分配任务
@@ -457,13 +402,13 @@ zh-CN:
due: 期限
feel_free: 可任意
move_to: 移动到
- no_tasks: "你没有任何 %{value} 任务"
+ no_tasks: 你没有任何 %{value} 任务
no_tasks_pending: 进行中
no_tasks_assigned: 已分配
no_tasks_completed: 完成
pending_tab: 进行中
pending_tasks: 进行中任务
- related: '相关:'
+ related: ! '相关:'
save_task: 保存任务
task_assigned: 任务已经分配给 %{value}
task_assigned_to: 并分配给 %{value}
@@ -490,10 +435,6 @@ zh-CN:
my_accounts: 我的账号
no_account_records: 暂无账号
select_task: 选择任务
-
-
- # Views -> Home.
- #----------------------------------------------------------------------------
action_commented: 评论于
action_completed: 已完成
action_created: 已创建
@@ -513,28 +454,25 @@ zh-CN:
subject_lead: 线索
subject_opportunity: 商机
subject_task: 任务
-
- # Views -> Common.
- #----------------------------------------------------------------------------
add_note: 添加注释
save_note: 保存注释
add_note_help: 添加一个新注释...
edit_note: 编辑注释
added_ago: 添加于 %{value} 之前
- added_by: 添加于 %{time_ago} 之前,由 %{user}
+ added_by: 添加于 %{time_ago} 之前,由 %{user}
back: 返回
cancel: 取消
close_form: 关闭,由
confirm_delete: 确认删除 %{value}?
copy_permissions: 复制 %{value} 权限
- could_not_find: "未找到 %{value}. 请"
- could_not_find_matching: "未找到 %{value} 匹配"
+ could_not_find: 未找到 %{value}. 请
+ could_not_find_matching: 未找到 %{value} 匹配
create_new: 创建新
select_existing: 选择已有
delete: 删除
- discard: Discard # TODO
+ discard: Discard
edit: 编辑
- items_total: '%{count} 总计'
+ items_total: ! '%{count} 总计'
me: 自己
n_a: 无
name: 名字
@@ -545,11 +483,11 @@ zh-CN:
please_retry: 请再试一次
recent_items: 最近项目
search_assets: 查找 %{value}
- time_ago: "%{value} 以前"
+ time_ago: ! '%{value} 以前'
background_info: 背景
address: 地址
- street1: 街道 1 # NEW
- street2: 街道 2 # NEW
+ street1: 街道 1
+ street2: 街道 2
city: 城市
zipcode: 邮编
state: 省
@@ -561,14 +499,8 @@ zh-CN:
destroy: 删除
expand_all: 展开
collapse_all: 收起
-
- # Views -> Tag.
- #----------------------------------------------------------------------------
select_or_create_tags: 选择标签
tags: 标签
-
- # Views -> Layout.
- #----------------------------------------------------------------------------
about: 关于
about_dev_group: 开发者讨论组
about_features: 特性与bugs
@@ -584,27 +516,14 @@ zh-CN:
logout: 退出
quick_find: 快速查找
welcome: 欢迎
-
- # Views -> Comments.
- #----------------------------------------------------------------------------
edit_comment: 编辑评论
show: 显示
- update: 更新
-
- # Views -> Passwords.
- #----------------------------------------------------------------------------
confirm_password_intro: 请输入新密码并确认
password_intro: 请输入邮件地址,重置密码邮件将发到您的邮箱
reset_password: 重置密码
update_password_and_login: 更新密码并登录
-
- # Views -> Admin
- #----------------------------------------------------------------------------
back_to_crm: 返回 Fat Free CRM
crm_admin_page: Fat Free CRM 管理
-
- # Views -> Admin -> Users.
- #----------------------------------------------------------------------------
approve: 批准
create_user: 创建用户
last_seen: 上次 %{value} 之前见到
@@ -617,7 +536,7 @@ zh-CN:
user_awaits_approval: 等待您的批准
user_confirm_delete: 只有没有其它相关信息的用户才能被删除
user_is_admin: 此用户是管理员
- user_never_logged_in: "尚未登录"
+ user_never_logged_in: 尚未登录
user_signed_up: 已申请
user_signed_up_on: 申请于 %{value}
user_since: 用户自 %{value}
@@ -625,38 +544,30 @@ zh-CN:
user_suspended_on: 暂停于 %{value}
users: 用户
users_small: 用户
-
- # Pluralizations.
- #----------------------------------------------------------------------------
pluralize:
comment:
- one: '1 comment' # TODO
- other: '%{count} comments' # TODO
- contact:
- one: '1 个联系人'
- other: '%{count} 个联系人'
+ one: 1 comment
+ other: ! '%{count} comments'
+ contact:
+ one: 1 个联系人
+ other: ! '%{count} 个联系人'
opportunity:
- one: '1 个商机'
- other: '%{count} 个商机'
+ one: 1 个商机
+ other: ! '%{count} 个商机'
lead:
- one: '1 个线索'
- other: '%{count} 个线索'
+ one: 1 个线索
+ other: ! '%{count} 个线索'
day:
- one: '1 天'
- other: '%{count} 天'
+ one: 1 天
+ other: ! '%{count} 天'
login:
- one: '1 个登录'
- other: '%{count} 个登录'
-
- # Custom date/time formats.
- #----------------------------------------------------------------------------
+ one: 1 个登录
+ other: ! '%{count} 个登录'
date:
formats:
- mmddyyyy: "%Y-%m-%d"
- mmdd: "%b %e"
- mmddyy: "%b %e, %Y"
-
+ mmddyyyy: ! '%Y-%m-%d'
+ mmdd: ! '%b %e'
+ mmddyy: ! '%b %e, %Y'
time:
formats:
- mmddhhss: "%b %e at %l:%M%p"
-
+ mmddhhss: ! '%b %e at %l:%M%p'
diff --git a/config/routes.rb b/config/routes.rb
index 8304e15e07..753887e6f5 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -21,10 +21,10 @@
match '/home/timezone', :as => :timezone
match '/home/redraw', :as => :redraw
- resource :authentication
- resources :comments
- resources :emails
- resources :passwords
+ resource :authentication, :except => [:index, :edit]
+ resources :comments, :except => [:new, :show]
+ resources :emails, :only => [:destroy]
+ resources :passwords, :only => [:new, :create, :edit, :update]
resources :accounts, :id => /\d+/ do
collection do
@@ -33,19 +33,19 @@
get :options
get :field_group
match :auto_complete
- post :redraw
- get :versions
+ get :redraw
+ get :versions
end
member do
get :cold_contacts
- post :redraw_show
+ get :redraw_show
post :move_contact
put :attach
post :discard
post :subscribe
post :unsubscribe
- get :contacts
- get :opportunities
+ get :contacts
+ get :opportunities
end
end
@@ -55,17 +55,17 @@
post :filter
get :options
get :field_group
- post :auto_complete
- post :redraw
- get :versions
+ match :auto_complete
+ get :redraw
+ get :versions
end
member do
put :attach
post :discard
post :subscribe
post :unsubscribe
- get :leads
- get :opportunities
+ get :leads
+ get :opportunities
end
end
@@ -75,9 +75,9 @@
post :filter
get :options
get :field_group
- post :auto_complete
- post :redraw
- get :versions
+ match :auto_complete
+ get :redraw
+ get :versions
get :attendances
get :mailchimp_webhooks
post :mailchimp_webhooks
@@ -105,9 +105,10 @@
post :filter
get :options
get :field_group
- post :auto_complete
- post :redraw
- get :versions
+ match :auto_complete
+ get :redraw
+ get :versions
+ get :autocomplete_account_name
end
member do
get :convert
@@ -118,8 +119,6 @@
put :promote
put :reject
end
-
- get :autocomplete_account_name, :on => :collection
end
resources :opportunities, :id => /\d+/ do
@@ -128,45 +127,42 @@
post :filter
get :options
get :field_group
- post :auto_complete
- post :redraw
- get :versions
+ match :auto_complete
+ get :redraw
+ get :versions
end
member do
put :attach
post :discard
post :subscribe
post :unsubscribe
- get :contacts
+ get :contacts
end
end
resources :tasks, :id => /\d+/ do
collection do
post :filter
- post :auto_complete
+ match :auto_complete
end
member do
- put :complete
+ put :complete
end
end
- resources :users, :id => /\d+/ do
+ resources :users, :id => /\d+/, :except => [:index, :destroy] do
member do
- post :assign_contact
- get :avatar
- get :password
- put :upload_avatar
- put :change_password
- post :redraw
+ get :avatar
+ get :password
+ put :upload_avatar
+ put :change_password
+ get :redraw
+ post :move_contact
end
-
collection do
+ get :opportunities_overview
match :auto_complete
end
- collection do
- get :opportunities_overview
- end
end
resources :contact_groups, :id => /\d+/ do
@@ -176,12 +172,12 @@
get :options
get :field_group
match :auto_complete
- post :redraw
- get :versions
+ get :redraw
+ get :versions
get :email
end
member do
- post :redraw_show
+ get :redraw_show
put :attach
post :discard
post :subscribe
@@ -200,8 +196,8 @@
get :options
get :field_group
match :auto_complete
- post :redraw
- get :versions
+ get :redraw
+ get :versions
get :compose
end
member do
@@ -221,8 +217,8 @@
get :options
get :field_group
match :auto_complete
- post :redraw
- get :versions
+ get :redraw
+ get :versions
get :toggle_comments
end
member do
@@ -230,7 +226,7 @@
get :email_registrants
put :send_emails
get :generate_report
- post :redraw_show
+ get :redraw_show
put :attach
#put :mark
#put :unmark
@@ -243,13 +239,13 @@
resources :event_instances, :id => /\d+/ do
collection do
- post :redraw
- get :versions
+ get :redraw
+ get :versions
end
member do
put :attach
- put :mark
- put :unmark
+ post :mark
+ post :unmark
post :discard
post :subscribe
post :unsubscribe
@@ -282,7 +278,7 @@
resources :users do
collection do
- post :auto_complete
+ match :auto_complete
end
member do
get :confirm
@@ -291,7 +287,7 @@
end
end
- resources :field_groups, :except => :index do
+ resources :field_groups, :except => [:index, :show] do
collection do
post :sort
end
@@ -302,15 +298,15 @@
resources :fields do
collection do
- post :auto_complete
- get :options
- post :redraw
- post :sort
- get :subform
+ match :auto_complete
+ get :options
+ get :redraw
+ post :sort
+ get :subform
end
end
- resources :tags do
+ resources :tags, :except => [:show] do
member do
get :confirm
end
@@ -319,9 +315,8 @@
resources :fields, :as => :custom_fields
resources :fields, :as => :core_fields
- resources :settings
- resources :plugins
+ resources :settings, :only => :index
+ resources :plugins, :only => :index
end
- get '/:controller/tagged/:id' => '#tagged'
end
diff --git a/config/settings.default.yml b/config/settings.default.yml
index 581c62cf73..53f8ad7da4 100644
--- a/config/settings.default.yml
+++ b/config/settings.default.yml
@@ -63,17 +63,15 @@
# Settings for outgoing email (SMTP)
-# - Default configuration is for GMail
#------------------------------------------------------------------------------
:smtp:
- :address : "smtp.gmail.com"
- :enable_starttls_auto : true
- :port : 587
+ :address : "" # e.g. smtp.gmail.com
+ :from : "" # e.g. no-reply@your-domain.com
+ :enable_starttls_auto : true # true/false
+ :port : "" # e.g. 587
:authentication : :plain
:user_name : ""
:password : ""
-# :delivery_method : :smtp # This is the default. Can be :smtp, :sendmail, :test, :file
-
# Settings for the Email dropbox (IMAP)
# - Connection settings for the IMAP account, server and folders.
@@ -197,27 +195,80 @@
# Main and Admin Tabs
#------------------------------------------------------------------------------
-:tabs: [
- { :active : true, :text : :tab_dashboard, :url : { :controller : "home" } },
- { :active : false, :text : :tab_tasks, :url : { :controller : "tasks" } },
- { :active : false, :text : :tab_campaigns, :url : { :controller : "campaigns" } },
- { :active : false, :text : :tab_leads, :url : { :controller : "leads" } },
- { :active : false, :text : :tab_accounts, :url : { :controller : "accounts" } },
- { :active : false, :text : :tab_contacts, :url : { :controller : "contacts" } },
- { :active : false, :text : :tab_opportunities, :url : { :controller : "opportunities" } },
- { :active : false, :text : :tab_team, :url : { :controller : "users",
- :action : "opportunities_overview" } }
-
-]
-
-:admin_tabs: [
- { :active : true, :text : :admin_tab_users, :url : { :controller : "admin/users" } },
- { :active : true, :text : :admin_tab_groups, :url : { :controller : "admin/groups" } },
- { :active : false, :text : :admin_tab_fields, :url : { :controller : "admin/fields" } },
- { :active : false, :text : :admin_tab_tags, :url : { :controller : "admin/tags" } },
- { :active : false, :text : :admin_tab_settings, :url : { :controller : "admin/settings" } },
- { :active : false, :text : :admin_tab_plugins, :url : { :controller : "admin/plugins" } }
-]
+:tabs:
+- :active: true
+ :text: :tab_dashboard
+ :icon: :fa-dashboard
+ :url:
+ :controller: home
+- :active: false
+ :text: :tab_tasks
+ :icon: :fa-check-square-o
+ :url:
+ :controller: tasks
+- :active: false
+ :text: :tab_campaigns
+ :icon: :fa-bar-chart-o
+ :url:
+ :controller: campaigns
+- :active: false
+ :text: :tab_leads
+ :icon: :fa-tasks
+ :url:
+ :controller: leads
+- :active: false
+ :text: :tab_accounts
+ :icon: :fa-users
+ :url:
+ :controller: accounts
+- :active: false
+ :text: :tab_contacts
+ :icon: :fa-user
+ :url:
+ :controller: contacts
+- :active: false
+ :text: :tab_opportunities
+ :icon: :fa-money
+ :url:
+ :controller: opportunities
+- :active: false
+ :text: :tab_team
+ :icon: :fa-globe
+ :url:
+ :controller: users
+ :action: opportunities_overview
+
+:admin_tabs:
+- :active: true
+ :text: :admin_tab_users
+ :icon: :fa-user
+ :url:
+ :controller: admin/users
+- :active: true
+ :text: :admin_tab_groups
+ :icon: :fa-users
+ :url:
+ :controller: admin/groups
+- :active: false
+ :text: :admin_tab_fields
+ :icon: :fa-list-alt
+ :url:
+ :controller: admin/fields
+- :active: false
+ :text: :admin_tab_tags
+ :icon: :fa-tags
+ :url:
+ :controller: admin/tags
+#- :active: false
+# :text: :admin_tab_settings
+# :icon: :fa-cogs
+# :url:
+# :controller: admin/settings
+#- :active: false
+# :text: :admin_tab_plugins
+# :icon: :fa-plus-circle
+# :url:
+# :controller: admin/plugins
# Account Category. To add custom account type use string value, for example:
#
diff --git a/custom_plan.rb b/custom_plan.rb
new file mode 100644
index 0000000000..3325564099
--- /dev/null
+++ b/custom_plan.rb
@@ -0,0 +1,11 @@
+require 'zeus/rails'
+
+class CustomPlan < Zeus::Rails
+
+ # def my_custom_command
+ # # see https://github.com/burke/zeus/blob/master/docs/ruby/modifying.md
+ # end
+
+end
+
+Zeus.plan = CustomPlan.new
diff --git a/db/migrate/20131207033244_add_user_id_to_lists.rb b/db/migrate/20131207033244_add_user_id_to_lists.rb
new file mode 100644
index 0000000000..f3359ef57b
--- /dev/null
+++ b/db/migrate/20131207033244_add_user_id_to_lists.rb
@@ -0,0 +1,6 @@
+class AddUserIdToLists < ActiveRecord::Migration
+ def change
+ add_column :lists, :user_id, :integer, :default => nil
+ add_index :lists, :user_id
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4a29364143..47ff08d30a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -401,8 +401,11 @@
t.text "url"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
+ t.integer "user_id"
end
+ add_index "lists", ["user_id"], :name => "index_lists_on_user_id"
+
create_table "mandrill_emails", :force => true do |t|
t.string "uuid", :limit => 36
t.integer "user_id"
diff --git a/fat_free_crm.gemspec b/fat_free_crm.gemspec
index 8b1157c1a6..56f72a74ae 100644
--- a/fat_free_crm.gemspec
+++ b/fat_free_crm.gemspec
@@ -15,15 +15,14 @@ Gem::Specification.new do |gem|
gem.license = 'MIT'
gem.add_dependency 'rails', '~> 3.2.12'
- gem.add_dependency 'prototype-rails'
gem.add_dependency 'jquery-rails', '~> 2.1.4' # pegs us to jQuery 1.8
gem.add_dependency 'select2-rails'
gem.add_dependency 'simple_form', '~> 2.0.1'
- gem.add_dependency 'will_paginate', '~> 3.0.2'
+ gem.add_dependency 'will_paginate'
gem.add_dependency 'paperclip'
# Manually added paperclip gem dependency "cocaine" in order to fix load error: "no such file to load -- cocaine"
gem.add_dependency 'cocaine'
- gem.add_dependency 'paper_trail'
+ gem.add_dependency 'paper_trail', '~> 2.7.0' # not ready for v3 yet
gem.add_dependency 'authlogic', '3.1.0'
gem.add_dependency 'acts_as_commentable', '~> 3.0.1'
gem.add_dependency 'acts-as-taggable-on', '~> 2.3.3'
@@ -33,11 +32,13 @@ Gem::Specification.new do |gem|
gem.add_dependency 'acts_as_list', '~> 0.1.4'
gem.add_dependency 'ffaker', '>= 1.12.0'
gem.add_dependency 'cancan'
+ gem.add_dependency 'font-awesome-rails'
gem.add_dependency 'premailer'
gem.add_dependency 'nokogiri'
gem.add_dependency 'responds_to_parent', '>= 1.1.0'
gem.add_dependency 'rails3-jquery-autocomplete'
gem.add_dependency 'valium'
+ gem.add_dependency 'psych', '~> 1' if RUBY_VERSION.to_f < 2.0
gem.add_dependency "combined_time_select", "~> 0.0.1"
gem.add_dependency 'mandrill-rails'
gem.add_dependency 'mailchimp'
@@ -53,8 +54,6 @@ Gem::Specification.new do |gem|
# FatFreeCRM has released it's own versions of the following gems:
#-----------------------------------------------------------------
- gem.add_dependency 'ransack_ffcrm', '~> 0.7.1'
gem.add_dependency 'ransack_ui', '>= 1.1.0'
- gem.add_dependency 'ajax-chosen-rails', '>= 0.2.1' # (now depends on chosen-rails_ffcrm)
gem.add_dependency 'email_reply_parser_ffcrm'
end
diff --git a/lib/plugins/country_select/lib/country_select.rb b/lib/country_select.rb
similarity index 100%
rename from lib/plugins/country_select/lib/country_select.rb
rename to lib/country_select.rb
diff --git a/lib/development_tasks/rspec.rake b/lib/development_tasks/rspec.rake
index 59f28fda4c..d9052a9dd3 100644
--- a/lib/development_tasks/rspec.rake
+++ b/lib/development_tasks/rspec.rake
@@ -5,7 +5,7 @@
#------------------------------------------------------------------------------
if defined?(RSpec)
require 'rspec/core/rake_task'
-
+
namespace :spec do
desc "Preparing test env"
task :prepare do
@@ -21,8 +21,4 @@ if defined?(RSpec)
Rake::Task["spec"].prerequisites.clear
Rake::Task["spec"].prerequisites.push("spec:prepare")
- desc 'Run the acceptance specs in ./acceptance'
- RSpec::Core::RakeTask.new(:acceptance => 'spec:prepare') do |t|
- t.pattern = 'acceptance/**/*_spec.rb'
- end
end
diff --git a/lib/fat_free_crm.rb b/lib/fat_free_crm.rb
index e07cdf68c7..b3c6f999c3 100644
--- a/lib/fat_free_crm.rb
+++ b/lib/fat_free_crm.rb
@@ -9,12 +9,22 @@ class << self
# Return either Application or Engine,
# depending on how Fat Free CRM has been loaded
def application
- defined?(FatFreeCRM::Engine) ? Engine : Application
+ engine? ? Engine : Application
end
def root
application.root
end
+
+ # Are we running as an engine?
+ def engine?
+ defined?(FatFreeCRM::Engine).present?
+ end
+
+ def application?
+ !engine?
+ end
+
end
end
@@ -28,7 +38,6 @@ def root
# Require gem dependencies, monkey patches, and vendored plugins (in lib)
require "fat_free_crm/gem_dependencies"
require "fat_free_crm/gem_ext"
-require "fat_free_crm/plugin_dependencies"
require "fat_free_crm/custom_fields" # load hooks for Field
require "fat_free_crm/version"
@@ -47,6 +56,9 @@ def root
require "fat_free_crm/callback"
require "fat_free_crm/plugin"
require "fat_free_crm/view_factory"
+
+require "country_select"
+require "gravatar_image_tag"
require "mandrill_email_job"
require "conference_email_job"
#require "ffcrm_merge"
diff --git a/lib/fat_free_crm/engine.rb b/lib/fat_free_crm/engine.rb
index 9afd2fc3aa..6e558ce4f8 100644
--- a/lib/fat_free_crm/engine.rb
+++ b/lib/fat_free_crm/engine.rb
@@ -7,9 +7,7 @@ module FatFreeCRM
class Engine < ::Rails::Engine
config.autoload_paths += Dir[root.join("app/models/**")] +
Dir[root.join("app/controllers/entities")]
-
- config.to_prepare do
- ActiveRecord::Base.observers = :lead_observer, :opportunity_observer, :task_observer, :mailchimp_observer, :saasu_observer
- end
+ config.active_record.observers = [:lead_observer, :opportunity_observer,
+ :task_observer, :entity_observer, :mailchimp_observer, :saasu_observer]
end
end
diff --git a/lib/fat_free_crm/export_csv.rb b/lib/fat_free_crm/export_csv.rb
index dae6207a76..c16808ae8a 100644
--- a/lib/fat_free_crm/export_csv.rb
+++ b/lib/fat_free_crm/export_csv.rb
@@ -7,7 +7,7 @@
module FatFreeCRM
class ExportCSV
-
+
# CSV export. Based on to_csv Rails plugin by Ary Djmal
# https://github.com/arydjmal/to_csv
#----------------------------------------------------------------------------
@@ -16,7 +16,7 @@ def self.from_array(items = [])
# Infer column types from the first item in the array
klass = items.first.class
columns = klass.columns.map(&:name).reject { |column| column =~ /password|token/ }
- columns << 'tags'
+ columns << 'tags' if klass.taggable?
CSV.generate do |csv|
csv << columns.map { |column| klass.human_attribute_name(column) }
items.each do |item|
@@ -30,6 +30,6 @@ def self.from_array(items = [])
end
end
end
-
+
end
end
diff --git a/lib/fat_free_crm/fields.rb b/lib/fat_free_crm/fields.rb
index 20eb2b08e1..8880eeea42 100755
--- a/lib/fat_free_crm/fields.rb
+++ b/lib/fat_free_crm/fields.rb
@@ -42,6 +42,16 @@ def serialize_custom_fields!
end
end
+ # Shows custom field select options in ransack search form
+ def ransack_column_select_options
+ field_groups.each_with_object({}) do |group, hash|
+ group.fields.select{|f| f.collection.present? }.each do |field|
+ hash[field.name] = field.collection.each_with_object({}) do |option, options|
+ options[option] = option
+ end
+ end
+ end
+ end
end
module InstanceMethods
@@ -66,7 +76,7 @@ def assign_attributes(new_attributes, options = {})
end
def method_missing(method_id, *args, &block)
- if method_id.to_s =~ /^cf_/
+ if method_id.to_s =~ /\Acf_/
# Refresh columns and try again.
self.class.reset_column_information
# If new record, create new object from class, else reload class
diff --git a/lib/fat_free_crm/gem_dependencies.rb b/lib/fat_free_crm/gem_dependencies.rb
index 58d3085cc8..81b1251248 100755
--- a/lib/fat_free_crm/gem_dependencies.rb
+++ b/lib/fat_free_crm/gem_dependencies.rb
@@ -6,7 +6,6 @@
require 'rails/all'
require 'jquery-rails'
require 'select2-rails'
-require 'prototype-rails'
require 'haml'
require 'sass'
require 'acts_as_commentable'
@@ -18,8 +17,6 @@
require 'simple_form'
require 'will_paginate'
require 'authlogic'
-require 'chosen-rails'
-require 'ajax-chosen-rails'
require 'ransack'
require 'ransack_ui'
require 'paper_trail'
@@ -29,6 +26,7 @@
require 'ffaker'
require 'premailer'
require 'nokogiri'
+require 'font-awesome-rails'
# Load redcloth if available (for textile markup in emails)
begin
diff --git a/lib/fat_free_crm/gem_ext.rb b/lib/fat_free_crm/gem_ext.rb
index 839a276ac6..1e501a0ceb 100755
--- a/lib/fat_free_crm/gem_ext.rb
+++ b/lib/fat_free_crm/gem_ext.rb
@@ -6,8 +6,6 @@
require "fat_free_crm/gem_ext/rails/text_helper"
require "fat_free_crm/gem_ext/active_record/schema_dumper"
require "fat_free_crm/gem_ext/active_support/buffered_logger"
-require "fat_free_crm/gem_ext/active_model/serializers/xml/serializer/attribute"
require "fat_free_crm/gem_ext/action_controller/base"
-require "fat_free_crm/gem_ext/authlogic/session/cookies"
require "fat_free_crm/gem_ext/simple_form/action_view_extensions/form_helper"
require "fat_free_crm/gem_ext/rake/task" if defined?(Rake)
diff --git a/lib/fat_free_crm/gem_ext/active_model/serializers/xml/serializer/attribute.rb b/lib/fat_free_crm/gem_ext/active_model/serializers/xml/serializer/attribute.rb
deleted file mode 100755
index 04f1419cb1..0000000000
--- a/lib/fat_free_crm/gem_ext/active_model/serializers/xml/serializer/attribute.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-#
-# Fat Free CRM is freely distributable under the terms of MIT license.
-# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-#------------------------------------------------------------------------------
-# Take into account current time zone when serializing datetime values
-# See: https://rails.lighthouseapp.com/projects/8994/tickets/6096-to_xml-datetime-format-regression
-
-ActiveModel::Serializers::Xml::Serializer::Attribute.class_eval do
- def initialize(name, serializable, raw_value=nil)
- @name, @serializable = name, serializable
- raw_value = raw_value.in_time_zone if raw_value.respond_to?(:in_time_zone)
- @value = raw_value || @serializable.send(name)
- @type = compute_type
- end
-end
-
diff --git a/lib/fat_free_crm/gem_ext/authlogic/session/cookies.rb b/lib/fat_free_crm/gem_ext/authlogic/session/cookies.rb
deleted file mode 100644
index 96aa7e804b..0000000000
--- a/lib/fat_free_crm/gem_ext/authlogic/session/cookies.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-#
-# Fat Free CRM is freely distributable under the terms of MIT license.
-# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-#------------------------------------------------------------------------------
-require 'action_controller'
-require 'authlogic'
-
-# Fix bug for default cookie name (use klass_name, instead of guessed_klass_name)
-# Pull request pending: https://github.com/binarylogic/authlogic/pull/281
-Authlogic::Session::Base.instance_eval do
- def cookie_key(value = nil)
- rw_config(:cookie_key, value, "#{klass_name.underscore}_credentials")
- end
-end
-
diff --git a/lib/fat_free_crm/gem_ext/rails/text_helper.rb b/lib/fat_free_crm/gem_ext/rails/text_helper.rb
index 3d79983464..888fe36b74 100755
--- a/lib/fat_free_crm/gem_ext/rails/text_helper.rb
+++ b/lib/fat_free_crm/gem_ext/rails/text_helper.rb
@@ -86,7 +86,7 @@ def auto_link_urls(text, html_options = {}, options = {})
href
else
# don't include trailing punctuation character as part of the URL
- while href.sub!(/[^\w\/-]$/, '')
+ while href.sub!(/[^\w\/-]\z/, '')
punctuation.push $&
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
href << punctuation.pop
@@ -127,4 +127,3 @@ def auto_linked?(left, right)
end
end
end
-
diff --git a/lib/fat_free_crm/i18n.rb b/lib/fat_free_crm/i18n.rb
index 5ad270592e..2ad6d9a8f7 100644
--- a/lib/fat_free_crm/i18n.rb
+++ b/lib/fat_free_crm/i18n.rb
@@ -3,34 +3,38 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
+require 'pathname'
+
module FatFreeCRM
module I18n
#----------------------------------------------------------------------------
def t(*args)
if args.size == 1
- super(args.first, :default => args.first.to_s)
+ super(args.first, default: args.first.to_s)
elsif args.second.is_a?(Hash)
super(*args)
elsif args.second.is_a?(Fixnum)
- super(args.first, :count => args.second)
+ super(args.first, count: args.second)
else
- super(args.first, :value => args.second)
+ super(args.first, value: args.second)
end
end
# Scan config/locales directory for Fat Free CRM localization files
# (i.e. *_fat_free_crm.yml) and return locale part of the file name.
+ # We can't use ::I18n.available_locales because rails provides it's own
+ # translations too and we only want the locales that Fat Free CRM supports.
#----------------------------------------------------------------------------
def locales
- @@locales ||= Dir.entries("#{Rails.root}/config/locales").grep(/_fat_free_crm\.yml$/) { |f| f.sub("_fat_free_crm.yml", "") }
+ @@locales ||= ::I18n.load_path.grep(/_fat_free_crm\.yml$/).map{ |path| Pathname.new(path).basename.to_s.match(/(.*)_fat_free_crm\.yml/)[1] }.uniq
end
# Return a hash where the key is locale name, and the value is language name
# as defined in the locale_fat_free_crm.yml file.
#----------------------------------------------------------------------------
def languages
- @@languages ||= Hash[ locales.map{ |locale| [ locale, t(:language, :locale => locale) ] } ]
+ @@languages ||= Hash[ locales.map{ |locale| [ locale, t(:language, locale: locale) ] } ]
end
end
end
diff --git a/lib/fat_free_crm/permissions.rb b/lib/fat_free_crm/permissions.rb
index 2927fa25ef..f34f1a8c9b 100644
--- a/lib/fat_free_crm/permissions.rb
+++ b/lib/fat_free_crm/permissions.rb
@@ -44,7 +44,6 @@ def #{model}_ids=(value)
if access != "Shared"
remove_permissions
else
- value.map!{|c| c.split(',')} if value.map{|v| v.to_s.include?(',')}.any? # fix for a bug in "Chosen" which gives values like ["", "1,2,3"]
value = value.flatten.reject(&:blank?).uniq.map(&:to_i)
permissions_to_remove = Permission.find_all_by_#{model}_id_and_asset_id_and_asset_type(self.#{model}_ids - value, self.id, self.class)
permissions_to_remove.each {|p| (permissions.delete(p); p.destroy)}
@@ -57,7 +56,7 @@ def #{model}_ids
end
}
end
-
+
# Remove all shared permissions if no longer shared
#--------------------------------------------------------------------------
def access=(value)
@@ -95,7 +94,7 @@ def save_with_model_permissions(model)
self.group_ids = model.group_ids
save
end
-
+
end
module SingletonMethods
diff --git a/lib/fat_free_crm/plugin_dependencies.rb b/lib/fat_free_crm/plugin_dependencies.rb
deleted file mode 100644
index 4302de3a46..0000000000
--- a/lib/fat_free_crm/plugin_dependencies.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-#
-# Fat Free CRM is freely distributable under the terms of MIT license.
-# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-#------------------------------------------------------------------------------
-# Plugin dependencies
-Dir.glob(File.join(File.dirname(__FILE__), '..', 'plugins', '**')).each do |plugin_dir|
- # Add 'plugin/lib' to $LOAD_PATH
- $:.unshift File.expand_path(File.join(plugin_dir, 'lib'))
- require File.basename(plugin_dir) # require 'plugin'
- require File.join(plugin_dir, 'init') # require 'plugin/init'
-end
diff --git a/lib/fat_free_crm/secret_token_generator.rb b/lib/fat_free_crm/secret_token_generator.rb
new file mode 100644
index 0000000000..17ea759d21
--- /dev/null
+++ b/lib/fat_free_crm/secret_token_generator.rb
@@ -0,0 +1,65 @@
+# Copyright (c) 2008-2014 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+
+require 'securerandom'
+
+module FatFreeCRM
+
+ class SecretTokenGenerator
+
+ class << self
+
+ #
+ # If there is no secret token defined, we generate one and save it as a setting
+ # If a token has been already been saved, we tell Rails to use it and move on.
+ def setup!
+ if !token_exists?
+ Rails.logger.info("No secret key defined yet... generating and saving to Setting.secret_token")
+ new_token!
+ end
+ # If db isn't setup yet, token will return nil, provide a randomly generated one for now.
+ FatFreeCRM::Application.config.secret_token = ( token || generate_token )
+ end
+
+ private
+
+ def token_exists?
+ Setting.secret_token.present?
+ end
+
+ #
+ # Read the current token from settings
+ def token
+ Setting.secret_token
+ end
+
+ #
+ # Create a new secret token and save it as a setting.
+ def new_token!
+ quietly do
+ Setting.secret_token = generate_token
+ end
+ end
+
+ def generate_token
+ SecureRandom.hex(64)
+ end
+
+ #
+ # Yields to a block that executes with the logging turned off
+ # This stops the secret token from being appended to the log
+ def quietly(&block)
+ temp_logger = ActiveRecord::Base.logger
+ ActiveRecord::Base.logger = nil
+ yield
+ ActiveRecord::Base.logger = temp_logger
+ end
+
+ end
+
+ end
+
+end
diff --git a/lib/fat_free_crm/version.rb b/lib/fat_free_crm/version.rb
index 77a5ee0c69..8d9a118b0a 100644
--- a/lib/fat_free_crm/version.rb
+++ b/lib/fat_free_crm/version.rb
@@ -6,8 +6,8 @@
module FatFreeCRM
module VERSION #:nodoc:
MAJOR = 0
- MINOR = 12
- TINY = 0
+ MINOR = 13
+ TINY = 2
PRE = nil
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
diff --git a/lib/fat_free_crm/view_factory.rb b/lib/fat_free_crm/view_factory.rb
index e1abd7df40..17a31e40b6 100644
--- a/lib/fat_free_crm/view_factory.rb
+++ b/lib/fat_free_crm/view_factory.rb
@@ -3,6 +3,7 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
+
module FatFreeCRM
# A view factory keeps track of views and the contexts in which they are available.
@@ -15,7 +16,7 @@ module FatFreeCRM
# Icon is optional. If specified, it will be passed to asset_path.
#
class ViewFactory
-
+
include Comparable
@@views = []
@@ -24,13 +25,13 @@ class ViewFactory
# Class methods
#----------------------------------------------------------------------------
class << self
-
+
# Register with the view factory
#----------------------------------------------------------------------------
def register(view)
@@views << view unless @@views.map(&:id).include?(view.id)
end
-
+
# Return views that are available based on context
#----------------------------------------------------------------------------
def views_for(options = {})
@@ -41,7 +42,7 @@ def views_for(options = {})
view.controllers.include?(controller) and view.actions.include?(action) and (name.present? ? view.name == name : true)
end
end
-
+
# Return template name of the current view
# pass in options[:name] to specify view name
#----------------------------------------------------------------------------
@@ -72,12 +73,14 @@ def <=>(other)
end
private
-
+
# This defines what it means for one view to be different to another
#----------------------------------------------------------------------------
def generate_id
[name, controllers.sort, actions.sort].flatten.map(&:to_s).map(&:underscore).join('_')
end
+ ActiveSupport.run_load_hooks(:fat_free_crm_view_factory, self)
+
end
end
diff --git a/lib/plugins/gravatar_image_tag/lib/gravatar_image_tag.rb b/lib/gravatar_image_tag.rb
similarity index 100%
rename from lib/plugins/gravatar_image_tag/lib/gravatar_image_tag.rb
rename to lib/gravatar_image_tag.rb
diff --git a/lib/plugins/country_select/MIT-LICENSE b/lib/plugins/country_select/MIT-LICENSE
deleted file mode 100644
index 77a51dab16..0000000000
--- a/lib/plugins/country_select/MIT-LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2008 Michael Koziarski
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/lib/plugins/country_select/README b/lib/plugins/country_select/README
deleted file mode 100644
index 15408fb421..0000000000
--- a/lib/plugins/country_select/README
+++ /dev/null
@@ -1,14 +0,0 @@
-CountrySelect
-=============
-
-Provides a simple helper to get an HTML select list of countries. The list of countries comes from the ISO 3166 standard. While it is a relatively neutral source of country names, it will still offend some users.
-
-Users are strongly advised to evaluate the suitability of this list given their user base.
-
-Example
-=======
-
-country_select("user", "country_name")
-
-
-Copyright (c) 2008 Michael Koziarski, released under the MIT license
diff --git a/lib/plugins/country_select/init.rb b/lib/plugins/country_select/init.rb
deleted file mode 100644
index d1d9d72a46..0000000000
--- a/lib/plugins/country_select/init.rb
+++ /dev/null
@@ -1 +0,0 @@
-require 'country_select'
diff --git a/lib/plugins/country_select/install.rb b/lib/plugins/country_select/install.rb
deleted file mode 100644
index 6ca58b4584..0000000000
--- a/lib/plugins/country_select/install.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-# Install hook code here
-puts "The list of countries provided by this plugin may offend some users. Please review it carefully before you use it"
diff --git a/lib/plugins/country_select/uninstall.rb b/lib/plugins/country_select/uninstall.rb
deleted file mode 100644
index 93b58bfbdb..0000000000
--- a/lib/plugins/country_select/uninstall.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-# Uninstall hook code here
-
diff --git a/lib/plugins/gravatar_image_tag/Gemfile b/lib/plugins/gravatar_image_tag/Gemfile
deleted file mode 100644
index c23cd449f4..0000000000
--- a/lib/plugins/gravatar_image_tag/Gemfile
+++ /dev/null
@@ -1,8 +0,0 @@
-source :rubygems
-
-group :development do
- gem 'activesupport'
- gem 'actionpack'
- gem 'jeweler'
- gem 'rspec'
-end
\ No newline at end of file
diff --git a/lib/plugins/gravatar_image_tag/README.textile b/lib/plugins/gravatar_image_tag/README.textile
deleted file mode 100644
index 1c9d728a6a..0000000000
--- a/lib/plugins/gravatar_image_tag/README.textile
+++ /dev/null
@@ -1,108 +0,0 @@
-!http://s.gravatar.com/images/logo.png(Gravatar Logo)!
-
-h1. Gravatar Image Tag Plugin
-
-Rails view helper for grabbing "Gravatar":http://en.gravatar.com/ images. The goal here is to be configurable and have those configuration points documented!
-
-h2. Install as a Ruby Gem
-
-h3. Rails 2
-
-p. Include the following line in your Rails environment
-
-# config/environment
- config.gem 'gravatar_image_tag'
-
-p. Then ensure the gem is installed by running the following rake task from the your application root.
-
-rake gems:install
-
-h3. Rails 3
-
-p. Include the following line in your Rails environment
-
-# Gemfile
- gem 'gravatar_image_tag'
-
-p. Then ensure the gem is installed by running the following command from the your application root.
-
-bundle install
-
-h2. Install as a Ruby on Rails Plugin
-
-./script/plugin install git://github.com/mdeering/gravatar_image_tag.git
-
-h2. Usage
-
-Once you have installed it as a plugin for your rails app usage is simple.
-
-gravatar_image_tag('spam@spam.com'.gsub('spam', 'mdeering'), :alt => 'Michael Deering')
-
-*Boom* here is my gravatar !http://www.gravatar.com/avatar/4da9ad2bd4a2d1ce3c428e32c423588a(Michael Deering)!
-
-h2. Configuration
-
-h3. Global configuration points
-
-# config/initializers/gravatar_image_tag.rb
-GravatarImageTag.configure do |config|
- config.default_image = nil # Set this to use your own default gravatar image rather then serving up Gravatar's default image [ 'http://example.com/images/default_gravitar.jpg', :identicon, :monsterid, :wavatar, 404 ].
- config.filetype = nil # Set this if you require a specific image file format ['gif', 'jpg' or 'png']. Gravatar's default is png
- config.rating = nil # Set this if you change the rating of the images that will be returned ['G', 'PG', 'R', 'X']. Gravatar's default is G
- config.size = nil # Set this to globally set the size of the gravatar image returned (1..512). Gravatar's default is 80
- config.secure = false # Set this to true if you require secure images on your pages.
-end
-
-
-h3. Setting the default image inline
-
-p. *Splat* the default gravatar image !http://www.gravatar.com/avatar/0c821f675f132d790b3f25e79da739a7(Default Gravatar Image)!
-
-p. You can set the default gravatar image inline as follows:
-
-gravatar_image_tag('junk', :alt => 'Github Default Gravatar', :gravatar => { :default => 'http://github.com/images/gravatars/gravatar-80.png' })
-
-p. *Ka-Pow* !http://www.gravatar.com/avatar/0c821f675f132d790b3f25e79da739a7?default=http%3A%2F%2Fgithub.com%2Fimages%2Fgravatars%2Fgravatar-80.png(Github Default Gravatar)!
-
-p. Other options supported besides an image url to fall back on include the following:
-
-* :identicon !http://www.gravatar.com/avatar/0c821f675f132d790b3f25e79da739a7?default=identicon(Identicon Avatar)!
-* :monsterid !http://www.gravatar.com/avatar/0c821f675f132d790b3f25e79da739a7?default=monsterid(Monster Id Avatar)!
-* :wavatar !http://www.gravatar.com/avatar/0c821f675f132d790b3f25e79da739a7?default=wavatar(Wavatar Avatar)!
-* 404: !http://www.gravatar.com/avatar/0c821f675f132d790b3f25e79da739a7?default=404(Not Found)!
-
-h3. Setting the default image size
-
-p. You can set the gravatar image size inline as follows:
-
-gravatar_image_tag('spam@spam.com'.gsub('spam', 'mdeering'), :alt => 'Michael Deering', :class => 'some-class', :gravatar => { :size => 15 })
-
-*Mini Me!* !(some-class)http://www.gravatar.com/avatar/4da9ad2bd4a2d1ce3c428e32c423588a?size=15(Michael Deering)!
-
-h3. Grabbing gravatars from the secure gravatar server.
-
-p. You can make a request for a gravatar from the secure server at https://secure.gravatar.com by passing the _:gravatar => { :secure => true }_ option to the gravatar_image_tag call.
-
-gravatar_image_tag('spam@spam.com'.gsub('spam', 'mdeering'), :alt => 'Michael Deering', :gravatar => { :secure => true } )
-
-Delivered by a secure url! !https://secure.gravatar.com/avatar/4da9ad2bd4a2d1ce3c428e32c423588a(Michael Deering)!
-
-h3. Using Gravatar's built in rating system
-
-p. You can set the gravatar rating inline as follows:
-
-gravatar_image_tag('spam@spam.com'.gsub('spam', 'mdeering'), :alt => 'Michael Deering', :gravatar => { :rating => 'pg' } )
-
-
-h3. Specifying a filetype
-
-p. You can set the gravatar filetype inline as follows:
-
-gravatar_image_tag('spam@spam.com'.gsub('spam', 'mdeering'), :alt => 'Michael Deering', :gravatar => { :filetype => :gif } )
-
-
-h2. Credits
-
-The ideas an methods for this plugin are from expanding upon my original blog post "Adding Gravatar To Your Website Or Blog (Gravatar Rails)":http://mdeering.com/posts/005-adding-gravitar-to-your-website-or-blog
-
-Copyright (c) 2009-2010 "Michael Deering(Ruby on Rails Development Edmonton)":http://mdeering.com, released under the MIT license
diff --git a/lib/plugins/gravatar_image_tag/ROADMAP.textile b/lib/plugins/gravatar_image_tag/ROADMAP.textile
deleted file mode 100644
index ca90482dbd..0000000000
--- a/lib/plugins/gravatar_image_tag/ROADMAP.textile
+++ /dev/null
@@ -1,33 +0,0 @@
-h1. 1.1.0
-
-* Add model helpers for ActiveRecord/ActiveModel
-
-class Comment < ActiveRecord::Base
- has_gravatar :author, :size => 120
-end
-
-Comment.first.gravatar_url
-
-h1. 1.0.0
-
-* -Block Configuration DSL support-
-
-# config/initializers/gravatar_image_tag.rb
-GravatarImageTag.configure do |config|
- config.default_image = nil # Set this to use your own default gravatar image rather then serving up Gravatar's default image [ 'http://example.com/images/default_gravitar.jpg', :identicon, :monsterid, :wavatar, 404 ].
- config.filetype = nil # Set this if you require a specific image file format ['gif', 'jpg' or 'png']. Gravatar's default is png
- config.rating = nil # Set this if you change the rating of the images that will be returned ['G', 'PG', 'R', 'X']. Gravatar's default is G
- config.size = nil # Set this to globally set the size of the gravatar image returned (1..512). Gravatar's default is 80
- config.secure = false # Set this to true if you require secure images on your pages.
-end
-
-
-h1. 0.1.0
-
-* -Add support for https calls to Gravatar-
-* -Add support the different ratings call to Gravatar-
-* -Add support for the filetype call to Gravatar-
-
-h1. 0.0.1
-
-* -package things up into a gem.- "Hosted on Gemcutter now(Gravatar Image Tag Ruby Gem)":http://rubygems.org/gems/gravatar_image_tag
diff --git a/lib/plugins/gravatar_image_tag/Rakefile b/lib/plugins/gravatar_image_tag/Rakefile
deleted file mode 100644
index 954b9fe28c..0000000000
--- a/lib/plugins/gravatar_image_tag/Rakefile
+++ /dev/null
@@ -1,50 +0,0 @@
-require 'rake'
-require 'rake/rdoctask'
-require 'spec/rake/spectask'
-
-begin
- AUTHOR = "Michael Deering"
- EMAIL = "mdeering@mdeering.com"
- GEM = "gravatar_image_tag"
- HOMEPAGE = "http://github.com/mdeering/gravatar_image_tag"
- SUMMARY = "A configurable and documented Rails view helper for adding gravatars into your Rails application."
-
- require 'jeweler'
- Jeweler::Tasks.new do |s|
- s.author = AUTHOR
- s.email = EMAIL
- s.files = %w(install.rb install.txt MIT-LICENSE README.textile Rakefile) + Dir.glob("{rails,lib,spec}/**/*")
- s.homepage = HOMEPAGE
- s.name = GEM
- s.require_path = 'lib'
- s.summary = SUMMARY
- end
- Jeweler::GemcutterTasks.new
-rescue LoadError
- puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
-end
-
-desc 'Default: spec tests.'
-task :default => :spec
-
-desc 'Test the gravatar_image_tag gem.'
-Spec::Rake::SpecTask.new('spec') do |t|
- t.spec_files = FileList['spec/**/*_spec.rb']
- t.spec_opts = ["-c"]
-end
-
-desc "Run all examples with RCov"
-Spec::Rake::SpecTask.new('examples_with_rcov') do |t|
- t.spec_files = FileList['spec/**/*_spec.rb']
- t.rcov = true
- t.rcov_opts = ['--exclude', '/opt,spec,Library']
-end
-
-desc 'Generate documentation for the gravatar_image_tag plugin.'
-Rake::RDocTask.new(:rdoc) do |rdoc|
- rdoc.rdoc_dir = 'rdoc'
- rdoc.title = 'GravatarImageTag'
- rdoc.options << '--line-numbers' << '--inline-source'
- rdoc.rdoc_files.include('README.textile')
- rdoc.rdoc_files.include('lib/**/*.rb')
-end
diff --git a/lib/plugins/gravatar_image_tag/VERSION b/lib/plugins/gravatar_image_tag/VERSION
deleted file mode 100644
index 97cc3cfda5..0000000000
--- a/lib/plugins/gravatar_image_tag/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-1.0.0.pre2
diff --git a/lib/plugins/gravatar_image_tag/gravatar_image_tag.gemspec b/lib/plugins/gravatar_image_tag/gravatar_image_tag.gemspec
deleted file mode 100644
index 5e0b5c3414..0000000000
--- a/lib/plugins/gravatar_image_tag/gravatar_image_tag.gemspec
+++ /dev/null
@@ -1,45 +0,0 @@
-# Generated by jeweler
-# DO NOT EDIT THIS FILE DIRECTLY
-# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
-# -*- encoding: utf-8 -*-
-
-Gem::Specification.new do |s|
- s.name = %q{gravatar_image_tag}
- s.version = "1.0.0.pre2"
-
- s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
- s.authors = ["Michael Deering"]
- s.date = %q{2010-09-08}
- s.email = %q{mdeering@mdeering.com}
- s.extra_rdoc_files = [
- "README.textile"
- ]
- s.files = [
- "MIT-LICENSE",
- "README.textile",
- "Rakefile",
- "lib/gravatar_image_tag.rb",
- "spec/gravatar_image_tag_spec.rb",
- "spec/test_helper.rb"
- ]
- s.homepage = %q{http://github.com/mdeering/gravatar_image_tag}
- s.rdoc_options = ["--charset=UTF-8"]
- s.require_paths = ["lib"]
- s.rubygems_version = %q{1.3.7}
- s.summary = %q{A configurable and documented Rails view helper for adding gravatars into your Rails application.}
- s.test_files = [
- "spec/gravatar_image_tag_spec.rb",
- "spec/test_helper.rb"
- ]
-
- if s.respond_to? :specification_version then
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
- s.specification_version = 3
-
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
- else
- end
- else
- end
-end
-
diff --git a/lib/plugins/gravatar_image_tag/init.rb b/lib/plugins/gravatar_image_tag/init.rb
deleted file mode 100644
index acd57bddc2..0000000000
--- a/lib/plugins/gravatar_image_tag/init.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require File.dirname(__FILE__) + '/lib/gravatar_image_tag'
-
diff --git a/lib/plugins/gravatar_image_tag/spec/gravatar_image_tag_spec.rb b/lib/plugins/gravatar_image_tag/spec/gravatar_image_tag_spec.rb
deleted file mode 100644
index 72c28874e9..0000000000
--- a/lib/plugins/gravatar_image_tag/spec/gravatar_image_tag_spec.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-require File.dirname(__FILE__) + '/test_helper'
-
-require 'gravatar_image_tag'
-
-ActionView::Base.send(:include, GravatarImageTag)
-
-describe GravatarImageTag do
-
- email = 'mdeering@mdeering.com'
- md5 = '4da9ad2bd4a2d1ce3c428e32c423588a'
- default_filetype = :gif
- default_image = 'http://mdeering.com/images/default_gravatar.png'
- default_image_escaped = 'http%3A%2F%2Fmdeering.com%2Fimages%2Fdefault_gravatar.png'
- default_rating = 'x'
- default_size = 50
- other_image = 'http://mdeering.com/images/other_gravatar.png'
- other_image_escaped = 'http%3A%2F%2Fmdeering.com%2Fimages%2Fother_gravatar.png'
- secure = false
-
- view = ActionView::Base.new
-
- {
- { :gravatar_id => md5 } => {},
- { :gravatar_id => md5 } => { :gravatar => { :rating => 'x' } },
- { :gravatar_id => md5, :size => 30 } => { :gravatar => {:size => 30 } },
- { :gravatar_id => md5, :default => other_image_escaped } => { :gravatar => {:default => other_image } },
- { :gravatar_id => md5, :default => other_image_escaped, :size => 30 } => { :gravatar => {:default => other_image, :size => 30 } }
- }.each do |params, options|
- it "#gravatar_image_tag should create the provided url with the provided options #{options}" do
- view = ActionView::Base.new
- image_tag = view.gravatar_image_tag(email, options)
- image_tag.include?("#{params.delete(:gravatar_id)}").should be_true
- params.all? {|key, value| image_tag.include?("#{key}=#{value}")}.should be_true
- end
- end
-
- {
- :default_gravatar_image => default_image,
- :default_gravatar_filetype => default_filetype,
- :default_gravatar_rating => default_rating,
- :default_gravatar_size => default_size,
- :secure_gravatar => secure
- }.each do |singleton_variable, value|
- it "should give a deprication warning for assigning to #{singleton_variable} and passthrough to set the new variable" do
- ActionView::Base.should_receive(:warn)
- ActionView::Base.send("#{singleton_variable}=", value)
- GravatarImageTag.configuration.default_image == value if singleton_variable == :default_gravatar_image
- GravatarImageTag.configuration.filetype == value if singleton_variable == :default_gravatar_filetype
- GravatarImageTag.configuration.rating == value if singleton_variable == :default_gravatar_rating
- GravatarImageTag.configuration.size == value if singleton_variable == :default_gravatar_size
- GravatarImageTag.configuration.secure == value if singleton_variable == :secure_gravatar
- end
- end
-
- # Now that the defaults are set...
- {
- { :gravatar_id => md5, :size => default_size, :default => default_image_escaped } => {},
- { :gravatar_id => md5, :size => 30, :default => default_image_escaped } => { :gravatar => { :size => 30 } },
- { :gravatar_id => md5, :size => default_size, :default => other_image_escaped } => { :gravatar => {:default => other_image } },
- { :gravatar_id => md5, :size => 30, :default => other_image_escaped } => { :gravatar => { :default => other_image, :size => 30 } },
- }.each do |params, options|
- it "#gravatar_image_tag #{params} should create the provided url when defaults have been set with the provided options #{options}" do
- view = ActionView::Base.new
- image_tag = view.gravatar_image_tag(email, options)
- image_tag.include?("#{params.delete(:gravatar_id)}.#{default_filetype}").should be_true
- params.all? {|key, value| image_tag.include?("#{key}=#{value}")}.should be_true
- end
- end
-
- it 'should request the gravatar image from the non-secure server if the https => false option is given' do
- (!!view.gravatar_image_tag(email, { :gravatar => { :secure => false } }).match(/^https:\/\/secure.gravatar.com\/avatar\//)).should be_false
- end
-
- it 'should request the gravatar image from the secure server if the https => true option is given' do
- (!!view.gravatar_image_tag(email, { :gravatar => { :secure => true } }).match(/src="https:\/\/secure.gravatar.com\/avatar\//)).should be_true
- end
-
- it 'GravatarImageTag#gravitar_id should not error out when email is nil' do
- lambda { GravatarImageTag::gravatar_id(nil) }.should_not raise_error(TypeError)
- end
-
-end
-
diff --git a/lib/plugins/gravatar_image_tag/spec/test_helper.rb b/lib/plugins/gravatar_image_tag/spec/test_helper.rb
deleted file mode 100644
index 8a2f2e54ea..0000000000
--- a/lib/plugins/gravatar_image_tag/spec/test_helper.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require 'rubygems'
-require 'spec'
-require 'active_support'
-require 'action_view'
-require 'digest/md5'
-require 'uri'
-
-Spec::Runner.configure do |config|
-end
-
-$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
-
diff --git a/lib/tasks/db/migrate.rake b/lib/tasks/db/migrate.rake
deleted file mode 100644
index 2ba5ace66f..0000000000
--- a/lib/tasks/db/migrate.rake
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-#
-# Fat Free CRM is freely distributable under the terms of MIT license.
-# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-#------------------------------------------------------------------------------
-Rake::Task.remove("db:migrate:status") # (Clears task so that it can be extended)
-
-namespace :db do
- namespace :migrate do
-
- desc "Display status of migrations, including plugins"
- task :status => :environment do
- def find_migrations(path)
- Dir.glob(path).each do |file|
- # only files matching "20091231235959_some_name.rb" pattern
- if match_data = /(\d{14})_(.+)\.rb/.match(file)
- status = @db_list.delete(match_data[1]) ? 'up' : 'down'
- @file_list << [status, match_data[1], match_data[2]]
- end
- end
- end
-
- config = ActiveRecord::Base.configurations[Rails.env || 'development']
- @db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM schema_migrations")
- @file_list = []
-
- # Find main migrations & plugin migrations
- find_migrations(File.join(Rails.root, 'db', 'migrate', '*'))
- find_migrations(File.join(Rails.root, 'vendor', 'plugins', '**', 'db', 'migrate', '*'))
-
- # output
- puts "\ndatabase: #{config['database']}\n\n"
- puts "#{"Status".center(8)} #{"Migration ID".ljust(14)} Migration Name"
- puts "-" * 50
- @file_list.each do |file|
- puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
- end
- @db_list.each do |version|
- puts "#{'up'.center(8)} #{version.ljust(14)} *** NO FILE ***"
- end
- puts
- end
-
- desc "Run plugin migrations"
- task :plugins => :environment do
- if Dir.glob("#{Rails.root}/vendor/plugins/*/db/migrate/*.rb").any?
- ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
-
- # The following tweak becomes necessary when plugins start to depend
- # on each others migrations.
- # ------------------------------------------------------------------------------
-
- # Copy all plugin migrations to temp directory
- system("mkdir -p /tmp/plugin_migrations && rm -rf /tmp/plugin_migrations/* && \
- cp #{Rails.root}/vendor/plugins/*/db/migrate/*.rb /tmp/plugin_migrations")
- # Run all plugin migrations, ordered by timestamp
- ActiveRecord::Migrator.migrate("/tmp/plugin_migrations", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
- # Remove temp migration directory
- system("rm -rf /tmp/plugin_migrations")
-
- Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
- end
- end
-
- end
-end
diff --git a/lib/tasks/db/schema.rake b/lib/tasks/db/schema.rake
deleted file mode 100644
index a1e075e8c2..0000000000
--- a/lib/tasks/db/schema.rake
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
-#
-# Fat Free CRM is freely distributable under the terms of MIT license.
-# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
-#------------------------------------------------------------------------------
-namespace :db do
- namespace :schema do
-
- desc "Upgrade your database schema from ids to timestamps"
- task :upgrade => :environment do
- timestamps = Dir.glob("db/migrate/*.rb").map{|f| File.basename(f)[/(\d+)/,1] }.sort
- timestamps[0..30].each_with_index do |timestamp, i|
- puts "== #{i+1} => #{timestamp}"
- ActiveRecord::Base.connection.
- execute("update schema_migrations set version=#{timestamp} where version='#{i+1}';")
- end
- end
-
- end
-end
diff --git a/lib/tasks/ffcrm/config.rake b/lib/tasks/ffcrm/config.rake
index aeae48bef6..cebfde722d 100644
--- a/lib/tasks/ffcrm/config.rake
+++ b/lib/tasks/ffcrm/config.rake
@@ -25,20 +25,17 @@ namespace :ffcrm do
#
desc "Ensures all yaml files in the config folder are readable by Psych. If not, assumes file is in the Syck format and converts it for you [creates a new file]."
task :syck_to_psych do
- error_count = 0
- total_files = 0
+ require 'fileutils'
+ require 'syck'
+ require 'psych'
Dir[File.join(Rails.root, 'config', '**', '*.yml')].each do |file|
- begin
- Psych.load_file(file)
- rescue Psych::SyntaxError => e
- puts e # prints error message with line number
- File.open("#{file}.new", 'w') {|f| f.puts Psych.dump(Syck.load_file(file)) }
- puts "Have written Psych compatible file to #{file}.new"
- error_count += 1
- end
- total_files += 1
+ YAML::ENGINE.yamler = 'syck'
+ puts "Converting #{file}"
+ yml = YAML.load( File.read(file) )
+ FileUtils.cp file, "#{file}.bak"
+ YAML::ENGINE.yamler = 'psych'
+ File.open(file, 'w'){ |file| file.write(YAML.dump(yml)) }
end
- puts "Scanned #{total_files} yml files. Found #{error_count} problems (see above)."
end
end
diff --git a/lib/tasks/ffcrm/missing_translations.rake b/lib/tasks/ffcrm/missing_translations.rake
index 861fa78b99..e6b111039f 100644
--- a/lib/tasks/ffcrm/missing_translations.rake
+++ b/lib/tasks/ffcrm/missing_translations.rake
@@ -13,7 +13,8 @@ namespace :ffcrm do
base_locale = 'en-US'
[[base_locale, args[:locale]],
- ["#{base_locale}_fat_free_crm", "#{args[:locale]}_fat_free_crm"]].each do |locale_file_names|
+ ["#{base_locale}_fat_free_crm", "#{args[:locale]}_fat_free_crm"],
+ ["#{base_locale}_ransack", "#{args[:locale]}_ransack"]].each do |locale_file_names|
detector = MissingTranslationDetector.new locale_file_names.first,
locale_file_names.last
detector.detect
diff --git a/lib/tasks/ffcrm/secret.rake b/lib/tasks/ffcrm/secret.rake
new file mode 100644
index 0000000000..17764c8c15
--- /dev/null
+++ b/lib/tasks/ffcrm/secret.rake
@@ -0,0 +1,17 @@
+# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+
+namespace :ffcrm do
+
+ desc "Generate a secret token for Rails to use."
+ task :secret do
+ require 'securerandom'
+ secret = SecureRandom.hex(64)
+ filename = File.join(Rails.root, 'config', 'initializers', 'secret_token.rb')
+ File.open(filename, 'w'){|f| f.puts "FatFreeCRM::Application.config.secret_token = '#{secret}'"}
+ end
+
+end
diff --git a/lib/tasks/ffcrm/settings.rake b/lib/tasks/ffcrm/settings.rake
index baec93ca56..dcdde6f3a0 100644
--- a/lib/tasks/ffcrm/settings.rake
+++ b/lib/tasks/ffcrm/settings.rake
@@ -5,30 +5,18 @@
#------------------------------------------------------------------------------
namespace :ffcrm do
namespace :settings do
-
+
desc "Clear settings from database (reset to default)"
task :clear => :environment do
- puts "== Clearing settings table..."
-
- # Truncate settings table
- ActiveRecord::Base.establish_connection(Rails.env)
- if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
- ActiveRecord::Base.connection.execute("DELETE FROM settings")
- else # mysql and postgres
- ActiveRecord::Base.connection.execute("TRUNCATE settings")
- end
-
- puts "===== Settings table has been cleared."
+ Setting.delete_all
end
desc "Show current settings in the database"
task :show => :environment do
- ActiveRecord::Base.establish_connection(Rails.env)
- names = ActiveRecord::Base.connection.select_values("SELECT name FROM settings ORDER BY name")
- names.each do |name|
+ Setting.select('name').order('name').pluck('name').each do |name|
puts "\n#{name}:\n #{Setting.send(name).inspect}"
end
end
-
+
end
end
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index d934ae7e9e..d8ff1b21e8 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -54,10 +54,8 @@
#----------------------------------------------------------------------------
describe "GET new" do
it "assigns a new user as @user and renders [new] template" do
- @user = User.new
-
xhr :get, :new
- assigns[:user].attributes.should == @user.attributes
+ expect(assigns[:user]).to be_new_record
response.should render_template("admin/users/new")
end
end
@@ -117,7 +115,7 @@
it "assigns a newly created user as @user and renders [create] template" do
@user = FactoryGirl.build(:user, :username => @username, :email => @email)
- User.stub!(:new).and_return(@user)
+ User.stub(:new).and_return(@user)
xhr :post, :create, :user => { :username => @username, :email => @email, :password => @password, :password_confirmation => @password }
assigns[:user].should == @user
@@ -140,7 +138,7 @@
describe "with invalid params" do
it "assigns a newly created but unsaved user as @user and re-renders [create] template" do
@user = FactoryGirl.build(:user, :username => "", :email => "")
- User.stub!(:new).and_return(@user)
+ User.stub(:new).and_return(@user)
xhr :post, :create, :user => {}
assigns[:user].should == @user
@@ -241,7 +239,7 @@
xhr :delete, :destroy, :id => @user.id
flash[:warning].should_not == nil
- lambda { User.find(@user) }.should_not raise_error(ActiveRecord::RecordNotFound)
+ expect { User.find(@user) }.not_to raise_error()
response.should render_template("admin/users/destroy")
end
end
diff --git a/spec/controllers/applications_controller_spec.rb b/spec/controllers/applications_controller_spec.rb
index c624e3966c..f438d14002 100644
--- a/spec/controllers/applications_controller_spec.rb
+++ b/spec/controllers/applications_controller_spec.rb
@@ -22,8 +22,8 @@
end
it "should return [6, 9] when related is 'campaigns/7'" do
- controller.stub!(:controller_name).and_return('opportunities')
- campaign = mock(Campaign, :opportunities => [mock(:id => 6), mock(:id => 9)])
+ controller.stub(:controller_name).and_return('opportunities')
+ campaign = double(Campaign, :opportunities => [double(:id => 6), double(:id => 9)])
Campaign.should_receive(:find_by_id).with('7').and_return(campaign)
controller.send(:auto_complete_ids_to_exclude, 'campaigns/7').sort.should == [6, 9]
end
@@ -34,8 +34,8 @@
end
it "should return [] when related object association is not found" do
- controller.stub!(:controller_name).and_return('not_a_method_that_exists')
- campaign = mock(Campaign)
+ controller.stub(:controller_name).and_return('not_a_method_that_exists')
+ campaign = double(Campaign)
Campaign.should_receive(:find_by_id).with('7').and_return(campaign)
controller.send(:auto_complete_ids_to_exclude, 'campaigns/7').should == []
end
diff --git a/spec/controllers/authentications_controller_spec.rb b/spec/controllers/authentications_controller_spec.rb
index 55d4cf525a..60ba812a71 100644
--- a/spec/controllers/authentications_controller_spec.rb
+++ b/spec/controllers/authentications_controller_spec.rb
@@ -34,7 +34,7 @@
describe "user must not be logged in" do
before(:each) do
@user = FactoryGirl.create(:user, :username => "user", :password => "pass", :password_confirmation => "pass")
- @controller.stub!(:current_user).and_return(@user)
+ @controller.stub(:current_user).and_return(@user)
end
describe "GET authentication (login form)" do
@@ -63,18 +63,18 @@
describe "POST authentications" do
before(:each) do
@login = { :username => "user", :password => "pass", :remember_me => "0" }
- @authentication = mock(Authentication, @login)
+ @authentication = double(Authentication, @login)
end
describe "successful authentication " do
before(:each) do
- @authentication.stub!(:save).and_return(true)
- Authentication.stub!(:new).and_return(@authentication)
+ @authentication.stub(:save).and_return(true)
+ Authentication.stub(:new).and_return(@authentication)
end
it "displays welcome message and redirects to the home page" do
@user = FactoryGirl.create(:user, :username => "user", :password => "pass", :password_confirmation => "pass", :login_count => 0)
- @authentication.stub!(:user).and_return(@user)
+ @authentication.stub(:user).and_return(@user)
post :create, :authentication => @login
flash[:notice].should_not == nil
@@ -84,7 +84,7 @@
it "displays last login time if it's not the first login" do
@user = FactoryGirl.create(:user, :username => "user", :password => "pass", :password_confirmation => "pass", :login_count => 42)
- @authentication.stub!(:user).and_return(@user)
+ @authentication.stub(:user).and_return(@user)
post :create, :authentication => @login
flash[:notice].should =~ /last login/
@@ -96,9 +96,9 @@
describe "user is not suspended" do
it "redirects to login page if username or password are invalid" do
@user = FactoryGirl.create(:user, :username => "user", :password => "pass", :password_confirmation => "pass")
- @authentication.stub!(:user).and_return(@user)
- @authentication.stub!(:save).and_return(false) # <--- Authentication failure.
- Authentication.stub!(:new).and_return(@authentication)
+ @authentication.stub(:user).and_return(@user)
+ @authentication.stub(:save).and_return(false) # <--- Authentication failure.
+ Authentication.stub(:new).and_return(@authentication)
post :create, :authentication => @login
flash[:warning].should_not == nil
@@ -108,14 +108,14 @@
describe "user has been suspended" do
before(:each) do
- @authentication.stub!(:save).and_return(true)
- Authentication.stub!(:new).and_return(@authentication)
+ @authentication.stub(:save).and_return(true)
+ Authentication.stub(:new).and_return(@authentication)
end
# This tests :before_save update_info callback in Authentication model.
it "keeps user login attributes intact" do
@user = FactoryGirl.create(:user, :username => "user", :password => "pass", :password_confirmation => "pass", :suspended_at => Date.yesterday, :login_count => 0, :last_login_at => nil, :last_login_ip => nil)
- @authentication.stub!(:user).and_return(@user)
+ @authentication.stub(:user).and_return(@user)
post :create, :authentication => @login
@authentication.user.login_count.should == 0
@@ -125,7 +125,7 @@
it "redirects to login page if user is suspended" do
@user = FactoryGirl.create(:user, :username => "user", :password => "pass", :password_confirmation => "pass", :suspended_at => Date.yesterday)
- @authentication.stub!(:user).and_return(@user)
+ @authentication.stub(:user).and_return(@user)
post :create, :authentication => @login
flash[:warning].should_not == nil # Invalid username/password.
@@ -134,9 +134,9 @@
end
it "redirects to login page with the message if signup needs approval and user hasn't been activated yet" do
- Setting.stub!(:user_signup).and_return(:needs_approval)
+ Setting.stub(:user_signup).and_return(:needs_approval)
@user = FactoryGirl.create(:user, :username => "user", :password => "pass", :password_confirmation => "pass", :suspended_at => Date.yesterday, :login_count => 0)
- @authentication.stub!(:user).and_return(@user)
+ @authentication.stub(:user).and_return(@user)
post :create, :authentication => @login
flash[:warning].should == nil # Invalid username/password.
diff --git a/spec/controllers/comments_controller_spec.rb b/spec/controllers/comments_controller_spec.rb
old mode 100644
new mode 100755
index db173c29dc..50b867910e
--- a/spec/controllers/comments_controller_spec.rb
+++ b/spec/controllers/comments_controller_spec.rb
@@ -3,7 +3,7 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'spec_helper'
describe CommentsController do
@@ -76,84 +76,6 @@
end
- # GET /comments/1
- # GET /comments/1.xml not implemented
- #----------------------------------------------------------------------------
- # describe "responding to GET show" do
- #
- # it "should expose the requested comment as @comment" do
- # Comment.should_receive(:find).with("37").and_return(mock_comment)
- # get :show, :id => "37"
- # assigns[:comment].should equal(mock_comment)
- # end
- #
- # describe "with mime type of xml" do
- # it "should render the requested comment as xml" do
- # request.env["HTTP_ACCEPT"] = "application/xml"
- # Comment.should_receive(:find).with("37").and_return(mock_comment)
- # mock_comment.should_receive(:to_xml).and_return("generated XML")
- # get :show, :id => "37"
- # response.body.should == "generated XML"
- # end
- # end
- #
- # end
-
- # GET /comments/new
- # GET /comments/new.xml AJAX
- #----------------------------------------------------------------------------
- describe "responding to GET new" do
-
- COMMENTABLE.each do |asset|
- it "should expose a new comment as @comment for #{asset}" do
- @asset = FactoryGirl.create(asset)
- @comment = Comment.new
-
- xhr :get, :new, "#{asset}_id".to_sym => @asset.id
- assigns[:comment].attributes.should == @comment.attributes
- assigns[:commentable].should == asset.to_s
- response.should render_template("comments/new")
- end
-
- it "should save the fact that a comment gets added to #{asset}" do
- @asset = FactoryGirl.create(asset)
- @comment = Comment.new
-
- xhr :get, :new, "#{asset}_id".to_sym => @asset.id
- session["#{asset}_new_comment"].should == true
- end
-
- it "should clear the session if user cancels a comment for #{asset}" do
- @asset = FactoryGirl.create(asset)
- @comment = Comment.new
-
- xhr :get, :new, "#{asset}_id".to_sym => @asset.id, :cancel => "true"
- session["#{asset}_new_comment"].should == nil
- end
-
- it "should redirect to #{asset}'s index page with the message if the #{asset} got deleted" do
- @asset = FactoryGirl.create(asset)
- @asset.destroy
- @comment = Comment.new
-
- xhr :get, :new, "#{asset}_id".to_sym => @asset.id
- flash[:warning].should_not == nil
- response.body.should =~ %r(window.location.href)m
- response.body.should =~ %r(#{asset.to_s.pluralize})m
- end
-
- it "should redirect to #{asset}'s index page with the message if the #{asset} got protected" do
- @asset = FactoryGirl.create(asset, :access => "Private")
- @comment = Comment.new
-
- xhr :get, :new, "#{asset}_id".to_sym => @asset.id
- flash[:warning].should_not == nil
- response.body.should =~ %r(window.location.href)m
- response.body.should =~ %r(#{asset.to_s.pluralize})m
- end
- end
- end
-
# GET /comments/1/edit AJAX
#----------------------------------------------------------------------------
describe "responding to GET edit" do
@@ -162,7 +84,7 @@
it "should expose the requested comment as @commment and render [edit] template" do
@asset = FactoryGirl.create(asset)
@comment = FactoryGirl.create(:comment, :id => 42, :commentable => @asset, :user => current_user)
- Comment.stub!(:new).and_return(@comment)
+ Comment.stub(:new).and_return(@comment)
xhr :get, :edit, :id => 42
assigns[:comment].should == @comment
@@ -182,7 +104,7 @@
it "should expose a newly created comment as @comment for the #{asset}" do
@asset = FactoryGirl.create(asset)
@comment = FactoryGirl.build(:comment, :commentable => @asset, :user => current_user)
- Comment.stub!(:new).and_return(@comment)
+ Comment.stub(:new).and_return(@comment)
xhr :post, :create, :comment => { :commentable_type => asset.to_s.classify, :commentable_id => @asset.id, :user_id => current_user.id, :comment => "Hello" }
assigns[:comment].should == @comment
@@ -196,7 +118,7 @@
it "should expose a newly created but unsaved comment as @comment for #{asset}" do
@asset = FactoryGirl.create(asset)
@comment = FactoryGirl.build(:comment, :commentable => @asset, :user => current_user)
- Comment.stub!(:new).and_return(@comment)
+ Comment.stub(:new).and_return(@comment)
xhr :post, :create, :comment => {}
assigns[:comment].should == @comment
@@ -220,13 +142,13 @@
# end
#
# it "should expose the requested comment as @comment" do
- # Comment.stub!(:find).and_return(mock_comment(:update_attributes => true))
+ # Comment.stub(:find).and_return(mock_comment(:update_attributes => true))
# put :update, :id => "1"
# assigns(:comment).should equal(mock_comment)
# end
#
# it "should redirect to the comment" do
- # Comment.stub!(:find).and_return(mock_comment(:update_attributes => true))
+ # Comment.stub(:find).and_return(mock_comment(:update_attributes => true))
# put :update, :id => "1"
# response.should redirect_to(comment_path(mock_comment))
# end
@@ -240,13 +162,13 @@
# end
#
# it "should expose the comment as @comment" do
- # Comment.stub!(:find).and_return(mock_comment(:update_attributes => false))
+ # Comment.stub(:find).and_return(mock_comment(:update_attributes => false))
# put :update, :id => "1"
# assigns(:comment).should equal(mock_comment)
# end
#
# it "should re-render the 'edit' template" do
- # Comment.stub!(:find).and_return(mock_comment(:update_attributes => false))
+ # Comment.stub(:find).and_return(mock_comment(:update_attributes => false))
# put :update, :id => "1"
# response.should render_template('edit')
# end
@@ -264,7 +186,7 @@
it "should destroy the requested comment and render [destroy] template" do
@asset = FactoryGirl.create(asset)
@comment = FactoryGirl.create(:comment, :commentable => @asset, :user => current_user)
- Comment.stub!(:new).and_return(@comment)
+ Comment.stub(:new).and_return(@comment)
xhr :delete, :destroy, :id => @comment.id
lambda { Comment.find(@comment) }.should raise_error(ActiveRecord::RecordNotFound)
diff --git a/spec/controllers/emails_controller_spec.rb b/spec/controllers/emails_controller_spec.rb
index b0998b5772..7ee5bd847d 100644
--- a/spec/controllers/emails_controller_spec.rb
+++ b/spec/controllers/emails_controller_spec.rb
@@ -22,7 +22,7 @@
it "should destroy the requested email and render [destroy] template" do
@asset = FactoryGirl.create(asset)
@email = FactoryGirl.create(:email, :mediator => @asset, :user => current_user)
- Email.stub!(:new).and_return(@email)
+ Email.stub(:new).and_return(@email)
xhr :delete, :destroy, :id => @email.id
lambda { Email.find(@email) }.should raise_error(ActiveRecord::RecordNotFound)
diff --git a/spec/controllers/entities/accounts_controller_spec.rb b/spec/controllers/entities/accounts_controller_spec.rb
index 784ad435c3..a74856b3ce 100644
--- a/spec/controllers/entities/accounts_controller_spec.rb
+++ b/spec/controllers/entities/accounts_controller_spec.rb
@@ -96,7 +96,7 @@ def get_data_for_sidebar
describe "with mime type of JSON" do
it "should render all accounts as json" do
- @controller.should_receive(:get_accounts).and_return(accounts = mock("Array of Accounts"))
+ @controller.should_receive(:get_accounts).and_return(accounts = double("Array of Accounts"))
accounts.should_receive(:to_json).and_return("generated JSON")
request.env["HTTP_ACCEPT"] = "application/json"
@@ -107,7 +107,7 @@ def get_data_for_sidebar
describe "with mime type of XML" do
it "should render all accounts as xml" do
- @controller.should_receive(:get_accounts).and_return(accounts = mock("Array of Accounts"))
+ @controller.should_receive(:get_accounts).and_return(accounts = double("Array of Accounts"))
accounts.should_receive(:to_xml).and_return("generated XML")
request.env["HTTP_ACCEPT"] = "application/xml"
@@ -304,7 +304,7 @@ def get_data_for_sidebar
it "should expose a newly created account as @account and render [create] template" do
@account = FactoryGirl.build(:account, :name => "Hello world", :user => current_user)
- Account.stub!(:new).and_return(@account)
+ Account.stub(:new).and_return(@account)
xhr :post, :create, :account => { :name => "Hello world" }
assigns(:account).should == @account
@@ -314,7 +314,7 @@ def get_data_for_sidebar
# Note: [Create Account] is shown only on Accounts index page.
it "should reload accounts to update pagination" do
@account = FactoryGirl.build(:account, :user => current_user)
- Account.stub!(:new).and_return(@account)
+ Account.stub(:new).and_return(@account)
xhr :post, :create, :account => { :name => "Hello" }
assigns[:accounts].should == [ @account ]
@@ -322,7 +322,7 @@ def get_data_for_sidebar
it "should get data to update account sidebar" do
@account = FactoryGirl.build(:account, :name => "Hello", :user => current_user)
- Campaign.stub!(:new).and_return(@account)
+ Campaign.stub(:new).and_return(@account)
xhr :post, :create, :account => { :name => "Hello" }
assigns[:account_category_total].should be_instance_of(HashWithIndifferentAccess)
@@ -330,7 +330,7 @@ def get_data_for_sidebar
it "should add a new comment to the newly created account when specified" do
@account = FactoryGirl.build(:account, :name => "Hello world", :user => current_user)
- Account.stub!(:new).and_return(@account)
+ Account.stub(:new).and_return(@account)
xhr :post, :create, :account => { :name => "Hello world" }, :comment_body => "Awesome comment is awesome"
assigns[:account].comments.map(&:comment).should include("Awesome comment is awesome")
@@ -340,7 +340,7 @@ def get_data_for_sidebar
describe "with invalid params" do
it "should expose a newly created but unsaved account as @account and still render [create] template" do
@account = FactoryGirl.build(:account, :name => nil, :user => nil)
- Account.stub!(:new).and_return(@account)
+ Account.stub(:new).and_return(@account)
xhr :post, :create, :account => {}
assigns(:account).should == @account
@@ -566,18 +566,18 @@ def get_data_for_sidebar
it_should_behave_like("auto complete")
end
- # POST /accounts/redraw AJAX
+ # GET /accounts/redraw AJAX
#----------------------------------------------------------------------------
- describe "responding to POST redraw" do
+ describe "responding to GET redraw" do
it "should save user selected account preference" do
- xhr :post, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
+ xhr :get, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
current_user.preference[:accounts_per_page].should == "42"
current_user.preference[:accounts_index_view].should == "brief"
current_user.preference[:accounts_sort_by].should == "accounts.name ASC"
end
it "should reset current page to 1" do
- xhr :post, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
+ xhr :get, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
session[:accounts_current_page].should == 1
end
@@ -587,7 +587,7 @@ def get_data_for_sidebar
FactoryGirl.create(:account, :name => "B", :user => current_user)
]
- xhr :post, :redraw, :per_page => 1, :sort_by => "name"
+ xhr :get, :redraw, :per_page => 1, :sort_by => "name"
assigns(:accounts).should == [ @accounts.first ]
response.should render_template("accounts/index")
end
diff --git a/spec/controllers/entities/campaigns_controller_spec.rb b/spec/controllers/entities/campaigns_controller_spec.rb
index ca435ad0fb..c28fc5e283 100644
--- a/spec/controllers/entities/campaigns_controller_spec.rb
+++ b/spec/controllers/entities/campaigns_controller_spec.rb
@@ -306,7 +306,7 @@ def get_data_for_sidebar
it "should expose a newly created campaign as @campaign and render [create] template" do
@campaign = FactoryGirl.build(:campaign, :name => "Hello", :user => current_user)
- Campaign.stub!(:new).and_return(@campaign)
+ Campaign.stub(:new).and_return(@campaign)
xhr :post, :create, :campaign => { :name => "Hello" }
assigns(:campaign).should == @campaign
@@ -315,7 +315,7 @@ def get_data_for_sidebar
it "should get data to update campaign sidebar" do
@campaign = FactoryGirl.build(:campaign, :name => "Hello", :user => current_user)
- Campaign.stub!(:new).and_return(@campaign)
+ Campaign.stub(:new).and_return(@campaign)
xhr :post, :create, :campaign => { :name => "Hello" }
assigns[:campaign_status_total].should be_instance_of(HashWithIndifferentAccess)
@@ -323,7 +323,7 @@ def get_data_for_sidebar
it "should reload campaigns to update pagination" do
@campaign = FactoryGirl.build(:campaign, :user => current_user)
- Campaign.stub!(:new).and_return(@campaign)
+ Campaign.stub(:new).and_return(@campaign)
xhr :post, :create, :campaign => { :name => "Hello" }
assigns[:campaigns].should == [ @campaign ]
@@ -331,7 +331,7 @@ def get_data_for_sidebar
it "should add a new comment to the newly created campaign when specified" do
@campaign = FactoryGirl.build(:campaign, :name => "Hello world", :user => current_user)
- Campaign.stub!(:new).and_return(@campaign)
+ Campaign.stub(:new).and_return(@campaign)
xhr :post, :create, :campaign => { :name => "Hello world" }, :comment_body => "Awesome comment is awesome"
@campaign.reload.comments.map(&:comment).should include("Awesome comment is awesome")
@@ -342,7 +342,7 @@ def get_data_for_sidebar
it "should expose a newly created but unsaved campaign as @campaign and still render [create] template" do
@campaign = FactoryGirl.build(:campaign, :id => nil, :name => nil, :user => current_user)
- Campaign.stub!(:new).and_return(@campaign)
+ Campaign.stub(:new).and_return(@campaign)
xhr :post, :create, :campaign => nil
assigns(:campaign).should == @campaign
@@ -605,18 +605,18 @@ def get_data_for_sidebar
it_should_behave_like("auto complete")
end
- # POST /campaigns/redraw AJAX
+ # GET /campaigns/redraw AJAX
#----------------------------------------------------------------------------
- describe "responding to POST redraw" do
+ describe "responding to GET redraw" do
it "should save user selected campaign preference" do
- xhr :post, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
+ xhr :get, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
current_user.preference[:campaigns_per_page].should == "42"
current_user.preference[:campaigns_index_view].should == "brief"
current_user.preference[:campaigns_sort_by].should == "campaigns.name ASC"
end
it "should reset current page to 1" do
- xhr :post, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
+ xhr :get, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
session[:campaigns_current_page].should == 1
end
@@ -626,7 +626,7 @@ def get_data_for_sidebar
FactoryGirl.create(:campaign, :name => "B", :user => current_user)
]
- xhr :post, :redraw, :per_page => 1, :sort_by => "name"
+ xhr :get, :redraw, :per_page => 1, :sort_by => "name"
assigns(:campaigns).should == [ @campaigns.first ]
response.should render_template("campaigns/index")
end
diff --git a/spec/controllers/entities/contacts_controller_spec.rb b/spec/controllers/entities/contacts_controller_spec.rb
index 1a321363f7..1c67a5f69f 100644
--- a/spec/controllers/entities/contacts_controller_spec.rb
+++ b/spec/controllers/entities/contacts_controller_spec.rb
@@ -70,7 +70,7 @@
describe "with mime type of JSON" do
it "should render all contacts as JSON" do
- @controller.should_receive(:get_contacts).and_return(contacts = mock("Array of Contacts"))
+ @controller.should_receive(:get_contacts).and_return(contacts = double("Array of Contacts"))
contacts.should_receive(:to_json).and_return("generated JSON")
request.env["HTTP_ACCEPT"] = "application/json"
@@ -81,7 +81,7 @@
describe "with mime type of XML" do
it "should render all contacts as xml" do
- @controller.should_receive(:get_contacts).and_return(contacts = mock("Array of Contacts"))
+ @controller.should_receive(:get_contacts).and_return(contacts = double("Array of Contacts"))
contacts.should_receive(:to_xml).and_return("generated XML")
request.env["HTTP_ACCEPT"] = "application/xml"
@@ -303,7 +303,7 @@
it "should expose a newly created contact as @contact and render [create] template" do
@contact = FactoryGirl.build(:contact, :first_name => "Billy", :last_name => "Bones")
- Contact.stub!(:new).and_return(@contact)
+ Contact.stub(:new).and_return(@contact)
xhr :post, :create, :contact => { :first_name => "Billy", :last_name => "Bones" }, :account => { :name => "Hello world" }
assigns(:contact).should == @contact
@@ -314,7 +314,7 @@
it "should be able to associate newly created contact with the opportunity" do
@opportunity = FactoryGirl.create(:opportunity, :id => 987);
@contact = FactoryGirl.build(:contact)
- Contact.stub!(:new).and_return(@contact)
+ Contact.stub(:new).and_return(@contact)
xhr :post, :create, :contact => { :first_name => "Billy"}, :account => {}, :opportunity => 987
assigns(:contact).opportunities.should include(@opportunity)
@@ -323,7 +323,7 @@
it "should reload contacts to update pagination if called from contacts index" do
@contact = FactoryGirl.build(:contact, :user => current_user)
- Contact.stub!(:new).and_return(@contact)
+ Contact.stub(:new).and_return(@contact)
request.env["HTTP_REFERER"] = "http://localhost/contacts"
xhr :post, :create, :contact => { :first_name => "Billy", :last_name => "Bones" }, :account => {}
@@ -332,7 +332,7 @@
it "should add a new comment to the newly created contact when specified" do
@contact = FactoryGirl.build(:contact, :user => current_user)
- Contact.stub!(:new).and_return(@contact)
+ Contact.stub(:new).and_return(@contact)
xhr :post, :create, :contact => { :first_name => "Testy", :last_name => "McTest" }, :account => { :name => "Hello world" }, :comment_body => "Awesome comment is awesome"
assigns[:contact].comments.map(&:comment).should include("Awesome comment is awesome")
@@ -343,7 +343,7 @@
before(:each) do
@contact = FactoryGirl.build(:contact, :first_name => nil, :user => current_user, :lead => nil)
- Contact.stub!(:new).and_return(@contact)
+ Contact.stub(:new).and_return(@contact)
end
# Redraw [create] form with selected account.
@@ -648,11 +648,11 @@
it_should_behave_like("auto complete")
end
- # POST /contacts/redraw AJAX
+ # GET /contacts/redraw AJAX
#----------------------------------------------------------------------------
describe "responding to POST redraw" do
it "should save user selected contact preference" do
- xhr :post, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
+ xhr :get, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
current_user.preference[:contacts_per_page].to_i.should == 42
current_user.preference[:contacts_index_view].should == "long"
current_user.preference[:contacts_sort_by].should == "contacts.first_name ASC"
@@ -660,13 +660,13 @@
end
it "should set similar options for Leads" do
- xhr :post, :redraw, :sort_by => "first_name", :naming => "after"
+ xhr :get, :redraw, :sort_by => "first_name", :naming => "after"
current_user.pref[:leads_sort_by].should == "leads.first_name ASC"
current_user.pref[:leads_naming].should == "after"
end
it "should reset current page to 1" do
- xhr :post, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
+ xhr :get, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
session[:contacts_current_page].should == 1
end
@@ -676,7 +676,7 @@
FactoryGirl.create(:contact, :first_name => "Bobby", :user => current_user)
]
- xhr :post, :redraw, :per_page => 1, :sort_by => "first_name"
+ xhr :get, :redraw, :per_page => 1, :sort_by => "first_name"
assigns(:contacts).should == [ @contacts.first ]
response.should render_template("contacts/index")
end
diff --git a/spec/controllers/entities/leads_controller_spec.rb b/spec/controllers/entities/leads_controller_spec.rb
index 0f3f050e1e..4a5f16dcc5 100644
--- a/spec/controllers/entities/leads_controller_spec.rb
+++ b/spec/controllers/entities/leads_controller_spec.rb
@@ -95,7 +95,7 @@
describe "with mime type of JSON" do
it "should render all leads as JSON" do
- @controller.should_receive(:get_leads).and_return(leads = mock("Array of Leads"))
+ @controller.should_receive(:get_leads).and_return(leads = double("Array of Leads"))
leads.should_receive(:to_json).and_return("generated JSON")
request.env["HTTP_ACCEPT"] = "application/json"
@@ -106,7 +106,7 @@
describe "with mime type of XML" do
it "should render all leads as xml" do
- @controller.should_receive(:get_leads).and_return(leads = mock("Array of Leads"))
+ @controller.should_receive(:get_leads).and_return(leads = double("Array of Leads"))
leads.should_receive(:to_xml).and_return("generated XML")
request.env["HTTP_ACCEPT"] = "application/xml"
@@ -210,7 +210,7 @@
it "should expose a new lead as @lead and render [new] template" do
@lead = FactoryGirl.build(:lead, :user => current_user, :campaign => nil)
- Lead.stub!(:new).and_return(@lead)
+ Lead.stub(:new).and_return(@lead)
@campaigns = [ FactoryGirl.create(:campaign, :user => current_user) ]
xhr :get, :new
@@ -322,7 +322,7 @@
it "should expose a newly created lead as @lead and render [create] template" do
@lead = FactoryGirl.build(:lead, :user => current_user, :campaign => nil)
- Lead.stub!(:new).and_return(@lead)
+ Lead.stub(:new).and_return(@lead)
@campaigns = [ FactoryGirl.create(:campaign, :user => current_user) ]
xhr :post, :create, :lead => { :first_name => "Billy", :last_name => "Bones" }
@@ -341,7 +341,7 @@
@campaign.save
@lead = FactoryGirl.build(:lead, :campaign => @campaign, :user => current_user, :access => "Shared")
- Lead.stub!(:new).and_return(@lead)
+ Lead.stub(:new).and_return(@lead)
xhr :post, :create, :lead => { :first_name => "Billy", :last_name => "Bones", :access => "Campaign", :user_ids => %w(7 8) }, :campaign => @campaign.id
assigns(:lead).should == @lead
@@ -353,7 +353,7 @@
it "should get the data to update leads sidebar if called from leads index" do
@lead = FactoryGirl.build(:lead, :user => current_user, :campaign => nil)
- Lead.stub!(:new).and_return(@lead)
+ Lead.stub(:new).and_return(@lead)
request.env["HTTP_REFERER"] = "http://localhost/leads"
xhr :post, :create, :lead => { :first_name => "Billy", :last_name => "Bones" }
@@ -362,7 +362,7 @@
it "should reload leads to update pagination if called from leads index" do
@lead = FactoryGirl.build(:lead, :user => current_user, :campaign => nil)
- Lead.stub!(:new).and_return(@lead)
+ Lead.stub(:new).and_return(@lead)
request.env["HTTP_REFERER"] = "http://localhost/leads"
xhr :post, :create, :lead => { :first_name => "Billy", :last_name => "Bones" }
@@ -377,10 +377,10 @@
xhr :put, :create, :lead => { :first_name => "Billy", :last_name => "Bones"}, :campaign => @campaign.id
assigns[:campaign].should == @campaign
end
-
+
it "should add a new comment to the newly created lead when specified" do
@lead = FactoryGirl.create(:lead)
- Lead.stub!(:new).and_return(@lead)
+ Lead.stub(:new).and_return(@lead)
xhr :post, :create, :lead => { :first_name => "Test", :last_name => "Lead" }, :comment_body => "This is an important lead."
@lead.reload.comments.map(&:comment).should include("This is an important lead.")
end
@@ -390,7 +390,7 @@
it "should expose a newly created but unsaved lead as @lead and still render [create] template" do
@lead = FactoryGirl.build(:lead, :user => current_user, :first_name => nil, :campaign => nil)
- Lead.stub!(:new).and_return(@lead)
+ Lead.stub(:new).and_return(@lead)
@campaigns = [ FactoryGirl.create(:campaign, :user => current_user) ]
xhr :post, :create, :lead => { :first_name => nil }
@@ -730,9 +730,9 @@
@account = FactoryGirl.create(:account, :id => 123, :user => current_user)
@opportunity = FactoryGirl.build(:opportunity, :user => current_user, :campaign => @lead.campaign,
:account => @account)
- Opportunity.stub!(:new).and_return(@opportunity)
+ Opportunity.stub(:new).and_return(@opportunity)
@contact = FactoryGirl.build(:contact, :user => current_user, :lead => @lead)
- Contact.stub!(:new).and_return(@contact)
+ Contact.stub(:new).and_return(@contact)
xhr :put, :promote, :id => 42, :account => { :id => 123 }, :opportunity => { :name => "Hello" }
@lead.reload.status.should == "converted"
@@ -755,11 +755,11 @@
@account = FactoryGirl.build(:account, :user => current_user, :access => "Shared")
@account.permissions << FactoryGirl.create(:permission, :user => he, :asset => @account)
@account.permissions << FactoryGirl.create(:permission, :user => she, :asset => @account)
- @account.stub!(:new).and_return(@account)
+ @account.stub(:new).and_return(@account)
@opportunity = FactoryGirl.build(:opportunity, :user => current_user, :access => "Shared")
@opportunity.permissions << FactoryGirl.create(:permission, :user => he, :asset => @opportunity)
@opportunity.permissions << FactoryGirl.create(:permission, :user => she, :asset => @opportunity)
- @opportunity.stub!(:new).and_return(@opportunity)
+ @opportunity.stub(:new).and_return(@opportunity)
xhr :put, :promote, :id => @lead.id, :access => "Lead", :account => { :name => "Hello", :access => "Lead", :user_id => current_user.id }, :opportunity => { :name => "World", :access => "Lead", :user_id => current_user.id }
@account.access.should == "Shared"
@@ -809,7 +809,7 @@
@lead = FactoryGirl.create(:lead, :id => 42, :user => current_user, :status => "new")
@account = FactoryGirl.create(:account, :id => 123, :user => current_user)
@contact = FactoryGirl.build(:contact, :first_name => nil) # make it fail
- Contact.stub!(:new).and_return(@contact)
+ Contact.stub(:new).and_return(@contact)
xhr :put, :promote, :id => 42, :account => { :id => 123 }
@lead.reload.status.should == "new"
@@ -970,11 +970,11 @@
it_should_behave_like("auto complete")
end
- # POST /leads/redraw AJAX
+ # GET /leads/redraw AJAX
#----------------------------------------------------------------------------
- describe "responding to POST redraw" do
+ describe "responding to GET redraw" do
it "should save user selected lead preference" do
- xhr :post, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
+ xhr :get, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
current_user.preference[:leads_per_page].should == "42"
current_user.preference[:leads_index_view].should == "long"
current_user.preference[:leads_sort_by].should == "leads.first_name ASC"
@@ -982,13 +982,13 @@
end
it "should set similar options for Contacts" do
- xhr :post, :redraw, :sort_by => "first_name", :naming => "after"
+ xhr :get, :redraw, :sort_by => "first_name", :naming => "after"
current_user.pref[:contacts_sort_by].should == "contacts.first_name ASC"
current_user.pref[:contacts_naming].should == "after"
end
it "should reset current page to 1" do
- xhr :post, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
+ xhr :get, :redraw, :per_page => 42, :view => "long", :sort_by => "first_name", :naming => "after"
session[:leads_current_page].should == 1
end
@@ -998,7 +998,7 @@
FactoryGirl.create(:lead, :first_name => "Bobby", :user => current_user)
]
- xhr :post, :redraw, :per_page => 1, :sort_by => "first_name"
+ xhr :get, :redraw, :per_page => 1, :sort_by => "first_name"
assigns(:leads).should == [ @leads.first ]
response.should render_template("leads/index")
end
diff --git a/spec/controllers/entities/opportunities_controller_spec.rb b/spec/controllers/entities/opportunities_controller_spec.rb
index e060d4464e..125a438f22 100644
--- a/spec/controllers/entities/opportunities_controller_spec.rb
+++ b/spec/controllers/entities/opportunities_controller_spec.rb
@@ -99,7 +99,7 @@ def get_data_for_sidebar
describe "with mime type of JSON" do
it "should render all opportunities as JSON" do
- @controller.should_receive(:get_opportunities).and_return(opportunities = mock("Array of Opportunities"))
+ @controller.should_receive(:get_opportunities).and_return(opportunities = double("Array of Opportunities"))
opportunities.should_receive(:to_json).and_return("generated JSON")
request.env["HTTP_ACCEPT"] = "application/json"
@@ -110,7 +110,7 @@ def get_data_for_sidebar
describe "with mime type of JSON" do
it "should render all opportunities as JSON" do
- @controller.should_receive(:get_opportunities).and_return(opportunities = mock("Array of Opportunities"))
+ @controller.should_receive(:get_opportunities).and_return(opportunities = double("Array of Opportunities"))
opportunities.should_receive(:to_json).and_return("generated JSON")
request.env["HTTP_ACCEPT"] = "application/json"
@@ -121,7 +121,7 @@ def get_data_for_sidebar
describe "with mime type of XML" do
it "should render all opportunities as xml" do
- @controller.should_receive(:get_opportunities).and_return(opportunities = mock("Array of Opportunities"))
+ @controller.should_receive(:get_opportunities).and_return(opportunities = double("Array of Opportunities"))
opportunities.should_receive(:to_xml).and_return("generated XML")
request.env["HTTP_ACCEPT"] = "application/xml"
@@ -348,7 +348,7 @@ def get_data_for_sidebar
before do
@opportunity = FactoryGirl.build(:opportunity, :user => current_user)
- Opportunity.stub!(:new).and_return(@opportunity)
+ Opportunity.stub(:new).and_return(@opportunity)
@stage = Setting.unroll(:opportunity_stage)
end
@@ -426,7 +426,7 @@ def get_data_for_sidebar
it "should update related campaign revenue if won" do
@campaign = FactoryGirl.create(:campaign, :revenue => 0)
@opportunity = FactoryGirl.build(:opportunity, :user => current_user, :stage => "won", :amount => 1100, :discount => 100)
- Opportunity.stub!(:new).and_return(@opportunity)
+ Opportunity.stub(:new).and_return(@opportunity)
xhr :post, :create, :opportunity => { :name => "Hello world" }, :campaign => @campaign.id, :account => { :name => "Test Account" }
assigns(:opportunity).should == @opportunity
@@ -436,7 +436,7 @@ def get_data_for_sidebar
it "should add a new comment to the newly created opportunity when specified" do
@opportunity = FactoryGirl.build(:opportunity, :user => current_user)
- Opportunity.stub!(:new).and_return(@opportunity)
+ Opportunity.stub(:new).and_return(@opportunity)
xhr :post, :create, :opportunity => { :name => "Opportunity Knocks" }, :account => { :name => "My Account" }, :comment_body => "Awesome comment is awesome"
@opportunity.reload.comments.map(&:comment).should include("Awesome comment is awesome")
@@ -449,7 +449,7 @@ def get_data_for_sidebar
@account = Account.new(:user => current_user)
@opportunity = FactoryGirl.build(:opportunity, :name => nil, :campaign => nil, :user => current_user,
:account => @account)
- Opportunity.stub!(:new).and_return(@opportunity)
+ Opportunity.stub(:new).and_return(@opportunity)
@stage = Setting.unroll(:opportunity_stage)
@accounts = [ FactoryGirl.create(:account, :user => current_user) ]
@@ -465,7 +465,7 @@ def get_data_for_sidebar
@account = FactoryGirl.create(:account, :id => 42, :user => current_user)
@opportunity = FactoryGirl.build(:opportunity, :name => nil, :campaign => nil, :user => current_user,
:account => @account)
- Opportunity.stub!(:new).and_return(@opportunity)
+ Opportunity.stub(:new).and_return(@opportunity)
@stage = Setting.unroll(:opportunity_stage)
# Expect to redraw [create] form with selected account.
@@ -864,18 +864,18 @@ def get_data_for_sidebar
it_should_behave_like("auto complete")
end
- # POST /opportunities/redraw AJAX
+ # GET /opportunities/redraw AJAX
#----------------------------------------------------------------------------
- describe "responding to POST redraw" do
+ describe "responding to GET redraw" do
it "should save user selected opportunity preference" do
- xhr :post, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
+ xhr :get, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
current_user.preference[:opportunities_per_page].should == "42"
current_user.preference[:opportunities_index_view].should == "brief"
current_user.preference[:opportunities_sort_by].should == "opportunities.name ASC"
end
it "should reset current page to 1" do
- xhr :post, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
+ xhr :get, :redraw, :per_page => 42, :view => "brief", :sort_by => "name"
session[:opportunities_current_page].should == 1
end
@@ -885,7 +885,7 @@ def get_data_for_sidebar
FactoryGirl.create(:opportunity, :name => "B", :user => current_user)
]
- xhr :post, :redraw, :per_page => 1, :sort_by => "name"
+ xhr :get, :redraw, :per_page => 1, :sort_by => "name"
assigns(:opportunities).should == [ @opportunities.first ]
response.should render_template("opportunities/index")
end
diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb
index 222a7ede04..6198159e12 100644
--- a/spec/controllers/home_controller_spec.rb
+++ b/spec/controllers/home_controller_spec.rb
@@ -42,13 +42,13 @@
assigns[:my_tasks].should == [task_1, task_2, task_3, task_4]
end
- it "should not display completed tasks" do
- task_1 = FactoryGirl.create(:task, :user_id => current_user.id, :name => "Your first task", :bucket => "due_asap", :assigned_to => current_user.id)
- task_2 = FactoryGirl.create(:task, :user_id => current_user.id, :name => "Completed task", :bucket => "due_asap", :completed_at => 1.days.ago, :completed_by => current_user.id, :assigned_to => current_user.id)
+ it "should not display completed tasks" do
+ task_1 = FactoryGirl.create(:task, :user_id => current_user.id, :name => "Your first task", :bucket => "due_asap", :assigned_to => current_user.id)
+ task_2 = FactoryGirl.create(:task, :user_id => current_user.id, :name => "Completed task", :bucket => "due_asap", :completed_at => 1.days.ago, :completed_by => current_user.id, :assigned_to => current_user.id)
- get :index
- assigns[:my_tasks].should == [task_1]
- end
+ get :index
+ assigns[:my_tasks].should == [task_1]
+ end
it "should get a list of my opportunities ordered by closes_on" do
opportunity_1 = FactoryGirl.create(:opportunity, :name => "Your first opportunity", :closes_on => 15.days.from_now, :assigned_to => current_user.id, :stage => 'proposal')
@@ -76,13 +76,6 @@
assigns[:my_accounts].should == [account_1, account_4, account_3, account_2]
end
- it "should assign @hello and call hook" do
- require_user
- controller.should_receive(:hook).at_least(:once)
-
- get :index
- assigns[:hello].should == "Hello world"
- end
end
# GET /home/options AJAX
@@ -113,15 +106,15 @@
end
end
- # POST /home/redraw AJAX
+ # GET /home/redraw AJAX
#----------------------------------------------------------------------------
- describe "responding to POST redraw" do
+ describe "responding to GET redraw" do
before(:each) do
require_user
end
it "should save user selected options" do
- xhr :post, :redraw, :asset => "tasks", :user => "Billy Bones", :duration => "two days"
+ xhr :get, :redraw, :asset => "tasks", :user => "Billy Bones", :duration => "two days"
current_user.pref[:activity_asset].should == "tasks"
current_user.pref[:activity_user].should == "Billy Bones"
current_user.pref[:activity_duration].should == "two days"
@@ -153,42 +146,93 @@
session[:hello].should == true
end
end
-
+
describe "activity_user" do
-
+
before(:each) do
- @user = mock(User, :id => 1, :is_a? => true)
- @cur_user = mock(User)
+ @user = double(User, :id => 1, :is_a? => true)
+ @cur_user = double(User)
end
-
+
it "should find a user by email" do
- @cur_user.stub!(:pref).and_return(:activity_user => 'billy@example.com')
+ @cur_user.stub(:pref).and_return(:activity_user => 'billy@example.com')
controller.instance_variable_set(:@current_user, @cur_user)
User.should_receive(:where).with(:email => 'billy@example.com').and_return([@user])
controller.send(:activity_user).should == 1
end
-
+
it "should find a user by first name or last name" do
- @cur_user.stub!(:pref).and_return(:activity_user => 'Billy')
+ @cur_user.stub(:pref).and_return(:activity_user => 'Billy')
controller.instance_variable_set(:@current_user, @cur_user)
- User.should_receive(:where).with("upper(first_name) LIKE upper('%Billy%') OR upper(last_name) LIKE upper('%Billy%')").and_return([@user])
+ User.should_receive(:where).with(:first_name => 'Billy').and_return([@user])
+ User.should_receive(:where).with(:last_name => 'Billy').and_return([@user])
controller.send(:activity_user).should == 1
end
-
+
it "should find a user by first name and last name" do
- @cur_user.stub!(:pref).and_return(:activity_user => 'Billy Elliot')
+ @cur_user.stub(:pref).and_return(:activity_user => 'Billy Elliot')
controller.instance_variable_set(:@current_user, @cur_user)
- User.should_receive(:where).with("(upper(first_name) LIKE upper('%Billy%') AND upper(last_name) LIKE upper('%Elliot%')) OR (upper(first_name) LIKE upper('%Elliot%') AND upper(last_name) LIKE upper('%Billy%'))").and_return([@user])
+ User.should_receive(:where).with(:first_name => 'Billy', :last_name => "Elliot").and_return([@user])
+ User.should_receive(:where).with(:first_name => 'Elliot', :last_name => "Billy").and_return([@user])
controller.send(:activity_user).should == 1
end
-
+
it "should return nil when 'all_users' is specified" do
- @cur_user.stub!(:pref).and_return(:activity_user => 'all_users')
+ @cur_user.stub(:pref).and_return(:activity_user => 'all_users')
controller.instance_variable_set(:@current_user, @cur_user)
User.should_not_receive(:where)
controller.send(:activity_user).should == nil
end
-
+
+ end
+
+ describe "timeline" do
+
+ before(:each) do
+ require_user
+ end
+
+ it "should collapse all comments and emails on a specific contact" do
+ comment = double(Comment)
+ Comment.should_receive(:find).with("1").and_return(comment)
+ comment.should_receive(:update_attribute).with(:state, 'Collapsed')
+ xhr :get, :timeline, :type => "comment", :id => "1", :state => "Collapsed"
+ end
+
+ it "should expand all comments and emails on a specific contact" do
+ comment = double(Comment)
+ Comment.should_receive(:find).with("1").and_return(comment)
+ comment.should_receive(:update_attribute).with(:state, 'Expanded')
+ xhr :get, :timeline, :type => "comment", :id => "1", :state => "Expanded"
+ end
+
+ it "should not do anything when state neither Expanded nor Collapsed" do
+ comment = double(Comment)
+ Comment.should_not_receive(:find).with("1")
+ xhr :get, :timeline, :type => "comment", :id => "1", :state => "Explode"
+ end
+
+ it "should collapse all comments and emails on Contact" do
+ where_stub = double
+ where_stub.should_receive(:update_all).with(:state => "Collapsed")
+ Comment.should_receive(:where).and_return(where_stub)
+ xhr :get, :timeline, :id => "1,2,3,4+", :state => "Collapsed"
+ end
+
+ it "should not allow an arbitary state (sanitizes input)" do
+ where_stub = double
+ where_stub.should_receive(:update_all).with(:state => "Expanded")
+ Comment.should_receive(:where).and_return(where_stub)
+ xhr :get, :timeline, :id => "1,2,3,4+", :state => "Expanded"
+ end
+
+ it "should not update an arbitary model (sanitizes input)" do
+ where_stub = double
+ where_stub.should_receive(:update_all).with(:state => "Expanded")
+ Comment.should_receive(:where).and_return(where_stub)
+ xhr :get, :timeline, :id => "1,2,3,4+", :state => "Expanded"
+ end
+
end
end
diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb
index 598baae625..04939cbcfe 100644
--- a/spec/controllers/passwords_controller_spec.rb
+++ b/spec/controllers/passwords_controller_spec.rb
@@ -3,14 +3,32 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'spec_helper'
describe PasswordsController do
- #Delete this example and add some real ones
- it "should use PasswordsController" do
- controller.should be_an_instance_of(PasswordsController)
+ let(:user) { FactoryGirl.build(:user) }
+
+ describe "update" do
+
+ before(:each) do
+ User.stub(:find_using_perishable_token).and_return(user)
+ end
+
+ it "should accept non-blank passwords" do
+ password = "password"
+ user.should_receive(:update_attributes).and_return(true)
+ put :update, id: 1, user: { password: password, password_confirmation: password }
+ response.should redirect_to( profile_url )
+ end
+
+ it "should not accept blank passwords" do
+ password = " "
+ user.should_not_receive(:update_attributes)
+ put :update, id: 1, user: { password: password, password_confirmation: password }
+ response.should render_template('edit')
+ end
+
end
end
-
diff --git a/spec/controllers/tasks_controller_spec.rb b/spec/controllers/tasks_controller_spec.rb
index 0fecc48158..4229fc5f90 100644
--- a/spec/controllers/tasks_controller_spec.rb
+++ b/spec/controllers/tasks_controller_spec.rb
@@ -9,7 +9,7 @@
def update_sidebar
@task_total = { :key => :value, :pairs => :etc }
- Task.stub!(:totals).and_return(@task_total)
+ Task.stub(:totals).and_return(@task_total)
end
def produce_tasks(user, view)
@@ -120,7 +120,7 @@ def produce_tasks(user, view)
TASK_STATUSES.each do |view|
it "should render the requested task as JSON for #{view} view" do
- Task.stub_chain(:tracked_by, :find).and_return(task = mock("Task"))
+ Task.stub_chain(:tracked_by, :find).and_return(task = double("Task"))
task.should_receive(:to_json).and_return("generated JSON")
request.env["HTTP_ACCEPT"] = "application/json"
@@ -129,7 +129,7 @@ def produce_tasks(user, view)
end
it "should render the requested task as xml for #{view} view" do
- Task.stub_chain(:tracked_by, :find).and_return(task = mock("Task"))
+ Task.stub_chain(:tracked_by, :find).and_return(task = double("Task"))
task.should_receive(:to_xml).and_return("generated XML")
request.env["HTTP_ACCEPT"] = "application/xml"
@@ -147,7 +147,7 @@ def produce_tasks(user, view)
it "should expose a new task as @task and render [new] template" do
account = FactoryGirl.create(:account, :user => current_user)
@task = FactoryGirl.build(:task, :user => current_user, :asset => account)
- Task.stub!(:new).and_return(@task)
+ Task.stub(:new).and_return(@task)
@bucket = Setting.unroll(:task_bucket)[1..-1] << [ "On Specific Date...", :specific_time ]
@category = Setting.unroll(:task_category)
@@ -268,7 +268,7 @@ def produce_tasks(user, view)
it "should expose a newly created task as @task and render [create] template" do
@task = FactoryGirl.build(:task, :user => current_user)
- Task.stub!(:new).and_return(@task)
+ Task.stub(:new).and_return(@task)
xhr :post, :create, :task => { :name => "Hello world" }
assigns(:task).should == @task
@@ -280,7 +280,7 @@ def produce_tasks(user, view)
[ "", "?view=pending", "?view=assigned", "?view=completed" ].each do |view|
it "should update tasks sidebar when [create] is being called from [/tasks#{view}] page" do
@task = FactoryGirl.build(:task, :user => current_user)
- Task.stub!(:new).and_return(@task)
+ Task.stub(:new).and_return(@task)
request.env["HTTP_REFERER"] = "http://localhost/tasks#{view}"
xhr :post, :create, :task => { :name => "Hello world" }
@@ -293,7 +293,7 @@ def produce_tasks(user, view)
it "should expose a newly created but unsaved task as @lead and still render [create] template" do
@task = FactoryGirl.build(:task, :name => nil, :user => current_user)
- Task.stub!(:new).and_return(@task)
+ Task.stub(:new).and_return(@task)
xhr :post, :create, :task => {}
assigns(:task).should == @task
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 55291912a5..c65b75a74d 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -3,7 +3,7 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'spec_helper'
describe UsersController do
@@ -15,11 +15,9 @@
require_user
end
- it "should expose the requested user as @user and render [show] template" do
- @user = FactoryGirl.create(:user)
-
- get :show, :id => @user.id
- assigns[:user].should == @user
+ it "should render [show] template" do
+ get :show, :id => current_user.id
+ assigns[:user].should == current_user
response.should render_template("users/show")
end
@@ -29,16 +27,30 @@
response.should render_template("users/show")
end
+ it "should show user if admin user" do
+ @user = create(:user)
+ require_user(admin: true)
+ get :show, id: @user.id
+ assigns[:user].should == @user
+ response.should render_template("users/show")
+ end
+
+ it "should not show user if not admin user" do
+ @user = create(:user)
+ get :show, id: @user.id
+ response.should redirect_to(root_url)
+ end
+
describe "with mime type of JSON" do
before(:each) do
request.env["HTTP_ACCEPT"] = "application/json"
end
it "should render the requested user as JSON" do
- User.should_receive(:find).and_return(user = mock("User"))
- user.should_receive(:to_json).and_return("generated JSON")
+ User.should_receive(:find).and_return(current_user)
+ current_user.should_receive(:to_json).and_return("generated JSON")
- get :show, :id => 42
+ get :show, :id => current_user.id
response.body.should == "generated JSON"
end
@@ -56,10 +68,10 @@
end
it "should render the requested user as XML" do
- User.should_receive(:find).and_return(user = mock("User"))
- user.should_receive(:to_xml).and_return("generated XML")
+ User.should_receive(:find).and_return(current_user)
+ current_user.should_receive(:to_xml).and_return("generated XML")
- get :show, :id => 42
+ get :show, :id => current_user.id
response.body.should == "generated XML"
end
@@ -79,9 +91,9 @@
describe "if user is allowed to sign up" do
it "should expose a new user as @user and render [new] template" do
- @controller.should_receive(:can_signup?).and_return(true)
+ User.should_receive(:can_signup?).and_return(true)
@user = FactoryGirl.build(:user)
- User.stub!(:new).and_return(@user)
+ User.stub(:new).and_return(@user)
get :new
assigns[:user].should == @user
@@ -91,7 +103,7 @@
describe "if user is not allowed to sign up" do
it "should redirect to login_path" do
- @controller.should_receive(:can_signup?).and_return(false)
+ User.should_receive(:can_signup?).and_return(false)
get :new
response.should redirect_to(login_path)
@@ -102,14 +114,27 @@
# GET /users/1/edit AJAX
#----------------------------------------------------------------------------
describe "responding to GET edit" do
- before(:each) do
+
+ it "should expose current user as @user and render [edit] template" do
require_user
@user = current_user
+ xhr :get, :edit, :id => @user.id
+ assigns[:user].should == current_user
+ response.should render_template("users/edit")
end
- it "should expose current user as @user and render [edit] template" do
+ it "should not allow current user to edit another user" do
+ @user = create(:user)
+ require_user
xhr :get, :edit, :id => @user.id
- assigns[:user].should == current_user
+ expect(response.body).to eql("window.location.reload();")
+ end
+
+ it "should allow admin to edit another user" do
+ require_user(admin: true)
+ @user = create(:user)
+ xhr :get, :edit, :id => @user.id
+ assigns[:user].should == @user
response.should render_template("users/edit")
end
@@ -126,10 +151,11 @@
@email = @username + "@example.com"
@password = "secret"
@user = FactoryGirl.build(:user, :username => @username, :email => @email)
- User.stub!(:new).and_return(@user)
+ User.stub(:new).and_return(@user)
end
it "exposes a newly created user as @user and redirect to profile page" do
+ require_user(admin: true)
post :create, :user => { :username => @username, :email => @email, :password => @password, :password_confirmation => @password }
assigns[:user].should == @user
flash[:notice].should =~ /welcome/
@@ -137,7 +163,7 @@
end
it "should redirect to login page if user signup needs approval" do
- Setting.stub!(:user_signup).and_return(:needs_approval)
+ Setting.stub(:user_signup).and_return(:needs_approval)
post :create, :user => { :username => @username, :email => @email, :password => @password, :password_confirmation => @password }
assigns[:user].should == @user
@@ -148,8 +174,9 @@
describe "with invalid params" do
it "assigns a newly created but unsaved user as @user and renders [new] template" do
+ require_user(admin: true)
@user = FactoryGirl.build(:user, :username => "", :email => "")
- User.stub!(:new).and_return(@user)
+ User.stub(:new).and_return(@user)
post :create, :user => {}
assigns[:user].should == @user
@@ -261,7 +288,7 @@
# -------------------------- Fix later --------------------------------
# it "should return errors if the avatar failed to get uploaded and resized" do
# @image = fixture_file_upload("spec/fixtures/rails.png", "image/png")
-# @user.stub!(:save).and_return(false) # make it fail
+# @user.stub(:save).and_return(false) # make it fail
# xhr :put, :upload_avatar, :id => @user.id, :avatar => { :image => @image }
# @user.avatar.errors.should_not be_empty
@@ -292,8 +319,9 @@
describe "responding to PUT change_password" do
before(:each) do
require_user
- @current_user_session.stub!(:unauthorized_record=).and_return(current_user)
- @current_user_session.stub!(:save).and_return(current_user)
+ User.stub(:find).and_return(current_user)
+ @current_user_session.stub(:unauthorized_record=).and_return(current_user)
+ @current_user_session.stub(:save).and_return(current_user)
@user = current_user
@new_password = "secret?!"
end
diff --git a/spec/features/support/selector_helpers.rb b/spec/features/support/selector_helpers.rb
index ae90efb1ce..1bd5080f0e 100644
--- a/spec/features/support/selector_helpers.rb
+++ b/spec/features/support/selector_helpers.rb
@@ -5,9 +5,9 @@
#------------------------------------------------------------------------------
module SelectorHelpers
def chosen_select(item_text, options)
- field_id = find_field(options[:from])[:id]
- option_value = page.evaluate_script("jQuery(\"##{field_id} option:contains('#{item_text}')\").val()")#page.evaluate_script("$(\"##{field_id} option:contains('#{item_text}')\").val()")
- page.execute_script("jQuery('##{field_id}').val('#{option_value}')")
+ field_id = find_field(options[:from], :visible => false)[:id]
+ option_value = page.evaluate_script("$(\"##{field_id} option:contains('#{item_text}')\").val()")
+ page.execute_script("$('##{field_id}').val('#{option_value}')")
end
def click_filter_tab(filter_name)
@@ -17,13 +17,13 @@ def click_filter_tab(filter_name)
def click_edit_for_task_id(task_id)
within("#task_#{task_id}") do
- page.execute_script "jQuery('#task_#{task_id} a')[0].click()"
+ page.execute_script "$('#task_#{task_id} a')[0].click()"
end
end
def click_delete_for_task_id(task_id)
within("#task_#{task_id}") do
- page.execute_script "jQuery('#task_#{task_id} a')[1].click()"
+ page.execute_script "$('#task_#{task_id} a')[1].click()"
end
end
end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 0808ab6429..2f81f0b32c 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -14,29 +14,29 @@
describe "link_to_emails" do
it "should add Bcc: if dropbox address is set" do
- Setting.stub!(:email_dropbox).and_return({ :address => "drop@example.com" })
+ Setting.stub(:email_dropbox).and_return({ :address => "drop@example.com" })
helper.link_to_email("hello@example.com").should == 'hello@example.com '
end
it "should not add Bcc: if dropbox address is not set" do
- Setting.stub!(:email_dropbox).and_return({ :address => nil })
+ Setting.stub(:email_dropbox).and_return({ :address => nil })
helper.link_to_email("hello@example.com").should == 'hello@example.com '
end
it "should truncate long emails" do
- Setting.stub!(:email_dropbox).and_return({ :address => nil })
+ Setting.stub(:email_dropbox).and_return({ :address => nil })
helper.link_to_email("hello@example.com", 5).should == 'he... '
end
it "should escape HTML entities" do
- Setting.stub!(:email_dropbox).and_return({ :address => 'dr&op@example.com' })
+ Setting.stub(:email_dropbox).and_return({ :address => 'dr&op@example.com' })
helper.link_to_email("hell&o@example.com").should == 'hell&o@example.com '
end
end
it "link_to_discard" do
lead = FactoryGirl.create(:lead)
- controller.request.stub!(:fullpath).and_return("http://www.example.com/leads/#{lead.id}")
+ controller.request.stub(:fullpath).and_return("http://www.example.com/leads/#{lead.id}")
link = helper.link_to_discard(lead)
link.should =~ %r|leads/#{lead.id}/discard|
@@ -45,26 +45,26 @@
describe "shown_on_landing_page?" do
it "should return true for Ajax request made from the asset landing page" do
- controller.request.stub!(:xhr?).and_return(true)
- controller.request.stub!(:referer).and_return("http://www.example.com/leads/123")
+ controller.request.stub(:xhr?).and_return(true)
+ controller.request.stub(:referer).and_return("http://www.example.com/leads/123")
helper.shown_on_landing_page?.should == true
end
it "should return true for regular request to display asset landing page" do
- controller.request.stub!(:xhr?).and_return(false)
- controller.request.stub!(:fullpath).and_return("http://www.example.com/leads/123")
+ controller.request.stub(:xhr?).and_return(false)
+ controller.request.stub(:fullpath).and_return("http://www.example.com/leads/123")
helper.shown_on_landing_page?.should == true
end
it "should return false for Ajax request made from page other than the asset landing page" do
- controller.request.stub!(:xhr?).and_return(true)
- controller.request.stub!(:referer).and_return("http://www.example.com/leads")
+ controller.request.stub(:xhr?).and_return(true)
+ controller.request.stub(:referer).and_return("http://www.example.com/leads")
helper.shown_on_landing_page?.should == false
end
it "should return false for regular request to display page other than asset landing page" do
- controller.request.stub!(:xhr?).and_return(false)
- controller.request.stub!(:fullpath).and_return("http://www.example.com/leads")
+ controller.request.stub(:xhr?).and_return(false)
+ controller.request.stub(:fullpath).and_return("http://www.example.com/leads")
helper.shown_on_landing_page?.should == false
end
end
@@ -73,8 +73,8 @@
before(:each) do
@user = mock_model(User)
- helper.stub!(:current_user).and_return(@user)
- controller.stub!(:params).and_return({'action' => 'show', 'controller' => 'contacts'})
+ helper.stub(:current_user).and_return(@user)
+ controller.stub(:params).and_return({'action' => 'show', 'controller' => 'contacts'})
end
it "should return the contact 'show' outline stored in the user preferences" do
diff --git a/spec/lib/fields_spec.rb b/spec/lib/fields_spec.rb
index 7477b26666..3bd56e5d37 100644
--- a/spec/lib/fields_spec.rb
+++ b/spec/lib/fields_spec.rb
@@ -21,82 +21,82 @@ class Bar
it do
Foo.new.should respond_to(:field_groups)
end
-
+
it do
Foo.should respond_to(:serialize_custom_fields!)
end
-
+
it do
Foo.should respond_to(:fields)
end
-
+
it "calling has_fields should invoke serialize_custom_fields!" do
Bar.should_receive(:serialize_custom_fields!)
Bar.has_fields
end
-
+
describe "field_groups" do
-
+
it "should call FieldGroup" do
ActiveRecord::Base.connection.should_receive(:table_exists?).with('field_groups').and_return(true)
- dummy_scope = mock
+ dummy_scope = double
dummy_scope.should_receive(:order).with(:position)
FieldGroup.should_receive(:where).and_return(dummy_scope)
Foo.new.field_groups
end
-
+
it "should not call FieldGroup if table doesn't exist (migrations not yet run)" do
ActiveRecord::Base.connection.should_receive(:table_exists?).with('field_groups').and_return(false)
Foo.new.field_groups.should == []
end
-
+
end
-
+
describe "fields" do
-
+
before(:each) do
- @f1 = mock(Field)
- @f2 = mock(Field)
- @f3 = mock(Field)
- @field_groups = [mock(FieldGroup, :fields => [@f1, @f2]), mock(FieldGroup, :fields => [@f3])]
+ @f1 = double(Field)
+ @f2 = double(Field)
+ @f3 = double(Field)
+ @field_groups = [double(FieldGroup, :fields => [@f1, @f2]), double(FieldGroup, :fields => [@f3])]
end
-
+
it "should convert field_groups into a flattened list of fields" do
Foo.should_receive(:field_groups).and_return(@field_groups)
Foo.fields.should == [@f1, @f2, @f3]
end
-
+
end
-
+
describe "serialize_custom_fields!" do
-
+
before(:each) do
- @f1 = mock(Field, :as => 'check_boxes', :name => 'field1')
- @f2 = mock(Field, :as => 'date', :name => 'field2')
+ @f1 = double(Field, :as => 'check_boxes', :name => 'field1')
+ @f2 = double(Field, :as => 'date', :name => 'field2')
end
-
+
it "should serialize checkbox fields as Array" do
Foo.stub(:serialized_attributes).and_return( {:field1 => @f1, :field2 => @f2} )
Foo.should_receive(:fields).and_return([@f1, @f2])
Foo.should_receive(:serialize).with(:field1, Array)
Foo.serialize_custom_fields!
end
-
+
end
-
+
it "should validate custom fields" do
foo = Foo.new
foo.should_receive(:custom_fields_validator)
foo.should be_valid
end
-
+
describe "custom_fields_validator" do
-
+
before(:each) do
- @f1 = mock(Field)
- @field_groups = [ mock(FieldGroup, :fields => [@f1]) ]
+ @f1 = double(Field)
+ @field_groups = [ double(FieldGroup, :fields => [@f1]) ]
end
-
+
it "should call custom_validator on each custom field" do
foo = Foo.new
@f1.should_receive(:custom_validator).with(foo)
@@ -105,5 +105,5 @@ class Bar
end
end
-
+
end
diff --git a/spec/lib/mail_processor/base_spec.rb b/spec/lib/mail_processor/base_spec.rb
index 2933e42307..1c5aa56d17 100644
--- a/spec/lib/mail_processor/base_spec.rb
+++ b/spec/lib/mail_processor/base_spec.rb
@@ -67,7 +67,7 @@
describe "Discarding a message" do
before(:each) do
mock_connect
- @uid = mock
+ @uid = double
@crawler.send(:connect!)
end
@@ -90,7 +90,7 @@
describe "Archiving a message" do
before(:each) do
mock_connect
- @uid = mock
+ @uid = double
@crawler.send(:connect!)
end
@@ -112,16 +112,16 @@
#------------------------------------------------------------------------------
describe "Validating email" do
before(:each) do
- @email = mock
+ @email = double
end
it "should be valid email if its contents type is text/plain" do
- @email.stub!(:content_type).and_return("text/plain")
+ @email.stub(:content_type).and_return("text/plain")
@crawler.send(:is_valid?, @email).should == true
end
it "should be invalid email if its contents type is not text/plain" do
- @email.stub!(:content_type).and_return("text/html")
+ @email.stub(:content_type).and_return("text/html")
@crawler.send(:is_valid?, @email).should == false
end
end
@@ -130,8 +130,8 @@
describe "Finding email sender among users" do
before(:each) do
@from = [ "Aaron@Example.Com", "Ben@Example.com" ]
- @email = mock
- @email.stub!(:from).and_return(@from)
+ @email = double
+ @email.stub(:from).and_return(@from)
end
it "should find non-suspended user that matches From: field" do
diff --git a/spec/lib/mail_processor/dropbox_spec.rb b/spec/lib/mail_processor/dropbox_spec.rb
index 646742cec3..85206fea64 100644
--- a/spec/lib/mail_processor/dropbox_spec.rb
+++ b/spec/lib/mail_processor/dropbox_spec.rb
@@ -288,17 +288,17 @@
describe "'access'" do
it "should be 'Private' if default setting is 'Private'" do
- Setting.stub!(:default_access).and_return('Private')
+ Setting.stub(:default_access).and_return('Private')
@crawler.send(:default_access).should == "Private"
end
it "should be 'Public' if default setting is 'Public'" do
- Setting.stub!(:default_access).and_return('Public')
+ Setting.stub(:default_access).and_return('Public')
@crawler.send(:default_access).should == "Public"
end
it "should be 'Private' if default setting is 'Shared'" do
- Setting.stub!(:default_access).and_return('Shared')
+ Setting.stub(:default_access).and_return('Shared')
@crawler.send(:default_access).should == "Private"
end
diff --git a/spec/lib/permissions_spec.rb b/spec/lib/permissions_spec.rb
index b91d2bd839..e80a03645d 100644
--- a/spec/lib/permissions_spec.rb
+++ b/spec/lib/permissions_spec.rb
@@ -13,7 +13,7 @@
string :access
end
end
-
+
describe "initialization" do
it "should add 'has_many permissions' to the model" do
entity = UserWithPermission.new
@@ -28,24 +28,18 @@
before(:each) do
@entity = UserWithPermission.create(:access => "Shared")
end
-
+
it "should assign permissions to the object" do
@entity.permissions.size.should == 0
@entity.update_attribute(:user_ids, ['1','2','3'])
@entity.permissions.find_all_by_user_id([1,2,3]).size.should == 3
end
-
- it "should assign permissions with the 'chosen' select box format" do
- @entity.permissions.size.should == 0
- @entity.update_attribute(:user_ids, ['', '1,2,3'])
- @entity.permissions.find_all_by_user_id([1,2,3]).size.should == 3
- end
-
+
it "should handle [] permissions" do
@entity.update_attribute(:user_ids, [])
@entity.permissions.size.should == 0
end
-
+
it "should replace existing permissions" do
@entity.permissions << FactoryGirl.create(:permission, :user_id => 1, :asset => @entity)
@entity.permissions << FactoryGirl.create(:permission, :user_id => 2, :asset => @entity)
@@ -55,9 +49,9 @@
@entity.permissions.find_all_by_user_id([2]).size.should == 1
@entity.permissions.find_all_by_user_id([3]).size.should == 1
end
-
+
end
-
+
describe "group_ids" do
before(:each) do
@entity = UserWithPermission.create(:access => "Shared")
@@ -67,18 +61,12 @@
@entity.update_attribute(:group_ids, ['1','2','3'])
@entity.permissions.find_all_by_group_id([1,2,3]).size.should == 3
end
-
- it "should assign permissions with the 'chosen' select box format" do
- @entity.permissions.size.should == 0
- @entity.update_attribute(:group_ids, ['', '1,2,3'])
- @entity.permissions.find_all_by_group_id([1,2,3]).size.should == 3
- end
-
+
it "should handle [] permissions" do
@entity.update_attribute(:group_ids, [])
@entity.permissions.size.should == 0
end
-
+
it "should replace existing permissions" do
@entity.permissions << FactoryGirl.build(:permission, :group_id => 1, :user_id => nil, :asset => @entity)
@entity.permissions << FactoryGirl.build(:permission, :group_id => 2, :user_id => nil, :asset => @entity)
@@ -124,7 +112,7 @@
entity.save_with_permissions
end
end
-
+
describe "update_with_permissions" do
it "should raise deprecation warning and call update_attributes" do
entity = UserWithPermission.new
@@ -145,5 +133,5 @@
entity.save_with_model_permissions(model)
end
end
-
+
end
diff --git a/spec/lib/secret_token_generator_spec.rb b/spec/lib/secret_token_generator_spec.rb
new file mode 100644
index 0000000000..a90ecc0c6e
--- /dev/null
+++ b/spec/lib/secret_token_generator_spec.rb
@@ -0,0 +1,79 @@
+# Copyright (c) 2008-2014 Michael Dvorkin and contributors.
+#
+# Fat Free CRM is freely distributable under the terms of MIT license.
+# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
+#------------------------------------------------------------------------------
+
+require 'spec_helper'
+require 'fat_free_crm/secret_token_generator'
+
+describe FatFreeCRM::SecretTokenGenerator do
+
+ let(:token) { 'e5a4b315c062dec4ecb40dabcde84fd6c067cb016a813702d2f4299ad16255c88ed1020bd47fb527e8e5f7052b04be1fbb8e63c043b8fb36f88d3c7d79a68681' }
+
+ describe "setup!" do
+
+ it "should not generate a new token if one exists" do
+ FatFreeCRM::SecretTokenGenerator.stub(:token_exists?).and_return(true)
+ FatFreeCRM::SecretTokenGenerator.should_not_receive(:new_token!)
+ FatFreeCRM::SecretTokenGenerator.setup!
+ end
+
+ it "should generate a token if none exists" do
+ FatFreeCRM::SecretTokenGenerator.stub(:token_exists?).and_return(false)
+ FatFreeCRM::SecretTokenGenerator.should_receive(:new_token!)
+ FatFreeCRM::SecretTokenGenerator.setup!
+ end
+
+ it "should generate a random token if not persisted" do
+ FatFreeCRM::SecretTokenGenerator.stub(:token_exists?).and_return(false)
+ FatFreeCRM::SecretTokenGenerator.stub(:new_token)
+ FatFreeCRM::SecretTokenGenerator.should_receive(:generate_token).exactly(:twice)
+ FatFreeCRM::SecretTokenGenerator.setup!
+ end
+
+ end
+
+ describe "token_exists?" do
+
+ it "should be true" do
+ Setting.stub(:secret_token).and_return(token)
+ FatFreeCRM::SecretTokenGenerator.send(:token_exists?).should eql(true)
+ end
+
+ it "should be false" do
+ Setting.stub(:secret_token).and_return(nil)
+ FatFreeCRM::SecretTokenGenerator.send(:token_exists?).should eql(false)
+ end
+
+ end
+
+ describe "token" do
+
+ it "should delegate to Setting" do
+ Setting.should_receive(:secret_token).and_return(token)
+ FatFreeCRM::SecretTokenGenerator.send(:token).should eql(token)
+ end
+
+ end
+
+ describe "new_token!" do
+
+ it "should generate and set a new token" do
+ FatFreeCRM::SecretTokenGenerator.should_receive(:generate_token).and_return(token)
+ Setting.should_receive(:secret_token=).with(token)
+ FatFreeCRM::SecretTokenGenerator.send(:new_token!)
+ end
+
+ end
+
+ describe "generate_token!" do
+
+ it "should generate a random token" do
+ SecureRandom.should_receive(:hex).with(64).and_return(token)
+ FatFreeCRM::SecretTokenGenerator.send(:generate_token)
+ end
+
+ end
+
+end
diff --git a/spec/lib/view_factory_spec.rb b/spec/lib/view_factory_spec.rb
index d0787ec9bb..8c8285d3f9 100644
--- a/spec/lib/view_factory_spec.rb
+++ b/spec/lib/view_factory_spec.rb
@@ -11,13 +11,13 @@
before(:each) do
FatFreeCRM::ViewFactory.send(:class_variable_set, '@@views', [])
end
-
+
describe "initialization" do
-
+
before(:each) do
- @view_params = {:name => 'brief', :title => 'Brief View', :icon => 'brief.png', :controllers => ['contacts'], :actions => ['show', 'index']}
+ @view_params = {:name => 'brief', :title => 'Brief View', :icon => 'fa-bars', :controllers => ['contacts'], :actions => ['show', 'index']}
end
-
+
it "should initialize with required parameters" do
view = FatFreeCRM::ViewFactory.new @view_params
view.name.should == 'brief'
@@ -26,48 +26,48 @@
view.actions.should include('show')
view.actions.should include('index')
end
-
+
it "should register view with ViewFactory" do
FatFreeCRM::ViewFactory.send(:class_variable_get, '@@views').size.should == 0
FatFreeCRM::ViewFactory.new @view_params
FatFreeCRM::ViewFactory.send(:class_variable_get, '@@views').size.should == 1
end
-
+
it "should not register the same view twice" do
FatFreeCRM::ViewFactory.new @view_params
FatFreeCRM::ViewFactory.new @view_params
views = FatFreeCRM::ViewFactory.send(:class_variable_get, '@@views')
views.size.should == 1
end
-
+
end
describe "views_for" do
-
+
before(:each) do
@v1 = FatFreeCRM::ViewFactory.new :name => 'brief', :title => 'Brief View', :controllers => ['contacts'], :actions => ['show', 'index']
@v2 = FatFreeCRM::ViewFactory.new :name => 'long', :title => 'Long View', :controllers => ['contacts'], :actions => ['show']
@v3 = FatFreeCRM::ViewFactory.new :name => 'full', :title => 'Full View', :controllers => ['accounts'], :actions => ['show']
end
-
+
it "should return 'brief' view for ContactsController#index" do
FatFreeCRM::ViewFactory.views_for(:controller => 'contacts', :action => 'index').should == [@v1]
end
-
+
it "should return 'brief' and 'long' view for ContactsController#show" do
views = FatFreeCRM::ViewFactory.views_for(:controller => 'contacts', :action => 'show')
views.should include(@v1)
views.should include(@v2)
end
-
+
it "should return 'full' view for AccountsController#show" do
FatFreeCRM::ViewFactory.views_for(:controller => 'accounts', :action => 'show').should == [@v3]
end
-
+
it "should return no views for TasksController#show" do
FatFreeCRM::ViewFactory.views_for(:controller => 'tasks', :action => 'show').should == []
end
-
+
end
-
+
end
diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb
index 39e84d19e5..0e2afaac4a 100644
--- a/spec/mailers/user_mailer_spec.rb
+++ b/spec/mailers/user_mailer_spec.rb
@@ -6,6 +6,7 @@
require 'spec_helper'
describe UserMailer do
+
describe "password_reset_instructions" do
let(:user) { FactoryGirl.create(:user, :email => "forgot_my_password@example.com") }
let(:mail) { UserMailer.password_reset_instructions(user) }
@@ -41,7 +42,7 @@
let(:mail) { UserMailer.assigned_entity_notification(account, assigner) }
it "sets fatfree as the sender" do
- mail.from.should eql(["notifications@fatfreecrm.com"])
+ mail.from.should eql(["noreply@fatfreecrm.com"])
end
it "sets user 'assignee@example.com' as recipient" do
@@ -66,7 +67,7 @@
let(:mail) { UserMailer.assigned_entity_notification(contact, assigner) }
it "sets fatfree as the sender" do
- mail.from.should eql(["notifications@fatfreecrm.com"])
+ mail.from.should eql(["noreply@fatfreecrm.com"])
end
it "sets user 'assignee@example.com' as recipient" do
@@ -91,7 +92,7 @@
let(:mail) { UserMailer.assigned_entity_notification(lead, assigner) }
it "sets fatfree as the sender" do
- mail.from.should eql(["notifications@fatfreecrm.com"])
+ mail.from.should eql(["noreply@fatfreecrm.com"])
end
it "sets user 'assignee@example.com' as recipient" do
@@ -116,7 +117,7 @@
let(:mail) { UserMailer.assigned_entity_notification(opportunity, assigner) }
it "sets fatfree as the sender" do
- mail.from.should eql(["notifications@fatfreecrm.com"])
+ mail.from.should eql(["noreply@fatfreecrm.com"])
end
it "sets user 'assignee@example.com' as recipient" do
diff --git a/spec/models/entities/opportunity_spec.rb b/spec/models/entities/opportunity_spec.rb
index dbc80c7314..62f4179c1f 100644
--- a/spec/models/entities/opportunity_spec.rb
+++ b/spec/models/entities/opportunity_spec.rb
@@ -37,7 +37,7 @@
it "should be possible to create opportunity with the same name" do
first = FactoryGirl.create(:opportunity, :name => "Hello", :user => current_user)
- lambda { FactoryGirl.create(:opportunity, :name => "Hello", :user => current_user) }.should_not raise_error(ActiveRecord::RecordInvalid)
+ expect { FactoryGirl.create(:opportunity, :name => "Hello", :user => current_user) }.to_not raise_error()
end
it "have a default stage" do
diff --git a/spec/models/fields/custom_field_date_pair_spec.rb b/spec/models/fields/custom_field_date_pair_spec.rb
index 2b52e14cde..306df37ab7 100644
--- a/spec/models/fields/custom_field_date_pair_spec.rb
+++ b/spec/models/fields/custom_field_date_pair_spec.rb
@@ -12,28 +12,28 @@
before(:each) do
@from = CustomFieldDatePair.new(:name => 'cf_event_from')
@to = CustomFieldDatePair.new(:name => 'cf_event_to')
- @from.stub!(:paired_with).and_return(@to)
+ @from.stub(:paired_with).and_return(@to)
@today = Date.today
@today_str = @today.strftime(I18n.t("date.formats.mmddyy"))
end
it "should be from..." do
- foo = mock(:cf_event_from => @today, :cf_event_to => nil)
+ foo = double(:cf_event_from => @today, :cf_event_to => nil)
@from.render_value(foo).should == "From #{@today_str}"
end
it "should be until..." do
- foo = mock(:cf_event_from => nil, :cf_event_to => @today)
+ foo = double(:cf_event_from => nil, :cf_event_to => @today)
@from.render_value(foo).should == "Until #{@today_str}"
end
it "should be from ... to" do
- foo = mock(:cf_event_from => @today, :cf_event_to => @today)
+ foo = double(:cf_event_from => @today, :cf_event_to => @today)
@from.render_value(foo).should == "From #{@today_str} to #{@today_str}"
end
it "should be empty string" do
- foo = mock(:cf_event_from => nil, :cf_event_to => nil)
+ foo = double(:cf_event_from => nil, :cf_event_to => nil)
@from.render_value(foo).should == ""
end
@@ -44,38 +44,38 @@
before(:each) do
@from = CustomFieldDatePair.new(:name => 'cf_event_from')
@to = CustomFieldDatePair.new(:name => 'cf_event_to', :pair_id => 1)
- CustomFieldPair.stub!(:find).and_return(@from)
+ CustomFieldPair.stub(:find).and_return(@from)
@today = Date.today
@today_str = @today.strftime(I18n.t("date.formats.mmddyy"))
end
it "when from is nil it should be valid" do
- foo = mock(:cf_event_from => nil, :cf_event_to => @today)
+ foo = double(:cf_event_from => nil, :cf_event_to => @today)
foo.should_not_receive(:errors)
@to.custom_validator(foo)
end
it "when to is nil it should be valid" do
- foo = mock(:cf_event_from => @today, :cf_event_to => nil)
+ foo = double(:cf_event_from => @today, :cf_event_to => nil)
foo.should_not_receive(:errors)
@to.custom_validator(foo)
end
it "when from <= to it should be valid" do
- foo = mock(:cf_event_from => @today, :cf_event_to => @today)
+ foo = double(:cf_event_from => @today, :cf_event_to => @today)
foo.should_not_receive(:errors)
@to.custom_validator(foo)
end
it "when from > to it should not be valid" do
- foo = mock(:cf_event_from => @today, :cf_event_to => @today - 1.day)
- err = mock(:errors); err.stub(:add)
+ foo = double(:cf_event_from => @today, :cf_event_to => @today - 1.day)
+ err = double(:errors); err.stub(:add)
foo.should_receive(:errors).and_return(err)
@to.custom_validator(foo)
end
it "should ignore validation when called on from" do
- foo = mock(:cf_event_from => @today, :cf_event_to => @today - 1.day)
+ foo = double(:cf_event_from => @today, :cf_event_to => @today - 1.day)
foo.should_not_receive(:errors)
CustomFieldPair.should_not_receive(:find)
@from.custom_validator(foo)
@@ -83,8 +83,8 @@
it "should call custom field validation on super class" do
from = CustomFieldDatePair.new(:name => 'cf_event_from', :required => true)
- foo = mock(:cf_event_from => nil)
- err = mock(:errors); err.stub(:add)
+ foo = double(:cf_event_from => nil)
+ err = double(:errors); err.stub(:add)
foo.should_receive(:errors).and_return(err)
from.custom_validator(foo)
end
diff --git a/spec/models/fields/custom_field_pair_spec.rb b/spec/models/fields/custom_field_pair_spec.rb
index 0b6c03dd42..48fa54857c 100644
--- a/spec/models/fields/custom_field_pair_spec.rb
+++ b/spec/models/fields/custom_field_pair_spec.rb
@@ -13,31 +13,31 @@ class CustomFieldFooPair
it "should respond to pair" do
CustomFieldPair.new.should respond_to(:pair)
end
-
+
describe "create_pair" do
-
+
before(:each) do
@field = {'as' => 'foopair', 'field_group_id' => 1, 'label' => 'Event'}
@pair1 = {'name' => 'pair1'}
@pair2 = {'name' => 'pair2'}
@params = { 'field' => @field, 'pair' => {'0' => @pair1, '1' => @pair2} }
end
-
+
it "should create the pair" do
params1 = @field.merge(@pair1)
- foo1 = mock(:id => 3, :required => true, :disabled => 'false')
+ foo1 = double(:id => 3, :required => true, :disabled => 'false')
CustomFieldFooPair.should_receive(:create).with( params1 ).and_return(foo1)
params2 = @field.merge(@pair2).merge('pair_id' => 3, 'required' => true, 'disabled' => 'false')
- foo2 = mock(:id => 5)
+ foo2 = double(:id => 5)
CustomFieldFooPair.should_receive(:create).with( params2 ).and_return(foo2)
CustomFieldPair.create_pair(@params).should == [foo1, foo2]
end
-
+
end
describe "update_pair" do
-
+
before(:each) do
@field = {'as' => 'foopair', 'field_group_id' => 1, 'label' => 'Event'}
@pair1 = {'name' => 'pair1'}
@@ -46,9 +46,9 @@ class CustomFieldFooPair
end
it "should update the pair" do
- foo1 = mock(:required => true, :disabled => 'false')
+ foo1 = double(:required => true, :disabled => 'false')
foo1.should_receive(:update_attributes).with( @field.merge(@pair1) )
- foo2 = mock
+ foo2 = double
foo2.should_receive(:update_attributes).with( @field.merge(@pair2).merge('required' => true, 'disabled' => 'false') )
foo1.should_receive(:paired_with).and_return(foo2)
CustomFieldPair.should_receive(:find).with('3').and_return(foo1)
@@ -57,19 +57,19 @@ class CustomFieldFooPair
end
end
-
+
describe "paired_with" do
-
+
before(:each) do
@field1 = CustomFieldDatePair.new(:name => 'cf_event_from')
@field2 = CustomFieldDatePair.new(:name => 'cf_event_to')
end
-
+
it "should return the 2nd field" do
@field1.should_receive(:pair).and_return(@field2)
@field1.paired_with.should == @field2
end
-
+
it "should return the 1st field" do
@field2.should_receive(:pair).and_return(nil)
@field2.should_receive(:id).and_return(1)
diff --git a/spec/models/fields/custom_field_spec.rb b/spec/models/fields/custom_field_spec.rb
index 8a13eecf18..61792bcbd7 100644
--- a/spec/models/fields/custom_field_spec.rb
+++ b/spec/models/fields/custom_field_spec.rb
@@ -49,7 +49,7 @@
columns = []
%w(cf_test_field cf_test_field_2 cf_test_field_3 cf_test_field_4).each do |field|
c.send(:generate_column_name).should == field
- c.stub!(:klass_column_names).and_return( columns << field )
+ c.stub(:klass_column_names).and_return( columns << field )
end
end
@@ -112,16 +112,16 @@
it "should have errors if custom field is required" do
event = CustomField.new(:name => 'cf_event', :required => true)
- foo = mock(:cf_event => nil)
- err = mock(:errors); err.stub(:add)
+ foo = double(:cf_event => nil)
+ err = double(:errors); err.stub(:add)
foo.should_receive(:errors).and_return(err)
event.custom_validator(foo)
end
it "should have errors if custom field is longer than maxlength" do
event = CustomField.new(:name => 'cf_event', :maxlength => 5)
- foo = mock(:cf_event => "This is too long")
- err = mock(:errors); err.stub(:add)
+ foo = double(:cf_event => "This is too long")
+ err = double(:errors); err.stub(:add)
foo.should_receive(:errors).and_return(err)
event.custom_validator(foo)
end
diff --git a/spec/models/fields/field_spec.rb b/spec/models/fields/field_spec.rb
index c8e0ac8846..6c7e8d2d7f 100644
--- a/spec/models/fields/field_spec.rb
+++ b/spec/models/fields/field_spec.rb
@@ -52,7 +52,7 @@
:label => "Availability",
:name => "availability"
)
- object = mock('Object')
+ object = double('Object')
# as | value | expected
[["check_boxes", [1, 2, 3], "1, 2 3"],
@@ -60,7 +60,7 @@
["checkbox", 1, "yes"],
["date", DateTime.new(2011,4,19), DateTime.new(2011,4,19).strftime(I18n.t("date.formats.mmddyy")) ]].each do |as, value, expected|
field.as = as
- object.stub!(field.name).and_return(value)
+ object.stub(field.name).and_return(value)
field.render_value(object).should == expected
end
end
diff --git a/spec/models/observers/entity_observer_spec.rb b/spec/models/observers/entity_observer_spec.rb
index 8b7783cbd8..b6272103fe 100644
--- a/spec/models/observers/entity_observer_spec.rb
+++ b/spec/models/observers/entity_observer_spec.rb
@@ -6,16 +6,18 @@
require 'spec_helper'
describe EntityObserver do
+
+ before do
+ Setting.stub(:host).and_return('http://www.example.com')
+ PaperTrail.stub(:whodunnit).and_return(assigner)
+ end
+
[:account, :contact, :lead, :opportunity].each do |entity_type|
describe "on creation of #{entity_type}" do
let(:assignee) { FactoryGirl.create(:user) }
let(:assigner) { FactoryGirl.create(:user) }
let!(:entity) { FactoryGirl.build(entity_type, :user => assigner, :assignee => assignee) }
- let(:mail) { mock('mail', :deliver => true) }
-
- before :each do
- PaperTrail.stub(:whodunnit).and_return(assigner)
- end
+ let(:mail) { double('mail', :deliver => true) }
after :each do
entity.save
@@ -34,17 +36,19 @@
entity.assignee = entity.user = assigner
UserMailer.should_not_receive(:assigned_entity_notification)
end
+
+ it "does not notify me if Setting.host has not been set" do
+ Setting.stub(:host).and_return('')
+ UserMailer.should_not_receive(:assigned_entity_notification)
+ end
+
end
describe "on update of #{entity_type}" do
let(:assignee) { FactoryGirl.create(:user) }
let(:assigner) { FactoryGirl.create(:user) }
let!(:entity) { FactoryGirl.create(entity_type, :user => FactoryGirl.create(:user)) }
- let(:mail) { mock('mail', :deliver => true) }
-
- before :each do
- PaperTrail.stub(:whodunnit).and_return(assigner)
- end
+ let(:mail) { double('mail', :deliver => true) }
it "notifies the new owner if the entity is re-assigned" do
UserMailer.should_receive(:assigned_entity_notification).with(entity, assigner).and_return(mail)
@@ -66,5 +70,6 @@
entity.update_attributes(:assignee => assigner)
end
end
+
end
end
diff --git a/spec/models/users/abilities/user_ability_spec.rb b/spec/models/users/abilities/user_ability_spec.rb
new file mode 100644
index 0000000000..e4f55debee
--- /dev/null
+++ b/spec/models/users/abilities/user_ability_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+require 'cancan/matchers'
+
+def all_actions
+ [:index, :show, :create, :update, :destroy, :manage]
+end
+
+describe "User abilities" do
+
+ subject(:ability) { Ability.new(user) }
+ let(:subject_user) { create :user }
+
+ context "when site manager, I" do
+ let(:user) { create :user, admin: true}
+ all_actions.each do |do_action|
+ it{ should be_able_to(do_action, subject_user) }
+ end
+ end
+
+ context "when myself, I" do
+ let(:user) { create :user }
+ let(:subject_user) { user }
+ all_actions.each do |do_action|
+ it{ should be_able_to(do_action, subject_user) }
+ end
+ end
+
+ context "when another user, I" do
+ let(:user) { create :user }
+ let(:can) { [] }
+ let(:cannot) { [:show, :create, :update, :index, :destroy, :manage] }
+ it{ can.each do |do_action|
+ should be_able_to(do_action, subject_user)
+ end}
+ it{ cannot.each do |do_action|
+ should_not be_able_to(do_action, subject_user)
+ end}
+ end
+
+ context "when anonymous user, I" do
+ let(:user) { nil }
+ let(:can) { [] }
+ let(:cannot) { [:show, :create, :update, :index, :destroy, :manage] }
+ it{ can.each do |do_action|
+ should be_able_to(do_action, subject_user)
+ end}
+ it{ cannot.each do |do_action|
+ should_not be_able_to(do_action, subject_user)
+ end}
+
+ it "and signup enabled" do
+ User.stub(:can_signup?).and_return(true)
+ should be_able_to(:create, User)
+ end
+
+ end
+
+end
diff --git a/spec/models/users/user_spec.rb b/spec/models/users/user_spec.rb
index 79007c20a2..2dd6149f27 100644
--- a/spec/models/users/user_spec.rb
+++ b/spec/models/users/user_spec.rb
@@ -60,14 +60,14 @@
it "should not destroy the user if she owns #{asset}" do
FactoryGirl.create(asset, :user => @user)
@user.destroy
- lambda { User.find(@user) }.should_not raise_error(ActiveRecord::RecordNotFound)
+ expect { User.find(@user) }.to_not raise_error()
@user.destroyed?.should == false
end
it "should not destroy the user if she has #{asset} assigned" do
FactoryGirl.create(asset, :assignee => @user)
@user.destroy
- lambda { User.find(@user) }.should_not raise_error(ActiveRecord::RecordNotFound)
+ expect { User.find(@user) }.to_not raise_error()
@user.destroyed?.should == false
end
end
@@ -77,20 +77,20 @@
account = FactoryGirl.create(:account, :user => current_user)
FactoryGirl.create(:comment, :user => @user, :commentable => account)
@user.destroy
- lambda { User.find(@user) }.should_not raise_error(ActiveRecord::RecordNotFound)
+ expect { User.find(@user) }.to_not raise_error()
@user.destroyed?.should == false
end
it "should not destroy the current user" do
login
current_user.destroy
- lambda { current_user.reload }.should_not raise_error(ActiveRecord::RecordNotFound)
+ expect { current_user.reload }.to_not raise_error()
current_user.should_not be_destroyed
end
it "should destroy the user" do
@user.destroy
- lambda { User.find(@user) }.should raise_error(ActiveRecord::RecordNotFound)
+ expect { User.find(@user) }.to raise_error(ActiveRecord::RecordNotFound)
@user.should be_destroyed
end
@@ -182,9 +182,9 @@
end
it "should update I18n.locale if proference[:locale] is set" do
- @user.preference[:locale] = :esperanto
+ @user.preference[:locale] = :es
@user.set_individual_locale
- I18n.locale.should == :esperanto
+ I18n.locale.should == :es
end
it "should not update I18n.locale if proference[:locale] is not set" do
@@ -209,4 +209,18 @@
@user.single_access_token.should == "token"
end
end
+
+ describe "serialization" do
+
+ let(:user) { FactoryGirl.build(:user) }
+
+ it "to json" do
+ expect(user.to_json).to eql([user.name].to_json)
+ end
+
+ it "to xml" do
+ expect(user.to_xml).to eql([user.name].to_xml)
+ end
+
+ end
end
diff --git a/spec/routing/accounts_routing_spec.rb b/spec/routing/accounts_routing_spec.rb
index c7a360d13d..94196cf571 100644
--- a/spec/routing/accounts_routing_spec.rb
+++ b/spec/routing/accounts_routing_spec.rb
@@ -53,7 +53,7 @@
end
it "recognizes and generates #auto_complete" do
- { :post => "/accounts/auto_complete" }.should route_to( :controller => "accounts", :action => "auto_complete" )
+ { :get => "/accounts/auto_complete" }.should route_to( :controller => "accounts", :action => "auto_complete" )
end
end
end
diff --git a/spec/routing/campaigns_routing_spec.rb b/spec/routing/campaigns_routing_spec.rb
index 41d45b885e..5d28f443be 100644
--- a/spec/routing/campaigns_routing_spec.rb
+++ b/spec/routing/campaigns_routing_spec.rb
@@ -53,7 +53,7 @@
end
it "recognizes and generates #auto_complete" do
- { :post => "/campaigns/auto_complete" }.should route_to( :controller => "campaigns", :action => "auto_complete" )
+ { :get => "/campaigns/auto_complete" }.should route_to( :controller => "campaigns", :action => "auto_complete" )
end
it "recognizes and generates #filter" do
diff --git a/spec/routing/comments_routing_spec.rb b/spec/routing/comments_routing_spec.rb
index b9cb4236a2..565b700f8c 100644
--- a/spec/routing/comments_routing_spec.rb
+++ b/spec/routing/comments_routing_spec.rb
@@ -12,14 +12,6 @@
{ :get => "/comments" }.should route_to(:controller => "comments", :action => "index")
end
- it "recognizes and generates #new" do
- { :get => "/comments/new" }.should route_to(:controller => "comments", :action => "new")
- end
-
- it "recognizes and generates #show" do
- { :get => "/comments/1" }.should route_to(:controller => "comments", :action => "show", :id => "1")
- end
-
it "recognizes and generates #edit" do
{ :get => "/comments/1/edit" }.should route_to(:controller => "comments", :action => "edit", :id => "1")
end
@@ -37,4 +29,3 @@
end
end
end
-
diff --git a/spec/routing/contacts_routing_spec.rb b/spec/routing/contacts_routing_spec.rb
index 824fa6a20b..f1baa2b8b9 100644
--- a/spec/routing/contacts_routing_spec.rb
+++ b/spec/routing/contacts_routing_spec.rb
@@ -53,7 +53,7 @@
end
it "recognizes and generates #auto_complete" do
- { :post => "/contacts/auto_complete" }.should route_to( :controller => "contacts", :action => "auto_complete" )
+ { :get => "/contacts/auto_complete" }.should route_to( :controller => "contacts", :action => "auto_complete" )
end
end
end
diff --git a/spec/routing/emails_routing_spec.rb b/spec/routing/emails_routing_spec.rb
index b57bc68951..fbfadf75e5 100644
--- a/spec/routing/emails_routing_spec.rb
+++ b/spec/routing/emails_routing_spec.rb
@@ -3,33 +3,33 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'spec_helper'
describe EmailsController do
describe "routing" do
- it "recognizes and generates #index" do
- { :get => "/emails" }.should route_to(:controller => "emails", :action => "index")
+ it "should not recognize #index" do
+ { :get => "/emails" }.should_not be_routable
end
- it "recognizes and generates #new" do
- { :get => "/emails/new" }.should route_to(:controller => "emails", :action => "new")
+ it "should not recognize #new" do
+ { :get => "/emails/new" }.should_not be_routable
end
- it "recognizes and generates #show" do
- { :get => "/emails/1" }.should route_to(:controller => "emails", :action => "show", :id => "1")
+ it "should not recognize #show" do
+ { :get => "/emails/1" }.should_not be_routable
end
- it "recognizes and generates #edit" do
- { :get => "/emails/1/edit" }.should route_to(:controller => "emails", :action => "edit", :id => "1")
+ it "should not recognize #edit" do
+ { :get => "/emails/1/edit" }.should_not be_routable
end
- it "recognizes and generates #create" do
- { :post => "/emails" }.should route_to(:controller => "emails", :action => "create")
+ it "should not recognize #create" do
+ { :post => "/emails" }.should_not be_routable
end
- it "recognizes and generates #update" do
- { :put => "/emails/1" }.should route_to(:controller => "emails", :action => "update", :id => "1")
+ it "should not recognize #update" do
+ { :put => "/emails/1" }.should_not be_routable
end
it "recognizes and generates #destroy" do
@@ -37,4 +37,3 @@
end
end
end
-
diff --git a/spec/routing/leads_routing_spec.rb b/spec/routing/leads_routing_spec.rb
index eceb57cc48..e24e640789 100644
--- a/spec/routing/leads_routing_spec.rb
+++ b/spec/routing/leads_routing_spec.rb
@@ -53,7 +53,7 @@
end
it "recognizes and generates #auto_complete" do
- { :post => "/leads/auto_complete" }.should route_to( :controller => "leads", :action => "auto_complete" )
+ { :get => "/leads/auto_complete" }.should route_to( :controller => "leads", :action => "auto_complete" )
end
it "recognizes and generates #filter" do
diff --git a/spec/routing/opportunities_routing_spec.rb b/spec/routing/opportunities_routing_spec.rb
index dfe85b7d97..d5a24f9355 100644
--- a/spec/routing/opportunities_routing_spec.rb
+++ b/spec/routing/opportunities_routing_spec.rb
@@ -53,7 +53,7 @@
end
it "recognizes and generates #auto_complete" do
- { :post => "/opportunities/auto_complete" }.should route_to( :controller => "opportunities", :action => "auto_complete" )
+ { :get => "/opportunities/auto_complete" }.should route_to( :controller => "opportunities", :action => "auto_complete" )
end
it "recognizes and generates #filter" do
diff --git a/spec/routing/users_routing_spec.rb b/spec/routing/users_routing_spec.rb
index 0c9ab8b0b8..f54782ff20 100644
--- a/spec/routing/users_routing_spec.rb
+++ b/spec/routing/users_routing_spec.rb
@@ -8,8 +8,8 @@
describe UsersController do
describe "routing" do
- it "recognizes and generates #index" do
- { :get => "/users" }.should route_to(:controller => "users", :action => "index")
+ it "doesn't recognize #index" do
+ { :get => "/users" }.should_not be_routable
end
it "recognizes and generates #new as /signup" do
@@ -40,8 +40,8 @@
{ :put => "/opportunities/aaron" }.should_not be_routable
end
- it "recognizes and generates #destroy" do
- { :delete => "/users/1" }.should route_to(:controller => "users", :action => "destroy", :id => "1")
+ it "doesn't recognize #destroy" do
+ { :delete => "/users/1" }.should_not be_routable
end
it "doesn't recognize #destroy with non-numeric id" do
@@ -81,4 +81,3 @@
end
end
end
-
diff --git a/spec/shared/controllers.rb b/spec/shared/controllers.rb
index 56e60ed84e..c15e3e7fdc 100644
--- a/spec/shared/controllers.rb
+++ b/spec/shared/controllers.rb
@@ -3,103 +3,101 @@
# Fat Free CRM is freely distributable under the terms of MIT license.
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-module SharedControllerSpecs
- shared_examples "auto complete" do
- before(:each) do
- @query = "Hello"
- end
+shared_examples "auto complete" do
+ before(:each) do
+ @query = "Hello"
+ end
- it "should do the search and find records that match autocomplete query" do
- post :auto_complete, :auto_complete_query => @query
- assigns[:query].should == @query
- assigns[:auto_complete].should == @auto_complete_matches # Each controller must define it.
- end
+ it "should do the search and find records that match autocomplete query" do
+ get :auto_complete, :auto_complete_query => @query
+ assigns[:query].should == @query
+ assigns[:auto_complete].should == @auto_complete_matches # Each controller must define it.
+ end
- it "should save current autocomplete controller in a session" do
- post :auto_complete, :auto_complete_query => @query
+ it "should save current autocomplete controller in a session" do
+ get :auto_complete, :auto_complete_query => @query
- # We don't save Admin/Users autocomplete controller in a session since Users are not
- # exposed through the Jumpbox.
- unless controller.class.to_s.starts_with?("Admin::")
- session[:auto_complete].should == @controller.controller_name.to_sym
- end
+ # We don't save Admin/Users autocomplete controller in a session since Users are not
+ # exposed through the Jumpbox.
+ unless controller.class.to_s.starts_with?("Admin::")
+ session[:auto_complete].should == @controller.controller_name.to_sym
end
+ end
- it "should render application/_auto_complete template" do
- post :auto_complete, :auto_complete_query => @query
- response.should render_template("application/_auto_complete")
- end
+ it "should render application/_auto_complete template" do
+ post :auto_complete, :auto_complete_query => @query
+ response.should render_template("application/_auto_complete")
end
+end
- shared_examples "attach" do
- it "should attach existing asset to the parent asset of different type" do
- xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
- @model.send(@attachment.class.name.tableize).should include(@attachment)
- assigns[:attachment].should == @attachment
- assigns[:attached].should == [ @attachment ]
- if @model.is_a?(Campaign) && (@attachment.is_a?(Lead) || @attachment.is_a?(Opportunity))
- assigns[:campaign].should == @attachment.reload.campaign
- end
- if @model.is_a?(Account) && @attachment.respond_to?(:account) # Skip Tasks...
- assigns[:account].should == @attachment.reload.account
- end
- response.should render_template("entities/attach")
+shared_examples "attach" do
+ it "should attach existing asset to the parent asset of different type" do
+ xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
+ @model.send(@attachment.class.name.tableize).should include(@attachment)
+ assigns[:attachment].should == @attachment
+ assigns[:attached].should == [ @attachment ]
+ if @model.is_a?(Campaign) && (@attachment.is_a?(Lead) || @attachment.is_a?(Opportunity))
+ assigns[:campaign].should == @attachment.reload.campaign
end
+ if @model.is_a?(Account) && @attachment.respond_to?(:account) # Skip Tasks...
+ assigns[:account].should == @attachment.reload.account
+ end
+ response.should render_template("entities/attach")
+ end
- it "should not attach the asset that is already attached" do
- if @model.is_a?(Campaign) && (@attachment.is_a?(Lead) || @attachment.is_a?(Opportunity))
- @attachment.update_attribute(:campaign_id, @model.id)
- else
- @model.send(@attachment.class.name.tableize) << @attachment
- end
-
- xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
- assigns[:attached].should == nil
- response.should render_template("entities/attach")
+ it "should not attach the asset that is already attached" do
+ if @model.is_a?(Campaign) && (@attachment.is_a?(Lead) || @attachment.is_a?(Opportunity))
+ @attachment.update_attribute(:campaign_id, @model.id)
+ else
+ @model.send(@attachment.class.name.tableize) << @attachment
end
- it "should display flash warning when the model is no longer available" do
- @model.destroy
+ xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
+ assigns[:attached].should == nil
+ response.should render_template("entities/attach")
+ end
- xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
- flash[:warning].should_not == nil
- response.body.should == "window.location.reload();"
- end
- it "should display flash warning when the attachment is no longer available" do
- @attachment.destroy
+ it "should display flash warning when the model is no longer available" do
+ @model.destroy
- xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
- flash[:warning].should_not == nil
- response.body.should == "window.location.reload();"
- end
+ xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
+ flash[:warning].should_not == nil
+ response.body.should == "window.location.reload();"
end
+ it "should display flash warning when the attachment is no longer available" do
+ @attachment.destroy
- shared_examples "discard" do
- it "should discard the attachment without deleting it" do
- xhr :post, :discard, :id => @model.id, :attachment => @attachment.class.name, :attachment_id => @attachment.id
- assigns[:attachment].should == @attachment.reload # The attachment should still exist.
- @model.reload.send("#{@attachment.class.name.tableize}").should == [] # But no longer associated with the model.
- assigns[:account].should == @model if @model.is_a?(Account)
- assigns[:campaign].should == @model if @model.is_a?(Campaign)
+ xhr :put, :attach, :id => @model.id, :assets => @attachment.class.name.tableize, :asset_id => @attachment.id
+ flash[:warning].should_not == nil
+ response.body.should == "window.location.reload();"
+ end
+end
- response.should render_template("entities/discard")
- end
+shared_examples "discard" do
+ it "should discard the attachment without deleting it" do
+ xhr :post, :discard, :id => @model.id, :attachment => @attachment.class.name, :attachment_id => @attachment.id
+ assigns[:attachment].should == @attachment.reload # The attachment should still exist.
+ @model.reload.send("#{@attachment.class.name.tableize}").should == [] # But no longer associated with the model.
+ assigns[:account].should == @model if @model.is_a?(Account)
+ assigns[:campaign].should == @model if @model.is_a?(Campaign)
- it "should display flash warning when the model is no longer available" do
- @model.destroy
+ response.should render_template("entities/discard")
+ end
- xhr :post, :discard, :id => @model.id, :attachment => @attachment.class.name, :attachment_id => @attachment.id
- flash[:warning].should_not == nil
- response.body.should == "window.location.reload();"
- end
+ it "should display flash warning when the model is no longer available" do
+ @model.destroy
- it "should display flash warning when the attachment is no longer available" do
- @attachment.destroy
+ xhr :post, :discard, :id => @model.id, :attachment => @attachment.class.name, :attachment_id => @attachment.id
+ flash[:warning].should_not == nil
+ response.body.should == "window.location.reload();"
+ end
- xhr :post, :discard, :id => @model.id, :attachment => @attachment.class.name, :attachment_id => @attachment.id
- flash[:warning].should_not == nil
- response.body.should == "window.location.reload();"
- end
+ it "should display flash warning when the attachment is no longer available" do
+ @attachment.destroy
+
+ xhr :post, :discard, :id => @model.id, :attachment => @attachment.class.name, :attachment_id => @attachment.id
+ flash[:warning].should_not == nil
+ response.body.should == "window.location.reload();"
end
end
diff --git a/spec/shared/models.rb b/spec/shared/models.rb
index 66d3cb4de8..3ab05db8bd 100644
--- a/spec/shared/models.rb
+++ b/spec/shared/models.rb
@@ -5,7 +5,7 @@
#------------------------------------------------------------------------------
require "cancan/matchers"
-shared_examples "exportable" do
+shared_examples_for "exportable" do
it "Model#export returns all records with extra attributes added" do
# User/assignee for the second record has no first/last name.
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index f4f252dce4..602c58ca1c 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -11,7 +11,7 @@
require 'capybara/rails'
require 'acts_as_fu'
-require 'factory_girl'
+require 'factory_girl_rails'
require 'ffaker'
require 'coveralls'
@@ -38,6 +38,7 @@
# RSpec configuration options for Fat Free CRM.
config.include RSpec::Rails::Matchers
+ config.include(FactoryGirl::Syntax::Methods)
config.before(:each) do
# Overwrite locale settings within "config/settings.yml" if necessary.
diff --git a/spec/support/auth_macros.rb b/spec/support/auth_macros.rb
index 8a7b6db78a..a1d8b0a218 100755
--- a/spec/support/auth_macros.rb
+++ b/spec/support/auth_macros.rb
@@ -17,8 +17,8 @@ def activate_authlogic
#----------------------------------------------------------------------------
def login(user_stubs = {}, session_stubs = {})
User.current_user = @current_user = FactoryGirl.create(:user, user_stubs)
- @current_user_session = mock(Authentication, {:record => current_user}.merge(session_stubs))
- Authentication.stub!(:find).and_return(@current_user_session)
+ @current_user_session = double(Authentication, {:record => current_user}.merge(session_stubs))
+ Authentication.stub(:find).and_return(@current_user_session)
#set_timezone
end
alias :require_user :login
@@ -33,7 +33,7 @@ def login_and_assign(user_stubs = {}, session_stubs = {})
def logout
@current_user = nil
@current_user_session = nil
- Authentication.stub!(:find).and_return(nil)
+ Authentication.stub(:find).and_return(nil)
end
alias :require_no_user :logout
diff --git a/spec/support/mail_processor_mocks.rb b/spec/support/mail_processor_mocks.rb
index df3501669a..a8bcc4815c 100644
--- a/spec/support/mail_processor_mocks.rb
+++ b/spec/support/mail_processor_mocks.rb
@@ -5,31 +5,31 @@
#------------------------------------------------------------------------------
module MockIMAP
def mock_imap
- @imap = mock
+ @imap = double
@settings = @crawler.instance_variable_get("@settings")
@settings[:address] = @mock_address
- Net::IMAP.stub!(:new).with(@settings[:server], @settings[:port], @settings[:ssl]).and_return(@imap)
+ Net::IMAP.stub(:new).with(@settings[:server], @settings[:port], @settings[:ssl]).and_return(@imap)
end
def mock_connect
mock_imap
- @imap.stub!(:login).and_return(true)
- @imap.stub!(:select).and_return(true)
+ @imap.stub(:login).and_return(true)
+ @imap.stub(:select).and_return(true)
end
def mock_disconnect
- @imap.stub!(:disconnected?).and_return(false)
- @imap.stub!(:logout).and_return(true)
- @imap.stub!(:disconnect).and_return(true)
+ @imap.stub(:disconnected?).and_return(false)
+ @imap.stub(:logout).and_return(true)
+ @imap.stub(:disconnect).and_return(true)
end
def mock_message(body)
- @fetch_data = mock
- @fetch_data.stub!(:attr).and_return("RFC822" => body)
- @imap.stub!(:uid_search).and_return([ :uid ])
- @imap.stub!(:uid_fetch).and_return([ @fetch_data ])
- @imap.stub!(:uid_copy).and_return(true)
- @imap.stub!(:uid_store).and_return(true)
+ @fetch_data = double
+ @fetch_data.stub(:attr).and_return("RFC822" => body)
+ @imap.stub(:uid_search).and_return([ :uid ])
+ @imap.stub(:uid_fetch).and_return([ @fetch_data ])
+ @imap.stub(:uid_copy).and_return(true)
+ @imap.stub(:uid_store).and_return(true)
body
end
end
diff --git a/spec/views/accounts/create.js.haml_spec.rb b/spec/views/accounts/create.js.haml_spec.rb
index cf4b795d65..9b24dcebc7 100644
--- a/spec/views/accounts/create.js.haml_spec.rb
+++ b/spec/views/accounts/create.js.haml_spec.rb
@@ -23,8 +23,8 @@
end
it "should hide [Create Account] form and insert account partial" do
- rendered.should include("jQuery('#accounts').prepend(' 'accounts/index', :formats => [:js]
- rendered.should include("jQuery('#accounts').html")
- rendered.should include("jQuery('#paginate').html")
+ rendered.should include("$('#accounts').html")
+ rendered.should include("$('#paginate').html")
end
it "should render [empty] template if @accounts collection if there are no accounts" do
@@ -26,8 +26,8 @@
render :template => 'accounts/index', :formats => [:js]
- rendered.should include("jQuery('#accounts').html(' current_user))
render
- rendered.should include("jQuery('#campaign_#{previous.id}').replaceWith('
'campaigns/index', :formats => [:js]
- rendered.should include("jQuery('#campaigns').html(' 'campaigns/index', :formats => [:js]
- rendered.should include("jQuery('#campaigns').html('")
+ rendered.should include("$('#campaigns').html('
")
rendered.should include("#paginate")
end
diff --git a/spec/views/campaigns/new.js.haml_spec.rb b/spec/views/campaigns/new.js.haml_spec.rb
index ecb0f718e6..bfc6733bec 100755
--- a/spec/views/campaigns/new.js.haml_spec.rb
+++ b/spec/views/campaigns/new.js.haml_spec.rb
@@ -25,7 +25,7 @@
params[:cancel] = nil
render
- rendered.should include("jQuery('#create_campaign').html")
+ rendered.should include("$('#create_campaign').html")
end
it "should call JavaScript functions to load Calendar popup" do
diff --git a/spec/views/campaigns/update.js.haml_spec.rb b/spec/views/campaigns/update.js.haml_spec.rb
index 573af0a57d..81216a6051 100755
--- a/spec/views/campaigns/update.js.haml_spec.rb
+++ b/spec/views/campaigns/update.js.haml_spec.rb
@@ -31,7 +31,7 @@
rendered.should include("#sidebar")
rendered.should have_text("Campaign Summary")
rendered.should have_text("Recent Items")
- rendered.should include("jQuery('#summary').effect('shake'")
+ rendered.should include("$('#summary').effect('shake'")
end
end
@@ -42,8 +42,8 @@
it "should replace [Edit Campaign] with campaign partial and highlight it" do
render
- rendered.should include("jQuery('#campaign_#{@campaign.id}').replaceWith('
true
+ :id => 321,
+ :new_record? => false,
+ :commentable => stub_model(Contact, :id => '123')
+ ))
+ #params["contact_id"] = "123"
+ assign(:current_user, stub_model(User,
+ :email => 'test@example.com'
))
- assign(:commentable, "contact")
- params["contact_id"] = "123"
end
- it "should render new form" do
+ it "should render edit form" do
render
- rendered.should include("hide()")
- rendered.should include("show()")
+ rendered.should include("textarea")
+ rendered.should include("123")
end
end
-
diff --git a/spec/views/contacts/create.js.haml_spec.rb b/spec/views/contacts/create.js.haml_spec.rb
index 52ac4381d3..68a5e85a14 100644
--- a/spec/views/contacts/create.js.haml_spec.rb
+++ b/spec/views/contacts/create.js.haml_spec.rb
@@ -21,8 +21,8 @@
it "should hide [Create Contact] form and insert contact partial" do
render
- rendered.should include("jQuery('#contacts').prepend(' current_user))
render
- rendered.should include("jQuery('#contact_#{previous.id}').replaceWith")
+ rendered.should include("$('#contact_#{previous.id}').replaceWith")
end
it "edit: should hide and remove previously open [Edit Contact] if it's no longer available" do
@@ -53,7 +53,7 @@
render
rendered.should include("crm.highlight_off('contact_#{@contact.id}');")
rendered.should include("crm.hide_form('create_contact')")
- rendered.should include("jQuery('#contact_#{@contact.id}').html")
+ rendered.should include("$('#contact_#{@contact.id}').html")
rendered.should include("crm.create_or_select_account(false)")
end
@@ -61,7 +61,7 @@
params[:cancel] = "false"
render
- rendered.should include("jQuery('#edit_contact').html")
+ rendered.should include("$('#edit_contact').html")
rendered.should include("crm.flip_form('edit_contact'")
end
diff --git a/spec/views/contacts/index.js.html_spec.rb b/spec/views/contacts/index.js.html_spec.rb
index 81056145ab..aa08776244 100644
--- a/spec/views/contacts/index.js.html_spec.rb
+++ b/spec/views/contacts/index.js.html_spec.rb
@@ -17,7 +17,7 @@
render :template => 'contacts/index', :formats => [:js]
- rendered.should include("jQuery('#contacts').html(' 'contacts/index', :formats => [:js]
- rendered.should include("jQuery('#contacts').html('")
+ rendered.should include("$('#contacts').html('
")
rendered.should include("#paginate")
end
diff --git a/spec/views/contacts/new.js.haml_spec.rb b/spec/views/contacts/new.js.haml_spec.rb
index 91c977c76f..e044df6fdd 100644
--- a/spec/views/contacts/new.js.haml_spec.rb
+++ b/spec/views/contacts/new.js.haml_spec.rb
@@ -28,7 +28,7 @@
params[:cancel] = nil
render
- rendered.should include("jQuery('#create_contact').html")
+ rendered.should include("$('#create_contact').html")
rendered.should include("crm.create_or_select_account(false)")
end
end
@@ -38,7 +38,7 @@
params[:cancel] = "true"
render
- rendered.should_not include("jQuery('#create_contact').html")
+ rendered.should_not include("$('#create_contact').html")
rendered.should include("crm.flip_form('create_contact');")
end
end
diff --git a/spec/views/contacts/update.js.haml_spec.rb b/spec/views/contacts/update.js.haml_spec.rb
index d9b643923b..67b4148012 100644
--- a/spec/views/contacts/update.js.haml_spec.rb
+++ b/spec/views/contacts/update.js.haml_spec.rb
@@ -32,7 +32,7 @@
render
rendered.should include("#sidebar")
rendered.should have_text("Recent Items")
- rendered.should include("jQuery('#summary').effect('shake'")
+ rendered.should include("$('#summary').effect('shake'")
end
end
@@ -45,8 +45,8 @@
controller.request.env["HTTP_REFERER"] = "http://localhost/contacts"
render
- rendered.should include("jQuery('#contact_#{@contact.id}').replaceWith('
'home/index', :formats => [:js]
- rendered.should include("jQuery('#activities').html")
+ rendered.should include("$('#activities').html")
rendered.should include("li class=\\'version\\' id=\\'version_42\\'")
end
diff --git a/spec/views/home/options.js.haml_spec.rb b/spec/views/home/options.js.haml_spec.rb
index 16f776b2c2..f83658ae03 100644
--- a/spec/views/home/options.js.haml_spec.rb
+++ b/spec/views/home/options.js.haml_spec.rb
@@ -21,8 +21,8 @@
render
- rendered.should include("jQuery('#options').html")
- rendered.should include("onLoading:function(request){$(\\'asset\\').update(\\'campaign\\'); $(\\'loading\\').show()}")
+ rendered.should include("$('#options').html")
+ rendered.should include("$(\\'#asset\\').html(\\'campaign\\')")
rendered.should include("crm.flip_form('options')")
rendered.should include("crm.set_title('title', 'Recent Activity Options')")
end
@@ -44,7 +44,7 @@
params[:cancel] = "true"
render
- rendered.should_not include("jQuery('#options').html")
+ rendered.should_not include("$('#options').html")
rendered.should include("crm.flip_form('options')")
rendered.should include("crm.set_title('title', 'Recent Activity')")
end
diff --git a/spec/views/leads/convert.js.haml_spec.rb b/spec/views/leads/convert.js.haml_spec.rb
index 483e22cbad..75d377cc0a 100755
--- a/spec/views/leads/convert.js.haml_spec.rb
+++ b/spec/views/leads/convert.js.haml_spec.rb
@@ -22,7 +22,7 @@
params[:cancel] = "true"
render
- rendered.should include("jQuery('#lead_#{@lead.id}').replaceWith(' current_user))
render
- rendered.should include("jQuery('#lead_#{previous.id}').replaceWith")
+ rendered.should include("$('#lead_#{previous.id}').replaceWith")
end
it "convert: should remove previously open [Convert Lead] if it's no longer available" do
@@ -55,7 +55,7 @@
render
rendered.should include("crm.highlight_off('lead_#{@lead.id}');")
rendered.should include("crm.hide_form('create_lead')")
- rendered.should include("jQuery('#lead_#{@lead.id}').html")
+ rendered.should include("$('#lead_#{@lead.id}').html")
end
it "convert from lead landing page: should hide [Edit Lead] and show [Convert Lead] form" do
diff --git a/spec/views/leads/create.js.haml_spec.rb b/spec/views/leads/create.js.haml_spec.rb
index 9927f5ff5d..ce1ff460dc 100755
--- a/spec/views/leads/create.js.haml_spec.rb
+++ b/spec/views/leads/create.js.haml_spec.rb
@@ -22,8 +22,8 @@
it "should hide [Create Lead] form and insert lead partial" do
render
- rendered.should include("jQuery('#leads').prepend(' current_user))
render
- rendered.should include("jQuery('#lead_#{previous.id}').replaceWith(' 'leads/index', :formats => [:js]
- rendered.should include("jQuery('#leads').html(' 'leads/index', :formats => [:js]
- rendered.should include("jQuery('#leads').html('")
+ rendered.should include("$('#leads').html('
")
rendered.should include("#paginate")
end
diff --git a/spec/views/leads/new.js.haml_spec.rb b/spec/views/leads/new.js.haml_spec.rb
index bbdbf90d0a..b5c0104f7c 100755
--- a/spec/views/leads/new.js.haml_spec.rb
+++ b/spec/views/leads/new.js.haml_spec.rb
@@ -28,7 +28,7 @@
params[:cancel] = nil
render
- rendered.should include("jQuery('#create_lead').html")
+ rendered.should include("$('#create_lead').html")
rendered.should include("crm.flip_form('create_lead')")
end
end
diff --git a/spec/views/leads/promote.js.haml_spec.rb b/spec/views/leads/promote.js.haml_spec.rb
index 9c0105b2f3..e83dfb905a 100755
--- a/spec/views/leads/promote.js.haml_spec.rb
+++ b/spec/views/leads/promote.js.haml_spec.rb
@@ -37,7 +37,7 @@
rendered.should include("#sidebar")
rendered.should have_text("Lead Summary")
rendered.should have_text("Recent Items")
- rendered.should include("jQuery('#summary').effect('shake'")
+ rendered.should include("$('#summary').effect('shake'")
end
end
@@ -48,8 +48,8 @@
it "should replace [Convert Lead] with lead partial and highlight it" do
render
- rendered.should include("jQuery('#lead_#{@lead.id}').replaceWith('
current_user))
render
- rendered.should include("jQuery('#opportunity_#{previous.id}').replaceWith")
+ rendered.should include("$('#opportunity_#{previous.id}').replaceWith")
end
it "edit: remove previously open [Edit Opportunity] if it's no longer available" do
@@ -55,14 +55,14 @@
render
rendered.should include("crm.highlight_off('opportunity_#{@opportunity.id}');")
rendered.should include("crm.hide_form('create_opportunity')")
- rendered.should include("jQuery('#opportunity_#{@opportunity.id}').html")
+ rendered.should include("$('#opportunity_#{@opportunity.id}').html")
end
it "edit from opportunity landing page: should show [Edit Opportunity] form" do
params[:cancel] = "false"
render
- rendered.should include("jQuery('#edit_opportunity').html")
+ rendered.should include("$('#edit_opportunity').html")
rendered.should include("crm.flip_form('edit_opportunity'")
end
diff --git a/spec/views/opportunities/index.js.haml_spec.rb b/spec/views/opportunities/index.js.haml_spec.rb
index 7cb07a8e02..a4a15f9a0a 100644
--- a/spec/views/opportunities/index.js.haml_spec.rb
+++ b/spec/views/opportunities/index.js.haml_spec.rb
@@ -18,7 +18,7 @@
render :template => 'opportunities/index', :formats => [:js]
- rendered.should include("jQuery('#opportunities').html")
+ rendered.should include("$('#opportunities').html")
rendered.should include("#paginate")
end
@@ -27,7 +27,7 @@
render :template => 'opportunities/index', :formats => [:js]
- rendered.should include("jQuery('#opportunities').html('")
+ rendered.should include("$('#opportunities').html('
")
rendered.should include("#paginate")
end
diff --git a/spec/views/opportunities/update.js.haml_spec.rb b/spec/views/opportunities/update.js.haml_spec.rb
index b00c517f78..917d5aa6a3 100644
--- a/spec/views/opportunities/update.js.haml_spec.rb
+++ b/spec/views/opportunities/update.js.haml_spec.rb
@@ -34,7 +34,7 @@
rendered.should include("#sidebar")
rendered.should have_text("Opportunity At a Glance")
rendered.should have_text("Recent Items")
- rendered.should include("jQuery('#summary').effect('shake'")
+ rendered.should include("$('#summary').effect('shake'")
end
end
@@ -45,8 +45,8 @@
it "should replace [Edit Opportunity] with opportunity partial and highlight it" do
render
- rendered.should include("jQuery('#opportunity_#{@opportunity.id}').replaceWith")
- rendered.should include(%Q/jQuery('#opportunity_#{@opportunity.id}').effect("highlight"/)
+ rendered.should include("$('#opportunity_#{@opportunity.id}').replaceWith")
+ rendered.should include(%Q/$('#opportunity_#{@opportunity.id}').effect("highlight"/)
end
it "should update sidebar" do
@@ -54,7 +54,7 @@
rendered.should include("sidebar")
rendered.should have_text("Opportunity Stages")
rendered.should have_text("Recent Items")
- rendered.should include("jQuery('#filters').effect('shake'")
+ rendered.should include("$('#filters').effect('shake'")
end
end
@@ -90,7 +90,7 @@
controller.request.env["HTTP_REFERER"] = "http://localhost/contacts/123"
render
- rendered.should include(%Q/jQuery('#opportunity_#{@opportunity.id}').effect("highlight"/)
+ rendered.should include(%Q/$('#opportunity_#{@opportunity.id}').effect("highlight"/)
end
end
end
@@ -107,9 +107,9 @@
it "should redraw the [edit_opportunity] form and shake it" do
render
- rendered.should include("jQuery('#edit_opportunity').html")
+ rendered.should include("$('#edit_opportunity').html")
rendered.should include('crm.create_or_select_account(false)')
- rendered.should include(%Q/jQuery('#edit_opportunity').effect("shake"/)
+ rendered.should include(%Q/$('#edit_opportunity').effect("shake"/)
rendered.should include('focus()')
end
end
@@ -121,9 +121,9 @@
it "should redraw the [edit_opportunity] form and shake it" do
render
- rendered.should include("jQuery('#opportunity_#{@opportunity.id}').html")
+ rendered.should include("$('#opportunity_#{@opportunity.id}').html")
rendered.should include('crm.create_or_select_account(false)')
- rendered.should include(%Q/jQuery('#opportunity_#{@opportunity.id}').effect("shake"/)
+ rendered.should include(%Q/$('#opportunity_#{@opportunity.id}').effect("shake"/)
rendered.should include('focus()')
end
end
@@ -140,8 +140,8 @@
it "should redraw the [edit_opportunity] form and shake it" do
render
- rendered.should include("jQuery('#opportunity_#{@opportunity.id}').html")
- rendered.should include(%Q/jQuery('#opportunity_#{@opportunity.id}').effect("shake"/)
+ rendered.should include("$('#opportunity_#{@opportunity.id}').html")
+ rendered.should include(%Q/$('#opportunity_#{@opportunity.id}').effect("shake"/)
rendered.should include('focus()')
end
end
diff --git a/spec/views/tasks/complete.js.haml_spec.rb b/spec/views/tasks/complete.js.haml_spec.rb
index 32abc9b46b..522de90fa0 100644
--- a/spec/views/tasks/complete.js.haml_spec.rb
+++ b/spec/views/tasks/complete.js.haml_spec.rb
@@ -26,8 +26,8 @@
controller.request.env["HTTP_REFERER"] = "http://localhost/tasks"
render
- rendered.should include("jQuery('#task_#{@task.id}').fadeOut")
- rendered.should include("jQuery('#list_due_asap').fadeOut")
+ rendered.should include("$('#task_#{@task.id}').fadeOut")
+ rendered.should include("$('#list_due_asap').fadeOut")
end
it "should update tasks sidebar" do
@@ -37,10 +37,10 @@
controller.request.env["HTTP_REFERER"] = "http://localhost/tasks"
render
- rendered.should include("jQuery('#sidebar').html")
+ rendered.should include("$('#sidebar').html")
rendered.should have_text("Assigned")
rendered.should have_text("Recent Items")
- rendered.should include("jQuery('#filters').effect('shake'")
+ rendered.should include("$('#filters').effect('shake'")
end
end
@@ -50,7 +50,7 @@
assign(:task, @task)
render
- rendered.should include("jQuery('#task_#{@task.id}').html('
')
end
diff --git a/spec/views/tasks/create.js.haml_spec.rb b/spec/views/tasks/create.js.haml_spec.rb
index 3cc27e093f..a8569df524 100644
--- a/spec/views/tasks/create.js.haml_spec.rb
+++ b/spec/views/tasks/create.js.haml_spec.rb
@@ -23,23 +23,23 @@
end
it "should hide [Create Task] form and insert task partial" do
- rendered.should include(%Q/jQuery('#due_asap').before(' /)
- rendered.should include(%Q/jQuery('#task_#{@task.id}').effect("highlight"/)
+ rendered.should include(%Q/$('#due_asap').before(' /)
+ rendered.should include(%Q/$('#task_#{@task.id}').effect("highlight"/)
end
it "should update tasks title" do
if status == "assigned"
- rendered.should include("jQuery('#title').html('Assigned Tasks');")
+ rendered.should include("$('#title').html('Assigned Tasks');")
else
- rendered.should include("jQuery('#title').html('Tasks');")
+ rendered.should include("$('#title').html('Tasks');")
end
end
it "should update tasks sidebar" do
- rendered.should include("jQuery('#sidebar').html")
+ rendered.should include("$('#sidebar').html")
rendered.should have_text("Recent Items")
rendered.should have_text("Sometime Later")
- rendered.should include("jQuery('#filters').effect('shake'")
+ rendered.should include("$('#filters').effect('shake'")
end
end
end
@@ -50,7 +50,7 @@
controller.request.env["HTTP_REFERER"] = "http://localhost/tasks"
render
- rendered.should include("jQuery('#flash').html")
+ rendered.should include("$('#flash').html")
rendered.should include("crm.flash('notice', true)")
end
@@ -70,7 +70,7 @@
controller.request.env["HTTP_REFERER"] = "http://localhost/tasks?view=assigned"
render
- rendered.should include("jQuery('#flash').html")
+ rendered.should include("$('#flash').html")
rendered.should include("crm.flash('notice', true)")
end
@@ -94,12 +94,12 @@
end
it "should update tasks title" do
- rendered.should include("jQuery('#create_task_title').html('Tasks')")
+ rendered.should include("$('#create_task_title').html('Tasks')")
end
it "should insert #{status} partial and highlight it" do
- rendered.should include("jQuery('#tasks').prepend(' ")
- rendered.should include(%Q/jQuery('#task_#{@task.id}').effect("highlight"/)
+ rendered.should include("$('#tasks').prepend(' ")
+ rendered.should include(%Q/$('#task_#{@task.id}').effect("highlight"/)
end
it "should update recently viewed items" do
@@ -113,8 +113,8 @@
assign(:task, FactoryGirl.build(:task, :name => nil)) # make it invalid
render
- rendered.should include(%Q/jQuery('#create_task').effect("shake"/)
- rendered.should include(%/jQuery('#new_task input[type=submit]').enable()/)
+ rendered.should include(%Q/$('#create_task').effect("shake"/)
+ rendered.should include(%/$('#new_task input[type=submit]').enable()/)
end
diff --git a/spec/views/tasks/destroy.js.haml_spec.rb b/spec/views/tasks/destroy.js.haml_spec.rb
index a3dfcd91f0..99053253d1 100644
--- a/spec/views/tasks/destroy.js.haml_spec.rb
+++ b/spec/views/tasks/destroy.js.haml_spec.rb
@@ -27,17 +27,17 @@
render
rendered.should include("slideUp")
- rendered.should include("jQuery('#list_due_asap').fadeOut")
+ rendered.should include("$('#list_due_asap').fadeOut")
end
it "should update tasks sidebar" do
controller.request.env["HTTP_REFERER"] = "http://localhost/tasks"
render
- rendered.should include("jQuery('#sidebar').html")
+ rendered.should include("$('#sidebar').html")
rendered.should have_text("Recent Items")
rendered.should have_text("Completed")
- rendered.should include("jQuery('#filters').effect('shake'")
+ rendered.should include("$('#filters').effect('shake'")
end
end
end
diff --git a/spec/views/tasks/edit.js.haml_spec.rb b/spec/views/tasks/edit.js.haml_spec.rb
index 81ea525c2f..be17f1d9c4 100644
--- a/spec/views/tasks/edit.js.haml_spec.rb
+++ b/spec/views/tasks/edit.js.haml_spec.rb
@@ -24,7 +24,7 @@
assign(:task, @task)
render
- rendered.should include("jQuery('#task_#{@task.id}').html(' FactoryGirl.create(:user)))
render
- rendered.should include("jQuery('#task_#{@task.id}').html(' current_user)
- current_user.stub!(:avatar).and_return(@avatar)
+ current_user.stub(:avatar).and_return(@avatar)
assign(:user, @user = current_user)
end
@@ -31,14 +31,14 @@
before do
@avatar = FactoryGirl.create(:avatar, :entity => current_user)
@avatar.errors.add(:image, "error")
- current_user.stub!(:avatar).and_return(@avatar)
+ current_user.stub(:avatar).and_return(@avatar)
assign(:user, @user = current_user)
end
it "should redraw the [Upload Avatar] form and shake it" do
render
- rendered.should include("jQuery('#upload_avatar').html")
- rendered.should include(%Q/jQuery('#upload_avatar').effect("shake"/)
+ rendered.should include("$('#upload_avatar').html")
+ rendered.should include(%Q/$('#upload_avatar').effect("shake"/)
end
end # errors
end
diff --git a/vendor/assets/images/brief.png b/vendor/assets/images/brief.png
deleted file mode 100644
index 39b46b6cc5..0000000000
Binary files a/vendor/assets/images/brief.png and /dev/null differ
diff --git a/vendor/assets/images/full.png b/vendor/assets/images/full.png
deleted file mode 100644
index 936b51696b..0000000000
Binary files a/vendor/assets/images/full.png and /dev/null differ
diff --git a/vendor/assets/images/long.png b/vendor/assets/images/long.png
deleted file mode 100644
index 4fc55e0874..0000000000
Binary files a/vendor/assets/images/long.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/campaigns.png b/vendor/assets/images/tab_icons/campaigns.png
deleted file mode 100644
index d539b16426..0000000000
Binary files a/vendor/assets/images/tab_icons/campaigns.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/campaigns_active.png b/vendor/assets/images/tab_icons/campaigns_active.png
deleted file mode 100644
index 2bb2746bfa..0000000000
Binary files a/vendor/assets/images/tab_icons/campaigns_active.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/contacts.png b/vendor/assets/images/tab_icons/contacts.png
deleted file mode 100644
index 2cab254227..0000000000
Binary files a/vendor/assets/images/tab_icons/contacts.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/contacts_active.png b/vendor/assets/images/tab_icons/contacts_active.png
deleted file mode 100644
index a08271baf0..0000000000
Binary files a/vendor/assets/images/tab_icons/contacts_active.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/dashboard.png b/vendor/assets/images/tab_icons/dashboard.png
deleted file mode 100644
index 880115db0a..0000000000
Binary files a/vendor/assets/images/tab_icons/dashboard.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/dashboard_active.png b/vendor/assets/images/tab_icons/dashboard_active.png
deleted file mode 100644
index 44512238f2..0000000000
Binary files a/vendor/assets/images/tab_icons/dashboard_active.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/leads.png b/vendor/assets/images/tab_icons/leads.png
deleted file mode 100644
index 7929c82e95..0000000000
Binary files a/vendor/assets/images/tab_icons/leads.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/leads_active.png b/vendor/assets/images/tab_icons/leads_active.png
deleted file mode 100644
index 1c3adfa82c..0000000000
Binary files a/vendor/assets/images/tab_icons/leads_active.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/opportunities.png b/vendor/assets/images/tab_icons/opportunities.png
deleted file mode 100644
index 6d5754afa4..0000000000
Binary files a/vendor/assets/images/tab_icons/opportunities.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/opportunities_active.png b/vendor/assets/images/tab_icons/opportunities_active.png
deleted file mode 100644
index e52910cc52..0000000000
Binary files a/vendor/assets/images/tab_icons/opportunities_active.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/tasks.png b/vendor/assets/images/tab_icons/tasks.png
deleted file mode 100644
index f9b957e777..0000000000
Binary files a/vendor/assets/images/tab_icons/tasks.png and /dev/null differ
diff --git a/vendor/assets/images/tab_icons/tasks_active.png b/vendor/assets/images/tab_icons/tasks_active.png
deleted file mode 100644
index 67f98f5446..0000000000
Binary files a/vendor/assets/images/tab_icons/tasks_active.png and /dev/null differ
diff --git a/vendor/assets/javascripts/ajax-chosen-jquery.js b/vendor/assets/javascripts/ajax-chosen-jquery.js
new file mode 100644
index 0000000000..2d243a36ab
--- /dev/null
+++ b/vendor/assets/javascripts/ajax-chosen-jquery.js
@@ -0,0 +1,2 @@
+//= require chosen-jquery
+//= require ajax-chosen.jquery
diff --git a/vendor/assets/javascripts/ajax-chosen.jquery.coffee b/vendor/assets/javascripts/ajax-chosen.jquery.coffee
new file mode 100644
index 0000000000..fb08f1a07b
--- /dev/null
+++ b/vendor/assets/javascripts/ajax-chosen.jquery.coffee
@@ -0,0 +1,171 @@
+# Thanks to https://raw.github.com/meltingice/ajax-chosen/master/src/ajax-chosen.coffee
+
+do ($ = jQuery) ->
+
+ $.fn.ajaxChosen = (settings = {}, callback, chosenOptions = {}) ->
+ defaultOptions =
+ minTermLength: 3
+ afterTypeDelay: 500
+ jsonTermKey: "term"
+ keepTypingMsg: "Keep typing..."
+ lookingForMsg: "Looking for"
+
+ # This will come in handy later.
+ select = @
+
+ chosenXhr = null
+
+ # Merge options with defaults
+ options = $.extend {}, defaultOptions, $(select).data(), settings
+
+ # Load chosen. To make things clear, I have taken the liberty
+ # of using the .chzn-autoselect class to specify input elements
+ # we want to use with ajax autocomplete.
+ @chosen(if chosenOptions then chosenOptions else {})
+
+ @each ->
+ # Now that chosen is loaded normally, we can bootstrap it with
+ # our ajax autocomplete code.
+ $(@).next('.chzn-container')
+ .find(".search-field > input, .chzn-search > input")
+ .bind 'keyup', ->
+ # This code will be executed every time the user types a letter
+ # into the input form that chosen has created
+
+ # Retrieve the current value of the input form
+ untrimmed_val = $(@).val()
+ val = $.trim $(@).val()
+
+ # Depending on how much text the user has typed, let them know
+ # if they need to keep typing or if we are looking for their data
+ msg = if val.length < options.minTermLength then options.keepTypingMsg else options.lookingForMsg + " '#{val}'"
+ select.next('.chzn-container').find('.no-results').text(msg)
+
+ # If input text has not changed ... do nothing
+ return false if val is $(@).data('prevVal')
+
+ # Set the current search term so we don't execute the ajax call if
+ # the user hits a key that isn't an input letter/number/symbol
+ $(@).data('prevVal', val)
+
+ # At this point, we have a new term/query ... the old timer
+ # is no longer valid. Clear it.
+
+ # We delay searches by a small amount so that we don't flood the
+ # server with ajax requests.
+ clearTimeout(@timer) if @timer
+
+ # Some simple validation so we don't make excess ajax calls. I am
+ # assuming you don't want to perform a search with less than 3
+ # characters.
+ return false if val.length < options.minTermLength
+
+ # This is a useful reference for later
+ field = $(@)
+
+ # Default term key is `term`. Specify alternative in options.options.jsonTermKey
+ options.data = {} unless options.data?
+ options.data[options.jsonTermKey] = val
+ options.data = options.dataCallback(options.data) if options.dataCallback?
+
+ # If the user provided an ajax success callback, store it so we can
+ # call it after our bootstrapping is finished.
+ success = options.success
+
+ # Create our own callback that will be executed when the ajax call is
+ # finished.
+ options.success = (data) ->
+ # Exit if the data we're given is invalid
+ return unless data?
+
+ # Go through all of the elements in the and remove
+ # ones that have not been selected by the user. For those selected
+ # by the user, add them to a list to filter from the results later.
+ selected_values = []
+ select.find('option').each ->
+ if not $(@).is(":selected")
+ $(@).remove()
+ else
+ selected_values.push $(@).val() + "-" + $(@).text()
+ select.find('optgroup:empty').each ->
+ $(@).remove()
+
+
+ # Send the ajax results to the user callback so we can get an object of
+ # value => text pairs to inject as elements.
+ items = if callback? then callback(data, field) else data
+
+
+ nbItems = 0
+
+ # Iterate through the given data and inject the elements into
+ # the DOM if it doesn't exist in the selector already
+ $.each items, (i, element) ->
+ nbItems++
+
+ if element.group
+ group = select.find("optgroup[label='#{element.text}']")
+ group = $(" ") unless group.size()
+
+ group.attr('label', element.text)
+ .appendTo(select)
+ $.each element.items, (i, element) ->
+ if typeof element == "string"
+ value = i;
+ text = element;
+ else
+ value = element.value;
+ text = element.text;
+ if $.inArray(value + "-" + text, selected_values) == -1
+ $(" ")
+ .attr('value', value)
+ .html(text)
+ .appendTo(group)
+ else
+ if typeof element == "string"
+ value = i;
+ text = element;
+ else
+ value = element.value;
+ text = element.text;
+ if $.inArray(value + "-" + text, selected_values) == -1
+ $(" ")
+ .attr('value', value)
+ .html(text)
+ .appendTo(select)
+
+ if nbItems
+ # Tell chosen that the contents of the input have been updated
+ # This makes chosen update its internal list of the input data.
+ select.trigger("liszt:updated")
+ else
+ # If there are no results, display the no_results text
+ select.data().chosen.no_results_clear()
+ select.data().chosen.no_results field.val()
+
+ # Finally, call the user supplied callback (if it exists)
+ settings.success(data) if settings.success?
+
+ # For some reason, the contents of the input field get removed once you
+ # call trigger above. Often, this can be very annoying (and can make some
+ # searches impossible), so we add the value the user was typing back into
+ # the input field.
+ field.val(untrimmed_val)
+
+ # Because non-ajax Chosen isn't constantly re-building results, when it
+ # DOES rebuild results (during liszt:updated above, it clears the input
+ # search field before scaling it. This causes the input field width to be
+ # at it's minimum, which is about 25px.
+
+ # The proper way to fix this would be create a new method in chosen for
+ # rebuilding results without clearing the input field. Or to call
+ # Chosen.search_field_scale() after resetting the value above. This isn't
+ # possible with the current state of Chosen. The quick fix is to simply reset
+ # the width of the field after we reset the value of the input text.
+ # field.css('width','auto')
+
+ # Execute the ajax call to search for autocomplete data with a timer
+ @timer = setTimeout ->
+ chosenXhr.abort() if chosenXhr
+ chosenXhr = $.ajax(options)
+ , options.afterTypeDelay
diff --git a/vendor/assets/javascripts/chosen-prototype.js b/vendor/assets/javascripts/chosen-prototype.js
deleted file mode 100644
index 3d7bcfeabb..0000000000
--- a/vendor/assets/javascripts/chosen-prototype.js
+++ /dev/null
@@ -1,3 +0,0 @@
-//= require lib/abstract-chosen
-//= require lib/select-parser
-//= require chosen.proto
diff --git a/vendor/assets/javascripts/chosen.jquery.coffee b/vendor/assets/javascripts/chosen.jquery.coffee
index a84ead59ad..253f246c72 100644
--- a/vendor/assets/javascripts/chosen.jquery.coffee
+++ b/vendor/assets/javascripts/chosen.jquery.coffee
@@ -347,7 +347,7 @@ class Chosen extends AbstractChosen
@search_field.val ""
- @form_field_jq.trigger "change"
+ @form_field_jq.trigger "change", {'selected': @form_field.options[item.options_index].value} if @is_multiple || @form_field.selectedIndex != @current_selectedIndex
this.search_field_scale()
else if @options.allow_option_creation
new_option = @search_field.val()
@@ -384,7 +384,7 @@ class Chosen extends AbstractChosen
this.result_clear_highlight()
this.winnow_results()
- @form_field_jq.trigger "change"
+ @form_field_jq.trigger "change", {deselected: @form_field.options[result_data.options_index].value}
this.search_field_scale()
single_deselect_control_build: ->
diff --git a/vendor/assets/javascripts/chosen.proto.coffee b/vendor/assets/javascripts/chosen.proto.coffee
deleted file mode 100644
index 3c708a10b0..0000000000
--- a/vendor/assets/javascripts/chosen.proto.coffee
+++ /dev/null
@@ -1,580 +0,0 @@
-###
-Chosen source: generate output using 'cake build'
-Copyright (c) 2011 by Harvest
-###
-root = this
-
-class Chosen extends AbstractChosen
-
- setup: ->
- @is_rtl = @form_field.hasClassName "chzn-rtl"
-
- finish_setup: ->
- @form_field.addClassName "chzn-done"
-
- set_default_values: ->
- super()
-
- # HTML Templates
- @single_temp = new Template('#{default}
')
- @multi_temp = new Template('')
- @choice_temp = new Template('#{choice} ')
- @no_results_temp = new Template('' + @results_none_found + ' "#{terms} " ')
-
- set_up_html: ->
- @container_id = @form_field.identify().replace(/(:|\.)/g, '_') + "_chzn"
-
- @f_width = if @form_field.getStyle("width") then parseInt @form_field.getStyle("width"), 10 else @form_field.getWidth()
-
- container_props =
- 'id': @container_id
- 'class': "chzn-container#{ if @is_rtl then ' chzn-rtl' else '' }"
- 'style': 'width: ' + (@f_width) + 'px' #use parens around @f_width so coffeescript doesn't think + ' px' is a function parameter
-
- @default_text = if @form_field.readAttribute 'data-placeholder' then @form_field.readAttribute 'data-placeholder' else @default_text_default
-
- base_template = if @is_multiple then new Element('div', container_props).update( @multi_temp.evaluate({ "default": @default_text}) ) else new Element('div', container_props).update( @single_temp.evaluate({ "default":@default_text }) )
-
- @form_field.hide().insert({ after: base_template })
- @container = $(@container_id)
- @container.addClassName( "chzn-container-" + (if @is_multiple then "multi" else "single") )
- @container.addClassName "chzn-container-single-nosearch" if not @is_multiple and @form_field.options.length <= @disable_search_threshold
- @dropdown = @container.down('div.chzn-drop')
-
- dd_top = @container.getHeight()
- dd_width = (@f_width - get_side_border_padding(@dropdown))
-
- @dropdown.setStyle({"width": dd_width + "px", "top": dd_top + "px"})
-
- @search_field = @container.down('input')
- @search_results = @container.down('ul.chzn-results')
- this.search_field_scale()
-
- @search_no_results = @container.down('li.no-results')
-
- if @is_multiple
- @search_choices = @container.down('ul.chzn-choices')
- @search_container = @container.down('li.search-field')
- else
- @search_container = @container.down('div.chzn-search')
- @selected_item = @container.down('.chzn-single')
- sf_width = dd_width - get_side_border_padding(@search_container) - get_side_border_padding(@search_field)
- @search_field.setStyle( {"width" : sf_width + "px"} )
-
- this.results_build()
- this.set_tab_index()
- @form_field.fire("liszt:ready", {chosen: this})
-
- register_observers: ->
- @container.observe "mousedown", (evt) => this.container_mousedown(evt)
- @container.observe "mouseup", (evt) => this.container_mouseup(evt)
- @container.observe "mouseenter", (evt) => this.mouse_enter(evt)
- @container.observe "mouseleave", (evt) => this.mouse_leave(evt)
-
- @search_results.observe "mouseup", (evt) => this.search_results_mouseup(evt)
- @search_results.observe "mouseover", (evt) => this.search_results_mouseover(evt)
- @search_results.observe "mouseout", (evt) => this.search_results_mouseout(evt)
-
- @form_field.observe "liszt:updated", (evt) => this.results_update_field(evt)
-
- @search_field.observe "blur", (evt) => this.input_blur(evt)
- @search_field.observe "keyup", (evt) => this.keyup_checker(evt)
- @search_field.observe "keydown", (evt) => this.keydown_checker(evt)
-
- if @is_multiple
- @search_choices.observe "click", (evt) => this.choices_click(evt)
- @search_field.observe "focus", (evt) => this.input_focus(evt)
-
- search_field_disabled: ->
- @is_disabled = @form_field.disabled
- if(@is_disabled)
- @container.addClassName 'chzn-disabled'
- @search_field.disabled = true
- @selected_item.stopObserving "focus", @activate_action if !@is_multiple
- this.close_field()
- else
- @container.removeClassName 'chzn-disabled'
- @search_field.disabled = false
- @selected_item.observe "focus", @activate_action if !@is_multiple
-
- container_mousedown: (evt) ->
- if !@is_disabled
- target_closelink = if evt? then evt.target.hasClassName "search-choice-close" else false
- if evt and evt.type is "mousedown" and not @results_showing
- evt.stop()
- if not @pending_destroy_click and not target_closelink
- if not @active_field
- @search_field.clear() if @is_multiple
- document.observe "click", @click_test_action
- this.results_show()
- else if not @is_multiple and evt and (evt.target is @selected_item || evt.target.up("a.chzn-single"))
- this.results_toggle()
-
- this.activate_field()
- else
- @pending_destroy_click = false
-
- container_mouseup: (evt) ->
- this.results_reset(evt) if evt.target.nodeName is "ABBR"
-
- blur_test: (evt) ->
- this.close_field() if not @active_field and @container.hasClassName("chzn-container-active")
-
- close_field: ->
- document.stopObserving "click", @click_test_action
-
- if not @is_multiple
- @selected_item.tabIndex = @search_field.tabIndex
- @search_field.tabIndex = -1
-
- @active_field = false
- this.results_hide()
-
- @container.removeClassName "chzn-container-active"
- this.winnow_results_clear()
- this.clear_backstroke()
-
- this.show_search_field_default()
- this.search_field_scale()
-
- activate_field: ->
- if not @is_multiple and not @active_field
- @search_field.tabIndex = @selected_item.tabIndex
- @selected_item.tabIndex = -1
-
- @container.addClassName "chzn-container-active"
- @active_field = true
-
- @search_field.value = @search_field.value
- @search_field.focus()
-
-
- test_active_click: (evt) ->
- if evt.target.up('#' + @container_id)
- @active_field = true
- else
- this.close_field()
-
- results_build: ->
- startTime = new Date()
- @parsing = true
- @results_data = root.SelectParser.select_to_array @form_field
-
- if @is_multiple and @choices > 0
- @search_choices.select("li.search-choice").invoke("remove")
- @choices = 0
- else if not @is_multiple
- @selected_item.down("span").update(@default_text)
-
- content = ''
- for data in @results_data
- if data.group
- content += this.result_add_group data
- else if !data.empty
- content += this.result_add_option data
- if data.selected and @is_multiple
- this.choice_build data
- else if data.selected and not @is_multiple
- @selected_item.down("span").update( data.html )
- this.single_deselect_control_build() if @allow_single_deselect
-
- this.search_field_disabled()
- this.show_search_field_default()
- this.search_field_scale()
-
- @search_results.update content
- @parsing = false
-
-
- result_add_group: (group) ->
- if not group.disabled
- group.dom_id = @container_id + "_g_" + group.array_index
- '' + group.label.escapeHTML() + ' '
- else
- ""
-
- result_do_highlight: (el) ->
- this.result_clear_highlight()
-
- @result_highlight = el
- @result_highlight.addClassName "highlighted"
-
- maxHeight = parseInt @search_results.getStyle('maxHeight'), 10
- visible_top = @search_results.scrollTop
- visible_bottom = maxHeight + visible_top
-
- high_top = @result_highlight.positionedOffset().top
- high_bottom = high_top + @result_highlight.getHeight()
-
- if high_bottom >= visible_bottom
- @search_results.scrollTop = if (high_bottom - maxHeight) > 0 then (high_bottom - maxHeight) else 0
- else if high_top < visible_top
- @search_results.scrollTop = high_top
-
- result_clear_highlight: ->
- @result_highlight.removeClassName('highlighted') if @result_highlight
- @result_highlight = null
-
- results_show: ->
- if not @is_multiple
- @selected_item.addClassName('chzn-single-with-drop')
- if @result_single_selected
- this.result_do_highlight( @result_single_selected )
-
- dd_top = if @is_multiple then @container.getHeight() else (@container.getHeight() - 1)
- @dropdown.setStyle {"top": dd_top + "px", "left":0}
- @results_showing = true
-
- @search_field.focus()
- @search_field.value = @search_field.value
-
- this.winnow_results()
-
- results_hide: ->
- @selected_item.removeClassName('chzn-single-with-drop') unless @is_multiple
- this.result_clear_highlight()
- @dropdown.setStyle({"left":"-9000px"})
- @results_showing = false
-
-
- set_tab_index: (el) ->
- if @form_field.tabIndex
- ti = @form_field.tabIndex
- @form_field.tabIndex = -1
-
- if @is_multiple
- @search_field.tabIndex = ti
- else
- @selected_item.tabIndex = ti
- @search_field.tabIndex = -1
-
- show_search_field_default: ->
- if @is_multiple and @choices < 1 and not @active_field
- @search_field.value = @default_text
- @search_field.addClassName "default"
- else
- @search_field.value = ""
- @search_field.removeClassName "default"
-
- search_results_mouseup: (evt) ->
- target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
- if target
- @result_highlight = target
- this.result_select(evt)
-
- search_results_mouseover: (evt) ->
- target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
- this.result_do_highlight( target ) if target
-
- search_results_mouseout: (evt) ->
- this.result_clear_highlight() if evt.target.hasClassName('active-result') or evt.target.up('.active-result')
-
-
- choices_click: (evt) ->
- evt.preventDefault()
- if( @active_field and not(evt.target.hasClassName('search-choice') or evt.target.up('.search-choice')) and not @results_showing )
- this.results_show()
-
- choice_build: (item) ->
- choice_id = @container_id + "_c_" + item.array_index
- @choices += 1
- @search_container.insert
- before: @choice_temp.evaluate
- id: choice_id
- choice: item.html
- position: item.array_index
- link = $(choice_id).down('a')
- link.observe "click", (evt) => this.choice_destroy_link_click(evt)
-
- choice_destroy_link_click: (evt) ->
- evt.preventDefault()
- if not @is_disabled
- @pending_destroy_click = true
- this.choice_destroy evt.target
-
- choice_destroy: (link) ->
- @choices -= 1
- this.show_search_field_default()
-
- this.results_hide() if @is_multiple and @choices > 0 and @search_field.value.length < 1
-
- this.result_deselect link.readAttribute("rel")
- link.up('li').remove()
-
- results_reset: (evt) ->
- @form_field.options[0].selected = true
- @selected_item.down("span").update(@default_text)
- this.show_search_field_default()
- evt.target.remove()
- @form_field.simulate("change") if typeof Event.simulate is 'function'
- this.results_hide() if @active_field
-
- result_select: (evt) ->
- if @result_highlight
- high = @result_highlight
- this.result_clear_highlight()
-
- if @is_multiple
- this.result_deactivate high
- else
- @search_results.descendants(".result-selected").invoke "removeClassName", "result-selected"
- @result_single_selected = high
-
- high.addClassName("result-selected")
-
- position = high.id.substr(high.id.lastIndexOf("_") + 1 )
- item = @results_data[position]
- item.selected = true
-
- @form_field.options[item.options_index].selected = true
-
- if @is_multiple
- this.choice_build item
- else
- @selected_item.down("span").update(item.html)
- this.single_deselect_control_build() if @allow_single_deselect
-
- @on_option_add(item.value) if @on_option_add
-
- this.results_hide() unless evt.metaKey and @is_multiple
-
- @search_field.value = ""
-
- @form_field.simulate("change") if typeof Event.simulate is 'function'
- this.search_field_scale()
- else if @options.allow_option_creation
- new_option = @search_field.value
- return unless new_option
- if @allow_creation(new_option)
- @form_field.insert(Element('option', {selected: true, value: new_option}).update(new_option))
- @results_update_field(evt)
- @on_option_add(new_option) if @on_option_add
- @form_field.simulate("change") if typeof Event.simulate is 'function'
- @search_field.value = ""
- @results_hide()
-
- allow_creation: (new_option) ->
- if @is_multiple
- matches = @search_choices.getElementsBySelector("li.search-choice span").select (el) ->
- console.debug(el)
- el.innerHTML.toLowerCase() == new_option.toLowerCase()
- console.debug(matches)
- !matches.length
- else
- @selected_item.getElementsBySelector('span').innerHTML.toLowerCase() != new_option.toLowerCase()
-
- result_activate: (el) ->
- el.addClassName("active-result")
-
- result_deactivate: (el) ->
- el.removeClassName("active-result")
-
- result_deselect: (pos) ->
- result_data = @results_data[pos]
- result_data.selected = false
-
- option = @form_field.options[result_data.options_index]
- option.selected = false
- @on_option_remove(option.value) if @on_option_remove
-
- result = $(@container_id + "_o_" + pos)
- result.removeClassName("result-selected").addClassName("active-result").show()
-
- this.result_clear_highlight()
- this.winnow_results()
-
- @form_field.simulate("change") if typeof Event.simulate is 'function'
- this.search_field_scale()
-
- single_deselect_control_build: ->
- @selected_item.down("span").insert { after: " " } if @allow_single_deselect and not @selected_item.down("abbr")
-
- winnow_results: ->
- startTime = new Date()
- this.no_results_clear()
-
- results = 0
-
- searchText = if @search_field.value is @default_text then "" else @search_field.value.strip().escapeHTML()
- textToSearch = searchText.replace(/[\-\[\]\{\}\(\)\*\+\?\.,\\\^\$\|\#\s]/g, "\\$&")
- regex = new RegExp('^' + textToSearch, 'i')
- zregex = new RegExp(textToSearch, 'i')
- fregex = new RegExp("^" + textToSearch + "$", 'i')
-
- for option in @results_data
- if not option.disabled and not option.empty
- if option.group
- $(option.dom_id).hide()
- else if not (@is_multiple and option.selected)
- found = false
- result_id = option.dom_id
-
- if @options.allow_option_creation && searchText && fregex.test(option.html)
- found = true
- results += 1
- @result_do_highlight($(option.dom_id))
- else if regex.test option.html
- found = true
- results += 1
- else if option.html.indexOf(" ") >= 0 or option.html.indexOf("[") == 0
- #TODO: replace this substitution of /\[\]/ with a list of characters to skip.
- parts = option.html.replace(/\[|\]/g, "").split(" ")
- if parts.length
- for part in parts
- if regex.test part
- found = true
- results += 1
-
- if found
- if searchText.length
- startpos = option.html.search zregex
- text = option.html.substr(0, startpos + searchText.length) + '' + option.html.substr(startpos + searchText.length)
- text = text.substr(0, startpos) + '' + text.substr(startpos)
- else
- text = option.html
-
- $(result_id).update text if $(result_id).innerHTML != text
-
- this.result_activate $(result_id)
-
- $(@results_data[option.group_array_index].dom_id).show() if option.group_array_index?
- else
- this.result_clear_highlight() if $(result_id) is @result_highlight
- this.result_deactivate $(result_id)
-
- if results < 1 and searchText.length
- this.no_results(searchText)
- @results_hide() if @options.allow_option_creation && @is_multiple
- else if not @options.allow_option_creation
- this.winnow_results_set_highlight()
-
- winnow_results_clear: ->
- @search_field.clear()
- lis = @search_results.select("li")
-
- for li in lis
- if li.hasClassName("group-result")
- li.show()
- else if not @is_multiple or not li.hasClassName("result-selected")
- this.result_activate li
-
- winnow_results_set_highlight: ->
- if not @result_highlight
-
- if not @is_multiple
- do_high = @search_results.down(".result-selected.active-result")
-
- if not do_high?
- do_high = @search_results.down(".active-result")
-
- this.result_do_highlight do_high if do_high?
-
- no_results: (terms) ->
- return if !@is_multiple && @options.allow_option_creation
- @search_results.insert @no_results_temp.evaluate( terms: terms )
-
- no_results_clear: ->
- nr = null
- nr.remove() while nr = @search_results.down(".no-results")
-
-
- keydown_arrow: ->
- actives = @search_results.select("li.active-result")
- if actives.length
- if not @result_highlight
- this.result_do_highlight actives.first()
- else if @results_showing
- sibs = @result_highlight.nextSiblings()
- nexts = sibs.intersect(actives)
- this.result_do_highlight nexts.first() if nexts.length
- this.results_show() if not @results_showing
-
- keyup_arrow: ->
- if not @results_showing and not @is_multiple
- this.results_show()
- else if @result_highlight
- sibs = @result_highlight.previousSiblings()
- actives = @search_results.select("li.active-result")
- prevs = sibs.intersect(actives)
-
- if prevs.length
- this.result_do_highlight prevs.first()
- else
- this.results_hide() if @choices > 0
- this.result_clear_highlight()
-
- keydown_backstroke: ->
- if @pending_backstroke
- this.choice_destroy @pending_backstroke.down("a")
- this.clear_backstroke()
- else
- @pending_backstroke = @search_container.siblings("li.search-choice").last()
- @pending_backstroke.addClassName("search-choice-focus")
-
- clear_backstroke: ->
- @pending_backstroke.removeClassName("search-choice-focus") if @pending_backstroke
- @pending_backstroke = null
-
- keydown_checker: (evt) ->
- stroke = evt.which ? evt.keyCode
- this.search_field_scale()
-
- this.clear_backstroke() if stroke != 8 and this.pending_backstroke
-
- switch stroke
- when 8
- @backstroke_length = this.search_field.value.length
- break
- when 9
- this.result_select(evt) if this.results_showing and not @is_multiple
- @mouse_on_container = false
- break
- when 13
- evt.preventDefault()
- break
- when 38
- evt.preventDefault()
- this.keyup_arrow()
- break
- when 40
- this.keydown_arrow()
- break
-
- search_field_scale: ->
- if @is_multiple
- h = 0
- w = 0
-
- style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"
- styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing']
-
- for style in styles
- style_block += style + ":" + @search_field.getStyle(style) + ";"
-
- div = new Element('div', { 'style' : style_block }).update(@search_field.value.escapeHTML())
- document.body.appendChild(div)
-
- w = Element.measure(div, 'width') + 25
- div.remove()
-
- if( w > @f_width-10 )
- w = @f_width - 10
-
- @search_field.setStyle({'width': w + 'px'})
-
- dd_top = @container.getHeight()
- @dropdown.setStyle({"top": dd_top + "px"})
-
-root.Chosen = Chosen
-
-# Prototype does not support version numbers so we add it ourselves
-if Prototype.Browser.IE
- if /MSIE (\d+\.\d+);/.test(navigator.userAgent)
- Prototype.BrowserFeatures['Version'] = new Number(RegExp.$1);
-
-
-get_side_border_padding = (elmt) ->
- layout = new Element.Layout(elmt)
- side_border_padding = layout.get("border-left") + layout.get("border-right") + layout.get("padding-left") + layout.get("padding-right")
-
-root.get_side_border_padding = get_side_border_padding
diff --git a/vendor/assets/javascripts/event.simulate.js b/vendor/assets/javascripts/event.simulate.js
deleted file mode 100644
index 22b33d6bff..0000000000
--- a/vendor/assets/javascripts/event.simulate.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Event.simulate(@element, eventName[, options]) -> Element
- *
- * - @element: element to fire event on
- * - eventName: name of event to fire (only MouseEvents and HTMLEvents interfaces are supported)
- * - options: optional object to fine-tune event properties - pointerX, pointerY, ctrlKey, etc.
- *
- * $('foo').simulate('click'); // => fires "click" event on an element with id=foo
- *
- **/
-(function(){
-
- var eventMatchers = {
- 'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
- 'MouseEvents': /^(?:click|mouse(?:down|up|over|move|out))$/
- }
- var defaultOptions = {
- pointerX: 0,
- pointerY: 0,
- button: 0,
- ctrlKey: false,
- altKey: false,
- shiftKey: false,
- metaKey: false,
- bubbles: true,
- cancelable: true
- }
-
- Event.simulate = function(element, eventName) {
- var options = Object.extend(defaultOptions, arguments[2] || { });
- var oEvent, eventType = null;
-
- element = $(element);
-
- for (var name in eventMatchers) {
- if (eventMatchers[name].test(eventName)) { eventType = name; break; }
- }
-
- if (!eventType)
- throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');
-
- if (document.createEvent) {
- oEvent = document.createEvent(eventType);
- if (eventType == 'HTMLEvents') {
- oEvent.initEvent(eventName, options.bubbles, options.cancelable);
- }
- else {
- oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
- options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
- options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
- }
- element.dispatchEvent(oEvent);
- }
- else {
- options.clientX = options.pointerX;
- options.clientY = options.pointerY;
- oEvent = Object.extend(document.createEventObject(), options);
- element.fireEvent('on' + eventName, oEvent);
- }
- return element;
- }
-
- Element.addMethods({ simulate: Event.simulate });
-})()
diff --git a/vendor/assets/javascripts/facebooklist.js b/vendor/assets/javascripts/facebooklist.js
deleted file mode 100644
index 7f3f79c0ed..0000000000
--- a/vendor/assets/javascripts/facebooklist.js
+++ /dev/null
@@ -1,548 +0,0 @@
-
-/*
- Proto!MultiSelect
- Copyright: InteRiders - Distributed under MIT - Keep this message!
-*/
-
-// Added key contstant for COMMA watching happiness
-Object.extend(Event, {
- KEY_COMMA: {code: 188, value:","},
- KEY_SPACE: {code: 32, value:" "}
-});
-
-var ResizableTextbox = Class.create({
- initialize: function(element, options) {
- var that = this;
- this.options = $H({
- min: 5,
- max: 500,
- step: 7
- });
- this.options.update(options);
- this.el = $(element);
- this.width = this.el.offsetWidth;
- this.el.observe(
- 'keyup', function() {
- var newsize = that.options.get('step') * $F(this).length;
- if(newsize <= that.options.get('min')) newsize = that.width;
- if(! ($F(this).length == this.retrieveData('rt-value') || newsize <= that.options.min || newsize >= that.options.max))
- this.setStyle({'width': newsize});
- }).observe('keydown', function() {
- this.cacheData('rt-value', $F(this).length);
- }
- );
- }
-});
-
-var TextboxList = Class.create({
- initialize: function(element, options) {
- this.options = $H({/*
- onFocus: $empty,
- onBlur: $empty,
- onInputFocus: $empty,
- onInputBlur: $empty,
- onBoxFocus: $empty,
- onBoxBlur: $empty,
- onBoxDispose: $empty,*/
- resizable: {},
- className: 'bit',
- separator: Event.KEY_COMMA,
- tabindex: null,
- extrainputs: true,
- startinput: true,
- hideempty: true,
- newValues: false,
- newValueDelimiters: ['[',']'],
- spaceReplace: '',
- fetchFile: undefined,
- fetchMethod: 'get',
- results: 10,
- maxResults: 0, // 0 = set to default (which is 10 (see FacebookList class)),
- wordMatch: false,
- onEmptyInput: function(input){},
- onAdd: function(tag){},
- onDispose: function(tag){},
- caseSensitive: false,
- regexSearch: true
- });
- this.current_input = "";
- this.options.update(options);
- this.element = $(element).hide();
- this.bits = new Hash();
- this.events = new Hash();
- this.count = 0;
- this.current = false;
- this.maininput = this.createInput({className: 'maininput'});
- this.maininput.addClassName('maininput');
- this.holder = new Element('ul', {
- className: 'holder'
- }).insert(this.maininput);
- if(this.options.get('tabindex')) {
- this.maininput.down('input').writeAttribute('tabindex', this.options.get('tabindex'));
- }
- this.element.insert({'before':this.holder});
- this.holder.observe('click', function(event){
- event.stop();
- if(this.maininput != this.current) this.focus(this.maininput);
- }.bind(this));
- this.makeResizable(this.maininput);
- this.setEvents();
- },
-
- setEvents: function() {
- document.observe(Prototype.Browser.IE ? 'keydown' : 'keypress', function(e) {
- if(! this.current) return;
- if(this.current.retrieveData('type') == 'box' && e.keyCode == Event.KEY_BACKSPACE) e.stop();
- }.bind(this));
-
- document.observe(
- 'keyup', function(e) {
- e.stop();
- if(! this.current) return;
- switch(e.keyCode){
- case Event.KEY_LEFT: return this.move('left');
- case Event.KEY_RIGHT: return this.move('right');
- case Event.KEY_DELETE:
- case Event.KEY_BACKSPACE: return this.moveDispose();
- }
- }.bind(this)).observe(
- 'click', function() { document.fire('blur'); }.bindAsEventListener(this)
- );
- },
-
- update: function() {
- this.element.value = this.bits.values().join(this.options.get('separator').value);
- if (!this.current_input.blank()){
- this.element.value += (this.element.value.blank() ? "" : this.options.get('separator').value) + this.current_input;
- }
- return this;
- },
-
- add: function(text, html) {
- var id = this.id_base + '-' + this.count++;
- var el = this.createBox($pick(html, text), {'id': id, 'class': this.options.get('className'), 'newValue' : text.newValue ? 'true' : 'false'});
- (this.current || this.maininput).insert({'before':el});
- el.observe('click', function(e) {
- e.stop();
- this.focus(el);
- }.bind(this));
- this.bits.set(id, text.value);
- // Dynamic updating... why not?
- this.update();
- if(this.options.get('extrainputs') && (this.options.get('startinput') || el.previous())) this.addSmallInput(el,'before');
- this.options.get('onAdd')(text.value, el);
- return el;
- },
-
- addSmallInput: function(el, where) {
- var input = this.createInput({'class': 'smallinput'});
- el.insert({}[where] = input);
- input.cacheData('small', true);
- this.makeResizable(input);
- if(this.options.get('hideempty')) input.hide();
- return input;
- },
-
- dispose: function(el) {
- this.options.get('onDispose')(this.bits.get(el.id));
- this.bits.unset(el.id);
- // Dynamic updating... why not?
- this.update();
- if(el.previous() && el.previous().retrieveData('small')) el.previous().remove();
- if(this.current == el) this.focus(el.next());
- if(el.retrieveData('type') == 'box') el.onBoxDispose(this);
- el.remove();
- return this;
- },
-
- focus: function(el, nofocus) {
- if(! this.current) el.fire('focus');
- else if(this.current == el) return this;
- this.blur();
- el.addClassName(this.options.get('className') + '-' + el.retrieveData('type') + '-focus');
- if(el.retrieveData('small')) el.setStyle({'display': 'block'});
- if(el.retrieveData('type') == 'input') {
- el.onInputFocus(this);
- if(! nofocus) this.callEvent(el.retrieveData('input'), 'focus');
- }
- else el.fire('onBoxFocus');
- this.current = el;
- return this;
- },
-
- blur: function(noblur) {
- if(! this.current) return this;
- if(this.current.retrieveData('type') == 'input') {
- var input = this.current.retrieveData('input');
- if(! noblur) this.callEvent(input, 'blur');
- input.onInputBlur(this);
- }
- else this.current.fire('onBoxBlur');
- if(this.current.retrieveData('small') && ! input.get('value') && this.options.get('hideempty'))
- this.current.hide();
- this.current.removeClassName(this.options.get('className') + '-' + this.current.retrieveData('type') + '-focus');
- this.current = false;
- return this;
- },
-
- createBox: function(text, options) {
- var box = new Element('li', options).addClassName(this.options.get('className') + '-box').update(text.caption).cacheData('type', 'box');
- return box;
- },
-
- createInput: function(options) {
- var opts = Object.extend(options,{'type': 'text', 'autocomplete':'off'});
- var li = new Element('li', {className: this.options.get('className') + '-input'});
- var el = new Element('input', options);
- el.observe('click', function(e) { e.stop(); }).observe('focus', function(e) { if(! this.isSelfEvent('focus')) this.focus(li, true); }.bind(this)).observe('blur', function() { if(! this.isSelfEvent('blur')) this.blur(true); }.bind(this)).observe('keydown', function(e) { this.cacheData('lastvalue', this.value).cacheData('lastcaret', this.getCaretPosition()); });
- var tmp = li.cacheData('type', 'input').cacheData('input', el).insert(el);
- return tmp;
- },
-
- callEvent: function(el, type) {
- this.events.set(type, el);
- el[type]();
- },
-
- isSelfEvent: function(type) {
- return (this.events.get(type)) ? !! this.events.unset(type) : false;
- },
-
- makeResizable: function(li) {
- var el = li.retrieveData('input');
- el.cacheData('resizable', new ResizableTextbox(el, Object.extend(this.options.get('resizable'),{min: el.offsetWidth, max: (this.element.getWidth()?this.element.getWidth():50)})));
- return this;
- },
-
- checkInput: function() {
- var input = this.current.retrieveData('input');
- return (! input.retrieveData('lastvalue') || (input.getCaretPosition() === 0 && input.retrieveData('lastcaret') === 0));
- },
-
- move: function(direction) {
- var el = this.current[(direction == 'left' ? 'previous' : 'next')]();
- if(el && (! this.current.retrieveData('input') || ((this.checkInput() || direction == 'right')))) this.focus(el);
- return this;
- },
-
- moveDispose: function() {
- if(this.current.retrieveData('type') == 'box') return this.dispose(this.current);
- if(this.checkInput() && this.bits.keys().length && this.current.previous()) return this.focus(this.current.previous());
- }
-});
-
-//helper functions
-Element.addMethods({
- getCaretPosition: function() {
- if (this.createTextRange) {
- var r = document.selection.createRange().duplicate();
- r.moveEnd('character', this.value.length);
- if (r.text === '') return this.value.length;
- return this.value.lastIndexOf(r.text);
- } else return this.selectionStart;
- },
- cacheData: function(element, key, value) {
- if (Object.isUndefined(this[$(element).identify()]) || !Object.isHash(this[$(element).identify()]))
- this[$(element).identify()] = $H();
- this[$(element).identify()].set(key,value);
- return element;
- },
- retrieveData: function(element,key) {
- return this[$(element).identify()].get(key);
- }
-});
-
-function $pick(){for(var B=0,A=arguments.length;B= 0) {
- matches[matches_found++] = this.data[i];
- }
- }
- }
- } else {
- if (this.options.get('wordMatch')) {
- var regexp = new RegExp("(^|\\s)"+search,(!this.options.get('caseSensitive') ? 'i' : ''));
- } else {
- var regexp = new RegExp(search,(!this.options.get('caseSensitive') ? 'i' : ''));
- var matches = this.data.filter(
- function(str) {
- return str ? regexp.test(str.evalJSON(true).caption) : false;
- });
- }
- }
-
- var count = 0;
- matches = matches.compact();
- matches = matches.sortBy(function(m) {
- m = m.evalJSON(true);
- return m.value.startsWith(search);
- }).reverse();
- matches.each(
- function(result, ti) {
- count++;
- if(ti >= (this.options.get('maxResults') ? this.options.get('maxResults') : this.loptions.get('autocomplete').maxresults)) return;
- var that = this;
- var el = new Element('li');
- el.observe('click',function(e) {
- e.stop();
- that.current_input = "";
- that.autoAdd(this);
- }
- ).observe('mouseover', function() { that.autoFocus(this); } ).update(
- this.autoHighlight(result.evalJSON(true).caption, search)
- );
- this.autoresults.insert(el);
- el.cacheData('result', result.evalJSON(true));
- if(ti == 0) this.autoFocus(el);
- },
- this
- );
- }
- if (count == 0) {
- // if there are no results, hide everything so that KEY_ENTER has no effect
- this.autoHide();
- } else {
- if (count > this.options.get('results'))
- this.autoresults.setStyle({'height': (this.options.get('results')*24)+'px'});
- else
- this.autoresults.setStyle({'height': (count?(count*24):0)+'px'});
- }
-
- return this;
- },
-
- autoHighlight: function(html, highlight) {
- return html.gsub(new RegExp(highlight,'i'), function(match) {
- return '' + match[0] + ' ';
- });
- },
-
- autoHide: function() {
- this.resultsshown = false;
- this.autoholder.hide();
- return this;
- },
-
- autoFocus: function(el) {
- if(! el) return;
- if(this.autocurrent) this.autocurrent.removeClassName('auto-focus');
- this.autocurrent = el.addClassName('auto-focus');
- return this;
- },
-
- autoMove: function(direction) {
- if(!this.resultsshown) return;
- this.autoFocus(this.autocurrent[(direction == 'up' ? 'previous' : 'next')]());
- this.autoresults.scrollTop = this.autocurrent.positionedOffset()[1]-this.autocurrent.getHeight();
- return this;
- },
-
- autoFeed: function(text) {
- var with_case = this.options.get('caseSensitive');
- if (this.data.indexOf(Object.toJSON(text)) == -1) {
- this.data.push(Object.toJSON(text));
- this.data_searchable.push(with_case ? Object.toJSON(text).evalJSON(true).caption : Object.toJSON(text).evalJSON(true).caption.toLowerCase());
- }
- return this;
- },
-
- autoAdd: function(el) {
- if(this.newvalue && this.options.get("newValues")) {
- this.add({caption: el.value, value: el.value, newValue: true});
- var input = el;
- } else if(!el || ! el.retrieveData('result')) {
- return;
- } else {
- this.add(el.retrieveData('result'));
- delete this.data[this.data.indexOf(Object.toJSON(el.retrieveData('result')))];
- var input = this.lastinput || this.current.retrieveData('input');
- }
- this.autoHide();
- input.clear().focus();
- return this;
- },
-
- createInput: function($super,options) {
- var li = $super(options);
- var input = li.retrieveData('input');
-
- if(options['className'] == "maininput") {
- // Give the input a hook for our cucumber tests to use.
- input.setAttribute('name', 'fblist-maininput');
- };
-
- input.observe('keydown', function(e) {
- this.dosearch = false;
- this.newvalue = false;
-
- switch(e.keyCode) {
- case Event.KEY_UP: e.stop(); return this.autoMove('up');
- case Event.KEY_DOWN: e.stop(); return this.autoMove('down');
-
- case Event.KEY_RETURN:
- // If the text input is blank and the user hits Enter call the
- // onEmptyInput callback.
- if (String('').valueOf() == String(this.current.retrieveData('input').getValue()).valueOf()) {
- this.options.get("onEmptyInput")();
- }
- e.stop();
- if(!this.autocurrent || !this.resultsshown) break;
- this.current_input = "";
- this.autoAdd(this.autocurrent);
- this.autocurrent = false;
- this.autoenter = true;
- break;
- case Event.KEY_ESC:
- this.autoHide();
- if(this.current && this.current.retrieveData('input'))
- this.current.retrieveData('input').clear();
- break;
- default:
- this.dosearch = true;
- }
- }.bind(this));
- input.observe('keyup',function(e) {
- var code = this.options.get('separator').code;
- var splitOn = this.options.get('separator').value;
- switch(e.keyCode) {
- case code:
- if(this.options.get('newValues')) {
- new_value_el = this.current.retrieveData('input');
- if (!new_value_el.value.endsWith('<')) {
- keep_input = "";
- if (new_value_el.value.indexOf(splitOn) < (new_value_el.value.length - splitOn.length)){
- separator_pos = new_value_el.value.indexOf(splitOn);
- keep_input = new_value_el.value.substr(separator_pos + 1);
- new_value_el.value = new_value_el.value.substr(0,separator_pos).escapeHTML().strip();
- } else {
- new_value_el.value = new_value_el.value.gsub(splitOn,"").escapeHTML().strip();
- }
- if(!this.options.get("spaceReplace").blank()) new_value_el.value.gsub(" ", this.options.get("spaceReplace"));
- if(!new_value_el.value.blank()) {
- e.stop();
- this.newvalue = true;
- this.current_input = keep_input.escapeHTML().strip();
- this.autoAdd(new_value_el);
- input.value = keep_input;
- this.update();
- }
- }
- }
- break;
- case Event.KEY_UP:
- case Event.KEY_DOWN:
- case Event.KEY_RETURN:
- case Event.KEY_ESC:
- break;
- default:
- // If the user doesn't add comma after, the value is discarded upon submit
- this.current_input = input.value.strip().escapeHTML();
- this.update();
-
- // Removed Ajax.Request from here and moved to initialize,
- // now doesn't create server queries every search but only
- // refreshes the list on initialize (page load)
- if(this.searchTimeout) clearTimeout(this.searchTimeout);
- this.searchTimeout = setTimeout(function(){
- var sanitizer = new RegExp("[({[^$*+?\\\]})]","g");
- if(this.dosearch) this.autoShow(input.value.replace(sanitizer,"\\$1"));
- }.bind(this), 250);
- }
- }.bind(this));
- input.observe(Prototype.Browser.IE ? 'keydown' : 'keypress', function(e) {
- if ((e.keyCode == Event.KEY_RETURN) && this.autoenter) e.stop();
- this.autoenter = false;
- }.bind(this));
- return li;
- },
-
- createBox: function($super,text, options) {
- var li = $super(text, options);
- li.observe('mouseover',function() {
- this.addClassName('bit-hover');
- }).observe('mouseout',function() {
- this.removeClassName('bit-hover');
- });
- var a = new Element('a', {
- 'href': '#',
- 'class': 'closebutton'
- });
- a.observe('click',function(e) {
- e.stop();
- if(! this.current) this.focus(this.maininput);
- this.dispose(li);
- }.bind(this));
- li.insert(a).cacheData('text', Object.toJSON(text));
- return li;
- }
-});
-
-Element.addMethods({
- onBoxDispose: function(item,obj) {
- // Set to not to "add back" values in the drop-down upon delete if they were new values
- item = item.retrieveData('text').evalJSON(true);
- if(!item.newValue)
- obj.autoFeed(item);
- },
- onInputFocus: function(el,obj) { obj.autoShow(); },
- onInputBlur: function(el,obj) {
- obj.lastinput = el;
- if(!obj.curOn) {
- obj.blurhide = obj.autoHide.bind(obj).delay(0.1);
- }
- },
- filter: function(D,E) { var C=[];for(var B=0,A=this.length;B -0400
+ return new Date(s);
+ },
+ datetime: function(elem) {
+ var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
+ return $t.parse(iso8601);
+ },
+ isTime: function(elem) {
+ // jQuery's `is()` doesn't play well with HTML5 in IE
+ return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
+ }
+ });
+
+ // functions that can be called via $(el).timeago('action')
+ // init is default when no action is given
+ // functions are called with context of a single element
+ var functions = {
+ init: function(){
+ var refresh_el = $.proxy(refresh, this);
+ refresh_el();
+ var $s = $t.settings;
+ if ($s.refreshMillis > 0) {
+ setInterval(refresh_el, $s.refreshMillis);
+ }
+ },
+ update: function(time){
+ $(this).data('timeago', { datetime: $t.parse(time) });
+ refresh.apply(this);
+ },
+ updateFromDOM: function(){
+ $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
+ refresh.apply(this);
+ }
+ };
+
+ $.fn.timeago = function(action, options) {
+ var fn = action ? functions[action] : functions.init;
+ if(!fn){
+ throw new Error("Unknown function name '"+ action +"' for timeago");
+ }
+ // each over objects here and call the requested function
+ this.each(function(){
+ fn.call(this, options);
+ });
+ return this;
+ };
+
+ function refresh() {
+ var data = prepareData(this);
+ var $s = $t.settings;
+
+ if (!isNaN(data.datetime)) {
+ if ( $s.cutoff == 0 || distance(data.datetime) < $s.cutoff) {
+ $(this).text(inWords(data.datetime));
+ }
+ }
+ return this;
+ }
+
+ function prepareData(element) {
+ element = $(element);
+ if (!element.data("timeago")) {
+ element.data("timeago", { datetime: $t.datetime(element) });
+ var text = $.trim(element.text());
+ if ($t.settings.localeTitle) {
+ element.attr("title", element.data('timeago').datetime.toLocaleString());
+ } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
+ element.attr("title", text);
+ }
+ }
+ return element.data("timeago");
+ }
+
+ function inWords(date) {
+ return $t.inWords(distance(date));
+ }
+
+ function distance(date) {
+ return (new Date().getTime() - date.getTime());
+ }
+
+ // fix for IE6 suckage
+ document.createElement("abbr");
+ document.createElement("time");
+}));
diff --git a/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pl.js b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pl.js
new file mode 100644
index 0000000000..ee4bdfaa12
--- /dev/null
+++ b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pl.js
@@ -0,0 +1,31 @@
+// Polish
+(function() {
+ function numpf(n, s, t) {
+ // s - 2-4, 22-24, 32-34 ...
+ // t - 5-21, 25-31, ...
+ var n10 = n % 10;
+ if ( (n10 > 1) && (n10 < 5) && ( (n > 20) || (n < 10) ) ) {
+ return s;
+ } else {
+ return t;
+ }
+ }
+
+ jQuery.timeago.settings.locales['pl'] = {
+ prefixAgo: null,
+ prefixFromNow: "za",
+ suffixAgo: "temu",
+ suffixFromNow: null,
+ seconds: "mniej niż minutę",
+ minute: "minutę",
+ minutes: function(value) { return numpf(value, "%d minuty", "%d minut"); },
+ hour: "godzinę",
+ hours: function(value) { return numpf(value, "%d godziny", "%d godzin"); },
+ day: "dzień",
+ days: "%d dni",
+ month: "miesiąc",
+ months: function(value) { return numpf(value, "%d miesiące", "%d miesięcy"); },
+ year: "rok",
+ years: function(value) { return numpf(value, "%d lata", "%d lat"); }
+ };
+})();
diff --git a/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pt-BR.js b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pt-BR.js
new file mode 100644
index 0000000000..c81e2ba1ad
--- /dev/null
+++ b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pt-BR.js
@@ -0,0 +1,18 @@
+// Brazilian Portuguese
+jQuery.timeago.settings.locales['pt-BR'] = {
+ prefixAgo: "há",
+ prefixFromNow: "em",
+ suffixAgo: null,
+ suffixFromNow: null,
+ seconds: "alguns segundos",
+ minute: "um minuto",
+ minutes: "%d minutos",
+ hour: "uma hora",
+ hours: "%d horas",
+ day: "um dia",
+ days: "%d dias",
+ month: "um mês",
+ months: "%d meses",
+ year: "um ano",
+ years: "%d anos"
+};
diff --git a/vendor/assets/javascripts/jquery_timeago/jquery.timeago.ru.js b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.ru.js
new file mode 100644
index 0000000000..6faf05afbc
--- /dev/null
+++ b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.ru.js
@@ -0,0 +1,34 @@
+// Russian
+(function() {
+ function numpf(n, f, s, t) {
+ // f - 1, 21, 31, ...
+ // s - 2-4, 22-24, 32-34 ...
+ // t - 5-20, 25-30, ...
+ var n10 = n % 10;
+ if ( (n10 == 1) && ( (n == 1) || (n > 20) ) ) {
+ return f;
+ } else if ( (n10 > 1) && (n10 < 5) && ( (n > 20) || (n < 10) ) ) {
+ return s;
+ } else {
+ return t;
+ }
+ }
+
+ jQuery.timeago.settings.locales['ru'] = {
+ prefixAgo: null,
+ prefixFromNow: "через",
+ suffixAgo: "назад",
+ suffixFromNow: null,
+ seconds: "меньше минуты",
+ minute: "минуту",
+ minutes: function(value) { return numpf(value, "%d минута", "%d минуты", "%d минут"); },
+ hour: "час",
+ hours: function(value) { return numpf(value, "%d час", "%d часа", "%d часов"); },
+ day: "день",
+ days: function(value) { return numpf(value, "%d день", "%d дня", "%d дней"); },
+ month: "месяц",
+ months: function(value) { return numpf(value, "%d месяц", "%d месяца", "%d месяцев"); },
+ year: "год",
+ years: function(value) { return numpf(value, "%d год", "%d года", "%d лет"); }
+ };
+})();
diff --git a/vendor/assets/javascripts/jquery_timeago/jquery.timeago.sv-SE.js b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.sv-SE.js
new file mode 100644
index 0000000000..7e59083feb
--- /dev/null
+++ b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.sv-SE.js
@@ -0,0 +1,18 @@
+// Swedish
+jQuery.timeago.settings.locales['sv-SE'] = {
+ prefixAgo: "för",
+ prefixFromNow: "om",
+ suffixAgo: "sedan",
+ suffixFromNow: "",
+ seconds: "mindre än en minut",
+ minute: "ungefär en minut",
+ minutes: "%d minuter",
+ hour: "ungefär en timme",
+ hours: "ungefär %d timmar",
+ day: "en dag",
+ days: "%d dagar",
+ month: "ungefär en månad",
+ months: "%d månader",
+ year: "ungefär ett år",
+ years: "%d år"
+};
diff --git a/vendor/assets/javascripts/jquery_timeago/jquery.timeago.th.js b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.th.js
new file mode 100644
index 0000000000..20ce5a7b15
--- /dev/null
+++ b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.th.js
@@ -0,0 +1,20 @@
+// Thai
+jQuery.timeago.settings.locales['th'] = {
+ prefixAgo: null,
+ prefixFromNow: null,
+ suffixAgo: "ที่แล้ว",
+ suffixFromNow: "จากตอนนี้",
+ seconds: "น้อยกว่าหนึ่งนาที",
+ minute: "ประมาณหนึ่งนาที",
+ minutes: "%d นาที",
+ hour: "ประมาณหนึ่งชั่วโมง",
+ hours: "ประมาณ %d ชั่วโมง",
+ day: "หนึ่งวัน",
+ days: "%d วัน",
+ month: "ประมาณหนึ่งเดือน",
+ months: "%d เดือน",
+ year: "ประมาณหนึ่งปี",
+ years: "%d ปี",
+ wordSeparator: "",
+ numbers: []
+};
diff --git a/vendor/assets/javascripts/jquery_timeago/jquery.timeago.zh-CN.js b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.zh-CN.js
new file mode 100644
index 0000000000..6c156d1867
--- /dev/null
+++ b/vendor/assets/javascripts/jquery_timeago/jquery.timeago.zh-CN.js
@@ -0,0 +1,20 @@
+// Simplified Chinese
+jQuery.timeago.settings.locales['zh-CN'] = {
+ prefixAgo: null,
+ prefixFromNow: "从现在开始",
+ suffixAgo: "之前",
+ suffixFromNow: null,
+ seconds: "不到 1 分钟",
+ minute: "大约 1 分钟",
+ minutes: "%d 分钟",
+ hour: "大约 1 小时",
+ hours: "大约 %d 小时",
+ day: "1 天",
+ days: "%d 天",
+ month: "大约 1 个月",
+ months: "%d 月",
+ year: "大约 1 年",
+ years: "%d 年",
+ numbers: [],
+ wordSeparator: ""
+};
diff --git a/vendor/assets/javascripts/modalbox.js b/vendor/assets/javascripts/modalbox.js
deleted file mode 100644
index d47b818679..0000000000
--- a/vendor/assets/javascripts/modalbox.js
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
-ModalBox - The pop-up window thingie with AJAX, based on prototype and script.aculo.us.
-
-Copyright Andrey Okonetchnikov (andrej.okonetschnikow@gmail.com), 2006-2007
-All rights reserved.
-
-VERSION 1.6.1
-Last Modified: 01/11/2010
-*/
-
-if (Object.isUndefined(Prototype.Browser.IE6)) {
- Prototype.Browser.IE6 = (navigator.appName.indexOf("Microsoft Internet Explorer") != -1 && navigator.appVersion.indexOf("MSIE 6.0") != -1 && !window.XMLHttpRequest);
-}
-
-if (!window.Modalbox)
- var Modalbox = {};
-
-Modalbox.Methods = {
- overrideAlert: false, // Override standard browser alert message with ModalBox
- focusableElements: [],
- currFocused: 0,
- initialized: false, // Modalbox is visible
- active: true, // Modalbox is visible and active
- options: {
- title: "ModalBox Window", // Title of the ModalBox window
- overlayClose: true, // Close modal box by clicking on overlay
- width: 500, // Default width in px
- height: 90, // Default height in px
- overlayOpacity: 0.5, // Default overlay opacity
- overlayDuration: 0.1, // Default overlay fade in/out duration in seconds
- slideDownDuration: 0.25, // Default Modalbox appear slide down effect in seconds
- slideUpDuration: 0.25, // Default Modalbox hiding slide up effect in seconds
- resizeDuration: 0.1, // Default resize duration seconds
- inactiveFade: true, // Fades MB window on inactive state
- transitions: true, // Toggles transition effects. Transitions are enabled by default
- loadingString: "Please wait. Loading...", // Default loading string message
- closeString: "Close window", // Default title attribute for close window link
- closeValue: "×", // Default string for close link in the header
- params: {},
- method: "get", // Default Ajax request method
- autoFocusing: true, // Toggles auto-focusing for form elements. Disable for long text pages.
- aspnet: false // Should be true when using with ASP.NET controls. When true Modalbox window will be injected into the first form element.
- },
- _options: {},
-
- setOptions: function(options) {
- Object.extend(this.options, options || {});
- },
-
- _init: function(options) {
- // Setting up original options with default options
- Object.extend(this._options, this.options);
- this.setOptions(options);
-
- // Creating the overlay
- this.MBoverlay = new Element("div", {id: "MB_overlay", style: "opacity: 0"});
-
- // Creating the modal window
- this.MBwindow = new Element("div", {id: "MB_window", style: "display: none"}).update(
- this.MBframe = new Element("div", {id: "MB_frame"}).update(
- this.MBheader = new Element("div", {id: "MB_header"}).update(
- this.MBcaption = new Element("div", {id: "MB_caption"})
- )
- )
- );
- this.MBclose = new Element("a", {id: "MB_close", title: this.options.closeString, href: "#"}).update("" + this.options.closeValue + " ");
- this.MBheader.insert({'bottom':this.MBclose});
-
- this.MBcontent = new Element("div", {id: "MB_content"}).update(
- this.MBloading = new Element("div", {id: "MB_loading"}).update(this.options.loadingString)
- );
- this.MBframe.insert({'bottom':this.MBcontent});
-
- // Inserting into DOM. If parameter set and form element have been found will inject into it. Otherwise will inject into body as topmost element.
- // Be sure to set padding and marging to null via CSS for both body and (in case of asp.net) form elements.
- var injectToEl = this.options.aspnet ? $(document.body).down('form') : $(document.body);
- injectToEl.insert({'top':this.MBwindow});
- injectToEl.insert({'top':this.MBoverlay});
-
- // Initial scrolling position of the window. To be used for remove scrolling effect during ModalBox appearing
- this.initScrollX = window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft;
- this.initScrollY = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
-
- //Adding event observers
- this.hideObserver = this._hide.bindAsEventListener(this);
- this.kbdObserver = this._kbdHandler.bindAsEventListener(this);
- this.resizeObserver = this._setWidthAndPosition.bindAsEventListener(this);
- this._initObservers();
-
- this.initialized = true; // Mark as initialized
- },
-
- show: function(content, options) {
- if (!this.initialized) this._init(options); // Check if MB is already initialized
-
- this.content = content;
- this.setOptions(options);
-
- if (this.options.title) { // Updating title of the MB
- this.MBcaption.update(this.options.title);
- } else { // If title isn't given, the header will not displayed
- this.MBheader.hide();
- this.MBcaption.hide();
- }
-
- if (this.MBwindow.style.display == "none") { // First MB appearing
- this._appear();
- this.event("onShow"); // Passing onShow callback
- } else { // If MB already on the screen, update it
- this._update();
- this.event("onUpdate"); // Passing onUpdate callback
- }
- },
-
- hide: function(options) { // External hide method to use from external HTML and JS
- if(this.initialized) {
- // Reading for options/callbacks except if event given as a parameter
- if (options && !Object.isFunction(options.element))
- Object.extend(this.options, options);
- this.event("beforeHide"); // Passing beforeHide callback
- if (this.options.transitions) {
- Effect.SlideUp(this.MBwindow, { duration: this.options.slideUpDuration, transition: Effect.Transitions.sinoidal, afterFinish: this._deinit.bind(this) });
- } else {
- this.MBwindow.hide();
- this._deinit();
- }
- } else {
- throw("Modalbox is not initialized.");
- }
- },
-
- _hide: function(event) { // Internal hide method to use with overlay and close link
- event.stop(); // Stop event propagation for link elements
- // When clicked on overlay we'll check the option and in case of overlayClose == false we'll break hiding execution [Fix for #139]
- if (event.element().id == 'MB_overlay' && !this.options.overlayClose) return false;
- this.hide();
- },
-
- alert: function(message){
- var html = '';
- Modalbox.show(html, {title: 'Alert: ' + document.title, width: 300});
- },
-
- _appear: function() { // First appearing of MB
- if (Prototype.Browser.IE6) { // Preparing IE 6 for showing modalbox
- window.scrollTo(0,0);
- this._prepareIEHtml("100%", "hidden");
- this._prepareIESelects("hidden");
- }
- this._setSize();
- this._setPosition();
- if(this.options.transitions) {
- this.MBoverlay.setOpacity(0);
- new Effect.Fade(this.MBoverlay, {
- from: 0,
- to: this.options.overlayOpacity,
- duration: this.options.overlayDuration,
- afterFinish: (function() {
- new Effect.SlideDown(this.MBwindow, {
- duration: this.options.slideDownDuration,
- transition: Effect.Transitions.sinoidal,
- afterFinish: (function() {
- this._setPosition();
- this.loadContent();
- }).bind(this)
- });
- }).bind(this)
- });
- } else {
- this.MBoverlay.setOpacity(this.options.overlayOpacity);
- this.MBwindow.show();
- this._setPosition();
- this.loadContent();
- }
- Event.observe(window, "resize", this.resizeObserver);
- },
-
- _update: function() { // Updating MB in case of wizards
- this.MBcontent.update($(this.MBloading).update(this.options.loadingString));
- this.loadContent();
- },
-
- resizeTo: function(newWidth, newHeight, options) { // Change size of MB without content reloading
- var o = this.MBoverlay.getDimensions();
- var newStyle = {width: newWidth + "px", height: newHeight + "px", left: (o.width - newWidth)/2 + "px"};
- this.options.width = newWidth;
- if (options) this.setOptions(options); // Passing callbacks
- if (this.options.transitions) {
- new Effect.Morph(this.MBwindow, {
- style: newStyle,
- duration: this.options.resizeDuration,
- beforeStart: function(fx){
- fx.element.setStyle({overflow: "hidden"}); // Fix for MSIE 6 to resize correctly
- },
- afterFinish: (function(fx) {
- fx.element.setStyle({overflow: "visible"});
- this.event("_afterResize"); // Passing internal callback
- this.event("afterResize"); // Passing callback
- }).bind(this)
- });
- } else {
- this.MBwindow.setStyle(newStyle);
- (function() {
- this.event("_afterResize"); // Passing internal callback
- this.event("afterResize"); // Passing callback
- }).bind(this).defer();
- }
- },
-
- resize: function(byWidth, byHeight, options) { // Change size of MB without loading content
- var w = this.MBwindow.getDimensions(), hHeight = this.MBheader.getHeight(), cHeight = this.MBcontent.getHeight();
- this.resizeTo((w.width + byWidth), Math.max(hHeight + cHeight, w.height + byHeight), options);
- },
-
- resizeToContent: function(options){
- // Resizes the modalbox window to the actual content height.
- // This might be useful to resize modalbox after some content modifications which were changed content height.
-
- var byHeight = this.options.height - this.MBwindow.getHeight();
- if (byHeight != 0) {
- this.resize(0, byHeight, options);
- }
- },
-
- resizeToInclude: function(element, options){
- // Resizes the modalbox window to the cumulative height of element. Calculations are using CSS properties for margins and border.
- // This method might be useful to resize modalbox before including or updating content.
-
- element = $(element);
- var styles = ['margin-top','margin-bottom','border-top-width','border-bottom-width'];
- var elHeight = styles.inject(element.getHeight(), function(acc, n) {
- var x = parseInt(element.getStyle(n), 10);
- acc += (isNaN(x) ? 0 : x);
- return acc;
- });
- if (elHeight > 0) {
- Modalbox.resize(0, elHeight, options);
- }
- },
-
- loadContent: function() {
- if (this.event("beforeLoad")) { // If callback returned false, skip loading of the content
- if (typeof this.content == 'string') {
- var htmlRegExp = new RegExp(/<\/?[^>]+>/gi), evalScript = function(script) {
- return eval(script.replace("", ""));
- };
- if (htmlRegExp.test(this.content)) { // Plain HTML given as a parameter
- this._insertContent(this.content.stripScripts(), (function() {
- this.content.extractScripts().map(evalScript, window);
- }).bind(this));
- } else { // URL given as a parameter. We'll request it via Ajax
- new Ajax.Request(this.content, {
- method: this.options.method.toLowerCase(),
- parameters: this.options.params,
- onSuccess: (function(transport) {
- var response = new String(transport.responseText);
- this._insertContent(transport.responseText.stripScripts(), function(){
- response.extractScripts().map(evalScript, window);
- });
- }).bind(this),
- onException: function(instance, exception){
- Modalbox.hide();
- throw('Modalbox Loading Error: ' + exception);
- }
- });
- }
- } else if (typeof this.content == 'object') { // HTML Object is given
- this._insertContent(this.content);
- } else {
- this.hide();
- throw('Modalbox Parameters Error: Please specify correct URL or HTML element (plain HTML or object)');
- }
- }
- },
-
- _insertContent: function(content, callback) {
- this.MBcontent.hide().update();
-
- if (typeof content == 'string') { // Plain HTML is given
- this.MBcontent.insert(new Element("div", { style: "display: none" }).update(content)).down().show();
- } else if (typeof content == 'object') { // HTML Object is given
- var _htmlObj = content.cloneNode(true); // If node already a part of DOM we'll clone it
- // If cloneable element has ID attribute defined, modifying it to prevent duplicates
- if (content.id) content.id = "MB_" + content.id;
- // Add prefix for IDs on all elements inside the DOM node
- $(content).select('*[id]').each(function(el) { el.id = "MB_" + el.id; });
- this.MBcontent.insert(_htmlObj).down().show();
- if (Prototype.Browser.IE6) { // Toggle back visibility for hidden selects in IE
- this._prepareIESelects("", "#MB_content ");
- }
- }
-
- // Prepare and resize modal box for content
- if (this.options.height == this._options.height) {
- this.resizeTo(this.options.width, this.MBheader.getHeight() + this.MBcontent.getHeight(), {
- afterResize: (function() {
- this._putContent.bind(this, callback).defer(); // MSIE fix
- }).bind(this)
- });
- } else { // Height is defined. Creating a scrollable window
- this._setSize();
- this.MBcontent.setStyle({
- overflow: 'auto',
- height: this.options.height - this.MBheader.getHeight() - 13 + 'px'
- });
- this._putContent.bind(this, callback).defer(); // MSIE fix
- }
- },
-
- _putContent: function(callback) {
- this.MBcontent.show();
- this._findFocusableElements();
- this._setFocus(); // Setting focus on first 'focusable' element in content (input, select, textarea, link or button)
- if (Object.isFunction(callback))
- callback(); // Executing internal JS from loaded content
- this.event("afterLoad"); // Passing callback
- },
-
- activate: function(options) {
- this.setOptions(options);
- this.active = true;
- if (this.options.overlayClose)
- this.MBoverlay.observe("click", this.hideObserver);
- this.MBclose.observe("click", this.hideObserver).show();
- if (this.options.transitions && this.options.inactiveFade)
- new Effect.Appear(this.MBwindow, {duration: this.options.slideUpDuration});
- },
-
- deactivate: function(options) {
- this.setOptions(options);
- this.active = false;
- if (this.options.overlayClose)
- this.MBoverlay.stopObserving("click", this.hideObserver);
- this.MBclose.stopObserving("click", this.hideObserver).hide();
- if (this.options.transitions && this.options.inactiveFade)
- new Effect.Fade(this.MBwindow, {duration: this.options.slideUpDuration, to: 0.75});
- },
-
- _initObservers: function() {
- this.MBclose.observe("click", this.hideObserver);
- if (this.options.overlayClose)
- this.MBoverlay.observe("click", this.hideObserver);
- // Gecko and Opera are moving focus a way too fast, all other browsers are okay with keydown
- var kbdEvent = (Prototype.Browser.Gecko || Prototype.Browser.Opera) ? "keypress" : "keydown";
- Event.observe(document, kbdEvent, this.kbdObserver);
- },
-
- _removeObservers: function() {
- this.MBclose.stopObserving("click", this.hideObserver);
- if (this.options.overlayClose)
- this.MBoverlay.stopObserving("click", this.hideObserver);
- var kbdEvent = (Prototype.Browser.Gecko || Prototype.Browser.Opera) ? "keypress" : "keydown";
- Event.stopObserving(document, kbdEvent, this.kbdObserver);
- },
-
- _setFocus: function() {
- // Setting focus to the first 'focusable' element which is one with tabindex = 1 or the first in the form loaded.
- if (this.options.autoFocusing === true && this.focusableElements.length > 0) {
- var firstEl = this.focusableElements.find(function (el){
- return el.tabIndex == 1;
- }) || this.focusableElements.first();
- this.currFocused = this.focusableElements.toArray().indexOf(firstEl);
- firstEl.focus(); // Focus on first focusable element except close button
- } else if (this.MBclose.visible()) {
- this.MBclose.focus(); // If no focusable elements exist focus on close button
- }
- },
-
- _findFocusableElements: function() { // Collect form elements or links from MB content
- if (this.options.autoFocusing === true) {
- // TODO maybe add :enabled to select and textarea elements
- this.MBcontent.select('input:not([type~=hidden]):enabled, select, textarea, button, a[href]').invoke('addClassName', 'MB_focusable');
- this.focusableElements = this.MBcontent.select('.MB_focusable');
- }
- },
-
- _kbdHandler: function(event) {
- var node = event.element();
- switch(event.keyCode) {
- case Event.KEY_TAB:
- event.stop();
-
- // Switching currFocused to the element which was focused by mouse instead of TAB-key. Fix for #134
- if (node != this.focusableElements[this.currFocused])
- this.currFocused = this.focusableElements.indexOf(node);
-
- if (!event.shiftKey) { // Focusing in direct order
- if(this.currFocused >= this.focusableElements.length - 1) {
- this.currFocused = 0;
- } else {
- this.currFocused++;
- }
- } else { // Shift key is pressed. Focusing in reverse order
- if(this.currFocused <= 0) {
- this.currFocused = this.focusableElements.length - 1;
- } else {
- this.currFocused--;
- }
- }
- this.focusableElements[this.currFocused].focus();
- break;
- case Event.KEY_ESC:
- if (this.active) this._hide(event);
- break;
- case 32:
- this._preventScroll(event);
- break;
- case 0: // For Gecko browsers compatibility
- if (event.which == 32) this._preventScroll(event);
- break;
- case Event.KEY_UP:
- case Event.KEY_DOWN:
- case Event.KEY_PAGEDOWN:
- case Event.KEY_PAGEUP:
- case Event.KEY_HOME:
- case Event.KEY_END:
- // Safari operates in slightly different way. This realization is still buggy in Safari.
- if (Prototype.Browser.WebKit && !["textarea", "select"].include(node.tagName.toLowerCase()))
- event.stop();
- else if ((node.tagName.toLowerCase() == "input" && ["submit", "button"].include(node.type)) || (node.tagName.toLowerCase() == "a"))
- event.stop();
- break;
- }
- },
-
- _preventScroll: function(event) { // Disabling scrolling by "space" key
- if (!["input", "textarea", "select", "button"].include(event.element().tagName.toLowerCase()))
- event.stop();
- },
-
- _deinit: function() {
- this._removeObservers();
- Event.stopObserving(window, "resize", this.resizeObserver);
- if (this.options.transitions) {
- Effect.toggle(this.MBoverlay, 'appear', {duration: this.options.overlayDuration, afterFinish: this._removeElements.bind(this) });
- } else {
- this.MBoverlay.hide();
- this._removeElements();
- }
- this.MBcontent.setStyle({overflow: '', height: ''});
- },
-
- _removeElements: function() {
- if (Prototype.Browser.Opera) { // Remove overlay after-effects in Opera
- window.scrollBy(0, 0);
- }
- this.MBoverlay.remove();
- this.MBwindow.remove();
- if (Prototype.Browser.IE6) {
- this._prepareIEHtml("", ""); // If set to auto MSIE will show horizontal scrolling
- this._prepareIESelects("");
- window.scrollTo(this.initScrollX, this.initScrollY);
- }
-
- // Replacing prefixes 'MB_' in IDs for the original content
- if (typeof this.content == 'object') {
- if(this.content.id && this.content.id.match(/MB_/)) {
- this.content.id = this.content.id.replace(/MB_/, "");
- }
- this.content.select('*[id]').each(function(el) { el.id = el.id.replace(/MB_/, ""); });
- }
- // Initialized will be set to false
- this.initialized = false;
- this.event("afterHide"); // Passing afterHide callback
- this.setOptions(this._options); // Settings options object into initial state
- },
-
- _setSize: function() { // Set size
- this.MBwindow.setStyle({width: this.options.width + "px", height: this.options.height + "px"});
- },
-
- _setPosition: function() {
- this.MBwindow.setStyle({left: ((this.MBoverlay.getWidth() - this.MBwindow.getWidth()) / 2 ) + "px"});
- },
-
- _setWidthAndPosition: function() {
- this.MBwindow.setStyle({
- width: this.options.width + "px",
- left: ((this.MBoverlay.getWidth() - this.options.width) / 2 ) + "px"
- });
- },
-
- _prepareIEHtml: function(height, overflow) { // IE requires width and height set to 100% and overflow hidden
- $$('html, body').invoke('setStyle', {width: height, height: height, overflow: overflow});
- },
-
- _prepareIESelects: function(overflow, prefix) { // Toggle visibility for select elements
- $$((prefix || "") + "select").invoke('setStyle', {'visibility': overflow});
- },
-
- event: function(eventName) {
- var r = true;
- if (this.options[eventName]) {
- var returnValue = this.options[eventName](); // Executing callback
- this.options[eventName] = null; // Removing callback after execution
- if (!Object.isUndefined(returnValue))
- r = returnValue;
- }
- Event.fire(document, 'Modalbox:' + eventName);
- return r;
- }
-};
-
-Object.extend(Modalbox, Modalbox.Methods);
-
-if (Modalbox.overrideAlert) window.alert = Modalbox.alert;
diff --git a/vendor/assets/javascripts/rating.js b/vendor/assets/javascripts/rating.js
index 3eb2b67cc2..5bcc095a24 100644
--- a/vendor/assets/javascripts/rating.js
+++ b/vendor/assets/javascripts/rating.js
@@ -96,7 +96,7 @@ var Ratable = Class.create({
this.options.callback(this.element, this.rating);
if (this.options.remote_url) {
var parameters = new Template(this.options.remote_parameters).evaluate({id: this.element.id, rating: this.rating});
- new Ajax.Request(this.options.remote_url, { method: this.options.remote_method, parameters: parameters });
+ $.ajax(this.options.remote_url, { type: this.options.remote_method, data: parameters });
}
},
@@ -152,7 +152,7 @@ var Rating = Class.create({
//---------------------------------------------------------------------------
parse: function() {
- $$(this.class_name).each(function(element) {
+ $(this.class_name).each(function(element) {
if (!this.elements.include(element)) {
this.elements.push(element);
new Ratable(element, this.options);
diff --git a/vendor/assets/stylesheets/facebooklist.css b/vendor/assets/stylesheets/facebooklist.css
deleted file mode 100644
index ee84817c4b..0000000000
--- a/vendor/assets/stylesheets/facebooklist.css
+++ /dev/null
@@ -1,47 +0,0 @@
-/* TextboxList sample CSS */
-ul.holder { margin: 0; border: 1px solid #999; border-color:#C4C4C4 #E4E4E4 #E4E4E4 #C4C4C4; overflow: hidden; height: auto !important; height: 1%; padding: 3px 6px 0; }
-*:first-child+html ul.holder { padding-bottom: 2px; } * html ul.holder { padding-bottom: 2px; } /* ie7 and below */
-ul.holder li { float: left; list-style-type: none; margin: 0 5px 4px 0; }
-ul.holder li.bit-box, ul.holder li.bit-input input { font: 11px "Lucida Grande", "Verdana"; }
-ul.holder li.bit-box { -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; border: 1px solid #CAD8F3; background: #DEE7F8; padding: 1px 5px 2px; }
-ul.holder li.bit-box-focus { border-color: #598BEC; background: #598BEC; color: #fff; }
-ul.holder li.bit-input input { width: 150px; margin: 0; border: none; outline: 0; padding: 3px 0 2px; } /* no left/right padding here please */
-ul.holder li.bit-input input.smallinput { width: 20px; }
-ul.hoder li.bit-input input.maininput { margin: 0; }
-
-/* Facebook demo CSS */
-#facebook-list ul.holder li.bit-box { padding-right: 15px; position: relative; }
-ul.holder li.bit-hover { background: #BBCEF1; border: 1px solid #6D95E0; }
-ul.holder li.bit-box-focus { border-color: #598BEC; background: #598BEC; color: #fff; }
-ul.holder li.bit-box a.closebutton { width: 7px; height: 7px; background: url('/assets/facebook-close.gif'); }
-ul.holder li.bit-box a.closebutton:hover { background-position: 7px; }
-ul.holder li.bit-box-focus a.closebutton, ul.holder li.bit-box-focus a.closebutton:hover { background-position: bottom; }
-
-/* Autocompleter */
-
-#facebook-auto { display: none; position: absolute; width: 500px; background: #eee; z-index: 9999; }
-#facebook-auto .default { padding: 5px 7px; border: 1px solid #ccc; border-width: 0 1px 1px; }
-#facebook-auto ul { display: none; margin: 0; padding: 0; overflow: auto; }
-#facebook-auto ul li { padding: 5px 12px; z-index: 1000; cursor: pointer; margin: 0; list-style-type: none; border: 1px solid #ccc; border-width: 0 1px 1px; font: 11px "Lucida Grande", "Verdana"; }
-#facebook-auto ul li em { font-weight: bold; font-style: normal; background: #ccc; }
-#facebook-auto ul li.auto-focus { background: #4173CC; color: #fff; }
-#facebook-auto ul li.auto-focus em { background: none; }
-
-#demo ul.holder li.bit-input input { padding: 2px 0 1px; border: 1px solid #999; }
-#add a { color: #666; }
-#add-test { width: 100px; padding: 2px; }
-#button_container { margin-left: 70px; margin-bottom: 30px;}
-
-/* Fixes for FFCRM */
-#facebook-list { margin: 0 0 18px; background-color: white; }
-#facebook-list li { border-bottom: 0; clear: none; }
-ul.holder li { padding: 0; }
-.facebook-tags { padding: 0; margin: 0; }
-
-
-/* Fixes for 'Peek-a-boo' bug in IE7 and below */
-#facebook-list ul.holder li.bit-box { padding-right: 5px; position: static; }
-ul.holder li.bit-box a.closebutton { display: inline-block; margin-left: 3px;}
-*:first-child+html ul.holder li.bit-box a.closebutton { margin-bottom: 2px; }
-* html ul.holder li.bit-box a.closebutton { margin-bottom: 2px; }
-
diff --git a/zeus.json b/zeus.json
index 3e075d6feb..aa33e03079 100644
--- a/zeus.json
+++ b/zeus.json
@@ -1,5 +1,5 @@
{
- "command": "ruby -rubygems -rzeus/rails -eZeus.go",
+ "command": "ruby -rubygems -r./custom_plan -eZeus.go",
"plan": {
"boot": {
@@ -10,6 +10,7 @@
"console": ["c"],
"server": ["s"],
"generate": ["g"],
+ "destroy": ["d"],
"dbconsole": []
},
"test_environment": {