136 Коммитов

Автор SHA1 Сообщение Дата
Mattia Roccoberton
f291f7e7e6 Merge pull request #62 from blocknotes/chore/bump-to-2.0.0
Bump version to 2.0.0
2025-04-16 22:02:34 +02:00
Mattia Roccoberton
df944277b5 chore: Bump version to 2.0.0 2025-04-16 12:55:31 +02:00
Mattia Roccoberton
3cc5683d44 Merge pull request #63 from blocknotes/chore/internal-improvements
Update Quill imageUploader plugin
2025-04-16 12:52:49 +02:00
Mattia Roccoberton
498cbbd0c9 build: Update Quill imageUploader 2025-04-16 09:03:32 +02:00
Mattia Roccoberton
bfc2e997f1 chore: Minor changes to dummy app migrations 2025-04-16 09:03:24 +02:00
Mattia Roccoberton
9bda446762 chore: internal improvements to quill editor input js 2025-04-16 08:52:13 +02:00
Mattia Roccoberton
533471c0d6 Merge pull request #61 from blocknotes/build/update-quill-to-2.0.3
Update Quill to version 2.0.3
2025-04-15 08:12:47 +02:00
Mattia Roccoberton
3617aab7f2 test: Improve some tests 2025-04-14 13:44:35 +02:00
Mattia Roccoberton
5196a8811a build: Update quill.imageUploader plugin 2025-04-14 13:44:35 +02:00
Mattia Roccoberton
5e9a3b6c5a build: Update Quill to version 2.0.3 2025-04-13 18:14:10 +02:00
Mattia Roccoberton
181aab7fd6 Merge pull request #60 from blocknotes/test/improve-tests
Improve tests
2025-04-13 16:36:07 +02:00
Mattia Roccoberton
300b4a0a03 test: Improve tests 2025-04-13 16:35:14 +02:00
Mattia Roccoberton
451a225277 Merge pull request #59 from blocknotes/build/improve-dev-setup
Improve dev and test setup
2025-04-13 15:04:13 +02:00
Mattia Roccoberton
6cbb39daad test: Improve test suite setup 2025-04-13 15:00:22 +02:00
Mattia Roccoberton
d19fc7ddfc build: Improve dev setup 2025-04-13 14:54:13 +02:00
Mattia Roccoberton
74790fc115 Merge pull request #58 from blocknotes/test/update-build-setup
test: Update build setup
2025-04-05 09:32:24 +02:00
Mattia Roccoberton
c3b129a212 ci: Update GitHub workflows 2025-04-05 09:25:11 +02:00
Mattia Roccoberton
ab858f7c6f test: Remove Appraisal dependency 2025-04-05 09:25:11 +02:00
Mattia Roccoberton
6cf744b84c test: Update build setup 2025-04-05 09:25:11 +02:00
Mattia Roccoberton
0ae4ce2035 Merge pull request #57 from blocknotes/test/setup-coverage
Test: setup coverage
2025-03-22 09:14:34 +01:00
Mattia Roccoberton
dd9aa22cf5 test: Install Appraisal dependencies 2025-03-22 09:10:47 +01:00
Mattia Roccoberton
b6f3c0c3a6 test: Setup coverage 2025-03-22 09:08:36 +01:00
Mattia Roccoberton
7d3a084977 Merge pull request #56 from blocknotes/v1.3.0
chore: Bump to version 1.3.0
2025-03-18 22:25:05 +01:00
Mattia Roccoberton
1569b1ff18 chore: Bump to version 1.3.0 2025-03-18 22:15:04 +01:00
Mattia Roccoberton
3459800dbf Merge pull request #55 from blocknotes/api/quill-editor-query-functions
API: Quill editor query functions
2025-03-18 08:49:00 +01:00
Mattia Roccoberton
af901f4f7d feat: API: expose quill editor query functions 2025-03-18 08:47:16 +01:00
Mattia Roccoberton
328ee0d9fa Merge pull request #54 from blocknotes/test/update-test-suite-2
test: Update test suite (2)
2025-03-17 09:08:23 +01:00
Mattia Roccoberton
751196ef8c test: Update dependencies 2025-03-17 09:06:04 +01:00
Mattia Roccoberton
589b782866 Merge pull request #53 from blocknotes/test/update-test-suite
test: Update test suite
2025-03-17 08:46:08 +01:00
Mattia Roccoberton
554f6086e7 test: Add Rails 8.0 workflow 2025-03-17 08:44:22 +01:00
Mattia Roccoberton
051ada9843 test: Add Rails 7.2 workflow 2025-03-17 08:35:44 +01:00
Mattia Roccoberton
fd90851a6b test: Update ruby versions in specs workflows 2025-03-17 08:30:59 +01:00
Mattia Roccoberton
bd32c5f28f Merge pull request #52 from blocknotes/test/improve-specs
test: Improve specs using page objects
2025-03-16 18:30:55 +01:00
Mattia Roccoberton
21ec7a918b chore: Update Rubocop config 2025-03-16 18:29:42 +01:00
Mattia Roccoberton
b310f9e71b test: Improve specs using page objects 2025-03-16 18:29:42 +01:00
Mattia Roccoberton
bbee6f7681 Merge pull request #51 from blocknotes/dev/docker-setup-2
Update Docker dev setup
2025-03-16 11:07:57 +01:00
Mattia Roccoberton
57e151aa03 test: Fix ProcessTimeoutError when using Docker
- Error details:

