├── .DS_Store ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE ├── README.markdown ├── Rakefile ├── active_admin_jcrop.gemspec ├── app ├── assets │ ├── .DS_Store │ ├── javascripts │ │ ├── .DS_Store │ │ └── active_admin_jcrop │ │ │ └── crop_modal.js.coffee │ └── stylesheets │ │ ├── .DS_Store │ │ └── active_admin_jcrop │ │ └── crop_modal.css └── views │ └── active_admin_jcrop │ └── _jcrop_modal.html.erb ├── config └── locales │ ├── en.yml │ └── pt-BR.yml ├── lib ├── .DS_Store ├── active_admin_jcrop.rb ├── active_admin_jcrop │ ├── .DS_Store │ ├── asset_engine.rb │ ├── asset_engine │ │ ├── carrier_wave.rb │ │ └── paperclip.rb │ ├── dsl.rb │ ├── engine.rb │ ├── image_helper.rb │ ├── orm.rb │ ├── railtie.rb │ ├── version.rb │ └── view_helpers.rb └── formtastic │ ├── .DS_Store │ └── inputs │ ├── .DS_Store │ └── jcrop_input.rb ├── spec ├── .DS_Store ├── dummy │ ├── .DS_Store │ ├── .rspec │ ├── README.rdoc │ ├── Rakefile │ ├── app │ │ ├── admin │ │ │ ├── dashboard.rb │ │ │ └── post.rb │ │ ├── assets │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ ├── active_admin.js.coffee │ │ │ │ └── application.js │ │ │ └── stylesheets │ │ │ │ ├── active_admin.css.scss │ │ │ │ └── application.css │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ └── concerns │ │ │ │ └── .keep │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ └── post.rb │ │ ├── uploaders │ │ │ └── image_uploader.rb │ │ └── views │ │ │ └── layouts │ │ │ └── application.html.erb │ ├── bin │ │ ├── bundle │ │ ├── rails │ │ └── rake │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── active_admin.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ ├── devise.en.yml │ │ │ └── en.yml │ │ ├── routes.rb │ │ └── secrets.yml │ ├── db │ │ ├── migrate │ │ │ ├── 20140609195344_create_posts.rb │ │ │ ├── 20140609200814_create_active_admin_comments.rb │ │ │ ├── 20140609202215_devise_create_admin_users.rb │ │ │ └── 20140619201236_drop_admin_user_table.rb │ │ └── schema.rb │ ├── lib │ │ └── assets │ │ │ └── .keep │ ├── log │ │ └── .keep │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ └── favicon.ico │ └── spec ├── factories.rb ├── features │ └── post_jcrop_feature_spec.rb ├── images │ └── example.jpeg ├── spec_helper.rb └── support │ ├── active_record.rb │ └── carrierwave.rb └── vendor └── assets ├── images └── active_admin_jcrop │ └── Jcrop.gif ├── javascripts └── active_admin_jcrop │ ├── .DS_Store │ ├── jquery.Jcrop.js │ ├── jquery.Jcrop.min.js │ └── jquery.color.js └── stylesheets └── active_admin_jcrop ├── Jcrop.gif ├── jquery.Jcrop.css └── jquery.Jcrop.min.css /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | test/dummy/db/*.sqlite3 5 | test/dummy/db/*.sqlite3-journal 6 | spec/dummy/log/*.log 7 | spec/dummy/tmp/ 8 | spec/dummy/public/uploads/ 9 | spec/dummy/log/*.log 10 | test/dummy/.sass-cache 11 | console 12 | spec/dummy/public/uploads/* 13 | spec/dummy/tmp/* 14 | spec/support/uploads/* 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.2 4 | before_script: 5 | - "export DISPLAY=:99.0" 6 | - "sh -e /etc/init.d/xvfb start" 7 | - sleep 3 # give xvfb some time to start 8 | - mysql -e 'create database active_admin_jcrop_test' 9 | script: 10 | - RAILS_ENV=test bundle exec rake db:migrate --trace 11 | - bundle exec rspec spec 12 | bundler_args: --binstubs=./bundler_stubs -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v0.0.10 2 | 3 | * Updated README to include the Paperclip fix for the processor 4 | * 4a10b33320 (Add ActiveAdmin namespace to jcropper_url only if not blank) 5 | 6 | ## v0.0.9 7 | 8 | * added show current dimension feature 9 | 10 | 11 | ## v0.0.8 12 | 13 | * added support to jcrop events 14 | 15 | 16 | ## v0.0.7 17 | 18 | * adding custom fields only once per model 19 | * add boxWidth option to jcrop_input 20 | 21 | ## v0.0.6 22 | 23 | * added support to Active Admin custom namespace 24 | 25 | ## v0.0.5 26 | 27 | * added specs to dummy app 28 | * refactored some code 29 | * added Travis CI 30 | 31 | 32 | ## v0.0.4 33 | 34 | * added spec configuration 35 | * fixed vendor on asset pipeline 36 | 37 | 38 | ## v0.0.3 39 | 40 | * added locale support 41 | * added jcrop options support 42 | * fixed modules location 43 | 44 | ## v0.0.2.alpha 45 | 46 | * initial release -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Declare your gem's dependencies in active_admin_jcrop.gemspec. 4 | # Bundler will treat runtime dependencies like base dependencies, and 5 | # development dependencies will be added by default to the :development group. 6 | gemspec 7 | 8 | # Declare any dependencies that are still in development here instead of in 9 | # your gemspec. These might include edge Rails or gems from your path or 10 | # Git. Remember to move these dependencies to your gemspec before releasing 11 | # your gem to rubygems.org. 12 | 13 | group :development do 14 | gem 'activeadmin', github: 'gregbell/active_admin' 15 | gem 'sass-rails', github: 'rails/sass-rails' 16 | end 17 | 18 | 19 | 20 | # To use debugger 21 | # gem 'debugger' 22 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/gregbell/active_admin.git 3 | revision: 21f76b1faf651cd4f71dd24997102f7eb83b49d2 4 | specs: 5 | activeadmin (1.0.0.pre2) 6 | arbre (~> 1.0, >= 1.0.2) 7 | bourbon 8 | coffee-rails 9 | formtastic (~> 3.1) 10 | formtastic_i18n 11 | inherited_resources (~> 1.6) 12 | jquery-rails 13 | jquery-ui-rails 14 | kaminari (~> 0.15) 15 | rails (>= 3.2, < 5.0) 16 | ransack (~> 1.3) 17 | sass-rails 18 | 19 | GIT 20 | remote: git://github.com/rails/sass-rails.git 21 | revision: 3a9e47db7d769221157c82229fc1bade55b580f0 22 | specs: 23 | sass-rails (4.0.1) 24 | railties (>= 4.0.0, < 5.0) 25 | sass (~> 3.2) 26 | sprockets (~> 2.12) 27 | sprockets-rails (~> 2.0) 28 | 29 | PATH 30 | remote: . 31 | specs: 32 | active_admin_jcrop (0.0.10) 33 | mini_magick 34 | rails (> 3.2.0) 35 | 36 | GEM 37 | remote: https://rubygems.org/ 38 | specs: 39 | actionmailer (4.1.1) 40 | actionpack (= 4.1.1) 41 | actionview (= 4.1.1) 42 | mail (~> 2.5.4) 43 | actionpack (4.1.1) 44 | actionview (= 4.1.1) 45 | activesupport (= 4.1.1) 46 | rack (~> 1.5.2) 47 | rack-test (~> 0.6.2) 48 | actionview (4.1.1) 49 | activesupport (= 4.1.1) 50 | builder (~> 3.1) 51 | erubis (~> 2.7.0) 52 | activemodel (4.1.1) 53 | activesupport (= 4.1.1) 54 | builder (~> 3.1) 55 | activerecord (4.1.1) 56 | activemodel (= 4.1.1) 57 | activesupport (= 4.1.1) 58 | arel (~> 5.0.0) 59 | activesupport (4.1.1) 60 | i18n (~> 0.6, >= 0.6.9) 61 | json (~> 1.7, >= 1.7.7) 62 | minitest (~> 5.1) 63 | thread_safe (~> 0.1) 64 | tzinfo (~> 1.1) 65 | addressable (2.3.6) 66 | arbre (1.0.3) 67 | activesupport (>= 3.0.0) 68 | arel (5.0.1.20140414130214) 69 | bourbon (4.1.1) 70 | sass (~> 3.3) 71 | thor 72 | builder (3.2.2) 73 | capybara (2.3.0) 74 | mime-types (>= 1.16) 75 | nokogiri (>= 1.3.3) 76 | rack (>= 1.0.0) 77 | rack-test (>= 0.5.4) 78 | xpath (~> 2.0) 79 | carrierwave (0.10.0) 80 | activemodel (>= 3.2.0) 81 | activesupport (>= 3.2.0) 82 | json (>= 1.7) 83 | mime-types (>= 1.16) 84 | childprocess (0.5.3) 85 | ffi (~> 1.0, >= 1.0.11) 86 | coderay (1.1.0) 87 | coffee-rails (4.1.0) 88 | coffee-script (>= 2.2.0) 89 | railties (>= 4.0.0, < 5.0) 90 | coffee-script (2.4.1) 91 | coffee-script-source 92 | execjs 93 | coffee-script-source (1.10.0) 94 | database_cleaner (1.3.0) 95 | diff-lcs (1.2.5) 96 | erubis (2.7.0) 97 | execjs (2.6.0) 98 | factory_girl (2.6.4) 99 | activesupport (>= 2.3.9) 100 | factory_girl_rails (1.7.0) 101 | factory_girl (~> 2.6.0) 102 | railties (>= 3.0.0) 103 | ffi (1.9.3) 104 | formtastic (3.1.3) 105 | actionpack (>= 3.2.13) 106 | formtastic_i18n (0.4.1) 107 | has_scope (0.6.0) 108 | actionpack (>= 3.2, < 5) 109 | activesupport (>= 3.2, < 5) 110 | hike (1.2.3) 111 | i18n (0.6.9) 112 | inherited_resources (1.6.0) 113 | actionpack (>= 3.2, < 5) 114 | has_scope (~> 0.6.0.rc) 115 | railties (>= 3.2, < 5) 116 | responders 117 | jquery-rails (3.1.4) 118 | railties (>= 3.0, < 5.0) 119 | thor (>= 0.14, < 2.0) 120 | jquery-ui-rails (5.0.5) 121 | railties (>= 3.2.16) 122 | json (1.8.1) 123 | kaminari (0.16.3) 124 | actionpack (>= 3.0.0) 125 | activesupport (>= 3.0.0) 126 | launchy (2.4.2) 127 | addressable (~> 2.3) 128 | mail (2.5.4) 129 | mime-types (~> 1.16) 130 | treetop (~> 1.4.8) 131 | method_source (0.8.2) 132 | mime-types (1.25.1) 133 | mini_magick (4.3.6) 134 | mini_portile (0.6.0) 135 | minitest (5.3.4) 136 | multi_json (1.10.1) 137 | mysql2 (0.3.16) 138 | nokogiri (1.6.2.1) 139 | mini_portile (= 0.6.0) 140 | phashion (1.1.1) 141 | polyamorous (1.2.0) 142 | activerecord (>= 3.0) 143 | polyglot (0.3.5) 144 | pry (0.10.0) 145 | coderay (~> 1.1.0) 146 | method_source (~> 0.8.1) 147 | slop (~> 3.4) 148 | rack (1.5.2) 149 | rack-test (0.6.2) 150 | rack (>= 1.0) 151 | rails (4.1.1) 152 | actionmailer (= 4.1.1) 153 | actionpack (= 4.1.1) 154 | actionview (= 4.1.1) 155 | activemodel (= 4.1.1) 156 | activerecord (= 4.1.1) 157 | activesupport (= 4.1.1) 158 | bundler (>= 1.3.0, < 2.0) 159 | railties (= 4.1.1) 160 | sprockets-rails (~> 2.0) 161 | railties (4.1.1) 162 | actionpack (= 4.1.1) 163 | activesupport (= 4.1.1) 164 | rake (>= 0.8.7) 165 | thor (>= 0.18.1, < 2.0) 166 | rake (10.3.2) 167 | ransack (1.7.0) 168 | actionpack (>= 3.0) 169 | activerecord (>= 3.0) 170 | activesupport (>= 3.0) 171 | i18n 172 | polyamorous (~> 1.2) 173 | responders (1.1.2) 174 | railties (>= 3.2, < 4.2) 175 | rmagick (2.13.2) 176 | rspec-core (3.0.1) 177 | rspec-support (~> 3.0.0) 178 | rspec-expectations (3.0.1) 179 | diff-lcs (>= 1.2.0, < 2.0) 180 | rspec-support (~> 3.0.0) 181 | rspec-mocks (3.0.1) 182 | rspec-support (~> 3.0.0) 183 | rspec-rails (3.0.1) 184 | actionpack (>= 3.0) 185 | activesupport (>= 3.0) 186 | railties (>= 3.0) 187 | rspec-core (~> 3.0.0) 188 | rspec-expectations (~> 3.0.0) 189 | rspec-mocks (~> 3.0.0) 190 | rspec-support (~> 3.0.0) 191 | rspec-support (3.0.0) 192 | rubyzip (1.1.4) 193 | sass (3.3.8) 194 | selenium-webdriver (2.42.0) 195 | childprocess (>= 0.5.0) 196 | multi_json (~> 1.0) 197 | rubyzip (~> 1.0) 198 | websocket (~> 1.0.4) 199 | slop (3.5.0) 200 | sprockets (2.12.1) 201 | hike (~> 1.2) 202 | multi_json (~> 1.0) 203 | rack (~> 1.0) 204 | tilt (~> 1.1, != 1.3.0) 205 | sprockets-rails (2.1.3) 206 | actionpack (>= 3.0) 207 | activesupport (>= 3.0) 208 | sprockets (~> 2.8) 209 | thor (0.19.1) 210 | thread_safe (0.3.4) 211 | tilt (1.4.1) 212 | treetop (1.4.15) 213 | polyglot 214 | polyglot (>= 0.3.1) 215 | tzinfo (1.2.1) 216 | thread_safe (~> 0.1) 217 | websocket (1.0.7) 218 | xpath (2.0.0) 219 | nokogiri (~> 1.3) 220 | 221 | PLATFORMS 222 | ruby 223 | 224 | DEPENDENCIES 225 | active_admin_jcrop! 226 | activeadmin! 227 | capybara (~> 2.3.0) 228 | carrierwave 229 | database_cleaner 230 | factory_girl_rails (~> 1.0) 231 | launchy 232 | mysql2 233 | phashion 234 | pry 235 | rake 236 | rmagick 237 | rspec-rails (~> 3.0.1) 238 | sass-rails! 239 | selenium-webdriver 240 | 241 | BUNDLED WITH 242 | 1.10.6 243 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Ricardo Nacif 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Active Admin Jcrop 2 | 3 | *DEPRECATED* 4 | 5 | [![Build Status](https://travis-ci.org/Ricardonacif/active_admin_jcrop.svg?branch=master)](https://travis-ci.org/Ricardonacif/active_admin_jcrop) [![Code Climate](https://codeclimate.com/github/Ricardonacif/active_admin_jcrop.png)](https://codeclimate.com/github/Ricardonacif/active_admin_jcrop) [![Gem Version](https://badge.fury.io/rb/active_admin_jcrop.svg)](http://badge.fury.io/rb/active_admin_jcrop) 6 | 7 | 8 | 9 | ## Cropping feature for Active Admin ## 10 | 11 | ### Instalation ### 12 | Add to your Gemfile: 13 | ```ruby 14 | gem 'activeadmin' 15 | # Because active_admin_jcrop autoload modules by checking plugins you use, it's 16 | # recommended to require it explictly before active_admin_jcrop 17 | # e.g. if you use carrierwave 18 | # gem 'carrierwave', :require => 'carrierwave' 19 | gem 'active_admin_jcrop' #, git: 'git://github.com/Ricardonacif/active_admin_jcrop.git' 20 | ``` 21 | 22 | Configure your form to use Jcrop: 23 | 24 | ```ruby 25 | # RAILS_ROOT/app/admin/post.rb 26 | ActiveAdmin.register Post do 27 | 28 | jcropable 29 | 30 | form do |f| 31 | f.inputs "Details" do 32 | f.input :image, as: :jcropable 33 | end 34 | f.actions 35 | end 36 | 37 | end 38 | 39 | ``` 40 | 41 | If you use Paperclip, you might need to set an empty original style hash so the processor can work correctly (this is needed in the latest versions of Paperclip, not really sure why: 42 | 43 | ```ruby 44 | has_attached_file :attachment, :styles => {:original => {}} 45 | 46 | ``` 47 | If CarrierWave is used, please invoke :active_admin_crop in your uploader, and include both modules: 48 | 49 | ```ruby 50 | class AvatarUploader < CarrierWave::Uploader::Base 51 | 52 | include CarrierWave::MiniMagick 53 | include ActiveAdminJcrop::AssetEngine::CarrierWave 54 | 55 | version :thumb do 56 | process :active_admin_crop 57 | process resize_to_fill: [500,320] 58 | end 59 | 60 | end 61 | ``` 62 | 63 | Done! Now when there's a image attached, visit the edit page of the resource and click on the button Crop Image to open the crop modal. You don't need to save this resource, cropping will be done via ajax. 64 | 65 | ## jCrop Options ## 66 | 67 | Simple, just pass the options here: 68 | ```ruby 69 | # RAILS_ROOT/app/admin/post.rb 70 | ActiveAdmin.register Post do 71 | 72 | jcropable 73 | 74 | form do |f| 75 | f.inputs "Details" do 76 | f.input :image, as: :jcropable, jcrop_options: {aspectRatio: 1, showDimensions: true} # showDimensions will display the current crop dimensions in the upper left hand corner 77 | end 78 | f.actions 79 | end 80 | 81 | end 82 | 83 | ``` 84 | The default option for ```setSelect``` is ```[0,0,100,100]```. For more available setting options, take a look at [jCrop Manual](http://deepliquid.com/content/Jcrop_Manual.html). 85 | ## Localization ## 86 | 87 | Localize the crop feature by adding these entries: 88 | 89 | en: 90 | active_admin: 91 | crop: 92 | open_crop_modal: Crop Image 93 | save_cropped_image: Save Cropped Image 94 | cancel: Cancel 95 | 96 | 97 | ## Dependencies ## 98 | 99 | * MRI +1.9.3 (All above 1.8.6 should work) 100 | * Rails 4.x (didn't tested with 3.2, but it might work) 101 | * MiniMagick 102 | 103 | ## Supported ORM ## 104 | 105 | * ActiveRecord 106 | * Mongoid 107 | 108 | ## Supported Asset Plugin ## 109 | 110 | * CarrierWave 111 | * Paperclip 112 | 113 | ## TODO ## 114 | 115 | * make sure :active_admin_jcrop load after paperclip/carrierwave load 116 | * automate :active_admin_jcrop for CarrierWave uploader 117 | 118 | ## Contributing ## 119 | 120 | Any help is encouraged. Here are some ways you can contribute: 121 | 122 | * by using it 123 | * by telling people 124 | * by reporting bugs or suggesting new features on github issue tracker 125 | * by fixing bugs or implementing features 126 | 127 | ## Thanks ## 128 | 129 | This gem was based on [Rails Admin Jcrop](https://github.com/janx/rails_admin_jcrop), so I'd like to thank those developers. Also, a special thanks to everyone that contributed to Active Admin and jCrop. 130 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'bundler/setup' 3 | rescue LoadError 4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 5 | end 6 | 7 | require 'rdoc/task' 8 | 9 | 10 | RDoc::Task.new(:rdoc) do |rdoc| 11 | rdoc.rdoc_dir = 'rdoc' 12 | rdoc.title = 'ActiveAdminJcrop' 13 | rdoc.options << '--line-numbers' 14 | rdoc.rdoc_files.include('README.rdoc') 15 | rdoc.rdoc_files.include('lib/**/*.rb') 16 | end 17 | 18 | APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) 19 | load 'rails/tasks/engine.rake' 20 | 21 | 22 | 23 | 24 | Bundler::GemHelper.install_tasks 25 | 26 | require 'rake/testtask' 27 | 28 | Rake::TestTask.new(:test) do |t| 29 | t.libs << 'lib' 30 | t.libs << 'test' 31 | t.pattern = 'test/**/*_test.rb' 32 | t.verbose = false 33 | end 34 | 35 | 36 | task default: :test 37 | -------------------------------------------------------------------------------- /active_admin_jcrop.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require "active_admin_jcrop/version" 5 | 6 | 7 | # Describe your gem and declare its dependencies: 8 | Gem::Specification.new do |s| 9 | s.name = "active_admin_jcrop" 10 | s.version = ActiveAdminJcrop::VERSION 11 | s.authors = ["Ricardo Nacif"] 12 | s.email = ["nacif.ricardo@gmail.com"] 13 | s.homepage = "https://github.com/Ricardonacif/active_admin_jcrop" 14 | s.summary = "Jcrop plugin for ActiveAdmin, enable image cropping solution on image fields" 15 | s.description = "Jcrop plugin for ActiveAdmin, enable image cropping solution on image fields" 16 | s.license = "MIT" 17 | 18 | s.files = Dir["{app,config,db,lib,vendor}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"] 19 | s.test_files = Dir["spec/**/*"] 20 | s.add_dependency "rails", "> 3.2.0" 21 | s.add_dependency "mini_magick" 22 | 23 | # Dummy 24 | s.add_development_dependency "mysql2" 25 | s.add_development_dependency "carrierwave" 26 | s.add_development_dependency "rmagick" 27 | 28 | # Tests 29 | s.add_development_dependency "rspec-rails", '~> 3.0.1' 30 | s.add_development_dependency "capybara", '~> 2.3.0' 31 | s.add_development_dependency 'selenium-webdriver' 32 | s.add_development_dependency 'launchy' 33 | s.add_development_dependency "database_cleaner" 34 | s.add_development_dependency 'factory_girl_rails', '~> 1.0' 35 | s.add_development_dependency "pry" 36 | s.add_development_dependency "phashion" 37 | s.add_development_dependency "rake" 38 | 39 | end 40 | -------------------------------------------------------------------------------- /app/assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/app/assets/.DS_Store -------------------------------------------------------------------------------- /app/assets/javascripts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/app/assets/javascripts/.DS_Store -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin_jcrop/crop_modal.js.coffee: -------------------------------------------------------------------------------- 1 | window.active_admin_jcrop = 2 | start: -> 3 | if $('.crop_modal_open').length 4 | $('.crop_modal_open').click -> 5 | content = $(this).parent().find('.crop_modal_content').clone() 6 | image = content.find('img.cropping_image') 7 | active_admin_jcrop.buttons_text = 8 | save_cropped_image: image.data('translateSaveCroppedImage') 9 | cancel: image.data('translateCancel') 10 | active_admin_jcrop.cropper = 11 | object_class: image.data('objectClass') 12 | object_id: image.data('objectId') 13 | crop_field: image.data('cropField') 14 | jcropper_url: image.data('jcropperUrl') 15 | 16 | $(content).appendTo('body').dialog 17 | width: content.width() 18 | height: content.height() + 100 19 | modal: true 20 | position: { 21 | my: "center", 22 | at: "center", 23 | of: window 24 | } 25 | buttons: [ 26 | { 27 | text: active_admin_jcrop.buttons_text.save_cropped_image 28 | click: -> 29 | submitButton = $('input[type="submit"]')[0] 30 | submitButton.disabled = true 31 | previousValue = submitButton.value 32 | submitButton.value = 'Cropping image...' 33 | text: 'aews' 34 | cropper = active_admin_jcrop.cropper 35 | $.ajax 36 | type: 'PUT' 37 | url: cropper.jcropper_url 38 | data: 39 | image_data: cropper 40 | success: -> 41 | location.reload() 42 | submitButton.value = previousValue 43 | submitButton.disabled = false 44 | error: -> 45 | alert('There was an error while cropping the image') 46 | $(@).dialog('close') 47 | } 48 | { 49 | text: active_admin_jcrop.buttons_text.cancel 50 | click: -> 51 | $(@).dialog('close').remove() 52 | 53 | } 54 | ] 55 | options = $.extend {}, image.data('jcropOptions') 56 | options.onSelect = (coords) -> 57 | update_cropper(coords) 58 | if image.data('jcropOptions').showDimensions 59 | content.find('.crop_modal_dimensions').first().text("#{coords.w}x#{coords.h}") 60 | if fn = image.data('jcropOptions').onSelect 61 | if typeof fn is 'string' 62 | window[fn] coords 63 | else if typeof fn is 'function' 64 | fn coords 65 | return 66 | options.onChange = (coords) -> 67 | update_cropper(coords) 68 | if image.data('jcropOptions').showDimensions 69 | content.find('.crop_modal_dimensions').first().text("#{coords.w}x#{coords.h}") 70 | if fn = image.data('jcropOptions').onChange 71 | if typeof fn is 'string' 72 | window[fn] coords 73 | else if typeof fn is 'function' 74 | fn coords 75 | return 76 | options.onRelease = -> 77 | if fn = image.data('jcropOptions').onRelease 78 | if typeof fn is 'string' 79 | window[fn] coords 80 | else if typeof fn is 'function' 81 | fn coords 82 | return 83 | image.Jcrop(options) 84 | return 85 | 86 | update_cropper = (coords) -> 87 | active_admin_jcrop.cropper.crop_x = coords.x 88 | active_admin_jcrop.cropper.crop_y = coords.y 89 | active_admin_jcrop.cropper.crop_w = coords.w 90 | active_admin_jcrop.cropper.crop_h = coords.h 91 | return 92 | return 93 | 94 | $ -> 95 | active_admin_jcrop.start() 96 | -------------------------------------------------------------------------------- /app/assets/stylesheets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/app/assets/stylesheets/.DS_Store -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin_jcrop/crop_modal.css: -------------------------------------------------------------------------------- 1 | .crop_modal_dimensions { 2 | float: left; 3 | } 4 | .crop_modal_content { 5 | display: none; 6 | overflow: scroll; 7 | width: 1000px; 8 | height: 600px ; 9 | } 10 | 11 | .ui-dialog 12 | { 13 | position:fixed; 14 | } -------------------------------------------------------------------------------- /app/views/active_admin_jcrop/_jcrop_modal.html.erb: -------------------------------------------------------------------------------- 1 | <%= link_to I18n.t("active_admin.crop.open_crop_modal").titleize, "#" , class: "button crop_modal_open" %> 2 | 3 | <%= content_tag :div, class: "crop_modal_content" do %> 4 |
5 |
6 | <%= image_tag object.send(field).url, class: 'cropping_image', data: { 7 | object_class: object.class.to_s.underscore, 8 | object_id: object.id, 9 | crop_field: field, 10 | jcropper_url: jcropper_url(object) , 11 | translate_save_cropped_image: I18n.t("active_admin.crop.save_cropped_image").titleize, 12 | translate_cancel: I18n.t("active_admin.crop.cancel").titleize, 13 | jcrop_options: jcrop_options.to_json 14 | } 15 | %> 16 |
17 | <% end %> 18 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | active_admin: 3 | crop: 4 | open_crop_modal: Crop Image 5 | save_cropped_image: Save Cropped Image 6 | cancel: Cancel 7 | -------------------------------------------------------------------------------- /config/locales/pt-BR.yml: -------------------------------------------------------------------------------- 1 | pt-BR: 2 | active_admin: 3 | crop: 4 | open_crop_modal: Cortar Imagem 5 | save_cropped_image: Salvar Imagem Cortada 6 | cancel: Cancelar 7 | -------------------------------------------------------------------------------- /lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/lib/.DS_Store -------------------------------------------------------------------------------- /lib/active_admin_jcrop.rb: -------------------------------------------------------------------------------- 1 | require "activeadmin" 2 | require "active_admin_jcrop/dsl" 3 | require 'active_admin_jcrop/asset_engine' 4 | require 'active_admin_jcrop/orm' 5 | require "formtastic/inputs/jcrop_input" 6 | require "active_admin_jcrop/engine" 7 | require "active_admin_jcrop/railtie" 8 | require 'active_admin_jcrop/image_helper' 9 | require 'active_admin_jcrop/view_helpers' 10 | -------------------------------------------------------------------------------- /lib/active_admin_jcrop/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/lib/active_admin_jcrop/.DS_Store -------------------------------------------------------------------------------- /lib/active_admin_jcrop/asset_engine.rb: -------------------------------------------------------------------------------- 1 | if Gem::Specification::find_all_by_name('carrierwave').any? 2 | require 'active_admin_jcrop/asset_engine/carrier_wave' 3 | elsif Gem::Specification::find_all_by_name('paperclip').any? 4 | require 'active_admin_jcrop/asset_engine/paperclip' 5 | end 6 | -------------------------------------------------------------------------------- /lib/active_admin_jcrop/asset_engine/carrier_wave.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdminJcrop 2 | module AssetEngine 3 | class <rake doc:app. 29 | -------------------------------------------------------------------------------- /spec/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/dashboard.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | 3 | menu priority: 1, label: proc{ I18n.t("active_admin.dashboard") } 4 | 5 | content title: proc{ I18n.t("active_admin.dashboard") } do 6 | div class: "blank_slate_container", id: "dashboard_default_message" do 7 | span class: "blank_slate" do 8 | span I18n.t("active_admin.dashboard_welcome.welcome") 9 | small I18n.t("active_admin.dashboard_welcome.call_to_action") 10 | end 11 | end 12 | 13 | # Here is an example of a simple dashboard with columns and panels. 14 | # 15 | # columns do 16 | # column do 17 | # panel "Recent Posts" do 18 | # ul do 19 | # Post.recent(5).map do |post| 20 | # li link_to(post.title, admin_post_path(post)) 21 | # end 22 | # end 23 | # end 24 | # end 25 | 26 | # column do 27 | # panel "Info" do 28 | # para "Welcome to ActiveAdmin." 29 | # end 30 | # end 31 | # end 32 | end # content 33 | end 34 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/post.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Post do 2 | 3 | jcropable 4 | 5 | form do |f| 6 | f.inputs "Details" do 7 | f.input :image, as: :jcropable , jcrop_options: Post::DEFAULT_CROP_OPTIONS 8 | end 9 | f.actions 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/active_admin.js.coffee: -------------------------------------------------------------------------------- 1 | #= require active_admin/base 2 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require_tree . 14 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/active_admin.css.scss: -------------------------------------------------------------------------------- 1 | // SASS variable overrides must be declared before loading up Active Admin's styles. 2 | // 3 | // To view the variables that Active Admin provides, take a look at 4 | // `app/assets/stylesheets/active_admin/mixins/_variables.css.scss` in the 5 | // Active Admin source. 6 | // 7 | // For example, to change the sidebar width: 8 | // $sidebar-width: 242px; 9 | 10 | // Active Admin's got SASS! 11 | @import "active_admin/mixins"; 12 | @import "active_admin/base"; 13 | 14 | // Overriding any non-variable SASS must be done after the fact. 15 | // For example, to change the default status-tag color: 16 | // 17 | // .status_tag { background: #6090DB; } 18 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/app/mailers/.keep -------------------------------------------------------------------------------- /spec/dummy/app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/app/models/.keep -------------------------------------------------------------------------------- /spec/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ActiveRecord::Base 2 | DEFAULT_CROP_OPTIONS = {aspectRatio: 1} 3 | mount_uploader :image, ImageUploader 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/uploaders/image_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class ImageUploader < CarrierWave::Uploader::Base 4 | 5 | # Include RMagick or MiniMagick support: 6 | # include CarrierWave::RMagick 7 | include CarrierWave::MiniMagick 8 | include ActiveAdminJcrop::AssetEngine::CarrierWave 9 | 10 | # Choose what kind of storage to use for this uploader: 11 | storage :file 12 | # storage :fog 13 | 14 | # Override the directory where uploaded files will be stored. 15 | # This is a sensible default for uploaders that are meant to be mounted: 16 | def store_dir 17 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" 18 | end 19 | 20 | # Provide a default URL as a default if there hasn't been a file uploaded: 21 | # def default_url 22 | # # For Rails 3.1+ asset pipeline compatibility: 23 | # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) 24 | # 25 | # "/images/fallback/" + [version_name, "default.png"].compact.join('_') 26 | # end 27 | 28 | # Process files as they are uploaded: 29 | # process :scale => [200, 300] 30 | # 31 | # def scale(width, height) 32 | # # do something 33 | # end 34 | 35 | # Create different versions of your uploaded files: 36 | version :thumb do 37 | process :active_admin_crop 38 | process :resize_to_fit => [200, 200] 39 | end 40 | 41 | # Add a white list of extensions which are allowed to be uploaded. 42 | # For images you might use something like this: 43 | # def extension_white_list 44 | # %w(jpg jpeg gif png) 45 | # end 46 | 47 | # Override the filename of the uploaded files: 48 | # Avoid using model.id or version_name here, see uploader/store.rb for details. 49 | # def filename 50 | # "something.jpg" if original_filename 51 | # end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/dummy/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /spec/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /spec/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /spec/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /spec/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | require "active_admin_jcrop" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | 11 | # Settings in config/environments/* take precedence over those specified here. 12 | # Application configuration should go into files in config/initializers 13 | # -- all .rb files in that directory are automatically loaded. 14 | 15 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 17 | # config.time_zone = 'Central Time (US & Canada)' 18 | 19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 21 | # config.i18n.default_locale = :de 22 | end 23 | end -------------------------------------------------------------------------------- /spec/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) -------------------------------------------------------------------------------- /spec/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: mysql2 3 | encoding: utf8 4 | reconnect: false 5 | database: active_admin_jcrop_development 6 | pool: 25 7 | username: root 8 | password: 9 | 10 | 11 | test: 12 | adapter: mysql2 13 | encoding: utf8 14 | reconnect: false 15 | database: active_admin_jcrop_test 16 | pool: 25 17 | username: root 18 | password: -------------------------------------------------------------------------------- /spec/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Adds additional error checking when serving assets at runtime. 31 | # Checks for improperly declared sprockets dependencies. 32 | # Raises helpful error messages. 33 | config.assets.raise_runtime_errors = true 34 | 35 | # Raises error for missing translations 36 | # config.action_view.raise_on_missing_translations = true 37 | end 38 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 20 | # config.action_dispatch.rack_cache = true 21 | 22 | # Disable Rails's static asset server (Apache or nginx will already do this). 23 | config.serve_static_assets = false 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = true 34 | 35 | # Version of your assets, change this if you want to expire all your assets. 36 | config.assets.version = '1.0' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Set to :debug to see everything in the log. 46 | config.log_level = :info 47 | 48 | # Prepend all log lines with the following tags. 49 | # config.log_tags = [ :subdomain, :uuid ] 50 | 51 | # Use a different logger for distributed setups. 52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 58 | # config.action_controller.asset_host = "http://assets.example.com" 59 | 60 | # Precompile additional assets. 61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 62 | # config.assets.precompile += %w( search.js ) 63 | 64 | # Ignore bad email addresses and do not raise email delivery errors. 65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 66 | # config.action_mailer.raise_delivery_errors = false 67 | 68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 69 | # the I18n.default_locale when a translation cannot be found). 70 | config.i18n.fallbacks = true 71 | 72 | # Send deprecation notices to registered listeners. 73 | config.active_support.deprecation = :notify 74 | 75 | # Disable automatic flushing of the log to improve performance. 76 | # config.autoflush_log = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | 81 | # Do not dump schema after migrations. 82 | config.active_record.dump_schema_after_migration = false 83 | end 84 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = false 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static asset server for tests with Cache-Control for performance. 16 | config.serve_static_assets = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | # Show full error reports and disable caching. 21 | config.consider_all_requests_local = true 22 | config.action_controller.perform_caching = false 23 | 24 | config.action_dispatch.show_exceptions = false 25 | # Don't care if the mailer can't send. 26 | config.action_mailer.raise_delivery_errors = false 27 | 28 | # Print deprecation notices to the Rails logger. 29 | config.active_support.deprecation = :log 30 | 31 | # Raise an error on page load if there are pending migrations. 32 | config.active_record.migration_error = :page_load 33 | # Disable request forgery protection in test environment. 34 | config.action_controller.allow_forgery_protection = false 35 | 36 | # Tell Action Mailer not to deliver emails to the real world. 37 | # The :test delivery method accumulates sent emails in the 38 | # ActionMailer::Base.deliveries array. 39 | config.action_mailer.delivery_method = :test 40 | 41 | # Print deprecation notices to the stderr. 42 | config.active_support.deprecation = :stderr 43 | 44 | # Raises error for missing translations 45 | # config.action_view.raise_on_missing_translations = true 46 | end 47 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/active_admin.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.setup do |config| 2 | 3 | # == Site Title 4 | # 5 | # Set the title that is displayed on the main layout 6 | # for each of the active admin pages. 7 | # 8 | config.site_title = "Dummy" 9 | 10 | # Set the link url for the title. For example, to take 11 | # users to your main site. Defaults to no link. 12 | # 13 | # config.site_title_link = "/" 14 | 15 | # Set an optional image to be displayed for the header 16 | # instead of a string (overrides :site_title) 17 | # 18 | # Note: Aim for an image that's 21px high so it fits in the header. 19 | # 20 | # config.site_title_image = "logo.png" 21 | 22 | # == Default Namespace 23 | # 24 | # Set the default namespace each administration resource 25 | # will be added to. 26 | # 27 | # eg: 28 | # config.default_namespace = :hello_world 29 | # 30 | # This will create resources in the HelloWorld module and 31 | # will namespace routes to /hello_world/* 32 | # 33 | # To set no namespace by default, use: 34 | # config.default_namespace = false 35 | # 36 | # Default: 37 | # config.default_namespace = :admin 38 | # 39 | # You can customize the settings for each namespace by using 40 | # a namespace block. For example, to change the site title 41 | # within a namespace: 42 | # 43 | # config.namespace :admin do |admin| 44 | # admin.site_title = "Custom Admin Title" 45 | # end 46 | # 47 | # This will ONLY change the title for the admin section. Other 48 | # namespaces will continue to use the main "site_title" configuration. 49 | 50 | # == User Authentication 51 | # 52 | # Active Admin will automatically call an authentication 53 | # method in a before filter of all controller actions to 54 | # ensure that there is a currently logged in admin user. 55 | # 56 | # This setting changes the method which Active Admin calls 57 | # within the application controller. 58 | #config.authentication_method = :authenticate_admin_user! 59 | 60 | # == User Authorization 61 | # 62 | # Active Admin will automatically call an authorization 63 | # method in a before filter of all controller actions to 64 | # ensure that there is a user with proper rights. You can use 65 | # CanCanAdapter or make your own. Please refer to documentation. 66 | # config.authorization_adapter = ActiveAdmin::CanCanAdapter 67 | 68 | # You can customize your CanCan Ability class name here. 69 | # config.cancan_ability_class = "Ability" 70 | 71 | # You can specify a method to be called on unauthorized access. 72 | # This is necessary in order to prevent a redirect loop which happens 73 | # because, by default, user gets redirected to Dashboard. If user 74 | # doesn't have access to Dashboard, he'll end up in a redirect loop. 75 | # Method provided here should be defined in application_controller.rb. 76 | # config.on_unauthorized_access = :access_denied 77 | 78 | # == Current User 79 | # 80 | # Active Admin will associate actions with the current 81 | # user performing them. 82 | # 83 | # This setting changes the method which Active Admin calls 84 | # (within the application controller) to return the currently logged in user. 85 | # config.current_user_method = :current_admin_user 86 | 87 | 88 | # == Logging Out 89 | # 90 | # Active Admin displays a logout link on each screen. These 91 | # settings configure the location and method used for the link. 92 | # 93 | # This setting changes the path where the link points to. If it's 94 | # a string, the strings is used as the path. If it's a Symbol, we 95 | # will call the method to return the path. 96 | # 97 | # Default: 98 | config.logout_link_path = :destroy_admin_user_session_path 99 | 100 | # This setting changes the http method used when rendering the 101 | # link. For example :get, :delete, :put, etc.. 102 | # 103 | # Default: 104 | # config.logout_link_method = :get 105 | 106 | 107 | # == Root 108 | # 109 | # Set the action to call for the root path. You can set different 110 | # roots for each namespace. 111 | # 112 | # Default: 113 | # config.root_to = 'dashboard#index' 114 | 115 | 116 | # == Admin Comments 117 | # 118 | # This allows your users to comment on any resource registered with Active Admin. 119 | # 120 | # You can completely disable comments: 121 | # config.allow_comments = false 122 | # 123 | # You can disable the menu item for the comments index page: 124 | # config.show_comments_in_menu = false 125 | # 126 | # You can change the name under which comments are registered: 127 | # config.comments_registration_name = 'AdminComment' 128 | 129 | 130 | # == Batch Actions 131 | # 132 | # Enable and disable Batch Actions 133 | # 134 | config.batch_actions = true 135 | 136 | 137 | # == Controller Filters 138 | # 139 | # You can add before, after and around filters to all of your 140 | # Active Admin resources and pages from here. 141 | # 142 | # config.before_filter :do_something_awesome 143 | 144 | 145 | # == Setting a Favicon 146 | # 147 | # config.favicon = '/assets/favicon.ico' 148 | 149 | 150 | # == Removing Breadcrumbs 151 | # 152 | # Breadcrumbs are enabled by default. You can customize them for individual 153 | # resources or you can disable them globally from here. 154 | # 155 | # config.breadcrumb = false 156 | 157 | 158 | # == Register Stylesheets & Javascripts 159 | # 160 | # We recommend using the built in Active Admin layout and loading 161 | # up your own stylesheets / javascripts to customize the look 162 | # and feel. 163 | # 164 | # To load a stylesheet: 165 | # config.register_stylesheet 'my_stylesheet.css' 166 | # 167 | # You can provide an options hash for more control, which is passed along to stylesheet_link_tag(): 168 | # config.register_stylesheet 'my_print_stylesheet.css', :media => :print 169 | # 170 | # To load a javascript file: 171 | # config.register_javascript 'active_admin_jcrop/crop_modal' 172 | 173 | 174 | # == CSV options 175 | # 176 | # Set the CSV builder separator 177 | # config.csv_options = { :col_sep => ';' } 178 | # 179 | # Force the use of quotes 180 | # config.csv_options = { :force_quotes => true } 181 | 182 | 183 | # == Menu System 184 | # 185 | # You can add a navigation menu to be used in your application, or configure a provided menu 186 | # 187 | # To change the default utility navigation to show a link to your website & a logout btn 188 | # 189 | # config.namespace :admin do |admin| 190 | # admin.build_menu :utility_navigation do |menu| 191 | # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank } 192 | # admin.add_logout_button_to_menu menu 193 | # end 194 | # end 195 | # 196 | # If you wanted to add a static menu item to the default menu provided: 197 | # 198 | # config.namespace :admin do |admin| 199 | # admin.build_menu :default do |menu| 200 | # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank } 201 | # end 202 | # end 203 | 204 | 205 | # == Download Links 206 | # 207 | # You can disable download links on resource listing pages, 208 | # or customize the formats shown per namespace/globally 209 | # 210 | # To disable/customize for the :admin namespace: 211 | # 212 | # config.namespace :admin do |admin| 213 | # 214 | # # Disable the links entirely 215 | # admin.download_links = false 216 | # 217 | # # Only show XML & PDF options 218 | # admin.download_links = [:xml, :pdf] 219 | # 220 | # # Enable/disable the links based on block 221 | # # (for example, with cancan) 222 | # admin.download_links = proc { can?(:view_download_links) } 223 | # 224 | # end 225 | 226 | 227 | # == Pagination 228 | # 229 | # Pagination is enabled by default for all resources. 230 | # You can control the default per page count for all resources here. 231 | # 232 | # config.default_per_page = 30 233 | 234 | 235 | # == Filters 236 | # 237 | # By default the index screen includes a “Filters” sidebar on the right 238 | # hand side with a filter for each attribute of the registered model. 239 | # You can enable or disable them for all resources here. 240 | # 241 | # config.filters = true 242 | 243 | end 244 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json -------------------------------------------------------------------------------- /spec/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /spec/dummy/config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | devise: 5 | confirmations: 6 | confirmed: "Your account was successfully confirmed." 7 | send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." 8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes." 9 | failure: 10 | already_authenticated: "You are already signed in." 11 | inactive: "Your account is not activated yet." 12 | invalid: "Invalid email or password." 13 | locked: "Your account is locked." 14 | last_attempt: "You have one more attempt before your account will be locked." 15 | not_found_in_database: "Invalid email or password." 16 | timeout: "Your session expired. Please sign in again to continue." 17 | unauthenticated: "You need to sign in or sign up before continuing." 18 | unconfirmed: "You have to confirm your account before continuing." 19 | mailer: 20 | confirmation_instructions: 21 | subject: "Confirmation instructions" 22 | reset_password_instructions: 23 | subject: "Reset password instructions" 24 | unlock_instructions: 25 | subject: "Unlock Instructions" 26 | omniauth_callbacks: 27 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 28 | success: "Successfully authenticated from %{kind} account." 29 | passwords: 30 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." 31 | send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." 32 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." 33 | updated: "Your password was changed successfully. You are now signed in." 34 | updated_not_active: "Your password was changed successfully." 35 | registrations: 36 | destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." 37 | signed_up: "Welcome! You have signed up successfully." 38 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." 39 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." 40 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account." 41 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." 42 | updated: "You updated your account successfully." 43 | sessions: 44 | signed_in: "Signed in successfully." 45 | signed_out: "Signed out successfully." 46 | unlocks: 47 | send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." 48 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes." 49 | unlocked: "Your account has been unlocked successfully. Please sign in to continue." 50 | errors: 51 | messages: 52 | already_confirmed: "was already confirmed, please try signing in" 53 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" 54 | expired: "has expired, please request a new one" 55 | not_found: "not found" 56 | not_locked: "was not locked" 57 | not_saved: 58 | one: "1 error prohibited this %{resource} from being saved:" 59 | other: "%{count} errors prohibited this %{resource} from being saved:" 60 | -------------------------------------------------------------------------------- /spec/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /spec/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | 3 | root to: "admin/dashboard#index" 4 | 5 | ActiveAdmin.routes(self) 6 | # The priority is based upon order of creation: first created -> highest priority. 7 | # See how all your routes lay out with "rake routes". 8 | 9 | # You can have the root of your site routed with "root" 10 | 11 | 12 | # Example of regular route: 13 | # get 'products/:id' => 'catalog#view' 14 | 15 | # Example of named route that can be invoked with purchase_url(id: product.id) 16 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 17 | 18 | # Example resource route (maps HTTP verbs to controller actions automatically): 19 | # resources :products 20 | 21 | # Example resource route with options: 22 | # resources :products do 23 | # member do 24 | # get 'short' 25 | # post 'toggle' 26 | # end 27 | # 28 | # collection do 29 | # get 'sold' 30 | # end 31 | # end 32 | 33 | # Example resource route with sub-resources: 34 | # resources :products do 35 | # resources :comments, :sales 36 | # resource :seller 37 | # end 38 | 39 | # Example resource route with more complex sub-resources: 40 | # resources :products do 41 | # resources :comments 42 | # resources :sales do 43 | # get 'recent', on: :collection 44 | # end 45 | # end 46 | 47 | # Example resource route with concerns: 48 | # concern :toggleable do 49 | # post 'toggle' 50 | # end 51 | # resources :posts, concerns: :toggleable 52 | # resources :photos, concerns: :toggleable 53 | 54 | # Example resource route within a namespace: 55 | # namespace :admin do 56 | # # Directs /admin/products/* to Admin::ProductsController 57 | # # (app/controllers/admin/products_controller.rb) 58 | # resources :products 59 | # end 60 | end 61 | -------------------------------------------------------------------------------- /spec/dummy/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: f97c679329258cbdfbef0be59bb6e5473b8371aac83e6ec3eb4d54bfe8de9c15a8be82d0699f0dd0d1a6cc23ab4a9c8b541aef398f556a4e12af1b578ff78842 15 | 16 | test: 17 | secret_key_base: ee2a0cec7b9b2d01092dfbd17477210ef6e8a8facd4dd83d6a25a41005f9f687ecca82ca31c72e826be15d2b0e5166d449d4d8bca563b5a50d9422d618a9139a 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20140609195344_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration 2 | def change 3 | create_table :posts do |t| 4 | t.string :name 5 | t.string :image 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20140609200814_create_active_admin_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateActiveAdminComments < ActiveRecord::Migration 2 | def self.up 3 | create_table :active_admin_comments do |t| 4 | t.string :namespace 5 | t.text :body 6 | t.string :resource_id, null: false 7 | t.string :resource_type, null: false 8 | t.references :author, polymorphic: true 9 | t.timestamps 10 | end 11 | add_index :active_admin_comments, [:namespace] 12 | add_index :active_admin_comments, [:author_type, :author_id] 13 | add_index :active_admin_comments, [:resource_type, :resource_id] 14 | end 15 | 16 | def self.down 17 | drop_table :active_admin_comments 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20140609202215_devise_create_admin_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateAdminUsers < ActiveRecord::Migration 2 | def migrate(direction) 3 | super 4 | # Create a default user 5 | #AdminUser.create!(email: 'admin@example.com', password: 'password', password_confirmation: 'password') if direction == :up 6 | end 7 | 8 | def change 9 | create_table(:admin_users) do |t| 10 | ## Database authenticatable 11 | t.string :email, null: false, default: "" 12 | t.string :encrypted_password, null: false, default: "" 13 | 14 | ## Recoverable 15 | t.string :reset_password_token 16 | t.datetime :reset_password_sent_at 17 | 18 | ## Rememberable 19 | t.datetime :remember_created_at 20 | 21 | ## Trackable 22 | t.integer :sign_in_count, default: 0, null: false 23 | t.datetime :current_sign_in_at 24 | t.datetime :last_sign_in_at 25 | t.string :current_sign_in_ip 26 | t.string :last_sign_in_ip 27 | 28 | ## Confirmable 29 | # t.string :confirmation_token 30 | # t.datetime :confirmed_at 31 | # t.datetime :confirmation_sent_at 32 | # t.string :unconfirmed_email # Only if using reconfirmable 33 | 34 | ## Lockable 35 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts 36 | # t.string :unlock_token # Only if unlock strategy is :email or :both 37 | # t.datetime :locked_at 38 | 39 | 40 | t.timestamps 41 | end 42 | 43 | add_index :admin_users, :email, unique: true 44 | add_index :admin_users, :reset_password_token, unique: true 45 | # add_index :admin_users, :confirmation_token, unique: true 46 | # add_index :admin_users, :unlock_token, unique: true 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20140619201236_drop_admin_user_table.rb: -------------------------------------------------------------------------------- 1 | class DropAdminUserTable < ActiveRecord::Migration 2 | def change 3 | drop_table :admin_users 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20140619201236) do 15 | 16 | create_table "active_admin_comments", force: true do |t| 17 | t.string "namespace" 18 | t.text "body" 19 | t.string "resource_id", null: false 20 | t.string "resource_type", null: false 21 | t.integer "author_id" 22 | t.string "author_type" 23 | t.datetime "created_at" 24 | t.datetime "updated_at" 25 | end 26 | 27 | add_index "active_admin_comments", ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id", using: :btree 28 | add_index "active_admin_comments", ["namespace"], name: "index_active_admin_comments_on_namespace", using: :btree 29 | add_index "active_admin_comments", ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id", using: :btree 30 | 31 | create_table "posts", force: true do |t| 32 | t.string "name" 33 | t.string "image" 34 | t.datetime "created_at" 35 | t.datetime "updated_at" 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /spec/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /spec/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/log/.keep -------------------------------------------------------------------------------- /spec/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

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

