зеркало из
https://github.com/rs-pro/activeadmin-quill_editor.git
synced 2026-08-28 15:36:17 +03:00
Сравнить коммиты
134 Коммитов
| Автор | SHA1 | Дата | |
|---|---|---|---|
|
|
f291f7e7e6 | ||
|
|
df944277b5 | ||
|
|
3cc5683d44 | ||
|
|
498cbbd0c9 | ||
|
|
bfc2e997f1 | ||
|
|
9bda446762 | ||
|
|
533471c0d6 | ||
|
|
3617aab7f2 | ||
|
|
5196a8811a | ||
|
|
5e9a3b6c5a | ||
|
|
181aab7fd6 | ||
|
|
300b4a0a03 | ||
|
|
451a225277 | ||
|
|
6cbb39daad | ||
|
|
d19fc7ddfc | ||
|
|
74790fc115 | ||
|
|
c3b129a212 | ||
|
|
ab858f7c6f | ||
|
|
6cf744b84c | ||
|
|
0ae4ce2035 | ||
|
|
dd9aa22cf5 | ||
|
|
b6f3c0c3a6 | ||
|
|
7d3a084977 | ||
|
|
1569b1ff18 | ||
|
|
3459800dbf | ||
|
|
af901f4f7d | ||
|
|
328ee0d9fa | ||
|
|
751196ef8c | ||
|
|
589b782866 | ||
|
|
554f6086e7 | ||
|
|
051ada9843 | ||
|
|
fd90851a6b | ||
|
|
bd32c5f28f | ||
|
|
21ec7a918b | ||
|
|
b310f9e71b | ||
|
|
bbee6f7681 | ||
|
|
57e151aa03 | ||
|
|
0913bb6915 | ||
|
|
728e3fa097 | ||
|
|
9d891f0602 | ||
|
|
21fc69c2c0 | ||
|
|
b0e770ca9e | ||
|
|
ba53f9febf | ||
|
|
d690b9906f | ||
|
|
99908f97f7 | ||
|
|
9389f9e32d | ||
|
|
4629ac4133 | ||
|
|
0d4485c321 | ||
|
|
0c1cfefa83 | ||
|
|
0c674025a9 | ||
|
|
770e069442 | ||
|
|
d346729cd1 | ||
|
|
ce65cfbb7e | ||
|
|
22a1c8714c | ||
|
|
489e1c35eb | ||
|
|
62efca80d6 | ||
|
|
46168cc7f8 | ||
|
|
02310804aa | ||
|
|
7e2f8733dc | ||
|
|
2d0a8f961f | ||
|
|
7262ad5523 | ||
|
|
71f227736d | ||
|
|
361da5096d | ||
|
|
17ef9aa5db | ||
|
|
b00fcd90ab | ||
|
|
edf5cbcb13 | ||
|
|
38e5406d5d | ||
|
|
c560dd5c60 | ||
|
|
597cae7adb | ||
|
|
6d0599c39e | ||
|
|
664765ac79 | ||
|
|
7be390701f | ||
|
|
e4401a469b | ||
|
|
d8632f069a | ||
|
|
7498cd65a1 | ||
|
|
038d66f387 | ||
|
|
7af25106a2 | ||
|
|
d021f3650e | ||
|
|
8a13dd49a4 | ||
|
|
1cad5a10c3 | ||
|
|
63b4c118f6 | ||
|
|
277d1a521a | ||
|
|
4a0ea5e8f2 | ||
|
|
ffc57e7d90 | ||
|
|
2ebc9176b4 | ||
|
|
0b44c683e6 | ||
|
|
9b460d36e3 | ||
|
|
d41f8450ea | ||
|
|
401d2528e8 | ||
|
|
e086bac0a7 | ||
|
|
36cd836ca8 | ||
|
|
c05666673e | ||
|
|
2d5429718c | ||
|
|
78126d0cd7 | ||
|
|
3190134973 | ||
|
|
8d6b05297a | ||
|
|
5d9b6f70fd | ||
|
|
6fa021c0c7 | ||
|
|
357ef382d6 | ||
|
|
43ae70c7c9 | ||
|
|
6daf6f6bc8 | ||
|
|
98c235d346 | ||
|
|
e6e6742753 | ||
|
|
c2c8d48795 | ||
|
|
72062c1a30 | ||
|
|
c4aa91225b | ||
|
|
3cc6edb302 | ||
|
|
d78fb2eb9c | ||
|
|
e5db64af96 | ||
|
|
c0d37ad94e | ||
|
|
96c70106a4 | ||
|
|
4ec6e80760 | ||
|
|
707f4a5cc7 | ||
|
|
dc97316303 | ||
|
|
e9b8abc88e | ||
|
|
582667dc59 | ||
|
|
76c06f5346 | ||
|
|
4e20e658ac | ||
|
|
135a56dc03 | ||
|
|
668bd642e5 | ||
|
|
ab8c4fd73f | ||
|
|
d60ed0f723 | ||
|
|
98b29d6f69 | ||
|
|
962b48bb30 | ||
|
|
03b2d0e4e8 | ||
|
|
593ad3841a | ||
|
|
d96162fedd | ||
|
|
a43a4ff0ba | ||
|
|
7a148c7cd1 | ||
|
|
5c462f5d7c | ||
|
|
9ecfceaa9a | ||
|
|
598b2d75cf | ||
|
|
54026744c4 | ||
|
|
5d35feedd8 |
7
.fasterer.yml
Обычный файл
7
.fasterer.yml
Обычный файл
@@ -0,0 +1,7 @@
|
||||
---
|
||||
exclude_paths:
|
||||
- bin/*
|
||||
- db/schema.rb
|
||||
- gemfiles/**/*
|
||||
- spec/dummy/**/*
|
||||
- vendor/**/*
|
||||
13
.github/FUNDING.yml
поставляемый
Обычный файл
13
.github/FUNDING.yml
поставляемый
Обычный файл
@@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [blocknotes]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
39
.github/workflows/linters.yml
поставляемый
Обычный файл
39
.github/workflows/linters.yml
поставляемый
Обычный файл
@@ -0,0 +1,39 @@
|
||||
---
|
||||
name: Linters
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
reviewdog:
|
||||
name: Reviewdog
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
RAILS_VERSION: 7.0
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.0
|
||||
bundler-cache: true
|
||||
|
||||
- name: Set up Reviewdog
|
||||
uses: reviewdog/action-setup@v1
|
||||
with:
|
||||
reviewdog_version: latest
|
||||
|
||||
- name: Run Reviewdog
|
||||
env:
|
||||
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer,rubocop
|
||||
|
||||
# NOTE: check with: reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer -diff="git diff" -tee
|
||||
43
.github/workflows/specs_rails61.yml
поставляемый
Обычный файл
43
.github/workflows/specs_rails61.yml
поставляемый
Обычный файл
@@ -0,0 +1,43 @@
|
||||
---
|
||||
name: Specs Rails 6.1 with ActiveAdmin 2.9
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: ['3.0']
|
||||
|
||||
env:
|
||||
RAILS_VERSION: 6.0
|
||||
ACTIVEADMIN_VERSION: 2.9.0
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Database setup
|
||||
run: bin/rails db:create db:migrate db:test:prepare
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec rspec --profile
|
||||
|
||||
- name: On failure, archive screenshots as artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-failed-screenshots
|
||||
path: spec/dummy/tmp/screenshots
|
||||
42
.github/workflows/specs_rails70.yml
поставляемый
Обычный файл
42
.github/workflows/specs_rails70.yml
поставляемый
Обычный файл
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: Specs Rails 7.0
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: ['3.0', '3.2']
|
||||
|
||||
env:
|
||||
RAILS_VERSION: 7.0
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Database setup
|
||||
run: bin/rails db:create db:migrate db:test:prepare
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec rspec --profile
|
||||
|
||||
- name: On failure, archive screenshots as artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-failed-screenshots
|
||||
path: spec/dummy/tmp/screenshots
|
||||
42
.github/workflows/specs_rails71.yml
поставляемый
Обычный файл
42
.github/workflows/specs_rails71.yml
поставляемый
Обычный файл
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: Specs Rails 7.1
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: ['3.2', '3.4']
|
||||
|
||||
env:
|
||||
RAILS_VERSION: 7.1
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Database setup
|
||||
run: bin/rails db:create db:migrate db:test:prepare
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec rspec --profile
|
||||
|
||||
- name: On failure, archive screenshots as artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-failed-screenshots
|
||||
path: spec/dummy/tmp/screenshots
|
||||
42
.github/workflows/specs_rails72.yml
поставляемый
Обычный файл
42
.github/workflows/specs_rails72.yml
поставляемый
Обычный файл
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: Specs Rails 7.2
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: ['3.2', '3.4']
|
||||
|
||||
env:
|
||||
RAILS_VERSION: 7.2
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Database setup
|
||||
run: bin/rails db:create db:migrate db:test:prepare
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec rspec --profile
|
||||
|
||||
- name: On failure, archive screenshots as artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-failed-screenshots
|
||||
path: spec/dummy/tmp/screenshots
|
||||
42
.github/workflows/specs_rails80.yml
поставляемый
Обычный файл
42
.github/workflows/specs_rails80.yml
поставляемый
Обычный файл
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: Specs Rails 8.0
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: ['3.2', '3.4']
|
||||
|
||||
env:
|
||||
RAILS_VERSION: 8.0
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Database setup
|
||||
run: bin/rails db:create db:migrate db:test:prepare
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec rspec --profile
|
||||
|
||||
- name: On failure, archive screenshots as artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-failed-screenshots
|
||||
path: spec/dummy/tmp/screenshots
|
||||
15
.gitignore
поставляемый
15
.gitignore
поставляемый
@@ -1,3 +1,14 @@
|
||||
_misc/
|
||||
|
||||
*.gem
|
||||
*.orig
|
||||
|
||||
/.rspec_failures
|
||||
/.rubocop-*
|
||||
/Gemfile.lock
|
||||
|
||||
/_misc/
|
||||
/coverage/
|
||||
/spec/dummy/db/*.sqlite3*
|
||||
/spec/dummy/db/schema-dev.rb
|
||||
/spec/dummy/log/
|
||||
/spec/dummy/storage/
|
||||
/spec/dummy/tmp/
|
||||
|
||||
13
.overcommit.yml
Обычный файл
13
.overcommit.yml
Обычный файл
@@ -0,0 +1,13 @@
|
||||
CommitMsg:
|
||||
CapitalizedSubject:
|
||||
enabled: false
|
||||
|
||||
MessageFormat:
|
||||
enabled: true
|
||||
pattern: "^(fixup! ){0,1}(fix|feat|build|chore|ci|docs|style|refactor|perf|test)[!]{0,1}: .+$"
|
||||
expected_pattern_message: "<Commit type>: <Commit Message>"
|
||||
sample_message: "chore: add Overcommit config"
|
||||
|
||||
TextWidth:
|
||||
enabled: true
|
||||
max_subject_width: 72
|
||||
8
.reviewdog.yml
Обычный файл
8
.reviewdog.yml
Обычный файл
@@ -0,0 +1,8 @@
|
||||
---
|
||||
runner:
|
||||
fasterer:
|
||||
cmd: bin/fasterer
|
||||
level: info
|
||||
rubocop:
|
||||
cmd: bin/rubocop
|
||||
level: info
|
||||
2
.rspec
Обычный файл
2
.rspec
Обычный файл
@@ -0,0 +1,2 @@
|
||||
--require rails_helper
|
||||
--format documentation
|
||||
33
.rubocop.yml
Обычный файл
33
.rubocop.yml
Обычный файл
@@ -0,0 +1,33 @@
|
||||
---
|
||||
inherit_from:
|
||||
- https://relaxed.ruby.style/rubocop.yml
|
||||
|
||||
plugins:
|
||||
- rubocop-capybara
|
||||
- rubocop-packaging
|
||||
- rubocop-performance
|
||||
- rubocop-rails
|
||||
- rubocop-rspec
|
||||
- rubocop-rspec_rails
|
||||
|
||||
AllCops:
|
||||
Exclude:
|
||||
- bin/*
|
||||
- db/schema.rb
|
||||
- gemfiles/**/*
|
||||
- spec/dummy/**/*
|
||||
- vendor/**/*
|
||||
NewCops: enable
|
||||
TargetRubyVersion: 3.0
|
||||
|
||||
RSpec/ExampleLength:
|
||||
# default 5
|
||||
Max: 12
|
||||
|
||||
RSpec/MultipleExpectations:
|
||||
# default 1
|
||||
Max: 4
|
||||
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
# default 5
|
||||
Max: 10
|
||||
72
CHANGELOG.md
Обычный файл
72
CHANGELOG.md
Обычный файл
@@ -0,0 +1,72 @@
|
||||
# Quill Editor for ActiveAdmin
|
||||
|
||||
An Active Admin plugin to use Quill Rich Text Editor.
|
||||
|
||||
## v2.0.0 - 2025-04-15
|
||||
|
||||
- Update Quill from 1.3.7 to 2.0.3
|
||||
|
||||
## v1.3.0 - 2025-03-18
|
||||
|
||||
- Javascript API: expose Quill editor query functions
|
||||
- ImageUploader: reject the Promise if an url is not provided in the response
|
||||
|
||||
## v1.2.0 - 2024-02-29
|
||||
|
||||
- Update minimum supported Ruby version to 3.0
|
||||
|
||||
## v1.1.0 - 2023-08-20
|
||||
|
||||
- Support ActiveAdmin 3.x
|
||||
- Minor tests config improvements
|
||||
|
||||
## v1.0.0 - 2022-04-18
|
||||
|
||||
- Set minimum Ruby version to 2.6.0
|
||||
- Remove `sassc` dependency
|
||||
- Enable Ruby 3.0 specs support
|
||||
- Enable Rails 7.0 specs support
|
||||
- Internal improvements
|
||||
|
||||
## v0.3.4 - 2021-03-16
|
||||
|
||||
- Fix editor loading with Turbolinks
|
||||
|
||||
## v0.3.2 - 2021-03-14
|
||||
|
||||
- Specs improvements
|
||||
- Minor internal changes
|
||||
|
||||
## v0.3.0 - 2020-10-01
|
||||
|
||||
- Add Webpacker support
|
||||
|
||||
## v0.2.14 - 2020-09-10
|
||||
|
||||
- JS: enable strict directive
|
||||
- Minor specs improvement
|
||||
|
||||
## v0.2.12 - 2020-09-08
|
||||
|
||||
- JS refactoring
|
||||
|
||||
## v0.2.10 - 2020-09-05
|
||||
|
||||
- Include Image Uploader plugin
|
||||
|
||||
## v0.2.9 - 2020-09-04
|
||||
|
||||
- Fix not working alignments (issue #8)
|
||||
- Fix empty editor problem which produces `<p><br></p>` (pull request #9)
|
||||
|
||||
## v0.2.8 - 2020-09-03
|
||||
|
||||
- Minor style improvements
|
||||
- Add specs for editor in nested resources
|
||||
- Add Rubocop and remove SimpleCov gems
|
||||
|
||||
## v0.2.4 - 2020-09-01
|
||||
|
||||
- Update Quill editor to version 1.3.7
|
||||
- Add minimum specs (using RSpec)
|
||||
- Minor internal changes
|
||||
62
Gemfile
62
Gemfile
@@ -1,4 +1,64 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
def eval_version(dependency, version)
|
||||
return [dependency] if version.empty?
|
||||
|
||||
version.count('.') < 2 ? [dependency, "~> #{version}.0"] : [dependency, version]
|
||||
end
|
||||
|
||||
if ENV['DEVEL'] == '1'
|
||||
gem 'activeadmin_quill_editor', path: './'
|
||||
else
|
||||
gemspec
|
||||
end
|
||||
|
||||
ruby_ver = ENV.fetch('RUBY_VERSION', '')
|
||||
|
||||
rails_ver = ENV.fetch('RAILS_VERSION', '')
|
||||
rails = eval_version('rails', rails_ver)
|
||||
gem(*rails)
|
||||
|
||||
active_admin_ver = ENV.fetch('ACTIVEADMIN_VERSION', '')
|
||||
active_admin = eval_version('activeadmin', active_admin_ver)
|
||||
gem(*active_admin)
|
||||
|
||||
ruby32 = ruby_ver.empty? || Gem::Version.new(ruby_ver) >= Gem::Version.new('3.2')
|
||||
rails72 = rails_ver.empty? || Gem::Version.new(rails_ver) >= Gem::Version.new('7.2')
|
||||
sqlite3 = ruby32 && rails72 ? ['sqlite3'] : ['sqlite3', '~> 1.4']
|
||||
gem(*sqlite3)
|
||||
|
||||
gem 'zeitwerk', '~> 2.6.18' unless ruby32
|
||||
|
||||
# NOTE: to avoid error: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger
|
||||
gem 'concurrent-ruby', '1.3.4'
|
||||
|
||||
# Misc
|
||||
gem 'bigdecimal'
|
||||
gem 'csv'
|
||||
gem 'mutex_m'
|
||||
gem 'puma'
|
||||
gem 'sassc'
|
||||
gem 'sprockets-rails'
|
||||
|
||||
# Testing
|
||||
gem 'capybara'
|
||||
gem 'cuprite'
|
||||
gem 'rspec_junit_formatter'
|
||||
gem 'rspec-rails'
|
||||
gem 'simplecov', require: false
|
||||
gem 'super_diff'
|
||||
|
||||
# Linters
|
||||
gem 'fasterer'
|
||||
gem 'rubocop'
|
||||
gem 'rubocop-capybara'
|
||||
gem 'rubocop-packaging'
|
||||
gem 'rubocop-performance'
|
||||
gem 'rubocop-rails'
|
||||
gem 'rubocop-rspec'
|
||||
gem 'rubocop-rspec_rails'
|
||||
|
||||
# Tools
|
||||
gem 'pry-rails'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017 Mattia Roccoberton
|
||||
Copyright (c) 2017-2022 Mattia Roccoberton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
47
Makefile
Обычный файл
47
Makefile
Обычный файл
@@ -0,0 +1,47 @@
|
||||
include extra/.env
|
||||
|
||||
help:
|
||||
@echo -e "${COMPOSE_PROJECT_NAME} - Main project commands:\n\
|
||||
make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN)\n\
|
||||
make specs # run the tests (after up)\n\
|
||||
make lint # run the linters (after up)\n\
|
||||
make server # run the server (after up)\n\
|
||||
make shell # open a shell (after up)\n\
|
||||
make down # cleanup (after up)\n\
|
||||
Example: RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up"
|
||||
|
||||
# System commands
|
||||
|
||||
build:
|
||||
@rm -f Gemfile.lock spec/dummy/db/*.sqlite3
|
||||
@docker compose -f extra/docker-compose.yml build
|
||||
|
||||
db_reset:
|
||||
@docker compose -f extra/docker-compose.yml run --rm app bin/rails db:create db:migrate db:test:prepare
|
||||
|
||||
up: build db_reset
|
||||
@docker compose -f extra/docker-compose.yml up
|
||||
|
||||
shell:
|
||||
@docker compose -f extra/docker-compose.yml exec app bash
|
||||
|
||||
down:
|
||||
@docker compose -f extra/docker-compose.yml down --volumes --rmi local --remove-orphans
|
||||
|
||||
# App commands
|
||||
|
||||
seed:
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rails db:seed
|
||||
|
||||
console: seed
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rails console
|
||||
|
||||
lint:
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rubocop
|
||||
|
||||
server: seed
|
||||
@rm -f spec/dummy/tmp/pids/server.pid
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rails server -b 0.0.0.0 -p ${SERVER_PORT}
|
||||
|
||||
specs:
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rspec --fail-fast
|
||||
111
README.md
111
README.md
@@ -1,33 +1,65 @@
|
||||
# ActiveAdmin Quill Editor [](https://badge.fury.io/rb/activeadmin_quill_editor)
|
||||
# ActiveAdmin Quill Editor
|
||||
[](https://badge.fury.io/rb/activeadmin_quill_editor)
|
||||
[](https://rubygems.org/gems/activeadmin_quill_editor)
|
||||
[](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/linters.yml)
|
||||
|
||||
An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quilljs/quill)
|
||||
[](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails61.yml)
|
||||
[](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails70.yml)
|
||||
[](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails71.yml)
|
||||
[](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails72.yml)
|
||||
[](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails80.yml)
|
||||
|
||||

|
||||
An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quilljs/quill) in form fields.
|
||||
|
||||

|
||||
|
||||
Please :star: if you like it.
|
||||
|
||||
## Install
|
||||
|
||||
- Update your Gemfile: `gem 'activeadmin_quill_editor'` (and execute *bundle*)
|
||||
- Add at the end of your ActiveAdmin styles (_app/assets/stylesheets/active_admin.scss_):
|
||||
```css
|
||||
_NOTE_: the gem 2.x provide Quill 2.x, while Quill 1.x is provided with the gem version 1.x
|
||||
|
||||
After installing Active Admin, add to your Gemfile: `gem 'activeadmin_quill_editor'` (and execute *bundle*)
|
||||
|
||||
If you installed Active Admin without Webpacker support (default for now):
|
||||
|
||||
- Add a SASS/SCSS gem to your Gemfile (ex. `gem 'sassc'`)
|
||||
- Add at the end of your Active Admin styles (_app/assets/stylesheets/active_admin.scss_):
|
||||
```scss
|
||||
@import 'activeadmin/quill_editor/quill.snow';
|
||||
@import 'activeadmin/quill_editor_input';
|
||||
```
|
||||
- Add at the end of your ActiveAdmin javascripts (_app/assets/javascripts/active_admin.js_):
|
||||
- Add at the end of your Active Admin javascripts (_app/assets/javascripts/active_admin.js_):
|
||||
```js
|
||||
//= require activeadmin/quill_editor/quill
|
||||
//= require activeadmin/quill_editor_input
|
||||
```
|
||||
- Use the input with `as: :quill_editor` in Active Admin model conf
|
||||
|
||||
Why 2 separated scripts? In this way you can include a different version of *quill editor* if you like.
|
||||
If you installed Active Admin with Webpacker support:
|
||||
|
||||
## Options
|
||||
- Execute in your project root:
|
||||
```sh
|
||||
yarn add blocknotes/activeadmin_quill_editor
|
||||
```
|
||||
- Add to your *app/javascript/packs/active_admin.js*:
|
||||
```js
|
||||
require('activeadmin_quill_editor')
|
||||
```
|
||||
|
||||
**data-options**: permits to set *quill editor* options directly - see [options list](https://quilljs.com/docs/quickstart/)
|
||||
## Usage
|
||||
|
||||
In your Active Admin models, form configuration, set the text inputs with `as: :quill_editor` where needed.
|
||||
|
||||
**data-options**: permits to set *quill editor* options directly - see [options list](https://quilljs.com/docs/configuration/)
|
||||
|
||||
If you are using Action Text (`has_rich_text`) on the same field of the Quill editor please take a look at [this workaround](https://github.com/blocknotes/activeadmin_quill_editor/issues/33#issuecomment-1965996947) to avoid issues.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic usage
|
||||
|
||||
```ruby
|
||||
# ActiveAdmin article form conf:
|
||||
# Active Admin article form conf:
|
||||
form do |f|
|
||||
f.inputs 'Article' do
|
||||
f.input :title
|
||||
@@ -38,26 +70,59 @@ Why 2 separated scripts? In this way you can include a different version of *qui
|
||||
end
|
||||
```
|
||||
|
||||
Toolbar buttons configuration:
|
||||
### Toolbar buttons configuration
|
||||
|
||||
```ruby
|
||||
f.input :description, as: :quill_editor, input_html: {data: {options: {modules: {toolbar: [['bold', 'italic', 'underline'], ['link']]}, placeholder: 'Type something...', theme: 'snow'}}}
|
||||
f.input :description, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: [['bold', 'italic', 'underline'], ['link']] }, placeholder: 'Type something...', theme: 'snow' } } }
|
||||
```
|
||||
|
||||
## Notes
|
||||
### ImageUploader plugin
|
||||
|
||||
- Upload functions (Images, Documents, Files, etc.) are not implemented yet
|
||||
This plugin allows to upload images to the server (instead of storing them in *base64* by default), reference [here](https://github.com/NoelOConnell/quill-image-uploader).
|
||||
|
||||
```ruby
|
||||
# Upload method (to be included in the admin entity configuration)
|
||||
member_action :upload, method: [:post] do
|
||||
result = { success: resource.images.attach(params[:file_upload]) }
|
||||
result[:url] = url_for(resource.images.last) if result[:success]
|
||||
render json: result
|
||||
end
|
||||
```
|
||||
|
||||
```ruby
|
||||
# Form field
|
||||
unless object.new_record?
|
||||
plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
|
||||
f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
|
||||
end
|
||||
```
|
||||
|
||||
For the relevant files of the upload example see [here](examples/upload_plugin_using_activestorage/).
|
||||
Consider that this is just a basic example: images are uploaded as soon as they are attached to the
|
||||
editor (regardless of the form submit), it shows the editor only for an existing record (because of
|
||||
the *upload_admin_post_path*) and it doesn't provide a way to remove images (just deleting them from
|
||||
the editor will not destroy them, you'll need to implement a purge logic for that).
|
||||
|
||||
## Javascript API
|
||||
|
||||
Some methods are provided for advanced use cases:
|
||||
|
||||
- `window.getQuillEditors()`: returns all the available Quill editors instances;
|
||||
- `window.getQuillEditorByIndex(n)`: returns the N-th Quill editor instance;
|
||||
- `window.getQuillEditorByElementId(id)`: returns the Quill editor instance related to the specified element id (e.g. _article_description_).
|
||||
|
||||
## Development
|
||||
|
||||
Project created by [Mattia Roccoberton](http://blocknot.es), thanks also to the good guys that opened issues and pull requests from time to time.
|
||||
|
||||
For development information please check [this document](extra/development.md).
|
||||
|
||||
## Do you like it? Star it!
|
||||
|
||||
If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
|
||||
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).
|
||||
|
||||
Take a look at [other ActiveAdmin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source) that I made if you are curious.
|
||||
|
||||
## Contributors
|
||||
|
||||
- [Mattia Roccoberton](http://blocknot.es) - creator, maintainer
|
||||
Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE.txt)
|
||||
The gem is available as open-source under the terms of the [MIT](LICENSE.txt).
|
||||
|
||||
28
Rakefile
28
Rakefile
@@ -1,3 +1,27 @@
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "bundler/gem_tasks"
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
||||
end
|
||||
|
||||
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
||||
load 'rails/tasks/engine.rake'
|
||||
|
||||
load 'rails/tasks/statistics.rake'
|
||||
|
||||
require 'bundler/gem_tasks'
|
||||
|
||||
begin
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec) do |t|
|
||||
# t.ruby_opts = %w[-w]
|
||||
t.rspec_opts = ['--color', '--format documentation']
|
||||
end
|
||||
|
||||
task default: :spec
|
||||
rescue LoadError
|
||||
puts '! LoadError: no RSpec available'
|
||||
end
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
# frozen_string_literal: true
|
||||
|
||||
lib = File.expand_path('lib', __dir__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'activeadmin/quill_editor/version'
|
||||
|
||||
@@ -12,8 +14,16 @@ Gem::Specification.new do |spec|
|
||||
spec.email = 'mat@blocknot.es'
|
||||
spec.homepage = 'https://github.com/blocknotes/activeadmin_quill_editor'
|
||||
|
||||
spec.files = `git ls-files -z`.split("\x0")
|
||||
spec.required_ruby_version = '>= 3.0'
|
||||
|
||||
spec.metadata['homepage_uri'] = spec.homepage
|
||||
spec.metadata['changelog_uri'] = 'https://github.com/blocknotes/activeadmin_quill_editor/blob/main/CHANGELOG.md'
|
||||
spec.metadata['source_code_uri'] = spec.homepage
|
||||
|
||||
spec.metadata['rubygems_mfa_required'] = 'true'
|
||||
|
||||
spec.files = Dir['{app,lib}/**/*', 'LICENSE.txt', 'Rakefile', 'README.md']
|
||||
spec.require_paths = ['lib']
|
||||
|
||||
spec.add_runtime_dependency 'activeadmin', '~> 1.0'
|
||||
spec.add_runtime_dependency 'activeadmin', '>= 2.9', '< 4' # rubocop:disable Gemspec/AddRuntimeDependency
|
||||
end
|
||||
|
||||
362
app/assets/javascripts/activeadmin/quill.imageUploader.js
Обычный файл
362
app/assets/javascripts/activeadmin/quill.imageUploader.js
Обычный файл
@@ -0,0 +1,362 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _blots_image_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var _quill_imageUploader_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
||||
/* harmony import */ var _quill_imageUploader_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_quill_imageUploader_css__WEBPACK_IMPORTED_MODULE_1__);
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
|
||||
|
||||
|
||||
var ImageUploader = function () {
|
||||
function ImageUploader(quill, options) {
|
||||
_classCallCheck(this, ImageUploader);
|
||||
|
||||
this.quill = quill;
|
||||
this.options = options;
|
||||
this.range = null;
|
||||
|
||||
if (typeof this.options.upload !== "function") {
|
||||
console.warn("[Missing config] upload function that returns a promise is required");
|
||||
}
|
||||
|
||||
if (this.options.loadingClass) {
|
||||
_blots_image_js__WEBPACK_IMPORTED_MODULE_0__["default"].className = this.options.loadingClass;
|
||||
}
|
||||
|
||||
var toolbar = this.quill.getModule("toolbar");
|
||||
toolbar.addHandler("image", this.selectLocalImage.bind(this));
|
||||
|
||||
this.handleDrop = this.handleDrop.bind(this);
|
||||
this.handlePaste = this.handlePaste.bind(this);
|
||||
|
||||
this.quill.root.addEventListener("drop", this.handleDrop, false);
|
||||
this.quill.root.addEventListener("paste", this.handlePaste, false);
|
||||
}
|
||||
|
||||
_createClass(ImageUploader, [{
|
||||
key: "selectLocalImage",
|
||||
value: function selectLocalImage() {
|
||||
var _this = this;
|
||||
|
||||
this.range = this.quill.getSelection();
|
||||
this.fileHolder = document.createElement("input");
|
||||
this.fileHolder.setAttribute("type", "file");
|
||||
this.fileHolder.setAttribute("accept", "image/*");
|
||||
this.fileHolder.setAttribute("style", "visibility:hidden");
|
||||
|
||||
this.fileHolder.onchange = this.fileChanged.bind(this);
|
||||
|
||||
document.body.appendChild(this.fileHolder);
|
||||
|
||||
this.fileHolder.click();
|
||||
|
||||
window.requestAnimationFrame(function () {
|
||||
document.body.removeChild(_this.fileHolder);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "handleDrop",
|
||||
value: function handleDrop(evt) {
|
||||
var _this2 = this;
|
||||
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
if (evt.dataTransfer && evt.dataTransfer.files && evt.dataTransfer.files.length) {
|
||||
if (document.caretRangeFromPoint) {
|
||||
var selection = document.getSelection();
|
||||
var range = document.caretRangeFromPoint(evt.clientX, evt.clientY);
|
||||
if (selection && range) {
|
||||
selection.setBaseAndExtent(range.startContainer, range.startOffset, range.startContainer, range.startOffset);
|
||||
}
|
||||
} else {
|
||||
var _selection = document.getSelection();
|
||||
var _range = document.caretPositionFromPoint(evt.clientX, evt.clientY);
|
||||
if (_selection && _range) {
|
||||
_selection.setBaseAndExtent(_range.offsetNode, _range.offset, _range.offsetNode, _range.offset);
|
||||
}
|
||||
}
|
||||
|
||||
this.range = this.quill.getSelection();
|
||||
var file = evt.dataTransfer.files[0];
|
||||
|
||||
setTimeout(function () {
|
||||
_this2.range = _this2.quill.getSelection();
|
||||
_this2.readAndUploadFile(file);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "handlePaste",
|
||||
value: function handlePaste(evt) {
|
||||
var _this3 = this;
|
||||
|
||||
var clipboard = evt.clipboardData || window.clipboardData;
|
||||
|
||||
// IE 11 is .files other browsers are .items
|
||||
if (clipboard && (clipboard.items || clipboard.files)) {
|
||||
var items = clipboard.items || clipboard.files;
|
||||
var IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png|svg|webp)$/i;
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (IMAGE_MIME_REGEX.test(items[i].type)) {
|
||||
(function () {
|
||||
var file = items[i].getAsFile ? items[i].getAsFile() : items[i];
|
||||
|
||||
if (file) {
|
||||
_this3.range = _this3.quill.getSelection();
|
||||
evt.preventDefault();
|
||||
setTimeout(function () {
|
||||
_this3.range = _this3.quill.getSelection();
|
||||
_this3.readAndUploadFile(file);
|
||||
}, 0);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "readAndUploadFile",
|
||||
value: function readAndUploadFile(file) {
|
||||
var _this4 = this;
|
||||
|
||||
var isUploadReject = false;
|
||||
|
||||
var fileReader = new FileReader();
|
||||
|
||||
fileReader.addEventListener("load", function () {
|
||||
if (!isUploadReject) {
|
||||
var base64ImageSrc = fileReader.result;
|
||||
_this4.insertBase64Image(base64ImageSrc);
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (file) {
|
||||
fileReader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
this.options.upload(file).then(function (imageUrl) {
|
||||
_this4.insertToEditor(imageUrl);
|
||||
}, function (error) {
|
||||
isUploadReject = true;
|
||||
_this4.removeBase64Image();
|
||||
console.warn(error);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "fileChanged",
|
||||
value: function fileChanged() {
|
||||
var file = this.fileHolder.files[0];
|
||||
this.readAndUploadFile(file);
|
||||
}
|
||||
}, {
|
||||
key: "insertBase64Image",
|
||||
value: function insertBase64Image(url) {
|
||||
var range = this.range;
|
||||
|
||||
this.quill.insertEmbed(range.index, _blots_image_js__WEBPACK_IMPORTED_MODULE_0__["default"].blotName, "" + url, "user");
|
||||
}
|
||||
}, {
|
||||
key: "insertToEditor",
|
||||
value: function insertToEditor(url) {
|
||||
var range = this.range;
|
||||
// Delete the placeholder image
|
||||
|
||||
this.quill.deleteText(range.index, 3, "user");
|
||||
// Insert the server saved image
|
||||
this.quill.insertEmbed(range.index, "image", "" + url, "user");
|
||||
|
||||
range.index++;
|
||||
this.quill.setSelection(range, "user");
|
||||
}
|
||||
}, {
|
||||
key: "removeBase64Image",
|
||||
value: function removeBase64Image() {
|
||||
var range = this.range;
|
||||
|
||||
this.quill.deleteText(range.index, 3, "user");
|
||||
}
|
||||
}]);
|
||||
|
||||
return ImageUploader;
|
||||
}();
|
||||
|
||||
window.ImageUploader = ImageUploader;
|
||||
/* harmony default export */ __webpack_exports__["default"] = (ImageUploader);
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var quill__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
||||
/* harmony import */ var quill__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(quill__WEBPACK_IMPORTED_MODULE_0__);
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
|
||||
|
||||
var InlineBlot = quill__WEBPACK_IMPORTED_MODULE_0___default.a.import('blots/block');
|
||||
|
||||
var LoadingImage = function (_InlineBlot) {
|
||||
_inherits(LoadingImage, _InlineBlot);
|
||||
|
||||
function LoadingImage() {
|
||||
_classCallCheck(this, LoadingImage);
|
||||
|
||||
return _possibleConstructorReturn(this, (LoadingImage.__proto__ || Object.getPrototypeOf(LoadingImage)).apply(this, arguments));
|
||||
}
|
||||
|
||||
_createClass(LoadingImage, [{
|
||||
key: 'deleteAt',
|
||||
value: function deleteAt(index, length) {
|
||||
_get(LoadingImage.prototype.__proto__ || Object.getPrototypeOf(LoadingImage.prototype), 'deleteAt', this).call(this, index, length);
|
||||
this.cache = {};
|
||||
}
|
||||
}], [{
|
||||
key: 'create',
|
||||
value: function create(src) {
|
||||
var node = _get(LoadingImage.__proto__ || Object.getPrototypeOf(LoadingImage), 'create', this).call(this, src);
|
||||
if (src === true) return node;
|
||||
|
||||
var image = document.createElement('img');
|
||||
image.setAttribute('src', src);
|
||||
node.appendChild(image);
|
||||
return node;
|
||||
}
|
||||
}, {
|
||||
key: 'value',
|
||||
value: function value(domNode) {
|
||||
var _domNode$dataset = domNode.dataset,
|
||||
src = _domNode$dataset.src,
|
||||
custom = _domNode$dataset.custom;
|
||||
|
||||
return { src: src, custom: custom };
|
||||
}
|
||||
}]);
|
||||
|
||||
return LoadingImage;
|
||||
}(InlineBlot);
|
||||
|
||||
LoadingImage.blotName = 'imageBlot';
|
||||
LoadingImage.className = 'quill-image-uploading';
|
||||
LoadingImage.tagName = 'span';
|
||||
quill__WEBPACK_IMPORTED_MODULE_0___default.a.register({ 'formats/imageBlot': LoadingImage });
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (LoadingImage);
|
||||
|
||||
/***/ }),
|
||||
/* 2 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = Quill;
|
||||
|
||||
/***/ }),
|
||||
/* 3 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
// removed by extract-text-webpack-plugin
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
1
app/assets/javascripts/activeadmin/quill.imageUploader.min.js
поставляемый
Обычный файл
1
app/assets/javascripts/activeadmin/quill.imageUploader.min.js
поставляемый
Обычный файл
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
8
app/assets/javascripts/activeadmin/quill_editor/quill.min.js
поставляемый
8
app/assets/javascripts/activeadmin/quill_editor/quill.min.js
поставляемый
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
@@ -1,49 +1,123 @@
|
||||
window.onload = function () {
|
||||
initQuillEditors();
|
||||
}
|
||||
/* globals $ Quill ImageUploader */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
$(document).on('has_many_add:after', function() {
|
||||
initQuillEditors();
|
||||
});
|
||||
// --- functions ---------------------------------------------------------------
|
||||
const initQuillEditors = () => {
|
||||
const defaultTheme = 'snow';
|
||||
const defaultToolbar = [
|
||||
['bold', 'italic', 'underline'],
|
||||
['link', 'blockquote', 'code-block'],
|
||||
[{ 'script': 'sub' }, { 'script': 'super' }],
|
||||
[{ 'align': [] }, { list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
['image'],
|
||||
['clean'],
|
||||
];
|
||||
const editors = document.querySelectorAll('[data-aa-quill-editor]');
|
||||
const registeredPlugins = {};
|
||||
|
||||
var initQuillEditors = function() {
|
||||
var editors = document.querySelectorAll( '.quill-editor' );
|
||||
var default_options = {
|
||||
modules: {
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline'],
|
||||
['link', 'blockquote', 'code-block'],
|
||||
[{ 'script': 'sub'}, { 'script': 'super' }],
|
||||
[{ 'align': [] }, { list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
['clean'],
|
||||
// [{ 'size': ['small', false, 'large', 'huge'] }],
|
||||
// [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
|
||||
]
|
||||
},
|
||||
placeholder: '',
|
||||
theme: 'snow'
|
||||
for (let i = 0; i < editors.length; i++) {
|
||||
const content = editors[i].querySelector('[data-aa-quill-content]');
|
||||
const isActive = editors[i].classList.contains('quill-editor--active');
|
||||
|
||||
if (content && !isActive) {
|
||||
// Setup editor options
|
||||
const options = editors[i].getAttribute('data-options') ? JSON.parse(editors[i].getAttribute('data-options')) : {};
|
||||
|
||||
if (!options.theme) options.theme = defaultTheme;
|
||||
if (!options.modules) options.modules = {};
|
||||
if (!options.modules.toolbar) options.modules.toolbar = defaultToolbar;
|
||||
|
||||
// Setup plugin options
|
||||
const pluginOptions = editors[i].getAttribute('data-plugins') ? JSON.parse(editors[i].getAttribute('data-plugins')) : {};
|
||||
|
||||
if (pluginOptions.image_uploader && pluginOptions.image_uploader.server_url) {
|
||||
if (!registeredPlugins.image_uploader) {
|
||||
Quill.register('modules/imageUploader', ImageUploader);
|
||||
registeredPlugins.image_uploader = true;
|
||||
}
|
||||
const opts = pluginOptions.image_uploader;
|
||||
|
||||
options.modules.imageUploader = setupImageUploader(opts.server_url, opts.field_name);
|
||||
}
|
||||
|
||||
// Init editor
|
||||
editors[i]['_quill-editor'] = new Quill(content, options);
|
||||
editors[i].classList += ' quill-editor--active';
|
||||
}
|
||||
}
|
||||
|
||||
const formtastic = document.querySelector('form.formtastic');
|
||||
|
||||
if (formtastic) {
|
||||
formtastic.onsubmit = () => {
|
||||
for (let i = 0; i < editors.length; i++) {
|
||||
const input = editors[i].querySelector('input[type="hidden"]');
|
||||
|
||||
if (editors[i]['_quill-editor'].editor.isBlank()) {
|
||||
input.value = '';
|
||||
} else {
|
||||
input.value = editors[i]['_quill-editor'].root.innerHTML;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
for( var i = 0; i < editors.length; i++ ) {
|
||||
var content = editors[i].querySelector( '.quill-editor-content' );
|
||||
var isActive = editors[i].classList.contains('quill-editor--active');
|
||||
if( content && !isActive) {
|
||||
var options = editors[i].getAttribute( 'data-options' ) ? JSON.parse( editors[i].getAttribute( 'data-options' ) ) : default_options;
|
||||
editors[i]['_quill-editor'] = new Quill( content, options );
|
||||
editors[i].classList += ' quill-editor--active';
|
||||
const setupImageUploader = (server_url, field_name) => {
|
||||
return {
|
||||
upload: (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append(field_name || 'file_upload', file);
|
||||
fetch(server_url, {
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
},
|
||||
method: 'POST'
|
||||
}).then(response => response.json())
|
||||
.then(result => {
|
||||
if (!result.url) {
|
||||
reject('Upload failed');
|
||||
}
|
||||
resolve(result.url);
|
||||
})
|
||||
.catch(error => {
|
||||
reject('Upload failed');
|
||||
console.error('Error: ', error);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var formtastic = document.querySelector( 'form.formtastic' );
|
||||
if( formtastic ) {
|
||||
formtastic.onsubmit = function() {
|
||||
for( var i = 0; i < editors.length; i++ ) {
|
||||
var input = editors[i].querySelector( 'input[type="hidden"]' );
|
||||
input.value = editors[i]['_quill-editor'].root.innerHTML;
|
||||
// input.value = editors[i]['_quill-editor'].getContents();
|
||||
// input.value = editors[i].querySelector( '.quill-editor-content' ).innerHTML;
|
||||
}
|
||||
};
|
||||
// --- public functions --------------------------------------------------------
|
||||
window.getQuillEditors = function() {
|
||||
const editors = document.querySelectorAll('[data-aa-quill-editor]');
|
||||
const list = [];
|
||||
|
||||
editors.forEach(function(editor) { list.push(editor['_quill-editor']) });
|
||||
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
window.getQuillEditorByIndex = function(index) {
|
||||
const editors = document.querySelectorAll('[data-aa-quill-editor]');
|
||||
|
||||
return (index >= 0 && index < editors.length) ? editors[index]['_quill-editor'] : null;
|
||||
}
|
||||
|
||||
window.getQuillEditorByElementId = function(id) {
|
||||
const editor = document.querySelector(`[data-aa-quill-editor]#${id}`);
|
||||
|
||||
return editor ? editor['_quill-editor'] : null;
|
||||
}
|
||||
|
||||
// --- events ------------------------------------------------------------------
|
||||
$(document).ready(initQuillEditors);
|
||||
$(document).on('has_many_add:after', '.has_many_container', initQuillEditors);
|
||||
$(document).on('turbolinks:load', initQuillEditors);
|
||||
})();
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
@import 'activeadmin/quill_editor/quill.snow'
|
||||
|
||||
body.active_admin form .quill-editor
|
||||
display: inline-block
|
||||
width: calc(80% - 22px)
|
||||
.ql-editor
|
||||
background-color: #fff
|
||||
max-height: 300px
|
||||
min-height: 150px
|
||||
padding: 10px
|
||||
// reset internal elements
|
||||
*
|
||||
margin: initial
|
||||
padding: initial
|
||||
text-align: initial
|
||||
p
|
||||
margin-bottom: 1em
|
||||
ol
|
||||
list-style-type: decimal
|
||||
ul
|
||||
list-style-type: disc
|
||||
ul, ol
|
||||
margin: 0 1.5em 1.5em 0
|
||||
padding-left: 1.5em
|
||||
56
app/assets/stylesheets/activeadmin/_quill_editor_input.scss
Обычный файл
56
app/assets/stylesheets/activeadmin/_quill_editor_input.scss
Обычный файл
@@ -0,0 +1,56 @@
|
||||
// reset internal elements
|
||||
.ql-editor * {
|
||||
margin: initial;
|
||||
padding: initial;
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
body.active_admin [data-aa-quill-editor] {
|
||||
display: inline-block;
|
||||
width: calc(80% - 2px);
|
||||
|
||||
button {
|
||||
text-shadow: none;
|
||||
box-shadow: none;
|
||||
|
||||
&:hover {
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.ql-container {
|
||||
border: 1px solid #c9d0d6;
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
background-color: #fff;
|
||||
max-height: 300px;
|
||||
min-height: 150px;
|
||||
padding: 10px;
|
||||
word-break: break-all;
|
||||
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin: 0 1.5em 1.5em 0;
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.ql-toolbar {
|
||||
border: 1px solid #c9d0d6;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
}
|
||||
33
app/assets/stylesheets/activeadmin/quill.imageUploader.min.css
поставляемый
Обычный файл
33
app/assets/stylesheets/activeadmin/quill.imageUploader.min.css
поставляемый
Обычный файл
@@ -0,0 +1,33 @@
|
||||
.quill-image-uploading {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.quill-image-uploading img {
|
||||
max-width: 98% !important;
|
||||
filter: blur(5px);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.quill-image-uploading::before {
|
||||
content: "";
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: -15px;
|
||||
margin-left: -15px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid #ccc;
|
||||
border-top-color: #1e40af;
|
||||
z-index: 1;
|
||||
animation: spinner 0.6s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spinner {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
29
bin/fasterer
Исполняемый файл
29
bin/fasterer
Исполняемый файл
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# This file was generated by Bundler.
|
||||
#
|
||||
# The application 'fasterer' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
|
||||
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
load Gem.bin_path("fasterer", "fasterer")
|
||||
16
bin/rails
Исполняемый файл
16
bin/rails
Исполняемый файл
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env ruby
|
||||
# This command will automatically be run when you run "rails" with Rails gems
|
||||
# installed from the root of your application.
|
||||
|
||||
ENV['RAILS_ENV'] ||= 'development'
|
||||
|
||||
ENGINE_ROOT = File.expand_path('..', __dir__)
|
||||
ENGINE_PATH = File.expand_path('../lib/activeadmin/quill_editor/engine', __dir__)
|
||||
APP_PATH = File.expand_path('../spec/dummy/config/application', __dir__)
|
||||
|
||||
# Set up gems listed in the Gemfile.
|
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
||||
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
||||
|
||||
require 'rails/all'
|
||||
require 'rails/engine/commands'
|
||||
29
bin/rake
Исполняемый файл
29
bin/rake
Исполняемый файл
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# This file was generated by Bundler.
|
||||
#
|
||||
# The application 'rake' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
|
||||
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
load Gem.bin_path("rake", "rake")
|
||||
29
bin/rspec
Исполняемый файл
29
bin/rspec
Исполняемый файл
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# This file was generated by Bundler.
|
||||
#
|
||||
# The application 'rspec' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
|
||||
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
load Gem.bin_path("rspec-core", "rspec")
|
||||
29
bin/rubocop
Исполняемый файл
29
bin/rubocop
Исполняемый файл
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# This file was generated by Bundler.
|
||||
#
|
||||
# The application 'rubocop' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
|
||||
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
load Gem.bin_path("rubocop", "rubocop")
|
||||
73
examples/upload_plugin_using_activestorage/app/admin/posts.rb
Обычный файл
73
examples/upload_plugin_using_activestorage/app/admin/posts.rb
Обычный файл
@@ -0,0 +1,73 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Post do
|
||||
permit_params :author_id,
|
||||
:title,
|
||||
:description,
|
||||
:category,
|
||||
:dt,
|
||||
:position,
|
||||
:published,
|
||||
tag_ids: []
|
||||
|
||||
member_action :upload, method: [:post] do
|
||||
result = { success: resource.images.attach(params[:file_upload]) }
|
||||
result[:url] = url_for(resource.images.last) if result[:success]
|
||||
render json: result
|
||||
end
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
id_column
|
||||
column :title
|
||||
column :author
|
||||
column :published
|
||||
column :created_at
|
||||
actions
|
||||
end
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row :author
|
||||
row :title
|
||||
row :description
|
||||
row :category
|
||||
row :dt
|
||||
row :position
|
||||
row :published
|
||||
row :tags
|
||||
row :created_at
|
||||
row :updated_at
|
||||
row :images do |resurce|
|
||||
resurce.images.each do |image|
|
||||
div do
|
||||
link_to image.filename, image, target: '_blank', rel: 'noopener'
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
active_admin_comments
|
||||
end
|
||||
|
||||
form do |f|
|
||||
f.inputs 'Post' do
|
||||
f.input :author
|
||||
f.input :title
|
||||
unless object.new_record?
|
||||
plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
|
||||
f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
|
||||
end
|
||||
f.input :category
|
||||
f.input :dt
|
||||
f.input :position
|
||||
f.input :published
|
||||
end
|
||||
|
||||
f.inputs 'Tags' do
|
||||
f.input :tags
|
||||
end
|
||||
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
//= require active_admin/base
|
||||
|
||||
//= require activeadmin/quill_editor/quill
|
||||
//= require activeadmin/quill_editor_input
|
||||
|
||||
//= require activeadmin/quill.imageUploader.min
|
||||
@@ -0,0 +1,7 @@
|
||||
@import 'active_admin/mixins';
|
||||
@import 'active_admin/base';
|
||||
|
||||
@import 'activeadmin/quill_editor/quill.snow';
|
||||
@import 'activeadmin/quill_editor_input';
|
||||
|
||||
@import 'activeadmin/quill.imageUploader.min';
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Post < ApplicationRecord
|
||||
has_many_attached :images
|
||||
|
||||
validates :title, allow_blank: false, presence: true
|
||||
end
|
||||
3
extra/.bashrc
Обычный файл
3
extra/.bashrc
Обычный файл
@@ -0,0 +1,3 @@
|
||||
alias ls='ls --color'
|
||||
alias ll='ls -l'
|
||||
alias la='ls -la'
|
||||
7
extra/.env
Обычный файл
7
extra/.env
Обычный файл
@@ -0,0 +1,7 @@
|
||||
COMPOSE_PROJECT_NAME=activeadmin_quill_editor
|
||||
|
||||
BUNDLER_VERSION=2.5.23
|
||||
SERVER_PORT=4000
|
||||
|
||||
UID=1000
|
||||
GID=1000
|
||||
31
extra/Dockerfile
Обычный файл
31
extra/Dockerfile
Обычный файл
@@ -0,0 +1,31 @@
|
||||
ARG RUBY_IMAGE=ruby:3
|
||||
FROM ${RUBY_IMAGE}
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV DEVEL=1
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -yqq --no-install-recommends build-essential chromium less libyaml-dev nano netcat-traditional pkg-config
|
||||
|
||||
ARG BUNDLER_VERSION
|
||||
RUN gem install bundler -v ${BUNDLER_VERSION}
|
||||
RUN echo 'gem: --no-document' > /etc/gemrc
|
||||
|
||||
ARG UID
|
||||
RUN useradd -u $UID --shell /bin/bash app
|
||||
|
||||
RUN mkdir -p /home/app && chown -R app:app /home/app
|
||||
|
||||
ARG RAILS_VERSION
|
||||
ENV RAILS_VERSION=$RAILS_VERSION
|
||||
|
||||
ARG ACTIVEADMIN_VERSION
|
||||
ENV ACTIVEADMIN_VERSION=$ACTIVEADMIN_VERSION
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
RUN bundle install
|
||||
RUN chown -R app:app /usr/local/bundle
|
||||
|
||||
RUN ln -s /app/extra/.bashrc /home/app/.bashrc
|
||||
6
extra/Dockerfile.dockerignore
Обычный файл
6
extra/Dockerfile.dockerignore
Обычный файл
@@ -0,0 +1,6 @@
|
||||
# Ignore everything but the required files for bundle install
|
||||
/**/*
|
||||
|
||||
!/*.gemspec
|
||||
!/Gemfile
|
||||
!/lib
|
||||
6
extra/dev_setup.sh
Исполняемый файл
6
extra/dev_setup.sh
Исполняемый файл
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
export DEVEL=1
|
||||
|
||||
export RAILS_VERSION=7.2.2.1
|
||||
export ACTIVEADMIN_VERSION=3.3.0
|
||||
50
extra/development.md
Обычный файл
50
extra/development.md
Обычный файл
@@ -0,0 +1,50 @@
|
||||
## Development
|
||||
|
||||
### Dev setup
|
||||
|
||||
There are 2 ways to interact with this project:
|
||||
|
||||
1) Using Docker:
|
||||
|
||||
```sh
|
||||
make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN)
|
||||
make specs # run the tests (after up)
|
||||
make lint # run the linters (after up)
|
||||
make server # run the server (after up)
|
||||
make shell # open a shell (after up)
|
||||
make down # cleanup (after up)
|
||||
|
||||
# Example using specific versions:
|
||||
RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up
|
||||
```
|
||||
|
||||
2) With a local setup:
|
||||
|
||||
```sh
|
||||
# Dev setup (set the required envs):
|
||||
source extra/dev_setup.sh
|
||||
# Install dependencies:
|
||||
bundle update
|
||||
# Run server (or any command):
|
||||
bin/rails s
|
||||
# To try different versions of Rails/ActiveAdmin edit extra/dev_setup.sh
|
||||
```
|
||||
|
||||
### Update the editor
|
||||
|
||||
- Update the CSS/JS editor assets:
|
||||
|
||||
```sh
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.snow.css" -O "app/assets/stylesheets/activeadmin/quill_editor/quill.snow.css"
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.bubble.css" -O "app/assets/stylesheets/activeadmin/quill_editor/quill.bubble.css"
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.core.css" -O "app/assets/stylesheets/activeadmin/quill_editor/quill.core.css"
|
||||
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.js"
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.core.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.core.js"
|
||||
|
||||
wget "https://github.com/valentsea/quill2-image-uploader/raw/refs/heads/master/dist/quill.imageUploader.min.js" -O "app/assets/javascripts/activeadmin/quill.imageUploader.min.js"
|
||||
|
||||
wget "https://github.com/valentsea/quill2-image-uploader/raw/refs/heads/master/dist/quill.imageUploader.min.css" -O "app/assets/stylesheets/activeadmin/quill.imageUploader.min.css"
|
||||
```
|
||||
|
||||
- Check the changes, most of them should be for updated files plus some new / removed file
|
||||
19
extra/docker-compose.yml
Обычный файл
19
extra/docker-compose.yml
Обычный файл
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: extra/Dockerfile
|
||||
args:
|
||||
BUNDLER_VERSION: ${BUNDLER_VERSION}
|
||||
RUBY_IMAGE: ruby:${RUBY:-3.4}-slim
|
||||
RAILS_VERSION: ${RAILS:-}
|
||||
ACTIVEADMIN_VERSION: ${ACTIVEADMIN:-}
|
||||
UID: ${UID}
|
||||
user: ${UID}:${GID}
|
||||
ports:
|
||||
- ${SERVER_PORT}:${SERVER_PORT}
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ..:/app
|
||||
stdin_open: true
|
||||
tty: true
|
||||
Двоичные данные
extra/screenshot.png
Обычный файл
Двоичные данные
extra/screenshot.png
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 52 KiB |
7
index.js
Обычный файл
7
index.js
Обычный файл
@@ -0,0 +1,7 @@
|
||||
// Styles
|
||||
import 'activeadmin_quill_editor/app/assets/stylesheets/activeadmin/quill_editor/quill.snow'
|
||||
import 'activeadmin_quill_editor/app/assets/stylesheets/activeadmin/_quill_editor_input'
|
||||
|
||||
// JS
|
||||
window.Quill = require('activeadmin_quill_editor/app/assets/javascripts/activeadmin/quill_editor/quill')
|
||||
require('activeadmin_quill_editor/app/assets/javascripts/activeadmin/quill_editor_input')
|
||||
@@ -1 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'activeadmin/quill_editor/engine'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'active_admin'
|
||||
|
||||
module ActiveAdmin
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ActiveAdmin
|
||||
module QuillEditor
|
||||
VERSION = '0.1.4'
|
||||
VERSION = '2.0.0'
|
||||
QUILL_VERSION = '2.0.3'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'activeadmin/quill_editor'
|
||||
|
||||
require 'formtastic/inputs/quill_editor_input'
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Formtastic
|
||||
module Inputs
|
||||
class QuillEditorInput < Formtastic::Inputs::TextInput
|
||||
def to_html
|
||||
input_wrapping do
|
||||
label_html <<
|
||||
template.content_tag( :div, input_html_options.merge( class: 'quill-editor' ) ) do
|
||||
builder.hidden_field( input_name ) <<
|
||||
template.content_tag( :div, class: 'quill-editor-content' ) do
|
||||
object.send( method ).try :html_safe
|
||||
template.content_tag(:div, input_html_options.merge('data-aa-quill-editor': '1')) do
|
||||
builder.hidden_field(input_name) <<
|
||||
template.content_tag(:div, 'data-aa-quill-content': '1') do
|
||||
object.send(method).try :html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
18
package.json
Обычный файл
18
package.json
Обычный файл
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "activeadmin_quill_editor",
|
||||
"version": "2.0.0",
|
||||
"description": "Quill Editor for ActiveAdmin",
|
||||
"author": "Mattia Roccoberton <mat@blocknot.es>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/blocknotes/activeadmin_quill_editor",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"app/**/*",
|
||||
"index.js"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.22.0",
|
||||
"eslint": "^9.22.0",
|
||||
"globals": "^16.0.0"
|
||||
}
|
||||
}
|
||||
Двоичные данные
screenshot.jpg
Двоичные данные
screenshot.jpg
Двоичный файл не отображается.
|
До Ширина: | Высота: | Размер: 33 KiB |
6
spec/dummy/Rakefile
Обычный файл
6
spec/dummy/Rakefile
Обычный файл
@@ -0,0 +1,6 @@
|
||||
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||
|
||||
require_relative 'config/application'
|
||||
|
||||
Rails.application.load_tasks
|
||||
57
spec/dummy/app/admin/authors.rb
Обычный файл
57
spec/dummy/app/admin/authors.rb
Обычный файл
@@ -0,0 +1,57 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Author do
|
||||
permit_params :name,
|
||||
:email,
|
||||
:age,
|
||||
:avatar,
|
||||
profile_attributes: %i[id description _destroy],
|
||||
posts_attributes: %i[id title description]
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
id_column
|
||||
column :name
|
||||
column :email
|
||||
column :created_at
|
||||
actions
|
||||
end
|
||||
|
||||
filter :name
|
||||
filter :created_at
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row :name
|
||||
row :email
|
||||
row :age
|
||||
row :avatar do |record|
|
||||
image_tag url_for(record.avatar), style: 'max-width:800px;max-height:500px' if record.avatar.attached?
|
||||
end
|
||||
row :created_at
|
||||
row :updated_at
|
||||
row :profile
|
||||
row :posts
|
||||
end
|
||||
active_admin_comments
|
||||
end
|
||||
|
||||
form do |f|
|
||||
f.inputs do
|
||||
f.input :name
|
||||
f.input :email
|
||||
f.input :age
|
||||
f.input :avatar,
|
||||
as: :file,
|
||||
hint: (object.avatar.attached? ? "Current: #{object.avatar.filename}" : nil)
|
||||
end
|
||||
f.has_many :profile, allow_destroy: true do |ff|
|
||||
ff.input :description
|
||||
end
|
||||
f.has_many :posts do |fp|
|
||||
fp.input :title
|
||||
fp.input :description, as: :quill_editor
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
32
spec/dummy/app/admin/dashboard.rb
Обычный файл
32
spec/dummy/app/admin/dashboard.rb
Обычный файл
@@ -0,0 +1,32 @@
|
||||
ActiveAdmin.register_page "Dashboard" do
|
||||
menu priority: 1, label: proc { I18n.t("active_admin.dashboard") }
|
||||
|
||||
content title: proc { I18n.t("active_admin.dashboard") } do
|
||||
div class: "blank_slate_container", id: "dashboard_default_message" do
|
||||
span class: "blank_slate" do
|
||||
span I18n.t("active_admin.dashboard_welcome.welcome")
|
||||
small I18n.t("active_admin.dashboard_welcome.call_to_action")
|
||||
end
|
||||
end
|
||||
|
||||
# Here is an example of a simple dashboard with columns and panels.
|
||||
#
|
||||
# columns do
|
||||
# column do
|
||||
# panel "Recent Posts" do
|
||||
# ul do
|
||||
# Post.recent(5).map do |post|
|
||||
# li link_to(post.title, admin_post_path(post))
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
# column do
|
||||
# panel "Info" do
|
||||
# para "Welcome to ActiveAdmin."
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
end # content
|
||||
end
|
||||
71
spec/dummy/app/admin/posts.rb
Обычный файл
71
spec/dummy/app/admin/posts.rb
Обычный файл
@@ -0,0 +1,71 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Post do
|
||||
permit_params :author_id, :title, :summary, :description, :category, :dt, :position, :published, tag_ids: []
|
||||
|
||||
member_action :upload, method: [:post] do
|
||||
result = { success: resource.images.attach(params[:file_upload]) }
|
||||
result[:url] = url_for(resource.images.last) if result[:success]
|
||||
render json: result
|
||||
end
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
id_column
|
||||
column :title
|
||||
column :author
|
||||
column :published
|
||||
column :created_at
|
||||
actions
|
||||
end
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row :author
|
||||
row :title
|
||||
row :summary
|
||||
row :description
|
||||
row :category
|
||||
row :dt
|
||||
row :position
|
||||
row :published
|
||||
row :tags
|
||||
row :created_at
|
||||
row :updated_at
|
||||
row :images do |resurce|
|
||||
resurce.images.each do |image|
|
||||
div do
|
||||
link_to image.filename, image, target: '_blank'
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
active_admin_comments
|
||||
end
|
||||
|
||||
form do |f|
|
||||
toolbar = %w[bold italic underline link]
|
||||
f.inputs 'Post' do
|
||||
f.input :author
|
||||
f.input :title
|
||||
f.input :summary, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: toolbar } } } }
|
||||
if object.new_record?
|
||||
f.input :description, as: :quill_editor # using default options
|
||||
else
|
||||
plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
|
||||
f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
|
||||
end
|
||||
f.input :category
|
||||
f.input :dt
|
||||
f.input :position
|
||||
f.input :published
|
||||
end
|
||||
|
||||
f.inputs 'Tags' do
|
||||
f.input :tags
|
||||
end
|
||||
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
5
spec/dummy/app/admin/profiles.rb
Обычный файл
5
spec/dummy/app/admin/profiles.rb
Обычный файл
@@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Profile do
|
||||
permit_params :author_id, :description
|
||||
end
|
||||
5
spec/dummy/app/admin/tags.rb
Обычный файл
5
spec/dummy/app/admin/tags.rb
Обычный файл
@@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Tag do
|
||||
permit_params :name
|
||||
end
|
||||
3
spec/dummy/app/assets/config/manifest.js
Обычный файл
3
spec/dummy/app/assets/config/manifest.js
Обычный файл
@@ -0,0 +1,3 @@
|
||||
//= link_tree ../images
|
||||
//= link_directory ../stylesheets .css
|
||||
// OFF link active_storage_db_manifest.js
|
||||
0
spec/dummy/app/assets/images/.keep
Обычный файл
0
spec/dummy/app/assets/images/.keep
Обычный файл
6
spec/dummy/app/assets/javascripts/active_admin.js
Обычный файл
6
spec/dummy/app/assets/javascripts/active_admin.js
Обычный файл
@@ -0,0 +1,6 @@
|
||||
//= require active_admin/base
|
||||
|
||||
//= require activeadmin/quill_editor/quill
|
||||
//= require activeadmin/quill_editor_input
|
||||
|
||||
//= require activeadmin/quill.imageUploader.min
|
||||
22
spec/dummy/app/assets/stylesheets/active_admin.scss
Обычный файл
22
spec/dummy/app/assets/stylesheets/active_admin.scss
Обычный файл
@@ -0,0 +1,22 @@
|
||||
// SASS variable overrides must be declared before loading up Active Admin's styles.
|
||||
//
|
||||
// To view the variables that Active Admin provides, take a look at
|
||||
// `app/assets/stylesheets/active_admin/mixins/_variables.scss` in the
|
||||
// Active Admin source.
|
||||
//
|
||||
// For example, to change the sidebar width:
|
||||
// $sidebar-width: 242px;
|
||||
|
||||
// Active Admin's got SASS!
|
||||
@import 'active_admin/mixins';
|
||||
@import 'active_admin/base';
|
||||
|
||||
@import 'activeadmin/quill_editor/quill.snow';
|
||||
@import 'activeadmin/quill_editor_input';
|
||||
|
||||
@import 'activeadmin/quill.imageUploader.min';
|
||||
|
||||
// Overriding any non-variable SASS must be done after the fact.
|
||||
// For example, to change the default status-tag color:
|
||||
//
|
||||
// .status_tag { background: #6090DB; }
|
||||
15
spec/dummy/app/assets/stylesheets/application.css
Обычный файл
15
spec/dummy/app/assets/stylesheets/application.css
Обычный файл
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
||||
* listed below.
|
||||
*
|
||||
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
||||
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
||||
*
|
||||
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
||||
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
||||
* files in this directory. Styles in this file should be added after the last require_* statement.
|
||||
* It is generally better to create a new file per style scope.
|
||||
*
|
||||
*= require_tree .
|
||||
*= require_self
|
||||
*/
|
||||
4
spec/dummy/app/channels/application_cable/channel.rb
Обычный файл
4
spec/dummy/app/channels/application_cable/channel.rb
Обычный файл
@@ -0,0 +1,4 @@
|
||||
module ApplicationCable
|
||||
class Channel < ActionCable::Channel::Base
|
||||
end
|
||||
end
|
||||
4
spec/dummy/app/channels/application_cable/connection.rb
Обычный файл
4
spec/dummy/app/channels/application_cable/connection.rb
Обычный файл
@@ -0,0 +1,4 @@
|
||||
module ApplicationCable
|
||||
class Connection < ActionCable::Connection::Base
|
||||
end
|
||||
end
|
||||
2
spec/dummy/app/controllers/application_controller.rb
Обычный файл
2
spec/dummy/app/controllers/application_controller.rb
Обычный файл
@@ -0,0 +1,2 @@
|
||||
class ApplicationController < ActionController::Base
|
||||
end
|
||||
0
spec/dummy/app/controllers/concerns/.keep
Обычный файл
0
spec/dummy/app/controllers/concerns/.keep
Обычный файл
2
spec/dummy/app/helpers/application_helper.rb
Обычный файл
2
spec/dummy/app/helpers/application_helper.rb
Обычный файл
@@ -0,0 +1,2 @@
|
||||
module ApplicationHelper
|
||||
end
|
||||
15
spec/dummy/app/javascript/packs/application.js
Обычный файл
15
spec/dummy/app/javascript/packs/application.js
Обычный файл
@@ -0,0 +1,15 @@
|
||||
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
||||
// listed below.
|
||||
//
|
||||
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
||||
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
||||
//
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
||||
//
|
||||
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
||||
// about supported directives.
|
||||
//
|
||||
//= require rails-ujs
|
||||
//= require activestorage
|
||||
//= require_tree .
|
||||
7
spec/dummy/app/jobs/application_job.rb
Обычный файл
7
spec/dummy/app/jobs/application_job.rb
Обычный файл
@@ -0,0 +1,7 @@
|
||||
class ApplicationJob < ActiveJob::Base
|
||||
# Automatically retry jobs that encountered a deadlock
|
||||
# retry_on ActiveRecord::Deadlocked
|
||||
|
||||
# Most jobs are safe to ignore if the underlying records are no longer available
|
||||
# discard_on ActiveJob::DeserializationError
|
||||
end
|
||||
4
spec/dummy/app/mailers/application_mailer.rb
Обычный файл
4
spec/dummy/app/mailers/application_mailer.rb
Обычный файл
@@ -0,0 +1,4 @@
|
||||
class ApplicationMailer < ActionMailer::Base
|
||||
default from: 'from@example.com'
|
||||
layout 'mailer'
|
||||
end
|
||||
7
spec/dummy/app/models/application_record.rb
Обычный файл
7
spec/dummy/app/models/application_record.rb
Обычный файл
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ApplicationRecord < ActiveRecord::Base
|
||||
self.abstract_class = true
|
||||
|
||||
scope :published, -> {}
|
||||
end
|
||||
32
spec/dummy/app/models/author.rb
Обычный файл
32
spec/dummy/app/models/author.rb
Обычный файл
@@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Author < ApplicationRecord
|
||||
has_many :posts
|
||||
has_many :published_posts, -> { published }, class_name: 'Post'
|
||||
has_many :recent_posts, -> { recents }, class_name: 'Post'
|
||||
|
||||
has_many :tags, through: :posts
|
||||
|
||||
has_one :profile, inverse_of: :author, dependent: :destroy
|
||||
|
||||
has_one_attached :avatar
|
||||
|
||||
accepts_nested_attributes_for :profile, allow_destroy: true
|
||||
accepts_nested_attributes_for :posts, allow_destroy: true
|
||||
|
||||
validates :email, format: { with: /\A[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\z/i, message: 'Invalid email' }
|
||||
|
||||
validate -> {
|
||||
errors.add( :base, 'Invalid age' ) if !age || age.to_i % 3 == 1
|
||||
}
|
||||
|
||||
def to_s
|
||||
"#{name} (#{age})"
|
||||
end
|
||||
|
||||
class << self
|
||||
def ransackable_attributes(_auth_object = nil)
|
||||
%w[age created_at email id name updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
0
spec/dummy/app/models/concerns/.keep
Обычный файл
0
spec/dummy/app/models/concerns/.keep
Обычный файл
37
spec/dummy/app/models/post.rb
Обычный файл
37
spec/dummy/app/models/post.rb
Обычный файл
@@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Post < ApplicationRecord
|
||||
belongs_to :author, inverse_of: :posts, autosave: true
|
||||
|
||||
has_one :author_profile, through: :author, source: :profile
|
||||
|
||||
has_many :post_tags, inverse_of: :post, dependent: :destroy
|
||||
has_many :tags, through: :post_tags
|
||||
|
||||
has_many_attached :images
|
||||
|
||||
accepts_nested_attributes_for :post_tags, allow_destroy: true
|
||||
|
||||
validates :title, allow_blank: false, presence: true
|
||||
|
||||
scope :published, -> { where(published: true) }
|
||||
scope :recents, -> { where('created_at > ?', Date.today - 8.month) }
|
||||
|
||||
def short_title
|
||||
title.truncate 10
|
||||
end
|
||||
|
||||
def upper_title
|
||||
title.upcase
|
||||
end
|
||||
|
||||
class << self
|
||||
def ransackable_associations(_auth_object = nil)
|
||||
%w[author author_profile post_tags tags images_attachments images_blobs]
|
||||
end
|
||||
|
||||
def ransackable_attributes(_auth_object = nil)
|
||||
%w[author_id category created_at description dt id position published title summary updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
15
spec/dummy/app/models/post_tag.rb
Обычный файл
15
spec/dummy/app/models/post_tag.rb
Обычный файл
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class PostTag < ApplicationRecord
|
||||
belongs_to :post, inverse_of: :post_tags
|
||||
belongs_to :tag, inverse_of: :post_tags
|
||||
|
||||
validates :post, presence: true
|
||||
validates :tag, presence: true
|
||||
|
||||
class << self
|
||||
def ransackable_attributes(auth_object = nil)
|
||||
%w[created_at id post_id tag_id updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
19
spec/dummy/app/models/profile.rb
Обычный файл
19
spec/dummy/app/models/profile.rb
Обычный файл
@@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Profile < ApplicationRecord
|
||||
belongs_to :author, inverse_of: :profile, touch: true
|
||||
|
||||
def to_s
|
||||
description
|
||||
end
|
||||
|
||||
class << self
|
||||
def ransackable_associations(_auth_object = nil)
|
||||
%w[author]
|
||||
end
|
||||
|
||||
def ransackable_attributes(_auth_object = nil)
|
||||
%w[author_id created_at description id updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
16
spec/dummy/app/models/tag.rb
Обычный файл
16
spec/dummy/app/models/tag.rb
Обычный файл
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Tag < ApplicationRecord
|
||||
has_many :post_tags, inverse_of: :tag, dependent: :destroy
|
||||
has_many :posts, through: :post_tags
|
||||
|
||||
class << self
|
||||
def ransackable_associations(auth_object = nil)
|
||||
%w[post_tags posts]
|
||||
end
|
||||
|
||||
def ransackable_attributes(auth_object = nil)
|
||||
%w[created_at id id_value name updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
14
spec/dummy/app/views/layouts/application.html.erb
Обычный файл
14
spec/dummy/app/views/layouts/application.html.erb
Обычный файл
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dummy</title>
|
||||
<%= csrf_meta_tags %>
|
||||
<%= csp_meta_tag %>
|
||||
|
||||
<%= stylesheet_link_tag 'application', media: 'all' %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= yield %>
|
||||
</body>
|
||||
</html>
|
||||
13
spec/dummy/app/views/layouts/mailer.html.erb
Обычный файл
13
spec/dummy/app/views/layouts/mailer.html.erb
Обычный файл
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<style>
|
||||
/* Email styles need to be inline */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= yield %>
|
||||
</body>
|
||||
</html>
|
||||
1
spec/dummy/app/views/layouts/mailer.text.erb
Обычный файл
1
spec/dummy/app/views/layouts/mailer.text.erb
Обычный файл
@@ -0,0 +1 @@
|
||||
<%= yield %>
|
||||
4
spec/dummy/bin/rails
Исполняемый файл
4
spec/dummy/bin/rails
Исполняемый файл
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env ruby
|
||||
APP_PATH = File.expand_path('../config/application', __dir__)
|
||||
require_relative '../config/boot'
|
||||
require 'rails/commands'
|
||||
4
spec/dummy/bin/rake
Исполняемый файл
4
spec/dummy/bin/rake
Исполняемый файл
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env ruby
|
||||
require_relative '../config/boot'
|
||||
require 'rake'
|
||||
Rake.application.run
|
||||
33
spec/dummy/bin/setup
Исполняемый файл
33
spec/dummy/bin/setup
Исполняемый файл
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env ruby
|
||||
require 'fileutils'
|
||||
|
||||
# path to your application root.
|
||||
APP_ROOT = File.expand_path('..', __dir__)
|
||||
|
||||
def system!(*args)
|
||||
system(*args) || abort("\n== Command #{args} failed ==")
|
||||
end
|
||||
|
||||
FileUtils.chdir APP_ROOT do
|
||||
# This script is a way to setup or update your development environment automatically.
|
||||
# This script is idempotent, so that you can run it at anytime and get an expectable outcome.
|
||||
# Add necessary setup steps to this file.
|
||||
|
||||
puts '== Installing dependencies =='
|
||||
system! 'gem install bundler --conservative'
|
||||
system('bundle check') || system!('bundle install')
|
||||
|
||||
# puts "\n== Copying sample files =="
|
||||
# unless File.exist?('config/database.yml')
|
||||
# FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
|
||||
# end
|
||||
|
||||
puts "\n== Preparing database =="
|
||||
system! 'bin/rails db:prepare'
|
||||
|
||||
puts "\n== Removing old logs and tempfiles =="
|
||||
system! 'bin/rails log:clear tmp:clear'
|
||||
|
||||
puts "\n== Restarting application server =="
|
||||
system! 'bin/rails restart'
|
||||
end
|
||||
5
spec/dummy/config.ru
Обычный файл
5
spec/dummy/config.ru
Обычный файл
@@ -0,0 +1,5 @@
|
||||
# This file is used by Rack-based servers to start the application.
|
||||
|
||||
require_relative 'config/environment'
|
||||
|
||||
run Rails.application
|
||||
23
spec/dummy/config/application.rb
Обычный файл
23
spec/dummy/config/application.rb
Обычный файл
@@ -0,0 +1,23 @@
|
||||
require_relative 'boot'
|
||||
|
||||
require 'rails/all'
|
||||
|
||||
Bundler.require(*Rails.groups)
|
||||
|
||||
module Dummy
|
||||
class Application < Rails::Application
|
||||
config.load_defaults Rails::VERSION::STRING.to_f
|
||||
|
||||
config.active_support.deprecation = :raise
|
||||
|
||||
if Gem::Version.new(Rails.version) < Gem::Version.new('7.1')
|
||||
config.active_record.legacy_connection_handling = false
|
||||
end
|
||||
|
||||
if Gem::Version.new(Rails.version) > Gem::Version.new('7.0')
|
||||
config.before_configuration do
|
||||
ActiveSupport::Cache.format_version = 7.0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
5
spec/dummy/config/boot.rb
Обычный файл
5
spec/dummy/config/boot.rb
Обычный файл
@@ -0,0 +1,5 @@
|
||||
# Set up gems listed in the Gemfile.
|
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
|
||||
|
||||
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
||||
$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
|
||||
10
spec/dummy/config/cable.yml
Обычный файл
10
spec/dummy/config/cable.yml
Обычный файл
@@ -0,0 +1,10 @@
|
||||
development:
|
||||
adapter: async
|
||||
|
||||
test:
|
||||
adapter: test
|
||||
|
||||
production:
|
||||
adapter: redis
|
||||
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
|
||||
channel_prefix: dummy_production
|
||||
13
spec/dummy/config/database.yml
Обычный файл
13
spec/dummy/config/database.yml
Обычный файл
@@ -0,0 +1,13 @@
|
||||
default: &default
|
||||
adapter: sqlite3
|
||||
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
||||
timeout: 5000
|
||||
|
||||
development:
|
||||
<<: *default
|
||||
database: db/development.sqlite3
|
||||
schema_dump: schema-dev.rb
|
||||
|
||||
test:
|
||||
<<: *default
|
||||
database: db/test.sqlite3
|
||||
5
spec/dummy/config/environment.rb
Обычный файл
5
spec/dummy/config/environment.rb
Обычный файл
@@ -0,0 +1,5 @@
|
||||
# Load the Rails application.
|
||||
require_relative 'application'
|
||||
|
||||
# Initialize the Rails application.
|
||||
Rails.application.initialize!
|
||||
66
spec/dummy/config/environments/development.rb
Обычный файл
66
spec/dummy/config/environments/development.rb
Обычный файл
@@ -0,0 +1,66 @@
|
||||
Rails.application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
# In the development environment your application's code is reloaded on
|
||||
# every request. This slows down response time but is perfect for development
|
||||
# since you don't have to restart the web server when you make code changes.
|
||||
config.cache_classes = false
|
||||
|
||||
# Do not eager load code on boot.
|
||||
config.eager_load = false
|
||||
|
||||
# Show full error reports.
|
||||
config.consider_all_requests_local = true
|
||||
|
||||
# Enable/disable caching. By default caching is disabled.
|
||||
# Run rails dev:cache to toggle caching.
|
||||
if Rails.root.join('tmp', 'caching-dev.txt').exist?
|
||||
config.action_controller.perform_caching = true
|
||||
config.action_controller.enable_fragment_cache_logging = true
|
||||
|
||||
config.cache_store = :memory_store
|
||||
config.public_file_server.headers = {
|
||||
'Cache-Control' => "public, max-age=#{2.days.to_i}"
|
||||
}
|
||||
else
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
config.cache_store = :null_store
|
||||
end
|
||||
|
||||
# Store uploaded files on the local file system (see config/storage.yml for options).
|
||||
config.active_storage.service = :local
|
||||
|
||||
# # Don't care if the mailer can't send.
|
||||
# config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
# config.action_mailer.perform_caching = false
|
||||
|
||||
# Print deprecation notices to the Rails logger.
|
||||
config.active_support.deprecation = :log
|
||||
|
||||
# Raise an error on page load if there are pending migrations.
|
||||
config.active_record.migration_error = :page_load
|
||||
|
||||
# Highlight code that triggered database queries in logs.
|
||||
config.active_record.verbose_query_logs = true
|
||||
|
||||
# Debug mode disables concatenation and preprocessing of assets.
|
||||
# This option may cause significant delays in view rendering with a large
|
||||
# number of complex assets.
|
||||
config.assets.debug = true
|
||||
|
||||
# Suppress logger output for asset requests.
|
||||
config.assets.quiet = true
|
||||
|
||||
# Raises error for missing translations.
|
||||
# config.action_view.raise_on_missing_translations = true
|
||||
|
||||
# Use an evented file watcher to asynchronously detect changes in source code,
|
||||
# routes, locales, etc. This feature depends on the listen gem.
|
||||
# config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
||||
|
||||
###
|
||||
|
||||
config.active_support.to_time_preserves_timezone = :zone if Gem::Version.new(Rails.version) >= Gem::Version.new('8.0')
|
||||
end
|
||||
53
spec/dummy/config/environments/test.rb
Обычный файл
53
spec/dummy/config/environments/test.rb
Обычный файл
@@ -0,0 +1,53 @@
|
||||
# The test environment is used exclusively to run your application's
|
||||
# test suite. You never need to work with it otherwise. Remember that
|
||||
# your test database is "scratch space" for the test suite and is wiped
|
||||
# and recreated between test runs. Don't rely on the data there!
|
||||
|
||||
Rails.application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
config.cache_classes = false
|
||||
config.action_view.cache_template_loading = true
|
||||
|
||||
# Do not eager load code on boot. This avoids loading your whole application
|
||||
# just for the purpose of running a single test. If you are using a tool that
|
||||
# preloads Rails for running tests, you may have to set it to true.
|
||||
config.eager_load = false
|
||||
|
||||
# Configure public file server for tests with Cache-Control for performance.
|
||||
config.public_file_server.enabled = true
|
||||
config.public_file_server.headers = {
|
||||
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
|
||||
}
|
||||
|
||||
# Show full error reports and disable caching.
|
||||
config.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
config.cache_store = :null_store
|
||||
|
||||
# Raise exceptions instead of rendering exception templates.
|
||||
config.action_dispatch.show_exceptions = :none
|
||||
|
||||
# Disable request forgery protection in test environment.
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
|
||||
# Store uploaded files on the local file system in a temporary directory.
|
||||
config.active_storage.service = :test
|
||||
|
||||
# config.action_mailer.perform_caching = false
|
||||
|
||||
# Tell Action Mailer not to deliver emails to the real world.
|
||||
# The :test delivery method accumulates sent emails in the
|
||||
# ActionMailer::Base.deliveries array.
|
||||
# config.action_mailer.delivery_method = :test
|
||||
|
||||
# Print deprecation notices to the stderr.
|
||||
config.active_support.deprecation = :stderr
|
||||
|
||||
# Raises error for missing translations.
|
||||
# config.action_view.raise_on_missing_translations = true
|
||||
|
||||
###
|
||||
|
||||
config.active_support.to_time_preserves_timezone = :zone if Gem::Version.new(Rails.version) >= Gem::Version.new('8.0')
|
||||
end
|
||||
335
spec/dummy/config/initializers/active_admin.rb
Обычный файл
335
spec/dummy/config/initializers/active_admin.rb
Обычный файл
@@ -0,0 +1,335 @@
|
||||
ActiveAdmin.setup do |config|
|
||||
# == Site Title
|
||||
#
|
||||
# Set the title that is displayed on the main layout
|
||||
# for each of the active admin pages.
|
||||
#
|
||||
config.site_title = "Dummy"
|
||||
|
||||
# Set the link url for the title. For example, to take
|
||||
# users to your main site. Defaults to no link.
|
||||
#
|
||||
# config.site_title_link = "/"
|
||||
|
||||
# Set an optional image to be displayed for the header
|
||||
# instead of a string (overrides :site_title)
|
||||
#
|
||||
# Note: Aim for an image that's 21px high so it fits in the header.
|
||||
#
|
||||
# config.site_title_image = "logo.png"
|
||||
|
||||
# == Default Namespace
|
||||
#
|
||||
# Set the default namespace each administration resource
|
||||
# will be added to.
|
||||
#
|
||||
# eg:
|
||||
# config.default_namespace = :hello_world
|
||||
#
|
||||
# This will create resources in the HelloWorld module and
|
||||
# will namespace routes to /hello_world/*
|
||||
#
|
||||
# To set no namespace by default, use:
|
||||
# config.default_namespace = false
|
||||
#
|
||||
# Default:
|
||||
# config.default_namespace = :admin
|
||||
#
|
||||
# You can customize the settings for each namespace by using
|
||||
# a namespace block. For example, to change the site title
|
||||
# within a namespace:
|
||||
#
|
||||
# config.namespace :admin do |admin|
|
||||
# admin.site_title = "Custom Admin Title"
|
||||
# end
|
||||
#
|
||||
# This will ONLY change the title for the admin section. Other
|
||||
# namespaces will continue to use the main "site_title" configuration.
|
||||
|
||||
# == User Authentication
|
||||
#
|
||||
# Active Admin will automatically call an authentication
|
||||
# method in a before filter of all controller actions to
|
||||
# ensure that there is a currently logged in admin user.
|
||||
#
|
||||
# This setting changes the method which Active Admin calls
|
||||
# within the application controller.
|
||||
# config.authentication_method = :authenticate_admin_user!
|
||||
|
||||
# == User Authorization
|
||||
#
|
||||
# Active Admin will automatically call an authorization
|
||||
# method in a before filter of all controller actions to
|
||||
# ensure that there is a user with proper rights. You can use
|
||||
# CanCanAdapter or make your own. Please refer to documentation.
|
||||
# config.authorization_adapter = ActiveAdmin::CanCanAdapter
|
||||
|
||||
# In case you prefer Pundit over other solutions you can here pass
|
||||
# the name of default policy class. This policy will be used in every
|
||||
# case when Pundit is unable to find suitable policy.
|
||||
# config.pundit_default_policy = "MyDefaultPunditPolicy"
|
||||
|
||||
# If you wish to maintain a separate set of Pundit policies for admin
|
||||
# resources, you may set a namespace here that Pundit will search
|
||||
# within when looking for a resource's policy.
|
||||
# config.pundit_policy_namespace = :admin
|
||||
|
||||
# You can customize your CanCan Ability class name here.
|
||||
# config.cancan_ability_class = "Ability"
|
||||
|
||||
# You can specify a method to be called on unauthorized access.
|
||||
# This is necessary in order to prevent a redirect loop which happens
|
||||
# because, by default, user gets redirected to Dashboard. If user
|
||||
# doesn't have access to Dashboard, he'll end up in a redirect loop.
|
||||
# Method provided here should be defined in application_controller.rb.
|
||||
# config.on_unauthorized_access = :access_denied
|
||||
|
||||
# == Current User
|
||||
#
|
||||
# Active Admin will associate actions with the current
|
||||
# user performing them.
|
||||
#
|
||||
# This setting changes the method which Active Admin calls
|
||||
# (within the application controller) to return the currently logged in user.
|
||||
# config.current_user_method = :current_admin_user
|
||||
|
||||
# == Logging Out
|
||||
#
|
||||
# Active Admin displays a logout link on each screen. These
|
||||
# settings configure the location and method used for the link.
|
||||
#
|
||||
# This setting changes the path where the link points to. If it's
|
||||
# a string, the strings is used as the path. If it's a Symbol, we
|
||||
# will call the method to return the path.
|
||||
#
|
||||
# Default:
|
||||
config.logout_link_path = :destroy_admin_user_session_path
|
||||
|
||||
# This setting changes the http method used when rendering the
|
||||
# link. For example :get, :delete, :put, etc..
|
||||
#
|
||||
# Default:
|
||||
# config.logout_link_method = :get
|
||||
|
||||
# == Root
|
||||
#
|
||||
# Set the action to call for the root path. You can set different
|
||||
# roots for each namespace.
|
||||
#
|
||||
# Default:
|
||||
# config.root_to = 'dashboard#index'
|
||||
|
||||
# == Admin Comments
|
||||
#
|
||||
# This allows your users to comment on any resource registered with Active Admin.
|
||||
#
|
||||
# You can completely disable comments:
|
||||
# config.comments = false
|
||||
#
|
||||
# You can change the name under which comments are registered:
|
||||
# config.comments_registration_name = 'AdminComment'
|
||||
#
|
||||
# You can change the order for the comments and you can change the column
|
||||
# to be used for ordering:
|
||||
# config.comments_order = 'created_at ASC'
|
||||
#
|
||||
# You can disable the menu item for the comments index page:
|
||||
# config.comments_menu = false
|
||||
#
|
||||
# You can customize the comment menu:
|
||||
# config.comments_menu = { parent: 'Admin', priority: 1 }
|
||||
|
||||
# == Batch Actions
|
||||
#
|
||||
# Enable and disable Batch Actions
|
||||
#
|
||||
config.batch_actions = true
|
||||
|
||||
# == Controller Filters
|
||||
#
|
||||
# You can add before, after and around filters to all of your
|
||||
# Active Admin resources and pages from here.
|
||||
#
|
||||
# config.before_action :do_something_awesome
|
||||
|
||||
# == Attribute Filters
|
||||
#
|
||||
# You can exclude possibly sensitive model attributes from being displayed,
|
||||
# added to forms, or exported by default by ActiveAdmin
|
||||
#
|
||||
config.filter_attributes = [:encrypted_password, :password, :password_confirmation]
|
||||
|
||||
# == Localize Date/Time Format
|
||||
#
|
||||
# Set the localize format to display dates and times.
|
||||
# To understand how to localize your app with I18n, read more at
|
||||
# https://guides.rubyonrails.org/i18n.html
|
||||
#
|
||||
# You can run `bin/rails runner 'puts I18n.t("date.formats")'` to see the
|
||||
# available formats in your application.
|
||||
#
|
||||
config.localize_format = :long
|
||||
|
||||
# == Setting a Favicon
|
||||
#
|
||||
# config.favicon = 'favicon.ico'
|
||||
|
||||
# == Meta Tags
|
||||
#
|
||||
# Add additional meta tags to the head element of active admin pages.
|
||||
#
|
||||
# Add tags to all pages logged in users see:
|
||||
# config.meta_tags = { author: 'My Company' }
|
||||
|
||||
# By default, sign up/sign in/recover password pages are excluded
|
||||
# from showing up in search engine results by adding a robots meta
|
||||
# tag. You can reset the hash of meta tags included in logged out
|
||||
# pages:
|
||||
# config.meta_tags_for_logged_out_pages = {}
|
||||
|
||||
# == Removing Breadcrumbs
|
||||
#
|
||||
# Breadcrumbs are enabled by default. You can customize them for individual
|
||||
# resources or you can disable them globally from here.
|
||||
#
|
||||
# config.breadcrumb = false
|
||||
|
||||
# == Create Another Checkbox
|
||||
#
|
||||
# Create another checkbox is disabled by default. You can customize it for individual
|
||||
# resources or you can enable them globally from here.
|
||||
#
|
||||
# config.create_another = true
|
||||
|
||||
# == Register Stylesheets & Javascripts
|
||||
#
|
||||
# We recommend using the built in Active Admin layout and loading
|
||||
# up your own stylesheets / javascripts to customize the look
|
||||
# and feel.
|
||||
#
|
||||
# To load a stylesheet:
|
||||
# config.register_stylesheet 'my_stylesheet.css'
|
||||
#
|
||||
# You can provide an options hash for more control, which is passed along to stylesheet_link_tag():
|
||||
# config.register_stylesheet 'my_print_stylesheet.css', media: :print
|
||||
#
|
||||
# To load a javascript file:
|
||||
# config.register_javascript 'my_javascript.js'
|
||||
|
||||
# == CSV options
|
||||
#
|
||||
# Set the CSV builder separator
|
||||
# config.csv_options = { col_sep: ';' }
|
||||
#
|
||||
# Force the use of quotes
|
||||
# config.csv_options = { force_quotes: true }
|
||||
|
||||
# == Menu System
|
||||
#
|
||||
# You can add a navigation menu to be used in your application, or configure a provided menu
|
||||
#
|
||||
# To change the default utility navigation to show a link to your website & a logout btn
|
||||
#
|
||||
# config.namespace :admin do |admin|
|
||||
# admin.build_menu :utility_navigation do |menu|
|
||||
# menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
|
||||
# admin.add_logout_button_to_menu menu
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# If you wanted to add a static menu item to the default menu provided:
|
||||
#
|
||||
# config.namespace :admin do |admin|
|
||||
# admin.build_menu :default do |menu|
|
||||
# menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
|
||||
# end
|
||||
# end
|
||||
|
||||
# == Download Links
|
||||
#
|
||||
# You can disable download links on resource listing pages,
|
||||
# or customize the formats shown per namespace/globally
|
||||
#
|
||||
# To disable/customize for the :admin namespace:
|
||||
#
|
||||
# config.namespace :admin do |admin|
|
||||
#
|
||||
# # Disable the links entirely
|
||||
# admin.download_links = false
|
||||
#
|
||||
# # Only show XML & PDF options
|
||||
# admin.download_links = [:xml, :pdf]
|
||||
#
|
||||
# # Enable/disable the links based on block
|
||||
# # (for example, with cancan)
|
||||
# admin.download_links = proc { can?(:view_download_links) }
|
||||
#
|
||||
# end
|
||||
|
||||
# == Pagination
|
||||
#
|
||||
# Pagination is enabled by default for all resources.
|
||||
# You can control the default per page count for all resources here.
|
||||
#
|
||||
# config.default_per_page = 30
|
||||
#
|
||||
# You can control the max per page count too.
|
||||
#
|
||||
# config.max_per_page = 10_000
|
||||
|
||||
# == Filters
|
||||
#
|
||||
# By default the index screen includes a "Filters" sidebar on the right
|
||||
# hand side with a filter for each attribute of the registered model.
|
||||
# You can enable or disable them for all resources here.
|
||||
#
|
||||
# config.filters = true
|
||||
#
|
||||
# By default the filters include associations in a select, which means
|
||||
# that every record will be loaded for each association (up
|
||||
# to the value of config.maximum_association_filter_arity).
|
||||
# You can enabled or disable the inclusion
|
||||
# of those filters by default here.
|
||||
#
|
||||
# config.include_default_association_filters = true
|
||||
|
||||
# config.maximum_association_filter_arity = 256 # default value of :unlimited will change to 256 in a future version
|
||||
# config.filter_columns_for_large_association, [
|
||||
# :display_name,
|
||||
# :full_name,
|
||||
# :name,
|
||||
# :username,
|
||||
# :login,
|
||||
# :title,
|
||||
# :email,
|
||||
# ]
|
||||
# config.filter_method_for_large_association, '_starts_with'
|
||||
|
||||
# == Head
|
||||
#
|
||||
# You can add your own content to the site head like analytics. Make sure
|
||||
# you only pass content you trust.
|
||||
#
|
||||
# config.head = ''.html_safe
|
||||
|
||||
# == Footer
|
||||
#
|
||||
# By default, the footer shows the current Active Admin version. You can
|
||||
# override the content of the footer here.
|
||||
#
|
||||
# config.footer = 'my custom footer text'
|
||||
|
||||
# == Sorting
|
||||
#
|
||||
# By default ActiveAdmin::OrderClause is used for sorting logic
|
||||
# You can inherit it with own class and inject it for all resources
|
||||
#
|
||||
# config.order_clause = MyOrderClause
|
||||
|
||||
# == Webpacker
|
||||
#
|
||||
# By default, Active Admin uses Sprocket's asset pipeline.
|
||||
# You can switch to using Webpacker here.
|
||||
#
|
||||
# config.use_webpacker = true
|
||||
end
|
||||
9
spec/dummy/config/initializers/active_storage.rb
Обычный файл
9
spec/dummy/config/initializers/active_storage.rb
Обычный файл
@@ -0,0 +1,9 @@
|
||||
Rails.application.reloader.to_prepare do
|
||||
ActiveStorage::Attachment.class_eval do
|
||||
class << self
|
||||
def ransackable_attributes(auth_object = nil)
|
||||
%w[blob_id created_at id name record_id record_type]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# ActiveSupport::Reloader.to_prepare do
|
||||
# ApplicationController.renderer.defaults.merge!(
|
||||
# http_host: 'example.org',
|
||||
# https: false
|
||||
# )
|
||||
# end
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user