Ferrum::ProcessTimeoutError:
  Browser did not produce websocket url within 10 seconds, try to increase `:process_timeout`

- Reference issue: https://github.com/rubycdp/cuprite/issues/180
2025-03-16 11:05:57 +01:00
Mattia Roccoberton
0913bb6915 chore: Update Docker dev setup 2025-03-16 11:05:57 +01:00
Mattia Roccoberton
728e3fa097 Merge pull request #50 from blocknotes/dev/docker-setup
chore: Docker dev setup
2025-03-14 15:57:12 +01:00
Mattia Roccoberton
9d891f0602 chore: Docker dev setup 2025-03-14 15:54:58 +01:00
Mattia Roccoberton
21fc69c2c0 Merge pull request #49 from blocknotes/mat/update-github-actions
Update Github actions
2025-03-09 15:36:22 +01:00
Mattia Roccoberton
b0e770ca9e ci: update Github actions 2025-03-09 15:28:46 +01:00
Mattia Roccoberton
ba53f9febf Merge pull request #47 from Shyrokonis/main
Add check to prevent GET request for non-existent image after upload
2025-03-09 09:17:33 +01:00
Dmytro Shyrokonis
d690b9906f [Fix] Add reject for nil result url 2024-11-12 16:22:31 +01:00
Mattia Roccoberton
99908f97f7 Merge pull request #45 from blocknotes/chore/bump-to-version-1.2.0
chore: bump to version 1.2.0
2024-02-29 17:08:52 +01:00
Mattia Roccoberton
9389f9e32d chore: bump to version 1.2.0 2024-02-29 17:07:32 +01:00
Mattia Roccoberton
4629ac4133 Merge pull request #44 from blocknotes/doc/update-readme
doc: update README
2024-02-29 17:04:06 +01:00
Mattia Roccoberton
0d4485c321 doc: update readme 2024-02-29 17:03:10 +01:00
Mattia Roccoberton
0c1cfefa83 Merge pull request #43 from blocknotes/test/update-test-suite-config
test: update test suite config
2024-02-26 09:16:55 +01:00
Mattia Roccoberton
0c674025a9 test: update test suite config 2024-02-26 09:15:38 +01:00
Mattia Roccoberton
770e069442 Merge pull request #42 from blocknotes/refactor/update-minimum-ruby-version
refactor: update minimum Ruby version to 3.0
2024-02-25 16:11:37 +01:00
Mattia Roccoberton
d346729cd1 build: update Appraisals dependencies 2024-02-25 16:08:53 +01:00
Mattia Roccoberton
ce65cfbb7e refactor!: update minimum Ruby version to 3.0 2024-02-25 16:08:50 +01:00
Mattia Roccoberton
22a1c8714c Merge pull request #41 from blocknotes/chore/rename-master-branch-to-main
chore: rename master branch to main
2024-02-25 11:50:30 +01:00
Mattia Roccoberton
489e1c35eb chore: rename master branch to main 2024-02-25 11:46:50 +01:00
Mattia Roccoberton
62efca80d6 chore: bump to version 1.1.0 2023-08-20 21:37:32 +02:00
Mattia Roccoberton
46168cc7f8 Merge pull request #38 from blocknotes/chore/update-ci-config
chore: update tests config
2023-08-20 21:27:50 +02:00
Mattia Roccoberton
02310804aa chore: add Overcommit config 2023-08-20 21:23:48 +02:00
Mattia Roccoberton
7e2f8733dc chore: update CI ruby versions 2023-08-20 21:23:46 +02:00
Mattia Roccoberton
2d0a8f961f chore: update tests config 2023-08-20 21:11:30 +02:00
Mattia Roccoberton
7262ad5523 Merge pull request #36 from alejandroperea/allow-active-admin-3
Allow ActiveAdmin 3
2023-08-20 20:08:39 +02:00
Alejandro Perea
71f227736d Update Appraisal gemfiles 2023-08-20 17:53:02 +02:00
Mattia Roccoberton
361da5096d Update activeadmin_quill_editor.gemspec
I'm going on with the proposed changes to speed up the PR
2023-08-20 16:13:24 +02:00
Alejandro Perea
17ef9aa5db Allow ActiveAdmin 3 2023-08-13 11:57:03 +02:00
Mattia Roccoberton
b00fcd90ab Add rspec-retry gem 2022-04-19 22:07:02 +02:00
Mattia Roccoberton
edf5cbcb13 Merge pull request #30 from blocknotes/minor-improvements
v1.0.0
2022-04-19 21:55:07 +02:00
Mattia Roccoberton
38e5406d5d Bump to version 1.0.0 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
c560dd5c60 Changelog update 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
597cae7adb Test the Quill JS presence and version 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
6d0599c39e Minor improvements 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
664765ac79 Remove unused gems 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
7be390701f Enable Rails 7.0 specs support 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
e4401a469b Enable Ruby 3.0 specs support 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
d8632f069a Setup Cuprite 2022-04-19 21:49:20 +02:00
Mattia Roccoberton
7498cd65a1 Setup Appraisal 2022-03-29 19:42:43 +02:00
Mattia Roccoberton
038d66f387 Set minimum Ruby version to 2.6.0 and enable MFA 2022-03-26 18:04:33 +01:00
Mattia Roccoberton
7af25106a2 Remove sassc dependency 2022-03-26 18:00:12 +01:00
Mattia Roccoberton
d021f3650e README update 2022-03-26 17:54:26 +01:00
Mattia Roccoberton
8a13dd49a4 Create FUNDING.yml 2022-03-18 18:42:18 +01:00
Mattia Roccoberton
1cad5a10c3 Merge pull request #26 from blocknotes/update-linters-config
Update linters config
2021-07-10 15:41:05 +02:00
Mattia Roccoberton
63b4c118f6 Update linters config 2021-07-10 15:34:00 +02:00
Mattia Roccoberton
277d1a521a Merge pull request #24 from blocknotes/github_actions_improvements2
Add linter workflow
2021-06-02 15:53:24 +02:00
Mattia Roccoberton
4a0ea5e8f2 Add linter workflow 2021-06-02 15:52:19 +02:00
Mattia Roccoberton
ffc57e7d90 Badge for gem downloads 2021-05-23 22:48:09 +02:00
Mattia Roccoberton
2ebc9176b4 Merge pull request #23 from blocknotes/github_actions_improvements
GitHub Actions improvements
2021-05-23 21:23:19 +02:00
Mattia Roccoberton
0b44c683e6 GitHub Actions improvements 2021-05-23 14:51:28 +02:00
Mattia Roccoberton
9b460d36e3 Minor specs changes 2021-05-23 14:23:19 +02:00
Mattia Roccoberton
d41f8450ea Move some dependencies to the Gemfile 2021-05-23 14:22:28 +02:00
Mattia Roccoberton
401d2528e8 Merge pull request #22 from blocknotes/setup_github_actions_specs
Update GitHub Actions
2021-05-13 23:01:05 +02:00
Mattia Roccoberton
e086bac0a7 Update README 2021-05-13 22:59:41 +02:00
Mattia Roccoberton
36cd836ca8 Remove CircleCI config 2021-05-13 22:57:46 +02:00
Mattia Roccoberton
c05666673e Update GitHub Actions 2021-05-13 22:24:14 +02:00
Mattia Roccoberton
2d5429718c Bump to version 0.3.4 2021-03-16 08:32:57 +01:00
Mattia Roccoberton
78126d0cd7 Fix editor loading with Turbolinks 2021-03-14 16:05:21 +01:00
Mattia Roccoberton
3190134973 Small update to the README 2021-03-14 15:42:14 +01:00
Mattia Roccoberton
8d6b05297a Bump to version 0.3.2 2021-03-14 15:30:59 +01:00
Mattia Roccoberton
5d9b6f70fd Improve specs
- Add test examples for bold and italic content
- Move some test examples
- Adjust RSpec options
2021-03-14 15:26:24 +01:00
Mattia Roccoberton
6fa021c0c7 Update README 2021-03-14 14:35:51 +01:00
Mattia Roccoberton
357ef382d6 Update dependencies to test on Rails 6.1 2021-03-14 12:44:55 +01:00
Mattia Roccoberton
43ae70c7c9 Update NPM package files list 2020-10-06 22:37:25 +02:00
Mattia Roccoberton
6daf6f6bc8 Set word-break: break-all to prevent editor overflow 2020-10-06 22:30:16 +02:00
Mattia Roccoberton
98c235d346 Create brakeman-analysis.yml 2020-10-01 22:22:41 +02:00
Mattia Roccoberton
e6e6742753 Merge pull request #15 from blocknotes/feature/webpacker-support
Webpacker support
2020-10-01 07:56:57 +02:00
Mattia Roccoberton
c2c8d48795 Webpacker support 2020-10-01 07:56:03 +02:00
Mattia Roccoberton
72062c1a30 v0.2.14 2020-09-10 07:40:35 +02:00
Mattia Roccoberton
c4aa91225b Minor specs improvement 2020-09-09 12:58:14 +02:00
Mattia Roccoberton
3cc6edb302 JS strict directive 2020-09-09 07:48:45 +02:00
Mattia Roccoberton
d78fb2eb9c v0.2.12 2020-09-08 18:35:23 +02:00
Mattia Roccoberton
e5db64af96 JS refactoring 2020-09-08 18:26:24 +02:00
Mattia Roccoberton
c0d37ad94e v0.2.10 2020-09-05 16:08:46 +02:00
Mattia Roccoberton
96c70106a4 Add a new example: upload plugin using Active Storage 2020-09-05 16:07:19 +02:00
Mattia Roccoberton
4ec6e80760 Editor default options refactoring + include imageUploader plugin
In order to use imageUploader plugin:
- js/css files must included in the app;
- an upload method must be provided in Active Admin entity;
- the image_uploader server_url field option needs to be set.
2020-09-04 10:53:29 +02:00
Mattia Roccoberton
707f4a5cc7 README improvements 2020-09-04 09:14:18 +02:00
Mattia Roccoberton
dc97316303 v0.2.9 2020-09-04 08:49:20 +02:00
Mattia Roccoberton
e9b8abc88e Merge pull request #14 from blocknotes/fix/text-alignment
Reduce the importance of the reset rules
2020-09-03 13:02:47 +02:00
Mattia Roccoberton
582667dc59 Reduce the importance of the reset rules
This allows to let Quill features to override the reset styles.

