├── spec
├── dummy
│ ├── log
│ │ └── .keep
│ ├── tmp
│ │ └── .keep
│ ├── lib
│ │ └── assets
│ │ │ └── .keep
│ ├── public
│ │ ├── favicon.ico
│ │ ├── apple-touch-icon.png
│ │ ├── apple-touch-icon-precomposed.png
│ │ ├── 500.html
│ │ ├── 422.html
│ │ └── 404.html
│ ├── app
│ │ ├── assets
│ │ │ ├── images
│ │ │ │ └── .keep
│ │ │ ├── config
│ │ │ │ └── manifest.js
│ │ │ ├── javascripts
│ │ │ │ └── active_admin.js
│ │ │ └── stylesheets
│ │ │ │ ├── active_admin.scss
│ │ │ │ └── application.css
│ │ ├── models
│ │ │ ├── concerns
│ │ │ │ └── .keep
│ │ │ ├── application_record.rb
│ │ │ ├── post_tag.rb
│ │ │ ├── tag.rb
│ │ │ ├── profile.rb
│ │ │ ├── author.rb
│ │ │ └── post.rb
│ │ ├── controllers
│ │ │ ├── concerns
│ │ │ │ └── .keep
│ │ │ └── application_controller.rb
│ │ ├── views
│ │ │ └── layouts
│ │ │ │ ├── mailer.text.erb
│ │ │ │ ├── mailer.html.erb
│ │ │ │ └── application.html.erb
│ │ ├── helpers
│ │ │ └── application_helper.rb
│ │ ├── admin
│ │ │ ├── tags.rb
│ │ │ ├── dashboard.rb
│ │ │ ├── posts.rb
│ │ │ └── authors.rb
│ │ ├── channels
│ │ │ └── application_cable
│ │ │ │ ├── channel.rb
│ │ │ │ └── connection.rb
│ │ ├── mailers
│ │ │ └── application_mailer.rb
│ │ ├── jobs
│ │ │ └── application_job.rb
│ │ └── javascript
│ │ │ └── packs
│ │ │ └── application.js
│ ├── .ruby-version
│ ├── .tool-versions
│ ├── bin
│ │ ├── rake
│ │ ├── rails
│ │ └── setup
│ ├── config
│ │ ├── routes.rb
│ │ ├── spring.rb
│ │ ├── environment.rb
│ │ ├── storage.yml
│ │ ├── database.yml
│ │ ├── initializers
│ │ │ ├── mime_types.rb
│ │ │ ├── filter_parameter_logging.rb
│ │ │ ├── application_controller_renderer.rb
│ │ │ ├── cookies_serializer.rb
│ │ │ ├── active_storage.rb
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── assets.rb
│ │ │ ├── wrap_parameters.rb
│ │ │ ├── inflections.rb
│ │ │ ├── content_security_policy.rb
│ │ │ └── active_admin.rb
│ │ ├── cable.yml
│ │ ├── boot.rb
│ │ ├── application.rb
│ │ ├── locales
│ │ │ └── en.yml
│ │ ├── puma.rb
│ │ └── environments
│ │ │ ├── test.rb
│ │ │ ├── development.rb
│ │ │ └── production.rb
│ ├── config.ru
│ ├── Rakefile
│ └── db
│ │ ├── migrate
│ │ ├── 20180607053255_create_tags.rb
│ │ ├── 20180607053251_create_authors.rb
│ │ ├── 20180607053254_create_profiles.rb
│ │ ├── 20180607053257_create_post_tags.rb
│ │ ├── 20180607053739_create_posts.rb
│ │ ├── 20180101010101_create_active_admin_comments.rb
│ │ └── 20170806125915_create_active_storage_tables.active_storage.rb
│ │ └── schema.rb
├── system
│ ├── medium_js_spec.rb
│ └── medium_editor_spec.rb
├── spec_helper.rb
├── support
│ └── capybara.rb
└── rails_helper.rb
├── .rspec
├── extra
├── .bashrc
├── screenshot.png
├── dev_setup.sh
├── .env
├── Dockerfile.dockerignore
├── docker-compose.yml
├── Dockerfile
└── development.md
├── lib
├── activeadmin
│ ├── medium_editor.rb
│ └── medium_editor
│ │ ├── version.rb
│ │ └── engine.rb
├── activeadmin_medium_editor.rb
└── formtastic
│ └── inputs
│ └── medium_editor_input.rb
├── .fasterer.yml
├── .reviewdog.yml
├── app
└── assets
│ ├── stylesheets
│ └── activeadmin
│ │ ├── medium_editor
│ │ ├── util
│ │ │ └── _clearfix.scss
│ │ ├── animations
│ │ │ ├── _image-loading.scss
│ │ │ └── _pop-upwards.scss
│ │ ├── _settings.scss
│ │ ├── components
│ │ │ ├── _file-dragging.scss
│ │ │ ├── _anchor-preview.scss
│ │ │ ├── _placeholder.scss
│ │ │ ├── _toolbar-form.scss
│ │ │ └── _toolbar.scss
│ │ ├── medium_editor.scss
│ │ └── themes
│ │ │ ├── default.scss
│ │ │ ├── flat.scss
│ │ │ ├── roman.scss
│ │ │ ├── mani.scss
│ │ │ ├── bootstrap.scss
│ │ │ ├── tim.scss
│ │ │ └── beagle.scss
│ │ └── _medium_editor_input.scss
│ └── javascripts
│ └── activeadmin
│ └── medium_editor_input.js
├── .gitignore
├── .rubocop.yml
├── bin
├── rails
├── rake
├── rspec
├── rubocop
└── fasterer
├── Rakefile
├── .github
├── FUNDING.yml
└── workflows
│ ├── linters.yml
│ ├── specs_rails70.yml
│ ├── specs_rails71.yml
│ ├── specs_rails72.yml
│ ├── specs_rails80.yml
│ └── specs_rails61.yml
├── CHANGELOG.md
├── LICENSE.txt
├── activeadmin_medium_editor.gemspec
├── Makefile
├── Gemfile
└── README.md
/spec/dummy/log/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/tmp/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/lib/assets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/app/assets/images/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.7.1
2 |
--------------------------------------------------------------------------------
/spec/dummy/.tool-versions:
--------------------------------------------------------------------------------
1 | ruby 2.6.6
2 |
--------------------------------------------------------------------------------
/spec/dummy/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --require rails_helper
2 | --format documentation
3 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/extra/.bashrc:
--------------------------------------------------------------------------------
1 | alias ls='ls --color'
2 | alias ll='ls -l'
3 | alias la='ls -la'
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/spec/dummy/app/admin/tags.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ActiveAdmin.register Tag do
4 | end
5 |
--------------------------------------------------------------------------------
/extra/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blocknotes/activeadmin_medium_editor/HEAD/extra/screenshot.png
--------------------------------------------------------------------------------
/lib/activeadmin/medium_editor.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'activeadmin/medium_editor/engine'
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | end
3 |
--------------------------------------------------------------------------------
/spec/dummy/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.fasterer.yml:
--------------------------------------------------------------------------------
1 | ---
2 | exclude_paths:
3 | - bin/*
4 | - db/schema.rb
5 | - gemfiles/**/*
6 | - spec/dummy/**/*
7 | - vendor/**/*
8 |
--------------------------------------------------------------------------------
/spec/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | ActiveAdmin.routes(self)
3 |
4 | root to: redirect('/admin')
5 | end
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/spec/dummy/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/extra/Dockerfile.dockerignore:
--------------------------------------------------------------------------------
1 | # Ignore everything but the required files for bundle install
2 | /**/*
3 |
4 | !/*.gemspec
5 | !/Gemfile
6 | !/lib
7 |
--------------------------------------------------------------------------------
/.reviewdog.yml:
--------------------------------------------------------------------------------
1 | ---
2 | runner:
3 | fasterer:
4 | cmd: bin/fasterer
5 | level: info
6 | rubocop:
7 | cmd: bin/rubocop
8 | level: info
9 |
--------------------------------------------------------------------------------
/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/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/spec/dummy/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/activeadmin/medium_editor/util/_clearfix.scss:
--------------------------------------------------------------------------------
1 | %clearfix {
2 | &:after {
3 | clear: both;
4 | content: "";
5 | display: table;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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/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/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/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/.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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | [](https://badge.fury.io/rb/activeadmin_medium_editor)
11 | [](https://rubygems.org/gems/activeadmin_medium_editor)
12 | [](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/linters.yml)
13 | [](https://github.com/blocknotes/activeadmin_medium_editor/actions/workflows/specs_rails61.yml)
14 | [](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 | 
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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------