63 |
64 |

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

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

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

63 |
64 |

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

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

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

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /spec/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/dummy/public/favicon.ico -------------------------------------------------------------------------------- /spec/dummy/spec: -------------------------------------------------------------------------------- 1 | ../../spec -------------------------------------------------------------------------------- /spec/factories.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :post do 3 | name "Name of Post" 4 | image Rack::Test::UploadedFile.new(File.open(Rails.root.join('spec', 'images', 'example.jpeg'))) 5 | #image { fixture_file_upload(Rails.root.join('spec', 'images', 'example.jpeg'), 'image/jpeg') } 6 | end 7 | end -------------------------------------------------------------------------------- /spec/features/post_jcrop_feature_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'phashion' 3 | 4 | 5 | feature 'Post admin' do 6 | 7 | describe 'Croping modal', js: true do 8 | 9 | subject { page } 10 | 11 | background do 12 | @post = FactoryGirl.create(:post) 13 | visit "/admin/posts/#{@post.id}/edit" 14 | end 15 | 16 | elements = {'button to open crop modal' => '.crop_modal_open', 17 | 'modal div' => '.crop_modal_content', 18 | 'image to be cropped' => '.cropping_image' 19 | } 20 | 21 | elements.each_pair do |name, element_class| 22 | it "should have the #{name} displayed" do 23 | expect(page).to have_css(element_class, visible: false) 24 | end 25 | end 26 | 27 | 28 | it "should open the crop modal when clicking at the button" do 29 | modal_classes = '.ui-dialog.ui-widget.ui-widget-content.ui-corner-all.ui-front' 30 | expect(page).not_to have_css(modal_classes) 31 | click_link "Crop Image" 32 | modal = page.find(modal_classes) 33 | expect(modal).to have_css('img.cropping_image') 34 | end 35 | 36 | it "should close the modal when click at cancel" do 37 | modal_classes = '.ui-dialog.ui-widget.ui-widget-content.ui-corner-all.ui-front' 38 | click_link "Crop Image" 39 | click_link "Cancel" 40 | expect(page).not_to have_css(modal_classes) 41 | end 42 | 43 | it "should crop the thumb version of the Image" do 44 | thumb = Phashion::Image.new(MiniMagick::Image.open(@post.image.thumb.path).path) #load copy of image as a temp file 45 | click_link "Crop Image" 46 | click_button "Save Cropped Image" 47 | sleep 3 # wait for the ajax 48 | cropped_thumb = Phashion::Image.new @post.image.thumb.path 49 | expect(cropped_thumb.duplicate?(thumb)).to be_falsey 50 | end 51 | 52 | it "should pass the options specified at the form to jcrop" do 53 | new_options = {aspectRatio: 0.5, setSelect: [0, 0, 25, 25]} 54 | stub_const "Post::DEFAULT_CROP_OPTIONS", new_options 55 | visit "/admin/posts/#{@post.id}/edit" 56 | jcrop_attributes = page.find('.cropping_image', visible: false)['data-jcrop-options'] 57 | expect(jcrop_attributes).to be_present 58 | jcrop_attributes = JSON.parse(jcrop_attributes).symbolize_keys 59 | expect(jcrop_attributes).to be == new_options 60 | end 61 | end 62 | end -------------------------------------------------------------------------------- /spec/images/example.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/spec/images/example.jpeg -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | require File.expand_path("../dummy/config/environment", __FILE__) 4 | require 'carrierwave' 5 | require 'carrierwave/orm/activerecord' 6 | 7 | require_relative 'dummy/app/models/post' 8 | 9 | require 'rspec/rails' 10 | require 'database_cleaner' 11 | require 'factory_girl' 12 | require 'factories' 13 | require 'formtastic/inputs/jcrop_input' 14 | 15 | require 'activeadmin' 16 | require 'pry' 17 | 18 | include ActionDispatch::TestProcess 19 | 20 | #Workaround for Capybara/RSPEC issues 21 | require_relative 'dummy/app/admin/post' 22 | require_relative 'dummy/app/admin/dashboard' 23 | require_relative 'dummy/config/routes' 24 | 25 | 26 | # Requires supporting ruby files with custom matchers and macros, etc, in 27 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 28 | # run as spec files by default. This means that files in spec/support that end 29 | # in _spec.rb will both be required and run as specs, causing the specs to be 30 | # run twice. It is recommended that you do not name files matching this glob to 31 | # end with _spec.rb. You can configure this pattern with with the --pattern 32 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 33 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 34 | 35 | # Checks for pending migrations before tests are run. 36 | # If you are not using ActiveRecord, you can remove this line. 37 | ActiveRecord::Migration.maintain_test_schema! 38 | 39 | RSpec.configure do |config| 40 | config.include FactoryGirl::Syntax::Methods 41 | # ## Mock Framework 42 | # 43 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 44 | # 45 | # config.mock_with :mocha 46 | # config.mock_with :flexmock 47 | # config.mock_with :rr 48 | 49 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 50 | # config.fixture_path = "#{::Rails.root}/spec/fixtures" 51 | 52 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 53 | # examples within a transaction, remove the following line or assign false 54 | # instead of true. 55 | #config.use_transactional_fixtures = false 56 | 57 | # If true, the base class of anonymous controllers will be inferred 58 | # automatically. This will be the default behavior in future versions of 59 | # rspec-rails. 60 | config.infer_base_class_for_anonymous_controllers = false 61 | 62 | # Run specs in random order to surface order dependencies. If you find an 63 | # order dependency and want to debug it, you can fix the order by providing 64 | # the seed, which is printed after each run. 65 | # --seed 1234 66 | config.after(:each) do 67 | if Rails.env.test? || Rails.env.cucumber? 68 | FileUtils.rm_rf(Dir["#{Rails.root}/spec/dummy/public/post"]) 69 | end 70 | end 71 | 72 | config.order = "random" 73 | 74 | # RSpec Rails can automatically mix in different behaviours to your tests 75 | # based on their file location, for example enabling you to call `get` and 76 | # `post` in specs under `spec/controllers`. 77 | # 78 | # You can disable this behaviour by removing the line below, and instead 79 | # explictly tag your specs with their type, e.g.: 80 | # 81 | # describe UsersController, :type => :controller do 82 | # # ... 83 | # end 84 | # 85 | 86 | 87 | config.use_transactional_fixtures = false 88 | config.before :each do 89 | DatabaseCleaner.start 90 | end 91 | config.after :each do 92 | DatabaseCleaner.clean 93 | end 94 | 95 | 96 | # config.before(:suite) do 97 | # DatabaseCleaner.strategy = :transaction 98 | # DatabaseCleaner.clean_with(:truncation) 99 | # end 100 | 101 | config.around(:each) do |example| 102 | DatabaseCleaner.cleaning do 103 | example.run 104 | end 105 | end 106 | 107 | # The different available types are documented in the features, such as in 108 | # https://relishapp.com/rspec/rspec-rails/v/3-0/docs 109 | config.infer_spec_type_from_file_location! 110 | end 111 | 112 | 113 | -------------------------------------------------------------------------------- /spec/support/active_record.rb: -------------------------------------------------------------------------------- 1 | class ActiveRecord::Base 2 | mattr_accessor :shared_connection 3 | @@shared_connection = nil 4 | 5 | def self.connection 6 | @@shared_connection || retrieve_connection 7 | end 8 | end 9 | 10 | # Forces all threads to share the same connection. This works on 11 | # Capybara because it starts the web server in a thread. 12 | ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection 13 | -------------------------------------------------------------------------------- /spec/support/carrierwave.rb: -------------------------------------------------------------------------------- 1 | if Rails.env.test? || Rails.env.cucumber? 2 | CarrierWave.configure do |config| 3 | config.storage = :file 4 | end 5 | 6 | # use different dirs when testing 7 | CarrierWave::Uploader::Base.descendants.each do |klass| 8 | next if klass.anonymous? 9 | klass.class_eval do 10 | def cache_dir 11 | "#{Rails.root}/public/tmp" 12 | end 13 | 14 | def store_dir 15 | "#{Rails.root}/public/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" 16 | end 17 | end 18 | end 19 | CarrierWave.configure do |config| 20 | config.root = "#{Rails.root}/public/" 21 | end 22 | end -------------------------------------------------------------------------------- /vendor/assets/images/active_admin_jcrop/Jcrop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/vendor/assets/images/active_admin_jcrop/Jcrop.gif -------------------------------------------------------------------------------- /vendor/assets/javascripts/active_admin_jcrop/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/vendor/assets/javascripts/active_admin_jcrop/.DS_Store -------------------------------------------------------------------------------- /vendor/assets/javascripts/active_admin_jcrop/jquery.Jcrop.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jquery.Jcrop.js v0.9.12 3 | * jQuery Image Cropping Plugin - released under MIT License 4 | * Author: Kelly Hallman 5 | * http://github.com/tapmodo/Jcrop 6 | * Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{ 7 | * 8 | * Permission is hereby granted, free of charge, to any person 9 | * obtaining a copy of this software and associated documentation 10 | * files (the "Software"), to deal in the Software without 11 | * restriction, including without limitation the rights to use, 12 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the 14 | * Software is furnished to do so, subject to the following 15 | * conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | * 29 | * }}} 30 | */ 31 | 32 | (function ($) { 33 | 34 | $.Jcrop = function (obj, opt) { 35 | var options = $.extend({}, $.Jcrop.defaults), 36 | docOffset, 37 | _ua = navigator.userAgent.toLowerCase(), 38 | is_msie = /msie/.test(_ua), 39 | ie6mode = /msie [1-6]\./.test(_ua); 40 | 41 | // Internal Methods {{{ 42 | function px(n) { 43 | return Math.round(n) + 'px'; 44 | } 45 | function cssClass(cl) { 46 | return options.baseClass + '-' + cl; 47 | } 48 | function supportsColorFade() { 49 | return $.fx.step.hasOwnProperty('backgroundColor'); 50 | } 51 | function getPos(obj) //{{{ 52 | { 53 | var pos = $(obj).offset(); 54 | return [pos.left, pos.top]; 55 | } 56 | //}}} 57 | function mouseAbs(e) //{{{ 58 | { 59 | return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])]; 60 | } 61 | //}}} 62 | function setOptions(opt) //{{{ 63 | { 64 | if (typeof(opt) !== 'object') opt = {}; 65 | options = $.extend(options, opt); 66 | 67 | $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) { 68 | if (typeof(options[e]) !== 'function') options[e] = function () {}; 69 | }); 70 | } 71 | //}}} 72 | function startDragMode(mode, pos, touch) //{{{ 73 | { 74 | docOffset = getPos($img); 75 | Tracker.setCursor(mode === 'move' ? mode : mode + '-resize'); 76 | 77 | if (mode === 'move') { 78 | return Tracker.activateHandlers(createMover(pos), doneSelect, touch); 79 | } 80 | 81 | var fc = Coords.getFixed(); 82 | var opp = oppLockCorner(mode); 83 | var opc = Coords.getCorner(oppLockCorner(opp)); 84 | 85 | Coords.setPressed(Coords.getCorner(opp)); 86 | Coords.setCurrent(opc); 87 | 88 | Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch); 89 | } 90 | //}}} 91 | function dragmodeHandler(mode, f) //{{{ 92 | { 93 | return function (pos) { 94 | if (!options.aspectRatio) { 95 | switch (mode) { 96 | case 'e': 97 | pos[1] = f.y2; 98 | break; 99 | case 'w': 100 | pos[1] = f.y2; 101 | break; 102 | case 'n': 103 | pos[0] = f.x2; 104 | break; 105 | case 's': 106 | pos[0] = f.x2; 107 | break; 108 | } 109 | } else { 110 | switch (mode) { 111 | case 'e': 112 | pos[1] = f.y + 1; 113 | break; 114 | case 'w': 115 | pos[1] = f.y + 1; 116 | break; 117 | case 'n': 118 | pos[0] = f.x + 1; 119 | break; 120 | case 's': 121 | pos[0] = f.x + 1; 122 | break; 123 | } 124 | } 125 | Coords.setCurrent(pos); 126 | Selection.update(); 127 | }; 128 | } 129 | //}}} 130 | function createMover(pos) //{{{ 131 | { 132 | var lloc = pos; 133 | KeyManager.watchKeys(); 134 | 135 | return function (pos) { 136 | Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]); 137 | lloc = pos; 138 | 139 | Selection.update(); 140 | }; 141 | } 142 | //}}} 143 | function oppLockCorner(ord) //{{{ 144 | { 145 | switch (ord) { 146 | case 'n': 147 | return 'sw'; 148 | case 's': 149 | return 'nw'; 150 | case 'e': 151 | return 'nw'; 152 | case 'w': 153 | return 'ne'; 154 | case 'ne': 155 | return 'sw'; 156 | case 'nw': 157 | return 'se'; 158 | case 'se': 159 | return 'nw'; 160 | case 'sw': 161 | return 'ne'; 162 | } 163 | } 164 | //}}} 165 | function createDragger(ord) //{{{ 166 | { 167 | return function (e) { 168 | if (options.disabled) { 169 | return false; 170 | } 171 | if ((ord === 'move') && !options.allowMove) { 172 | return false; 173 | } 174 | 175 | // Fix position of crop area when dragged the very first time. 176 | // Necessary when crop image is in a hidden element when page is loaded. 177 | docOffset = getPos($img); 178 | 179 | btndown = true; 180 | startDragMode(ord, mouseAbs(e)); 181 | e.stopPropagation(); 182 | e.preventDefault(); 183 | return false; 184 | }; 185 | } 186 | //}}} 187 | function presize($obj, w, h) //{{{ 188 | { 189 | var nw = $obj.width(), 190 | nh = $obj.height(); 191 | if ((nw > w) && w > 0) { 192 | nw = w; 193 | nh = (w / $obj.width()) * $obj.height(); 194 | } 195 | if ((nh > h) && h > 0) { 196 | nh = h; 197 | nw = (h / $obj.height()) * $obj.width(); 198 | } 199 | xscale = $obj.width() / nw; 200 | yscale = $obj.height() / nh; 201 | $obj.width(nw).height(nh); 202 | } 203 | //}}} 204 | function unscale(c) //{{{ 205 | { 206 | return { 207 | x: c.x * xscale, 208 | y: c.y * yscale, 209 | x2: c.x2 * xscale, 210 | y2: c.y2 * yscale, 211 | w: c.w * xscale, 212 | h: c.h * yscale 213 | }; 214 | } 215 | //}}} 216 | function doneSelect(pos) //{{{ 217 | { 218 | var c = Coords.getFixed(); 219 | if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) { 220 | Selection.enableHandles(); 221 | Selection.done(); 222 | } else { 223 | Selection.release(); 224 | } 225 | Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); 226 | } 227 | //}}} 228 | function newSelection(e) //{{{ 229 | { 230 | if (options.disabled) { 231 | return false; 232 | } 233 | if (!options.allowSelect) { 234 | return false; 235 | } 236 | btndown = true; 237 | docOffset = getPos($img); 238 | Selection.disableHandles(); 239 | Tracker.setCursor('crosshair'); 240 | var pos = mouseAbs(e); 241 | Coords.setPressed(pos); 242 | Selection.update(); 243 | Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch'); 244 | KeyManager.watchKeys(); 245 | 246 | e.stopPropagation(); 247 | e.preventDefault(); 248 | return false; 249 | } 250 | //}}} 251 | function selectDrag(pos) //{{{ 252 | { 253 | Coords.setCurrent(pos); 254 | Selection.update(); 255 | } 256 | //}}} 257 | function newTracker() //{{{ 258 | { 259 | var trk = $('
').addClass(cssClass('tracker')); 260 | if (is_msie) { 261 | trk.css({ 262 | opacity: 0, 263 | backgroundColor: 'white' 264 | }); 265 | } 266 | return trk; 267 | } 268 | //}}} 269 | 270 | // }}} 271 | // Initialization {{{ 272 | // Sanitize some options {{{ 273 | if (typeof(obj) !== 'object') { 274 | obj = $(obj)[0]; 275 | } 276 | if (typeof(opt) !== 'object') { 277 | opt = {}; 278 | } 279 | // }}} 280 | setOptions(opt); 281 | // Initialize some jQuery objects {{{ 282 | // The values are SET on the image(s) for the interface 283 | // If the original image has any of these set, they will be reset 284 | // However, if you destroy() the Jcrop instance the original image's 285 | // character in the DOM will be as you left it. 286 | var img_css = { 287 | border: 'none', 288 | visibility: 'visible', 289 | margin: 0, 290 | padding: 0, 291 | position: 'absolute', 292 | top: 0, 293 | left: 0 294 | }; 295 | 296 | var $origimg = $(obj), 297 | img_mode = true; 298 | 299 | if (obj.tagName == 'IMG') { 300 | // Fix size of crop image. 301 | // Necessary when crop image is within a hidden element when page is loaded. 302 | if ($origimg[0].width != 0 && $origimg[0].height != 0) { 303 | // Obtain dimensions from contained img element. 304 | $origimg.width($origimg[0].width); 305 | $origimg.height($origimg[0].height); 306 | } else { 307 | // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0). 308 | var tempImage = new Image(); 309 | tempImage.src = $origimg[0].src; 310 | $origimg.width(tempImage.width); 311 | $origimg.height(tempImage.height); 312 | } 313 | 314 | var $img = $origimg.clone().removeAttr('id').css(img_css).show(); 315 | 316 | $img.width($origimg.width()); 317 | $img.height($origimg.height()); 318 | $origimg.after($img).hide(); 319 | 320 | } else { 321 | $img = $origimg.css(img_css).show(); 322 | img_mode = false; 323 | if (options.shade === null) { options.shade = true; } 324 | } 325 | 326 | presize($img, options.boxWidth, options.boxHeight); 327 | 328 | var boundx = $img.width(), 329 | boundy = $img.height(), 330 | 331 | 332 | $div = $('
').width(boundx).height(boundy).addClass(cssClass('holder')).css({ 333 | position: 'relative', 334 | backgroundColor: options.bgColor 335 | }).insertAfter($origimg).append($img); 336 | 337 | if (options.addClass) { 338 | $div.addClass(options.addClass); 339 | } 340 | 341 | var $img2 = $('
'), 342 | 343 | $img_holder = $('
') 344 | .width('100%').height('100%').css({ 345 | zIndex: 310, 346 | position: 'absolute', 347 | overflow: 'hidden' 348 | }), 349 | 350 | $hdl_holder = $('
') 351 | .width('100%').height('100%').css('zIndex', 320), 352 | 353 | $sel = $('
') 354 | .css({ 355 | position: 'absolute', 356 | zIndex: 600 357 | }).dblclick(function(){ 358 | var c = Coords.getFixed(); 359 | options.onDblClick.call(api,c); 360 | }).insertBefore($img).append($img_holder, $hdl_holder); 361 | 362 | if (img_mode) { 363 | 364 | $img2 = $('') 365 | .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy), 366 | 367 | $img_holder.append($img2); 368 | 369 | } 370 | 371 | if (ie6mode) { 372 | $sel.css({ 373 | overflowY: 'hidden' 374 | }); 375 | } 376 | 377 | var bound = options.boundary; 378 | var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({ 379 | position: 'absolute', 380 | top: px(-bound), 381 | left: px(-bound), 382 | zIndex: 290 383 | }).mousedown(newSelection); 384 | 385 | /* }}} */ 386 | // Set more variables {{{ 387 | var bgcolor = options.bgColor, 388 | bgopacity = options.bgOpacity, 389 | xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true, 390 | btndown, animating, shift_down; 391 | 392 | docOffset = getPos($img); 393 | // }}} 394 | // }}} 395 | // Internal Modules {{{ 396 | // Touch Module {{{ 397 | var Touch = (function () { 398 | // Touch support detection function adapted (under MIT License) 399 | // from code by Jeffrey Sambells - http://github.com/iamamused/ 400 | function hasTouchSupport() { 401 | var support = {}, events = ['touchstart', 'touchmove', 'touchend'], 402 | el = document.createElement('div'), i; 403 | 404 | try { 405 | for(i=0; i x1 + ox) { 491 | ox -= ox + x1; 492 | } 493 | if (0 > y1 + oy) { 494 | oy -= oy + y1; 495 | } 496 | 497 | if (boundy < y2 + oy) { 498 | oy += boundy - (y2 + oy); 499 | } 500 | if (boundx < x2 + ox) { 501 | ox += boundx - (x2 + ox); 502 | } 503 | 504 | x1 += ox; 505 | x2 += ox; 506 | y1 += oy; 507 | y2 += oy; 508 | } 509 | //}}} 510 | function getCorner(ord) //{{{ 511 | { 512 | var c = getFixed(); 513 | switch (ord) { 514 | case 'ne': 515 | return [c.x2, c.y]; 516 | case 'nw': 517 | return [c.x, c.y]; 518 | case 'se': 519 | return [c.x2, c.y2]; 520 | case 'sw': 521 | return [c.x, c.y2]; 522 | } 523 | } 524 | //}}} 525 | function getFixed() //{{{ 526 | { 527 | if (!options.aspectRatio) { 528 | return getRect(); 529 | } 530 | // This function could use some optimization I think... 531 | var aspect = options.aspectRatio, 532 | min_x = options.minSize[0] / xscale, 533 | 534 | 535 | //min_y = options.minSize[1]/yscale, 536 | max_x = options.maxSize[0] / xscale, 537 | max_y = options.maxSize[1] / yscale, 538 | rw = x2 - x1, 539 | rh = y2 - y1, 540 | rwa = Math.abs(rw), 541 | rha = Math.abs(rh), 542 | real_ratio = rwa / rha, 543 | xx, yy, w, h; 544 | 545 | if (max_x === 0) { 546 | max_x = boundx * 10; 547 | } 548 | if (max_y === 0) { 549 | max_y = boundy * 10; 550 | } 551 | if (real_ratio < aspect) { 552 | yy = y2; 553 | w = rha * aspect; 554 | xx = rw < 0 ? x1 - w : w + x1; 555 | 556 | if (xx < 0) { 557 | xx = 0; 558 | h = Math.abs((xx - x1) / aspect); 559 | yy = rh < 0 ? y1 - h : h + y1; 560 | } else if (xx > boundx) { 561 | xx = boundx; 562 | h = Math.abs((xx - x1) / aspect); 563 | yy = rh < 0 ? y1 - h : h + y1; 564 | } 565 | } else { 566 | xx = x2; 567 | h = rwa / aspect; 568 | yy = rh < 0 ? y1 - h : y1 + h; 569 | if (yy < 0) { 570 | yy = 0; 571 | w = Math.abs((yy - y1) * aspect); 572 | xx = rw < 0 ? x1 - w : w + x1; 573 | } else if (yy > boundy) { 574 | yy = boundy; 575 | w = Math.abs(yy - y1) * aspect; 576 | xx = rw < 0 ? x1 - w : w + x1; 577 | } 578 | } 579 | 580 | // Magic %-) 581 | if (xx > x1) { // right side 582 | if (xx - x1 < min_x) { 583 | xx = x1 + min_x; 584 | } else if (xx - x1 > max_x) { 585 | xx = x1 + max_x; 586 | } 587 | if (yy > y1) { 588 | yy = y1 + (xx - x1) / aspect; 589 | } else { 590 | yy = y1 - (xx - x1) / aspect; 591 | } 592 | } else if (xx < x1) { // left side 593 | if (x1 - xx < min_x) { 594 | xx = x1 - min_x; 595 | } else if (x1 - xx > max_x) { 596 | xx = x1 - max_x; 597 | } 598 | if (yy > y1) { 599 | yy = y1 + (x1 - xx) / aspect; 600 | } else { 601 | yy = y1 - (x1 - xx) / aspect; 602 | } 603 | } 604 | 605 | if (xx < 0) { 606 | x1 -= xx; 607 | xx = 0; 608 | } else if (xx > boundx) { 609 | x1 -= xx - boundx; 610 | xx = boundx; 611 | } 612 | 613 | if (yy < 0) { 614 | y1 -= yy; 615 | yy = 0; 616 | } else if (yy > boundy) { 617 | y1 -= yy - boundy; 618 | yy = boundy; 619 | } 620 | 621 | return makeObj(flipCoords(x1, y1, xx, yy)); 622 | } 623 | //}}} 624 | function rebound(p) //{{{ 625 | { 626 | if (p[0] < 0) p[0] = 0; 627 | if (p[1] < 0) p[1] = 0; 628 | 629 | if (p[0] > boundx) p[0] = boundx; 630 | if (p[1] > boundy) p[1] = boundy; 631 | 632 | return [Math.round(p[0]), Math.round(p[1])]; 633 | } 634 | //}}} 635 | function flipCoords(x1, y1, x2, y2) //{{{ 636 | { 637 | var xa = x1, 638 | xb = x2, 639 | ya = y1, 640 | yb = y2; 641 | if (x2 < x1) { 642 | xa = x2; 643 | xb = x1; 644 | } 645 | if (y2 < y1) { 646 | ya = y2; 647 | yb = y1; 648 | } 649 | return [xa, ya, xb, yb]; 650 | } 651 | //}}} 652 | function getRect() //{{{ 653 | { 654 | var xsize = x2 - x1, 655 | ysize = y2 - y1, 656 | delta; 657 | 658 | if (xlimit && (Math.abs(xsize) > xlimit)) { 659 | x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit); 660 | } 661 | if (ylimit && (Math.abs(ysize) > ylimit)) { 662 | y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit); 663 | } 664 | 665 | if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) { 666 | y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale); 667 | } 668 | if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) { 669 | x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale); 670 | } 671 | 672 | if (x1 < 0) { 673 | x2 -= x1; 674 | x1 -= x1; 675 | } 676 | if (y1 < 0) { 677 | y2 -= y1; 678 | y1 -= y1; 679 | } 680 | if (x2 < 0) { 681 | x1 -= x2; 682 | x2 -= x2; 683 | } 684 | if (y2 < 0) { 685 | y1 -= y2; 686 | y2 -= y2; 687 | } 688 | if (x2 > boundx) { 689 | delta = x2 - boundx; 690 | x1 -= delta; 691 | x2 -= delta; 692 | } 693 | if (y2 > boundy) { 694 | delta = y2 - boundy; 695 | y1 -= delta; 696 | y2 -= delta; 697 | } 698 | if (x1 > boundx) { 699 | delta = x1 - boundy; 700 | y2 -= delta; 701 | y1 -= delta; 702 | } 703 | if (y1 > boundy) { 704 | delta = y1 - boundy; 705 | y2 -= delta; 706 | y1 -= delta; 707 | } 708 | 709 | return makeObj(flipCoords(x1, y1, x2, y2)); 710 | } 711 | //}}} 712 | function makeObj(a) //{{{ 713 | { 714 | return { 715 | x: a[0], 716 | y: a[1], 717 | x2: a[2], 718 | y2: a[3], 719 | w: a[2] - a[0], 720 | h: a[3] - a[1] 721 | }; 722 | } 723 | //}}} 724 | 725 | return { 726 | flipCoords: flipCoords, 727 | setPressed: setPressed, 728 | setCurrent: setCurrent, 729 | getOffset: getOffset, 730 | moveOffset: moveOffset, 731 | getCorner: getCorner, 732 | getFixed: getFixed 733 | }; 734 | }()); 735 | 736 | //}}} 737 | // Shade Module {{{ 738 | var Shade = (function() { 739 | var enabled = false, 740 | holder = $('
').css({ 741 | position: 'absolute', 742 | zIndex: 240, 743 | opacity: 0 744 | }), 745 | shades = { 746 | top: createShade(), 747 | left: createShade().height(boundy), 748 | right: createShade().height(boundy), 749 | bottom: createShade() 750 | }; 751 | 752 | function resizeShades(w,h) { 753 | shades.left.css({ height: px(h) }); 754 | shades.right.css({ height: px(h) }); 755 | } 756 | function updateAuto() 757 | { 758 | return updateShade(Coords.getFixed()); 759 | } 760 | function updateShade(c) 761 | { 762 | shades.top.css({ 763 | left: px(c.x), 764 | width: px(c.w), 765 | height: px(c.y) 766 | }); 767 | shades.bottom.css({ 768 | top: px(c.y2), 769 | left: px(c.x), 770 | width: px(c.w), 771 | height: px(boundy-c.y2) 772 | }); 773 | shades.right.css({ 774 | left: px(c.x2), 775 | width: px(boundx-c.x2) 776 | }); 777 | shades.left.css({ 778 | width: px(c.x) 779 | }); 780 | } 781 | function createShade() { 782 | return $('
').css({ 783 | position: 'absolute', 784 | backgroundColor: options.shadeColor||options.bgColor 785 | }).appendTo(holder); 786 | } 787 | function enableShade() { 788 | if (!enabled) { 789 | enabled = true; 790 | holder.insertBefore($img); 791 | updateAuto(); 792 | Selection.setBgOpacity(1,0,1); 793 | $img2.hide(); 794 | 795 | setBgColor(options.shadeColor||options.bgColor,1); 796 | if (Selection.isAwake()) 797 | { 798 | setOpacity(options.bgOpacity,1); 799 | } 800 | else setOpacity(1,1); 801 | } 802 | } 803 | function setBgColor(color,now) { 804 | colorChangeMacro(getShades(),color,now); 805 | } 806 | function disableShade() { 807 | if (enabled) { 808 | holder.remove(); 809 | $img2.show(); 810 | enabled = false; 811 | if (Selection.isAwake()) { 812 | Selection.setBgOpacity(options.bgOpacity,1,1); 813 | } else { 814 | Selection.setBgOpacity(1,1,1); 815 | Selection.disableHandles(); 816 | } 817 | colorChangeMacro($div,0,1); 818 | } 819 | } 820 | function setOpacity(opacity,now) { 821 | if (enabled) { 822 | if (options.bgFade && !now) { 823 | holder.animate({ 824 | opacity: 1-opacity 825 | },{ 826 | queue: false, 827 | duration: options.fadeTime 828 | }); 829 | } 830 | else holder.css({opacity:1-opacity}); 831 | } 832 | } 833 | function refreshAll() { 834 | options.shade ? enableShade() : disableShade(); 835 | if (Selection.isAwake()) setOpacity(options.bgOpacity); 836 | } 837 | function getShades() { 838 | return holder.children(); 839 | } 840 | 841 | return { 842 | update: updateAuto, 843 | updateRaw: updateShade, 844 | getShades: getShades, 845 | setBgColor: setBgColor, 846 | enable: enableShade, 847 | disable: disableShade, 848 | resize: resizeShades, 849 | refresh: refreshAll, 850 | opacity: setOpacity 851 | }; 852 | }()); 853 | // }}} 854 | // Selection Module {{{ 855 | var Selection = (function () { 856 | var awake, 857 | hdep = 370, 858 | borders = {}, 859 | handle = {}, 860 | dragbar = {}, 861 | seehandles = false; 862 | 863 | // Private Methods 864 | function insertBorder(type) //{{{ 865 | { 866 | var jq = $('
').css({ 867 | position: 'absolute', 868 | opacity: options.borderOpacity 869 | }).addClass(cssClass(type)); 870 | $img_holder.append(jq); 871 | return jq; 872 | } 873 | //}}} 874 | function dragDiv(ord, zi) //{{{ 875 | { 876 | var jq = $('
').mousedown(createDragger(ord)).css({ 877 | cursor: ord + '-resize', 878 | position: 'absolute', 879 | zIndex: zi 880 | }).addClass('ord-'+ord); 881 | 882 | if (Touch.support) { 883 | jq.bind('touchstart.jcrop', Touch.createDragger(ord)); 884 | } 885 | 886 | $hdl_holder.append(jq); 887 | return jq; 888 | } 889 | //}}} 890 | function insertHandle(ord) //{{{ 891 | { 892 | var hs = options.handleSize, 893 | 894 | div = dragDiv(ord, hdep++).css({ 895 | opacity: options.handleOpacity 896 | }).addClass(cssClass('handle')); 897 | 898 | if (hs) { div.width(hs).height(hs); } 899 | 900 | return div; 901 | } 902 | //}}} 903 | function insertDragbar(ord) //{{{ 904 | { 905 | return dragDiv(ord, hdep++).addClass('jcrop-dragbar'); 906 | } 907 | //}}} 908 | function createDragbars(li) //{{{ 909 | { 910 | var i; 911 | for (i = 0; i < li.length; i++) { 912 | dragbar[li[i]] = insertDragbar(li[i]); 913 | } 914 | } 915 | //}}} 916 | function createBorders(li) //{{{ 917 | { 918 | var cl,i; 919 | for (i = 0; i < li.length; i++) { 920 | switch(li[i]){ 921 | case'n': cl='hline'; break; 922 | case's': cl='hline bottom'; break; 923 | case'e': cl='vline right'; break; 924 | case'w': cl='vline'; break; 925 | } 926 | borders[li[i]] = insertBorder(cl); 927 | } 928 | } 929 | //}}} 930 | function createHandles(li) //{{{ 931 | { 932 | var i; 933 | for (i = 0; i < li.length; i++) { 934 | handle[li[i]] = insertHandle(li[i]); 935 | } 936 | } 937 | //}}} 938 | function moveto(x, y) //{{{ 939 | { 940 | if (!options.shade) { 941 | $img2.css({ 942 | top: px(-y), 943 | left: px(-x) 944 | }); 945 | } 946 | $sel.css({ 947 | top: px(y), 948 | left: px(x) 949 | }); 950 | } 951 | //}}} 952 | function resize(w, h) //{{{ 953 | { 954 | $sel.width(Math.round(w)).height(Math.round(h)); 955 | } 956 | //}}} 957 | function refresh() //{{{ 958 | { 959 | var c = Coords.getFixed(); 960 | 961 | Coords.setPressed([c.x, c.y]); 962 | Coords.setCurrent([c.x2, c.y2]); 963 | 964 | updateVisible(); 965 | } 966 | //}}} 967 | 968 | // Internal Methods 969 | function updateVisible(select) //{{{ 970 | { 971 | if (awake) { 972 | return update(select); 973 | } 974 | } 975 | //}}} 976 | function update(select) //{{{ 977 | { 978 | var c = Coords.getFixed(); 979 | 980 | resize(c.w, c.h); 981 | moveto(c.x, c.y); 982 | if (options.shade) Shade.updateRaw(c); 983 | 984 | awake || show(); 985 | 986 | if (select) { 987 | options.onSelect.call(api, unscale(c)); 988 | } else { 989 | options.onChange.call(api, unscale(c)); 990 | } 991 | } 992 | //}}} 993 | function setBgOpacity(opacity,force,now) //{{{ 994 | { 995 | if (!awake && !force) return; 996 | if (options.bgFade && !now) { 997 | $img.animate({ 998 | opacity: opacity 999 | },{ 1000 | queue: false, 1001 | duration: options.fadeTime 1002 | }); 1003 | } else { 1004 | $img.css('opacity', opacity); 1005 | } 1006 | } 1007 | //}}} 1008 | function show() //{{{ 1009 | { 1010 | $sel.show(); 1011 | 1012 | if (options.shade) Shade.opacity(bgopacity); 1013 | else setBgOpacity(bgopacity,true); 1014 | 1015 | awake = true; 1016 | } 1017 | //}}} 1018 | function release() //{{{ 1019 | { 1020 | disableHandles(); 1021 | $sel.hide(); 1022 | 1023 | if (options.shade) Shade.opacity(1); 1024 | else setBgOpacity(1); 1025 | 1026 | awake = false; 1027 | options.onRelease.call(api); 1028 | } 1029 | //}}} 1030 | function showHandles() //{{{ 1031 | { 1032 | if (seehandles) { 1033 | $hdl_holder.show(); 1034 | } 1035 | } 1036 | //}}} 1037 | function enableHandles() //{{{ 1038 | { 1039 | seehandles = true; 1040 | if (options.allowResize) { 1041 | $hdl_holder.show(); 1042 | return true; 1043 | } 1044 | } 1045 | //}}} 1046 | function disableHandles() //{{{ 1047 | { 1048 | seehandles = false; 1049 | $hdl_holder.hide(); 1050 | } 1051 | //}}} 1052 | function animMode(v) //{{{ 1053 | { 1054 | if (v) { 1055 | animating = true; 1056 | disableHandles(); 1057 | } else { 1058 | animating = false; 1059 | enableHandles(); 1060 | } 1061 | } 1062 | //}}} 1063 | function done() //{{{ 1064 | { 1065 | animMode(false); 1066 | refresh(); 1067 | } 1068 | //}}} 1069 | // Insert draggable elements {{{ 1070 | // Insert border divs for outline 1071 | 1072 | if (options.dragEdges && $.isArray(options.createDragbars)) 1073 | createDragbars(options.createDragbars); 1074 | 1075 | if ($.isArray(options.createHandles)) 1076 | createHandles(options.createHandles); 1077 | 1078 | if (options.drawBorders && $.isArray(options.createBorders)) 1079 | createBorders(options.createBorders); 1080 | 1081 | //}}} 1082 | 1083 | // This is a hack for iOS5 to support drag/move touch functionality 1084 | $(document).bind('touchstart.jcrop-ios',function(e) { 1085 | if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation(); 1086 | }); 1087 | 1088 | var $track = newTracker().mousedown(createDragger('move')).css({ 1089 | cursor: 'move', 1090 | position: 'absolute', 1091 | zIndex: 360 1092 | }); 1093 | 1094 | if (Touch.support) { 1095 | $track.bind('touchstart.jcrop', Touch.createDragger('move')); 1096 | } 1097 | 1098 | $img_holder.append($track); 1099 | disableHandles(); 1100 | 1101 | return { 1102 | updateVisible: updateVisible, 1103 | update: update, 1104 | release: release, 1105 | refresh: refresh, 1106 | isAwake: function () { 1107 | return awake; 1108 | }, 1109 | setCursor: function (cursor) { 1110 | $track.css('cursor', cursor); 1111 | }, 1112 | enableHandles: enableHandles, 1113 | enableOnly: function () { 1114 | seehandles = true; 1115 | }, 1116 | showHandles: showHandles, 1117 | disableHandles: disableHandles, 1118 | animMode: animMode, 1119 | setBgOpacity: setBgOpacity, 1120 | done: done 1121 | }; 1122 | }()); 1123 | 1124 | //}}} 1125 | // Tracker Module {{{ 1126 | var Tracker = (function () { 1127 | var onMove = function () {}, 1128 | onDone = function () {}, 1129 | trackDoc = options.trackDocument; 1130 | 1131 | function toFront(touch) //{{{ 1132 | { 1133 | $trk.css({ 1134 | zIndex: 450 1135 | }); 1136 | 1137 | if (touch) 1138 | $(document) 1139 | .bind('touchmove.jcrop', trackTouchMove) 1140 | .bind('touchend.jcrop', trackTouchEnd); 1141 | 1142 | else if (trackDoc) 1143 | $(document) 1144 | .bind('mousemove.jcrop',trackMove) 1145 | .bind('mouseup.jcrop',trackUp); 1146 | } 1147 | //}}} 1148 | function toBack() //{{{ 1149 | { 1150 | $trk.css({ 1151 | zIndex: 290 1152 | }); 1153 | // Monkey patch, see https://github.com/tapmodo/Jcrop/issues/79 1154 | //$(document).unbind('.jcrop'); 1155 | $(document).unbind('touchmove.jcrop'); 1156 | $(document).unbind('touchend.jcrop'); 1157 | $(document).unbind('mousemove.jcrop'); 1158 | $(document).unbind('mouseup.jcrop'); 1159 | } 1160 | //}}} 1161 | function trackMove(e) //{{{ 1162 | { 1163 | onMove(mouseAbs(e)); 1164 | return false; 1165 | } 1166 | //}}} 1167 | function trackUp(e) //{{{ 1168 | { 1169 | e.preventDefault(); 1170 | e.stopPropagation(); 1171 | 1172 | if (btndown) { 1173 | btndown = false; 1174 | 1175 | onDone(mouseAbs(e)); 1176 | 1177 | if (Selection.isAwake()) { 1178 | options.onSelect.call(api, unscale(Coords.getFixed())); 1179 | } 1180 | 1181 | toBack(); 1182 | onMove = function () {}; 1183 | onDone = function () {}; 1184 | } 1185 | 1186 | return false; 1187 | } 1188 | //}}} 1189 | function activateHandlers(move, done, touch) //{{{ 1190 | { 1191 | btndown = true; 1192 | onMove = move; 1193 | onDone = done; 1194 | toFront(touch); 1195 | return false; 1196 | } 1197 | //}}} 1198 | function trackTouchMove(e) //{{{ 1199 | { 1200 | onMove(mouseAbs(Touch.cfilter(e))); 1201 | return false; 1202 | } 1203 | //}}} 1204 | function trackTouchEnd(e) //{{{ 1205 | { 1206 | return trackUp(Touch.cfilter(e)); 1207 | } 1208 | //}}} 1209 | function setCursor(t) //{{{ 1210 | { 1211 | $trk.css('cursor', t); 1212 | } 1213 | //}}} 1214 | 1215 | if (!trackDoc) { 1216 | $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp); 1217 | } 1218 | 1219 | $img.before($trk); 1220 | return { 1221 | activateHandlers: activateHandlers, 1222 | setCursor: setCursor 1223 | }; 1224 | }()); 1225 | //}}} 1226 | // KeyManager Module {{{ 1227 | var KeyManager = (function () { 1228 | var $keymgr = $('').css({ 1229 | position: 'fixed', 1230 | left: '-120px', 1231 | width: '12px' 1232 | }).addClass('jcrop-keymgr'), 1233 | 1234 | $keywrap = $('
').css({ 1235 | position: 'absolute', 1236 | overflow: 'hidden' 1237 | }).append($keymgr); 1238 | 1239 | function watchKeys() //{{{ 1240 | { 1241 | if (options.keySupport) { 1242 | $keymgr.show(); 1243 | $keymgr.focus(); 1244 | } 1245 | } 1246 | //}}} 1247 | function onBlur(e) //{{{ 1248 | { 1249 | $keymgr.hide(); 1250 | } 1251 | //}}} 1252 | function doNudge(e, x, y) //{{{ 1253 | { 1254 | if (options.allowMove) { 1255 | Coords.moveOffset([x, y]); 1256 | Selection.updateVisible(true); 1257 | } 1258 | e.preventDefault(); 1259 | e.stopPropagation(); 1260 | } 1261 | //}}} 1262 | function parseKey(e) //{{{ 1263 | { 1264 | if (e.ctrlKey || e.metaKey) { 1265 | return true; 1266 | } 1267 | shift_down = e.shiftKey ? true : false; 1268 | var nudge = shift_down ? 10 : 1; 1269 | 1270 | switch (e.keyCode) { 1271 | case 37: 1272 | doNudge(e, -nudge, 0); 1273 | break; 1274 | case 39: 1275 | doNudge(e, nudge, 0); 1276 | break; 1277 | case 38: 1278 | doNudge(e, 0, -nudge); 1279 | break; 1280 | case 40: 1281 | doNudge(e, 0, nudge); 1282 | break; 1283 | case 27: 1284 | if (options.allowSelect) Selection.release(); 1285 | break; 1286 | case 9: 1287 | return true; 1288 | } 1289 | 1290 | return false; 1291 | } 1292 | //}}} 1293 | 1294 | if (options.keySupport) { 1295 | $keymgr.keydown(parseKey).blur(onBlur); 1296 | if (ie6mode || !options.fixedSupport) { 1297 | $keymgr.css({ 1298 | position: 'absolute', 1299 | left: '-20px' 1300 | }); 1301 | $keywrap.append($keymgr).insertBefore($img); 1302 | } else { 1303 | $keymgr.insertBefore($img); 1304 | } 1305 | } 1306 | 1307 | 1308 | return { 1309 | watchKeys: watchKeys 1310 | }; 1311 | }()); 1312 | //}}} 1313 | // }}} 1314 | // API methods {{{ 1315 | function setClass(cname) //{{{ 1316 | { 1317 | $div.removeClass().addClass(cssClass('holder')).addClass(cname); 1318 | } 1319 | //}}} 1320 | function animateTo(a, callback) //{{{ 1321 | { 1322 | var x1 = a[0] / xscale, 1323 | y1 = a[1] / yscale, 1324 | x2 = a[2] / xscale, 1325 | y2 = a[3] / yscale; 1326 | 1327 | if (animating) { 1328 | return; 1329 | } 1330 | 1331 | var animto = Coords.flipCoords(x1, y1, x2, y2), 1332 | c = Coords.getFixed(), 1333 | initcr = [c.x, c.y, c.x2, c.y2], 1334 | animat = initcr, 1335 | interv = options.animationDelay, 1336 | ix1 = animto[0] - initcr[0], 1337 | iy1 = animto[1] - initcr[1], 1338 | ix2 = animto[2] - initcr[2], 1339 | iy2 = animto[3] - initcr[3], 1340 | pcent = 0, 1341 | velocity = options.swingSpeed; 1342 | 1343 | x1 = animat[0]; 1344 | y1 = animat[1]; 1345 | x2 = animat[2]; 1346 | y2 = animat[3]; 1347 | 1348 | Selection.animMode(true); 1349 | var anim_timer; 1350 | 1351 | function queueAnimator() { 1352 | window.setTimeout(animator, interv); 1353 | } 1354 | var animator = (function () { 1355 | return function () { 1356 | pcent += (100 - pcent) / velocity; 1357 | 1358 | animat[0] = Math.round(x1 + ((pcent / 100) * ix1)); 1359 | animat[1] = Math.round(y1 + ((pcent / 100) * iy1)); 1360 | animat[2] = Math.round(x2 + ((pcent / 100) * ix2)); 1361 | animat[3] = Math.round(y2 + ((pcent / 100) * iy2)); 1362 | 1363 | if (pcent >= 99.8) { 1364 | pcent = 100; 1365 | } 1366 | if (pcent < 100) { 1367 | setSelectRaw(animat); 1368 | queueAnimator(); 1369 | } else { 1370 | Selection.done(); 1371 | Selection.animMode(false); 1372 | if (typeof(callback) === 'function') { 1373 | callback.call(api); 1374 | } 1375 | } 1376 | }; 1377 | }()); 1378 | queueAnimator(); 1379 | } 1380 | //}}} 1381 | function setSelect(rect) //{{{ 1382 | { 1383 | setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]); 1384 | options.onSelect.call(api, unscale(Coords.getFixed())); 1385 | Selection.enableHandles(); 1386 | } 1387 | //}}} 1388 | function setSelectRaw(l) //{{{ 1389 | { 1390 | Coords.setPressed([l[0], l[1]]); 1391 | Coords.setCurrent([l[2], l[3]]); 1392 | Selection.update(); 1393 | } 1394 | //}}} 1395 | function tellSelect() //{{{ 1396 | { 1397 | return unscale(Coords.getFixed()); 1398 | } 1399 | //}}} 1400 | function tellScaled() //{{{ 1401 | { 1402 | return Coords.getFixed(); 1403 | } 1404 | //}}} 1405 | function setOptionsNew(opt) //{{{ 1406 | { 1407 | setOptions(opt); 1408 | interfaceUpdate(); 1409 | } 1410 | //}}} 1411 | function disableCrop() //{{{ 1412 | { 1413 | options.disabled = true; 1414 | Selection.disableHandles(); 1415 | Selection.setCursor('default'); 1416 | Tracker.setCursor('default'); 1417 | } 1418 | //}}} 1419 | function enableCrop() //{{{ 1420 | { 1421 | options.disabled = false; 1422 | interfaceUpdate(); 1423 | } 1424 | //}}} 1425 | function cancelCrop() //{{{ 1426 | { 1427 | Selection.done(); 1428 | Tracker.activateHandlers(null, null); 1429 | } 1430 | //}}} 1431 | function destroy() //{{{ 1432 | { 1433 | $div.remove(); 1434 | $origimg.show(); 1435 | $origimg.css('visibility','visible'); 1436 | $(obj).removeData('Jcrop'); 1437 | } 1438 | //}}} 1439 | function setImage(src, callback) //{{{ 1440 | { 1441 | Selection.release(); 1442 | disableCrop(); 1443 | var img = new Image(); 1444 | img.onload = function () { 1445 | var iw = img.width; 1446 | var ih = img.height; 1447 | var bw = options.boxWidth; 1448 | var bh = options.boxHeight; 1449 | $img.width(iw).height(ih); 1450 | $img.attr('src', src); 1451 | $img2.attr('src', src); 1452 | presize($img, bw, bh); 1453 | boundx = $img.width(); 1454 | boundy = $img.height(); 1455 | $img2.width(boundx).height(boundy); 1456 | $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2)); 1457 | $div.width(boundx).height(boundy); 1458 | Shade.resize(boundx,boundy); 1459 | enableCrop(); 1460 | 1461 | if (typeof(callback) === 'function') { 1462 | callback.call(api); 1463 | } 1464 | }; 1465 | img.src = src; 1466 | } 1467 | //}}} 1468 | function colorChangeMacro($obj,color,now) { 1469 | var mycolor = color || options.bgColor; 1470 | if (options.bgFade && supportsColorFade() && options.fadeTime && !now) { 1471 | $obj.animate({ 1472 | backgroundColor: mycolor 1473 | }, { 1474 | queue: false, 1475 | duration: options.fadeTime 1476 | }); 1477 | } else { 1478 | $obj.css('backgroundColor', mycolor); 1479 | } 1480 | } 1481 | function interfaceUpdate(alt) //{{{ 1482 | // This method tweaks the interface based on options object. 1483 | // Called when options are changed and at end of initialization. 1484 | { 1485 | if (options.allowResize) { 1486 | if (alt) { 1487 | Selection.enableOnly(); 1488 | } else { 1489 | Selection.enableHandles(); 1490 | } 1491 | } else { 1492 | Selection.disableHandles(); 1493 | } 1494 | 1495 | Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); 1496 | Selection.setCursor(options.allowMove ? 'move' : 'default'); 1497 | 1498 | if (options.hasOwnProperty('trueSize')) { 1499 | xscale = options.trueSize[0] / boundx; 1500 | yscale = options.trueSize[1] / boundy; 1501 | } 1502 | 1503 | if (options.hasOwnProperty('setSelect')) { 1504 | setSelect(options.setSelect); 1505 | Selection.done(); 1506 | delete(options.setSelect); 1507 | } 1508 | 1509 | Shade.refresh(); 1510 | 1511 | if (options.bgColor != bgcolor) { 1512 | colorChangeMacro( 1513 | options.shade? Shade.getShades(): $div, 1514 | options.shade? 1515 | (options.shadeColor || options.bgColor): 1516 | options.bgColor 1517 | ); 1518 | bgcolor = options.bgColor; 1519 | } 1520 | 1521 | if (bgopacity != options.bgOpacity) { 1522 | bgopacity = options.bgOpacity; 1523 | if (options.shade) Shade.refresh(); 1524 | else Selection.setBgOpacity(bgopacity); 1525 | } 1526 | 1527 | xlimit = options.maxSize[0] || 0; 1528 | ylimit = options.maxSize[1] || 0; 1529 | xmin = options.minSize[0] || 0; 1530 | ymin = options.minSize[1] || 0; 1531 | 1532 | if (options.hasOwnProperty('outerImage')) { 1533 | $img.attr('src', options.outerImage); 1534 | delete(options.outerImage); 1535 | } 1536 | 1537 | Selection.refresh(); 1538 | } 1539 | //}}} 1540 | //}}} 1541 | 1542 | if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection); 1543 | 1544 | $hdl_holder.hide(); 1545 | interfaceUpdate(true); 1546 | 1547 | var api = { 1548 | setImage: setImage, 1549 | animateTo: animateTo, 1550 | setSelect: setSelect, 1551 | setOptions: setOptionsNew, 1552 | tellSelect: tellSelect, 1553 | tellScaled: tellScaled, 1554 | setClass: setClass, 1555 | 1556 | disable: disableCrop, 1557 | enable: enableCrop, 1558 | cancel: cancelCrop, 1559 | release: Selection.release, 1560 | destroy: destroy, 1561 | 1562 | focus: KeyManager.watchKeys, 1563 | 1564 | getBounds: function () { 1565 | return [boundx * xscale, boundy * yscale]; 1566 | }, 1567 | getWidgetSize: function () { 1568 | return [boundx, boundy]; 1569 | }, 1570 | getScaleFactor: function () { 1571 | return [xscale, yscale]; 1572 | }, 1573 | getOptions: function() { 1574 | // careful: internal values are returned 1575 | return options; 1576 | }, 1577 | 1578 | ui: { 1579 | holder: $div, 1580 | selection: $sel 1581 | } 1582 | }; 1583 | 1584 | if (is_msie) $div.bind('selectstart', function () { return false; }); 1585 | 1586 | $origimg.data('Jcrop', api); 1587 | return api; 1588 | }; 1589 | $.fn.Jcrop = function (options, callback) //{{{ 1590 | { 1591 | var api; 1592 | // Iterate over each object, attach Jcrop 1593 | this.each(function () { 1594 | // If we've already attached to this object 1595 | if ($(this).data('Jcrop')) { 1596 | // The API can be requested this way (undocumented) 1597 | if (options === 'api') return $(this).data('Jcrop'); 1598 | // Otherwise, we just reset the options... 1599 | else $(this).data('Jcrop').setOptions(options); 1600 | } 1601 | // If we haven't been attached, preload and attach 1602 | else { 1603 | if (this.tagName == 'IMG') 1604 | $.Jcrop.Loader(this,function(){ 1605 | $(this).css({display:'block',visibility:'hidden'}); 1606 | api = $.Jcrop(this, options); 1607 | if ($.isFunction(callback)) callback.call(api); 1608 | }); 1609 | else { 1610 | $(this).css({display:'block',visibility:'hidden'}); 1611 | api = $.Jcrop(this, options); 1612 | if ($.isFunction(callback)) callback.call(api); 1613 | } 1614 | } 1615 | }); 1616 | 1617 | // Return "this" so the object is chainable (jQuery-style) 1618 | return this; 1619 | }; 1620 | //}}} 1621 | // $.Jcrop.Loader - basic image loader {{{ 1622 | 1623 | $.Jcrop.Loader = function(imgobj,success,error){ 1624 | var $img = $(imgobj), img = $img[0]; 1625 | 1626 | function completeCheck(){ 1627 | if (img.complete) { 1628 | $img.unbind('.jcloader'); 1629 | if ($.isFunction(success)) success.call(img); 1630 | } 1631 | else window.setTimeout(completeCheck,50); 1632 | } 1633 | 1634 | $img 1635 | .bind('load.jcloader',completeCheck) 1636 | .bind('error.jcloader',function(e){ 1637 | $img.unbind('.jcloader'); 1638 | if ($.isFunction(error)) error.call(img); 1639 | }); 1640 | 1641 | if (img.complete && $.isFunction(success)){ 1642 | $img.unbind('.jcloader'); 1643 | success.call(img); 1644 | } 1645 | }; 1646 | 1647 | //}}} 1648 | // Global Defaults {{{ 1649 | $.Jcrop.defaults = { 1650 | 1651 | // Basic Settings 1652 | allowSelect: true, 1653 | allowMove: true, 1654 | allowResize: true, 1655 | 1656 | trackDocument: true, 1657 | 1658 | // Styling Options 1659 | baseClass: 'jcrop', 1660 | addClass: null, 1661 | bgColor: 'black', 1662 | bgOpacity: 0.6, 1663 | bgFade: false, 1664 | borderOpacity: 0.4, 1665 | handleOpacity: 0.5, 1666 | handleSize: null, 1667 | 1668 | aspectRatio: 0, 1669 | keySupport: true, 1670 | createHandles: ['n','s','e','w','nw','ne','se','sw'], 1671 | createDragbars: ['n','s','e','w'], 1672 | createBorders: ['n','s','e','w'], 1673 | drawBorders: true, 1674 | dragEdges: true, 1675 | fixedSupport: true, 1676 | touchSupport: null, 1677 | 1678 | shade: null, 1679 | 1680 | boxWidth: 0, 1681 | boxHeight: 0, 1682 | boundary: 2, 1683 | fadeTime: 400, 1684 | animationDelay: 20, 1685 | swingSpeed: 3, 1686 | 1687 | minSelect: [0, 0], 1688 | maxSize: [0, 0], 1689 | minSize: [0, 0], 1690 | 1691 | // Callbacks / Event Handlers 1692 | onChange: function () {}, 1693 | onSelect: function () {}, 1694 | onDblClick: function () {}, 1695 | onRelease: function () {} 1696 | }; 1697 | 1698 | // }}} 1699 | }(jQuery)); 1700 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/active_admin_jcrop/jquery.Jcrop.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jquery.Jcrop.min.js v0.9.12 (build:20130202) 3 | * jQuery Image Cropping Plugin - released under MIT License 4 | * Copyright (c) 2008-2013 Tapmodo Interactive LLC 5 | * https://github.com/tapmodo/Jcrop 6 | */ 7 | (function(a){a.Jcrop=function(b,c){function i(a){return Math.round(a)+"px"}function j(a){return d.baseClass+"-"+a}function k(){return a.fx.step.hasOwnProperty("backgroundColor")}function l(b){var c=a(b).offset();return[c.left,c.top]}function m(a){return[a.pageX-e[0],a.pageY-e[1]]}function n(b){typeof b!="object"&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){typeof d[b]!="function"&&(d[b]=function(){})})}function o(a,b,c){e=l(D),bc.setCursor(a==="move"?a:a+"-resize");if(a==="move")return bc.activateHandlers(q(b),v,c);var d=_.getFixed(),f=r(a),g=_.getCorner(r(f));_.setPressed(_.getCorner(f)),_.setCurrent(g),bc.activateHandlers(p(a,d),v,c)}function p(a,b){return function(c){if(!d.aspectRatio)switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}else switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}_.setCurrent(c),bb.update()}}function q(a){var b=a;return bd.watchKeys 8 | (),function(a){_.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bb.update()}}function r(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function s(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(b)),b.stopPropagation(),b.preventDefault(),!1)}}function t(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),T=a.width()/d,U=a.height()/e,a.width(d).height(e)}function u(a){return{x:a.x*T,y:a.y*U,x2:a.x2*T,y2:a.y2*U,w:a.w*T,h:a.h*U}}function v(a){var b=_.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bb.enableHandles(),bb.done()):bb.release(),bc.setCursor(d.allowSelect?"crosshair":"default")}function w(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;W=!0,e=l(D),bb.disableHandles(),bc.setCursor("crosshair");var b=m(a);return _.setPressed(b),bb.update(),bc.activateHandlers(x,v,a.type.substring 9 | (0,5)==="touch"),bd.watchKeys(),a.stopPropagation(),a.preventDefault(),!1}function x(a){_.setCurrent(a),bb.update()}function y(){var b=a("
").addClass(j("tracker"));return g&&b.css({opacity:0,backgroundColor:"white"}),b}function be(a){G.removeClass().addClass(j("holder")).addClass(a)}function bf(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/T,e=a[1]/U,f=a[2]/T,g=a[3]/U;if(X)return;var h=_.flipCoords(c,e,f,g),i=_.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;c=k[0],e=k[1],f=k[2],g=k[3],bb.animMode(!0);var s,u=function(){return function(){q+=(100-q)/r,k[0]=Math.round(c+q/100*m),k[1]=Math.round(e+q/100*n),k[2]=Math.round(f+q/100*o),k[3]=Math.round(g+q/100*p),q>=99.8&&(q=100),q<100?(bh(k),t()):(bb.done(),bb.animMode(!1),typeof b=="function"&&b.call(bs))}}();t()}function bg(a){bh([a[0]/T,a[1]/U,a[2]/T,a[3]/U]),d.onSelect.call(bs,u(_.getFixed())),bb.enableHandles()}function bh(a){_.setPressed([a[0],a[1]]),_.setCurrent([a[2], 10 | a[3]]),bb.update()}function bi(){return u(_.getFixed())}function bj(){return _.getFixed()}function bk(a){n(a),br()}function bl(){d.disabled=!0,bb.disableHandles(),bb.setCursor("default"),bc.setCursor("default")}function bm(){d.disabled=!1,br()}function bn(){bb.done(),bc.activateHandlers(null,null)}function bo(){G.remove(),A.show(),A.css("visibility","visible"),a(b).removeData("Jcrop")}function bp(a,b){bb.release(),bl();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;D.width(e).height(f),D.attr("src",a),H.attr("src",a),t(D,g,h),E=D.width(),F=D.height(),H.width(E).height(F),M.width(E+L*2).height(F+L*2),G.width(E).height(F),ba.resize(E,F),bm(),typeof b=="function"&&b.call(bs)},c.src=a}function bq(a,b,c){var e=b||d.bgColor;d.bgFade&&k()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function br(a){d.allowResize?a?bb.enableOnly():bb.enableHandles():bb.disableHandles(),bc.setCursor(d.allowSelect?"crosshair":"default"),bb 11 | .setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(T=d.trueSize[0]/E,U=d.trueSize[1]/F),d.hasOwnProperty("setSelect")&&(bg(d.setSelect),bb.done(),delete d.setSelect),ba.refresh(),d.bgColor!=N&&(bq(d.shade?ba.getShades():G,d.shade?d.shadeColor||d.bgColor:d.bgColor),N=d.bgColor),O!=d.bgOpacity&&(O=d.bgOpacity,d.shade?ba.refresh():bb.setBgOpacity(O)),P=d.maxSize[0]||0,Q=d.maxSize[1]||0,R=d.minSize[0]||0,S=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(D.attr("src",d.outerImage),delete d.outerImage),bb.refresh()}var d=a.extend({},a.Jcrop.defaults),e,f=navigator.userAgent.toLowerCase(),g=/msie/.test(f),h=/msie [1-6]\./.test(f);typeof b!="object"&&(b=a(b)[0]),typeof c!="object"&&(c={}),n(c);var z={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},A=a(b),B=!0;if(b.tagName=="IMG"){if(A[0].width!=0&&A[0].height!=0)A.width(A[0].width),A.height(A[0].height);else{var C=new Image;C.src=A[0].src,A.width(C.width),A.height(C.height)}var D=A.clone().removeAttr("id"). 12 | css(z).show();D.width(A.width()),D.height(A.height()),A.after(D).hide()}else D=A.css(z).show(),B=!1,d.shade===null&&(d.shade=!0);t(D,d.boxWidth,d.boxHeight);var E=D.width(),F=D.height(),G=a("
").width(E).height(F).addClass(j("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(A).append(D);d.addClass&&G.addClass(d.addClass);var H=a("
"),I=a("
").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),J=a("
").width("100%").height("100%").css("zIndex",320),K=a("
").css({position:"absolute",zIndex:600}).dblclick(function(){var a=_.getFixed();d.onDblClick.call(bs,a)}).insertBefore(D).append(I,J);B&&(H=a("").attr("src",D.attr("src")).css(z).width(E).height(F),I.append(H)),h&&K.css({overflowY:"hidden"});var L=d.boundary,M=y().width(E+L*2).height(F+L*2).css({position:"absolute",top:i(-L),left:i(-L),zIndex:290}).mousedown(w),N=d.bgColor,O=d.bgOpacity,P,Q,R,S,T,U,V=!0,W,X,Y;e=l(D);var Z=function(){function a(){var a={},b=["touchstart" 13 | ,"touchmove","touchend"],c=document.createElement("div"),d;try{for(d=0;da+f&&(f-=f+a),0>b+g&&(g-=g+b),FE&&(r=E,u=Math.abs((r-a)/f),s=k<0?b-u:u+b)):(r=c,u=l/f,s=k<0?b-u:b+u,s<0?(s=0,t=Math.abs((s-b)*f),r=j<0?a-t:t+a):s>F&&(s=F,t=Math.abs(s-b)*f,r=j<0?a-t:t+a)),r>a?(r-ah&&(r=a+h),s>b?s=b+(r-a)/f:s=b-(r-a)/f):rh&&(r=a-h),s>b?s=b+(a-r)/f:s=b-(a-r)/f),r<0?(a-=r,r=0):r>E&&(a-=r-E,r=E),s<0?(b-=s,s=0):s>F&&(b-=s-F,s=F),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>E&&(a[0]=E),a[1]>F&&(a[1]=F),[Math.round(a[0]),Math.round(a[1])]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return cP&&(c=d>0?a+P:a-P),Q&&Math.abs 15 | (f)>Q&&(e=f>0?b+Q:b-Q),S/U&&Math.abs(f)0?b+S/U:b-S/U),R/T&&Math.abs(d)0?a+R/T:a-R/T),a<0&&(c-=a,a-=a),b<0&&(e-=b,b-=b),c<0&&(a-=c,c-=c),e<0&&(b-=e,e-=e),c>E&&(g=c-E,a-=g,c-=g),e>F&&(g=e-F,b-=g,e-=g),a>E&&(g=a-F,e-=g,b-=g),b>F&&(g=b-F,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var a=0,b=0,c=0,e=0,f,g;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),ba=function(){function f(a,b){e.left.css({height:i(b)}),e.right.css({height:i(b)})}function g(){return h(_.getFixed())}function h(a){e.top.css({left:i(a.x),width:i(a.w),height:i(a.y)}),e.bottom.css({top:i(a.y2),left:i(a.x),width:i(a.w),height:i(F-a.y2)}),e.right.css({left:i(a.x2),width:i(E-a.x2)}),e.left.css({width:i(a.x)})}function j(){return a("
").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(D),g(),bb.setBgOpacity(1,0,1),H.hide(),l(d.shadeColor||d.bgColor,1),bb. 16 | isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){bq(p(),a,b)}function m(){b&&(c.remove(),H.show(),b=!1,bb.isAwake()?bb.setBgOpacity(d.bgOpacity,1,1):(bb.setBgOpacity(1,1,1),bb.disableHandles()),bq(G,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bb.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("
").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(F),right:j().height(F),bottom:j()};return{update:g,updateRaw:h,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bb=function(){function k(b){var c=a("
").css({position:"absolute",opacity:d.borderOpacity}).addClass(j(b));return I.append(c),c}function l(b,c){var d=a("
").mousedown(s(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return Z.support&&d.bind("touchstart.jcrop",Z.createDragger(b)),J.append(d),d}function m(a){var b=d.handleSize,e=l(a,c++ 17 | ).css({opacity:d.handleOpacity}).addClass(j("handle"));return b&&e.width(b).height(b),e}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o(a){var b;for(b=0;b').css({position:"fixed",left:"-120px",width:"12px"}).addClass("jcrop-keymgr"),c=a("
").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),h||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(D)):b.insertBefore(D)),{watchKeys:e}}();Z.support&&M.bind("touchstart.jcrop",Z.newSelection),J.hide(),br(!0);var bs={setImage:bp,animateTo:bf,setSelect:bg,setOptions:bk,tellSelect:bi,tellScaled:bj,setClass:be,disable:bl,enable:bm,cancel:bn,release:bb.release,destroy:bo,focus:bd.watchKeys,getBounds:function(){return[E*T,F*U]},getWidgetSize:function(){return[E,F]},getScaleFactor:function(){return[T,U]},getOptions:function(){return d},ui:{holder:G,selection:K}};return g&&G.bind("selectstart",function(){return!1}),A.data("Jcrop",bs),bs},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if( 21 | b==="api")return a(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else this.tagName=="IMG"?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(b){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:null,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges 22 | :!0,fixedSupport:!0,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}})(jQuery); -------------------------------------------------------------------------------- /vendor/assets/javascripts/active_admin_jcrop/jquery.color.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Color Animations v2.0pre 3 | * http://jquery.org/ 4 | * 5 | * Copyright 2011 John Resig 6 | * Dual licensed under the MIT or GPL Version 2 licenses. 7 | * http://jquery.org/license 8 | */ 9 | 10 | (function( jQuery, undefined ){ 11 | var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color outlineColor".split(" "), 12 | 13 | // plusequals test for += 100 -= 100 14 | rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, 15 | // a set of RE's that can match strings and generate color tuples. 16 | stringParsers = [{ 17 | re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 18 | parse: function( execResult ) { 19 | return [ 20 | execResult[ 1 ], 21 | execResult[ 2 ], 22 | execResult[ 3 ], 23 | execResult[ 4 ] 24 | ]; 25 | } 26 | }, { 27 | re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 28 | parse: function( execResult ) { 29 | return [ 30 | 2.55 * execResult[1], 31 | 2.55 * execResult[2], 32 | 2.55 * execResult[3], 33 | execResult[ 4 ] 34 | ]; 35 | } 36 | }, { 37 | re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, 38 | parse: function( execResult ) { 39 | return [ 40 | parseInt( execResult[ 1 ], 16 ), 41 | parseInt( execResult[ 2 ], 16 ), 42 | parseInt( execResult[ 3 ], 16 ) 43 | ]; 44 | } 45 | }, { 46 | re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, 47 | parse: function( execResult ) { 48 | return [ 49 | parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), 50 | parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), 51 | parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) 52 | ]; 53 | } 54 | }, { 55 | re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 56 | space: "hsla", 57 | parse: function( execResult ) { 58 | return [ 59 | execResult[1], 60 | execResult[2] / 100, 61 | execResult[3] / 100, 62 | execResult[4] 63 | ]; 64 | } 65 | }], 66 | 67 | // jQuery.Color( ) 68 | color = jQuery.Color = function( color, green, blue, alpha ) { 69 | return new jQuery.Color.fn.parse( color, green, blue, alpha ); 70 | }, 71 | spaces = { 72 | rgba: { 73 | cache: "_rgba", 74 | props: { 75 | red: { 76 | idx: 0, 77 | type: "byte", 78 | empty: true 79 | }, 80 | green: { 81 | idx: 1, 82 | type: "byte", 83 | empty: true 84 | }, 85 | blue: { 86 | idx: 2, 87 | type: "byte", 88 | empty: true 89 | }, 90 | alpha: { 91 | idx: 3, 92 | type: "percent", 93 | def: 1 94 | } 95 | } 96 | }, 97 | hsla: { 98 | cache: "_hsla", 99 | props: { 100 | hue: { 101 | idx: 0, 102 | type: "degrees", 103 | empty: true 104 | }, 105 | saturation: { 106 | idx: 1, 107 | type: "percent", 108 | empty: true 109 | }, 110 | lightness: { 111 | idx: 2, 112 | type: "percent", 113 | empty: true 114 | } 115 | } 116 | } 117 | }, 118 | propTypes = { 119 | "byte": { 120 | floor: true, 121 | min: 0, 122 | max: 255 123 | }, 124 | "percent": { 125 | min: 0, 126 | max: 1 127 | }, 128 | "degrees": { 129 | mod: 360, 130 | floor: true 131 | } 132 | }, 133 | rgbaspace = spaces.rgba.props, 134 | support = color.support = {}, 135 | 136 | // colors = jQuery.Color.names 137 | colors, 138 | 139 | // local aliases of functions called often 140 | each = jQuery.each; 141 | 142 | spaces.hsla.props.alpha = rgbaspace.alpha; 143 | 144 | function clamp( value, prop, alwaysAllowEmpty ) { 145 | var type = propTypes[ prop.type ] || {}, 146 | allowEmpty = prop.empty || alwaysAllowEmpty; 147 | 148 | if ( allowEmpty && value == null ) { 149 | return null; 150 | } 151 | if ( prop.def && value == null ) { 152 | return prop.def; 153 | } 154 | if ( type.floor ) { 155 | value = ~~value; 156 | } else { 157 | value = parseFloat( value ); 158 | } 159 | if ( value == null || isNaN( value ) ) { 160 | return prop.def; 161 | } 162 | if ( type.mod ) { 163 | value = value % type.mod; 164 | // -10 -> 350 165 | return value < 0 ? type.mod + value : value; 166 | } 167 | 168 | // for now all property types without mod have min and max 169 | return type.min > value ? type.min : type.max < value ? type.max : value; 170 | } 171 | 172 | function stringParse( string ) { 173 | var inst = color(), 174 | rgba = inst._rgba = []; 175 | 176 | string = string.toLowerCase(); 177 | 178 | each( stringParsers, function( i, parser ) { 179 | var match = parser.re.exec( string ), 180 | values = match && parser.parse( match ), 181 | parsed, 182 | spaceName = parser.space || "rgba", 183 | cache = spaces[ spaceName ].cache; 184 | 185 | 186 | if ( values ) { 187 | parsed = inst[ spaceName ]( values ); 188 | 189 | // if this was an rgba parse the assignment might happen twice 190 | // oh well.... 191 | inst[ cache ] = parsed[ cache ]; 192 | rgba = inst._rgba = parsed._rgba; 193 | 194 | // exit each( stringParsers ) here because we matched 195 | return false; 196 | } 197 | }); 198 | 199 | // Found a stringParser that handled it 200 | if ( rgba.length !== 0 ) { 201 | 202 | // if this came from a parsed string, force "transparent" when alpha is 0 203 | // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) 204 | if ( Math.max.apply( Math, rgba ) === 0 ) { 205 | jQuery.extend( rgba, colors.transparent ); 206 | } 207 | return inst; 208 | } 209 | 210 | // named colors / default - filter back through parse function 211 | if ( string = colors[ string ] ) { 212 | return string; 213 | } 214 | } 215 | 216 | color.fn = color.prototype = { 217 | constructor: color, 218 | parse: function( red, green, blue, alpha ) { 219 | if ( red === undefined ) { 220 | this._rgba = [ null, null, null, null ]; 221 | return this; 222 | } 223 | if ( red instanceof jQuery || red.nodeType ) { 224 | red = red instanceof jQuery ? red.css( green ) : jQuery( red ).css( green ); 225 | green = undefined; 226 | } 227 | 228 | var inst = this, 229 | type = jQuery.type( red ), 230 | rgba = this._rgba = [], 231 | source; 232 | 233 | // more than 1 argument specified - assume ( red, green, blue, alpha ) 234 | if ( green !== undefined ) { 235 | red = [ red, green, blue, alpha ]; 236 | type = "array"; 237 | } 238 | 239 | if ( type === "string" ) { 240 | return this.parse( stringParse( red ) || colors._default ); 241 | } 242 | 243 | if ( type === "array" ) { 244 | each( rgbaspace, function( key, prop ) { 245 | rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); 246 | }); 247 | return this; 248 | } 249 | 250 | if ( type === "object" ) { 251 | if ( red instanceof color ) { 252 | each( spaces, function( spaceName, space ) { 253 | if ( red[ space.cache ] ) { 254 | inst[ space.cache ] = red[ space.cache ].slice(); 255 | } 256 | }); 257 | } else { 258 | each( spaces, function( spaceName, space ) { 259 | each( space.props, function( key, prop ) { 260 | var cache = space.cache; 261 | 262 | // if the cache doesn't exist, and we know how to convert 263 | if ( !inst[ cache ] && space.to ) { 264 | 265 | // if the value was null, we don't need to copy it 266 | // if the key was alpha, we don't need to copy it either 267 | if ( red[ key ] == null || key === "alpha") { 268 | return; 269 | } 270 | inst[ cache ] = space.to( inst._rgba ); 271 | } 272 | 273 | // this is the only case where we allow nulls for ALL properties. 274 | // call clamp with alwaysAllowEmpty 275 | inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); 276 | }); 277 | }); 278 | } 279 | return this; 280 | } 281 | }, 282 | is: function( compare ) { 283 | var is = color( compare ), 284 | same = true, 285 | myself = this; 286 | 287 | each( spaces, function( _, space ) { 288 | var isCache = is[ space.cache ], 289 | localCache; 290 | if (isCache) { 291 | localCache = myself[ space.cache ] || space.to && space.to( myself._rgba ) || []; 292 | each( space.props, function( _, prop ) { 293 | if ( isCache[ prop.idx ] != null ) { 294 | same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); 295 | return same; 296 | } 297 | }); 298 | } 299 | return same; 300 | }); 301 | return same; 302 | }, 303 | _space: function() { 304 | var used = [], 305 | inst = this; 306 | each( spaces, function( spaceName, space ) { 307 | if ( inst[ space.cache ] ) { 308 | used.push( spaceName ); 309 | } 310 | }); 311 | return used.pop(); 312 | }, 313 | transition: function( other, distance ) { 314 | var end = color( other ), 315 | spaceName = end._space(), 316 | space = spaces[ spaceName ], 317 | start = this[ space.cache ] || space.to( this._rgba ), 318 | result = start.slice(); 319 | 320 | end = end[ space.cache ]; 321 | each( space.props, function( key, prop ) { 322 | var index = prop.idx, 323 | startValue = start[ index ], 324 | endValue = end[ index ], 325 | type = propTypes[ prop.type ] || {}; 326 | 327 | // if null, don't override start value 328 | if ( endValue === null ) { 329 | return; 330 | } 331 | // if null - use end 332 | if ( startValue === null ) { 333 | result[ index ] = endValue; 334 | } else { 335 | if ( type.mod ) { 336 | if ( endValue - startValue > type.mod / 2 ) { 337 | startValue += type.mod; 338 | } else if ( startValue - endValue > type.mod / 2 ) { 339 | startValue -= type.mod; 340 | } 341 | } 342 | result[ prop.idx ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); 343 | } 344 | }); 345 | return this[ spaceName ]( result ); 346 | }, 347 | blend: function( opaque ) { 348 | // if we are already opaque - return ourself 349 | if ( this._rgba[ 3 ] === 1 ) { 350 | return this; 351 | } 352 | 353 | var rgb = this._rgba.slice(), 354 | a = rgb.pop(), 355 | blend = color( opaque )._rgba; 356 | 357 | return color( jQuery.map( rgb, function( v, i ) { 358 | return ( 1 - a ) * blend[ i ] + a * v; 359 | })); 360 | }, 361 | toRgbaString: function() { 362 | var prefix = "rgba(", 363 | rgba = jQuery.map( this._rgba, function( v, i ) { 364 | return v == null ? ( i > 2 ? 1 : 0 ) : v; 365 | }); 366 | 367 | if ( rgba[ 3 ] === 1 ) { 368 | rgba.pop(); 369 | prefix = "rgb("; 370 | } 371 | 372 | return prefix + rgba.join(",") + ")"; 373 | }, 374 | toHslaString: function() { 375 | var prefix = "hsla(", 376 | hsla = jQuery.map( this.hsla(), function( v, i ) { 377 | if ( v == null ) { 378 | v = i > 2 ? 1 : 0; 379 | } 380 | 381 | // catch 1 and 2 382 | if ( i && i < 3 ) { 383 | v = Math.round( v * 100 ) + "%"; 384 | } 385 | return v; 386 | }); 387 | 388 | if ( hsla[ 3 ] === 1 ) { 389 | hsla.pop(); 390 | prefix = "hsl("; 391 | } 392 | return prefix + hsla.join(",") + ")"; 393 | }, 394 | toHexString: function( includeAlpha ) { 395 | var rgba = this._rgba.slice(), 396 | alpha = rgba.pop(); 397 | 398 | if ( includeAlpha ) { 399 | rgba.push( ~~( alpha * 255 ) ); 400 | } 401 | 402 | return "#" + jQuery.map( rgba, function( v, i ) { 403 | 404 | // default to 0 when nulls exist 405 | v = ( v || 0 ).toString( 16 ); 406 | return v.length === 1 ? "0" + v : v; 407 | }).join(""); 408 | }, 409 | toString: function() { 410 | return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); 411 | } 412 | }; 413 | color.fn.parse.prototype = color.fn; 414 | 415 | // hsla conversions adapted from: 416 | // http://www.google.com/codesearch/p#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/inspector/front-end/Color.js&d=7&l=193 417 | 418 | function hue2rgb( p, q, h ) { 419 | h = ( h + 1 ) % 1; 420 | if ( h * 6 < 1 ) { 421 | return p + (q - p) * 6 * h; 422 | } 423 | if ( h * 2 < 1) { 424 | return q; 425 | } 426 | if ( h * 3 < 2 ) { 427 | return p + (q - p) * ((2/3) - h) * 6; 428 | } 429 | return p; 430 | } 431 | 432 | spaces.hsla.to = function ( rgba ) { 433 | if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { 434 | return [ null, null, null, rgba[ 3 ] ]; 435 | } 436 | var r = rgba[ 0 ] / 255, 437 | g = rgba[ 1 ] / 255, 438 | b = rgba[ 2 ] / 255, 439 | a = rgba[ 3 ], 440 | max = Math.max( r, g, b ), 441 | min = Math.min( r, g, b ), 442 | diff = max - min, 443 | add = max + min, 444 | l = add * 0.5, 445 | h, s; 446 | 447 | if ( min === max ) { 448 | h = 0; 449 | } else if ( r === max ) { 450 | h = ( 60 * ( g - b ) / diff ) + 360; 451 | } else if ( g === max ) { 452 | h = ( 60 * ( b - r ) / diff ) + 120; 453 | } else { 454 | h = ( 60 * ( r - g ) / diff ) + 240; 455 | } 456 | 457 | if ( l === 0 || l === 1 ) { 458 | s = l; 459 | } else if ( l <= 0.5 ) { 460 | s = diff / add; 461 | } else { 462 | s = diff / ( 2 - add ); 463 | } 464 | return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; 465 | }; 466 | 467 | spaces.hsla.from = function ( hsla ) { 468 | if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { 469 | return [ null, null, null, hsla[ 3 ] ]; 470 | } 471 | var h = hsla[ 0 ] / 360, 472 | s = hsla[ 1 ], 473 | l = hsla[ 2 ], 474 | a = hsla[ 3 ], 475 | q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, 476 | p = 2 * l - q, 477 | r, g, b; 478 | 479 | return [ 480 | Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), 481 | Math.round( hue2rgb( p, q, h ) * 255 ), 482 | Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), 483 | a 484 | ]; 485 | }; 486 | 487 | 488 | each( spaces, function( spaceName, space ) { 489 | var props = space.props, 490 | cache = space.cache, 491 | to = space.to, 492 | from = space.from; 493 | 494 | // makes rgba() and hsla() 495 | color.fn[ spaceName ] = function( value ) { 496 | 497 | // generate a cache for this space if it doesn't exist 498 | if ( to && !this[ cache ] ) { 499 | this[ cache ] = to( this._rgba ); 500 | } 501 | if ( value === undefined ) { 502 | return this[ cache ].slice(); 503 | } 504 | 505 | var type = jQuery.type( value ), 506 | arr = ( type === "array" || type === "object" ) ? value : arguments, 507 | local = this[ cache ].slice(), 508 | ret; 509 | 510 | each( props, function( key, prop ) { 511 | var val = arr[ type === "object" ? key : prop.idx ]; 512 | if ( val == null ) { 513 | val = local[ prop.idx ]; 514 | } 515 | local[ prop.idx ] = clamp( val, prop ); 516 | }); 517 | 518 | if ( from ) { 519 | ret = color( from( local ) ); 520 | ret[ cache ] = local; 521 | return ret; 522 | } else { 523 | return color( local ); 524 | } 525 | }; 526 | 527 | // makes red() green() blue() alpha() hue() saturation() lightness() 528 | each( props, function( key, prop ) { 529 | // alpha is included in more than one space 530 | if ( color.fn[ key ] ) { 531 | return; 532 | } 533 | color.fn[ key ] = function( value ) { 534 | var vtype = jQuery.type( value ), 535 | fn = ( key === 'alpha' ? ( this._hsla ? 'hsla' : 'rgba' ) : spaceName ), 536 | local = this[ fn ](), 537 | cur = local[ prop.idx ], 538 | match; 539 | 540 | if ( vtype === "undefined" ) { 541 | return cur; 542 | } 543 | 544 | if ( vtype === "function" ) { 545 | value = value.call( this, cur ); 546 | vtype = jQuery.type( value ); 547 | } 548 | if ( value == null && prop.empty ) { 549 | return this; 550 | } 551 | if ( vtype === "string" ) { 552 | match = rplusequals.exec( value ); 553 | if ( match ) { 554 | value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); 555 | } 556 | } 557 | local[ prop.idx ] = value; 558 | return this[ fn ]( local ); 559 | }; 560 | }); 561 | }); 562 | 563 | // add .fx.step functions 564 | each( stepHooks, function( i, hook ) { 565 | jQuery.cssHooks[ hook ] = { 566 | set: function( elem, value ) { 567 | var parsed, backgroundColor, curElem; 568 | 569 | if ( jQuery.type( value ) !== 'string' || ( parsed = stringParse( value ) ) ) 570 | { 571 | value = color( parsed || value ); 572 | if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { 573 | curElem = hook === "backgroundColor" ? elem.parentNode : elem; 574 | do { 575 | backgroundColor = jQuery.curCSS( curElem, "backgroundColor" ); 576 | } while ( 577 | ( backgroundColor === "" || backgroundColor === "transparent" ) && 578 | ( curElem = curElem.parentNode ) && 579 | curElem.style 580 | ); 581 | 582 | value = value.blend( backgroundColor && backgroundColor !== "transparent" ? 583 | backgroundColor : 584 | "_default" ); 585 | } 586 | 587 | value = value.toRgbaString(); 588 | } 589 | elem.style[ hook ] = value; 590 | } 591 | }; 592 | jQuery.fx.step[ hook ] = function( fx ) { 593 | if ( !fx.colorInit ) { 594 | fx.start = color( fx.elem, hook ); 595 | fx.end = color( fx.end ); 596 | fx.colorInit = true; 597 | } 598 | jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); 599 | }; 600 | }); 601 | 602 | // detect rgba support 603 | jQuery(function() { 604 | var div = document.createElement( "div" ), 605 | div_style = div.style; 606 | 607 | div_style.cssText = "background-color:rgba(1,1,1,.5)"; 608 | support.rgba = div_style.backgroundColor.indexOf( "rgba" ) > -1; 609 | }); 610 | 611 | // Some named colors to work with 612 | // From Interface by Stefan Petre 613 | // http://interface.eyecon.ro/ 614 | colors = jQuery.Color.names = { 615 | aqua: "#00ffff", 616 | azure: "#f0ffff", 617 | beige: "#f5f5dc", 618 | black: "#000000", 619 | blue: "#0000ff", 620 | brown: "#a52a2a", 621 | cyan: "#00ffff", 622 | darkblue: "#00008b", 623 | darkcyan: "#008b8b", 624 | darkgrey: "#a9a9a9", 625 | darkgreen: "#006400", 626 | darkkhaki: "#bdb76b", 627 | darkmagenta: "#8b008b", 628 | darkolivegreen: "#556b2f", 629 | darkorange: "#ff8c00", 630 | darkorchid: "#9932cc", 631 | darkred: "#8b0000", 632 | darksalmon: "#e9967a", 633 | darkviolet: "#9400d3", 634 | fuchsia: "#ff00ff", 635 | gold: "#ffd700", 636 | green: "#008000", 637 | indigo: "#4b0082", 638 | khaki: "#f0e68c", 639 | lightblue: "#add8e6", 640 | lightcyan: "#e0ffff", 641 | lightgreen: "#90ee90", 642 | lightgrey: "#d3d3d3", 643 | lightpink: "#ffb6c1", 644 | lightyellow: "#ffffe0", 645 | lime: "#00ff00", 646 | magenta: "#ff00ff", 647 | maroon: "#800000", 648 | navy: "#000080", 649 | olive: "#808000", 650 | orange: "#ffa500", 651 | pink: "#ffc0cb", 652 | purple: "#800080", 653 | violet: "#800080", 654 | red: "#ff0000", 655 | silver: "#c0c0c0", 656 | white: "#ffffff", 657 | yellow: "#ffff00", 658 | transparent: [ null, null, null, 0 ], 659 | _default: "#ffffff" 660 | }; 661 | })( jQuery ); 662 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/active_admin_jcrop/Jcrop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ricardonacif/active_admin_jcrop/a63b39327a087a9d1463ef9eb525f14fe4ba3d89/vendor/assets/stylesheets/active_admin_jcrop/Jcrop.gif -------------------------------------------------------------------------------- /vendor/assets/stylesheets/active_admin_jcrop/jquery.Jcrop.css: -------------------------------------------------------------------------------- 1 | /* jquery.Jcrop.css v0.9.12 - MIT License */ 2 | /* 3 | The outer-most container in a typical Jcrop instance 4 | If you are having difficulty with formatting related to styles 5 | on a parent element, place any fixes here or in a like selector 6 | 7 | You can also style this element if you want to add a border, etc 8 | A better method for styling can be seen below with .jcrop-light 9 | (Add a class to the holder and style elements for that extended class) 10 | */ 11 | .jcrop-holder { 12 | direction: ltr; 13 | text-align: left; 14 | } 15 | /* Selection Border */ 16 | .jcrop-vline, 17 | .jcrop-hline { 18 | background: #ffffff url("Jcrop.gif"); 19 | font-size: 0; 20 | position: absolute; 21 | } 22 | .jcrop-vline { 23 | height: 100%; 24 | width: 1px !important; 25 | } 26 | .jcrop-vline.right { 27 | right: 0; 28 | } 29 | .jcrop-hline { 30 | height: 1px !important; 31 | width: 100%; 32 | } 33 | .jcrop-hline.bottom { 34 | bottom: 0; 35 | } 36 | /* Invisible click targets */ 37 | .jcrop-tracker { 38 | height: 100%; 39 | width: 100%; 40 | /* "turn off" link highlight */ 41 | -webkit-tap-highlight-color: transparent; 42 | /* disable callout, image save panel */ 43 | -webkit-touch-callout: none; 44 | /* disable cut copy paste */ 45 | -webkit-user-select: none; 46 | } 47 | /* Selection Handles */ 48 | .jcrop-handle { 49 | background-color: #333333; 50 | border: 1px #eeeeee solid; 51 | width: 7px; 52 | height: 7px; 53 | font-size: 1px; 54 | } 55 | .jcrop-handle.ord-n { 56 | left: 50%; 57 | margin-left: -4px; 58 | margin-top: -4px; 59 | top: 0; 60 | } 61 | .jcrop-handle.ord-s { 62 | bottom: 0; 63 | left: 50%; 64 | margin-bottom: -4px; 65 | margin-left: -4px; 66 | } 67 | .jcrop-handle.ord-e { 68 | margin-right: -4px; 69 | margin-top: -4px; 70 | right: 0; 71 | top: 50%; 72 | } 73 | .jcrop-handle.ord-w { 74 | left: 0; 75 | margin-left: -4px; 76 | margin-top: -4px; 77 | top: 50%; 78 | } 79 | .jcrop-handle.ord-nw { 80 | left: 0; 81 | margin-left: -4px; 82 | margin-top: -4px; 83 | top: 0; 84 | } 85 | .jcrop-handle.ord-ne { 86 | margin-right: -4px; 87 | margin-top: -4px; 88 | right: 0; 89 | top: 0; 90 | } 91 | .jcrop-handle.ord-se { 92 | bottom: 0; 93 | margin-bottom: -4px; 94 | margin-right: -4px; 95 | right: 0; 96 | } 97 | .jcrop-handle.ord-sw { 98 | bottom: 0; 99 | left: 0; 100 | margin-bottom: -4px; 101 | margin-left: -4px; 102 | } 103 | /* Dragbars */ 104 | .jcrop-dragbar.ord-n, 105 | .jcrop-dragbar.ord-s { 106 | height: 7px; 107 | width: 100%; 108 | } 109 | .jcrop-dragbar.ord-e, 110 | .jcrop-dragbar.ord-w { 111 | height: 100%; 112 | width: 7px; 113 | } 114 | .jcrop-dragbar.ord-n { 115 | margin-top: -4px; 116 | } 117 | .jcrop-dragbar.ord-s { 118 | bottom: 0; 119 | margin-bottom: -4px; 120 | } 121 | .jcrop-dragbar.ord-e { 122 | margin-right: -4px; 123 | right: 0; 124 | } 125 | .jcrop-dragbar.ord-w { 126 | margin-left: -4px; 127 | } 128 | /* The "jcrop-light" class/extension */ 129 | .jcrop-light .jcrop-vline, 130 | .jcrop-light .jcrop-hline { 131 | background: #ffffff; 132 | filter: alpha(opacity=70) !important; 133 | opacity: .70!important; 134 | } 135 | .jcrop-light .jcrop-handle { 136 | -moz-border-radius: 3px; 137 | -webkit-border-radius: 3px; 138 | background-color: #000000; 139 | border-color: #ffffff; 140 | border-radius: 3px; 141 | } 142 | /* The "jcrop-dark" class/extension */ 143 | .jcrop-dark .jcrop-vline, 144 | .jcrop-dark .jcrop-hline { 145 | background: #000000; 146 | filter: alpha(opacity=70) !important; 147 | opacity: 0.7 !important; 148 | } 149 | .jcrop-dark .jcrop-handle { 150 | -moz-border-radius: 3px; 151 | -webkit-border-radius: 3px; 152 | background-color: #ffffff; 153 | border-color: #000000; 154 | border-radius: 3px; 155 | } 156 | /* Simple macro to turn off the antlines */ 157 | .solid-line .jcrop-vline, 158 | .solid-line .jcrop-hline { 159 | background: #ffffff; 160 | } 161 | /* Fix for twitter bootstrap et al. */ 162 | .jcrop-holder img, 163 | img.jcrop-preview { 164 | max-width: none; 165 | } 166 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/active_admin_jcrop/jquery.Jcrop.min.css: -------------------------------------------------------------------------------- 1 | /* jquery.Jcrop.min.css v0.9.12 (build:20130126) */ 2 | .jcrop-holder{direction:ltr;text-align:left;} 3 | .jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif);font-size:0;position:absolute;} 4 | .jcrop-vline{height:100%;width:1px!important;} 5 | .jcrop-vline.right{right:0;} 6 | .jcrop-hline{height:1px!important;width:100%;} 7 | .jcrop-hline.bottom{bottom:0;} 8 | .jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;} 9 | .jcrop-handle{background-color:#333;border:1px #EEE solid;font-size:1px;height:7px;width:7px;} 10 | .jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;} 11 | .jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;} 12 | .jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;} 13 | .jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;} 14 | .jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;} 15 | .jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;} 16 | .jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;} 17 | .jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;} 18 | .jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;} 19 | .jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;} 20 | .jcrop-dragbar.ord-n{margin-top:-4px;} 21 | .jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;} 22 | .jcrop-dragbar.ord-e{margin-right:-4px;right:0;} 23 | .jcrop-dragbar.ord-w{margin-left:-4px;} 24 | .jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.70!important;} 25 | .jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;} 26 | .jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important;} 27 | .jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;} 28 | .solid-line .jcrop-vline,.solid-line .jcrop-hline{background:#FFF;} 29 | .jcrop-holder img,img.jcrop-preview{max-width:none;} 30 | --------------------------------------------------------------------------------