Closes #8
2020-09-03 13:00:42 +02:00
m.pestov
76c06f5346 Don't send paragraph tag if editor blank 2020-09-03 12:45:42 +02:00
Mattia Roccoberton
4e20e658ac v0.2.8 2020-09-03 11:53:48 +02:00
Mattia Roccoberton
135a56dc03 Add specs for editor in nested resources 2020-09-03 11:50:23 +02:00
Mattia Roccoberton
668bd642e5 Add Rubocop 2020-09-03 11:26:54 +02:00
Mattia Roccoberton
ab8c4fd73f Remove SimpleCov 2020-09-03 11:24:55 +02:00
Mattia Roccoberton
d60ed0f723 Update screenshot 2020-09-03 11:20:35 +02:00
Mattia Roccoberton
98b29d6f69 Minor style improvements 2020-09-03 11:20:12 +02:00
Mattia Roccoberton
962b48bb30 README improvements 2020-09-01 11:48:47 +02:00
Mattia Roccoberton
03b2d0e4e8 Merge pull request #13 from blocknotes/circleci-project-setup
Add CircleCI setup
2020-09-01 11:45:00 +02:00
Mattia Roccoberton
593ad3841a Add .circleci/config.yml 2020-09-01 11:40:23 +02:00
Mattia Roccoberton
d96162fedd v0.2.4 2020-09-01 11:31:12 +02:00
Mattia Roccoberton
a43a4ff0ba Add minimum specs 2020-09-01 11:17:38 +02:00
Mattia Roccoberton
7a148c7cd1 Add specs configuration 2020-09-01 11:16:56 +02:00
Mattia Roccoberton
5c462f5d7c Update Quill editor to version 1.3.7 2020-09-01 11:05:48 +02:00
Mattia Roccoberton
9ecfceaa9a 🎉 Support ActiveAdmin 2.x and code style improvements
- Add support ActiveAdmin for 2.x
- Add rubocop config
- Add frozen_string_literal to ruby files
- Apply changes to respect rubocop alerts
2019-06-15 19:55:45 +02:00
Mattia Roccoberton
598b2d75cf Merge pull request #6 from seanfcarroll/patch-1
Correct Quill options list link
2018-11-24 17:37:57 +01:00
Sean
54026744c4 Correct Quill options list link 2018-11-16 13:39:41 +01:00
mat@blocknot.es
5d35feedd8 v0.1.4: PR4 + Quill Editor 1.3.6 2018-11-03 18:44:54 +01:00
Mattia Roccoberton
73ee9e3787 Merge pull request #4 from mylescc/master
Thank you @mylescc
2018-11-03 17:07:30 +01:00
Myles Cowper-Coles
b251a28b13 Making sure quill editor updates with has_many
What:

