├── .fasterer.yml ├── .github ├── FUNDING.yml └── workflows │ ├── linters.yml │ ├── specs_rails61.yml │ ├── specs_rails70.yml │ ├── specs_rails71.yml │ ├── specs_rails72.yml │ └── specs_rails80.yml ├── .gitignore ├── .reviewdog.yml ├── .rspec ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── Makefile ├── README.md ├── Rakefile ├── activeadmin_medium_editor.gemspec ├── app └── assets │ ├── javascripts │ └── activeadmin │ │ ├── medium_editor │ │ ├── medium_editor.js │ │ └── medium_editor.min.js │ │ └── medium_editor_input.js │ └── stylesheets │ └── activeadmin │ ├── _medium_editor_input.scss │ └── medium_editor │ ├── _settings.scss │ ├── animations │ ├── _image-loading.scss │ └── _pop-upwards.scss │ ├── components │ ├── _anchor-preview.scss │ ├── _file-dragging.scss │ ├── _placeholder.scss │ ├── _toolbar-form.scss │ └── _toolbar.scss │ ├── medium_editor.scss │ ├── themes │ ├── beagle.scss │ ├── bootstrap.scss │ ├── default.scss │ ├── flat.scss │ ├── mani.scss │ ├── roman.scss │ └── tim.scss │ └── util │ └── _clearfix.scss ├── bin ├── fasterer ├── rails ├── rake ├── rspec └── rubocop ├── extra ├── .bashrc ├── .env ├── Dockerfile ├── Dockerfile.dockerignore ├── dev_setup.sh ├── development.md ├── docker-compose.yml └── screenshot.png ├── lib ├── activeadmin │ ├── medium_editor.rb │ └── medium_editor │ │ ├── engine.rb │ │ └── version.rb ├── activeadmin_medium_editor.rb └── formtastic │ └── inputs │ └── medium_editor_input.rb └── spec ├── dummy ├── .ruby-version ├── .tool-versions ├── Rakefile ├── app │ ├── admin │ │ ├── authors.rb │ │ ├── dashboard.rb │ │ ├── posts.rb │ │ └── tags.rb │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── images │ │ │ └── .keep │ │ ├── javascripts │ │ │ └── active_admin.js │ │ └── stylesheets │ │ │ ├── active_admin.scss │ │ │ └── application.css │ ├── channels │ │ └── application_cable │ │ │ ├── channel.rb │ │ │ └── connection.rb │ ├── controllers │ │ ├── application_controller.rb │ │ └── concerns │ │ │ └── .keep │ ├── helpers │ │ └── application_helper.rb │ ├── javascript │ │ └── packs │ │ │ └── application.js │ ├── jobs │ │ └── application_job.rb │ ├── mailers │ │ └── application_mailer.rb │ ├── models │ │ ├── application_record.rb │ │ ├── author.rb │ │ ├── concerns │ │ │ └── .keep │ │ ├── post.rb │ │ ├── post_tag.rb │ │ ├── profile.rb │ │ └── tag.rb │ └── views │ │ └── layouts │ │ ├── application.html.erb │ │ ├── mailer.html.erb │ │ └── mailer.text.erb ├── bin │ ├── rails │ ├── rake │ └── setup ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── cable.yml │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── active_admin.rb │ │ ├── active_storage.rb │ │ ├── application_controller_renderer.rb │ │ ├── assets.rb │ │ ├── backtrace_silencers.rb │ │ ├── content_security_policy.rb │ │ ├── cookies_serializer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ ├── puma.rb │ ├── routes.rb │ ├── spring.rb │ └── storage.yml ├── db │ ├── migrate │ │ ├── 20170806125915_create_active_storage_tables.active_storage.rb │ │ ├── 20180101010101_create_active_admin_comments.rb │ │ ├── 20180607053251_create_authors.rb │ │ ├── 20180607053254_create_profiles.rb │ │ ├── 20180607053255_create_tags.rb │ │ ├── 20180607053257_create_post_tags.rb │ │ └── 20180607053739_create_posts.rb │ └── schema.rb ├── lib │ └── assets │ │ └── .keep ├── log │ └── .keep ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── apple-touch-icon-precomposed.png │ ├── apple-touch-icon.png │ └── favicon.ico └── tmp │ └── .keep ├── rails_helper.rb ├── spec_helper.rb ├── support └── capybara.rb └── system ├── medium_editor_spec.rb └── medium_js_spec.rb /.fasterer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude_paths: 3 | - bin/* 4 | - db/schema.rb 5 | - gemfiles/**/* 6 | - spec/dummy/**/* 7 | - vendor/**/* 8 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [blocknotes] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Linters 3 | 4 | on: 5 | pull_request: 6 | branches: [master] 7 | push: 8 | branches: [master] 9 | 10 | jobs: 11 | reviewdog: 12 | name: Reviewdog 13 | runs-on: ubuntu-latest 14 | 15 | env: 16 | RAILS_VERSION: 7.0 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | 22 | - name: Set up Ruby 23 | uses: ruby/setup-ruby@v1 24 | with: 25 | ruby-version: 3.0 26 | bundler-cache: true 27 | 28 | - name: Set up Reviewdog 29 | uses: reviewdog/action-setup@v1 30 | with: 31 | reviewdog_version: latest 32 | 33 | - name: Run Reviewdog 34 | env: 35 | REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | run: | 37 | reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer,rubocop 38 | 39 | # NOTE: check with: reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer -diff="git diff" -tee 40 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails61.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 6.1 with ActiveAdmin 2.9 3 | 4 | on: 5 | pull_request: 6 | branches: [master] 7 | push: 8 | branches: [master] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.0'] 17 | 18 | env: 19 | RAILS_VERSION: 6.0 20 | ACTIVEADMIN_VERSION: 2.9.0 21 | 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | - name: Set up Ruby 27 | uses: ruby/setup-ruby@v1 28 | with: 29 | ruby-version: ${{ matrix.ruby }} 30 | bundler-cache: true 31 | 32 | - name: Database setup 33 | run: bin/rails db:create db:migrate db:test:prepare 34 | 35 | - name: Run tests 36 | run: bundle exec rspec --profile 37 | 38 | - name: On failure, archive screenshots as artifacts 39 | uses: actions/upload-artifact@v4 40 | if: failure() 41 | with: 42 | name: test-failed-screenshots 43 | path: spec/dummy/tmp/screenshots 44 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails70.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 7.0 3 | 4 | on: 5 | pull_request: 6 | branches: [master] 7 | push: 8 | branches: [master] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.0', '3.2'] 17 | 18 | env: 19 | RAILS_VERSION: 7.0 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails71.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 7.1 3 | 4 | on: 5 | pull_request: 6 | branches: [master] 7 | push: 8 | branches: [master] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.2', '3.4'] 17 | 18 | env: 19 | RAILS_VERSION: 7.1 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails72.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 7.2 3 | 4 | on: 5 | pull_request: 6 | branches: [master] 7 | push: 8 | branches: [master] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.2', '3.4'] 17 | 18 | env: 19 | RAILS_VERSION: 7.2 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails80.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 8.0 3 | 4 | on: 5 | pull_request: 6 | branches: [master] 7 | push: 8 | branches: [master] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.2', '3.4'] 17 | 18 | env: 19 | RAILS_VERSION: 8.0 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.orig 3 | 4 | /.rspec_failures 5 | /.rubocop-* 6 | /Gemfile.lock 7 | 8 | /_misc/ 9 | /spec/dummy/db/*.sqlite3* 10 | /spec/dummy/log/ 11 | /spec/dummy/storage/ 12 | /spec/dummy/tmp/ 13 | -------------------------------------------------------------------------------- /.reviewdog.yml: -------------------------------------------------------------------------------- 1 | --- 2 | runner: 3 | fasterer: 4 | cmd: bin/fasterer 5 | level: info 6 | rubocop: 7 | cmd: bin/rubocop 8 | level: info 9 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require rails_helper 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | inherit_from: 3 | - https://relaxed.ruby.style/rubocop.yml 4 | 5 | AllCops: 6 | Exclude: 7 | - bin/* 8 | - db/schema.rb 9 | - gemfiles/**/* 10 | - spec/dummy/**/* 11 | - vendor/**/* 12 | NewCops: enable 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # medium-editor for ActiveAdmin 2 | 3 | An Active Admin plugin to use Medium Editor. 4 | 5 | ## v1.0.0 - 2022-04-18 6 | 7 | - Set minimum Ruby version to 2.6.0 8 | - Remove `sassc` dependency 9 | - Enable Ruby 3.0 specs support 10 | - Enable Rails 7.0 specs support 11 | - Internal improvements 12 | 13 | ## v0.2.14 - 2021-03-20 14 | 15 | - Fix editor loading with Turbolinks 16 | - Specs improvements 17 | 18 | ## v0.2.12 - 2020-09-09 19 | 20 | - JS refactoring 21 | - Minor specs improvements 22 | - README changes 23 | 24 | ## v0.2.9 - 2020-09-04 25 | 26 | - Reset some styles manually to the defaults to render better the elements in the editor 27 | 28 | ## v0.2.8 - 2020-09-03 29 | 30 | - Update MediumEditor to commit `d113a744` 31 | - Add specs for editor in nested resources 32 | - Add Rubocop and remove SimpleCov gems 33 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | def eval_version(dependency, version) 6 | return [dependency] if version.empty? 7 | 8 | version.count('.') < 2 ? [dependency, "~> #{version}.0"] : [dependency, version] 9 | end 10 | 11 | if ENV['DEVEL'] == '1' 12 | gem 'activeadmin_medium_editor', path: './' 13 | else 14 | gemspec 15 | end 16 | 17 | ruby_ver = ENV.fetch('RUBY_VERSION', '') 18 | 19 | rails_ver = ENV.fetch('RAILS_VERSION', '') 20 | rails = eval_version('rails', rails_ver) 21 | gem(*rails) 22 | 23 | active_admin_ver = ENV.fetch('ACTIVEADMIN_VERSION', '') 24 | active_admin = eval_version('activeadmin', active_admin_ver) 25 | gem(*active_admin) 26 | 27 | ruby32 = ruby_ver.empty? || Gem::Version.new(ruby_ver) >= Gem::Version.new('3.2') 28 | rails72 = rails_ver.empty? || Gem::Version.new(rails_ver) >= Gem::Version.new('7.2') 29 | sqlite3 = ruby32 && rails72 ? ['sqlite3'] : ['sqlite3', '~> 1.4'] 30 | gem(*sqlite3) 31 | 32 | gem 'zeitwerk', '~> 2.6.18' unless ruby32 33 | 34 | # NOTE: to avoid error: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger 35 | gem 'concurrent-ruby', '1.3.4' 36 | 37 | # Misc 38 | gem 'bigdecimal' 39 | gem 'csv' 40 | gem 'mutex_m' 41 | gem 'puma' 42 | gem 'sassc' 43 | gem 'sprockets-rails' 44 | 45 | # Testing 46 | gem 'capybara' 47 | gem 'cuprite' 48 | gem 'rspec_junit_formatter' 49 | gem 'rspec-rails' 50 | gem 'simplecov', require: false 51 | gem 'super_diff' 52 | 53 | # Linters 54 | gem 'fasterer' 55 | gem 'rubocop' 56 | gem 'rubocop-capybara' 57 | gem 'rubocop-packaging' 58 | gem 'rubocop-performance' 59 | gem 'rubocop-rails' 60 | gem 'rubocop-rspec' 61 | gem 'rubocop-rspec_rails' 62 | 63 | # Tools 64 | gem 'pry-rails' 65 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2020 Mattia Roccoberton 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include extra/.env 2 | 3 | help: 4 | @echo -e "${COMPOSE_PROJECT_NAME} - Main project commands:\n\ 5 | make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN)\n\ 6 | make specs # run the tests (after up)\n\ 7 | make lint # run the linters (after up)\n\ 8 | make server # run the server (after up)\n\ 9 | make shell # open a shell (after up)\n\ 10 | make down # cleanup (after up)\n\ 11 | Example: RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up" 12 | 13 | # System commands 14 | 15 | build: 16 | @rm -f Gemfile.lock spec/dummy/db/*.sqlite3 17 | @docker compose -f extra/docker-compose.yml build 18 | 19 | db_reset: 20 | @docker compose -f extra/docker-compose.yml run --rm app bin/rails db:create db:migrate db:test:prepare 21 | 22 | up: build db_reset 23 | @docker compose -f extra/docker-compose.yml up 24 | 25 | shell: 26 | @docker compose -f extra/docker-compose.yml exec app bash 27 | 28 | down: 29 | @docker compose -f extra/docker-compose.yml down --volumes --rmi local --remove-orphans 30 | 31 | # App commands 32 | 33 | seed: 34 | @docker compose -f extra/docker-compose.yml exec app bin/rails db:seed 35 | 36 | console: seed 37 | @docker compose -f extra/docker-compose.yml exec app bin/rails console 38 | 39 | lint: 40 | @docker compose -f extra/docker-compose.yml exec app bin/rubocop 41 | 42 | server: seed 43 | @rm -f spec/dummy/tmp/pids/server.pid 44 | @docker compose -f extra/docker-compose.yml exec app bin/rails server -b 0.0.0.0 -p ${SERVER_PORT} 45 | 46 | specs: 47 | @docker compose -f extra/docker-compose.yml exec app bin/rspec --fail-fast 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PROJECT UNMAINTAINED 2 | 3 | > *This project is not maintained anymore* 4 | > 5 | > *If you like it or continue to use it fork it please.* 6 | 7 | --- 8 | 9 | # Active Admin Medium Editor 10 | [![gem version](https://badge.fury.io/rb/activeadmin_medium_editor.svg)](https://badge.fury.io/rb/activeadmin_medium_editor) 11 | [![Gem downloads](https://badgen.net/rubygems/dt/activeadmin_medium_editor)](https://rubygems.org/gems/activeadmin_medium_editor) 12 | [![linters](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/linters.yml) 13 | [![specs Rails 6.1](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/specs_rails61.yml/badge.svg)](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/specs_rails61.yml) 14 | [![specs Rails 7.0](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/specs_rails70.yml/badge.svg)](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/specs_rails70.yml) 15 | 16 | An Active Admin plugin to use [medium-editor](https://github.com/yabwe/medium-editor), a compact and clean WYSIWYG editor. 17 | 18 | **IMPORTANT NOTICE**: while I like the Medium Editor idea of having floating buttons, it looks like that they are slow to release new stable versions. Some editor bugs are related to this problem unfortunately. 19 | 20 | ![screenshot](extra/screenshot.png) 21 | 22 | ## Usage 23 | 24 | - After the installation, select some text in the editor 25 | - A pop-up menu is shown with the available buttons 26 | - Click on a button and the effect will be applied to the selected text 27 | 28 | ## Install 29 | 30 | - After installing Active Admin, add to your Gemfile: `gem 'activeadmin_medium_editor'` 31 | - Add also a SASS/SCSS gem to your Gemfile (ex. `gem 'sassc'`) 32 | - Add at the end of your Active Admin styles (_app/assets/stylesheets/active_admin.scss_): 33 | ```scss 34 | @import 'activeadmin/medium_editor/medium_editor'; 35 | @import 'activeadmin/medium_editor_input'; 36 | @import 'activeadmin/medium_editor/themes/default'; // or another theme 37 | ``` 38 | - Add at the end of your Active Admin javascripts (_app/assets/javascripts/active_admin.js_): 39 | ```js 40 | //= require activeadmin/medium_editor/medium_editor 41 | //= require activeadmin/medium_editor_input 42 | ``` 43 | - Use the input with `as: :medium_editor` in Active Admin model conf 44 | - **data-options**: permits to set *medium-editor* options directly - see [options list](https://github.com/yabwe/medium-editor#mediumeditor-options) (examples below) 45 | 46 | > Why 2 separated scripts/styles? In this way you can include a different version of *medium-editor* if you like 47 | 48 | > **UPDATE FROM VERSION < 0.2.8**: please change your _app/assets/stylesheets/active_admin.scss_ using the new import lines above 49 | 50 | ## Examples 51 | 52 | ### Basic usage 53 | 54 | ```ruby 55 | # Active Admin post form conf: 56 | form do |f| 57 | f.inputs 'Post' do 58 | f.input :title 59 | f.input :description, as: :medium_editor, input_html: { data: { options: '{"spellcheck":false,"toolbar":{"buttons":["bold","italic","underline","anchor"]}}' } } 60 | f.input :published 61 | end 62 | f.actions 63 | end 64 | ``` 65 | 66 | ### Buttons configuration 67 | 68 | ```ruby 69 | toolbar = { buttons: %w[bold italic underline strikethrough subscript superscript anchor image quote pre orderedlist unorderedlist indent outdent justifyLeft justifyCenter justifyRight justifyFull h1 h2 h3 h4 h5 h6 removeFormat html] } 70 | f.input :description, as: :medium_editor, input_html: { data: { options: { toolbar: toolbar } } } 71 | ``` 72 | 73 | For details about the buttons' effect please refer to medium-editor documentation. 74 | 75 | ## Changelog 76 | 77 | The changelog is available [here](CHANGELOG.md). 78 | 79 | ## Do you like it? Star it! 80 | 81 | If you use this component just star it. A developer is more motivated to improve a project when there is some interest. My other [Active Admin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source). 82 | 83 | Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me). 84 | 85 | ## Contributors 86 | 87 | - [Mattia Roccoberton](https://blocknot.es): author 88 | - The good guys that opened issues and pull requests from time to time 89 | 90 | ## License 91 | 92 | The gem is available as open-source under the terms of the [MIT](LICENSE.txt). 93 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | begin 4 | require 'bundler/setup' 5 | rescue LoadError 6 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 7 | end 8 | 9 | APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__) 10 | load 'rails/tasks/engine.rake' 11 | 12 | load 'rails/tasks/statistics.rake' 13 | 14 | require 'bundler/gem_tasks' 15 | 16 | begin 17 | require 'rspec/core/rake_task' 18 | 19 | RSpec::Core::RakeTask.new(:spec) do |t| 20 | # t.ruby_opts = %w[-w] 21 | t.rspec_opts = ['--color', '--format documentation'] 22 | end 23 | 24 | task default: :spec 25 | rescue LoadError 26 | puts '! LoadError: no RSpec available' 27 | end 28 | -------------------------------------------------------------------------------- /activeadmin_medium_editor.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('lib', __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require 'activeadmin/medium_editor/version' 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = 'activeadmin_medium_editor' 9 | spec.version = ActiveAdmin::MediumEditor::VERSION 10 | spec.summary = 'medium-editor for ActiveAdmin' 11 | spec.description = 'An Active Admin plugin to use Medium Editor' 12 | spec.license = 'MIT' 13 | spec.authors = ['Mattia Roccoberton'] 14 | spec.email = 'mat@blocknot.es' 15 | spec.homepage = 'https://github.com/blocknotes/activeadmin_medium_editor' 16 | 17 | spec.required_ruby_version = '>= 2.6.0' 18 | 19 | spec.metadata['homepage_uri'] = spec.homepage 20 | spec.metadata['changelog_uri'] = 'https://github.com/blocknotes/activeadmin_medium_editor/blob/master/CHANGELOG.md' 21 | spec.metadata['source_code_uri'] = spec.homepage 22 | 23 | spec.metadata['rubygems_mfa_required'] = 'true' 24 | 25 | spec.files = Dir['{app,lib}/**/*', 'LICENSE.txt', 'Rakefile', 'README.md'] 26 | spec.require_paths = ['lib'] 27 | 28 | spec.add_dependency 'activeadmin', '>= 2.0' 29 | end 30 | -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/medium_editor_input.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict' 3 | 4 | // --- functions ------------------------------------------------------------- 5 | function initMediumEditors() { 6 | $('[data-aa-medium-editor]').each(function () { 7 | if (!$(this).hasClass('medium-editor--active')) { 8 | let options = {} 9 | options = $.extend({}, options, $(this).data('options')) 10 | new MediumEditor($(this), options) 11 | $(this).addClass('medium-editor--active') 12 | } 13 | }) 14 | } 15 | 16 | // --- events ---------------------------------------------------------------- 17 | $(document).ready(initMediumEditors) 18 | $(document).on('has_many_add:after', '.has_many_container', initMediumEditors) 19 | $(document).on('turbolinks:load', initMediumEditors) 20 | })() 21 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/_medium_editor_input.scss: -------------------------------------------------------------------------------- 1 | body.active_admin form { 2 | textarea.medium-editor-hidden{ 3 | display: none; 4 | } 5 | 6 | .medium-editor-element { 7 | background-color: #fff; 8 | border-radius: 3px; 9 | border: 1px solid #c9d0d6; 10 | display: inline-block; 11 | max-height: 200px; 12 | min-height: 100px; 13 | overflow-y: scroll; 14 | padding: 8px 10px 7px; 15 | width: calc(80% - 22px); 16 | 17 | // reset internal elements 18 | * { 19 | margin: initial; 20 | padding: initial; 21 | text-align: initial; 22 | } 23 | 24 | h1 { 25 | margin-top: 0.67em; 26 | margin-bottom: 0.67em; 27 | } 28 | 29 | h2 { 30 | margin-top: 0.83em; 31 | margin-bottom: 0.83em; 32 | } 33 | 34 | h3 { 35 | margin-top: 1em; 36 | margin-bottom: 1em; 37 | } 38 | 39 | h4 { 40 | margin-top: 1.33em; 41 | margin-bottom: 1.33em; 42 | } 43 | 44 | h5 { 45 | margin-top: 1.67em; 46 | margin-bottom: 1.67em; 47 | } 48 | 49 | h6 { 50 | margin-top: 2.33em; 51 | margin-bottom: 2.33em; 52 | } 53 | 54 | blockquote { 55 | margin: 1.5em; 56 | } 57 | 58 | ol { 59 | list-style-type: decimal; 60 | } 61 | 62 | p { 63 | margin-top: 1em; 64 | margin-bottom: 1em; 65 | } 66 | 67 | ul { 68 | list-style-type: disc; 69 | } 70 | 71 | ul, ol { 72 | margin: 1em 2em 1em 0; 73 | padding-left: 2em; 74 | } 75 | } 76 | 77 | .medium-editor-element:focus { 78 | border-color: transparent; 79 | } 80 | 81 | .medium_editor > label { 82 | display: inline-block; 83 | float: none; 84 | vertical-align: top; 85 | } 86 | } 87 | 88 | button.medium-editor-action { 89 | border-radius: 0; 90 | } 91 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/_settings.scss: -------------------------------------------------------------------------------- 1 | // typography 2 | $font-fixed: Consolas, "Liberation Mono", Menlo, Courier, monospace !default; 3 | $font-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif !default; 4 | 5 | // ui / positioning 6 | $z-toolbar: 2000 !default; 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/animations/_image-loading.scss: -------------------------------------------------------------------------------- 1 | @keyframes medium-editor-image-loading { 2 | 0% { 3 | transform: scale(0) 4 | } 5 | 100% { 6 | transform: scale(1); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/animations/_pop-upwards.scss: -------------------------------------------------------------------------------- 1 | @keyframes medium-editor-pop-upwards { 2 | 0% { 3 | opacity: 0; 4 | transform: matrix(.97, 0, 0, 1, 0, 12); 5 | } 6 | 7 | 20% { 8 | opacity: .7; 9 | transform: matrix(.99, 0, 0, 1, 0, 2); 10 | } 11 | 12 | 40% { 13 | opacity: 1; 14 | transform: matrix(1, 0, 0, 1, 0, -1); 15 | } 16 | 17 | 100% { 18 | transform: matrix(1, 0, 0, 1, 0, 0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/components/_anchor-preview.scss: -------------------------------------------------------------------------------- 1 | .medium-editor-anchor-preview { 2 | font-family: $font-sans-serif; 3 | font-size: 16px; 4 | left: 0; 5 | line-height: 1.4; 6 | max-width: 280px; 7 | position: absolute; 8 | text-align: center; 9 | top: 0; 10 | word-break: break-all; 11 | word-wrap: break-word; 12 | visibility: hidden; 13 | z-index: $z-toolbar; 14 | 15 | a { 16 | color: #fff; 17 | display: inline-block; 18 | margin: 5px 5px 10px; 19 | } 20 | } 21 | 22 | .medium-editor-anchor-preview-active { 23 | visibility: visible; 24 | } 25 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/components/_file-dragging.scss: -------------------------------------------------------------------------------- 1 | .medium-editor-dragover { 2 | background: #ddd; 3 | } 4 | 5 | .medium-editor-image-loading { 6 | animation: medium-editor-image-loading 1s infinite ease-in-out; 7 | background-color: #333; 8 | border-radius: 100%; 9 | display: inline-block; 10 | height: 40px; 11 | width: 40px; 12 | } 13 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/components/_placeholder.scss: -------------------------------------------------------------------------------- 1 | .medium-editor-placeholder { 2 | position: relative; 3 | 4 | &:after { 5 | content: attr(data-placeholder) !important; 6 | font-style: italic; 7 | position: absolute; 8 | left: 0; 9 | top: 0; 10 | white-space: pre; 11 | padding: inherit; 12 | margin: inherit; 13 | } 14 | } 15 | 16 | .medium-editor-placeholder-relative { 17 | position: relative; 18 | 19 | &:after { 20 | content: attr(data-placeholder) !important; 21 | font-style: italic; 22 | position: relative; 23 | white-space: pre; 24 | padding: inherit; 25 | margin: inherit; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/components/_toolbar-form.scss: -------------------------------------------------------------------------------- 1 | .medium-editor-toolbar-form { 2 | display: none; 3 | 4 | input, 5 | a { 6 | font-family: $font-sans-serif; 7 | } 8 | 9 | .medium-editor-toolbar-form-row { 10 | line-height: 14px; 11 | margin-left: 5px; 12 | padding-bottom: 5px; 13 | } 14 | 15 | .medium-editor-toolbar-input, 16 | label { 17 | border: none; 18 | box-sizing: border-box; 19 | font-size: 14px; 20 | margin: 0; 21 | padding: 6px; 22 | width: 316px; 23 | display: inline-block; 24 | 25 | &:focus { 26 | appearance: none; 27 | border: none; 28 | box-shadow: none; 29 | outline: 0; 30 | } 31 | } 32 | 33 | a { 34 | display: inline-block; 35 | font-size: 24px; 36 | font-weight: bolder; 37 | margin: 0 10px; 38 | text-decoration: none; 39 | } 40 | } 41 | 42 | .medium-editor-toolbar-form-active { 43 | display: block; 44 | } 45 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/components/_toolbar.scss: -------------------------------------------------------------------------------- 1 | %medium-toolbar-arrow { 2 | border-style: solid; 3 | content: ''; 4 | display: block; 5 | height: 0; 6 | left: 50%; 7 | margin-left: -8px; 8 | position: absolute; 9 | width: 0; 10 | } 11 | 12 | .medium-toolbar-arrow-under:after { 13 | @extend %medium-toolbar-arrow; 14 | border-width: 8px 8px 0 8px; 15 | } 16 | 17 | .medium-toolbar-arrow-over:before { 18 | @extend %medium-toolbar-arrow; 19 | border-width: 0 8px 8px 8px; 20 | top: -8px; 21 | } 22 | 23 | .medium-editor-toolbar { 24 | font-family: $font-sans-serif; 25 | font-size: 16px; 26 | left: 0; 27 | position: absolute; 28 | top: 0; 29 | visibility: hidden; 30 | z-index: $z-toolbar; 31 | 32 | ul { 33 | margin: 0; 34 | padding: 0; 35 | } 36 | 37 | li { 38 | float: left; 39 | list-style: none; 40 | margin: 0; 41 | padding: 0; 42 | 43 | button { 44 | box-sizing: border-box; 45 | cursor: pointer; 46 | display: block; 47 | font-size: 14px; 48 | line-height: 1.33; 49 | margin: 0; 50 | padding: 15px; 51 | text-decoration: none; 52 | 53 | &:focus { 54 | outline: none; 55 | } 56 | } 57 | 58 | .medium-editor-action-underline { 59 | text-decoration: underline; 60 | } 61 | 62 | .medium-editor-action-pre { 63 | font-family: $font-fixed; 64 | font-size: 12px; 65 | font-weight: 100; 66 | padding: 15px 0; 67 | } 68 | } 69 | } 70 | 71 | .medium-editor-toolbar-active { 72 | visibility: visible; 73 | } 74 | 75 | .medium-editor-sticky-toolbar { 76 | position: fixed; 77 | top: 1px; 78 | } 79 | 80 | .medium-editor-relative-toolbar { 81 | position: relative; 82 | } 83 | 84 | .medium-editor-toolbar-active.medium-editor-stalker-toolbar { 85 | animation: medium-editor-pop-upwards 160ms forwards linear; 86 | } 87 | 88 | .medium-editor-toolbar-actions { 89 | @extend %clearfix; 90 | } 91 | 92 | .medium-editor-action-bold { 93 | font-weight: bolder; 94 | } 95 | 96 | .medium-editor-action-italic { 97 | font-style: italic; 98 | } 99 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/medium_editor.scss: -------------------------------------------------------------------------------- 1 | @import "settings"; 2 | @import "animations/image-loading"; 3 | @import "animations/pop-upwards"; 4 | @import "components/anchor-preview"; 5 | @import "components/file-dragging"; 6 | @import "components/placeholder"; 7 | @import "components/toolbar"; 8 | @import "components/toolbar-form"; 9 | @import "util/clearfix"; 10 | 11 | // contenteditable rules 12 | .medium-editor-element { 13 | word-wrap: break-word; 14 | min-height: 30px; 15 | 16 | img { 17 | max-width: 100%; 18 | } 19 | 20 | sub { 21 | vertical-align: sub; 22 | } 23 | 24 | sup { 25 | vertical-align: super; 26 | } 27 | } 28 | 29 | .medium-editor-hidden { 30 | display: none; 31 | } 32 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/themes/beagle.scss: -------------------------------------------------------------------------------- 1 | // theme settings 2 | $medium-editor-bgcolor: #000; 3 | $medium-editor-button-size: 40px; 4 | $medium-editor-button-active-text-color: #a2d7c7; 5 | $medium-editor-hover-color: $medium-editor-bgcolor; 6 | $medium-editor-link-color: #ccc; 7 | $medium-editor-border-radius: 50px; 8 | $medium-editor-placeholder-color: #f8f5f3; 9 | 10 | // theme rules 11 | .medium-toolbar-arrow-under:after { 12 | border-color: $medium-editor-bgcolor transparent transparent transparent; 13 | top: $medium-editor-button-size; 14 | } 15 | 16 | .medium-toolbar-arrow-over:before { 17 | border-color: transparent transparent $medium-editor-bgcolor transparent; 18 | } 19 | 20 | .medium-editor-toolbar { 21 | background-color: $medium-editor-bgcolor; 22 | border: none; 23 | border-radius: $medium-editor-border-radius; 24 | 25 | li { 26 | button { 27 | background-color: transparent; 28 | border: none; 29 | box-sizing: border-box; 30 | color: $medium-editor-link-color; 31 | height: $medium-editor-button-size; 32 | min-width: $medium-editor-button-size; 33 | padding: 5px 12px; 34 | transition: background-color .2s ease-in, color .2s ease-in; 35 | &:hover { 36 | background-color: $medium-editor-hover-color; 37 | color: $medium-editor-button-active-text-color; 38 | } 39 | } 40 | 41 | .medium-editor-button-first { 42 | border-bottom-left-radius: $medium-editor-border-radius; 43 | border-top-left-radius: $medium-editor-border-radius; 44 | padding-left: 24px; 45 | } 46 | 47 | .medium-editor-button-last { 48 | border-bottom-right-radius: $medium-editor-border-radius; 49 | border-right: none; 50 | border-top-right-radius: $medium-editor-border-radius; 51 | padding-right: 24px 52 | } 53 | 54 | .medium-editor-button-active { 55 | background-color: $medium-editor-hover-color; 56 | color: $medium-editor-button-active-text-color; 57 | } 58 | } 59 | } 60 | 61 | .medium-editor-toolbar-form { 62 | background: $medium-editor-bgcolor; 63 | border-radius: $medium-editor-border-radius; 64 | color: $medium-editor-link-color; 65 | overflow: hidden; 66 | 67 | .medium-editor-toolbar-input { 68 | background: $medium-editor-bgcolor; 69 | box-sizing: border-box; 70 | color: $medium-editor-link-color; 71 | height: $medium-editor-button-size; 72 | padding-left: 16px; 73 | width: 220px; 74 | 75 | &::-webkit-input-placeholder { 76 | color: $medium-editor-placeholder-color; 77 | color: rgba($medium-editor-placeholder-color, .8); 78 | } 79 | &:-moz-placeholder { /* Firefox 18- */ 80 | color: $medium-editor-placeholder-color; 81 | color: rgba($medium-editor-placeholder-color, .8); 82 | } 83 | &::-moz-placeholder { /* Firefox 19+ */ 84 | color: $medium-editor-placeholder-color; 85 | color: rgba($medium-editor-placeholder-color, .8); 86 | } 87 | &:-ms-input-placeholder { 88 | color: $medium-editor-placeholder-color; 89 | color: rgba($medium-editor-placeholder-color, .8); 90 | } 91 | } 92 | 93 | a { 94 | color: $medium-editor-link-color; 95 | transform: translateY(2px); 96 | } 97 | 98 | .medium-editor-toolbar-close { 99 | margin-right: 16px; 100 | } 101 | } 102 | 103 | .medium-editor-toolbar-anchor-preview { 104 | background: $medium-editor-bgcolor; 105 | border-radius: $medium-editor-border-radius; 106 | padding: 5px 12px; 107 | } 108 | 109 | .medium-editor-anchor-preview { 110 | a { 111 | color: $medium-editor-link-color; 112 | text-decoration: none; 113 | } 114 | } 115 | 116 | .medium-editor-toolbar-actions { 117 | li, button { 118 | border-radius: $medium-editor-border-radius; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/themes/bootstrap.scss: -------------------------------------------------------------------------------- 1 | // theme settings 2 | $medium-editor-bgcolor: #428bca; 3 | $medium-editor-border-color: #357ebd; 4 | $medium-editor-button-size: 60px; 5 | $medium-editor-button-active-text-color: #fff; 6 | $medium-editor-hover-color: #3276b1; 7 | $medium-editor-link-color: #fff; 8 | $medium-editor-border-radius: 4px; 9 | $medium-editor-placeholder-color: #fff; 10 | 11 | // theme rules 12 | .medium-toolbar-arrow-under:after { 13 | border-color: $medium-editor-bgcolor transparent transparent transparent; 14 | top: $medium-editor-button-size; 15 | } 16 | 17 | .medium-toolbar-arrow-over:before { 18 | border-color: transparent transparent $medium-editor-bgcolor transparent; 19 | } 20 | 21 | .medium-editor-toolbar { 22 | background-color: $medium-editor-bgcolor; 23 | border: 1px solid $medium-editor-border-color; 24 | border-radius: $medium-editor-border-radius; 25 | 26 | li { 27 | button { 28 | background-color: transparent; 29 | border: none; 30 | border-right: 1px solid $medium-editor-border-color; 31 | box-sizing: border-box; 32 | color: $medium-editor-link-color; 33 | height: $medium-editor-button-size; 34 | min-width: $medium-editor-button-size; 35 | transition: background-color .2s ease-in, color .2s ease-in; 36 | &:hover { 37 | background-color: $medium-editor-hover-color; 38 | color: $medium-editor-button-active-text-color; 39 | } 40 | } 41 | 42 | .medium-editor-button-first { 43 | border-bottom-left-radius: $medium-editor-border-radius; 44 | border-top-left-radius: $medium-editor-border-radius; 45 | } 46 | 47 | .medium-editor-button-last { 48 | border-bottom-right-radius: $medium-editor-border-radius; 49 | border-right: none; 50 | border-top-right-radius: $medium-editor-border-radius; 51 | } 52 | 53 | .medium-editor-button-active { 54 | background-color: $medium-editor-hover-color; 55 | color: $medium-editor-button-active-text-color; 56 | } 57 | } 58 | } 59 | 60 | .medium-editor-toolbar-form { 61 | background: $medium-editor-bgcolor; 62 | border-radius: $medium-editor-border-radius; 63 | color: #fff; 64 | 65 | .medium-editor-toolbar-input { 66 | background: $medium-editor-bgcolor; 67 | color: $medium-editor-link-color; 68 | height: $medium-editor-button-size; 69 | 70 | &::-webkit-input-placeholder { 71 | color: $medium-editor-placeholder-color; 72 | color: rgba($medium-editor-placeholder-color, .8); 73 | } 74 | &:-moz-placeholder { /* Firefox 18- */ 75 | color: $medium-editor-placeholder-color; 76 | color: rgba($medium-editor-placeholder-color, .8); 77 | } 78 | &::-moz-placeholder { /* Firefox 19+ */ 79 | color: $medium-editor-placeholder-color; 80 | color: rgba($medium-editor-placeholder-color, .8); 81 | } 82 | &:-ms-input-placeholder { 83 | color: $medium-editor-placeholder-color; 84 | color: rgba($medium-editor-placeholder-color, .8); 85 | } 86 | } 87 | 88 | a { 89 | color: $medium-editor-link-color; 90 | } 91 | } 92 | 93 | .medium-editor-toolbar-anchor-preview { 94 | background: $medium-editor-bgcolor; 95 | border-radius: $medium-editor-border-radius; 96 | color: $medium-editor-link-color; 97 | } 98 | 99 | .medium-editor-placeholder:after { 100 | color: $medium-editor-border-color; 101 | } 102 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/themes/default.scss: -------------------------------------------------------------------------------- 1 | // theme settings 2 | $medium-editor-bgcolor: #242424; 3 | $medium-editor-button-size: 50px; 4 | $medium-editor-border-radius: 5px; 5 | 6 | // theme rules 7 | .medium-toolbar-arrow-under:after { 8 | border-color: $medium-editor-bgcolor transparent transparent transparent; 9 | top: $medium-editor-button-size; 10 | } 11 | 12 | .medium-toolbar-arrow-over:before { 13 | border-color: transparent transparent $medium-editor-bgcolor transparent; 14 | top: -8px; 15 | } 16 | 17 | .medium-editor-toolbar { 18 | background-color: $medium-editor-bgcolor; 19 | background: linear-gradient(to bottom, $medium-editor-bgcolor, rgba($medium-editor-bgcolor, 0.75)); 20 | border: 1px solid #000; 21 | border-radius: $medium-editor-border-radius; 22 | box-shadow: 0 0 3px #000; 23 | 24 | li { 25 | button { 26 | background-color: $medium-editor-bgcolor; 27 | background: linear-gradient(to bottom, $medium-editor-bgcolor, rgba($medium-editor-bgcolor, 0.89)); 28 | border: 0; 29 | border-right: 1px solid #000; 30 | border-left: 1px solid #333; 31 | border-left: 1px solid rgba(#fff, .1); 32 | box-shadow: 0 2px 2px rgba(0,0,0,0.3); 33 | color: #fff; 34 | height: $medium-editor-button-size; 35 | min-width: $medium-editor-button-size; 36 | transition: background-color .2s ease-in; 37 | 38 | &:hover { 39 | background-color: #000; 40 | color: yellow; 41 | } 42 | } 43 | 44 | .medium-editor-button-first { 45 | border-bottom-left-radius: $medium-editor-border-radius; 46 | border-top-left-radius: $medium-editor-border-radius; 47 | } 48 | 49 | .medium-editor-button-last { 50 | border-bottom-right-radius: $medium-editor-border-radius; 51 | border-top-right-radius: $medium-editor-border-radius; 52 | } 53 | 54 | .medium-editor-button-active { 55 | background-color: #000; 56 | background: linear-gradient(to bottom, $medium-editor-bgcolor, rgba(#000, 0.89)); 57 | color: #fff; 58 | } 59 | } 60 | } 61 | 62 | .medium-editor-toolbar-form { 63 | background: $medium-editor-bgcolor; 64 | border-radius: $medium-editor-border-radius; 65 | color: #999; 66 | 67 | .medium-editor-toolbar-input { 68 | background: $medium-editor-bgcolor; 69 | box-sizing: border-box; 70 | color: #ccc; 71 | height: $medium-editor-button-size; 72 | } 73 | 74 | a { 75 | color: #fff; 76 | } 77 | } 78 | 79 | .medium-editor-toolbar-anchor-preview { 80 | background: $medium-editor-bgcolor; 81 | border-radius: $medium-editor-border-radius; 82 | color: #fff; 83 | } 84 | 85 | .medium-editor-placeholder:after { 86 | color: #b3b3b1; 87 | } 88 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/themes/flat.scss: -------------------------------------------------------------------------------- 1 | // theme settings 2 | $medium-editor-bgcolor: #57ad68; 3 | $medium-editor-border-color: #fff; 4 | $medium-editor-button-size: 60px; 5 | $medium-editor-button-active-text-color: #fff; 6 | $medium-editor-link-color: #fff; 7 | $medium-editor-placeholder-color: #fff; 8 | 9 | // theme rules 10 | .medium-toolbar-arrow-under:after { 11 | top: $medium-editor-button-size; 12 | border-color: $medium-editor-bgcolor transparent transparent transparent; 13 | } 14 | 15 | .medium-toolbar-arrow-over:before { 16 | top: -8px; 17 | border-color: transparent transparent $medium-editor-bgcolor transparent; 18 | } 19 | 20 | .medium-editor-toolbar { 21 | background-color: $medium-editor-bgcolor; 22 | 23 | li { 24 | padding: 0; 25 | 26 | button { 27 | min-width: $medium-editor-button-size; 28 | height: $medium-editor-button-size; 29 | border: none; 30 | border-right: 1px solid lighten($medium-editor-bgcolor, 20); 31 | background-color: transparent; 32 | color: $medium-editor-link-color; 33 | transition: background-color .2s ease-in, color .2s ease-in; 34 | &:hover { 35 | background-color: darken($medium-editor-bgcolor, 20); 36 | color: $medium-editor-button-active-text-color; 37 | } 38 | } 39 | 40 | .medium-editor-button-active { 41 | background-color: darken($medium-editor-bgcolor, 30); 42 | color: $medium-editor-button-active-text-color; 43 | } 44 | 45 | .medium-editor-button-last { 46 | border-right: none; 47 | } 48 | } 49 | } 50 | 51 | .medium-editor-toolbar-form { 52 | .medium-editor-toolbar-input { 53 | height: $medium-editor-button-size; 54 | background: $medium-editor-bgcolor; 55 | color: $medium-editor-link-color; 56 | 57 | &::-webkit-input-placeholder { 58 | color: $medium-editor-placeholder-color; 59 | color: rgba($medium-editor-placeholder-color, .8); 60 | } 61 | 62 | &:-moz-placeholder { /* Firefox 18- */ 63 | color: $medium-editor-placeholder-color; 64 | color: rgba($medium-editor-placeholder-color, .8); 65 | } 66 | 67 | &::-moz-placeholder { /* Firefox 19+ */ 68 | color: $medium-editor-placeholder-color; 69 | color: rgba($medium-editor-placeholder-color, .8); 70 | } 71 | 72 | &:-ms-input-placeholder { 73 | color: $medium-editor-placeholder-color; 74 | color: rgba($medium-editor-placeholder-color, .8); 75 | } 76 | } 77 | 78 | a { 79 | color: $medium-editor-link-color; 80 | } 81 | } 82 | 83 | .medium-editor-toolbar-anchor-preview { 84 | background: $medium-editor-bgcolor; 85 | color: $medium-editor-link-color; 86 | } 87 | 88 | .medium-editor-placeholder:after { 89 | color: lighten($medium-editor-bgcolor, 20); 90 | } 91 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/themes/mani.scss: -------------------------------------------------------------------------------- 1 | // inspired by http://dribbble.com/shots/857472-Toolbar 2 | 3 | // theme settings 4 | $medium-editor-bgcolor: #dee7f0; 5 | $medium-editor-bgcolor-alt: #5c90c7; 6 | $medium-editor-border-color: #cdd6e0; 7 | $medium-editor-button-size: 50px; 8 | $medium-editor-button-hover-text-color: #fff; 9 | $medium-editor-button-active-text-color: #000; 10 | $medium-editor-link-color: #40648a; 11 | $medium-editor-border-radius: 2px; 12 | 13 | // theme rules 14 | .medium-toolbar-arrow-under:after, 15 | .medium-toolbar-arrow-over:before { 16 | display: none; 17 | } 18 | 19 | .medium-editor-toolbar { 20 | border: 1px solid $medium-editor-border-color; 21 | background-color: $medium-editor-bgcolor; 22 | background-color: rgba($medium-editor-bgcolor, .95); 23 | background: linear-gradient(to top, $medium-editor-bgcolor, rgba(#fff, 1)); 24 | border-radius: $medium-editor-border-radius; 25 | box-shadow: 0 2px 6px rgba(#000, .45); 26 | 27 | li { 28 | button { 29 | min-width: $medium-editor-button-size; 30 | height: $medium-editor-button-size; 31 | border: none; 32 | border-right: 1px solid $medium-editor-border-color; 33 | background-color: transparent; 34 | color: $medium-editor-link-color; 35 | transition: background-color .2s ease-in, color .2s ease-in; 36 | &:hover { 37 | background-color: $medium-editor-bgcolor-alt; 38 | background-color: rgba($medium-editor-bgcolor-alt, .45); 39 | color: $medium-editor-button-hover-text-color; 40 | } 41 | } 42 | 43 | .medium-editor-button-first { 44 | border-top-left-radius: $medium-editor-border-radius; 45 | border-bottom-left-radius: $medium-editor-border-radius; 46 | } 47 | 48 | .medium-editor-button-last { 49 | border-top-right-radius: $medium-editor-border-radius; 50 | border-bottom-right-radius: $medium-editor-border-radius; 51 | } 52 | 53 | .medium-editor-button-active { 54 | background-color: $medium-editor-bgcolor-alt; 55 | background-color: rgba($medium-editor-bgcolor-alt, .45); 56 | color: $medium-editor-button-active-text-color; 57 | background: linear-gradient(to bottom, $medium-editor-bgcolor, rgba(#000, .1)); 58 | } 59 | } 60 | } 61 | 62 | .medium-editor-toolbar-form { 63 | background: $medium-editor-bgcolor; 64 | color: #999; 65 | border-radius: $medium-editor-border-radius; 66 | 67 | .medium-editor-toolbar-input { 68 | height: $medium-editor-button-size; 69 | background: $medium-editor-bgcolor; 70 | color: $medium-editor-link-color; 71 | box-sizing: border-box; 72 | } 73 | 74 | a { 75 | color: $medium-editor-link-color; 76 | } 77 | } 78 | 79 | .medium-editor-toolbar-anchor-preview { 80 | background: $medium-editor-bgcolor; 81 | color: $medium-editor-link-color; 82 | border-radius: $medium-editor-border-radius; 83 | } 84 | 85 | .medium-editor-placeholder:after { 86 | color: $medium-editor-border-color; 87 | } 88 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/themes/roman.scss: -------------------------------------------------------------------------------- 1 | // inspired by http://dribbble.com/shots/848100-Toolbar-Psd 2 | 3 | // theme settings 4 | $medium-editor-bgcolor: #fff; 5 | $medium-editor-border-color: #a8a8a8; 6 | $medium-editor-button-size: 50px; 7 | $medium-editor-button-hover-text-color: #fff; 8 | $medium-editor-button-active-text-color: #000; 9 | $medium-editor-link-color: #889aac; 10 | $medium-editor-border-radius: 5px; 11 | 12 | // theme rules 13 | .medium-toolbar-arrow-under:after, 14 | .medium-toolbar-arrow-over:before { 15 | display: none; 16 | } 17 | 18 | .medium-editor-toolbar { 19 | background-color: $medium-editor-bgcolor; 20 | background-color: rgba($medium-editor-bgcolor, .95); 21 | border-radius: $medium-editor-border-radius; 22 | box-shadow: 0 2px 6px rgba(#000, .45); 23 | 24 | li { 25 | button { 26 | min-width: $medium-editor-button-size; 27 | height: $medium-editor-button-size; 28 | border: none; 29 | border-right: 1px solid $medium-editor-border-color; 30 | background-color: transparent; 31 | color: $medium-editor-link-color; 32 | box-shadow: inset 0 0 3px #f8f8e6; 33 | background: linear-gradient(to bottom, $medium-editor-bgcolor, rgba(#000, .2)); 34 | text-shadow: 1px 4px 6px #def, 0 0 0 #000, 1px 4px 6px #def; 35 | transition: background-color .2s ease-in; 36 | &:hover { 37 | background-color: #fff; 38 | color: $medium-editor-button-hover-text-color; 39 | color: rgba(#000, .8); 40 | } 41 | } 42 | 43 | .medium-editor-button-first { 44 | border-top-left-radius: $medium-editor-border-radius; 45 | border-bottom-left-radius: $medium-editor-border-radius; 46 | } 47 | 48 | .medium-editor-button-last { 49 | border-top-right-radius: $medium-editor-border-radius; 50 | border-bottom-right-radius: $medium-editor-border-radius; 51 | } 52 | 53 | .medium-editor-button-active { 54 | background-color: #ccc; 55 | color: $medium-editor-button-active-text-color; 56 | color: rgba(#000, .8); 57 | background: linear-gradient(to top, $medium-editor-bgcolor, rgba(#000, .1)); 58 | } 59 | } 60 | } 61 | 62 | .medium-editor-toolbar-form { 63 | background: $medium-editor-bgcolor; 64 | color: #999; 65 | border-radius: $medium-editor-border-radius; 66 | 67 | .medium-editor-toolbar-input { 68 | margin: 0; 69 | height: $medium-editor-button-size; 70 | background: $medium-editor-bgcolor; 71 | color: $medium-editor-border-color; 72 | } 73 | 74 | a { 75 | color: $medium-editor-link-color; 76 | } 77 | } 78 | 79 | .medium-editor-toolbar-anchor-preview { 80 | background: $medium-editor-bgcolor; 81 | color: $medium-editor-link-color; 82 | border-radius: $medium-editor-border-radius; 83 | } 84 | 85 | .medium-editor-placeholder:after { 86 | color: $medium-editor-border-color; 87 | } 88 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/themes/tim.scss: -------------------------------------------------------------------------------- 1 | // theme settings 2 | $medium-editor-bgcolor: #2f1e07; 3 | $medium-editor-border-color: lighten($medium-editor-bgcolor, 10); 4 | $medium-editor-button-size: 60px; 5 | $medium-editor-button-active-text-color: #ffedd5; 6 | $medium-editor-hover-color: darken($medium-editor-bgcolor, 10); 7 | $medium-editor-link-color: #ffedd5; 8 | $medium-editor-border-radius: 6px; 9 | $medium-editor-placeholder-color: #ffedd5; 10 | 11 | // theme rules 12 | .medium-toolbar-arrow-under:after { 13 | border-color: $medium-editor-bgcolor transparent transparent transparent; 14 | top: $medium-editor-button-size; 15 | } 16 | 17 | .medium-toolbar-arrow-over:before { 18 | border-color: transparent transparent $medium-editor-bgcolor transparent; 19 | } 20 | 21 | .medium-editor-toolbar { 22 | background-color: $medium-editor-bgcolor; 23 | border: 1px solid $medium-editor-border-color; 24 | border-radius: $medium-editor-border-radius; 25 | 26 | li { 27 | button { 28 | background-color: transparent; 29 | border: none; 30 | border-right: 1px solid $medium-editor-border-color; 31 | box-sizing: border-box; 32 | color: $medium-editor-link-color; 33 | height: $medium-editor-button-size; 34 | min-width: $medium-editor-button-size; 35 | transition: background-color .2s ease-in, color .2s ease-in; 36 | &:hover { 37 | background-color: $medium-editor-hover-color; 38 | color: $medium-editor-button-active-text-color; 39 | } 40 | } 41 | 42 | .medium-editor-button-first { 43 | border-bottom-left-radius: $medium-editor-border-radius; 44 | border-top-left-radius: $medium-editor-border-radius; 45 | } 46 | 47 | .medium-editor-button-last { 48 | border-bottom-right-radius: $medium-editor-border-radius; 49 | border-right: none; 50 | border-top-right-radius: $medium-editor-border-radius; 51 | } 52 | 53 | .medium-editor-button-active { 54 | background-color: $medium-editor-hover-color; 55 | color: $medium-editor-button-active-text-color; 56 | } 57 | } 58 | } 59 | 60 | .medium-editor-toolbar-form { 61 | background: $medium-editor-bgcolor; 62 | border-radius: $medium-editor-border-radius; 63 | color: #ffedd5; 64 | 65 | .medium-editor-toolbar-input { 66 | background: $medium-editor-bgcolor; 67 | color: $medium-editor-link-color; 68 | height: $medium-editor-button-size; 69 | 70 | &::-webkit-input-placeholder { 71 | color: $medium-editor-placeholder-color; 72 | color: rgba($medium-editor-placeholder-color, .8); 73 | } 74 | &:-moz-placeholder { /* Firefox 18- */ 75 | color: $medium-editor-placeholder-color; 76 | color: rgba($medium-editor-placeholder-color, .8); 77 | } 78 | &::-moz-placeholder { /* Firefox 19+ */ 79 | color: $medium-editor-placeholder-color; 80 | color: rgba($medium-editor-placeholder-color, .8); 81 | } 82 | &:-ms-input-placeholder { 83 | color: $medium-editor-placeholder-color; 84 | color: rgba($medium-editor-placeholder-color, .8); 85 | } 86 | } 87 | 88 | a { 89 | color: $medium-editor-link-color; 90 | } 91 | } 92 | 93 | .medium-editor-toolbar-anchor-preview { 94 | background: $medium-editor-bgcolor; 95 | border-radius: $medium-editor-border-radius; 96 | color: $medium-editor-link-color; 97 | } 98 | 99 | .medium-editor-placeholder:after { 100 | color: $medium-editor-border-color; 101 | } 102 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/medium_editor/util/_clearfix.scss: -------------------------------------------------------------------------------- 1 | %clearfix { 2 | &:after { 3 | clear: both; 4 | content: ""; 5 | display: table; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /bin/fasterer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'fasterer' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("fasterer", "fasterer") 30 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails gems 3 | # installed from the root of your application. 4 | 5 | ENV['RAILS_ENV'] ||= 'test' 6 | 7 | ENGINE_ROOT = File.expand_path('..', __dir__) 8 | ENGINE_PATH = File.expand_path('../lib/activeadmin_medium_editor', __dir__) 9 | APP_PATH = File.expand_path('../spec/dummy/config/application', __dir__) 10 | 11 | # Set up gems listed in the Gemfile. 12 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 13 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 14 | 15 | require 'rails/all' 16 | require 'rails/engine/commands' 17 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rake' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rake", "rake") 30 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rspec' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rspec-core", "rspec") 30 | -------------------------------------------------------------------------------- /bin/rubocop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rubocop' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rubocop", "rubocop") 30 | -------------------------------------------------------------------------------- /extra/.bashrc: -------------------------------------------------------------------------------- 1 | alias ls='ls --color' 2 | alias ll='ls -l' 3 | alias la='ls -la' 4 | -------------------------------------------------------------------------------- /extra/.env: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=activeadmin_medium_editor 2 | 3 | BUNDLER_VERSION=2.5.23 4 | SERVER_PORT=4000 5 | 6 | UID=1000 7 | GID=1000 8 | -------------------------------------------------------------------------------- /extra/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG RUBY_IMAGE=ruby:3 2 | FROM ${RUBY_IMAGE} 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | ENV DEVEL=1 6 | ENV LANG=C.UTF-8 7 | 8 | RUN apt-get update -qq 9 | RUN apt-get install -yqq --no-install-recommends build-essential chromium less libyaml-dev nano netcat-traditional pkg-config 10 | 11 | ARG BUNDLER_VERSION 12 | RUN gem install bundler -v ${BUNDLER_VERSION} 13 | RUN echo 'gem: --no-document' > /etc/gemrc 14 | 15 | ARG UID 16 | RUN useradd -u $UID --shell /bin/bash app 17 | 18 | RUN mkdir -p /home/app && chown -R app:app /home/app 19 | 20 | ARG RAILS_VERSION 21 | ENV RAILS_VERSION=$RAILS_VERSION 22 | 23 | ARG ACTIVEADMIN_VERSION 24 | ENV ACTIVEADMIN_VERSION=$ACTIVEADMIN_VERSION 25 | 26 | WORKDIR /app 27 | COPY . /app 28 | RUN bundle install 29 | RUN chown -R app:app /usr/local/bundle 30 | 31 | RUN ln -s /app/extra/.bashrc /home/app/.bashrc 32 | -------------------------------------------------------------------------------- /extra/Dockerfile.dockerignore: -------------------------------------------------------------------------------- 1 | # Ignore everything but the required files for bundle install 2 | /**/* 3 | 4 | !/*.gemspec 5 | !/Gemfile 6 | !/lib 7 | -------------------------------------------------------------------------------- /extra/dev_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export DEVEL=1 4 | 5 | export RAILS_VERSION=7.2.2.1 6 | export ACTIVEADMIN_VERSION=3.3.0 7 | -------------------------------------------------------------------------------- /extra/development.md: -------------------------------------------------------------------------------- 1 | ## Development 2 | 3 | ### Dev setup 4 | 5 | There are 2 ways to interact with this project: 6 | 7 | 1) Using Docker: 8 | 9 | ```sh 10 | make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN) 11 | make specs # run the tests (after up) 12 | make lint # run the linters (after up) 13 | make server # run the server (after up) 14 | make shell # open a shell (after up) 15 | make down # cleanup (after up) 16 | 17 | # Example using specific versions: 18 | RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up 19 | ``` 20 | 21 | 2) With a local setup: 22 | 23 | ```sh 24 | # Dev setup (set the required envs): 25 | source extra/dev_setup.sh 26 | # Install dependencies: 27 | bundle update 28 | # Run server (or any command): 29 | bin/rails s 30 | # To try different versions of Rails/ActiveAdmin edit extra/dev_setup.sh 31 | ``` 32 | -------------------------------------------------------------------------------- /extra/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | app: 3 | build: 4 | context: .. 5 | dockerfile: extra/Dockerfile 6 | args: 7 | BUNDLER_VERSION: ${BUNDLER_VERSION} 8 | RUBY_IMAGE: ruby:${RUBY:-3.4}-slim 9 | RAILS_VERSION: ${RAILS:-} 10 | ACTIVEADMIN_VERSION: ${ACTIVEADMIN:-} 11 | UID: ${UID} 12 | user: ${UID}:${GID} 13 | ports: 14 | - ${SERVER_PORT}:${SERVER_PORT} 15 | working_dir: /app 16 | volumes: 17 | - ..:/app 18 | stdin_open: true 19 | tty: true 20 | -------------------------------------------------------------------------------- /extra/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/extra/screenshot.png -------------------------------------------------------------------------------- /lib/activeadmin/medium_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'activeadmin/medium_editor/engine' 4 | -------------------------------------------------------------------------------- /lib/activeadmin/medium_editor/engine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_admin' 4 | 5 | module ActiveAdmin 6 | module MediumEditor 7 | class Engine < ::Rails::Engine 8 | engine_name 'activeadmin_medium_editor' 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/activeadmin/medium_editor/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActiveAdmin 4 | module MediumEditor 5 | VERSION = '1.0.1' 6 | MEDIUM_VERSION = '5.23.3' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/activeadmin_medium_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'activeadmin/medium_editor' 4 | 5 | require 'formtastic/inputs/medium_editor_input' 6 | -------------------------------------------------------------------------------- /lib/formtastic/inputs/medium_editor_input.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Formtastic 4 | module Inputs 5 | class MediumEditorInput < Formtastic::Inputs::TextInput 6 | def input_html_options 7 | super.merge('data-aa-medium-editor': '1') 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/dummy/.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.7.1 2 | -------------------------------------------------------------------------------- /spec/dummy/.tool-versions: -------------------------------------------------------------------------------- 1 | ruby 2.6.6 2 | -------------------------------------------------------------------------------- /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_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/authors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveAdmin.register Author do 4 | permit_params :name, 5 | :email, 6 | :age, 7 | :avatar, 8 | profile_attributes: %i[id description _destroy], 9 | posts_attributes: %i[id title description] 10 | 11 | index do 12 | selectable_column 13 | id_column 14 | column :name 15 | column :email 16 | column :created_at 17 | actions 18 | end 19 | 20 | filter :name 21 | filter :created_at 22 | 23 | show do 24 | attributes_table do 25 | row :name 26 | row :email 27 | row :age 28 | row :avatar do |record| 29 | image_tag url_for(record.avatar), style: 'max-width:800px;max-height:500px' if record.avatar.attached? 30 | end 31 | row :created_at 32 | row :updated_at 33 | row :profile 34 | row :posts 35 | end 36 | active_admin_comments 37 | end 38 | 39 | form do |f| 40 | f.inputs do 41 | f.input :name 42 | f.input :email 43 | f.input :age 44 | f.input :avatar, 45 | as: :file, 46 | hint: (object.avatar.attached? ? "Current: #{object.avatar.filename}" : nil) 47 | end 48 | f.has_many :profile, allow_destroy: true do |ff| 49 | ff.input :description 50 | end 51 | f.has_many :posts do |fp| 52 | fp.input :title 53 | fp.input :description, as: :medium_editor 54 | end 55 | f.actions 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/dashboard.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | menu priority: 1, label: proc { I18n.t("active_admin.dashboard") } 3 | 4 | content title: proc { I18n.t("active_admin.dashboard") } do 5 | div class: "blank_slate_container", id: "dashboard_default_message" do 6 | span class: "blank_slate" do 7 | span I18n.t("active_admin.dashboard_welcome.welcome") 8 | small I18n.t("active_admin.dashboard_welcome.call_to_action") 9 | end 10 | end 11 | 12 | # Here is an example of a simple dashboard with columns and panels. 13 | # 14 | # columns do 15 | # column do 16 | # panel "Recent Posts" do 17 | # ul do 18 | # Post.recent(5).map do |post| 19 | # li link_to(post.title, admin_post_path(post)) 20 | # end 21 | # end 22 | # end 23 | # end 24 | 25 | # column do 26 | # panel "Info" do 27 | # para "Welcome to ActiveAdmin." 28 | # end 29 | # end 30 | # end 31 | end # content 32 | end 33 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveAdmin.register Post do 4 | permit_params :author_id, :title, :description, :category, :dt, :position, :published, tag_ids: [] 5 | 6 | index do 7 | selectable_column 8 | id_column 9 | column :title 10 | column :author 11 | column :published 12 | column :created_at 13 | actions 14 | end 15 | 16 | show do 17 | attributes_table do 18 | row :author 19 | row :title 20 | row :description 21 | row :category 22 | row :dt 23 | row :position 24 | row :published 25 | row :tags 26 | row :created_at 27 | row :updated_at 28 | end 29 | active_admin_comments 30 | end 31 | 32 | form do |f| 33 | toolbar = { buttons: %w[bold italic underline justifyCenter indent html] } 34 | f.inputs 'Post' do 35 | f.input :author 36 | f.input :title 37 | f.input :description, as: :medium_editor, input_html: { data: { options: { toolbar: toolbar } } } 38 | f.input :category 39 | f.input :dt 40 | f.input :position 41 | f.input :published 42 | end 43 | 44 | f.inputs 'Tags' do 45 | f.input :tags 46 | end 47 | 48 | f.actions 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/tags.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveAdmin.register Tag do 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | // OFF link active_storage_db_manifest.js 4 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/active_admin.js: -------------------------------------------------------------------------------- 1 | //= require active_admin/base 2 | 3 | //= require activeadmin/medium_editor/medium_editor 4 | //= require activeadmin/medium_editor_input 5 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/active_admin.scss: -------------------------------------------------------------------------------- 1 | @import 'active_admin/mixins'; 2 | @import 'active_admin/base'; 3 | 4 | @import 'activeadmin/medium_editor/medium_editor'; 5 | @import 'activeadmin/medium_editor_input'; 6 | @import 'activeadmin/medium_editor/themes/default'; // or another theme 7 | -------------------------------------------------------------------------------- /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 any plugin's vendor/assets/stylesheets directory 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 other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /spec/dummy/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/javascript/packs/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 any plugin's vendor/assets/javascripts directory 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. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require rails-ujs 14 | //= require activestorage 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /spec/dummy/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /spec/dummy/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationRecord < ActiveRecord::Base 4 | self.abstract_class = true 5 | 6 | scope :published, -> {} 7 | end 8 | -------------------------------------------------------------------------------- /spec/dummy/app/models/author.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Author < ApplicationRecord 4 | has_many :posts 5 | has_many :published_posts, -> { published }, class_name: 'Post' 6 | has_many :recent_posts, -> { recents }, class_name: 'Post' 7 | 8 | has_many :tags, through: :posts 9 | 10 | has_one :profile, inverse_of: :author, dependent: :destroy 11 | 12 | has_one_attached :avatar 13 | 14 | accepts_nested_attributes_for :profile, allow_destroy: true 15 | accepts_nested_attributes_for :posts, allow_destroy: true 16 | 17 | validates :email, format: { with: /\A[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\z/i, message: 'Invalid email' } 18 | 19 | validate -> { 20 | errors.add( :base, 'Invalid age' ) if !age || age.to_i % 3 == 1 21 | } 22 | 23 | def to_s 24 | "#{name} (#{age})" 25 | end 26 | 27 | class << self 28 | def ransackable_attributes(_auth_object = nil) 29 | %w[age created_at email id name updated_at] 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/models/post.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Post < ApplicationRecord 4 | belongs_to :author, inverse_of: :posts, autosave: true 5 | 6 | has_one :author_profile, through: :author, source: :profile 7 | 8 | has_many :post_tags, inverse_of: :post, dependent: :destroy 9 | has_many :tags, through: :post_tags 10 | 11 | has_many_attached :images 12 | 13 | accepts_nested_attributes_for :post_tags, allow_destroy: true 14 | 15 | validates :title, allow_blank: false, presence: true 16 | 17 | scope :published, -> { where(published: true) } 18 | scope :recents, -> { where('created_at > ?', Date.today - 8.month) } 19 | 20 | def short_title 21 | title.truncate 10 22 | end 23 | 24 | def upper_title 25 | title.upcase 26 | end 27 | 28 | class << self 29 | def ransackable_associations(_auth_object = nil) 30 | %w[author author_profile post_tags tags images_attachments images_blobs] 31 | end 32 | 33 | def ransackable_attributes(_auth_object = nil) 34 | %w[author_id category created_at description dt id position published title summary updated_at] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/dummy/app/models/post_tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PostTag < ApplicationRecord 4 | belongs_to :post, inverse_of: :post_tags 5 | belongs_to :tag, inverse_of: :post_tags 6 | 7 | validates :post, presence: true 8 | validates :tag, presence: true 9 | 10 | class << self 11 | def ransackable_attributes(auth_object = nil) 12 | %w[created_at id post_id tag_id updated_at] 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/dummy/app/models/profile.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Profile < ApplicationRecord 4 | belongs_to :author, inverse_of: :profile, touch: true 5 | 6 | def to_s 7 | description 8 | end 9 | 10 | class << self 11 | def ransackable_associations(_auth_object = nil) 12 | %w[author] 13 | end 14 | 15 | def ransackable_attributes(_auth_object = nil) 16 | %w[author_id created_at description id updated_at] 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/dummy/app/models/tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Tag < ApplicationRecord 4 | has_many :post_tags, inverse_of: :tag, dependent: :destroy 5 | has_many :posts, through: :post_tags 6 | 7 | class << self 8 | def ransackable_associations(auth_object = nil) 9 | %w[post_tags posts] 10 | end 11 | 12 | def ransackable_attributes(auth_object = nil) 13 | %w[created_at id id_value name updated_at] 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= csrf_meta_tags %> 6 | <%= csp_meta_tag %> 7 | 8 | <%= stylesheet_link_tag 'application', media: 'all' %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /spec/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 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/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path('..', __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to setup or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at anytime and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?('config/database.yml') 22 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! 'bin/rails db:prepare' 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! 'bin/rails log:clear tmp:clear' 30 | 31 | puts "\n== Restarting application server ==" 32 | system! 'bin/rails restart' 33 | end 34 | -------------------------------------------------------------------------------- /spec/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /spec/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | 7 | module Dummy 8 | class Application < Rails::Application 9 | config.load_defaults Rails::VERSION::STRING.to_f 10 | 11 | config.active_support.deprecation = :raise 12 | 13 | if Gem::Version.new(Rails.version) < Gem::Version.new('7.1') 14 | config.active_record.legacy_connection_handling = false 15 | end 16 | 17 | if Gem::Version.new(Rails.version) > Gem::Version.new('7.0') 18 | config.before_configuration do 19 | ActiveSupport::Cache.format_version = 7.0 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) 6 | -------------------------------------------------------------------------------- /spec/dummy/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: dummy_production 11 | -------------------------------------------------------------------------------- /spec/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: sqlite3 3 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 4 | timeout: 5000 5 | 6 | test: 7 | <<: *default 8 | database: db/test.sqlite3 9 | -------------------------------------------------------------------------------- /spec/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 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. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | # Run rails dev:cache to toggle caching. 17 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 18 | config.action_controller.perform_caching = true 19 | config.action_controller.enable_fragment_cache_logging = true 20 | 21 | config.cache_store = :memory_store 22 | config.public_file_server.headers = { 23 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 24 | } 25 | else 26 | config.action_controller.perform_caching = false 27 | 28 | config.cache_store = :null_store 29 | end 30 | 31 | # Store uploaded files on the local file system (see config/storage.yml for options). 32 | config.active_storage.service = :local 33 | 34 | # # Don't care if the mailer can't send. 35 | # config.action_mailer.raise_delivery_errors = false 36 | 37 | # config.action_mailer.perform_caching = false 38 | 39 | # Print deprecation notices to the Rails logger. 40 | config.active_support.deprecation = :log 41 | 42 | # Raise an error on page load if there are pending migrations. 43 | config.active_record.migration_error = :page_load 44 | 45 | # Highlight code that triggered database queries in logs. 46 | config.active_record.verbose_query_logs = true 47 | 48 | # Debug mode disables concatenation and preprocessing of assets. 49 | # This option may cause significant delays in view rendering with a large 50 | # number of complex assets. 51 | config.assets.debug = true 52 | 53 | # Suppress logger output for asset requests. 54 | config.assets.quiet = true 55 | 56 | # Raises error for missing translations. 57 | # config.action_view.raise_on_missing_translations = true 58 | 59 | # Use an evented file watcher to asynchronously detect changes in source code, 60 | # routes, locales, etc. This feature depends on the listen gem. 61 | # config.file_watcher = ActiveSupport::EventedFileUpdateChecker 62 | end 63 | -------------------------------------------------------------------------------- /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 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 19 | # config.require_master_key = true 20 | 21 | # Disable serving static files from the `/public` folder by default since 22 | # Apache or NGINX already handles this. 23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 24 | 25 | # Compress CSS using a preprocessor. 26 | # config.assets.css_compressor = :sass 27 | 28 | # Do not fallback to assets pipeline if a precompiled asset is missed. 29 | config.assets.compile = false 30 | 31 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 32 | # config.action_controller.asset_host = 'http://assets.example.com' 33 | 34 | # Specifies the header that your server uses for sending files. 35 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 36 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 37 | 38 | # Store uploaded files on the local file system (see config/storage.yml for options). 39 | config.active_storage.service = :local 40 | 41 | # Mount Action Cable outside main process or domain. 42 | # config.action_cable.mount_path = nil 43 | # config.action_cable.url = 'wss://example.com/cable' 44 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 45 | 46 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 47 | # config.force_ssl = true 48 | 49 | # Use the lowest log level to ensure availability of diagnostic information 50 | # when problems arise. 51 | config.log_level = :debug 52 | 53 | # Prepend all log lines with the following tags. 54 | config.log_tags = [ :request_id ] 55 | 56 | # Use a different cache store in production. 57 | # config.cache_store = :mem_cache_store 58 | 59 | # Use a real queuing backend for Active Job (and separate queues per environment). 60 | # config.active_job.queue_adapter = :resque 61 | # config.active_job.queue_name_prefix = "dummy_production" 62 | 63 | # config.action_mailer.perform_caching = false 64 | 65 | # Ignore bad email addresses and do not raise email delivery errors. 66 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 67 | # config.action_mailer.raise_delivery_errors = false 68 | 69 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 70 | # the I18n.default_locale when a translation cannot be found). 71 | config.i18n.fallbacks = true 72 | 73 | # Send deprecation notices to registered listeners. 74 | config.active_support.deprecation = :notify 75 | 76 | # Use default logging formatter so that PID and timestamp are not suppressed. 77 | config.log_formatter = ::Logger::Formatter.new 78 | 79 | # Use a different logger for distributed setups. 80 | # require 'syslog/logger' 81 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 82 | 83 | if ENV["RAILS_LOG_TO_STDOUT"].present? 84 | logger = ActiveSupport::Logger.new(STDOUT) 85 | logger.formatter = config.log_formatter 86 | config.logger = ActiveSupport::TaggedLogging.new(logger) 87 | end 88 | 89 | # Do not dump schema after migrations. 90 | config.active_record.dump_schema_after_migration = false 91 | 92 | # Inserts middleware to perform automatic connection switching. 93 | # The `database_selector` hash is used to pass options to the DatabaseSelector 94 | # middleware. The `delay` is used to determine how long to wait after a write 95 | # to send a subsequent read to the primary. 96 | # 97 | # The `database_resolver` class is used by the middleware to determine which 98 | # database is appropriate to use based on the time delay. 99 | # 100 | # The `database_resolver_context` class is used by the middleware to set 101 | # timestamps for the last write to the primary. The resolver uses the context 102 | # class timestamps to determine how long to wait before reading from the 103 | # replica. 104 | # 105 | # By default Rails will store a last write timestamp in the session. The 106 | # DatabaseSelector middleware is designed as such you can define your own 107 | # strategy for connection switching and pass that into the middleware through 108 | # these configuration options. 109 | # config.active_record.database_selector = { delay: 2.seconds } 110 | # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver 111 | # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session 112 | end 113 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # The test environment is used exclusively to run your application's 2 | # test suite. You never need to work with it otherwise. Remember that 3 | # your test database is "scratch space" for the test suite and is wiped 4 | # and recreated between test runs. Don't rely on the data there! 5 | 6 | Rails.application.configure do 7 | # Settings specified here will take precedence over those in config/application.rb. 8 | 9 | config.cache_classes = false 10 | config.action_view.cache_template_loading = true 11 | 12 | # Do not eager load code on boot. This avoids loading your whole application 13 | # just for the purpose of running a single test. If you are using a tool that 14 | # preloads Rails for running tests, you may have to set it to true. 15 | config.eager_load = false 16 | 17 | # Configure public file server for tests with Cache-Control for performance. 18 | config.public_file_server.enabled = true 19 | config.public_file_server.headers = { 20 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 21 | } 22 | 23 | # Show full error reports and disable caching. 24 | config.consider_all_requests_local = true 25 | config.action_controller.perform_caching = false 26 | config.cache_store = :null_store 27 | 28 | # Raise exceptions instead of rendering exception templates. 29 | config.action_dispatch.show_exceptions = false 30 | 31 | # Disable request forgery protection in test environment. 32 | config.action_controller.allow_forgery_protection = false 33 | 34 | # Store uploaded files on the local file system in a temporary directory. 35 | config.active_storage.service = :test 36 | 37 | # config.action_mailer.perform_caching = false 38 | 39 | # Tell Action Mailer not to deliver emails to the real world. 40 | # The :test delivery method accumulates sent emails in the 41 | # ActionMailer::Base.deliveries array. 42 | # config.action_mailer.delivery_method = :test 43 | 44 | # Print deprecation notices to the stderr. 45 | config.active_support.deprecation = :stderr 46 | 47 | # Raises error for missing translations. 48 | # config.action_view.raise_on_missing_translations = true 49 | end 50 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/active_admin.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.setup do |config| 2 | # == Site Title 3 | # 4 | # Set the title that is displayed on the main layout 5 | # for each of the active admin pages. 6 | # 7 | config.site_title = "Dummy" 8 | 9 | # Set the link url for the title. For example, to take 10 | # users to your main site. Defaults to no link. 11 | # 12 | # config.site_title_link = "/" 13 | 14 | # Set an optional image to be displayed for the header 15 | # instead of a string (overrides :site_title) 16 | # 17 | # Note: Aim for an image that's 21px high so it fits in the header. 18 | # 19 | # config.site_title_image = "logo.png" 20 | 21 | # == Default Namespace 22 | # 23 | # Set the default namespace each administration resource 24 | # will be added to. 25 | # 26 | # eg: 27 | # config.default_namespace = :hello_world 28 | # 29 | # This will create resources in the HelloWorld module and 30 | # will namespace routes to /hello_world/* 31 | # 32 | # To set no namespace by default, use: 33 | # config.default_namespace = false 34 | # 35 | # Default: 36 | # config.default_namespace = :admin 37 | # 38 | # You can customize the settings for each namespace by using 39 | # a namespace block. For example, to change the site title 40 | # within a namespace: 41 | # 42 | # config.namespace :admin do |admin| 43 | # admin.site_title = "Custom Admin Title" 44 | # end 45 | # 46 | # This will ONLY change the title for the admin section. Other 47 | # namespaces will continue to use the main "site_title" configuration. 48 | 49 | # == User Authentication 50 | # 51 | # Active Admin will automatically call an authentication 52 | # method in a before filter of all controller actions to 53 | # ensure that there is a currently logged in admin user. 54 | # 55 | # This setting changes the method which Active Admin calls 56 | # within the application controller. 57 | # config.authentication_method = :authenticate_admin_user! 58 | 59 | # == User Authorization 60 | # 61 | # Active Admin will automatically call an authorization 62 | # method in a before filter of all controller actions to 63 | # ensure that there is a user with proper rights. You can use 64 | # CanCanAdapter or make your own. Please refer to documentation. 65 | # config.authorization_adapter = ActiveAdmin::CanCanAdapter 66 | 67 | # In case you prefer Pundit over other solutions you can here pass 68 | # the name of default policy class. This policy will be used in every 69 | # case when Pundit is unable to find suitable policy. 70 | # config.pundit_default_policy = "MyDefaultPunditPolicy" 71 | 72 | # If you wish to maintain a separate set of Pundit policies for admin 73 | # resources, you may set a namespace here that Pundit will search 74 | # within when looking for a resource's policy. 75 | # config.pundit_policy_namespace = :admin 76 | 77 | # You can customize your CanCan Ability class name here. 78 | # config.cancan_ability_class = "Ability" 79 | 80 | # You can specify a method to be called on unauthorized access. 81 | # This is necessary in order to prevent a redirect loop which happens 82 | # because, by default, user gets redirected to Dashboard. If user 83 | # doesn't have access to Dashboard, he'll end up in a redirect loop. 84 | # Method provided here should be defined in application_controller.rb. 85 | # config.on_unauthorized_access = :access_denied 86 | 87 | # == Current User 88 | # 89 | # Active Admin will associate actions with the current 90 | # user performing them. 91 | # 92 | # This setting changes the method which Active Admin calls 93 | # (within the application controller) to return the currently logged in user. 94 | # config.current_user_method = :current_admin_user 95 | 96 | # == Logging Out 97 | # 98 | # Active Admin displays a logout link on each screen. These 99 | # settings configure the location and method used for the link. 100 | # 101 | # This setting changes the path where the link points to. If it's 102 | # a string, the strings is used as the path. If it's a Symbol, we 103 | # will call the method to return the path. 104 | # 105 | # Default: 106 | config.logout_link_path = :destroy_admin_user_session_path 107 | 108 | # This setting changes the http method used when rendering the 109 | # link. For example :get, :delete, :put, etc.. 110 | # 111 | # Default: 112 | # config.logout_link_method = :get 113 | 114 | # == Root 115 | # 116 | # Set the action to call for the root path. You can set different 117 | # roots for each namespace. 118 | # 119 | # Default: 120 | # config.root_to = 'dashboard#index' 121 | 122 | # == Admin Comments 123 | # 124 | # This allows your users to comment on any resource registered with Active Admin. 125 | # 126 | # You can completely disable comments: 127 | # config.comments = false 128 | # 129 | # You can change the name under which comments are registered: 130 | # config.comments_registration_name = 'AdminComment' 131 | # 132 | # You can change the order for the comments and you can change the column 133 | # to be used for ordering: 134 | # config.comments_order = 'created_at ASC' 135 | # 136 | # You can disable the menu item for the comments index page: 137 | # config.comments_menu = false 138 | # 139 | # You can customize the comment menu: 140 | # config.comments_menu = { parent: 'Admin', priority: 1 } 141 | 142 | # == Batch Actions 143 | # 144 | # Enable and disable Batch Actions 145 | # 146 | config.batch_actions = true 147 | 148 | # == Controller Filters 149 | # 150 | # You can add before, after and around filters to all of your 151 | # Active Admin resources and pages from here. 152 | # 153 | # config.before_action :do_something_awesome 154 | 155 | # == Attribute Filters 156 | # 157 | # You can exclude possibly sensitive model attributes from being displayed, 158 | # added to forms, or exported by default by ActiveAdmin 159 | # 160 | config.filter_attributes = [:encrypted_password, :password, :password_confirmation] 161 | 162 | # == Localize Date/Time Format 163 | # 164 | # Set the localize format to display dates and times. 165 | # To understand how to localize your app with I18n, read more at 166 | # https://guides.rubyonrails.org/i18n.html 167 | # 168 | # You can run `bin/rails runner 'puts I18n.t("date.formats")'` to see the 169 | # available formats in your application. 170 | # 171 | config.localize_format = :long 172 | 173 | # == Setting a Favicon 174 | # 175 | # config.favicon = 'favicon.ico' 176 | 177 | # == Meta Tags 178 | # 179 | # Add additional meta tags to the head element of active admin pages. 180 | # 181 | # Add tags to all pages logged in users see: 182 | # config.meta_tags = { author: 'My Company' } 183 | 184 | # By default, sign up/sign in/recover password pages are excluded 185 | # from showing up in search engine results by adding a robots meta 186 | # tag. You can reset the hash of meta tags included in logged out 187 | # pages: 188 | # config.meta_tags_for_logged_out_pages = {} 189 | 190 | # == Removing Breadcrumbs 191 | # 192 | # Breadcrumbs are enabled by default. You can customize them for individual 193 | # resources or you can disable them globally from here. 194 | # 195 | # config.breadcrumb = false 196 | 197 | # == Create Another Checkbox 198 | # 199 | # Create another checkbox is disabled by default. You can customize it for individual 200 | # resources or you can enable them globally from here. 201 | # 202 | # config.create_another = true 203 | 204 | # == Register Stylesheets & Javascripts 205 | # 206 | # We recommend using the built in Active Admin layout and loading 207 | # up your own stylesheets / javascripts to customize the look 208 | # and feel. 209 | # 210 | # To load a stylesheet: 211 | # config.register_stylesheet 'my_stylesheet.css' 212 | # 213 | # You can provide an options hash for more control, which is passed along to stylesheet_link_tag(): 214 | # config.register_stylesheet 'my_print_stylesheet.css', media: :print 215 | # 216 | # To load a javascript file: 217 | # config.register_javascript 'my_javascript.js' 218 | 219 | # == CSV options 220 | # 221 | # Set the CSV builder separator 222 | # config.csv_options = { col_sep: ';' } 223 | # 224 | # Force the use of quotes 225 | # config.csv_options = { force_quotes: true } 226 | 227 | # == Menu System 228 | # 229 | # You can add a navigation menu to be used in your application, or configure a provided menu 230 | # 231 | # To change the default utility navigation to show a link to your website & a logout btn 232 | # 233 | # config.namespace :admin do |admin| 234 | # admin.build_menu :utility_navigation do |menu| 235 | # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank } 236 | # admin.add_logout_button_to_menu menu 237 | # end 238 | # end 239 | # 240 | # If you wanted to add a static menu item to the default menu provided: 241 | # 242 | # config.namespace :admin do |admin| 243 | # admin.build_menu :default do |menu| 244 | # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank } 245 | # end 246 | # end 247 | 248 | # == Download Links 249 | # 250 | # You can disable download links on resource listing pages, 251 | # or customize the formats shown per namespace/globally 252 | # 253 | # To disable/customize for the :admin namespace: 254 | # 255 | # config.namespace :admin do |admin| 256 | # 257 | # # Disable the links entirely 258 | # admin.download_links = false 259 | # 260 | # # Only show XML & PDF options 261 | # admin.download_links = [:xml, :pdf] 262 | # 263 | # # Enable/disable the links based on block 264 | # # (for example, with cancan) 265 | # admin.download_links = proc { can?(:view_download_links) } 266 | # 267 | # end 268 | 269 | # == Pagination 270 | # 271 | # Pagination is enabled by default for all resources. 272 | # You can control the default per page count for all resources here. 273 | # 274 | # config.default_per_page = 30 275 | # 276 | # You can control the max per page count too. 277 | # 278 | # config.max_per_page = 10_000 279 | 280 | # == Filters 281 | # 282 | # By default the index screen includes a "Filters" sidebar on the right 283 | # hand side with a filter for each attribute of the registered model. 284 | # You can enable or disable them for all resources here. 285 | # 286 | # config.filters = true 287 | # 288 | # By default the filters include associations in a select, which means 289 | # that every record will be loaded for each association (up 290 | # to the value of config.maximum_association_filter_arity). 291 | # You can enabled or disable the inclusion 292 | # of those filters by default here. 293 | # 294 | # config.include_default_association_filters = true 295 | 296 | # config.maximum_association_filter_arity = 256 # default value of :unlimited will change to 256 in a future version 297 | # config.filter_columns_for_large_association, [ 298 | # :display_name, 299 | # :full_name, 300 | # :name, 301 | # :username, 302 | # :login, 303 | # :title, 304 | # :email, 305 | # ] 306 | # config.filter_method_for_large_association, '_starts_with' 307 | 308 | # == Head 309 | # 310 | # You can add your own content to the site head like analytics. Make sure 311 | # you only pass content you trust. 312 | # 313 | # config.head = ''.html_safe 314 | 315 | # == Footer 316 | # 317 | # By default, the footer shows the current Active Admin version. You can 318 | # override the content of the footer here. 319 | # 320 | # config.footer = 'my custom footer text' 321 | 322 | # == Sorting 323 | # 324 | # By default ActiveAdmin::OrderClause is used for sorting logic 325 | # You can inherit it with own class and inject it for all resources 326 | # 327 | # config.order_clause = MyOrderClause 328 | 329 | # == Webpacker 330 | # 331 | # By default, Active Admin uses Sprocket's asset pipeline. 332 | # You can switch to using Webpacker here. 333 | # 334 | # config.use_webpacker = true 335 | end 336 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/active_storage.rb: -------------------------------------------------------------------------------- 1 | Rails.application.reloader.to_prepare do 2 | ActiveStorage::Attachment.class_eval do 3 | class << self 4 | def ransackable_attributes(auth_object = nil) 5 | %w[blob_id created_at id name record_id record_type] 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /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/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | 19 | # If you are using UJS then enable automatic nonce generation 20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 21 | 22 | # Set the nonce only to specific directives 23 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src) 24 | 25 | # Report CSP violations to a specified URI 26 | # For further information see the following documentation: 27 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 28 | # Rails.application.config.content_security_policy_report_only = true 29 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /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/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] 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/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 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /spec/dummy/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 12 | # 13 | port ENV.fetch("PORT") { 3000 } 14 | 15 | # Specifies the `environment` that Puma will run in. 16 | # 17 | environment ENV.fetch("RAILS_ENV") { "development" } 18 | 19 | # Specifies the `pidfile` that Puma will use. 20 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 21 | 22 | # Specifies the number of `workers` to boot in clustered mode. 23 | # Workers are forked web server processes. If using threads and workers together 24 | # the concurrency of the application would be max `threads` * `workers`. 25 | # Workers do not work on JRuby or Windows (both of which do not support 26 | # processes). 27 | # 28 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 29 | 30 | # Use the `preload_app!` method when specifying a `workers` number. 31 | # This directive tells Puma to first boot the application and load code 32 | # before forking the application. This takes advantage of Copy On Write 33 | # process behavior so workers use less memory. 34 | # 35 | # preload_app! 36 | 37 | # Allow puma to be restarted by `rails restart` command. 38 | plugin :tmp_restart 39 | -------------------------------------------------------------------------------- /spec/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | ActiveAdmin.routes(self) 3 | 4 | root to: redirect('/admin') 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/config/spring.rb: -------------------------------------------------------------------------------- 1 | Spring.watch( 2 | ".ruby-version", 3 | ".rbenv-vars", 4 | "tmp/restart.txt", 5 | "tmp/caching-dev.txt" 6 | ) 7 | -------------------------------------------------------------------------------- /spec/dummy/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20170806125915_create_active_storage_tables.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20170806125915) 2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2] 3 | def change 4 | create_table :active_storage_blobs do |t| 5 | t.string :key, null: false 6 | t.string :filename, null: false 7 | t.string :content_type 8 | t.text :metadata 9 | t.bigint :byte_size, null: false 10 | t.string :checksum, null: false 11 | t.datetime :created_at, null: false 12 | 13 | t.index [ :key ], unique: true 14 | end 15 | 16 | create_table :active_storage_attachments do |t| 17 | t.string :name, null: false 18 | t.references :record, null: false, polymorphic: true, index: false 19 | t.references :blob, null: false 20 | 21 | t.datetime :created_at, null: false 22 | 23 | t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true 24 | t.foreign_key :active_storage_blobs, column: :blob_id 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180101010101_create_active_admin_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateActiveAdminComments < ActiveRecord::Migration[6.0] 2 | def self.up 3 | create_table :active_admin_comments do |t| 4 | t.string :namespace 5 | t.text :body 6 | t.references :resource, polymorphic: true 7 | t.references :author, polymorphic: true 8 | t.timestamps 9 | end 10 | add_index :active_admin_comments, [:namespace] 11 | end 12 | 13 | def self.down 14 | drop_table :active_admin_comments 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053251_create_authors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAuthors < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :authors do |t| 6 | t.string :name 7 | t.integer :age 8 | t.string :email 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053254_create_profiles.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateProfiles < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :profiles do |t| 6 | t.text :description 7 | t.belongs_to :author, foreign_key: true 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053255_create_tags.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateTags < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :tags do |t| 6 | t.string :name 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053257_create_post_tags.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePostTags < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :post_tags do |t| 6 | t.belongs_to :post, foreign_key: true 7 | t.belongs_to :tag, foreign_key: true 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053739_create_posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePosts < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :posts do |t| 6 | t.string :title 7 | t.text :description 8 | t.belongs_to :author, foreign_key: true 9 | t.string :category 10 | t.datetime :dt 11 | t.float :position 12 | t.boolean :published 13 | 14 | t.timestamps 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # This file is the source Rails uses to define your schema when running `bin/rails 6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 7 | # be faster and is potentially less error prone than running all of your 8 | # migrations from scratch. Old migrations may fail to apply correctly if those 9 | # migrations use external dependencies or application code. 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema[8.0].define(version: 2018_06_07_053739) do 14 | create_table "active_admin_comments", force: :cascade do |t| 15 | t.string "namespace" 16 | t.text "body" 17 | t.string "resource_type" 18 | t.integer "resource_id" 19 | t.string "author_type" 20 | t.integer "author_id" 21 | t.datetime "created_at", null: false 22 | t.datetime "updated_at", null: false 23 | t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id" 24 | t.index ["namespace"], name: "index_active_admin_comments_on_namespace" 25 | t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id" 26 | end 27 | 28 | create_table "active_storage_attachments", force: :cascade do |t| 29 | t.string "name", null: false 30 | t.string "record_type", null: false 31 | t.integer "record_id", null: false 32 | t.integer "blob_id", null: false 33 | t.datetime "created_at", null: false 34 | t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" 35 | t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true 36 | end 37 | 38 | create_table "active_storage_blobs", force: :cascade do |t| 39 | t.string "key", null: false 40 | t.string "filename", null: false 41 | t.string "content_type" 42 | t.text "metadata" 43 | t.bigint "byte_size", null: false 44 | t.string "checksum", null: false 45 | t.datetime "created_at", null: false 46 | t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true 47 | end 48 | 49 | create_table "authors", force: :cascade do |t| 50 | t.string "name" 51 | t.integer "age" 52 | t.string "email" 53 | t.datetime "created_at", null: false 54 | t.datetime "updated_at", null: false 55 | end 56 | 57 | create_table "post_tags", force: :cascade do |t| 58 | t.integer "post_id" 59 | t.integer "tag_id" 60 | t.datetime "created_at", null: false 61 | t.datetime "updated_at", null: false 62 | t.index ["post_id"], name: "index_post_tags_on_post_id" 63 | t.index ["tag_id"], name: "index_post_tags_on_tag_id" 64 | end 65 | 66 | create_table "posts", force: :cascade do |t| 67 | t.string "title" 68 | t.text "description" 69 | t.integer "author_id" 70 | t.string "category" 71 | t.datetime "dt" 72 | t.float "position" 73 | t.boolean "published" 74 | t.datetime "created_at", null: false 75 | t.datetime "updated_at", null: false 76 | t.index ["author_id"], name: "index_posts_on_author_id" 77 | end 78 | 79 | create_table "profiles", force: :cascade do |t| 80 | t.text "description" 81 | t.integer "author_id" 82 | t.datetime "created_at", null: false 83 | t.datetime "updated_at", null: false 84 | t.index ["author_id"], name: "index_profiles_on_author_id" 85 | end 86 | 87 | create_table "tags", force: :cascade do |t| 88 | t.string "name" 89 | t.datetime "created_at", null: false 90 | t.datetime "updated_at", null: false 91 | end 92 | 93 | add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" 94 | add_foreign_key "post_tags", "posts" 95 | add_foreign_key "post_tags", "tags" 96 | add_foreign_key "posts", "authors" 97 | add_foreign_key "profiles", "authors" 98 | end 99 | -------------------------------------------------------------------------------- /spec/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /spec/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/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/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /spec/dummy/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/public/apple-touch-icon.png -------------------------------------------------------------------------------- /spec/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/public/favicon.ico -------------------------------------------------------------------------------- /spec/dummy/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/f6b0f0662c723ceb5af1e574255d400551750897/spec/dummy/tmp/.keep -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | ENV['RAILS_ENV'] = 'test' 6 | 7 | require File.expand_path('dummy/config/environment.rb', __dir__) 8 | 9 | abort('The Rails environment is running in production mode!') if Rails.env.production? 10 | 11 | require 'rspec/rails' 12 | require 'capybara/rails' 13 | 14 | Dir[File.expand_path('support/**/*.rb', __dir__)].sort.each { |f| require f } 15 | 16 | # Force deprecations to raise an exception. 17 | # ActiveSupport::Deprecation.behavior = :raise 18 | 19 | # Checks for pending migrations and applies them before tests are run. 20 | # If you are not using ActiveRecord, you can remove these lines. 21 | begin 22 | ActiveRecord::Migration.maintain_test_schema! 23 | rescue ActiveRecord::PendingMigrationError => e 24 | puts e.to_s.strip 25 | exit 1 26 | end 27 | 28 | RSpec.configure do |config| 29 | if Gem::Version.new(Rails.version) >= Gem::Version.new('7.1') 30 | config.fixture_paths = [Rails.root.join('spec/fixtures')] 31 | else 32 | config.fixture_path = Rails.root.join('spec/fixtures') 33 | end 34 | 35 | config.infer_spec_type_from_file_location! 36 | config.filter_rails_from_backtrace! 37 | 38 | config.use_transactional_fixtures = true 39 | config.use_instantiated_fixtures = false 40 | config.render_views = false 41 | 42 | config.before(:suite) do 43 | intro = ('-' * 80) 44 | intro << "\n" 45 | intro << "- Ruby: #{RUBY_VERSION}\n" 46 | intro << "- Rails: #{Rails.version}\n" 47 | intro << "- ActiveAdmin: #{ActiveAdmin::VERSION}\n" 48 | intro << ('-' * 80) 49 | 50 | RSpec.configuration.reporter.message(intro) 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |config| 4 | config.disable_monkey_patching! 5 | config.filter_run focus: true 6 | config.filter_run_excluding changes_filesystem: true 7 | config.run_all_when_everything_filtered = true 8 | 9 | config.color = true 10 | config.tty = true 11 | 12 | config.example_status_persistence_file_path = '.rspec_failures' 13 | config.order = :random 14 | config.shared_context_metadata_behavior = :apply_to_host_groups 15 | 16 | config.expect_with :rspec do |expectations| 17 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 18 | end 19 | config.mock_with :rspec do |mocks| 20 | mocks.verify_partial_doubles = true 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/support/capybara.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'capybara/cuprite' 4 | 5 | Capybara.register_driver(:capybara_cuprite) do |app| 6 | browser_options = {}.tap do |opts| 7 | opts['no-sandbox'] = nil if ENV['DEVEL'] 8 | end 9 | 10 | Capybara::Cuprite::Driver.new( 11 | app, 12 | window_size: [1600, 1024], 13 | browser_options: browser_options, 14 | process_timeout: 30, 15 | timeout: 30, 16 | inspector: true, 17 | headless: !ENV['CUPRITE_HEADLESS'].in?(%w[n 0 no false]) 18 | ) 19 | end 20 | 21 | # Capybara.server = :puma 22 | Capybara.default_driver = Capybara.javascript_driver = :capybara_cuprite 23 | 24 | RSpec.configure do |config| 25 | config.prepend_before(:each, type: :system) do 26 | driven_by Capybara.javascript_driver 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/system/medium_editor_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe 'Medium editor', type: :system do 4 | let(:author) { Author.create!(email: 'some_email@example.com', name: 'John Doe', age: 30) } 5 | let(:post) { Post.create!(title: 'Test', author: author, description: 'Some content...') } 6 | 7 | before do 8 | post 9 | end 10 | 11 | after do 12 | Post.delete_all 13 | author.delete 14 | end 15 | 16 | context 'with a Medium editor' do 17 | it 'initialize the editor' do 18 | visit "/admin/posts/#{post.id}/edit" 19 | 20 | %w[bold italic underline justifyCenter html].each do |button| 21 | expect(page).to have_css(".medium-editor-action[data-action=\"#{button}\"]", visible: :hidden) 22 | end 23 | expect(page).to have_css('#post_description[data-aa-medium-editor]', visible: :hidden) 24 | expect(page).to have_css('#post_description_input .medium-editor-element', text: 'Some content...') 25 | end 26 | 27 | it 'adds some text to the description' do 28 | visit "/admin/posts/#{post.id}/edit" 29 | 30 | find('#post_description_input .medium-editor-element').click 31 | find('#post_description_input .medium-editor-element').base.send_keys(' more text') 32 | find('[type="submit"]').click 33 | 34 | expect(page).to have_content('was successfully updated') 35 | expect(post.reload.description).to match /Some content.*more text/ 36 | end 37 | end 38 | 39 | context 'with a Medium editor in a nested resource' do 40 | it 'updates some HTML content of a new nested resource' do 41 | visit "/admin/authors/#{author.id}/edit" 42 | 43 | expect(page).to have_css('.posts.has_many_container .medium-editor-element', text: 'Some content...') 44 | find('.posts.has_many_container .has_many_add').click 45 | expect(page).to have_css('.posts.has_many_container .medium-editor-element', count: 2) 46 | 47 | fill_in('author[posts_attributes][1][title]', with: 'A new post') 48 | find('#author_posts_attributes_1_description_input .medium-editor-element').base.send_keys(' new post text') 49 | find('[type="submit"]').click 50 | 51 | expect(page).to have_content('was successfully updated') 52 | expect(author.posts.last.description).to match /new post text/ 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/system/medium_js_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe 'Medium JS', type: :system do 4 | it 'defines a Javascript object for the editor', :aggregate_failures do 5 | visit '/admin/posts' 6 | 7 | expect(page.evaluate_script('typeof MediumEditor')).to eq 'function' 8 | expect(page.evaluate_script('MediumEditor.version.toString()')).to eq ActiveAdmin::MediumEditor::MEDIUM_VERSION 9 | end 10 | end 11 | --------------------------------------------------------------------------------