├── .fasterer.yml ├── .github ├── FUNDING.yml └── workflows │ ├── linters.yml │ ├── specs_rails61.yml │ ├── specs_rails70.yml │ ├── specs_rails71.yml │ ├── specs_rails72.yml │ └── specs_rails80.yml ├── .gitignore ├── .reviewdog.yml ├── .rspec ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── Makefile ├── README.md ├── Rakefile ├── activeadmin_froala_editor.gemspec ├── app └── assets │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 │ ├── javascripts │ └── activeadmin │ │ ├── froala_editor │ │ ├── froala_editor.min.js │ │ ├── froala_editor.pkgd.min.js │ │ ├── languages │ │ │ ├── ar.js │ │ │ ├── bs.js │ │ │ ├── cs.js │ │ │ ├── da.js │ │ │ ├── de.js │ │ │ ├── el.js │ │ │ ├── en_ca.js │ │ │ ├── en_gb.js │ │ │ ├── es.js │ │ │ ├── et.js │ │ │ ├── fa.js │ │ │ ├── fi.js │ │ │ ├── fr.js │ │ │ ├── he.js │ │ │ ├── hr.js │ │ │ ├── hu.js │ │ │ ├── id.js │ │ │ ├── it.js │ │ │ ├── ja.js │ │ │ ├── ko.js │ │ │ ├── ku.js │ │ │ ├── me.js │ │ │ ├── nb.js │ │ │ ├── nl.js │ │ │ ├── pl.js │ │ │ ├── pt_br.js │ │ │ ├── pt_pt.js │ │ │ ├── ro.js │ │ │ ├── ru.js │ │ │ ├── sk.js │ │ │ ├── sl.js │ │ │ ├── sr.js │ │ │ ├── sv.js │ │ │ ├── th.js │ │ │ ├── tr.js │ │ │ ├── uk.js │ │ │ ├── vi.js │ │ │ ├── zh_cn.js │ │ │ └── zh_tw.js │ │ ├── plugins.pkgd.min.js │ │ ├── plugins │ │ │ ├── align.min.js │ │ │ ├── char_counter.min.js │ │ │ ├── code_beautifier.min.js │ │ │ ├── code_view.min.js │ │ │ ├── colors.min.js │ │ │ ├── cryptojs.min.js │ │ │ ├── draggable.min.js │ │ │ ├── edit_in_popup.min.js │ │ │ ├── emoticons.min.js │ │ │ ├── entities.min.js │ │ │ ├── file.min.js │ │ │ ├── files_manager.min.js │ │ │ ├── filestack.min.js │ │ │ ├── font_family.min.js │ │ │ ├── font_size.min.js │ │ │ ├── forms.min.js │ │ │ ├── fullscreen.min.js │ │ │ ├── help.min.js │ │ │ ├── image.min.js │ │ │ ├── image_manager.min.js │ │ │ ├── inline_class.min.js │ │ │ ├── inline_style.min.js │ │ │ ├── line_breaker.min.js │ │ │ ├── line_height.min.js │ │ │ ├── link.min.js │ │ │ ├── lists.min.js │ │ │ ├── markdown.min.js │ │ │ ├── paragraph_format.min.js │ │ │ ├── paragraph_style.min.js │ │ │ ├── print.min.js │ │ │ ├── quick_insert.min.js │ │ │ ├── quote.min.js │ │ │ ├── save.min.js │ │ │ ├── special_characters.min.js │ │ │ ├── table.min.js │ │ │ ├── track_changes.min.js │ │ │ ├── trim_video.min.js │ │ │ ├── url.min.js │ │ │ ├── video.min.js │ │ │ ├── word_counter.min.js │ │ │ └── word_paste.min.js │ │ └── third_party │ │ │ ├── embedly.min.js │ │ │ ├── font_awesome.min.js │ │ │ ├── image_tui.min.js │ │ │ ├── showdown.min.js │ │ │ └── spell_checker.min.js │ │ └── froala_editor_input.js │ └── stylesheets │ ├── activeadmin │ ├── _froala_editor_input.scss │ └── froala_editor │ │ ├── froala_editor.css │ │ ├── froala_editor.min.css │ │ ├── froala_editor.pkgd.css │ │ ├── froala_editor.pkgd.min.css │ │ ├── froala_style.css │ │ ├── froala_style.min.css │ │ ├── plugins.pkgd.css │ │ ├── plugins.pkgd.min.css │ │ ├── plugins │ │ ├── char_counter.css │ │ ├── char_counter.min.css │ │ ├── code_view.css │ │ ├── code_view.min.css │ │ ├── colors.css │ │ ├── colors.min.css │ │ ├── draggable.css │ │ ├── draggable.min.css │ │ ├── emoticons.css │ │ ├── emoticons.min.css │ │ ├── file.css │ │ ├── file.min.css │ │ ├── files_manager.css │ │ ├── files_manager.min.css │ │ ├── filestack.css │ │ ├── filestack.min.css │ │ ├── fullscreen.css │ │ ├── fullscreen.min.css │ │ ├── help.css │ │ ├── help.min.css │ │ ├── image.css │ │ ├── image.min.css │ │ ├── image_manager.css │ │ ├── image_manager.min.css │ │ ├── line_breaker.css │ │ ├── line_breaker.min.css │ │ ├── markdown.css │ │ ├── markdown.min.css │ │ ├── quick_insert.css │ │ ├── quick_insert.min.css │ │ ├── special_characters.css │ │ ├── special_characters.min.css │ │ ├── table.css │ │ ├── table.min.css │ │ ├── trim_video.css │ │ ├── trim_video.min.css │ │ ├── video.css │ │ └── video.min.css │ │ ├── themes │ │ ├── dark.css │ │ ├── dark.min.css │ │ ├── gray.css │ │ ├── gray.min.css │ │ ├── royal.css │ │ └── royal.min.css │ │ └── third_party │ │ ├── embedly.css │ │ ├── embedly.min.css │ │ ├── font_awesome.css │ │ ├── font_awesome.min.css │ │ ├── image_tui.css │ │ ├── image_tui.min.css │ │ ├── spell_checker.css │ │ └── spell_checker.min.css │ └── font-awesome │ ├── _animated.scss │ ├── _bordered-pulled.scss │ ├── _core.scss │ ├── _fixed-width.scss │ ├── _icons.scss │ ├── _larger.scss │ ├── _list.scss │ ├── _mixins.scss │ ├── _path.scss │ ├── _rotated-flipped.scss │ ├── _screen-reader.scss │ ├── _stacked.scss │ ├── _variables.scss │ └── font-awesome.scss ├── bin ├── brakeman ├── fasterer ├── rails ├── rake ├── rspec └── rubocop ├── examples └── upload_plugin_using_activestorage │ └── app │ ├── admin │ └── posts.rb │ ├── assets │ ├── javascripts │ │ └── active_admin.js │ └── stylesheets │ │ └── active_admin.scss │ └── models │ └── post.rb ├── extra ├── .bashrc ├── .env ├── Dockerfile ├── Dockerfile.dockerignore ├── dev_setup.sh ├── development.md ├── docker-compose.yml └── screenshot.png ├── index.js ├── lib ├── activeadmin │ ├── froala_editor.rb │ └── froala_editor │ │ ├── engine.rb │ │ └── version.rb ├── activeadmin_froala_editor.rb └── formtastic │ └── inputs │ └── froala_editor_input.rb ├── package.json ├── spec ├── dummy │ ├── .ruby-version │ ├── Rakefile │ ├── app │ │ ├── admin │ │ │ ├── authors.rb │ │ │ ├── dashboard.rb │ │ │ ├── posts.rb │ │ │ └── tags.rb │ │ ├── assets │ │ │ ├── config │ │ │ │ └── manifest.js │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ └── active_admin.js │ │ │ └── stylesheets │ │ │ │ ├── active_admin.scss │ │ │ │ └── application.css │ │ ├── channels │ │ │ └── application_cable │ │ │ │ ├── channel.rb │ │ │ │ └── connection.rb │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ └── concerns │ │ │ │ └── .keep │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── javascript │ │ │ └── packs │ │ │ │ └── application.js │ │ ├── jobs │ │ │ └── application_job.rb │ │ ├── mailers │ │ │ └── application_mailer.rb │ │ ├── models │ │ │ ├── application_record.rb │ │ │ ├── author.rb │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ ├── post.rb │ │ │ ├── post_tag.rb │ │ │ ├── profile.rb │ │ │ └── tag.rb │ │ └── views │ │ │ └── layouts │ │ │ ├── application.html.erb │ │ │ ├── mailer.html.erb │ │ │ └── mailer.text.erb │ ├── bin │ │ ├── rails │ │ ├── rake │ │ └── setup │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── cable.yml │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── active_admin.rb │ │ │ ├── active_storage.rb │ │ │ ├── application_controller_renderer.rb │ │ │ ├── assets.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── content_security_policy.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ ├── puma.rb │ │ ├── routes.rb │ │ ├── spring.rb │ │ └── storage.yml │ ├── db │ │ ├── migrate │ │ │ ├── 20170806125915_create_active_storage_tables.active_storage.rb │ │ │ ├── 20180101010101_create_active_admin_comments.rb │ │ │ ├── 20180607053251_create_authors.rb │ │ │ ├── 20180607053254_create_profiles.rb │ │ │ ├── 20180607053255_create_tags.rb │ │ │ ├── 20180607053257_create_post_tags.rb │ │ │ └── 20180607053739_create_posts.rb │ │ ├── schema.rb │ │ └── seeds.rb │ ├── lib │ │ └── assets │ │ │ └── .keep │ └── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ └── favicon.ico ├── page_objects │ ├── admin │ │ ├── authors │ │ │ └── edit_page.rb │ │ └── posts │ │ │ └── edit_page.rb │ ├── base_object.rb │ ├── base_page.rb │ └── shared │ │ ├── froala_editor.rb │ │ └── html_editor.rb ├── rails_helper.rb ├── spec_helper.rb ├── support │ ├── capybara.rb │ └── string_clean_multiline.rb └── system │ ├── froala_editor_spec.rb │ └── froala_js_spec.rb └── yarn.lock /.fasterer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude_paths: 3 | - bin/* 4 | - db/schema.rb 5 | - gemfiles/**/* 6 | - spec/dummy/**/* 7 | - vendor/**/* 8 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [blocknotes] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Linters 3 | 4 | on: 5 | pull_request: 6 | branches: [main] 7 | push: 8 | branches: [main] 9 | 10 | jobs: 11 | reviewdog: 12 | name: Reviewdog 13 | runs-on: ubuntu-latest 14 | 15 | env: 16 | RAILS_VERSION: 7.0 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | 22 | - name: Set up Ruby 23 | uses: ruby/setup-ruby@v1 24 | with: 25 | ruby-version: 3.0 26 | bundler-cache: true 27 | 28 | - name: Set up Reviewdog 29 | uses: reviewdog/action-setup@v1 30 | with: 31 | reviewdog_version: latest 32 | 33 | - name: Run Reviewdog 34 | env: 35 | REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | run: | 37 | reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer,rubocop 38 | 39 | # NOTE: check with: reviewdog -fail-on-error -reporter=github-pr-review -runners=fasterer -diff="git diff" -tee 40 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails61.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 6.1 with ActiveAdmin 2.9 3 | 4 | on: 5 | pull_request: 6 | branches: [main] 7 | push: 8 | branches: [main] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.0'] 17 | 18 | env: 19 | RAILS_VERSION: 6.0 20 | ACTIVEADMIN_VERSION: 2.9.0 21 | 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | - name: Set up Ruby 27 | uses: ruby/setup-ruby@v1 28 | with: 29 | ruby-version: ${{ matrix.ruby }} 30 | bundler-cache: true 31 | 32 | - name: Database setup 33 | run: bin/rails db:create db:migrate db:test:prepare 34 | 35 | - name: Run tests 36 | run: bundle exec rspec --profile 37 | 38 | - name: On failure, archive screenshots as artifacts 39 | uses: actions/upload-artifact@v4 40 | if: failure() 41 | with: 42 | name: test-failed-screenshots 43 | path: spec/dummy/tmp/screenshots 44 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails70.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 7.0 3 | 4 | on: 5 | pull_request: 6 | branches: [main] 7 | push: 8 | branches: [main] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.0', '3.2'] 17 | 18 | env: 19 | RAILS_VERSION: 7.0 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails71.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 7.1 3 | 4 | on: 5 | pull_request: 6 | branches: [main] 7 | push: 8 | branches: [main] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.2', '3.4'] 17 | 18 | env: 19 | RAILS_VERSION: 7.1 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails72.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 7.2 3 | 4 | on: 5 | pull_request: 6 | branches: [main] 7 | push: 8 | branches: [main] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.2', '3.4'] 17 | 18 | env: 19 | RAILS_VERSION: 7.2 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.github/workflows/specs_rails80.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Specs Rails 8.0 3 | 4 | on: 5 | pull_request: 6 | branches: [main] 7 | push: 8 | branches: [main] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | ruby: ['3.2', '3.4'] 17 | 18 | env: 19 | RAILS_VERSION: 8.0 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: ${{ matrix.ruby }} 29 | bundler-cache: true 30 | 31 | - name: Database setup 32 | run: bin/rails db:create db:migrate db:test:prepare 33 | 34 | - name: Run tests 35 | run: bundle exec rspec --profile 36 | 37 | - name: On failure, archive screenshots as artifacts 38 | uses: actions/upload-artifact@v4 39 | if: failure() 40 | with: 41 | name: test-failed-screenshots 42 | path: spec/dummy/tmp/screenshots 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.orig 3 | 4 | /.rspec_failures 5 | /.rubocop-* 6 | /Gemfile.lock 7 | 8 | /_misc/ 9 | /coverage/ 10 | /spec/dummy/db/*.sqlite3* 11 | /spec/dummy/db/schema-dev* 12 | /spec/dummy/log/ 13 | /spec/dummy/storage/ 14 | /spec/dummy/tmp/ 15 | 16 | /node_modules/ 17 | -------------------------------------------------------------------------------- /.reviewdog.yml: -------------------------------------------------------------------------------- 1 | --- 2 | runner: 3 | fasterer: 4 | cmd: bin/fasterer 5 | level: info 6 | rubocop: 7 | cmd: bin/rubocop 8 | level: info 9 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require rails_helper 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | inherit_from: 3 | - https://relaxed.ruby.style/rubocop.yml 4 | 5 | plugins: 6 | - rubocop-capybara 7 | - rubocop-packaging 8 | - rubocop-performance 9 | - rubocop-rails 10 | - rubocop-rspec 11 | - rubocop-rspec_rails 12 | 13 | AllCops: 14 | Exclude: 15 | - bin/* 16 | - db/schema.rb 17 | - gemfiles/**/* 18 | - spec/dummy/**/* 19 | - vendor/**/* 20 | NewCops: enable 21 | TargetRubyVersion: 3.0 22 | 23 | RSpec/ExampleLength: 24 | # default 5 25 | Max: 12 26 | 27 | RSpec/MultipleMemoizedHelpers: 28 | # default: 5 29 | Max: 10 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Froala editor for ActiveAdmin 2 | 3 | An Active Admin plugin to use Froala WYSIWYG editor. 4 | 5 | ## v1.2.0 - 2025-04-13 6 | 7 | - Update Froala to version 4.5.1 8 | - Internal: improve tests 9 | - Internal: update dev setup 10 | - Internal: update CI configuration 11 | 12 | ## v1.1.0 - 2024-02-18 13 | 14 | - Set minimum Ruby version to 3.0.0 15 | - Set minimum ActiveAdmin version to 2.9.0 16 | - Update CI configuration 17 | 18 | ## v1.0.0 - 2022-18-04 19 | 20 | - Set minimum Ruby version to 2.6.0 21 | - Remove `sassc` dependency 22 | - Update Froala to version 4.0.10 23 | - Enable Ruby 3.0 specs support 24 | - Enable Rails 7.0 specs support 25 | - Internal improvements 26 | 27 | ## v0.4.0 - 2021-08-04 28 | 29 | - Update Froala to version 4.0.4 30 | - Permits to load editor options form a window object 31 | - Improve specs 32 | 33 | ## v0.3.0 - 2021-05-28 34 | 35 | - Webpacker support 36 | - Specs improvements 37 | - Minor internal changes 38 | 39 | ## v0.2.12 - 2021-03-19 40 | 41 | - Update Froala editor to version 3.2.6 42 | 43 | ## v0.2.10 - 2021-03-18 44 | 45 | - Fix editor loading with Turbolinks 46 | - Update dependencies to test on Rails 6.1 47 | - Minor specs improvements 48 | 49 | ## v0.2.8 - 2020-09-09 50 | 51 | - JS refactoring (init the editor by data attribute in place of class name, use an anonymous function wrapper, enable strict directive) 52 | - Minor specs improvements 53 | - README changes 54 | 55 | ## v0.2.4 - 2020-09-03 56 | 57 | - Include CSRF token in POST requests 58 | - Minor style improvements 59 | - Add specs for editor in nested resources 60 | - Add Rubocop and remove Simplecov 61 | - Add a new example: upload plugin using Active Storage 62 | 63 | ## v0.2.0 - 2020-08-26 64 | 65 | - Update Froala wysiwyg editor to version 3.2.1 66 | - Add specs with RSpec 67 | - Tested with ActiveAdmin 2.x 68 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | def eval_version(dependency, version) 6 | return [dependency] if version.empty? 7 | 8 | version.count('.') < 2 ? [dependency, "~> #{version}.0"] : [dependency, version] 9 | end 10 | 11 | if ENV['DEVEL'] == '1' 12 | gem 'activeadmin_froala_editor', path: './' 13 | else 14 | gemspec 15 | end 16 | 17 | ruby_ver = ENV.fetch('RUBY_VERSION', '') 18 | 19 | rails_ver = ENV.fetch('RAILS_VERSION', '') 20 | rails = eval_version('rails', rails_ver) 21 | gem(*rails) 22 | 23 | active_admin_ver = ENV.fetch('ACTIVEADMIN_VERSION', '') 24 | active_admin = eval_version('activeadmin', active_admin_ver) 25 | gem(*active_admin) 26 | 27 | ruby32 = ruby_ver.empty? || Gem::Version.new(ruby_ver) >= Gem::Version.new('3.2') 28 | rails72 = rails_ver.empty? || Gem::Version.new(rails_ver) >= Gem::Version.new('7.2') 29 | sqlite3 = ruby32 && rails72 ? ['sqlite3'] : ['sqlite3', '~> 1.4'] 30 | gem(*sqlite3) 31 | 32 | gem 'zeitwerk', '~> 2.6.18' unless ruby32 33 | 34 | # NOTE: to avoid error: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger 35 | gem 'concurrent-ruby', '1.3.4' 36 | 37 | gem 'bigdecimal' 38 | gem 'mutex_m' 39 | gem 'puma' 40 | gem 'sassc' 41 | gem 'sprockets-rails' 42 | 43 | # Testing 44 | gem 'capybara' 45 | gem 'cuprite' 46 | gem 'rspec_junit_formatter' 47 | gem 'rspec-rails' 48 | gem 'rspec-retry' 49 | gem 'simplecov', require: false 50 | 51 | # Linters 52 | gem 'fasterer' 53 | gem 'rubocop' 54 | gem 'rubocop-capybara' 55 | gem 'rubocop-packaging' 56 | gem 'rubocop-performance' 57 | gem 'rubocop-rails' 58 | gem 'rubocop-rspec' 59 | gem 'rubocop-rspec_rails' 60 | 61 | # Tools 62 | gem 'pry-rails' 63 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2022 Mattia Roccoberton 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include extra/.env 2 | 3 | help: 4 | @echo -e "${COMPOSE_PROJECT_NAME} - Main project commands:\n\ 5 | make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN)\n\ 6 | make specs # run the tests (after up)\n\ 7 | make lint # run the linters (after up)\n\ 8 | make server # run the server (after up)\n\ 9 | make shell # open a shell (after up)\n\ 10 | make down # cleanup (after up)\n\ 11 | Example: RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up" 12 | 13 | # System commands 14 | 15 | build: 16 | @rm -f Gemfile.lock spec/dummy/db/*.sqlite3 17 | @docker compose -f extra/docker-compose.yml build 18 | 19 | db_reset: 20 | @docker compose -f extra/docker-compose.yml run --rm app bin/rails db:create db:migrate db:test:prepare 21 | 22 | up: build db_reset 23 | @docker compose -f extra/docker-compose.yml up 24 | 25 | shell: 26 | @docker compose -f extra/docker-compose.yml exec app bash 27 | 28 | down: 29 | @docker compose -f extra/docker-compose.yml down --volumes --rmi local --remove-orphans 30 | 31 | # App commands 32 | 33 | seed: 34 | @docker compose -f extra/docker-compose.yml exec app bin/rails db:seed 35 | 36 | console: seed 37 | @docker compose -f extra/docker-compose.yml exec app bin/rails console 38 | 39 | lint: 40 | @docker compose -f extra/docker-compose.yml exec app bin/rubocop 41 | 42 | server: seed 43 | @docker compose -f extra/docker-compose.yml exec app bin/rails server -b 0.0.0.0 -p ${SERVER_PORT} 44 | 45 | specs: 46 | @docker compose -f extra/docker-compose.yml exec app bin/rspec --fail-fast 47 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | begin 4 | require 'bundler/setup' 5 | rescue LoadError 6 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 7 | end 8 | 9 | APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__) 10 | load 'rails/tasks/engine.rake' 11 | 12 | load 'rails/tasks/statistics.rake' 13 | 14 | require 'bundler/gem_tasks' 15 | 16 | begin 17 | require 'rspec/core/rake_task' 18 | 19 | RSpec::Core::RakeTask.new(:spec) do |t| 20 | # t.ruby_opts = %w[-w] 21 | t.rspec_opts = ['--color', '--format documentation'] 22 | end 23 | 24 | task default: :spec 25 | rescue LoadError 26 | puts '! LoadError: no RSpec available' 27 | end 28 | -------------------------------------------------------------------------------- /activeadmin_froala_editor.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('lib', __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require 'activeadmin/froala_editor/version' 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = 'activeadmin_froala_editor' 9 | spec.version = ActiveAdmin::FroalaEditor::VERSION 10 | spec.summary = 'Froala editor for ActiveAdmin' 11 | spec.description = 'An Active Admin plugin to use Froala WYSIWYG editor' 12 | spec.license = 'MIT' 13 | spec.authors = ['Mattia Roccoberton'] 14 | spec.email = 'mat@blocknot.es' 15 | spec.homepage = 'https://github.com/blocknotes/activeadmin_froala_editor' 16 | 17 | spec.required_ruby_version = '>= 3.0' 18 | 19 | spec.metadata['homepage_uri'] = spec.homepage 20 | spec.metadata['source_code_uri'] = spec.homepage 21 | spec.metadata['changelog_uri'] = 'https://github.com/blocknotes/activeadmin_froala_editor/blob/main/CHANGELOG.md' 22 | spec.metadata['rubygems_mfa_required'] = 'true' 23 | 24 | spec.files = Dir['{app,lib}/**/*', 'LICENSE.txt', 'Rakefile', 'README.md'] 25 | spec.require_paths = ['lib'] 26 | 27 | spec.add_dependency 'activeadmin', '>= 2.9.0' 28 | end 29 | -------------------------------------------------------------------------------- /app/assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/app/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /app/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/app/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /app/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/app/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/app/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /app/assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/app/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/align.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(i){"use strict";(i=i&&i.hasOwnProperty("default")?i["default"]:i).PLUGINS.align=function(o){var s=o.$;return{apply:function c(e){var t=o.selection.element(),n=s(t).closest(".fr-table-selected"),i=s(t).parents("TD"),a="TD"===t.tagName||i.length&&o.el.contains(i.get(0));if(s(t).parents(".fr-img-caption").length)s(t).css("text-align",e);else if(n.length&&o.el.contains(n[0]))n.find("td").css("text-align",e);else if(a)o.node.isBlock(t)?s(t).css("text-align",e):i.css("text-align",e);else{o.selection.save(),o.html.wrap(!0,!0,!0,!0),o.selection.restore();for(var l=o.selection.blocks(),r=0;r *").first().replaceWith(o.icon.create("align-".concat(n)))}},refreshOnShow:function a(e,t){var n=o.selection.blocks();if(n.length){var i=o.helpers.getAlignment(s(n[0]));t.find('a.fr-command[data-param1="'.concat(i,'"]')).addClass("fr-active").attr("aria-selected",!0)}},refreshForToolbar:function l(e){var t=o.selection.blocks();if(t.length){var n=o.helpers.getAlignment(s(t[0]));n=n.charAt(0).toUpperCase()+n.slice(1),"align".concat(n)===e.attr("data-cmd")&&e.addClass("fr-active")}}}},i.DefineIcon("align",{NAME:"align-left",SVG_KEY:"alignLeft"}),i.DefineIcon("align-left",{NAME:"align-left",SVG_KEY:"alignLeft"}),i.DefineIcon("align-right",{NAME:"align-right",SVG_KEY:"alignRight"}),i.DefineIcon("align-center",{NAME:"align-center",SVG_KEY:"alignCenter"}),i.DefineIcon("align-justify",{NAME:"align-justify",SVG_KEY:"alignJustify"}),i.RegisterCommand("align",{type:"dropdown",title:"Align",options:{left:"Align Left",center:"Align Center",right:"Align Right",justify:"Align Justify"},html:function(){var e='"},callback:function(e,t){this.align.apply(t)},refresh:function(e){this.align.refresh(e)},refreshOnShow:function(e,t){this.align.refreshOnShow(e,t)},plugin:"align"}),i.RegisterCommand("alignLeft",{type:"button",icon:"align-left",title:"Align Left",callback:function(){this.align.apply("left")},refresh:function(e){this.align.refreshForToolbar(e)},plugin:"align"}),i.RegisterCommand("alignRight",{type:"button",icon:"align-right",title:"Align Right",callback:function(){this.align.apply("right")},refresh:function(e){this.align.refreshForToolbar(e)},plugin:"align"}),i.RegisterCommand("alignCenter",{type:"button",icon:"align-center",title:"Align Center",callback:function(){this.align.apply("center")},refresh:function(e){this.align.refreshForToolbar(e)},plugin:"align"}),i.RegisterCommand("alignJustify",{type:"button",icon:"align-justify",title:"Align Justify",callback:function(){this.align.apply("justify")},refresh:function(e){this.align.refreshForToolbar(e)},plugin:"align"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/char_counter.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],e):e(t.FroalaEditor)}(this,function(i){"use strict";i=i&&i.hasOwnProperty("default")?i["default"]:i,Object.assign(i.DEFAULTS,{charCounterMax:-1,charCounterCount:!0}),i.PLUGINS.charCounter=function(r){var n,o=r.$,a=function a(){return(r.opts.iframe&&r.markdown&&r.markdown.isEnabled()?r.$el.text()||"":r.el.textContent||"").replace(/\u200B/g,"").length};function t(t){if(r.opts.charCounterMax<0)return!0;if(a()").html(t).text().length+a()<=r.opts.charCounterMax?t:(r.events.trigger("charCounter.exceeded"),"")}function c(t,e,n){return r.opts.charCounterMax<0||(t.includes('=r.opts.charCounterMax)||(r.events.trigger("charCounter.exceeded"),!1):o("
").html(t).text().length+a()<=r.opts.charCounterMax||(r.events.trigger("charCounter.exceeded"),!1))}function s(){if(r.opts.charCounterCount){var t=a()+(0
")};i.popups.create("text.edit",t)}(),t())},update:function e(){var t=i.popups.get("text.edit").find("input").val();0===t.length&&(t=i.opts.placeholderText),"INPUT"===i.el.tagName?i.$el.attr("placeholder",t):i.$el.text(t),i.events.trigger("contentChanged"),i.popups.hide("text.edit")}}},t.RegisterCommand("updateText",{focus:!1,undo:!1,callback:function(){this.editInPopup.update()}})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/entities.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,a){"object"==typeof exports&&"undefined"!=typeof module?a(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],a):a(e.FroalaEditor)}(this,function(e){"use strict";e=e&&e.hasOwnProperty("default")?e["default"]:e,Object.assign(e.DEFAULTS,{entities:""'¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿŒœŠšŸƒˆ˜ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρςστυφχψωϑϒϖ   ‌‍‎‏–—‘’‚“”„†‡•…‰′″‹›‾⁄€ℑ℘ℜ™ℵ←↑→↓↔↵⇐⇑⇒⇓⇔∀∂∃∅∇∈∉∋∏∑−∗√∝∞∠∧∨∩∪∫∴∼≅≈≠≡≤≥⊂⊃⊄⊆⊇⊕⊗⊥⋅⌈⌉⌊⌋⟨⟩◊♠♣♥♦"}),e.PLUGINS.entities=function(i){var n,o,l=i.$;function r(e){var a=e.textContent;if(a.match(n)){for(var t="",r=0;r span").text(o.opts.fontFamily[n()]||t[0]||o.language.translate(o.opts.fontFamilyDefaultSelection))}}}},e.RegisterCommand("fontFamily",{type:"dropdown",displaySelection:function(e){return e.opts.fontFamilySelection},defaultSelection:function(e){return e.opts.fontFamilyDefaultSelection},displaySelectionWidth:120,html:function(){var e='"},title:"Font Family",callback:function(e,t){this.fontFamily.apply(t)},refresh:function(e){this.fontFamily.refresh(e)},refreshOnShow:function(e,t){this.fontFamily.refreshOnShow(e,t)},plugin:"fontFamily"}),e.DefineIcon("fontFamily",{NAME:"font",SVG_KEY:"fontFamily"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/font_size.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],e):e(t.FroalaEditor)}(this,function(t){"use strict";t=t&&t.hasOwnProperty("default")?t["default"]:t,Object.assign(t.DEFAULTS,{fontSize:["8","9","10","11","12","14","18","24","30","36","48","60","72","96"],fontSizeSelection:!1,fontSizeDefaultSelection:"Font Size",fontSizeUnit:"px"}),t.PLUGINS.fontSize=function(o){var i=o.$;return{apply:function e(t){o.format.applyStyle("font-size",t)},refreshOnShow:function a(t,e){var n=i(o.selection.element()).css("font-size");"pt"===o.opts.fontSizeUnit&&(n="".concat(Math.round(72*parseFloat(n,10)/96),"pt")),e.find(".fr-command.fr-active").removeClass("fr-active").attr("aria-selected",!1),e.find('.fr-command[data-param1="'.concat(n,'"]')).addClass("fr-active").attr("aria-selected",!0)},refresh:function n(t){if(o.opts.fontSizeSelection){var e=o.helpers.getPX(i(o.selection.element()).css("font-size"));"pt"===o.opts.fontSizeUnit&&(e="".concat(Math.round(72*parseFloat(e,10)/96),"pt")),t.find("> span").text(e)}}}},t.RegisterCommand("fontSize",{type:"dropdown",title:"Font Size",displaySelection:function(t){return t.opts.fontSizeSelection},displaySelectionWidth:30,defaultSelection:function(t){return t.opts.fontSizeDefaultSelection},html:function(){for(var t='"},callback:function(t,e){this.fontSize.apply(e)},refresh:function(t){this.fontSize.refresh(t)},refreshOnShow:function(t,e){this.fontSize.refreshOnShow(t,e)},plugin:"fontSize"}),t.DefineIcon("fontSize",{NAME:"text-height",SVG_KEY:"fontSize"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/fullscreen.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(e){"use strict";(e=e&&e.hasOwnProperty("default")?e["default"]:e).PLUGINS.fullscreen=function(s){var t,r,o,n,i=s.$,a=function a(){return s.$box.hasClass("fr-fullscreen")};function l(){if(s.helpers.isIOS()&&s.core.hasFocus())return s.$el.blur(),setTimeout(c,250),!1;t=s.helpers.scrollTop(),s.opts.iframe&&s.markdown&&s.markdown.isEnabled()&&(s.$box=s.$oel),s.$box.toggleClass("fr-fullscreen"),i("body").first().toggleClass("fr-fullscreen"),s.helpers.isMobile()&&(s.opts.toolbarBottom?s.$tb[0].removeAttribute("style"):(s.$tb.data("parent",s.$tb.parent()),s.$box.prepend(s.$tb),s.$tb.data("sticky-dummy")&&s.$tb.after(s.$tb.data("sticky-dummy")))),r=s.opts.height,o=s.opts.heightMax,n=s.opts.zIndex,s.opts.height=s.o_win.innerHeight-(s.opts.toolbarInline?0:s.$tb.outerHeight()+(s.$second_tb?s.$second_tb.outerHeight():0)),s.opts.zIndex=2147483641,s.opts.heightMax=null,s.size.refresh(),s.opts.toolbarInline&&s.toolbar.showInline();for(var e=s.$box.parent();!e.first().is("body");)e.addClass("fr-fullscreen-wrapper"),e=e.parent();s.opts.toolbarContainer&&s.$box.prepend(s.$tb),s.events.trigger("charCounter.update"),s.events.trigger("codeView.update"),s.$win.trigger("scroll")}function f(){if(s.helpers.isIOS()&&s.core.hasFocus())return s.$el.blur(),setTimeout(c,250),!1;s.$box.toggleClass("fr-fullscreen"),i("body").first().toggleClass("fr-fullscreen"),s.$tb.data("parent")&&s.$tb.data("parent").prepend(s.$tb),s.$tb.data("sticky-dummy")&&s.$tb.after(s.$tb.data("sticky-dummy")),s.opts.height=r,s.opts.heightMax=o,s.opts.zIndex=n,s.size.refresh(),s.o_win.scroll(0,t),s.opts.toolbarInline&&s.toolbar.showInline(),s.events.trigger("charCounter.update"),s.opts.toolbarSticky&&s.opts.toolbarStickyOffset&&(s.opts.toolbarBottom?s.$tb.css("bottom",s.opts.toolbarStickyOffset).data("bottom",s.opts.toolbarStickyOffset):s.$tb.css("top",s.opts.toolbarStickyOffset).data("top",s.opts.toolbarStickyOffset));for(var e=s.$box.parent();!e.first().is("body");)e.removeClass("fr-fullscreen-wrapper"),e=e.parent();s.opts.toolbarContainer&&i(s.opts.toolbarContainer).append(s.$tb),i(s.o_win).trigger("scroll"),s.events.trigger("codeView.update")}function c(){a()?f():l(),d(s.$tb.find('.fr-command[data-cmd="fullscreen"]'));var e=s.$tb.find('.fr-command[data-cmd="moreText"]'),t=s.$tb.find('.fr-command[data-cmd="moreParagraph"]'),r=s.$tb.find('.fr-command[data-cmd="moreRich"]'),o=s.$tb.find('.fr-command[data-cmd="moreMisc"]');e.length&&s.refresh.moreText(e),t.length&&s.refresh.moreParagraph(t),r.length&&s.refresh.moreRich(r),o.length&&s.refresh.moreMisc(o)}function d(e){var t=a();e.toggleClass("fr-active",t).attr("aria-pressed",t),e.find("> *").not(".fr-sr-only").replaceWith(t?s.icon.create("fullscreenCompress"):s.icon.create("fullscreen"))}return{_init:function e(){if(!s.$wp)return!1;s.events.$on(i(s.o_win),"resize",function(){a()&&(f(),l())}),s.events.on("toolbar.hide",function(){if(a()&&s.helpers.isMobile())return!1}),s.events.on("position.refresh",function(){if(s.helpers.isIOS())return!a()}),s.events.on("destroy",function(){a()&&f()},!0)},toggle:c,refresh:d,isActive:a}},e.RegisterCommand("fullscreen",{title:"Fullscreen",undo:!1,focus:!1,accessibilityFocus:!0,forcedRefresh:!0,toggle:!0,callback:function(){this.fullscreen.toggle()},refresh:function(e){this.fullscreen.refresh(e)},plugin:"fullscreen"}),e.DefineIcon("fullscreen",{NAME:"expand",SVG_KEY:"fullscreen"}),e.DefineIcon("fullscreenCompress",{NAME:"compress",SVG_KEY:"exitFullscreen"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/help.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(e){"use strict";e=e&&e.hasOwnProperty("default")?e["default"]:e,Object.assign(e.DEFAULTS,{helpSets:[{title:"Inline Editor",commands:[{val:"OSkeyE",desc:"Show the editor"}]},{title:"Common actions",commands:[{val:"OSkeyC",desc:"Copy"},{val:"OSkeyX",desc:"Cut"},{val:"OSkeyV",desc:"Paste"},{val:"OSkeyZ",desc:"Undo"},{val:"OSkeyShift+Z",desc:"Redo"},{val:"OSkeyK",desc:"Insert Link"},{val:"OSkeyP",desc:"Insert Image"}]},{title:"Basic Formatting",commands:[{val:"OSkeyA",desc:"Select All"},{val:"OSkeyB",desc:"Bold"},{val:"OSkeyI",desc:"Italic"},{val:"OSkeyU",desc:"Underline"},{val:"OSkeyS",desc:"Strikethrough"},{val:"OSkey]",desc:"Increase Indent"},{val:"OSkey[",desc:"Decrease Indent"}]},{title:"Quote",commands:[{val:"OSkey'",desc:"Increase quote level"},{val:"OSkeyShift+'",desc:"Decrease quote level"}]},{title:"Image / Video",commands:[{val:"OSkey+",desc:"Resize larger"},{val:"OSkey-",desc:"Resize smaller"}]},{title:"Table",commands:[{val:"Alt+Space",desc:"Select table cell"},{val:"Shift+Left/Right arrow",desc:"Extend selection one cell"},{val:"Shift+Up/Down arrow",desc:"Extend selection one row"}]},{title:"Navigation",commands:[{val:"OSkey/",desc:"Shortcuts"},{val:"Alt+F10",desc:"Focus popup / toolbar"},{val:"Esc",desc:"Return focus to previous position"}]}]}),e.PLUGINS.help=function(c){var a,o=c.$,s="help";return{_init:function e(){},show:function d(){if(!a){var e="

".concat(c.language.translate("Shortcuts"),"

"),t=function n(){for(var e='
',t=0;t";a+="".concat(c.language.translate(l.title),""),a+="";for(var o=0;o",a+="".concat(c.language.translate(s.desc),""),a+="".concat(s.val.replace("OSkey",c.helpers.isMac()?"⌘":"Ctrl+"),""),a+=""}e+=a+=""}return e+="
"}(),l=c.modals.create(s,e,t);a=l.$modal,c.events.$on(o(c.o_win),"resize",function(){c.modals.resize(s)})}c.modals.show(s),c.modals.resize(s)},hide:function t(){c.modals.hide(s)}}},e.DefineIcon("help",{NAME:"question",SVG_KEY:"help"}),e.RegisterShortcut(e.KEYCODE.SLASH,"help",null,"/"),e.RegisterCommand("help",{title:"Help",icon:"help",undo:!1,focus:!1,modal:!0,callback:function(){this.help.show()},plugin:"help",showOnMobile:!1})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/inline_class.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(n,a){"object"==typeof exports&&"undefined"!=typeof module?a(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],a):a(n.FroalaEditor)}(this,function(n){"use strict";n=n&&n.hasOwnProperty("default")?n["default"]:n,Object.assign(n.DEFAULTS,{inlineClasses:{"fr-class-code":"Code","fr-class-highlighted":"Highlighted","fr-class-transparency":"Transparent"}}),n.PLUGINS.inlineClass=function(e){var i=e.$;return{apply:function a(n){e.format.toggle("span",{"class":n})},refreshOnShow:function s(n,a){a.find(".fr-command").each(function(){var n=i(this).data("param1"),a=e.format.is("span",{"class":n});i(this).toggleClass("fr-active",a).attr("aria-selected",a)})}}},n.RegisterCommand("inlineClass",{type:"dropdown",title:"Inline Class",html:function(){var n='"},callback:function(n,a){this.inlineClass.apply(a)},refreshOnShow:function(n,a){this.inlineClass.refreshOnShow(n,a)},plugin:"inlineClass"}),n.DefineIcon("inlineClass",{NAME:"tag",SVG_KEY:"inlineClass"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/inline_style.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(e){"use strict";e=e&&e.hasOwnProperty("default")?e["default"]:e,Object.assign(e.DEFAULTS,{inlineStyles:{"Big Red":"font-size: 20px; color: red;","Small Blue":"font-size: 14px; color: blue;"}}),e.PLUGINS.inlineStyle=function(i){return{apply:function a(e){for(var t=e.split(";"),n=0;n').concat(this.language.translate(n),"
")}return e+=""},title:"Inline Style",callback:function(e,t){this.inlineStyle.apply(t)},plugin:"inlineStyle"}),e.DefineIcon("inlineStyle",{NAME:"paint-brush",SVG_KEY:"inlineStyle"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/line_height.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(r){"use strict";r=r&&r.hasOwnProperty("default")?r["default"]:r,Object.assign(r.DEFAULTS,{lineHeights:{Default:"",Single:"1",1.15:"1.15",1.5:"1.5",Double:"2"}}),r.PLUGINS.lineHeight=function(a){var o=a.$;return{_init:function e(){},apply:function i(e){a.selection.save(),a.html.wrap(!0,!0,!0,!0),a.selection.restore();var t=a.selection.blocks();t.length&&o(t[0]).parent().is("td")&&a.format.applyStyle("line-height",e.toString()),a.selection.save();for(var n=0;n').concat(this.language.translate(t[n].label),"");else if(t instanceof Object)for(var a in t)t.hasOwnProperty(a)&&(e+='
  • ').concat(this.language.translate(a),"
  • "));return e+=""},title:"Line Height",callback:function(e,t){this.lineHeight.apply(t)},refreshOnShow:function(e,t){this.lineHeight.refreshOnShow(e,t)},plugin:"lineHeight"}),r.DefineIcon("lineHeight",{NAME:"arrows-v",FA5NAME:"arrows-alt-v",SVG_KEY:"lineHeight"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/paragraph_style.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(a,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],e):e(a.FroalaEditor)}(this,function(a){"use strict";a=a&&a.hasOwnProperty("default")?a["default"]:a,Object.assign(a.DEFAULTS,{paragraphStyles:{"fr-text-gray":"Gray","fr-text-bordered":"Bordered","fr-text-spaced":"Spaced","fr-text-uppercase":"Uppercase"},paragraphMultipleStyles:!0}),a.PLUGINS.paragraphStyle=function(i){var p=i.$;return{_init:function a(){},apply:function c(a,e,t){void 0===e&&(e=i.opts.paragraphStyles),void 0===t&&(t=i.opts.paragraphMultipleStyles);var r="";t||((r=Object.keys(e)).splice(r.indexOf(a),1),r=r.join(" ")),i.selection.save(),i.html.wrap(!0,!0,!0,!0),i.selection.restore();var l=i.selection.blocks();i.selection.save();for(var n=p(l[0]).hasClass(a),s=0;s");l[0].after(o[0])}i.html.unwrap(),i.selection.restore()},refreshOnShow:function l(a,e){var t=i.selection.blocks();if(t.length){var r=p(t[0]);e.find(".fr-command").each(function(){var a=p(this).data("param1"),e=r.hasClass(a);p(this).toggleClass("fr-active",e).attr("aria-selected",e)})}}}},a.RegisterCommand("paragraphStyle",{type:"dropdown",html:function(){var a='"},title:"Paragraph Style",callback:function(a,e){this.paragraphStyle.apply(e)},refreshOnShow:function(a,e){this.paragraphStyle.refreshOnShow(a,e)},plugin:"paragraphStyle"}),a.DefineIcon("paragraphStyle",{NAME:"magic",SVG_KEY:"paragraphStyle"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/print.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(e){"use strict";e=e&&e.hasOwnProperty("default")?e["default"]:e,Object.assign(e.DEFAULTS,{html2pdf:window.html2pdf}),e.PLUGINS.print=function(a){return{run:function e(){!function l(e){var t=a.html.get(),n=null;a.shared.print_iframe?n=a.shared.print_iframe:((n=document.createElement("iframe")).name="fr-print",n.style.position="fixed",n.style.top="0",n.style.left="-9999px",n.style.height="100%",n.style.width="0",n.style.overflow="hidden",n.style["z-index"]="2147483647",n.style.tabIndex="-1",a.events.on("shared.destroy",function(){n.remove()}),a.shared.print_iframe=n);try{document.body.removeChild(n)}catch(d){}document.body.appendChild(n);var i=function(){e(),n.removeEventListener("load",i)};n.addEventListener("load",i);var o=n.contentWindow;o.document.open(),o.document.write(""+document.title+""),Array.prototype.forEach.call(document.querySelectorAll("style"),function(e){e=e.cloneNode(!0),o.document.write(e.outerHTML)});var r=document.querySelectorAll("link[rel=stylesheet]");Array.prototype.forEach.call(r,function(e){var t=document.createElement("link");t.rel=e.rel,t.href=e.href,t.media="print",t.type="text/css",t.media="all",o.document.write(t.outerHTML)}),o.document.write('
    '),o.document.write(t),o.document.write("
    "),o.document.close()}(function(){setTimeout(function(){a.events.disableBlur(),window.frames["fr-print"].focus(),window.frames["fr-print"].print(),a.$win.get(0).focus(),a.events.disableBlur(),a.events.focus()},0)})},toPDF:function t(){a.opts.html2pdf&&(a.$el.css("text-align","left"),a.opts.html2pdf().set({margin:[10,20],html2canvas:{useCORS:!0}}).from(a.el).save(),setTimeout(function(){a.$el.css("text-align","")},100))}}},e.DefineIcon("print",{NAME:"print",SVG_KEY:"print"}),e.RegisterCommand("print",{title:"Print",undo:!1,focus:!1,plugin:"print",callback:function(){this.print.run()}}),e.DefineIcon("getPDF",{NAME:"file-pdf-o",FA5NAME:"file-pdf",SVG_KEY:"pdfExport"}),e.RegisterCommand("getPDF",{title:"Download PDF",type:"button",focus:!1,undo:!1,callback:function(){this.print.toPDF()}})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/quote.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(e){"use strict";(e=e&&e.hasOwnProperty("default")?e["default"]:e).PLUGINS.quote=function(r){var c=r.$;function s(e){for(;e.parentNode&&e.parentNode!=r.el;)e=e.parentNode;return e}return{apply:function t(e){r.selection.save(),r.html.wrap(!0,!0,!0,!0),r.selection.restore(),"increase"==e?function o(){var e,t=r.selection.blocks();for(e=0;e').concat(this.language.translate(t[n])).concat(o?''.concat(o,""):"","")}return e+=""},callback:function(e,t){this.quote.apply(t)},plugin:"quote"}),e.DefineIcon("quote",{NAME:"quote-left",SVG_KEY:"blockquote"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/save.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(e){"use strict";e=e&&e.hasOwnProperty("default")?e["default"]:e,Object.assign(e.DEFAULTS,{saveInterval:1e4,saveURL:null,saveParams:{},saveParam:"body",saveMethod:"POST"}),e.PLUGINS.save=function(i){var f=i.$,n=null,l=null,t=!1,v=1,c=2,s={};function u(e,t){i.events.trigger("save.error",[{code:e,message:s[e]},t])}function a(e){void 0===e&&(e=i.html.get());var n=e,t=i.events.trigger("save.before",[e]);if(!1===t)return!1;if("string"==typeof t&&(e=t),i.opts.saveURL){var s={};for(var a in i.opts.saveParams)if(i.opts.saveParams.hasOwnProperty(a)){var o=i.opts.saveParams[a];s[a]="function"==typeof o?o.call(this):o}var r={};r[i.opts.saveParam]=e,f(this).ajax({method:i.opts.saveMethod,url:i.opts.saveURL,data:Object.assign(r,s),crossDomain:i.opts.requestWithCORS,withCredentials:i.opts.requestWithCredentials,headers:i.opts.requestHeaders,done:function(e,t,s){l=n,i.events.trigger("save.after",[e])},fail:function(e){u(c,e.response||e.responseText)}})}else u(v)}function o(){clearTimeout(n),n=setTimeout(function(){var e=i.html.get();(l!=e||t)&&(t=!1,a(l=e))},0)}return s[v]="Missing saveURL option.",s[c]="Something went wrong during save.",{_init:function r(){if(i.opts.letteringClass)for(var e=i.opts.letteringClass,t=i.$el.find(".".concat(e)).length,s=0;s$1");i.opts.saveInterval&&(l=i.html.get(),i.events.on("contentChanged",function(){setTimeout(o,i.opts.saveInterval)}),i.events.on("keydown destroy",function(){clearTimeout(n)}))},save:a,reset:function e(){o(),t=!1},force:function d(){t=!0}}},e.DefineIcon("save",{NAME:"floppy-o",FA5NAME:"save"}),e.RegisterCommand("save",{title:"Save",undo:!1,focus:!1,refreshAfterCallback:!1,callback:function(){this.save.save()},plugin:"save"})}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/plugins/word_counter.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(E){"use strict";E=E&&E.hasOwnProperty("default")?E["default"]:E,Object.assign(E.DEFAULTS,{wordCounterMax:-1,wordCounterCount:!0}),E.PLUGINS.wordCounter=function(C){var r,t=C.$;function f(){var e=C.el.innerText.toString();e=(e=(e=(e=(e=(e=(e=(e=e.replace(/(^\s*)|(\s*$)/gi," ")).replace(/\u00a0/g," ")).replace(/[ ]{2,}/gi," ")).replace(/\n /,"\n")).replace(/[\u200A\u200C-\u200D\uFEFF\u202F\u2000-\u2009\u205F\u3000\u1680\u00A0\u0020]/g," ")).replace(/[\u200B]/g,"")).replace(/\t+/g," ")).split(" ").join("\n");var t=C.$el.find(".fr-pagebreak"),r=e.split(/\r?\n/),n=0;return r.forEach(function(e){0<(e=e.replace(/\s/g,"")).length&&n++}),n-2*t.length}function e(e){var t=!1;if(C.opts.wordCounterMax<0)return!0;if(f()C.opts.wordCounterMax&&(C.keys.isCharacter(r)||r===E.KEYCODE.ENTER)&&(t=!0),!(!C.keys.ctrlKey(e)&&t||r===E.KEYCODE.IME)||(e.preventDefault(),e.stopPropagation(),C.events.trigger("wordCounter.exceeded"),!1)}function n(){if(C.opts.wordCounterCount){var e=f()+(0").html(e).text().split(" ").length+f()<=C.opts.wordCounterMax?e:(C.events.trigger("wordCounter.exceeded"),"")}return{_init:function a(){return!!C.$wp&&!!C.opts.wordCounterCount&&((r=t(document.createElement("span")).attr("class","fr-counter fr-wCounter")).css("bottom",C.$wp.css("border-bottom-width")),C.$second_tb?C.$second_tb.append(r):C.$wp.append(r),C.events.on("keydown",e,!0),C.events.on("paste.afterCleanup",o),C.events.on("keyup contentChanged input",function(){C.events.trigger("wordCounter.update")}),C.events.on("wordCounter.update",n),C.events.trigger("wordCounter.update"),void C.events.on("destroy",function(){t(C.o_win).off("resize.char".concat(C.id)),r.removeData().remove(),r=null}))},wordCount:f}}}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/third_party/image_tui.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(e){"use strict";function v(e){return(v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}if(e=e&&e.hasOwnProperty("default")?e["default"]:e,Object.assign(e.DEFAULTS,{imageTUIOptions:{includeUI:{theme:{"menu.normalIcon.path":"https://cdn.jsdelivr.net/npm/tui-image-editor@3.2.2/dist/svg/icon-d.svg","menu.activeIcon.path":"https://cdn.jsdelivr.net/npm/tui-image-editor@3.2.2/dist/svg/icon-b.svg","menu.disabledIcon.path":"https://cdn.jsdelivr.net/npm/tui-image-editor@3.2.2/dist/svg/icon-a.svg","menu.hoverIcon.path":"https://cdn.jsdelivr.net/npm/tui-image-editor@3.2.2/dist/svg/icon-c.svg","submenu.normalIcon.path":"https://cdn.jsdelivr.net/npm/tui-image-editor@3.2.2/dist/svg/icon-d.svg","submenu.normalIcon.name":"icon-d","submenu.activeIcon.path":"https://cdn.jsdelivr.net/npm/tui-image-editor@3.2.2/dist/svg/icon-c.svg","submenu.activeIcon.name":"icon-c"},initMenu:"filter",menuBarPosition:"left"}},tui:window.tui}),e.PLUGINS.imageTUI=function(c){var l=c.$,m=!0;function g(e,t){l("#tuieditor").remove(),e.style.display="none",m||t===undefined||t.filesManager.setChildWindowState(!1)}function p(e,t,i,n,o){for(var a=e.toDataURL(),d=atob(a.split(",")[1]),r=[],s=0;sCancel '),l(".tui-editor-cancel-btn")[0].addEventListener("click",function(e){g(d,t)}),l(".tui-editor-save-btn")[0].addEventListener("click",function(e){null!=n?p(s,t,o,i,n):p(s,t,o,i),g(d,t)})}}}},e.DefineIcon("imageTUI",{NAME:"sliders",FA5NAME:"sliders-h",SVG_KEY:"advancedImageEditor"}),e.RegisterCommand("imageTUI",{title:"Advanced Edit",undo:!1,focus:!1,callback:function(e,t){this.imageTUI.launch(this,!0)},plugin:"imageTUI"}),!e.PLUGINS.image)throw new Error("TUI image editor plugin requires image plugin.");e.DEFAULTS.imageEditButtons.push("imageTUI")}); -------------------------------------------------------------------------------- /app/assets/javascripts/activeadmin/froala_editor/third_party/spell_checker.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("froala-editor")):"function"==typeof define&&define.amd?define(["froala-editor"],t):t(e.FroalaEditor)}(this,function(p){"use strict";(p=p&&p.hasOwnProperty("default")?p["default"]:p).DEFAULT_SCAYT_OPTIONS={enableOnTouchDevices:!1,disableOptionsStorage:["all"],localization:"en",extraModules:"ui",DefaultSelection:"American English",spellcheckLang:"en_US",contextMenuSections:"suggest|moresuggest",serviceProtocol:"https",servicePort:"80",serviceHost:"svc.webspellchecker.net",servicePath:"spellcheck/script/ssrv.cgi",contextMenuForMisspelledOnly:!0,scriptPath:"https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js"},Object.assign(p.DEFAULTS,{scaytAutoload:!1,scaytCustomerId:"1:ldogw1-MSDuT3-slyfO-0YJgB1-Wx7262-HIT741-MAMDv4-10qfb3-A4LDP-c60m3-hSQgd2-az2",scaytOptions:{}}),p.PLUGINS.spellChecker=function(s){var l;function e(e){if(l&&l.isDisabled){var t=!l.isDisabled();e.toggleClass("fr-active",t).attr("aria-pressed",t),s.$el.attr("spellcheck",s.opts.spellcheck&&!t)}}function t(e){l&&l.isDisabled&&!l.isDisabled()&&0<=["bold","italic","underline","strikeThrough","subscript","superscript","fontFamily","fontSize","html"].indexOf(e)&&l.removeMarkupInSelectionNode({removeInside:!0})}function o(e){l&&l.isDisabled&&!l.isDisabled()&&0<=["bold","italic","underline","strikeThrough","subscript","superscript","fontFamily","fontSize","html"].indexOf(e)&&l.reloadMarkup()}function a(e){l&&l.isDisabled&&!l.isDisabled()&&(e.which==p.KEYCODE.ENTER&&setTimeout(l.reloadMarkup,0))}function i(e){if(e&&e.getAttribute&&e.getAttribute("data-scayt-word"))e.outerHTML=e.innerHTML;else if(e&&e.nodeType==Node.ELEMENT_NODE)for(var t=e.querySelectorAll("[data-scayt-word], [data-spelling-word]"),s=0;s button { 18 | font-weight: normal; 19 | text-shadow: none; 20 | } 21 | 22 | .fr-box { 23 | display: inline-block; 24 | width: calc(80% - 2px); 25 | } 26 | 27 | .fr-checkbox-line { 28 | >label { 29 | display: inline-block; 30 | float: none; 31 | width: auto; 32 | } 33 | 34 | >span { 35 | height: auto; 36 | padding: 0; 37 | width: auto; 38 | } 39 | } 40 | 41 | .fr-element { 42 | ul, ol { 43 | margin: 0 10px 15px 0; 44 | padding-left: 25px; 45 | } 46 | li { 47 | padding: 0; 48 | } 49 | } 50 | 51 | .fr-input-line >label { 52 | font-weight: normal; 53 | } 54 | 55 | .fr-top { 56 | border-radius: 3px 3px 0 0; 57 | } 58 | 59 | .fr-wrapper { 60 | min-height: 150px; 61 | max-height: 300px; 62 | overflow-y: scroll; 63 | } 64 | 65 | .second-toolbar { 66 | border-radius: 0 0 4px 4px; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/char_counter.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-box .fr-counter { 24 | padding: 10px; 25 | float: right; 26 | color: #999999; 27 | content: attr(data-chars); 28 | font-size: 14px; 29 | font-family: sans-serif; 30 | z-index: 1; 31 | border-radius: 2px 0 0 0; 32 | -moz-border-radius: 2px 0 0 0; 33 | -webkit-border-radius: 2px 0 0 0; 34 | -moz-background-clip: padding; 35 | -webkit-background-clip: padding-box; 36 | background-clip: padding-box; } 37 | .fr-box.fr-rtl .fr-counter { 38 | left: 0; 39 | right: auto; 40 | border-left: none; 41 | border-radius: 0 2px 0 0; 42 | -moz-border-radius: 0 2px 0 0; 43 | -webkit-border-radius: 0 2px 0 0; 44 | -moz-background-clip: padding; 45 | -webkit-background-clip: padding-box; 46 | background-clip: padding-box; } 47 | 48 | .fr-box.fr-code-view .fr-counter { 49 | display: none; } 50 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/char_counter.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-box .fr-counter{padding:10px;float:right;color:#999;content:attr(data-chars);font-size:14px;font-family:sans-serif;z-index:1;border-radius:2px 0 0 0;-moz-border-radius:2px 0 0 0;-webkit-border-radius:2px 0 0 0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.fr-box.fr-rtl .fr-counter{left:0;right:auto;border-left:none;border-radius:0 2px 0 0;-moz-border-radius:0 2px 0 0;-webkit-border-radius:0 2px 0 0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.fr-box.fr-code-view .fr-counter{display:none} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/code_view.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | textarea.fr-code { 24 | display: none; 25 | width: 100%; 26 | resize: none; 27 | -moz-resize: none; 28 | -webkit-resize: none; 29 | -webkit-box-sizing: border-box; 30 | -moz-box-sizing: border-box; 31 | box-sizing: border-box; 32 | border: none; 33 | padding: 10px; 34 | margin: 0; 35 | font-family: "Courier New",monospace; 36 | font-size: 14px; 37 | background: #FFF; 38 | color: #000; 39 | outline: none; } 40 | 41 | .fr-box.fr-rtl textarea.fr-code { 42 | direction: rtl; } 43 | 44 | .fr-box .CodeMirror { 45 | display: none; } 46 | 47 | .fr-box.fr-code-view textarea.fr-code { 48 | display: block; } 49 | .fr-box.fr-code-view .fr-element, .fr-box.fr-code-view .fr-placeholder, .fr-box.fr-code-view .fr-iframe { 50 | display: none; } 51 | .fr-box.fr-code-view .CodeMirror { 52 | display: block; } 53 | 54 | .fr-box.fr-inline.fr-code-view .fr-command.fr-btn.html-switch { 55 | display: block; } 56 | .fr-box.fr-inline .fr-command.fr-btn.html-switch { 57 | display: none; 58 | position: absolute; 59 | top: 0; 60 | right: 0; 61 | display: none; 62 | background: #FFF; 63 | color: #333333; 64 | -moz-outline: 0; 65 | outline: 0; 66 | border: 0; 67 | line-height: 1; 68 | cursor: pointer; 69 | text-align: left; 70 | padding: 8px 7px; 71 | -webkit-transition: background 0.2s ease 0s; 72 | -moz-transition: background 0.2s ease 0s; 73 | -ms-transition: background 0.2s ease 0s; 74 | -o-transition: background 0.2s ease 0s; 75 | border-radius: 0; 76 | -moz-border-radius: 0; 77 | -webkit-border-radius: 0; 78 | -moz-background-clip: padding; 79 | -webkit-background-clip: padding-box; 80 | background-clip: padding-box; 81 | z-index: 2; 82 | -webkit-box-sizing: border-box; 83 | -moz-box-sizing: border-box; 84 | box-sizing: border-box; 85 | text-decoration: none; 86 | user-select: none; 87 | -o-user-select: none; 88 | -moz-user-select: none; 89 | -khtml-user-select: none; 90 | -webkit-user-select: none; 91 | -ms-user-select: none; } 92 | .fr-box.fr-inline .fr-command.fr-btn.html-switch i { 93 | font-size: 24px; 94 | width: 24px; 95 | text-align: center; } 96 | .fr-box.fr-inline .fr-command.fr-btn.html-switch.fr-desktop:hover { 97 | background: #ebebeb; } 98 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/code_view.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}textarea.fr-code{display:none;width:100%;resize:none;-moz-resize:none;-webkit-resize:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;padding:10px;margin:0;font-family:"Courier New",monospace;font-size:14px;background:#FFF;color:#000;outline:none}.fr-box.fr-rtl textarea.fr-code{direction:rtl}.fr-box .CodeMirror{display:none}.fr-box.fr-code-view textarea.fr-code{display:block}.fr-box.fr-code-view .fr-element,.fr-box.fr-code-view .fr-placeholder,.fr-box.fr-code-view .fr-iframe{display:none}.fr-box.fr-code-view .CodeMirror{display:block}.fr-box.fr-inline.fr-code-view .fr-command.fr-btn.html-switch{display:block}.fr-box.fr-inline .fr-command.fr-btn.html-switch{display:none;position:absolute;top:0;right:0;display:none;background:#FFF;color:#333;-moz-outline:0;outline:0;border:0;line-height:1;cursor:pointer;text-align:left;padding:8px 7px;-webkit-transition:background 0.2s ease 0s;-moz-transition:background 0.2s ease 0s;-ms-transition:background 0.2s ease 0s;-o-transition:background 0.2s ease 0s;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;text-decoration:none;user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none}.fr-box.fr-inline .fr-command.fr-btn.html-switch i{font-size:24px;width:24px;text-align:center}.fr-box.fr-inline .fr-command.fr-btn.html-switch.fr-desktop:hover{background:#ebebeb} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/colors.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-popup .fr-layer.fr-color-hex-layer { 24 | margin: 0; 25 | padding: 20px; 26 | padding-top: 0; 27 | float: left; } 28 | .fr-popup .fr-layer.fr-color-hex-layer .fr-input-line { 29 | float: left; 30 | width: calc(100% - 50px); 31 | padding: 15px 0 0; } 32 | .fr-popup .fr-layer.fr-color-hex-layer .fr-action-buttons { 33 | float: right; 34 | width: 38px; 35 | height: 40px; 36 | padding: 17px 0 0; 37 | margin: 0; } 38 | .fr-popup .fr-layer.fr-color-hex-layer .fr-action-buttons button.fr-command { 39 | border-radius: 2px; 40 | -moz-border-radius: 2px; 41 | -webkit-border-radius: 2px; 42 | -moz-background-clip: padding; 43 | -webkit-background-clip: padding-box; 44 | background-clip: padding-box; 45 | font-size: 13px; 46 | height: 40px; 47 | width: 38px; } 48 | .fr-popup .fr-separator + .fr-colors-tabs { 49 | margin-left: 2px; 50 | margin-right: 2px; } 51 | .fr-popup .fr-color-set { 52 | line-height: 0; 53 | display: none; } 54 | .fr-popup .fr-color-set.fr-selected-set { 55 | display: block; 56 | padding: 20px; 57 | padding-bottom: 0; } 58 | .fr-popup .fr-color-set > span { 59 | display: inline-block; 60 | width: 32px; 61 | height: 32px; 62 | position: relative; 63 | z-index: 1; } 64 | .fr-popup .fr-color-set > span > i, .fr-popup .fr-color-set > span > svg { 65 | text-align: center; 66 | line-height: 32px; 67 | height: 24px; 68 | width: 24px; 69 | margin: 4px; 70 | font-size: 13px; 71 | position: absolute; 72 | bottom: 0; 73 | cursor: default; 74 | left: 0; } 75 | .fr-popup .fr-color-set > span > i path, .fr-popup .fr-color-set > span > svg path { 76 | fill: #222222; } 77 | .fr-popup .fr-color-set > span .fr-selected-color { 78 | color: #FFF; 79 | font-family: FontAwesome; 80 | font-size: 13px; 81 | font-weight: 400; 82 | line-height: 32px; 83 | position: absolute; 84 | top: 0; 85 | bottom: 0; 86 | right: 0; 87 | left: 0; 88 | text-align: center; 89 | cursor: default; } 90 | .fr-popup .fr-color-set > span:hover, .fr-popup .fr-color-set > span:focus { 91 | outline: 1px solid #222222; 92 | z-index: 2; } 93 | 94 | .fr-rtl .fr-popup .fr-colors-tabs .fr-colors-tab.fr-selected-tab[data-param1="text"] ~ [data-param1="background"]::after { 95 | -webkit-transform: translate3d(100%, 0, 0); 96 | -moz-transform: translate3d(100%, 0, 0); 97 | -ms-transform: translate3d(100%, 0, 0); 98 | -o-transform: translate3d(100%, 0, 0); } 99 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/colors.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-popup .fr-layer.fr-color-hex-layer{margin:0;padding:20px;padding-top:0;float:left}.fr-popup .fr-layer.fr-color-hex-layer .fr-input-line{float:left;width:calc(100% - 50px);padding:15px 0 0}.fr-popup .fr-layer.fr-color-hex-layer .fr-action-buttons{float:right;width:38px;height:40px;padding:17px 0 0;margin:0}.fr-popup .fr-layer.fr-color-hex-layer .fr-action-buttons button.fr-command{border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;font-size:13px;height:40px;width:38px}.fr-popup .fr-separator+.fr-colors-tabs{margin-left:2px;margin-right:2px}.fr-popup .fr-color-set{line-height:0;display:none}.fr-popup .fr-color-set.fr-selected-set{display:block;padding:20px;padding-bottom:0}.fr-popup .fr-color-set>span{display:inline-block;width:32px;height:32px;position:relative;z-index:1}.fr-popup .fr-color-set>span>i,.fr-popup .fr-color-set>span>svg{text-align:center;line-height:32px;height:24px;width:24px;margin:4px;font-size:13px;position:absolute;bottom:0;cursor:default;left:0}.fr-popup .fr-color-set>span>i path,.fr-popup .fr-color-set>span>svg path{fill:#222}.fr-popup .fr-color-set>span .fr-selected-color{color:#FFF;font-family:FontAwesome;font-size:13px;font-weight:400;line-height:32px;position:absolute;top:0;bottom:0;right:0;left:0;text-align:center;cursor:default}.fr-popup .fr-color-set>span:hover,.fr-popup .fr-color-set>span:focus{outline:1px solid #222;z-index:2}.fr-rtl .fr-popup .fr-colors-tabs .fr-colors-tab.fr-selected-tab[data-param1="text"] ~ [data-param1="background"]::after{-webkit-transform:translate3d(100%, 0, 0);-moz-transform:translate3d(100%, 0, 0);-ms-transform:translate3d(100%, 0, 0);-o-transform:translate3d(100%, 0, 0)} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/draggable.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-drag-helper { 24 | background: #0098f7; 25 | height: 2px; 26 | margin-top: -1px; 27 | -webkit-opacity: 0.2; 28 | -moz-opacity: 0.2; 29 | opacity: 0.2; 30 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 31 | position: absolute; 32 | z-index: 2147483640; 33 | display: none; } 34 | .fr-drag-helper.fr-visible { 35 | display: block; } 36 | 37 | .fr-dragging { 38 | -webkit-opacity: 0.4; 39 | -moz-opacity: 0.4; 40 | opacity: 0.4; 41 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; } 42 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/draggable.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-drag-helper{background:#0098f7;height:2px;margin-top:-1px;-webkit-opacity:.2;-moz-opacity:.2;opacity:.2;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";position:absolute;z-index:2147483640;display:none}.fr-drag-helper.fr-visible{display:block}.fr-dragging{-webkit-opacity:.4;-moz-opacity:.4;opacity:.4;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/emoticons.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-popup .fr-emoticon { 24 | width: 24px; 25 | height: 24px; 26 | font-family: "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; } 27 | .fr-popup .fr-emoticon img { 28 | height: 24px; 29 | width: 24px; } 30 | .fr-popup .fr-command.fr-btn.fr-tabs-unicode { 31 | padding: 0 0 0 14px; } 32 | @media screen and (-ms-high-contrast: active) and (min-width: 768px), (-ms-high-contrast: none) and (min-width: 768px) { 33 | .fr-popup .fr-icon-container.fr-emoticon-container { 34 | width: 368px; } } 35 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/emoticons.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-popup .fr-emoticon{width:24px;height:24px;font-family:"Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols}.fr-popup .fr-emoticon img{height:24px;width:24px}.fr-popup .fr-command.fr-btn.fr-tabs-unicode{padding:0 0 0 14px}@media screen and (-ms-high-contrast: active) and (min-width: 768px), (-ms-high-contrast: none) and (min-width: 768px){.fr-popup .fr-icon-container.fr-emoticon-container{width:368px}} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/file.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-popup .fr-file-upload-layer { 24 | border: dashed 2px #bdbdbd; 25 | padding: 25px 0; 26 | margin: 20px; 27 | position: relative; 28 | font-size: 14px; 29 | letter-spacing: 1px; 30 | line-height: 140%; 31 | -webkit-box-sizing: border-box; 32 | -moz-box-sizing: border-box; 33 | box-sizing: border-box; 34 | text-align: center; } 35 | .fr-popup .fr-file-upload-layer:hover { 36 | background: #ebebeb; } 37 | .fr-popup .fr-file-upload-layer.fr-drop { 38 | background: #ebebeb; 39 | border-color: #0098f7; } 40 | .fr-popup .fr-file-upload-layer .fr-form { 41 | -webkit-opacity: 0; 42 | -moz-opacity: 0; 43 | opacity: 0; 44 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 45 | position: absolute; 46 | top: 0; 47 | bottom: 0; 48 | left: 0; 49 | right: 0; 50 | z-index: 2147483640; 51 | overflow: hidden; 52 | margin: 0 !important; 53 | padding: 0 !important; 54 | width: 100% !important; } 55 | .fr-popup .fr-file-upload-layer .fr-form input { 56 | cursor: pointer; 57 | position: absolute; 58 | right: 0; 59 | top: 0; 60 | bottom: 0; 61 | width: 500%; 62 | height: 100%; 63 | margin: 0; 64 | font-size: 400px; } 65 | .fr-popup .fr-file-progress-bar-layer { 66 | -webkit-box-sizing: border-box; 67 | -moz-box-sizing: border-box; 68 | box-sizing: border-box; } 69 | .fr-popup .fr-file-progress-bar-layer > h3 { 70 | font-size: 16px; 71 | margin: 10px 0; 72 | font-weight: normal; } 73 | .fr-popup .fr-file-progress-bar-layer > div.fr-action-buttons { 74 | display: none; } 75 | .fr-popup .fr-file-progress-bar-layer > div.fr-loader { 76 | background: #b3e0fd; 77 | height: 10px; 78 | width: 100%; 79 | margin-top: 20px; 80 | overflow: hidden; 81 | position: relative; } 82 | .fr-popup .fr-file-progress-bar-layer > div.fr-loader span { 83 | display: block; 84 | height: 100%; 85 | width: 0%; 86 | background: #0098f7; 87 | -webkit-transition: width 0.2s ease 0s; 88 | -moz-transition: width 0.2s ease 0s; 89 | -ms-transition: width 0.2s ease 0s; 90 | -o-transition: width 0.2s ease 0s; } 91 | .fr-popup .fr-file-progress-bar-layer > div.fr-loader.fr-indeterminate span { 92 | width: 30% !important; 93 | position: absolute; 94 | top: 0; 95 | -webkit-animation: loading 2s linear infinite; 96 | -moz-animation: loading 2s linear infinite; 97 | -o-animation: loading 2s linear infinite; 98 | animation: loading 2s linear infinite; } 99 | .fr-popup .fr-file-progress-bar-layer.fr-error > div.fr-loader { 100 | display: none; } 101 | .fr-popup .fr-file-progress-bar-layer.fr-error > div.fr-action-buttons { 102 | display: block; } 103 | 104 | @keyframes loading { 105 | from { 106 | left: -25%; } 107 | to { 108 | left: 100%; } } 109 | @-webkit-keyframes loading { 110 | from { 111 | left: -25%; } 112 | to { 113 | left: 100%; } } 114 | @-moz-keyframes loading { 115 | from { 116 | left: -25%; } 117 | to { 118 | left: 100%; } } 119 | @-o-keyframes loading { 120 | from { 121 | left: -25%; } 122 | to { 123 | left: 100%; } } 124 | @keyframes loading { 125 | from { 126 | left: -25%; } 127 | to { 128 | left: 100%; } } 129 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/file.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-popup .fr-file-upload-layer{border:dashed 2px #bdbdbd;padding:25px 0;margin:20px;position:relative;font-size:14px;letter-spacing:1px;line-height:140%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;text-align:center}.fr-popup .fr-file-upload-layer:hover{background:#ebebeb}.fr-popup .fr-file-upload-layer.fr-drop{background:#ebebeb;border-color:#0098f7}.fr-popup .fr-file-upload-layer .fr-form{-webkit-opacity:0;-moz-opacity:0;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";position:absolute;top:0;bottom:0;left:0;right:0;z-index:2147483640;overflow:hidden;margin:0 !important;padding:0 !important;width:100% !important}.fr-popup .fr-file-upload-layer .fr-form input{cursor:pointer;position:absolute;right:0;top:0;bottom:0;width:500%;height:100%;margin:0;font-size:400px}.fr-popup .fr-file-progress-bar-layer{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fr-popup .fr-file-progress-bar-layer>h3{font-size:16px;margin:10px 0;font-weight:normal}.fr-popup .fr-file-progress-bar-layer>div.fr-action-buttons{display:none}.fr-popup .fr-file-progress-bar-layer>div.fr-loader{background:#b3e0fd;height:10px;width:100%;margin-top:20px;overflow:hidden;position:relative}.fr-popup .fr-file-progress-bar-layer>div.fr-loader span{display:block;height:100%;width:0%;background:#0098f7;-webkit-transition:width 0.2s ease 0s;-moz-transition:width 0.2s ease 0s;-ms-transition:width 0.2s ease 0s;-o-transition:width 0.2s ease 0s}.fr-popup .fr-file-progress-bar-layer>div.fr-loader.fr-indeterminate span{width:30% !important;position:absolute;top:0;-webkit-animation:loading 2s linear infinite;-moz-animation:loading 2s linear infinite;-o-animation:loading 2s linear infinite;animation:loading 2s linear infinite}.fr-popup .fr-file-progress-bar-layer.fr-error>div.fr-loader{display:none}.fr-popup .fr-file-progress-bar-layer.fr-error>div.fr-action-buttons{display:block}@keyframes loading{from{left:-25%}to{left:100%}}@-webkit-keyframes loading{from{left:-25%}to{left:100%}}@-moz-keyframes loading{from{left:-25%}to{left:100%}}@-o-keyframes loading{from{left:-25%}to{left:100%}}@keyframes loading{from{left:-25%}to{left:100%}} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/filestack.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-popup .fr-command.fr-btn[data-cmd="filestackIcon"] svg path, 8 | .fr-popup .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path, 9 | .fr-popup .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path, 10 | .fr-toolbar .fr-command.fr-btn[data-cmd="openFilePicker"] svg path, 11 | .fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path, 12 | .fr-popup .fr-tabs .fr-command.fr-btn[data-cmd="openFilePicker"] svg path, 13 | .fr-popup .fr-tabs .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path, 14 | .fr-popup .fr-tabs .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path, 15 | .fr-command.fr-btn[data-cmd="openFilePickerReplaceImageOnly"] svg path, 16 | .fr-command.fr-btn[data-cmd="openFilePickerReplaceVideoOnly"] svg path, 17 | .fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path, 18 | .fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerImageOnly"] svg path:last-child, 19 | .fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerVideoOnly"] svg path:last-child, 20 | .fr-popup .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path, 21 | .fr-popup .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path, 22 | .fr-popup .fr-command.fr-btn[data-cmd="filestackIcon"] svg path, 23 | .fr-popup .fr-command.fr-btn[data-cmd="openFilePickerFile"] svg path { 24 | fill: #ef4a25; } 25 | 26 | .fr-command.fr-filestack-active.fr-btn.fr-filestack-active svg path { 27 | fill: #0098F7; } 28 | 29 | .fsp-picker-appear-active { 30 | position: absolute; 31 | top: 50%; 32 | left: 50%; 33 | transform: translate(-50%, -50%); 34 | z-index: 9; } 35 | 36 | body.fr-fullscreen .fs-transforms-container { 37 | position: absolute; 38 | z-index: 2247483660; } 39 | 40 | .fsp-notifications__container { 41 | position: fixed !important; } 42 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/filestack.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-popup .fr-command.fr-btn[data-cmd="filestackIcon"] svg path,.fr-popup .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path,.fr-popup .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path,.fr-toolbar .fr-command.fr-btn[data-cmd="openFilePicker"] svg path,.fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path,.fr-popup .fr-tabs .fr-command.fr-btn[data-cmd="openFilePicker"] svg path,.fr-popup .fr-tabs .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path,.fr-popup .fr-tabs .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path,.fr-command.fr-btn[data-cmd="openFilePickerReplaceImageOnly"] svg path,.fr-command.fr-btn[data-cmd="openFilePickerReplaceVideoOnly"] svg path,.fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path,.fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerImageOnly"] svg path:last-child,.fr-toolbar .fr-command.fr-btn[data-cmd="openFilePickerVideoOnly"] svg path:last-child,.fr-popup .fr-command.fr-btn[data-cmd="openFilePickerImage"] svg path,.fr-popup .fr-command.fr-btn[data-cmd="openFilePickerVideo"] svg path,.fr-popup .fr-command.fr-btn[data-cmd="filestackIcon"] svg path,.fr-popup .fr-command.fr-btn[data-cmd="openFilePickerFile"] svg path{fill:#ef4a25}.fr-command.fr-filestack-active.fr-btn.fr-filestack-active svg path{fill:#0098F7}.fsp-picker-appear-active{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:9}body.fr-fullscreen .fs-transforms-container{position:absolute;z-index:2247483660}.fsp-notifications__container{position:fixed !important} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/fullscreen.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | body.fr-fullscreen { 24 | overflow: hidden; 25 | height: 100%; 26 | width: 100%; 27 | position: fixed; } 28 | 29 | .fr-box.fr-fullscreen { 30 | margin: 0 !important; 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | bottom: 0; 35 | right: 0; 36 | z-index: 2147483630 !important; 37 | width: auto !important; } 38 | .fr-box.fr-fullscreen .fr-wrapper { 39 | background-color: #FFF; } 40 | .fr-box.fr-fullscreen.fr-basic.fr-top .fr-wrapper { 41 | border-radius: 0; 42 | -moz-border-radius: 0; 43 | -webkit-border-radius: 0; 44 | -moz-background-clip: padding; 45 | -webkit-background-clip: padding-box; 46 | background-clip: padding-box; } 47 | .fr-box.fr-fullscreen.fr-basic.fr-bottom .fr-wrapper { 48 | border-radius: 0; 49 | -moz-border-radius: 0; 50 | -webkit-border-radius: 0; 51 | -moz-background-clip: padding; 52 | -webkit-background-clip: padding-box; 53 | background-clip: padding-box; } 54 | .fr-box.fr-fullscreen .fr-toolbar { 55 | border-radius: 0; 56 | -moz-border-radius: 0; 57 | -webkit-border-radius: 0; 58 | -moz-background-clip: padding; 59 | -webkit-background-clip: padding-box; 60 | background-clip: padding-box; } 61 | .fr-box.fr-fullscreen .fr-toolbar.fr-top { 62 | top: 0 !important; } 63 | .fr-box.fr-fullscreen .fr-toolbar.fr-bottom { 64 | bottom: 0 !important; } 65 | .fr-box.fr-fullscreen .fr-second-toolbar { 66 | margin-top: 0; 67 | border-radius: 0; 68 | -moz-border-radius: 0; 69 | -webkit-border-radius: 0; 70 | -moz-background-clip: padding; 71 | -webkit-background-clip: padding-box; 72 | background-clip: padding-box; } 73 | 74 | .fr-fullscreen-wrapper { 75 | z-index: 2147483640 !important; 76 | width: 100% !important; 77 | margin: 0 !important; 78 | padding: 0 !important; 79 | overflow: visible !important; } 80 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/fullscreen.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}body.fr-fullscreen{overflow:hidden;height:100%;width:100%;position:fixed}.fr-box.fr-fullscreen{margin:0 !important;position:fixed;top:0;left:0;bottom:0;right:0;z-index:2147483630 !important;width:auto !important}.fr-box.fr-fullscreen .fr-wrapper{background-color:#FFF}.fr-box.fr-fullscreen.fr-basic.fr-top .fr-wrapper{border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.fr-box.fr-fullscreen.fr-basic.fr-bottom .fr-wrapper{border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.fr-box.fr-fullscreen .fr-toolbar{border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.fr-box.fr-fullscreen .fr-toolbar.fr-top{top:0 !important}.fr-box.fr-fullscreen .fr-toolbar.fr-bottom{bottom:0 !important}.fr-box.fr-fullscreen .fr-second-toolbar{margin-top:0;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.fr-fullscreen-wrapper{z-index:2147483640 !important;width:100% !important;margin:0 !important;padding:0 !important;overflow:visible !important} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/help.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal { 24 | text-align: left; 25 | padding: 20px 20px 10px; } 26 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table { 27 | border-collapse: collapse; 28 | font-size: 14px; 29 | line-height: 1.5; 30 | width: 100%; } 31 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table + table { 32 | margin-top: 20px; } 33 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tr { 34 | border: 0; } 35 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table th { 36 | text-align: left; } 37 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table th, .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table td { 38 | padding: 6px 0 4px; } 39 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tbody tr { 40 | border-bottom: solid 1px #ebebeb; } 41 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tbody td:first-child { 42 | width: 60%; 43 | color: #646464; } 44 | .fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tbody td:nth-child(n+2) { 45 | letter-spacing: 0.5px; } 46 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/help.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal{text-align:left;padding:20px 20px 10px}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table{border-collapse:collapse;font-size:14px;line-height:1.5;width:100%}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table+table{margin-top:20px}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tr{border:0}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table th{text-align:left}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table th,.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table td{padding:6px 0 4px}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tbody tr{border-bottom:solid 1px #ebebeb}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tbody td:first-child{width:60%;color:#646464}.fr-modal .fr-modal-wrapper .fr-modal-body .fr-help-modal table tbody td:nth-child(n+2){letter-spacing:0.5px} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/line_breaker.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-line-breaker { 24 | cursor: text; 25 | border-top: 1px solid #0098f7; 26 | position: fixed; 27 | z-index: 2; 28 | display: none; } 29 | .fr-line-breaker.fr-visible { 30 | display: block; } 31 | .fr-line-breaker a.fr-floating-btn { 32 | position: absolute; 33 | left: calc(50% - (40px / 2)); 34 | top: -20px; } 35 | .fr-line-breaker a.fr-floating-btn svg { 36 | margin: 8px; 37 | height: 24px; 38 | width: 24px; } 39 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/line_breaker.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-line-breaker{cursor:text;border-top:1px solid #0098f7;position:fixed;z-index:2;display:none}.fr-line-breaker.fr-visible{display:block}.fr-line-breaker a.fr-floating-btn{position:absolute;left:calc(50% - (40px / 2));top:-20px}.fr-line-breaker a.fr-floating-btn svg{margin:8px;height:24px;width:24px} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/markdown.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-wrapper-markdown { 24 | display: flex; } 25 | 26 | .fr-markdown-view { 27 | width: calc(52% - 1px); 28 | box-sizing: inherit; } 29 | 30 | .fr-markdown-editor { 31 | width: calc(48% - 1px); 32 | box-sizing: inherit; 33 | background-color: #eee; } 34 | 35 | .fr-markdown-editor > p { 36 | margin: 0; } 37 | 38 | .fr-markdown-view > p { 39 | margin-top: 0; } 40 | 41 | .gutter-horizontal { 42 | display: flex; 43 | z-index: 9; 44 | background-color: #dadada; 45 | cursor: col-resize; 46 | width: 2px; } 47 | 48 | .e-resize-handler { 49 | z-index: 9; 50 | width: 1px; 51 | display: flex; 52 | justify-content: center; 53 | align-items: center; 54 | align-self: center; 55 | position: relative; 56 | font-size: 10px; 57 | color: #c5c5c5; } 58 | 59 | .fr-markdown-view > dl { 60 | margin-top: 0; 61 | margin-bottom: 1rem; } 62 | 63 | .fr-markdown-view > dt { 64 | font-weight: 700; } 65 | 66 | .fr-markdown-view > dd { 67 | margin-bottom: .5rem; 68 | margin-left: 0; } 69 | 70 | .fr-markdown-view > pre { 71 | white-space: pre-wrap; 72 | white-space: -moz-pre-wrap; 73 | white-space: -pre-wrap; 74 | white-space: -o-pre-wrap; 75 | word-wrap: break-word; 76 | background-color: #f8f8f8; 77 | border: 1px solid #dfdfdf; 78 | margin-top: 1.5em; 79 | margin-bottom: 1.5em; 80 | padding: 0.125rem 0.3125rem 0.0625rem; } 81 | 82 | .fr-markdown-view > code { 83 | background-color: #f8f8f8; 84 | border-color: #dfdfdf; 85 | border-style: solid; 86 | border-width: 1px; 87 | color: #333; 88 | font-family: Consolas,"Liberation Mono",Courier,monospace; 89 | font-weight: normal; 90 | padding: 0.125rem 0.3125rem 0.0625rem; } 91 | 92 | .fr-markdown-view > pre code { 93 | background-color: transparent; 94 | border: 0; 95 | padding: 0; } 96 | 97 | .fr-markdown-view > sup { 98 | top: -.5em; } 99 | 100 | .footnote-a { 101 | color: #007bff; 102 | text-decoration: none; 103 | background-color: transparent; } 104 | 105 | .fr-markdown-view > hr { 106 | margin-top: 1rem; 107 | margin-bottom: 1rem; 108 | border: 0; 109 | border-top: 1px solid rgba(0, 0, 0, 0.1); } 110 | 111 | .blockquote { 112 | margin: 0 0 1rem; 113 | border-left: 5px solid #eee; 114 | padding: 10px 20px; 115 | font-size: 1.25rem; } 116 | 117 | .fr-markdown-view > table { 118 | width: 100%; 119 | max-width: 100%; 120 | margin-bottom: 20px; 121 | background-color: transparent; 122 | border-spacing: 0; 123 | border-collapse: collapse; } 124 | 125 | .fr-markdown-view > table > tbody > tr > td, 126 | .fr-markdown-view > table > tbody > tr > th, 127 | .fr-markdown-view > table > thead > tr > td, 128 | .fr-markdown-view > table > thead > tr > th { 129 | padding: 8px; 130 | line-height: 1.42857143; 131 | vertical-align: top; 132 | border: 1px solid #ddd; } 133 | 134 | .fr-markdown-view > table > thead > tr > td, 135 | .fr-markdown-view > table > thead > tr > th { 136 | border-bottom-width: 2px; } 137 | 138 | .fr-markdown-view > table > tbody > tr:nth-of-type(odd) { 139 | background-color: #f9f9f9; } 140 | 141 | .fr-markdown-view > a { 142 | color: #337ab7; 143 | text-decoration: none; } 144 | 145 | .fr-markdown-view > h1 { 146 | font-size: 2em !important; } 147 | 148 | .fr-markdown-view > h2 { 149 | font-size: 1.5em !important; } 150 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/markdown.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-wrapper-markdown{display:flex}.fr-markdown-view{width:calc(52% - 1px);box-sizing:inherit}.fr-markdown-editor{width:calc(48% - 1px);box-sizing:inherit;background-color:#eee}.fr-markdown-editor>p{margin:0}.fr-markdown-view>p{margin-top:0}.gutter-horizontal{display:flex;z-index:9;background-color:#dadada;cursor:col-resize;width:2px}.e-resize-handler{z-index:9;width:1px;display:flex;justify-content:center;align-items:center;align-self:center;position:relative;font-size:10px;color:#c5c5c5}.fr-markdown-view>dl{margin-top:0;margin-bottom:1rem}.fr-markdown-view>dt{font-weight:700}.fr-markdown-view>dd{margin-bottom:.5rem;margin-left:0}.fr-markdown-view>pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;background-color:#f8f8f8;border:1px solid #dfdfdf;margin-top:1.5em;margin-bottom:1.5em;padding:0.125rem 0.3125rem 0.0625rem}.fr-markdown-view>code{background-color:#f8f8f8;border-color:#dfdfdf;border-style:solid;border-width:1px;color:#333;font-family:Consolas,"Liberation Mono",Courier,monospace;font-weight:normal;padding:0.125rem 0.3125rem 0.0625rem}.fr-markdown-view>pre code{background-color:transparent;border:0;padding:0}.fr-markdown-view>sup{top:-.5em}.footnote-a{color:#007bff;text-decoration:none;background-color:transparent}.fr-markdown-view>hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,0.1)}.blockquote{margin:0 0 1rem;border-left:5px solid #eee;padding:10px 20px;font-size:1.25rem}.fr-markdown-view>table{width:100%;max-width:100%;margin-bottom:20px;background-color:transparent;border-spacing:0;border-collapse:collapse}.fr-markdown-view>table>tbody>tr>td,.fr-markdown-view>table>tbody>tr>th,.fr-markdown-view>table>thead>tr>td,.fr-markdown-view>table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border:1px solid #ddd}.fr-markdown-view>table>thead>tr>td,.fr-markdown-view>table>thead>tr>th{border-bottom-width:2px}.fr-markdown-view>table>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.fr-markdown-view>a{color:#337ab7;text-decoration:none}.fr-markdown-view>h1{font-size:2em !important}.fr-markdown-view>h2{font-size:1.5em !important} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/quick_insert.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-quick-insert { 24 | position: absolute; 25 | z-index: 2147483639; 26 | white-space: nowrap; 27 | padding-right: 10px; 28 | -webkit-box-sizing: content-box; 29 | -moz-box-sizing: content-box; 30 | box-sizing: content-box; } 31 | .fr-quick-insert a.fr-floating-btn svg { 32 | margin: 8px; 33 | width: 24px; 34 | height: 24px; } 35 | .fr-quick-insert.fr-on a.fr-floating-btn svg { 36 | -webkit-transform: rotate(135deg); 37 | -moz-transform: rotate(135deg); 38 | -ms-transform: rotate(135deg); 39 | -o-transform: rotate(135deg); } 40 | .fr-quick-insert.fr-hidden { 41 | display: none; } 42 | 43 | .fr-qi-helper { 44 | position: absolute; 45 | z-index: 3; 46 | padding-left: 20px; 47 | white-space: nowrap; } 48 | .fr-qi-helper a.fr-btn.fr-floating-btn { 49 | text-align: center; 50 | padding: 6px 10px 10px 10px; 51 | display: inline-block; 52 | color: #222222; 53 | background: #FFF; 54 | -webkit-opacity: 0; 55 | -moz-opacity: 0; 56 | opacity: 0; 57 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 58 | -webkit-transform: scale(0); 59 | -moz-transform: scale(0); 60 | -ms-transform: scale(0); 61 | -o-transform: scale(0); } 62 | .fr-qi-helper a.fr-btn.fr-floating-btn svg { 63 | fill: #222222; } 64 | .fr-qi-helper a.fr-btn.fr-floating-btn.fr-size-1 { 65 | -webkit-opacity: 1; 66 | -moz-opacity: 1; 67 | opacity: 1; 68 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 69 | -webkit-transform: scale(1); 70 | -moz-transform: scale(1); 71 | -ms-transform: scale(1); 72 | -o-transform: scale(1); } 73 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/quick_insert.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-quick-insert{position:absolute;z-index:2147483639;white-space:nowrap;padding-right:10px;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.fr-quick-insert a.fr-floating-btn svg{margin:8px;width:24px;height:24px}.fr-quick-insert.fr-on a.fr-floating-btn svg{-webkit-transform:rotate(135deg);-moz-transform:rotate(135deg);-ms-transform:rotate(135deg);-o-transform:rotate(135deg)}.fr-quick-insert.fr-hidden{display:none}.fr-qi-helper{position:absolute;z-index:3;padding-left:20px;white-space:nowrap}.fr-qi-helper a.fr-btn.fr-floating-btn{text-align:center;padding:6px 10px 10px 10px;display:inline-block;color:#222;background:#FFF;-webkit-opacity:0;-moz-opacity:0;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";-webkit-transform:scale(0);-moz-transform:scale(0);-ms-transform:scale(0);-o-transform:scale(0)}.fr-qi-helper a.fr-btn.fr-floating-btn svg{fill:#222}.fr-qi-helper a.fr-btn.fr-floating-btn.fr-size-1{-webkit-opacity:1;-moz-opacity:1;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1)} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/special_characters.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-popup .fr-buttons.fr-tabs .fr-special-character-category { 24 | padding: 10px 15px; } 25 | .fr-popup .fr-buttons.fr-tabs .fr-special-character-category span { 26 | font-weight: normal; 27 | font-size: 16px; } 28 | .fr-popup .fr-special-character { 29 | width: 24px; 30 | height: 24px; } 31 | @media screen and (-ms-high-contrast: active) and (min-width: 768px), (-ms-high-contrast: none) and (min-width: 768px) { 32 | .fr-popup .fr-icon-container.fr-sc-container { 33 | width: 368px; } } 34 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/special_characters.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-popup .fr-buttons.fr-tabs .fr-special-character-category{padding:10px 15px}.fr-popup .fr-buttons.fr-tabs .fr-special-character-category span{font-weight:normal;font-size:16px}.fr-popup .fr-special-character{width:24px;height:24px}@media screen and (-ms-high-contrast: active) and (min-width: 768px), (-ms-high-contrast: none) and (min-width: 768px){.fr-popup .fr-icon-container.fr-sc-container{width:368px}} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/table.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-element table td.fr-selected-cell,.fr-element table th.fr-selected-cell{border:1px double #0098f7;position:relative}.fr-element table td.fr-selected-cell:after,.fr-element table th.fr-selected-cell:after{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(0,100,255,0.15);pointer-events:none}.fr-element table td,.fr-element table th{user-select:text;-o-user-select:text;-moz-user-select:text;-khtml-user-select:text;-webkit-user-select:text;-ms-user-select:text}.fr-element .fr-no-selection table td,.fr-element .fr-no-selection table th{user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none}.fr-table-resizer{cursor:col-resize;position:absolute;z-index:3;display:none}.fr-table-resizer.fr-moving{z-index:2}.fr-table-resizer div{-webkit-opacity:0;-moz-opacity:0;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";border-right:1px solid #0098f7}.fr-no-selection{user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none}.fr-table-selector{display:block;position:absolute;z-index:9999;width:16px;height:16px;padding:3px;border:transparent 2px solid;border-radius:4px 4px 0 0}.fr-table-selector a{width:16px;height:16px;display:block}.fr-table-selector a>svg{width:16px;height:16px}.fr-table-selector-active{opacity:1;visibility:visible;border:#fdcf00 2px solid}.fr-table-selector-active a>svg{color:#fdcf00}.fr-table-selector-active-selected{border:#0d65ff 2px solid}.fr-table-selector-active-selected a>svg{color:#0d65ff}.fr-table-selector-inactive{opacity:0;visibility:hidden}.fr-view .fr-table-selection-hover{outline:#fdcf00 2px solid}.fr-view .fr-table-selected{outline:#0d65ff 2px solid;caret-color:transparent}.fr-popup .fr-table-size{margin:20px}.fr-popup .fr-table-size .fr-table-size-info{text-align:center;font-size:14px}.fr-popup .fr-table-size .fr-select-table-size{line-height:0;padding:5px;white-space:nowrap}.fr-popup .fr-table-size .fr-select-table-size>span{display:inline-block;padding:0 4px 4px 0;background:transparent}.fr-popup .fr-table-size .fr-select-table-size>span>span{display:inline-block;width:18px;height:18px;border:1px solid #DDD}.fr-popup .fr-table-size .fr-select-table-size>span.hover{background:transparent}.fr-popup .fr-table-size .fr-select-table-size>span.hover>span{background:rgba(0,152,247,0.3);border:solid 1px #0098f7}.fr-popup .fr-table-size .fr-select-table-size .new-line::after{clear:both;display:block;content:"";height:0}.fr-popup.fr-above .fr-table-size .fr-select-table-size>span{display:inline-block !important}.fr-popup .fr-table-colors{display:block;padding:20px;padding-bottom:0}.fr-popup.fr-desktop .fr-table-size .fr-select-table-size>span>span{width:12px;height:12px}.fr-insert-helper{position:absolute;z-index:9999;white-space:nowrap} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/plugins/trim_video.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}#fr-form-container{margin:auto;position:relative;top:10%;background-color:#f5f5f5;width:60%;border-radius:5px;z-index:9002;overflow:auto;background-color:#fefefe}.fr-trim-video-name{font-family:Arial, Helvetica, sans-serif;padding-top:15px}.fr-file-loader{border:4px solid #f3f3f3;border-radius:50%;border-top:4px solid #53777a;display:inline-block !important;-webkit-animation:spin 2s linear infinite;animation:spin 2s linear infinite;width:20px;height:20px;display:block !important;align-items:center}.fr-trim-button{margin-top:5px;height:36px;line-height:1;color:#0098f7;padding:10px;cursor:pointer;text-decoration:none;border:none;background:none;font-size:16px;border-radius:5px;background-color:#eff5fa;outline:none}.fr-trim-button:hover{background:#ebebeb}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.fr-slidecontainer{width:100%}.fr-slider{-webkit-appearance:none;width:100%;height:15px;background:#d3d3d3}.fr-video-trim-buttons{text-align:right;padding-bottom:5px;padding-right:15px;margin-top:10px}.fr-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:15px;height:15px;border-radius:50%;cursor:pointer}.fr-slider::-moz-range-thumb{width:15px;height:15px;background:#3498db;border-radius:50%;cursor:pointer}.fr-range-value-start{position:absolute}.fr-range-value-start>span{width:60px;height:24px;line-height:24px;text-align:center;background:#03a9f4;color:#fff;font-size:12px;display:block;position:absolute;left:50%;transform:translate(-85%, 0);border-radius:6px}.fr-range-value-start>span:before{content:"";position:absolute;width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;left:86%;margin-left:-5px;margin-top:-1px}.fr-range-value-end{position:absolute}.fr-range-value-end>span{width:60px;height:24px;line-height:24px;text-align:center;background:#03a9f4;color:#fff;font-size:12px;display:block;position:absolute;left:14%;transform:translate(-8%, 0);border-radius:6px}.fr-range-value-end>span:before{content:"";position:absolute;width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;left:14%;margin-left:-5px;margin-top:-1px}#startTimeValue{top:-153% !important}#startTimeValue span:before{border-top:10px solid #03a9f4;top:100%}#endTimeValue{top:-153% !important}#endTimeValue span:before{border-top:10px solid #03a9f4;top:100%}.fr-range-slider{position:relative;width:80%;height:15px}.fr-range-slider>input{pointer-events:none;position:absolute;left:0;top:10px;width:100%;outline:none;height:6px;border-radius:10px}.fr-range-slider>input::-webkit-slider-thumb{pointer-events:all;position:relative;z-index:1;-webkit-appearance:none;appearance:none;width:15px;height:15px;background:#3498db;cursor:pointer;border-radius:7px;margin-top:-3.6px}.fr-range-slider>input::-moz-range-thumb{pointer-events:all;position:relative;z-index:10;-moz-appearance:none;width:9px;height:15px;border-radius:7px;margin-top:-3.6px}.fr-range-slider>input::-moz-range-track{position:relative;z-index:-1;background-color:black;border:0;height:15px;border-radius:50%;margin-top:-3.6px}.fr-range-slider>input:last-of-type::-moz-range-track{-moz-appearance:none;background:none transparent;border:0}.fr-range-slider>input[type="range"]::-moz-focus-outer{border:0}@media screen and (max-width: 430px){.range-value span{width:40px;font-size:10px}#fr-form-container{top:20%}}#fr-video-edit{width:80%;text-align:center;height:50%;margin-bottom:20px;padding-top:8px;padding-bottom:8px} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/embedly.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-element .fr-embedly { 24 | user-select: none; 25 | -o-user-select: none; 26 | -moz-user-select: none; 27 | -khtml-user-select: none; 28 | -webkit-user-select: none; 29 | -ms-user-select: none; 30 | position: relative; } 31 | .fr-element .fr-embedly::after { 32 | position: absolute; 33 | z-index: 1; 34 | top: 0; 35 | left: 0; 36 | right: 0; 37 | bottom: 0; 38 | cursor: pointer; 39 | display: block; 40 | background: rgba(0, 0, 0, 0); } 41 | .fr-element .fr-embedly > * { 42 | -webkit-box-sizing: content-box; 43 | -moz-box-sizing: content-box; 44 | box-sizing: content-box; 45 | max-width: 100%; 46 | border: none; } 47 | 48 | .fr-box .fr-embedly-resizer { 49 | position: absolute; 50 | z-index: 2; 51 | border: solid 1px #0098f7; 52 | display: none; 53 | user-select: none; 54 | -o-user-select: none; 55 | -moz-user-select: none; 56 | -khtml-user-select: none; 57 | -webkit-user-select: none; 58 | -ms-user-select: none; } 59 | .fr-box .fr-embedly-resizer.fr-active { 60 | display: block; } 61 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/embedly.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-element .fr-embedly{user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;position:relative}.fr-element .fr-embedly::after{position:absolute;z-index:1;top:0;left:0;right:0;bottom:0;cursor:pointer;display:block;background:transparent}.fr-element .fr-embedly>*{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;max-width:100%;border:none}.fr-box .fr-embedly-resizer{position:absolute;z-index:2;border:solid 1px #0098f7;display:none;user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none}.fr-box .fr-embedly-resizer.fr-active{display:block} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/font_awesome.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .fr-popup .fr-icon.fr-fa-icon { 24 | width: 18px; 25 | padding: 8px; 26 | margin: 6px; 27 | font-size: 16px; } 28 | @supports not (-ms-high-contrast: none) { 29 | .fr-popup .fr-icon-container.fr-fa-container { 30 | grid-template-columns: repeat(auto-fill, minmax(45px, 45px)); } } 31 | @media screen and (-ms-high-contrast: active) and (min-width: 768px), (-ms-high-contrast: none) and (min-width: 768px) { 32 | .fr-popup .fr-icon-container.fr-fa-container { 33 | width: 506px; } } 34 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/font_awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.fr-popup .fr-icon.fr-fa-icon{width:18px;padding:8px;margin:6px;font-size:16px}@supports not (-ms-high-contrast: none){.fr-popup .fr-icon-container.fr-fa-container{grid-template-columns:repeat(auto-fill, minmax(45px, 45px))}}@media screen and (-ms-high-contrast: active) and (min-width: 768px), (-ms-high-contrast: none) and (min-width: 768px){.fr-popup .fr-icon-container.fr-fa-container{width:506px}} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/image_tui.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .tui-image-editor-container { 24 | position: fixed; 25 | top: 0; 26 | left: 0; 27 | bottom: 0; 28 | right: 0; 29 | height: 100%; 30 | width: 100%; 31 | z-index: 10; } 32 | 33 | .tui-editor-cancel-btn { 34 | background-color: #FFF; 35 | border: 1px solid #CCCCCC; 36 | color: #222; } 37 | 38 | .tui-editor-save-btn { 39 | background-color: #fdba3b; 40 | border: 1px solid #fdba3b; 41 | color: #FFF; } 42 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/image_tui.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.tui-image-editor-container{position:fixed;top:0;left:0;bottom:0;right:0;height:100%;width:100%;z-index:10}.tui-editor-cancel-btn{background-color:#FFF;border:1px solid #ccc;color:#222}.tui-editor-save-btn{background-color:#fdba3b;border:1px solid #fdba3b;color:#FFF} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/spell_checker.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after { 8 | clear: both; 9 | display: block; 10 | content: ""; 11 | height: 0; } 12 | 13 | .fr-hide-by-clipping { 14 | position: absolute; 15 | width: 1px; 16 | height: 1px; 17 | padding: 0; 18 | margin: -1px; 19 | overflow: hidden; 20 | clip: rect(0, 0, 0, 0); 21 | border: 0; } 22 | 23 | .examples-variante > a { 24 | font-size: 14px; 25 | font-family: Arial, Helvetica, sans-serif; } 26 | 27 | .sc-cm-holder > .sc-cm { 28 | border-top: 5px solid #222222 !important; 29 | padding: 0 !important; 30 | line-height: 200% !important; } 31 | 32 | .sc-cm .sc-cm__item.examples-variante.sc-cm__item_active > a > i { 33 | display: none !important; } 34 | 35 | .sc-cm .sc-cm__item.examples-variante > a > i { 36 | display: none !important; } 37 | 38 | .sc-cm__item_dropdown .i-icon { 39 | display: none !important; } 40 | 41 | .sc-cm__item_dropdown .i-icon::before { 42 | display: none !important; } 43 | 44 | .sc-cm::before { 45 | display: none !important; } 46 | 47 | div.sc-cm-holder.sc-cm_show > ul > li.sc-cm__item.sc-cm__item_dropdown.sc-cm__item_arrow > div > ul { 48 | border-style: none !important; 49 | padding: 0 !important; } 50 | 51 | .sc-cm__item_dropdown:hover > a, .sc-cm a:hover { 52 | background-color: #ebebeb !important; } 53 | 54 | .sc-cm__item_active > a, .sc-cm__item_active > a:hover, .sc-cm a:active, .sc-cm a:focus { 55 | background-color: #d6d6d6 !important; } 56 | 57 | .sc-cm__item > a { 58 | line-height: 200% !important; } 59 | 60 | .sc-cm-holder > .sc-cm:before { 61 | background-color: #ebebeb !important; } 62 | 63 | .sc-cm-holder { 64 | display: none; } 65 | -------------------------------------------------------------------------------- /app/assets/stylesheets/activeadmin/froala_editor/third_party/spell_checker.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * froala_editor v4.5.1 (https://www.froala.com/wysiwyg-editor) 3 | * License https://froala.com/wysiwyg-editor/terms/ 4 | * Copyright 2014-2025 Froala Labs 5 | */ 6 | 7 | .fr-clearfix::after{clear:both;display:block;content:"";height:0}.fr-hide-by-clipping{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.examples-variante>a{font-size:14px;font-family:Arial,Helvetica,sans-serif}.sc-cm-holder>.sc-cm{border-top:5px solid #222 !important;padding:0 !important;line-height:200% !important}.sc-cm .sc-cm__item.examples-variante.sc-cm__item_active>a>i{display:none !important}.sc-cm .sc-cm__item.examples-variante>a>i{display:none !important}.sc-cm__item_dropdown .i-icon{display:none !important}.sc-cm__item_dropdown .i-icon::before{display:none !important}.sc-cm::before{display:none !important}div.sc-cm-holder.sc-cm_show>ul>li.sc-cm__item.sc-cm__item_dropdown.sc-cm__item_arrow>div>ul{border-style:none !important;padding:0 !important}.sc-cm__item_dropdown:hover>a,.sc-cm a:hover{background-color:#ebebeb !important}.sc-cm__item_active>a,.sc-cm__item_active>a:hover,.sc-cm a:active,.sc-cm a:focus{background-color:#d6d6d6 !important}.sc-cm__item>a{line-height:200% !important}.sc-cm-holder>.sc-cm:before{background-color:#ebebeb !important}.sc-cm-holder{display:none} 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: font-url('fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: font-url('fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | font-url('fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | font-url('fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | font-url('fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | font-url('fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /app/assets/stylesheets/font-awesome/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /bin/brakeman: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'brakeman' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("brakeman", "brakeman") 30 | -------------------------------------------------------------------------------- /bin/fasterer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'fasterer' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("fasterer", "fasterer") 30 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # This command will automatically be run when you run "rails" with Rails gems 5 | # installed from the root of your application. 6 | 7 | ENV['RAILS_ENV'] ||= 'development' 8 | 9 | ENGINE_ROOT = File.expand_path('..', __dir__) 10 | ENGINE_PATH = File.expand_path('../lib/activeadmin/froala_editor/engine', __dir__) 11 | APP_PATH = File.expand_path('../spec/dummy/config/application', __dir__) 12 | 13 | # Set up gems listed in the Gemfile. 14 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 15 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 16 | 17 | require 'rails/all' 18 | require 'rails/engine/commands' 19 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rake' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rake", "rake") 30 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rspec' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rspec-core", "rspec") 30 | -------------------------------------------------------------------------------- /bin/rubocop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'rubocop' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "pathname" 12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 13 | Pathname.new(__FILE__).realpath) 14 | 15 | bundle_binstub = File.expand_path("../bundle", __FILE__) 16 | 17 | if File.file?(bundle_binstub) 18 | if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ 19 | load(bundle_binstub) 20 | else 21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 23 | end 24 | end 25 | 26 | require "rubygems" 27 | require "bundler/setup" 28 | 29 | load Gem.bin_path("rubocop", "rubocop") 30 | -------------------------------------------------------------------------------- /examples/upload_plugin_using_activestorage/app/admin/posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveAdmin.register Post do 4 | permit_params :author_id, :title, :description, :category, :dt, :position, :published, tag_ids: [] 5 | 6 | member_action :upload, method: [:post] do 7 | success = resource.images.attach(params[:file_upload]) 8 | result = success ? { link: url_for(resource.images.last) } : {} 9 | render json: result 10 | end 11 | 12 | index do 13 | selectable_column 14 | id_column 15 | column :title 16 | column :author 17 | column :published 18 | column :created_at 19 | actions 20 | end 21 | 22 | show do 23 | attributes_table do 24 | row :author 25 | row :title 26 | row :description 27 | row :category 28 | row :dt 29 | row :position 30 | row :published 31 | row :tags 32 | row :created_at 33 | row :updated_at 34 | row :images do |resurce| 35 | resurce.images.each do |image| 36 | div do 37 | link_to image.filename, image, target: '_blank', rel: :noopener 38 | end 39 | end 40 | nil 41 | end 42 | end 43 | active_admin_comments 44 | end 45 | 46 | form do |f| 47 | f.inputs 'Post' do 48 | f.input :author 49 | f.input :title 50 | unless resource.new_record? 51 | options = { 52 | imageUploadParam: 'file_upload', 53 | imageUploadURL: upload_admin_post_path(resource.id), 54 | toolbarButtons: %w[bold italic underline | insertImage insertVideo insertFile] 55 | } 56 | f.input :description, as: :froala_editor, input_html: { data: { options: options } } 57 | end 58 | f.input :category 59 | f.input :dt 60 | f.input :position 61 | f.input :published 62 | end 63 | 64 | f.inputs 'Tags' do 65 | f.input :tags 66 | end 67 | 68 | f.actions 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /examples/upload_plugin_using_activestorage/app/assets/javascripts/active_admin.js: -------------------------------------------------------------------------------- 1 | //= require active_admin/base 2 | 3 | //= require activeadmin/froala_editor/froala_editor.pkgd.min 4 | //= require activeadmin/froala_editor_input 5 | //= require activeadmin/froala_editor/plugins/image.min 6 | -------------------------------------------------------------------------------- /examples/upload_plugin_using_activestorage/app/assets/stylesheets/active_admin.scss: -------------------------------------------------------------------------------- 1 | @import 'active_admin/mixins'; 2 | @import 'active_admin/base'; 3 | 4 | @import 'font-awesome/font-awesome'; 5 | @import 'activeadmin/froala_editor_input'; 6 | -------------------------------------------------------------------------------- /examples/upload_plugin_using_activestorage/app/models/post.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Post < ApplicationRecord 4 | has_many_attached :images 5 | 6 | validates :title, allow_blank: false, presence: true 7 | end 8 | -------------------------------------------------------------------------------- /extra/.bashrc: -------------------------------------------------------------------------------- 1 | alias ls='ls --color' 2 | alias ll='ls -l' 3 | alias la='ls -la' 4 | -------------------------------------------------------------------------------- /extra/.env: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=activeadmin_froala_editor 2 | 3 | BUNDLER_VERSION=2.5.23 4 | SERVER_PORT=4000 5 | 6 | UID=1000 7 | GID=1000 8 | -------------------------------------------------------------------------------- /extra/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG RUBY_IMAGE=ruby:3 2 | FROM ${RUBY_IMAGE} 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | ENV DEVEL=1 6 | ENV LANG=C.UTF-8 7 | 8 | RUN apt-get update -qq 9 | RUN apt-get install -yqq --no-install-recommends build-essential chromium less libyaml-dev nano netcat-traditional pkg-config 10 | 11 | ARG BUNDLER_VERSION 12 | RUN gem install bundler -v ${BUNDLER_VERSION} 13 | RUN echo 'gem: --no-document' > /etc/gemrc 14 | 15 | ARG UID 16 | RUN useradd -u $UID --shell /bin/bash app 17 | 18 | RUN mkdir -p /home/app && chown -R app:app /home/app 19 | 20 | ARG RAILS_VERSION 21 | ENV RAILS_VERSION=$RAILS_VERSION 22 | 23 | ARG ACTIVEADMIN_VERSION 24 | ENV ACTIVEADMIN_VERSION=$ACTIVEADMIN_VERSION 25 | 26 | WORKDIR /app 27 | COPY . /app 28 | RUN bundle install 29 | RUN chown -R app:app /usr/local/bundle 30 | 31 | RUN ln -s /app/extra/.bashrc /home/app/.bashrc 32 | -------------------------------------------------------------------------------- /extra/Dockerfile.dockerignore: -------------------------------------------------------------------------------- 1 | # Ignore everything but the required files for bundle install 2 | /**/* 3 | 4 | !/*.gemspec 5 | !/Gemfile 6 | !/lib 7 | -------------------------------------------------------------------------------- /extra/dev_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export DEVEL=1 4 | 5 | export RAILS_VERSION=7.2.2.1 6 | export ACTIVEADMIN_VERSION=3.3.0 7 | -------------------------------------------------------------------------------- /extra/development.md: -------------------------------------------------------------------------------- 1 | ## Development 2 | 3 | ### Dev setup 4 | 5 | There are 2 ways to interact with this project: 6 | 7 | 1) Using Docker: 8 | 9 | ```sh 10 | make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN) 11 | make specs # run the tests (after up) 12 | make lint # run the linters (after up) 13 | make server # run the server (after up) 14 | make shell # open a shell (after up) 15 | make down # cleanup (after up) 16 | 17 | # Example using specific versions: 18 | RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up 19 | ``` 20 | 21 | 2) With a local setup: 22 | 23 | ```sh 24 | # Dev setup (set the required envs): 25 | source extra/dev_setup.sh 26 | # Install dependencies: 27 | bundle update 28 | # Run server (or any command): 29 | bin/rails s 30 | # To try different versions of Rails/ActiveAdmin edit extra/dev_setup.sh 31 | ``` 32 | 33 | ### Update the editor 34 | 35 | - Download the editor packages: https://github.com/froala/wysiwyg-editor/releases/latest 36 | - Unpack it somewhere: `tar xvfz *.tar.gz` 37 | - Enter in the extracted folder: `cd wysiwyg-editor*` 38 | - Copy the JS files: `cp -r css js /tmp/` 39 | - Enter in the gem root path 40 | - Copy the new editor assets: 41 | 42 | ```sh 43 | # From activeadmin_froala_editor root folder, move or delete the current JS files: 44 | mv app/assets/javascripts/activeadmin/froala_editor /tmp/old_js 45 | # Move the previously copied JS files: 46 | mv /tmp/js app/assets/javascripts/activeadmin/froala_editor 47 | # Move or delete the current CSS files: 48 | mv app/assets/stylesheets/activeadmin/froala_editor /tmp/old_css 49 | # Move the previously copied CSS files: 50 | mv /tmp/css app/assets/stylesheets/activeadmin/froala_editor 51 | ``` 52 | 53 | - Check the changes, most of them should be for updated files plus some new / removed file 54 | - Update _package.json_ with the new Froala version 55 | - Update the lock file: `npx yarn` 56 | - Update the _version.rb_ with the new Froala version 57 | -------------------------------------------------------------------------------- /extra/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | app: 3 | build: 4 | context: .. 5 | dockerfile: extra/Dockerfile 6 | args: 7 | BUNDLER_VERSION: ${BUNDLER_VERSION} 8 | RUBY_IMAGE: ruby:${RUBY:-3.4}-slim 9 | RAILS_VERSION: ${RAILS:-} 10 | ACTIVEADMIN_VERSION: ${ACTIVEADMIN:-} 11 | UID: ${UID} 12 | user: ${UID}:${GID} 13 | ports: 14 | - ${SERVER_PORT}:${SERVER_PORT} 15 | working_dir: /app 16 | volumes: 17 | - ..:/app 18 | stdin_open: true 19 | tty: true 20 | -------------------------------------------------------------------------------- /extra/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/extra/screenshot.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Styles 2 | import 'activeadmin_froala_editor/app/assets/stylesheets/activeadmin/_froala_editor_input' 3 | 4 | // JS 5 | window.FroalaEditor = require('activeadmin_froala_editor/app/assets/javascripts/activeadmin/froala_editor/froala_editor.pkgd.min') 6 | require('activeadmin_froala_editor/app/assets/javascripts/activeadmin/froala_editor_input') 7 | -------------------------------------------------------------------------------- /lib/activeadmin/froala_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'activeadmin/froala_editor/engine' 4 | -------------------------------------------------------------------------------- /lib/activeadmin/froala_editor/engine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_admin' 4 | 5 | module ActiveAdmin 6 | module FroalaEditor 7 | class Engine < ::Rails::Engine 8 | engine_name 'activeadmin_froala_editor' 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/activeadmin/froala_editor/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActiveAdmin 4 | module FroalaEditor 5 | VERSION = '1.2.0' 6 | FROALA_VERSION = '4.5.1' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/activeadmin_froala_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'activeadmin/froala_editor' 4 | require 'formtastic/inputs/froala_editor_input' 5 | -------------------------------------------------------------------------------- /lib/formtastic/inputs/froala_editor_input.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Formtastic 4 | module Inputs 5 | class FroalaEditorInput < Formtastic::Inputs::TextInput 6 | def input_html_options 7 | super.merge('data-aa-froala-editor': '1') 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "activeadmin_froala_editor", 3 | "version": "1.2.0", 4 | "description": "An Active Admin plugin to use Froala WYSIWYG editor", 5 | "repository": "https://github.com/blocknotes/activeadmin_froala_editor", 6 | "author": "Mattia Roccoberton ", 7 | "license": "MIT", 8 | "main": "index.js", 9 | "files": [ 10 | "app/**/*", 11 | "index.js" 12 | ], 13 | "devDependencies": { 14 | "froala-editor": "^4.5.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /spec/dummy/.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.7.1 2 | -------------------------------------------------------------------------------- /spec/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/authors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveAdmin.register Author do 4 | permit_params :name, 5 | :email, 6 | :age, 7 | :avatar, 8 | profile_attributes: %i[id description _destroy], 9 | posts_attributes: %i[id title description] 10 | 11 | index do 12 | selectable_column 13 | id_column 14 | column :name 15 | column :email 16 | column :created_at 17 | actions 18 | end 19 | 20 | filter :name 21 | filter :created_at 22 | 23 | show do 24 | attributes_table do 25 | row :name 26 | row :email 27 | row :age 28 | row :avatar do |record| 29 | image_tag url_for(record.avatar), style: 'max-width:800px;max-height:500px' if record.avatar.attached? 30 | end 31 | row :created_at 32 | row :updated_at 33 | row :profile 34 | row :posts 35 | end 36 | active_admin_comments 37 | end 38 | 39 | form do |f| 40 | f.inputs do 41 | f.input :name 42 | f.input :email 43 | f.input :age 44 | f.input :avatar, 45 | as: :file, 46 | hint: (object.avatar.attached? ? "Current: #{object.avatar.filename}" : nil) 47 | end 48 | f.has_many :profile, allow_destroy: true do |ff| 49 | ff.input :description 50 | end 51 | f.has_many :posts do |fp| 52 | fp.input :title 53 | fp.input :description, as: :froala_editor 54 | end 55 | f.actions 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/dashboard.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | menu priority: 1, label: proc { I18n.t("active_admin.dashboard") } 3 | 4 | content title: proc { I18n.t("active_admin.dashboard") } do 5 | div class: "blank_slate_container", id: "dashboard_default_message" do 6 | span class: "blank_slate" do 7 | span I18n.t("active_admin.dashboard_welcome.welcome") 8 | small I18n.t("active_admin.dashboard_welcome.call_to_action") 9 | end 10 | end 11 | 12 | # Here is an example of a simple dashboard with columns and panels. 13 | # 14 | # columns do 15 | # column do 16 | # panel "Recent Posts" do 17 | # ul do 18 | # Post.recent(5).map do |post| 19 | # li link_to(post.title, admin_post_path(post)) 20 | # end 21 | # end 22 | # end 23 | # end 24 | 25 | # column do 26 | # panel "Info" do 27 | # para "Welcome to ActiveAdmin." 28 | # end 29 | # end 30 | # end 31 | end # content 32 | end 33 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveAdmin.register Post do 4 | permit_params :author_id, :title, :summary, :description, :category, :dt, :position, :published, tag_ids: [] 5 | 6 | index do 7 | selectable_column 8 | id_column 9 | column :title 10 | column :author 11 | column :published 12 | column :created_at 13 | actions 14 | end 15 | 16 | show do 17 | attributes_table do 18 | row :author 19 | row :title 20 | row :summary 21 | row :description 22 | row :category 23 | row :dt 24 | row :position 25 | row :published 26 | row :tags 27 | row :created_at 28 | row :updated_at 29 | row :images do |resurce| 30 | resurce.images.each do |image| 31 | div do 32 | link_to image.filename, image, target: '_blank', rel: :noopener 33 | end 34 | end 35 | nil 36 | end 37 | end 38 | active_admin_comments 39 | end 40 | 41 | form do |f| 42 | buttons = %w[undo redo bold italic] 43 | f.inputs 'Post' do 44 | f.input :author 45 | f.input :title 46 | f.input :summary, as: :froala_editor, input_html: { data: { options: { toolbarButtons: buttons } } } 47 | f.input :description, as: :froala_editor # using default options 48 | f.input :category 49 | f.input :dt 50 | f.input :position 51 | f.input :published 52 | end 53 | 54 | f.inputs 'Tags' do 55 | f.input :tags 56 | end 57 | 58 | f.actions 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/dummy/app/admin/tags.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveAdmin.register Tag do 4 | permit_params :name 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | // OFF link active_storage_db_manifest.js 4 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/spec/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/active_admin.js: -------------------------------------------------------------------------------- 1 | //= require active_admin/base 2 | 3 | //= require activeadmin/froala_editor/froala_editor.pkgd.min 4 | //= require activeadmin/froala_editor_input 5 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/active_admin.scss: -------------------------------------------------------------------------------- 1 | // SASS variable overrides must be declared before loading up Active Admin's styles. 2 | // 3 | // To view the variables that Active Admin provides, take a look at 4 | // `app/assets/stylesheets/active_admin/mixins/_variables.scss` in the 5 | // Active Admin source. 6 | // 7 | // For example, to change the sidebar width: 8 | // $sidebar-width: 242px; 9 | 10 | // Active Admin's got SASS! 11 | @import "active_admin/mixins"; 12 | @import "active_admin/base"; 13 | 14 | @import 'font-awesome/font-awesome'; 15 | @import 'activeadmin/froala_editor_input'; 16 | 17 | // Overriding any non-variable SASS must be done after the fact. 18 | // For example, to change the default status-tag color: 19 | // 20 | // .status_tag { background: #6090DB; } 21 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /spec/dummy/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/spec/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/javascript/packs/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require rails-ujs 14 | //= require activestorage 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /spec/dummy/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /spec/dummy/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationRecord < ActiveRecord::Base 4 | self.abstract_class = true 5 | 6 | scope :published, -> {} 7 | end 8 | -------------------------------------------------------------------------------- /spec/dummy/app/models/author.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Author < ApplicationRecord 4 | has_many :posts 5 | has_many :published_posts, -> { published }, class_name: 'Post' 6 | has_many :recent_posts, -> { recents }, class_name: 'Post' 7 | 8 | has_many :tags, through: :posts 9 | 10 | has_one :profile, inverse_of: :author, dependent: :destroy 11 | 12 | has_one_attached :avatar 13 | 14 | accepts_nested_attributes_for :profile, allow_destroy: true 15 | accepts_nested_attributes_for :posts, allow_destroy: true 16 | 17 | validates :email, format: { with: /\A[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\z/i, message: 'Invalid email' } 18 | 19 | validate -> { 20 | errors.add( :base, 'Invalid age' ) if !age || age.to_i % 3 == 1 21 | } 22 | 23 | def to_s 24 | "#{name} (#{age})" 25 | end 26 | 27 | class << self 28 | def ransackable_attributes(auth_object = nil) 29 | %w[age created_at email id name updated_at] 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/spec/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/models/post.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Post < ApplicationRecord 4 | belongs_to :author, inverse_of: :posts, autosave: true 5 | 6 | has_one :author_profile, through: :author, source: :profile 7 | 8 | has_many :post_tags, inverse_of: :post, dependent: :destroy 9 | has_many :tags, through: :post_tags 10 | 11 | has_many_attached :images 12 | 13 | accepts_nested_attributes_for :post_tags, allow_destroy: true 14 | 15 | validates :title, allow_blank: false, presence: true 16 | # validates :description, allow_blank: false, presence: true 17 | 18 | scope :published, -> { where(published: true) } 19 | scope :recents, -> { where('created_at > ?', Date.today - 8.month) } 20 | 21 | def short_title 22 | title.truncate 10 23 | end 24 | 25 | def upper_title 26 | title.upcase 27 | end 28 | 29 | class << self 30 | def ransackable_associations(auth_object = nil) 31 | %w[author author_profile post_tags tags images_attachments images_blobs] 32 | end 33 | 34 | def ransackable_attributes(auth_object = nil) 35 | %w[author_id category created_at description dt id position published title summary updated_at] 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/dummy/app/models/post_tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PostTag < ApplicationRecord 4 | belongs_to :post, inverse_of: :post_tags 5 | belongs_to :tag, inverse_of: :post_tags 6 | 7 | validates :post, presence: true 8 | validates :tag, presence: true 9 | 10 | class << self 11 | def ransackable_attributes(auth_object = nil) 12 | %w[created_at id post_id tag_id updated_at] 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/dummy/app/models/profile.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Profile < ApplicationRecord 4 | belongs_to :author, inverse_of: :profile, touch: true 5 | 6 | def to_s 7 | description 8 | end 9 | 10 | class << self 11 | def ransackable_attributes(auth_object = nil) 12 | %w[author_id created_at description id updated_at] 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/dummy/app/models/tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Tag < ApplicationRecord 4 | has_many :post_tags, inverse_of: :tag, dependent: :destroy 5 | has_many :posts, through: :post_tags 6 | 7 | def self.ransackable_associations(auth_object = nil) 8 | ["post_tags", "posts"] 9 | end 10 | 11 | def self.ransackable_attributes(auth_object = nil) 12 | ["created_at", "id", "name", "updated_at"] 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= csrf_meta_tags %> 6 | <%= csp_meta_tag %> 7 | 8 | <%= stylesheet_link_tag 'application', media: 'all' %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /spec/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /spec/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /spec/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path('..', __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to setup or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at anytime and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?('config/database.yml') 22 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! 'bin/rails db:prepare' 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! 'bin/rails log:clear tmp:clear' 30 | 31 | puts "\n== Restarting application server ==" 32 | system! 'bin/rails restart' 33 | end 34 | -------------------------------------------------------------------------------- /spec/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /spec/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | 7 | module Dummy 8 | class Application < Rails::Application 9 | config.load_defaults Rails::VERSION::STRING.to_f 10 | 11 | config.active_support.deprecation = :raise 12 | 13 | config.active_record.legacy_connection_handling = false if Gem::Version.new(Rails.version) < Gem::Version.new('7.1') 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) 6 | -------------------------------------------------------------------------------- /spec/dummy/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: dummy_production 11 | -------------------------------------------------------------------------------- /spec/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: sqlite3 3 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 4 | timeout: 5000 5 | 6 | development: 7 | <<: *default 8 | database: db/development.sqlite3 9 | schema_dump: schema-dev.rb 10 | 11 | test: 12 | <<: *default 13 | database: db/test.sqlite3 14 | -------------------------------------------------------------------------------- /spec/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | # Run rails dev:cache to toggle caching. 17 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 18 | config.action_controller.perform_caching = true 19 | config.action_controller.enable_fragment_cache_logging = true 20 | 21 | config.cache_store = :memory_store 22 | config.public_file_server.headers = { 23 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 24 | } 25 | else 26 | config.action_controller.perform_caching = false 27 | 28 | config.cache_store = :null_store 29 | end 30 | 31 | # Store uploaded files on the local file system (see config/storage.yml for options). 32 | config.active_storage.service = :local 33 | 34 | # # Don't care if the mailer can't send. 35 | # config.action_mailer.raise_delivery_errors = false 36 | 37 | # config.action_mailer.perform_caching = false 38 | 39 | # Print deprecation notices to the Rails logger. 40 | config.active_support.deprecation = :log 41 | 42 | # Raise an error on page load if there are pending migrations. 43 | config.active_record.migration_error = :page_load 44 | 45 | # Highlight code that triggered database queries in logs. 46 | config.active_record.verbose_query_logs = true 47 | 48 | # Debug mode disables concatenation and preprocessing of assets. 49 | # This option may cause significant delays in view rendering with a large 50 | # number of complex assets. 51 | config.assets.debug = true 52 | 53 | # Suppress logger output for asset requests. 54 | config.assets.quiet = true 55 | 56 | # Raises error for missing translations. 57 | # config.action_view.raise_on_missing_translations = true 58 | 59 | # Use an evented file watcher to asynchronously detect changes in source code, 60 | # routes, locales, etc. This feature depends on the listen gem. 61 | # config.file_watcher = ActiveSupport::EventedFileUpdateChecker 62 | 63 | ### 64 | 65 | config.active_support.to_time_preserves_timezone = :zone if Gem::Version.new(Rails.version) >= Gem::Version.new('8.0') 66 | end 67 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # The test environment is used exclusively to run your application's 2 | # test suite. You never need to work with it otherwise. Remember that 3 | # your test database is "scratch space" for the test suite and is wiped 4 | # and recreated between test runs. Don't rely on the data there! 5 | 6 | Rails.application.configure do 7 | # Settings specified here will take precedence over those in config/application.rb. 8 | 9 | config.cache_classes = false 10 | config.action_view.cache_template_loading = true 11 | 12 | # Do not eager load code on boot. This avoids loading your whole application 13 | # just for the purpose of running a single test. If you are using a tool that 14 | # preloads Rails for running tests, you may have to set it to true. 15 | config.eager_load = false 16 | 17 | # Configure public file server for tests with Cache-Control for performance. 18 | config.public_file_server.enabled = true 19 | config.public_file_server.headers = { 20 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 21 | } 22 | 23 | # Show full error reports and disable caching. 24 | config.consider_all_requests_local = true 25 | config.action_controller.perform_caching = false 26 | config.cache_store = :null_store 27 | 28 | # Raise exceptions instead of rendering exception templates. 29 | config.action_dispatch.show_exceptions = false 30 | 31 | # Disable request forgery protection in test environment. 32 | config.action_controller.allow_forgery_protection = false 33 | 34 | # Store uploaded files on the local file system in a temporary directory. 35 | config.active_storage.service = :test 36 | 37 | # config.action_mailer.perform_caching = false 38 | 39 | # Tell Action Mailer not to deliver emails to the real world. 40 | # The :test delivery method accumulates sent emails in the 41 | # ActionMailer::Base.deliveries array. 42 | # config.action_mailer.delivery_method = :test 43 | 44 | # Print deprecation notices to the stderr. 45 | config.active_support.deprecation = :stderr 46 | 47 | # Raises error for missing translations. 48 | # config.action_view.raise_on_missing_translations = true 49 | 50 | ### 51 | 52 | config.active_support.to_time_preserves_timezone = :zone if Gem::Version.new(Rails.version) >= Gem::Version.new('8.0') 53 | end 54 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/active_storage.rb: -------------------------------------------------------------------------------- 1 | Rails.application.reloader.to_prepare do 2 | ActiveStorage::Attachment.class_eval do 3 | class << self 4 | def ransackable_attributes(auth_object = nil) 5 | %w[blob_id created_at id name record_id record_type] 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | 19 | # If you are using UJS then enable automatic nonce generation 20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 21 | 22 | # Set the nonce only to specific directives 23 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src) 24 | 25 | # Report CSP violations to a specified URI 26 | # For further information see the following documentation: 27 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 28 | # Rails.application.config.content_security_policy_report_only = true 29 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /spec/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /spec/dummy/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 12 | # 13 | port ENV.fetch("PORT") { 3000 } 14 | 15 | # Specifies the `environment` that Puma will run in. 16 | # 17 | environment ENV.fetch("RAILS_ENV") { "development" } 18 | 19 | # Specifies the `pidfile` that Puma will use. 20 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 21 | 22 | # Specifies the number of `workers` to boot in clustered mode. 23 | # Workers are forked web server processes. If using threads and workers together 24 | # the concurrency of the application would be max `threads` * `workers`. 25 | # Workers do not work on JRuby or Windows (both of which do not support 26 | # processes). 27 | # 28 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 29 | 30 | # Use the `preload_app!` method when specifying a `workers` number. 31 | # This directive tells Puma to first boot the application and load code 32 | # before forking the application. This takes advantage of Copy On Write 33 | # process behavior so workers use less memory. 34 | # 35 | # preload_app! 36 | 37 | # Allow puma to be restarted by `rails restart` command. 38 | plugin :tmp_restart 39 | -------------------------------------------------------------------------------- /spec/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | ActiveAdmin.routes(self) 3 | 4 | root to: redirect('/admin') 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummy/config/spring.rb: -------------------------------------------------------------------------------- 1 | Spring.watch( 2 | ".ruby-version", 3 | ".rbenv-vars", 4 | "tmp/restart.txt", 5 | "tmp/caching-dev.txt" 6 | ) 7 | -------------------------------------------------------------------------------- /spec/dummy/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20170806125915_create_active_storage_tables.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20170806125915) 2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2] 3 | def change 4 | create_table :active_storage_blobs do |t| 5 | t.string :key, null: false 6 | t.string :filename, null: false 7 | t.string :content_type 8 | t.text :metadata 9 | t.bigint :byte_size, null: false 10 | t.string :checksum, null: false 11 | t.datetime :created_at, null: false 12 | 13 | t.index [ :key ], unique: true 14 | end 15 | 16 | create_table :active_storage_attachments do |t| 17 | t.string :name, null: false 18 | t.references :record, null: false, polymorphic: true, index: false 19 | t.references :blob, null: false 20 | 21 | t.datetime :created_at, null: false 22 | 23 | t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true 24 | t.foreign_key :active_storage_blobs, column: :blob_id 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180101010101_create_active_admin_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateActiveAdminComments < ActiveRecord::Migration[6.0] 2 | def self.up 3 | create_table :active_admin_comments do |t| 4 | t.string :namespace 5 | t.text :body 6 | t.references :resource, polymorphic: true 7 | t.references :author, polymorphic: true 8 | t.timestamps 9 | end 10 | add_index :active_admin_comments, [:namespace] 11 | end 12 | 13 | def self.down 14 | drop_table :active_admin_comments 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053251_create_authors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAuthors < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :authors do |t| 6 | t.string :name 7 | t.integer :age 8 | t.string :email 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053254_create_profiles.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateProfiles < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :profiles do |t| 6 | t.text :description 7 | t.belongs_to :author, foreign_key: true 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053255_create_tags.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateTags < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :tags do |t| 6 | t.string :name 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053257_create_post_tags.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePostTags < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :post_tags do |t| 6 | t.belongs_to :post, foreign_key: true 7 | t.belongs_to :tag, foreign_key: true 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/dummy/db/migrate/20180607053739_create_posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePosts < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :posts do |t| 6 | t.string :title 7 | t.text :summary 8 | t.text :description 9 | t.belongs_to :author, foreign_key: true 10 | t.string :category 11 | t.datetime :dt 12 | t.float :position 13 | t.boolean :published 14 | 15 | t.timestamps 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/dummy/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | (11..16).each do |i| 4 | Tag.find_or_create_by!(name: "Tag #{i}") 5 | end 6 | 7 | (11..20).each do |i| 8 | age = 21 + 3 * (i - 10) 9 | attrs = { name: "Author #{i}", age: age, email: "some@email#{i}.com" } 10 | Author.find_or_create_by!(name: "Author #{i}") do |author| 11 | author.assign_attributes(attrs) 12 | author.profile = Profile.new(description: "Profile description for Author #{i}") if (i % 3).zero? 13 | end 14 | end 15 | 16 | authors = Author.pluck(:id) 17 | tags = Tag.where.not(name: 'A test tag').pluck(:id) 18 | (11..40).each do |i| 19 | attrs = { 20 | title: "Post #{i}", 21 | author_id: authors.sample, 22 | position: rand(100), 23 | summary: "

    Summary for post #{i}

    ", 24 | description: "

    Some bold Some italic Some underline [#{i}]

    ", 25 | created_at: Time.now - rand(3600).seconds 26 | } 27 | attrs[:category] = 'news' if (i % 4).zero? 28 | attrs[:dt] = Time.now - rand(30).days if (i % 3).zero? 29 | 30 | Post.find_or_create_by!(title: "Post #{i}") do |post| 31 | post.assign_attributes(attrs) 32 | post.tags = Tag.where(id: tags.sample(2)) if (i % 2).zero? 33 | end 34 | end 35 | 36 | Author.find_or_create_by!(name: 'A test author', email: 'aaa@bbb.ccc', age: 30) 37 | Tag.find_or_create_by!(name: 'A test tag') 38 | 39 | puts '> Seeds: done.' 40 | -------------------------------------------------------------------------------- /spec/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/spec/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /spec/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    The page you were looking for doesn't exist.

    62 |

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

    63 |
    64 |

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

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

    The change you wanted was rejected.

    62 |

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

    63 |
    64 |

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

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

    We're sorry, but something went wrong.

    62 |
    63 |

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

    64 |
    65 | 66 | 67 | -------------------------------------------------------------------------------- /spec/dummy/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/spec/dummy/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /spec/dummy/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/spec/dummy/public/apple-touch-icon.png -------------------------------------------------------------------------------- /spec/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blocknotes/activeadmin_froala_editor/bb4f223b06fff16e1a9a9ab40df094981dc60013/spec/dummy/public/favicon.ico -------------------------------------------------------------------------------- /spec/page_objects/admin/authors/edit_page.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Admin 4 | module Authors 5 | class EditPage < BasePage 6 | include Capybara::DSL 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/page_objects/admin/posts/edit_page.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Admin 4 | module Posts 5 | class EditPage < BasePage 6 | include Capybara::DSL 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/page_objects/base_object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class BaseObject 4 | include Capybara::DSL 5 | 6 | attr_reader :element, :selector 7 | 8 | def initialize(selector:) 9 | @selector = selector 10 | @element = find(selector) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/page_objects/base_page.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class BasePage 4 | include Capybara::DSL 5 | 6 | attr_reader :path 7 | 8 | def initialize(path:) 9 | @path = path 10 | end 11 | 12 | def load = visit(path) 13 | 14 | def lookup_editor(editor_container:) 15 | @editor = Shared::FroalaEditor.new(editor_container) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/page_objects/shared/froala_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Shared 4 | class FroalaEditor < HtmlEditor 5 | attr_reader :editor_selector 6 | 7 | def initialize(container) 8 | @editor_selector = "#{container} .fr-box" 9 | super(selector: editor_selector) 10 | end 11 | 12 | def content = content_element['innerHTML'] 13 | 14 | def content_element 15 | @content_element ||= find("#{editor_selector} [contenteditable]") 16 | end 17 | 18 | def toggle_bold = find("#{editor_selector} [data-cmd='bold']").click 19 | 20 | def toggle_italic = find("#{editor_selector} [data-cmd='italic']").click 21 | 22 | def toggle_underline = find("#{editor_selector} [data-cmd='underline']").click 23 | 24 | def toggle_align_left = find("#{editor_selector} [data-cmd='alignLeft']").click 25 | 26 | def toggle_align_center = find("#{editor_selector} [data-cmd='alignCenter']").click 27 | 28 | def toggle_ordered_list = find("#{editor_selector} [data-cmd='formatOLSimple']").click 29 | 30 | def toggle_link = find("#{editor_selector} [data-cmd='insertLink']").click 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/page_objects/shared/html_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Shared 4 | class HtmlEditor < BaseObject 5 | def content_element 6 | raise NotImplementedError 7 | end 8 | 9 | def clear 10 | select_all 11 | content_element.send_keys(:delete) 12 | self 13 | end 14 | 15 | # @return [self] 16 | def open_dropdown 17 | raise NotImplementedError 18 | end 19 | 20 | def select_all 21 | content_element.send_keys([:control, "a"]) 22 | self 23 | end 24 | 25 | def toolbar_control(control, ...) 26 | send(:"toggle_#{control}", ...) 27 | self 28 | end 29 | 30 | def <<(content) 31 | content_element.send_keys(content) 32 | self 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'spec_helper' 4 | 5 | require 'zeitwerk' 6 | loader = Zeitwerk::Loader.new 7 | loader.push_dir("#{__dir__}/page_objects") 8 | loader.setup 9 | 10 | ENV['RAILS_ENV'] = 'test' 11 | 12 | require File.expand_path('dummy/config/environment.rb', __dir__) 13 | 14 | abort('The Rails environment is running in production mode!') if Rails.env.production? 15 | 16 | require 'rspec/rails' 17 | require 'capybara/rails' 18 | 19 | Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require_relative f } 20 | 21 | # Checks for pending migrations and applies them before tests are run. 22 | # If you are not using ActiveRecord, you can remove these lines. 23 | begin 24 | ActiveRecord::Migration.maintain_test_schema! 25 | rescue ActiveRecord::PendingMigrationError => e 26 | puts e.to_s.strip 27 | exit 1 28 | end 29 | 30 | RSpec.configure do |config| 31 | if Gem::Version.new(Rails.version) >= Gem::Version.new('7.1') 32 | config.fixture_paths = [Rails.root.join('spec/fixtures')] 33 | else 34 | config.fixture_path = Rails.root.join('spec/fixtures') 35 | end 36 | 37 | config.infer_spec_type_from_file_location! 38 | config.filter_rails_from_backtrace! 39 | 40 | config.use_transactional_fixtures = true 41 | config.use_instantiated_fixtures = false 42 | config.render_views = false 43 | 44 | config.before(:suite) do 45 | intro = ('-' * 80) 46 | intro << "\n" 47 | intro << "- Ruby: #{RUBY_VERSION}\n" 48 | intro << "- Rails: #{Rails.version}\n" 49 | intro << "- ActiveAdmin: #{ActiveAdmin::VERSION}\n" 50 | intro << ('-' * 80) 51 | 52 | RSpec.configuration.reporter.message(intro) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |config| 4 | config.disable_monkey_patching! 5 | config.filter_run focus: true 6 | config.filter_run_excluding changes_filesystem: true 7 | config.run_all_when_everything_filtered = true 8 | 9 | config.color = true 10 | config.tty = true 11 | 12 | config.example_status_persistence_file_path = '.rspec_failures' 13 | config.order = :random 14 | config.shared_context_metadata_behavior = :apply_to_host_groups 15 | 16 | config.expect_with :rspec do |expectations| 17 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 18 | end 19 | config.mock_with :rspec do |mocks| 20 | mocks.verify_partial_doubles = true 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/support/capybara.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'capybara/cuprite' 4 | 5 | Capybara.register_driver(:capybara_cuprite) do |app| 6 | browser_options = {}.tap do |opts| 7 | opts['no-sandbox'] = nil if ENV['DEVEL'] 8 | end 9 | 10 | Capybara::Cuprite::Driver.new( 11 | app, 12 | window_size: [1600, 1024], 13 | browser_options: browser_options, 14 | process_timeout: 30, 15 | timeout: 30, 16 | inspector: true, 17 | headless: !ENV['CUPRITE_HEADLESS'].in?(%w[n 0 no false]) 18 | ) 19 | end 20 | 21 | # Capybara.server = :puma 22 | Capybara.default_driver = Capybara.javascript_driver = :capybara_cuprite 23 | 24 | RSpec.configure do |config| 25 | config.prepend_before(:each, type: :system) do 26 | driven_by Capybara.javascript_driver 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/support/string_clean_multiline.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module StringCleanMultiline 4 | refine String do 5 | def clean_multiline 6 | # Get rid of newlines and indentation spaces 7 | strip.gsub(/\s*\n\s*/, "") 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/system/froala_js_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe 'Froala JS' do 4 | it 'has a Javascript function defined and returns the version', :aggregate_failures do 5 | visit '/admin/posts' 6 | 7 | expect(page.evaluate_script('typeof FroalaEditor')).to eq 'function' 8 | expect(page.evaluate_script('FroalaEditor.VERSION')).to eq(ActiveAdmin::FroalaEditor::FROALA_VERSION) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | froala-editor@^4.5.1: 6 | version "4.5.1" 7 | resolved "https://registry.yarnpkg.com/froala-editor/-/froala-editor-4.5.1.tgz#4a5c9bd6bb72dfb19f80749ae68c810a4e16d1d8" 8 | integrity sha512-hgx4JJAM80yM3PGdyj7+41OQHP+Yj59yMvknwQkizlkbo/aKn2lbEtiqPMm//thNEE6NCuGLpHCZqppR/7Vymg== 9 | --------------------------------------------------------------------------------