* adding an event listerner so when people add a 'has_many' relationship
the quill editor is initialized correctly on any fields;

Why:

* If you have a nested has_many attributes in active admin, the form
is not created until you click the 'Add New ObjectName' button. This
triggers a jQuery event called 'has_many_add:after' which you can use to
trigger the re init of the quill editor.
* 9a33a081c9/app/assets/javascripts/active_admin/lib/has_many.es6 (L52)
2018-09-25 14:57:33 +01:00
141 изменённых файлов: 3763 добавлений и 22066 удалений

7
.fasterer.yml Обычный файл
Просмотреть файл

@@ -0,0 +1,7 @@
---
exclude_paths:
- bin/*
- db/schema.rb
- gemfiles/**/*
- spec/dummy/**/*
- vendor/**/*

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 поставляемый Обычный файл
Просмотреть файл

@@ -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 поставляемый Обычный файл
Просмотреть файл

@@ -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 поставляемый Обычный файл
Просмотреть файл

@@ -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 поставляемый Обычный файл
Просмотреть файл

@@ -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 поставляемый Обычный файл
Просмотреть файл

@@ -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 поставляемый Обычный файл
Просмотреть файл

@@ -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 поставляемый
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -0,0 +1,8 @@
---
runner:
fasterer:
cmd: bin/fasterer
level: info
rubocop:
cmd: bin/rubocop
level: info

2
.rspec Обычный файл
Просмотреть файл

@@ -0,0 +1,2 @@
--require rails_helper
--format documentation

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 Обычный файл
Просмотреть файл

@@ -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
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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
Просмотреть файл

@@ -1,33 +1,65 @@
# ActiveAdmin Quill Editor [![Gem Version](https://badge.fury.io/rb/activeadmin_quill_editor.svg)](https://badge.fury.io/rb/activeadmin_quill_editor)
# ActiveAdmin Quill Editor
[![gem version](https://badge.fury.io/rb/activeadmin_quill_editor.svg)](https://badge.fury.io/rb/activeadmin_quill_editor)
[![gem downloads](https://badgen.net/rubygems/dt/activeadmin_quill_editor)](https://rubygems.org/gems/activeadmin_quill_editor)
[![linters](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/linters.yml/badge.svg)](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)
[![specs Rails 6.1](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails61.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails61.yml)
[![specs Rails 7.0](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails70.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails70.yml)
[![Specs Rails 7.1](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails71.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails71.yml)
[![Specs Rails 7.2](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails72.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails72.yml)
[![Specs Rails 8.0](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails80.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails80.yml)
![screenshot](screenshot.jpg)
An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quilljs/quill) in form fields.
![screenshot](extra/screenshot.png)
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).

Просмотреть файл

@@ -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

Просмотреть файл

@@ -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,39 +1,123 @@
window.onload = 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'
/* globals $ Quill ImageUploader */
(function () {
'use strict';
// --- 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 = {};
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' );
if( content ) {
var options = editors[i].getAttribute( 'data-options' ) ? JSON.parse( editors[i].getAttribute( 'data-options' ) ) : default_options;
editors[i]['_quill-editor'] = new Quill( content, options );
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

Просмотреть файл

@@ -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 поставляемый Обычный файл
Просмотреть файл

@@ -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 Исполняемый файл
Просмотреть файл

@@ -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 Исполняемый файл
Просмотреть файл

@@ -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 Исполняемый файл
Просмотреть файл

@@ -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 Исполняемый файл
Просмотреть файл

@@ -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 Исполняемый файл
Просмотреть файл

@@ -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")

Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -0,0 +1,3 @@
alias ls='ls --color'
alias ll='ls -l'
alias la='ls -la'

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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -0,0 +1,6 @@
# Ignore everything but the required files for bundle install
/**/*
!/*.gemspec
!/Gemfile
!/lib

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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 52 KiB

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.2'
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 Обычный файл
Просмотреть файл

@@ -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

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 33 KiB

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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -0,0 +1,5 @@
# frozen_string_literal: true
ActiveAdmin.register Tag do
permit_params :name
end

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,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,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; }

Просмотреть файл

@@ -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
*/

Просмотреть файл

@@ -0,0 +1,4 @@
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end

Просмотреть файл

@@ -0,0 +1,4 @@
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end

Просмотреть файл

@@ -0,0 +1,2 @@
class ApplicationController < ActionController::Base
end

0
spec/dummy/app/controllers/concerns/.keep Обычный файл
Просмотреть файл

Просмотреть файл

@@ -0,0 +1,2 @@
module ApplicationHelper
end

Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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

Просмотреть файл

@@ -0,0 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com'
layout 'mailer'
end

Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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

Просмотреть файл

@@ -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>

Просмотреть файл

@@ -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>

Просмотреть файл

@@ -0,0 +1 @@
<%= yield %>

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 Исполняемый файл
Просмотреть файл

@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
require_relative '../config/boot'
require 'rake'
Rake.application.run

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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -0,0 +1,5 @@
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!

Просмотреть файл

@@ -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 Обычный файл
Просмотреть файл

@@ -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

Просмотреть файл

@@ -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

Просмотреть файл

@@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше