Showing preview only (1,343K chars total). Download the full file or copy to clipboard to get everything.
Repository: basecamp/trix
Branch: main
Commit: 2e46d5128f39
Files: 282
Total size: 1.2 MB
Directory structure:
gitextract_zvcmyhvl/
├── .eslintrc
├── .github/
│ ├── ISSUE_TEMPLATE.md
│ ├── stale.yml
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── .node-version
├── .npmignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── action_text-trix/
│ ├── .gitignore
│ ├── Gemfile
│ ├── LICENSE
│ ├── README.md
│ ├── Rakefile
│ ├── action_text-trix.gemspec
│ ├── app/
│ │ └── assets/
│ │ ├── javascripts/
│ │ │ ├── .gitattributes
│ │ │ └── trix.js
│ │ └── stylesheets/
│ │ └── trix.css
│ ├── bin/
│ │ └── rails
│ ├── lib/
│ │ └── action_text/
│ │ ├── trix/
│ │ │ ├── engine.rb
│ │ │ └── version.rb
│ │ └── trix.rb
│ └── test/
│ ├── application_system_test_case.rb
│ ├── dummy/
│ │ ├── Rakefile
│ │ ├── app/
│ │ │ ├── assets/
│ │ │ │ ├── images/
│ │ │ │ │ └── .keep
│ │ │ │ └── stylesheets/
│ │ │ │ ├── actiontext.css
│ │ │ │ └── application.css
│ │ │ ├── controllers/
│ │ │ │ ├── application_controller.rb
│ │ │ │ ├── concerns/
│ │ │ │ │ └── .keep
│ │ │ │ └── messages_controller.rb
│ │ │ ├── javascript/
│ │ │ │ └── application.js
│ │ │ ├── models/
│ │ │ │ ├── application_record.rb
│ │ │ │ ├── concerns/
│ │ │ │ │ └── .keep
│ │ │ │ └── message.rb
│ │ │ └── views/
│ │ │ ├── active_storage/
│ │ │ │ └── blobs/
│ │ │ │ └── _blob.html.erb
│ │ │ ├── layouts/
│ │ │ │ ├── action_text/
│ │ │ │ │ └── contents/
│ │ │ │ │ └── _content.html.erb
│ │ │ │ ├── application.html.erb
│ │ │ │ ├── mailer.html.erb
│ │ │ │ └── mailer.text.erb
│ │ │ ├── messages/
│ │ │ │ ├── _form.html.erb
│ │ │ │ ├── index.html.erb
│ │ │ │ └── new.html.erb
│ │ │ └── pwa/
│ │ │ ├── manifest.json.erb
│ │ │ └── service-worker.js
│ │ ├── bin/
│ │ │ ├── dev
│ │ │ ├── importmap
│ │ │ ├── rails
│ │ │ ├── rake
│ │ │ └── setup
│ │ ├── config/
│ │ │ ├── application.rb
│ │ │ ├── boot.rb
│ │ │ ├── cable.yml
│ │ │ ├── database.yml
│ │ │ ├── environment.rb
│ │ │ ├── environments/
│ │ │ │ ├── development.rb
│ │ │ │ ├── production.rb
│ │ │ │ └── test.rb
│ │ │ ├── importmap.rb
│ │ │ ├── initializers/
│ │ │ │ ├── assets.rb
│ │ │ │ ├── content_security_policy.rb
│ │ │ │ ├── filter_parameter_logging.rb
│ │ │ │ └── inflections.rb
│ │ │ ├── locales/
│ │ │ │ └── en.yml
│ │ │ ├── puma.rb
│ │ │ ├── routes.rb
│ │ │ └── storage.yml
│ │ ├── config.ru
│ │ ├── db/
│ │ │ ├── migrate/
│ │ │ │ ├── 20250926170812_create_active_storage_tables.active_storage.rb
│ │ │ │ ├── 20250926170813_create_action_text_tables.action_text.rb
│ │ │ │ └── 20250926170921_create_messages.rb
│ │ │ └── schema.rb
│ │ └── public/
│ │ ├── 400.html
│ │ ├── 404.html
│ │ ├── 406-unsupported-browser.html
│ │ ├── 422.html
│ │ └── 500.html
│ ├── fixtures/
│ │ └── action_text/
│ │ └── rich_texts.yml
│ ├── system/
│ │ └── action_text_test.rb
│ └── test_helper.rb
├── assets/
│ ├── index.html
│ ├── test.html
│ ├── trix/
│ │ ├── images/
│ │ │ └── README.md
│ │ └── stylesheets/
│ │ ├── attachments.scss
│ │ ├── content.scss
│ │ ├── editor.scss
│ │ ├── icons.scss
│ │ ├── media-queries.scss
│ │ ├── selection.scss
│ │ └── toolbar.scss
│ └── trix.scss
├── babel.config.json
├── bin/
│ ├── ci
│ ├── sass-build
│ └── setup
├── package.json
├── rollup.config.js
├── src/
│ ├── inspector/
│ │ ├── control_element.js
│ │ ├── debugger.js
│ │ ├── element.js
│ │ ├── global.js
│ │ ├── inspector.js
│ │ ├── templates/
│ │ │ ├── debug.js
│ │ │ ├── document.js
│ │ │ ├── performance.js
│ │ │ ├── render.js
│ │ │ ├── selection.js
│ │ │ └── undo.js
│ │ ├── templates.js
│ │ ├── view.js
│ │ ├── views/
│ │ │ ├── debug_view.js
│ │ │ ├── document_view.js
│ │ │ ├── performance_view.js
│ │ │ ├── render_view.js
│ │ │ ├── selection_view.js
│ │ │ └── undo_view.js
│ │ ├── watchdog/
│ │ │ ├── deserializer.js
│ │ │ ├── player.js
│ │ │ ├── player_controller.js
│ │ │ ├── player_element.js
│ │ │ ├── player_view.js
│ │ │ ├── recorder.js
│ │ │ ├── recording.js
│ │ │ └── serializer.js
│ │ └── watchdog.js
│ ├── test/
│ │ ├── system/
│ │ │ ├── accessibility_test.js
│ │ │ ├── attachment_caption_test.js
│ │ │ ├── attachment_gallery_test.js
│ │ │ ├── attachment_test.js
│ │ │ ├── basic_input_test.js
│ │ │ ├── block_formatting_test.js
│ │ │ ├── caching_test.js
│ │ │ ├── canceled_input_test.js
│ │ │ ├── composition_input_test.js
│ │ │ ├── cursor_movement_test.js
│ │ │ ├── custom_element_test.js
│ │ │ ├── html_loading_test.js
│ │ │ ├── html_reparsing_test.js
│ │ │ ├── html_replacement_test.js
│ │ │ ├── installation_process_test.js
│ │ │ ├── level_2_input_test.js
│ │ │ ├── list_formatting_test.js
│ │ │ ├── morphing_test.js
│ │ │ ├── mutation_input_test.js
│ │ │ ├── pasting_test.js
│ │ │ ├── text_formatting_test.js
│ │ │ └── undo_test.js
│ │ ├── system.js
│ │ ├── test.js
│ │ ├── test_helper.js
│ │ ├── test_helpers/
│ │ │ ├── assertions.js
│ │ │ ├── editor_helpers.js
│ │ │ ├── event_helpers.js
│ │ │ ├── fixtures/
│ │ │ │ ├── editor_default_aria_label.js
│ │ │ │ ├── editor_empty.js
│ │ │ │ ├── editor_html.js
│ │ │ │ ├── editor_in_table.js
│ │ │ │ ├── editor_with_block_styles.js
│ │ │ │ ├── editor_with_bold_styles.js
│ │ │ │ ├── editor_with_image.js
│ │ │ │ ├── editor_with_labels.js
│ │ │ │ ├── editor_with_styled_content.js
│ │ │ │ ├── editor_with_toolbar_and_input.js
│ │ │ │ ├── editors_with_forms.js
│ │ │ │ ├── fixtures.js
│ │ │ │ └── test_image_url.js
│ │ │ ├── functions.js
│ │ │ ├── input_helpers.js
│ │ │ ├── selection_helpers.js
│ │ │ ├── test_helpers.js
│ │ │ ├── test_stubs.js
│ │ │ ├── timing_helpers.js
│ │ │ └── toolbar_helpers.js
│ │ ├── unit/
│ │ │ ├── attachment_test.js
│ │ │ ├── bidi_test.js
│ │ │ ├── block_test.js
│ │ │ ├── composition_test.js
│ │ │ ├── document_test.js
│ │ │ ├── document_view_test.js
│ │ │ ├── helpers/
│ │ │ │ └── custom_elements_test.js
│ │ │ ├── html_parser_test.js
│ │ │ ├── html_sanitizer_test.js
│ │ │ ├── location_mapper_test.js
│ │ │ ├── mutation_observer_test.js
│ │ │ ├── serialization_test.js
│ │ │ ├── string_change_summary_test.js
│ │ │ └── text_test.js
│ │ └── unit.js
│ └── trix/
│ ├── config/
│ │ ├── attachments.js
│ │ ├── block_attributes.js
│ │ ├── browser.js
│ │ ├── css.js
│ │ ├── dompurify.js
│ │ ├── file_size_formatting.js
│ │ ├── index.js
│ │ ├── input.js
│ │ ├── key_names.js
│ │ ├── lang.js
│ │ ├── parser.js
│ │ ├── text_attributes.js
│ │ ├── toolbar.js
│ │ └── undo.js
│ ├── constants.js
│ ├── controllers/
│ │ ├── attachment_editor_controller.js
│ │ ├── composition_controller.js
│ │ ├── controller.js
│ │ ├── editor_controller.js
│ │ ├── index.js
│ │ ├── input_controller.js
│ │ ├── level_0_input_controller.js
│ │ ├── level_2_input_controller.js
│ │ └── toolbar_controller.js
│ ├── core/
│ │ ├── basic_object.js
│ │ ├── collections/
│ │ │ ├── element_store.js
│ │ │ ├── hash.js
│ │ │ ├── index.js
│ │ │ ├── object_group.js
│ │ │ └── object_map.js
│ │ ├── helpers/
│ │ │ ├── arrays.js
│ │ │ ├── bidi.js
│ │ │ ├── config.js
│ │ │ ├── custom_elements.js
│ │ │ ├── dom.js
│ │ │ ├── events.js
│ │ │ ├── extend.js
│ │ │ ├── functions.js
│ │ │ ├── global.js
│ │ │ ├── index.js
│ │ │ ├── objects.js
│ │ │ ├── ranges.js
│ │ │ ├── selection.js
│ │ │ └── strings.js
│ │ ├── index.js
│ │ ├── object.js
│ │ ├── serialization.js
│ │ ├── utilities/
│ │ │ ├── index.js
│ │ │ ├── operation.js
│ │ │ └── utf16_string.js
│ │ └── utilities.js
│ ├── elements/
│ │ ├── index.js
│ │ ├── trix_editor_element.js
│ │ └── trix_toolbar_element.js
│ ├── filters/
│ │ ├── attachment_gallery_filter.js
│ │ ├── filter.js
│ │ └── index.js
│ ├── models/
│ │ ├── attachment.js
│ │ ├── attachment_manager.js
│ │ ├── attachment_piece.js
│ │ ├── block.js
│ │ ├── composition.js
│ │ ├── document.js
│ │ ├── editor.js
│ │ ├── flaky_android_keyboard_detector.js
│ │ ├── html_parser.js
│ │ ├── html_sanitizer.js
│ │ ├── index.js
│ │ ├── line_break_insertion.js
│ │ ├── location_mapper.js
│ │ ├── managed_attachment.js
│ │ ├── piece.js
│ │ ├── point_mapper.js
│ │ ├── selection_manager.js
│ │ ├── splittable_list.js
│ │ ├── string_piece.js
│ │ ├── text.js
│ │ └── undo_manager.js
│ ├── observers/
│ │ ├── index.js
│ │ ├── mutation_observer.js
│ │ └── selection_change_observer.js
│ ├── operations/
│ │ ├── file_verification_operation.js
│ │ ├── image_preload_operation.js
│ │ └── index.js
│ ├── trix.js
│ └── views/
│ ├── attachment_view.js
│ ├── block_view.js
│ ├── document_view.js
│ ├── index.js
│ ├── object_view.js
│ ├── piece_view.js
│ ├── previewable_attachment_view.js
│ └── text_view.js
└── web-test-runner.config.mjs
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc
================================================
{
"parser": "babel-eslint",
"extends": "eslint:recommended",
"rules": {
"array-bracket-spacing": ["error", "always"],
"block-spacing": ["error", "always"],
"camelcase": ["error"],
"comma-spacing": ["error"],
"curly": ["error", "multi-line"],
"dot-notation": ["error"],
"eol-last": ["error"],
"getter-return": ["error"],
"id-length": ["error", { "properties": "never", "exceptions": ["_", "i", "j", "n"] }],
"keyword-spacing": ["error"],
"no-extra-parens": ["error"],
"no-multi-spaces": ["error", { "exceptions": { "VariableDeclarator": true } }],
"no-multiple-empty-lines": ["error", { "max": 2 }],
"no-restricted-globals": ["error", "event"],
"no-trailing-spaces": ["error"],
"no-unused-vars": ["error", { "vars": "all", "args": "none" }],
"no-var": ["error"],
"object-curly-spacing": ["error", "always"],
"prefer-const": ["error"],
"quotes": ["error", "double"],
"semi": ["error", "never"],
"sort-imports": ["error", { "ignoreDeclarationSort": true }]
},
"ignorePatterns": ["dist/**/*.js", "**/vendor/**/*.js", "action_text-trix/**/*.js"],
"globals": {
"after": true,
"getComposition": true,
"getDocument": true,
"getEditor": true,
"getEditorController": true,
"getEditorElement": true,
"getSelectionManager": true,
"getToolbarElement": true,
"QUnit": true,
"rangy": true,
"Trix": true
},
"env": {
"browser": true,
"node": true,
"es6": true
}
}
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
Describe the bug or issue here…
##### Steps to Reproduce
1.
2.
3.
##### Details
* Trix version:
* Browser name and version:
* Operating system:
================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- bug
- enhancement
- pinned
- security
- WIP
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale after 90 days of inactivity.
It will be closed if no further activity occurs.
pulls:
markComment: >
This pull request has been automatically marked as stale after 90 days of inactivity.
It will be closed if no further activity occurs.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
concurrency:
group: "${{github.workflow}}-${{github.ref}}"
cancel-in-progress: true
on:
workflow_dispatch:
push:
branches: [ main ]
pull_request:
types: [opened, synchronize]
branches: [ '*' ]
env:
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
SAUCE_REGION: us
SAUCE_TUNNEL_IDENTIFIER: trix-${{ github.run_id }}
jobs:
build:
name: Browser tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "yarn"
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Start Sauce Connect
if: ${{ env.SAUCE_ACCESS_KEY != '' }}
uses: saucelabs/sauce-connect-action@v3
with:
username: ${{ env.SAUCE_USERNAME }}
accessKey: ${{ env.SAUCE_ACCESS_KEY }}
tunnelName: ${{ env.SAUCE_TUNNEL_IDENTIFIER }}
region: ${{ env.SAUCE_REGION }}
proxyLocalhost: allow
- name: Install Playwright Browsers
if: ${{ env.SAUCE_ACCESS_KEY == '' }}
run: npx playwright install --with-deps chromium
- run: bin/ci
- name: Fail when generated npm changes are not checked-in
run: |
git update-index --refresh && git diff-index --quiet HEAD --
rails-tests:
name: Downstream Rails integration tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "yarn"
- uses: ruby/setup-ruby-pkgs@v1
with:
ruby-version: "3.4"
apt-get: libvips-tools
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Packaging
run: yarn build
- name: Clone Rails
run: git clone --depth=1 https://github.com/rails/rails
- name: Configure Rails
run: |
cd rails
yarn install --frozen-lockfile
bundle add action_text-trix --path ".."
bundle show --paths action_text-trix
- name: Action Text tests
env:
RACK_ENV: test # see https://github.com/rails/rails/issues/56563
run: |
cd rails/actiontext
bundle exec rake test test:system
action_text-trix:
name: Action Text tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- ruby: "3.2"
rails_branch: 7-2-stable
- ruby: "3.3"
rails_branch: 7-2-stable
- ruby: "3.4"
rails_branch: 7-2-stable
- ruby: "3.2"
rails_branch: 8-0-stable
- ruby: "3.3"
rails_branch: 8-0-stable
- ruby: "3.4"
rails_branch: 8-0-stable
- ruby: "3.2"
rails_branch: 8-1-stable
- ruby: "3.3"
rails_branch: 8-1-stable
- ruby: "3.4"
rails_branch: 8-1-stable
- ruby: "4.0"
rails_branch: 8-1-stable
- ruby: "3.3"
rails_branch: main
experimental: true
- ruby: "3.4"
rails_branch: main
experimental: true
- ruby: "4.0"
rails_branch: main
experimental: true
- ruby: head
rails_branch: main
experimental: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "yarn"
- uses: ruby/setup-ruby@v1
env:
RAILS_BRANCH: ${{ matrix.rails_branch }}
with:
working-directory: "./action_text-trix"
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Run tests
env:
RAILS_BRANCH: ${{ matrix.rails_branch }}
continue-on-error: ${{ matrix.experimental || false }}
working-directory: "./action_text-trix"
run: bin/rails test:all
================================================
FILE: .gitignore
================================================
yarn-error.log
package-lock.json
/dist
/node_modules
/tmp
================================================
FILE: .node-version
================================================
18.18.0
================================================
FILE: .npmignore
================================================
.DS_Store
/node_modules
/.github
/bin
/assets
yarn-error.log
yarn.lock
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the [project maintainers](#project-maintainers). All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Project Maintainers
* Javan Makhmali <<javan@basecamp.com>>
* Sam Stephenson <<sam@basecamp.com>>
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: LICENSE
================================================
Copyright (c) 37signals, LLC
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# Trix
### A Rich Text Editor for Everyday Writing
**Compose beautifully formatted text in your web application.** Trix is a WYSIWYG editor for writing messages, comments, articles, and lists—the simple documents most web apps are made of. It features a sophisticated document model, support for embedded attachments, and outputs terse and consistent HTML.
Trix is an open-source project from [37signals](https://37signals.com), the creators of [Ruby on Rails](http://rubyonrails.org/). Millions of people trust their text to us, and we built Trix to give them the best possible editing experience. See Trix in action in [Basecamp](https://basecamp.com).
### Different By Design
When Trix was designed in 2014, most WYSIWYG editors were wrappers around HTML’s `contenteditable` and `execCommand` APIs, designed by Microsoft to support live editing of web pages in Internet Explorer 5.5, and [eventually reverse-engineered](https://blog.whatwg.org/the-road-to-html-5-contenteditable#history) and copied by other browsers.
Because these APIs were not fully specified or documented, and because WYSIWYG HTML editors are enormous in scope, each browser’s implementation has its own set of bugs and quirks, and JavaScript developers are left to resolve the inconsistencies.
Trix sidestepped these inconsistencies by treating `contenteditable` as an I/O device: when input makes its way to the editor, Trix converts that input into an editing operation on its internal document model, then re-renders that document back into the editor. This gives Trix complete control over what happens after every keystroke, and avoids the need to use `execCommand` at all.
This is the approach that all modern, production ready, WYSIWYG editors now take.
### Built on Web standards
<details><summary>Trix supports all evergreen, self-updating desktop and mobile browsers.</summary><img src="https://app.saucelabs.com/browser-matrix/basecamp_trix.svg"></details>
Trix is built with established web standards, notably [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements), [Element Internals](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals), [Mutation Observer](https://dom.spec.whatwg.org/#mutation-observers), and [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
# Getting Started
Trix comes bundled in ESM and UMD formats and works with any asset packaging system.
The easiest way to start with Trix is including it from an npm CDN in the `<head>` of your page:
```html
<head>
…
<link rel="stylesheet" type="text/css" href="https://unpkg.com/trix@2.0.8/dist/trix.css">
<script type="text/javascript" src="https://unpkg.com/trix@2.0.8/dist/trix.umd.min.js"></script>
</head>
```
`trix.css` includes default styles for the Trix toolbar, editor, and attachments. Skip this file if you prefer to define these styles yourself.
Alternatively, you can install the npm package and import it in your application:
```js
import Trix from "trix"
document.addEventListener("trix-before-initialize", () => {
// Change Trix.config if you need
})
```
## Creating an Editor
Place an empty `<trix-editor></trix-editor>` tag on the page. Trix will automatically insert a separate `<trix-toolbar>` before the editor.
Like an HTML `<textarea>`, `<trix-editor>` accepts `autofocus` and `placeholder` attributes. Unlike a `<textarea>`, `<trix-editor>` automatically expands vertically to fit its contents.
## Creating a Toolbar
Trix automatically will create a toolbar for you and attach it right before the `<trix-editor>` element. If you'd like to place the toolbar in a different place you can use the `toolbar` attribute:
```html
<main>
<trix-toolbar id="my_toolbar"></trix-toolbar>
<div class="more-stuff-inbetween"></div>
<trix-editor toolbar="my_toolbar" input="my_input"></trix-editor>
</main>
```
To change the toolbar without modifying Trix, you can overwrite the `Trix.config.toolbar.getDefaultHTML()` function. The default toolbar HTML is in `config/toolbar.js`. Trix uses data attributes to determine how to respond to a toolbar button click.
**Toggle Attribute**
With `data-trix-attribute="<attribute name>"`, you can add an attribute to the current selection.
For example, to apply bold styling to the selected text the button is:
``` html
<button type="button" class="bold" data-trix-attribute="bold" data-trix-key="b"></button>
```
Trix will determine that a range of text is selected and will apply the formatting defined in `Trix.config.textAttributes` (found in `config/text_attributes.js`).
`data-trix-key="b"` tells Trix that this attribute should be applied when you use <kbd>meta</kbd>+<kbd>b</kdb>.
If the attribute is defined in `Trix.config.blockAttributes`, Trix will apply the attribute to the current block of text.
``` html
<button type="button" class="quote" data-trix-attribute="quote"></button>
```
Clicking the quote button toggles whether the block should be rendered with `<blockquote>`.
## Integrating with Element Internals
Trix will integrate `<trix-editor>` elements with forms depending on the browser's support for [Element Internals](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals). If there is a need to disable support for `ElementInternals`, set `Trix.elements.TrixEditorElement.formAssociated = false`:
```js
import Trix from "trix"
Trix.elements.TrixEditorElement.formAssociated = false
```
When Trix is configured to be compatible with `ElementInternals`, it is also
capable of functioning without an `<input type="hidden">` element. To configure
a `<trix-editor>` element to skip creating its `<input type="hidden">`, set the
element's `willCreateInput = false`:
```js
addEventListener("before-trix-initialize", (event) => {
const trixEditor = event.target
trixEditor.willCreateInput = false
})
```
> [!NOTE]
> Trix will *always* use an associated `<input type="hidden">` element when the
> `[input]` attribute is set. To migrate to `<input>`-free support, set
> `willCreateInput = false`, then render the `<trix-editor>` without the
> `[input]` attribute.
> [!WARNING]
> In the absence of an `<input type="hidden">` element, the `<trix-editor>`
> element's value will not be included in `<form>` element submissions unless it
> is rendered with a `[name]` attribute. Set the `[name]` attribute to the same
> value that the `<input type="hidden">` element would have.
## Invoking Internal Trix Actions
Internal actions are defined in `controllers/editor_controller.js` and consist of:
* undo
* redo
* link
* increaseBlockLevel
* decreaseBlockLevel
``` html
<button type="button" class="block-level decrease" data-trix-action="decreaseBlockLevel"></button>
```
## Invoking External Custom Actions
If you want to add a button to the toolbar and have it invoke an external action, you can prefix your action name with `x-`. For example, if I want to print a log statement any time my new button is clicked, I would set by button's data attribute to be `data-trix-action="x-log"`
``` html
<button id="log-button" type="button" data-trix-action="x-log"></button>
```
To respond to the action, listen for `trix-action-invoke`. The event's `target` property returns a reference to the `<trix-editor>` element, its `invokingElement` property returns a reference to the `<button>` element, and its `actionName` property returns the value of the `[data-trix-action]` attribute. Use the value of the `actionName` property to detect which external action was invoked.
```javascript
document.addEventListener("trix-action-invoke", function(event) {
const { target, invokingElement, actionName } = event
if (actionName === "x-log") {
console.log(`Custom ${actionName} invoked from ${invokingElement.id} button on ${target.id} trix-editor`)
}
})
```
## Integrating With Forms
To submit the contents of a `<trix-editor>` with a form, first define a hidden input field in the form and assign it an `id`. Then reference that `id` in the editor’s `input` attribute.
```html
<form …>
<input id="x" type="hidden" name="content">
<trix-editor input="x"></trix-editor>
</form>
```
Trix will automatically update the value of the hidden input field with each change to the editor.
## Populating With Stored Content
To populate a `<trix-editor>` with stored content, include that content in the associated input element’s `value` attribute.
```html
<form …>
<input id="x" value="Editor content goes here" type="hidden" name="content">
<trix-editor input="x"></trix-editor>
</form>
```
Use an associated input element to initially populate an editor. When an associated input element is absent, Trix will safely sanitize then load any HTML content inside a `<trix-editor>…</trix-editor>` tag.
```html
<form …>
<trix-editor>Editor content goes here</trix-editor>
</form>
```
> [!WARNING]
> When a `<trix-editor>` element initially connects with both HTML content *and*
> an associated input element, Trix will *always* disregard the HTML content and
> load its initial content from the associated input element.
## Validating the Editor
Out of the box, `<trix-editor>` elements support browsers' built-in [Constraint
validation][]. When rendered with the [required][] attribute, editors will be
invalid when they're completely empty. For example, consider the following HTML:
```html
<input id="x" value="" type="hidden" name="content">
<trix-editor input="x" required></trix-editor>
```
Since the `<trix-editor>` element is `[required]`, it is invalid when its value
is empty:
```js
const editor = document.querySelector("trix-editor")
editor.validity.valid // => false
editor.validity.valueMissing // => true
editor.matches(":valid") // => false
editor.matches(":invalid") // => true
editor.value = "A value that isn't empty"
editor.validity.valid // => true
editor.validity.valueMissing // => false
editor.matches(":valid") // => true
editor.matches(":invalid") // => false
```
In addition to the built-in `[required]` attribute, `<trix-editor>`
elements support custom validation through their [setCustomValidity][] method.
For example, consider the following HTML:
```js
<input id="x" value="" type="hidden" name="content">
<trix-editor input="x"></trix-editor>
```
Custom validation can occur at any time. For example, validation can occur after
a `trix-change` event fired after the editor's contents change:
```js
addEventListener("trix-change", (event) => {
const editorElement = event.target
const trixDocument = editorElement.editor.getDocument()
const isValid = (trixDocument) => {
// determine the validity based on your custom criteria
return true
}
if (isValid(trixDocument)) {
editorElement.setCustomValidity("")
} else {
editorElement.setCustomValidity("The document is not valid.")
}
}
```
[Constraint validation]: https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation
[required]: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/required
[setCustomValidity]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity
## Disabling the Editor
To disable the `<trix-editor>`, render it with the `[disabled]` attribute:
```html
<trix-editor disabled></trix-editor>
```
Disabled editors are not editable, cannot receive focus, and their values will
be ignored when their related `<form>` element is submitted.
To change whether or not an editor is disabled, either toggle the `[disabled]`
attribute or assign a boolean to the `.disabled` property:
```html
<trix-editor id="editor" disabled></trix-editor>
<script>
const editor = document.getElementById("editor")
editor.toggleAttribute("disabled", false)
editor.disabled = true
</script>
```
When disabled, the editor will match the [:disabled CSS
pseudo-class][:disabled].
[:disabled]: https://developer.mozilla.org/en-US/docs/Web/CSS/:disabled
## Providing an Accessible Name
Like other form controls, `<trix-editor>` elements should have an accessible name. The `<trix-editor>` element integrates with `<label>` elements. It supports two styles of integrating with `<label>` elements:
1. render the `<trix-editor>` element with an `[id]` attribute that the `<label>` element references through its `[for]` attribute:
```html
<label for="editor">Editor</label>
<trix-editor id="editor"></trix-editor>
```
2. render the `<trix-editor>` element as a child of the `<label>` element:
```html
<trix-toolbar id="editor-toolbar"></trix-toolbar>
<label>
Editor
<trix-editor toolbar="editor-toolbar"></trix-editor>
</label>
```
> [!WARNING]
> When rendering the `<trix-editor>` element as a child of the `<label>` element, [explicitly render](#creating-an-editor) the corresponding `<trix-toolbar>` element outside of the `<label>` element.
In addition to integrating with `<label>` elements, `<trix-editor>` elements support `[aria-label]` and `[aria-labelledby]` attributes.
## Styling Formatted Content
To ensure what you see when you edit is what you see when you save, use a CSS class name to scope styles for Trix formatted content. Apply this class name to your `<trix-editor>` element, and to a containing element when you render stored Trix content for display in your application.
```html
<trix-editor class="trix-content"></trix-editor>
```
```html
<div class="trix-content">Stored content here</div>
```
The default `trix.css` file includes styles for basic formatted content—including bulleted and numbered lists, code blocks, and block quotes—under the class name `trix-content`. We encourage you to use these styles as a starting point by copying them into your application’s CSS with a different class name.
## Storing Attached Files
Trix automatically accepts files dragged or pasted into an editor and inserts them as attachments in the document. Each attachment is considered _pending_ until you store it remotely and provide Trix with a permanent URL.
To store attachments, listen for the `trix-attachment-add` event. Upload the attached files with XMLHttpRequest yourself and set the attachment’s URL attribute upon completion. See the [attachment example](https://trix-editor.org/js/attachments.js) for detailed information.
If you don’t want to accept dropped or pasted files, call `preventDefault()` on the `trix-file-accept` event, which Trix dispatches just before the `trix-attachment-add` event.
## Previewing Attached Files
Trix automatically previews attached image files. To determine whether or not to preview an attached file, Trix compares the file's content type against the [Trix.Attachment.previewablePattern](./src/trix/models/attachment.js#L7). By default, Trix will preview the following content types:
* `image/gif`
* `image/png`
* `image/webp`
* `image/jpg`
* `image/jpeg`
To customize an attachment's preview, listen for the `trix-attachment-add` event. When handling the event, set the attachment's `previewable` attribute, then change its preview URL by calling `setPreviewURL`:
```js
addEventListener("trix-attachment-add", (event) => {
if (event.attachment.file instanceof File) {
event.attachment.setAttribute("previewable", true)
event.attachment.setPreviewURL("...")
}
})
```
# Editing Text Programmatically
You can manipulate a Trix editor programmatically through the `Trix.Editor` interface, available on each `<trix-editor>` element through its `editor` property.
```js
var element = document.querySelector("trix-editor")
element.editor // is a Trix.Editor instance
```
## Understanding the Document Model
The formatted content of a Trix editor is known as a _document_, and is represented as an instance of the `Trix.Document` class. To get the editor’s current document, use the `editor.getDocument` method.
```js
element.editor.getDocument() // is a Trix.Document instance
```
You can convert a document to an unformatted JavaScript string with the `document.toString` method.
```js
var document = element.editor.getDocument()
document.toString() // is a JavaScript string
```
### Immutability and Equality
Documents are immutable values. Each change you make in an editor replaces the previous document with a new document. Capturing a snapshot of the editor’s content is as simple as keeping a reference to its document, since that document will never change over time. (This is how Trix implements undo.)
To compare two documents for equality, use the `document.isEqualTo` method.
```js
var document = element.editor.getDocument()
document.isEqualTo(element.editor.getDocument()) // true
```
## Getting and Setting the Selection
Trix documents are structured as sequences of individually addressable characters. The index of one character in a document is called a _position_, and a start and end position together make up a _range_.
To get the editor’s current selection, use the `editor.getSelectedRange` method, which returns a two-element array containing the start and end positions.
```js
element.editor.getSelectedRange() // [0, 0]
```
You can set the editor’s current selection by passing a range array to the `editor.setSelectedRange` method.
```js
// Select the first character in the document
element.editor.setSelectedRange([0, 1])
```
### Collapsed Selections
When the start and end positions of a range are equal, the range is said to be _collapsed_. In the editor, a collapsed selection appears as a blinking cursor rather than a highlighted span of text.
For convenience, the following calls to `setSelectedRange` are equivalent when working with collapsed selections:
```js
element.editor.setSelectedRange(1)
element.editor.setSelectedRange([1])
element.editor.setSelectedRange([1, 1])
```
### Directional Movement
To programmatically move the cursor or selection through the document, call the `editor.moveCursorInDirection` or `editor.expandSelectionInDirection` methods with a _direction_ argument. The direction can be either `"forward"` or `"backward"`.
```js
// Move the cursor backward one character
element.editor.moveCursorInDirection("backward")
// Expand the end of the selection forward by one character
element.editor.expandSelectionInDirection("forward")
```
### Converting Positions to Pixel Offsets
Sometimes you need to know the _x_ and _y_ coordinates of a character at a given position in the editor. For example, you might want to absolutely position a pop-up menu element below the editor’s cursor.
Call the `editor.getClientRectAtPosition` method with a position argument to get a [`DOMRect`](https://drafts.fxtf.org/geometry/#DOMRect) instance representing the left and top offsets, width, and height of the character at the given position.
```js
var rect = element.editor.getClientRectAtPosition(0)
[rect.left, rect.top] // [17, 49]
```
## Inserting and Deleting Text
The editor interface provides methods for inserting, replacing, and deleting text at the current selection.
To insert or replace text, begin by setting the selected range, then call one of the insertion methods below. Trix will first remove any selected text, then insert the new text at the start position of the selected range.
### Inserting Plain Text
To insert unformatted text into the document, call the `editor.insertString` method.
```js
// Insert “Hello” at the beginning of the document
element.editor.setSelectedRange([0, 0])
element.editor.insertString("Hello")
```
### Inserting HTML
To insert HTML into the document, call the `editor.insertHTML` method. Trix will first convert the HTML into its internal document model. During this conversion, any formatting that cannot be represented in a Trix document will be lost.
```js
// Insert a bold “Hello” at the beginning of the document
element.editor.setSelectedRange([0, 0])
element.editor.insertHTML("<strong>Hello</strong>")
```
### Inserting a File
To insert a DOM [`File`](http://www.w3.org/TR/FileAPI/#file) object into the document, call the `editor.insertFile` method. Trix will insert a pending attachment for the file as if you had dragged and dropped it onto the editor.
```js
// Insert the selected file from the first file input element
var file = document.querySelector("input[type=file]").file
element.editor.insertFile(file)
```
### Inserting a Content Attachment
Content attachments are self-contained units of HTML that behave like files in the editor. They can be moved or removed, but not edited directly, and are represented by a single character position in the document model.
To insert HTML as an attachment, create a `Trix.Attachment` with a `content` attribute and call the `editor.insertAttachment` method. The HTML inside a content attachment is not subject to Trix’s document conversion rules and will be rendered as-is.
```js
var attachment = new Trix.Attachment({ content: '<span class="mention">@trix</span>' })
element.editor.insertAttachment(attachment)
```
### Inserting a Line Break
To insert a line break, call the `editor.insertLineBreak` method, which is functionally equivalent to pressing the return key.
```js
// Insert “Hello\n”
element.editor.insertString("Hello")
element.editor.insertLineBreak()
```
### Deleting Text
If the current selection is collapsed, you can simulate deleting text before or after the cursor with the `editor.deleteInDirection` method.
```js
// “Backspace” the first character in the document
element.editor.setSelectedRange([1, 1])
element.editor.deleteInDirection("backward")
// Delete the second character in the document
element.editor.setSelectedRange([1, 1])
element.editor.deleteInDirection("forward")
```
To delete a range of text, first set the selected range, then call `editor.deleteInDirection` with either direction as the argument.
```js
// Delete the first five characters
element.editor.setSelectedRange([0, 4])
element.editor.deleteInDirection("forward")
```
## Working With Attributes and Nesting
Trix represents formatting as sets of _attributes_ applied across ranges of a document.
By default, Trix supports the inline attributes `bold`, `italic`, `href`, and `strike`, and the block-level attributes `heading1`, `quote`, `code`, `bullet`, and `number`.
### Applying Formatting
To apply formatting to the current selection, use the `editor.activateAttribute` method.
```js
element.editor.insertString("Hello")
element.editor.setSelectedRange([0, 5])
element.editor.activateAttribute("bold")
```
To set the `href` attribute, pass a URL as the second argument to `editor.activateAttribute`.
```js
element.editor.insertString("Trix")
element.editor.setSelectedRange([0, 4])
element.editor.activateAttribute("href", "https://trix-editor.org/")
```
### Removing Formatting
Use the `editor.deactivateAttribute` method to remove formatting from a selection.
```js
element.editor.setSelectedRange([2, 4])
element.editor.deactivateAttribute("bold")
```
### Formatting With a Collapsed Selection
If you activate or deactivate attributes when the selection is collapsed, your formatting changes will apply to the text inserted by any subsequent calls to `editor.insertString`.
```js
element.editor.activateAttribute("italic")
element.editor.insertString("This is italic")
```
### Adjusting the Nesting Level
To adjust the nesting level of quotes, bulleted lists, or numbered lists, call the `editor.increaseNestingLevel` and `editor.decreaseNestingLevel` methods.
```js
element.editor.activateAttribute("quote")
element.editor.increaseNestingLevel()
element.editor.decreaseNestingLevel()
```
## Using Undo and Redo
Trix editors support unlimited undo and redo. Successive typing and formatting changes are consolidated together at five-second intervals; all other input changes are recorded individually in undo history.
Call the `editor.undo` and `editor.redo` methods to perform an undo or redo operation.
```js
element.editor.undo()
element.editor.redo()
```
Changes you make through the editor interface will not automatically record undo entries. You can save your own undo entries by calling the `editor.recordUndoEntry` method with a description argument.
```js
element.editor.recordUndoEntry("Insert Text")
element.editor.insertString("Hello")
```
## Loading and Saving Editor State
Serialize an editor’s state with `JSON.stringify` and restore saved state with the `editor.loadJSON` method. The serialized state includes the document and current selection, but does not include undo history.
```js
// Save editor state to local storage
localStorage["editorState"] = JSON.stringify(element.editor)
// Restore editor state from local storage
element.editor.loadJSON(JSON.parse(localStorage["editorState"]))
```
## HTML Sanitization
Trix uses [DOMPurify](https://github.com/cure53/DOMPurify/) to sanitize the editor content. You can set the DOMPurify config via `Trix.config.dompurify`.
For example if you want to keep a custom tag, you can access do that with:
```js
Trix.config.dompurify.ADD_TAGS = [ "my-custom-tag" ]
```
## HTML Rendering
Trix renders changes to editor content by replacing existing nodes with new nodes.
To customize how Trix renders changes, set the `<trix-editor>` element's
`render` property to a function that accepts a `<trix-editor>` instance and a
[DocumentFragment][]:
```js
document.addEventListener("trix-before-render", (event) => {
const defaultRender = event.render
event.render = function(editorElement, documentFragment) {
// modify the documentFragment…
customize(documentFragment)
// render it with the default rendering function
defaultRender(editorElement, documentFragment)
}
})
```
> [!CAUTION]
> By the time that `render(editorElement, documentFragment)` is
> invoked, Trix will have finalized modifications to the HTML content (like HTML
> sanitization, for example). If you make further modifications to the content,
> be sure that they are safe.
[DocumentFragment]: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
## Observing Editor Changes
The `<trix-editor>` element emits several events which you can use to observe and respond to changes in editor state.
* `trix-before-initialize` fires when the `<trix-editor>` element is attached to the DOM just before Trix installs its `editor` object. If you need to use a custom Trix configuration you can change `Trix.config` here.
* `trix-initialize` fires when the `<trix-editor>` element is attached to the DOM and its `editor` object is ready for use.
* `trix-change` fires whenever the editor’s contents have changed.
* `trix-before-render` fires before the editor’s new contents are rendered. You can override the function used to render the content through the `render` property on the event. The `render` function expects two positional arguments: the `<trix-editor>` element that will render and a [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment) instance that contains the new content. Read [HTML Rendering](#html-rendering) to learn more.
* `trix-before-paste` fires just before text is pasted into the editor. You can use this to modify the content being pasted or prevent the paste event from happening at all. The `paste` property on the event contains the pasted `string` or `html`, and the `range` of the inserted text.
* `trix-paste` fires whenever text is pasted into the editor. The `paste` property on the event contains the pasted `string` or `html`, and the `range` of the inserted text.
* `trix-selection-change` fires any time the selected range changes in the editor.
* `trix-focus` and `trix-blur` fire when the editor gains or loses focus, respectively.
* `trix-file-accept` fires when a file is dropped or inserted into the editor. You can access the DOM `File` object through the `file` property on the event. Call `preventDefault` on the event to prevent attaching the file to the document.
* `trix-attachment-add` fires after an attachment is added to the document. You can access the Trix attachment object through the `attachment` property on the event. If the `attachment` object has a `file` property, you should store this file remotely and set the attachment’s URL attribute. See the [attachment example](http://trix-editor.org/js/attachments.js) for detailed information.
* `trix-attachment-edit` fires after an attachment is edited in the document. You can access the Trix attachment object through the `attachment` property on the event.
* `trix-attachment-remove` fires when an attachment is removed from the document. You can access the Trix attachment object through the `attachment` property on the event. You may wish to use this event to clean up remotely stored files.
* `trix-action-invoke` fires when a Trix action is invoked. You can access the `<trix-editor>` element through the event's `target` property, the element responsible for invoking the action through the `invokingElement` property, and the action's name through the `actionName` property. The `trix-action-invoke` event will only fire for [custom](#invoking-external-custom-actions) actions and not for [built-in](#invoking-internal-trix-actions).
# Contributing to Trix
Trix is open-source software, freely distributable under the terms of an [MIT-style license](LICENSE). The [source code is hosted on GitHub](https://github.com/basecamp/trix).
We welcome contributions in the form of bug reports, pull requests, or thoughtful discussions in the [GitHub issue tracker](https://github.com/basecamp/trix/issues). Please see the [Code of Conduct](CODE_OF_CONDUCT.md) for our pledge to contributors.
Trix was created by [Javan Makhmali](https://twitter.com/javan) and [Sam Stephenson](https://twitter.com/sstephenson), with development sponsored by [37signals](https://37signals.com).
### Building From Source
Trix uses [Yarn](https://yarnpkg.com/) to manage dependencies and [Rollup](https://rollupjs.org/guide/en/) to bundle its source.
Install development dependencies with:
```
$ yarn install
```
To generate distribution files run:
```
$ yarn build
```
### Developing In-Browser
You can run a watch process to automatically generate distribution files when your source file change:
```
$ yarn watch
```
When the watch process is running you can run a web server to serve the compiled assets:
```
$ yarn dev
```
With the development server running, you can visit `/index.html` to see a Trix debugger inspector, or `/test.html` to run the tests on a browser.
For easier development, you can watch for changes to the JavaScript and style files, and serve the results in a browser, with a single command:
```
$ yarn start
```
### Running Tests
You can also run the test in a headless mode with:
```
$ yarn test
```
---
© 37signals, LLC.
================================================
FILE: action_text-trix/.gitignore
================================================
Gemfile.lock
pkg
tmp/
log/
storage/
vendor/
================================================
FILE: action_text-trix/Gemfile
================================================
source "https://rubygems.org"
# Specify your gem's dependencies in trix.gemspec.
gemspec
branch = ENV.fetch("RAILS_BRANCH", "main")
gem "rails", github: "rails/rails", branch: branch
gem "importmap-rails"
gem "propshaft"
gem "puma"
gem "sqlite3"
group :test do
gem "cuprite", require: "capybara/cuprite"
gem "minitest", "< 6.0" # can be removed once Rails' line_filtering supports Minitest 6+
end
================================================
FILE: action_text-trix/LICENSE
================================================
Copyright (c) 37signals, LLC
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: action_text-trix/README.md
================================================
## Building the Trix Ruby gem
1. `cd action_text-trix`
2. `bundle exec rake sync` (updates files which must be committed to git)
3. `bundle exec rake build`
4. `gem push pkg/*.gem`
================================================
FILE: action_text-trix/Rakefile
================================================
require "bundler/gem_tasks"
require "rake/clean"
if defined?(Rails)
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
load "rails/tasks/engine.rake"
end
task :sync do
require "json"
FileUtils.cp File.expand_path("../LICENSE", __dir__), __dir__, verbose: true
package_json = JSON.load(File.read(File.join(__dir__, "../package.json")))
version = package_json["version"]
File.write(File.join(__dir__, "lib", "action_text", "trix", "version.rb"), <<~RUBY)
module Trix
VERSION = "#{version}"
end
RUBY
puts "Updated gem version to #{version}"
end
CLEAN.add "pkg"
CLOBBER.add "app/assets/javascripts/trix.js", "app/assets/stylesheets/trix.css"
================================================
FILE: action_text-trix/action_text-trix.gemspec
================================================
require_relative "lib/action_text/trix/version"
Gem::Specification.new do |spec|
spec.name = "action_text-trix"
spec.version = Trix::VERSION
spec.authors = "37signals, LLC"
spec.summary = "A rich text editor for everyday writing"
spec.license = "MIT"
spec.homepage = "https://github.com/basecamp/trix"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
spec.metadata["changelog_uri"] = "#{spec.homepage}/releases"
spec.metadata["rubygems_mfa_required"] = "true"
spec.files = [
"LICENSE",
"app/assets/javascripts/trix.js",
"app/assets/stylesheets/trix.css",
"lib/action_text/trix.rb",
"lib/action_text/trix/engine.rb",
"lib/action_text/trix/version.rb"
]
spec.add_dependency "railties"
end
================================================
FILE: action_text-trix/app/assets/javascripts/.gitattributes
================================================
trix.js linguist-vendored -whitespace
================================================
FILE: action_text-trix/app/assets/javascripts/trix.js
================================================
/*
Trix 2.1.17
Copyright © 2026 37signals, LLC
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Trix = factory());
})(this, (function () { 'use strict';
var name = "trix";
var version = "2.1.17";
var description = "A rich text editor for everyday writing";
var main = "dist/trix.umd.min.js";
var module = "dist/trix.esm.min.js";
var style = "dist/trix.css";
var files = [
"dist/*.css",
"dist/*.js",
"dist/*.map",
"src/{inspector,trix}/*.js"
];
var repository = {
type: "git",
url: "git+https://github.com/basecamp/trix.git"
};
var keywords = [
"rich text",
"wysiwyg",
"editor"
];
var author = "37signals, LLC";
var license = "MIT";
var bugs = {
url: "https://github.com/basecamp/trix/issues"
};
var homepage = "https://trix-editor.org/";
var devDependencies = {
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.4",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^22.0.2",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.3.0",
"@web/dev-server": "^0.1.34",
"@web/test-runner": "^0.20.2",
"@web/test-runner-playwright": "^0.11.1",
"@web/test-runner-webdriver": "^0.9.0",
"babel-eslint": "^10.1.0",
chokidar: "^4.0.2",
concurrently: "^7.4.0",
eslint: "^7.32.0",
esm: "^3.2.25",
idiomorph: "^0.7.3",
qunit: "2.19.1",
rangy: "^1.3.0",
rollup: "^2.56.3",
"rollup-plugin-includepaths": "^0.2.4",
"rollup-plugin-terser": "^7.0.2",
sass: "^1.83.0",
"source-map": "^0.7.6",
svgo: "^2.8.0",
webdriverio: "^7.19.5"
};
var resolutions = {
webdriverio: "^7.19.5"
};
var scripts = {
"build-css": "bin/sass-build assets/trix.scss dist/trix.css action_text-trix/app/assets/stylesheets/trix.css",
"build-js": "rollup -c",
"build-assets": "cp -f assets/*.html dist/",
"build-ruby": "rake -C action_text-trix sync",
build: "yarn run build-js && yarn run build-css && yarn run build-assets && yarn run build-ruby",
watch: "rollup -c -w",
lint: "eslint .",
pretest: "yarn run lint && yarn run build",
test: "web-test-runner",
"test:watch": "web-test-runner --watch",
version: "yarn build && git add action_text-trix",
prerelease: "yarn version && yarn test",
"release-npm": "npm adduser && npm publish",
"release-ruby": "rake -C action_text-trix release",
release: "yarn run release-npm && yarn run release-ruby",
postrelease: "git push && git push --tags",
dev: "web-dev-server --app-index index.html --root-dir dist --node-resolve --open",
start: "yarn build-assets && concurrently --kill-others --names js,css,dev-server 'yarn watch' 'yarn build-css --watch' 'yarn dev'"
};
var dependencies = {
dompurify: "^3.2.5"
};
var engines = {
node: ">= 18"
};
var _package = {
name: name,
version: version,
description: description,
main: main,
module: module,
style: style,
files: files,
repository: repository,
keywords: keywords,
author: author,
license: license,
bugs: bugs,
homepage: homepage,
devDependencies: devDependencies,
resolutions: resolutions,
scripts: scripts,
dependencies: dependencies,
engines: engines
};
const attachmentSelector = "[data-trix-attachment]";
const attachments = {
preview: {
presentation: "gallery",
caption: {
name: true,
size: true
}
},
file: {
caption: {
size: true
}
}
};
const attributes = {
default: {
tagName: "div",
parse: false
},
quote: {
tagName: "blockquote",
nestable: true
},
heading1: {
tagName: "h1",
terminal: true,
breakOnReturn: true,
group: false
},
code: {
tagName: "pre",
terminal: true,
htmlAttributes: ["language"],
text: {
plaintext: true
}
},
bulletList: {
tagName: "ul",
parse: false
},
bullet: {
tagName: "li",
listAttribute: "bulletList",
group: false,
nestable: true,
test(element) {
return tagName$1(element.parentNode) === attributes[this.listAttribute].tagName;
}
},
numberList: {
tagName: "ol",
parse: false
},
number: {
tagName: "li",
listAttribute: "numberList",
group: false,
nestable: true,
test(element) {
return tagName$1(element.parentNode) === attributes[this.listAttribute].tagName;
}
},
attachmentGallery: {
tagName: "div",
exclusive: true,
terminal: true,
parse: false,
group: false
}
};
const tagName$1 = element => {
var _element$tagName;
return element === null || element === void 0 || (_element$tagName = element.tagName) === null || _element$tagName === void 0 ? void 0 : _element$tagName.toLowerCase();
};
const androidVersionMatch = navigator.userAgent.match(/android\s([0-9]+.*Chrome)/i);
const androidVersion = androidVersionMatch && parseInt(androidVersionMatch[1]);
var browser$1 = {
// Android emits composition events when moving the cursor through existing text
// Introduced in Chrome 65: https://bugs.chromium.org/p/chromium/issues/detail?id=764439#c9
composesExistingText: /Android.*Chrome/.test(navigator.userAgent),
// Android 13, especially on Samsung keyboards, emits extra compositionend and beforeinput events
// that can make the input handler lose the current selection or enter an infinite input -> render -> input
// loop.
recentAndroid: androidVersion && androidVersion > 12,
samsungAndroid: androidVersion && navigator.userAgent.match(/Android.*SM-/),
// IE 11 activates resizing handles on editable elements that have "layout"
forcesObjectResizing: /Trident.*rv:11/.test(navigator.userAgent),
// https://www.w3.org/TR/input-events-1/ + https://www.w3.org/TR/input-events-2/
supportsInputEvents: typeof InputEvent !== "undefined" && ["data", "getTargetRanges", "inputType"].every(prop => prop in InputEvent.prototype)
};
var css$3 = {
attachment: "attachment",
attachmentCaption: "attachment__caption",
attachmentCaptionEditor: "attachment__caption-editor",
attachmentMetadata: "attachment__metadata",
attachmentMetadataContainer: "attachment__metadata-container",
attachmentName: "attachment__name",
attachmentProgress: "attachment__progress",
attachmentSize: "attachment__size",
attachmentToolbar: "attachment__toolbar",
attachmentGallery: "attachment-gallery"
};
var dompurify = {
ADD_ATTR: ["language"],
SAFE_FOR_XML: false,
RETURN_DOM: true
};
var lang$1 = {
attachFiles: "Attach Files",
bold: "Bold",
bullets: "Bullets",
byte: "Byte",
bytes: "Bytes",
captionPlaceholder: "Add a caption…",
code: "Code",
heading1: "Heading",
indent: "Increase Level",
italic: "Italic",
link: "Link",
numbers: "Numbers",
outdent: "Decrease Level",
quote: "Quote",
redo: "Redo",
remove: "Remove",
strike: "Strikethrough",
undo: "Undo",
unlink: "Unlink",
url: "URL",
urlPlaceholder: "Enter a URL…",
GB: "GB",
KB: "KB",
MB: "MB",
PB: "PB",
TB: "TB"
};
/* eslint-disable
no-case-declarations,
*/
const sizes = [lang$1.bytes, lang$1.KB, lang$1.MB, lang$1.GB, lang$1.TB, lang$1.PB];
var file_size_formatting = {
prefix: "IEC",
precision: 2,
formatter(number) {
switch (number) {
case 0:
return "0 ".concat(lang$1.bytes);
case 1:
return "1 ".concat(lang$1.byte);
default:
let base;
if (this.prefix === "SI") {
base = 1000;
} else if (this.prefix === "IEC") {
base = 1024;
}
const exp = Math.floor(Math.log(number) / Math.log(base));
const humanSize = number / Math.pow(base, exp);
const string = humanSize.toFixed(this.precision);
const withoutInsignificantZeros = string.replace(/0*$/, "").replace(/\.$/, "");
return "".concat(withoutInsignificantZeros, " ").concat(sizes[exp]);
}
}
};
const ZERO_WIDTH_SPACE = "\uFEFF";
const NON_BREAKING_SPACE = "\u00A0";
const OBJECT_REPLACEMENT_CHARACTER = "\uFFFC";
const extend = function (properties) {
for (const key in properties) {
const value = properties[key];
this[key] = value;
}
return this;
};
const html$2 = document.documentElement;
const match = html$2.matches;
const handleEvent = function (eventName) {
let {
onElement,
matchingSelector,
withCallback,
inPhase,
preventDefault,
times
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const element = onElement ? onElement : html$2;
const selector = matchingSelector;
const useCapture = inPhase === "capturing";
const handler = function (event) {
if (times != null && --times === 0) {
handler.destroy();
}
const target = findClosestElementFromNode(event.target, {
matchingSelector: selector
});
if (target != null) {
withCallback === null || withCallback === void 0 || withCallback.call(target, event, target);
if (preventDefault) {
event.preventDefault();
}
}
};
handler.destroy = () => element.removeEventListener(eventName, handler, useCapture);
element.addEventListener(eventName, handler, useCapture);
return handler;
};
const handleEventOnce = function (eventName) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
options.times = 1;
return handleEvent(eventName, options);
};
const createEvent = function (eventName) {
let {
bubbles,
cancelable,
attributes
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
bubbles = bubbles !== false;
cancelable = cancelable !== false;
const event = document.createEvent("Events");
event.initEvent(eventName, bubbles, cancelable);
if (attributes != null) {
extend.call(event, attributes);
}
return event;
};
const triggerEvent = function (eventName) {
let {
onElement,
bubbles,
cancelable,
attributes
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const element = onElement != null ? onElement : html$2;
const event = createEvent(eventName, {
bubbles,
cancelable,
attributes
});
return element.dispatchEvent(event);
};
const elementMatchesSelector = function (element, selector) {
if ((element === null || element === void 0 ? void 0 : element.nodeType) === 1) {
return match.call(element, selector);
}
};
const findClosestElementFromNode = function (node) {
let {
matchingSelector,
untilNode
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
while (node && node.nodeType !== Node.ELEMENT_NODE) {
node = node.parentNode;
}
if (node == null) {
return;
}
if (matchingSelector != null) {
if (node.closest && untilNode == null) {
return node.closest(matchingSelector);
} else {
while (node && node !== untilNode) {
if (elementMatchesSelector(node, matchingSelector)) {
return node;
}
node = node.parentNode;
}
}
} else {
return node;
}
};
const findInnerElement = function (element) {
while ((_element = element) !== null && _element !== void 0 && _element.firstElementChild) {
var _element;
element = element.firstElementChild;
}
return element;
};
const innerElementIsActive = element => document.activeElement !== element && elementContainsNode(element, document.activeElement);
const elementContainsNode = function (element, node) {
if (!element || !node) {
return;
}
while (node) {
if (node === element) {
return true;
}
node = node.parentNode;
}
};
const findNodeFromContainerAndOffset = function (container, offset) {
if (!container) {
return;
}
if (container.nodeType === Node.TEXT_NODE) {
return container;
} else if (offset === 0) {
return container.firstChild != null ? container.firstChild : container;
} else {
return container.childNodes.item(offset - 1);
}
};
const findElementFromContainerAndOffset = function (container, offset) {
const node = findNodeFromContainerAndOffset(container, offset);
return findClosestElementFromNode(node);
};
const findChildIndexOfNode = function (node) {
var _node;
if (!((_node = node) !== null && _node !== void 0 && _node.parentNode)) {
return;
}
let childIndex = 0;
node = node.previousSibling;
while (node) {
childIndex++;
node = node.previousSibling;
}
return childIndex;
};
const removeNode = node => {
var _node$parentNode;
return node === null || node === void 0 || (_node$parentNode = node.parentNode) === null || _node$parentNode === void 0 ? void 0 : _node$parentNode.removeChild(node);
};
const walkTree = function (tree) {
let {
onlyNodesOfType,
usingFilter,
expandEntityReferences
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const whatToShow = (() => {
switch (onlyNodesOfType) {
case "element":
return NodeFilter.SHOW_ELEMENT;
case "text":
return NodeFilter.SHOW_TEXT;
case "comment":
return NodeFilter.SHOW_COMMENT;
default:
return NodeFilter.SHOW_ALL;
}
})();
return document.createTreeWalker(tree, whatToShow, usingFilter != null ? usingFilter : null, expandEntityReferences === true);
};
const tagName = element => {
var _element$tagName;
return element === null || element === void 0 || (_element$tagName = element.tagName) === null || _element$tagName === void 0 ? void 0 : _element$tagName.toLowerCase();
};
const makeElement = function (tag) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
let key, value;
if (typeof tag === "object") {
options = tag;
tag = options.tagName;
} else {
options = {
attributes: options
};
}
const element = document.createElement(tag);
if (options.editable != null) {
if (options.attributes == null) {
options.attributes = {};
}
options.attributes.contenteditable = options.editable;
}
if (options.attributes) {
for (key in options.attributes) {
value = options.attributes[key];
element.setAttribute(key, value);
}
}
if (options.style) {
for (key in options.style) {
value = options.style[key];
element.style[key] = value;
}
}
if (options.data) {
for (key in options.data) {
value = options.data[key];
element.dataset[key] = value;
}
}
if (options.className) {
options.className.split(" ").forEach(className => {
element.classList.add(className);
});
}
if (options.textContent) {
element.textContent = options.textContent;
}
if (options.childNodes) {
[].concat(options.childNodes).forEach(childNode => {
element.appendChild(childNode);
});
}
return element;
};
let blockTagNames = undefined;
const getBlockTagNames = function () {
if (blockTagNames != null) {
return blockTagNames;
}
blockTagNames = [];
for (const key in attributes) {
const attributes$1 = attributes[key];
if (attributes$1.tagName) {
blockTagNames.push(attributes$1.tagName);
}
}
return blockTagNames;
};
const nodeIsBlockContainer = node => nodeIsBlockStartComment(node === null || node === void 0 ? void 0 : node.firstChild);
const nodeProbablyIsBlockContainer = function (node) {
return getBlockTagNames().includes(tagName(node)) && !getBlockTagNames().includes(tagName(node.firstChild));
};
const nodeIsBlockStart = function (node) {
let {
strict
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
strict: true
};
if (strict) {
return nodeIsBlockStartComment(node);
} else {
return nodeIsBlockStartComment(node) || !nodeIsBlockStartComment(node.firstChild) && nodeProbablyIsBlockContainer(node);
}
};
const nodeIsBlockStartComment = node => nodeIsCommentNode(node) && (node === null || node === void 0 ? void 0 : node.data) === "block";
const nodeIsCommentNode = node => (node === null || node === void 0 ? void 0 : node.nodeType) === Node.COMMENT_NODE;
const nodeIsCursorTarget = function (node) {
let {
name
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!node) {
return;
}
if (nodeIsTextNode(node)) {
if (node.data === ZERO_WIDTH_SPACE) {
if (name) {
return node.parentNode.dataset.trixCursorTarget === name;
} else {
return true;
}
}
} else {
return nodeIsCursorTarget(node.firstChild);
}
};
const nodeIsAttachmentElement = node => elementMatchesSelector(node, attachmentSelector);
const nodeIsEmptyTextNode = node => nodeIsTextNode(node) && (node === null || node === void 0 ? void 0 : node.data) === "";
const nodeIsTextNode = node => (node === null || node === void 0 ? void 0 : node.nodeType) === Node.TEXT_NODE;
const input = {
level2Enabled: true,
getLevel() {
if (this.level2Enabled && browser$1.supportsInputEvents) {
return 2;
} else {
return 0;
}
},
pickFiles(callback) {
const input = makeElement("input", {
type: "file",
multiple: true,
hidden: true,
id: this.fileInputId
});
input.addEventListener("change", () => {
callback(input.files);
removeNode(input);
});
removeNode(document.getElementById(this.fileInputId));
document.body.appendChild(input);
input.click();
}
};
var key_names = {
8: "backspace",
9: "tab",
13: "return",
27: "escape",
37: "left",
39: "right",
46: "delete",
68: "d",
72: "h",
79: "o"
};
var parser = {
removeBlankTableCells: false,
tableCellSeparator: " | ",
tableRowSeparator: "\n"
};
var text_attributes = {
bold: {
tagName: "strong",
inheritable: true,
parser(element) {
const style = window.getComputedStyle(element);
return style.fontWeight === "bold" || style.fontWeight >= 600;
}
},
italic: {
tagName: "em",
inheritable: true,
parser(element) {
const style = window.getComputedStyle(element);
return style.fontStyle === "italic";
}
},
href: {
groupTagName: "a",
parser(element) {
const matchingSelector = "a:not(".concat(attachmentSelector, ")");
const link = element.closest(matchingSelector);
if (link) {
return link.getAttribute("href");
}
}
},
strike: {
tagName: "del",
inheritable: true
},
frozen: {
style: {
backgroundColor: "highlight"
}
}
};
var toolbar = {
getDefaultHTML() {
return "<div class=\"trix-button-row\">\n <span class=\"trix-button-group trix-button-group--text-tools\" data-trix-button-group=\"text-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bold\" data-trix-attribute=\"bold\" data-trix-key=\"b\" title=\"".concat(lang$1.bold, "\" tabindex=\"-1\">").concat(lang$1.bold, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-italic\" data-trix-attribute=\"italic\" data-trix-key=\"i\" title=\"").concat(lang$1.italic, "\" tabindex=\"-1\">").concat(lang$1.italic, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-strike\" data-trix-attribute=\"strike\" title=\"").concat(lang$1.strike, "\" tabindex=\"-1\">").concat(lang$1.strike, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-link\" data-trix-attribute=\"href\" data-trix-action=\"link\" data-trix-key=\"k\" title=\"").concat(lang$1.link, "\" tabindex=\"-1\">").concat(lang$1.link, "</button>\n </span>\n\n <span class=\"trix-button-group trix-button-group--block-tools\" data-trix-button-group=\"block-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-heading-1\" data-trix-attribute=\"heading1\" title=\"").concat(lang$1.heading1, "\" tabindex=\"-1\">").concat(lang$1.heading1, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-quote\" data-trix-attribute=\"quote\" title=\"").concat(lang$1.quote, "\" tabindex=\"-1\">").concat(lang$1.quote, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-code\" data-trix-attribute=\"code\" title=\"").concat(lang$1.code, "\" tabindex=\"-1\">").concat(lang$1.code, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bullet-list\" data-trix-attribute=\"bullet\" title=\"").concat(lang$1.bullets, "\" tabindex=\"-1\">").concat(lang$1.bullets, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-number-list\" data-trix-attribute=\"number\" title=\"").concat(lang$1.numbers, "\" tabindex=\"-1\">").concat(lang$1.numbers, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-decrease-nesting-level\" data-trix-action=\"decreaseNestingLevel\" title=\"").concat(lang$1.outdent, "\" tabindex=\"-1\">").concat(lang$1.outdent, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-increase-nesting-level\" data-trix-action=\"increaseNestingLevel\" title=\"").concat(lang$1.indent, "\" tabindex=\"-1\">").concat(lang$1.indent, "</button>\n </span>\n\n <span class=\"trix-button-group trix-button-group--file-tools\" data-trix-button-group=\"file-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-attach\" data-trix-action=\"attachFiles\" title=\"").concat(lang$1.attachFiles, "\" tabindex=\"-1\">").concat(lang$1.attachFiles, "</button>\n </span>\n\n <span class=\"trix-button-group-spacer\"></span>\n\n <span class=\"trix-button-group trix-button-group--history-tools\" data-trix-button-group=\"history-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-undo\" data-trix-action=\"undo\" data-trix-key=\"z\" title=\"").concat(lang$1.undo, "\" tabindex=\"-1\">").concat(lang$1.undo, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-redo\" data-trix-action=\"redo\" data-trix-key=\"shift+z\" title=\"").concat(lang$1.redo, "\" tabindex=\"-1\">").concat(lang$1.redo, "</button>\n </span>\n </div>\n\n <div class=\"trix-dialogs\" data-trix-dialogs>\n <div class=\"trix-dialog trix-dialog--link\" data-trix-dialog=\"href\" data-trix-dialog-attribute=\"href\">\n <div class=\"trix-dialog__link-fields\">\n <input type=\"url\" name=\"href\" class=\"trix-input trix-input--dialog\" placeholder=\"").concat(lang$1.urlPlaceholder, "\" aria-label=\"").concat(lang$1.url, "\" data-trix-validate-href required data-trix-input>\n <div class=\"trix-button-group\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"").concat(lang$1.link, "\" data-trix-method=\"setAttribute\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"").concat(lang$1.unlink, "\" data-trix-method=\"removeAttribute\">\n </div>\n </div>\n </div>\n </div>");
}
};
const undo = {
interval: 5000
};
var config = /*#__PURE__*/Object.freeze({
__proto__: null,
attachments: attachments,
blockAttributes: attributes,
browser: browser$1,
css: css$3,
dompurify: dompurify,
fileSize: file_size_formatting,
input: input,
keyNames: key_names,
lang: lang$1,
parser: parser,
textAttributes: text_attributes,
toolbar: toolbar,
undo: undo
});
class BasicObject {
static proxyMethod(expression) {
const {
name,
toMethod,
toProperty,
optional
} = parseProxyMethodExpression(expression);
this.prototype[name] = function () {
let subject;
let object;
if (toMethod) {
if (optional) {
var _this$toMethod;
object = (_this$toMethod = this[toMethod]) === null || _this$toMethod === void 0 ? void 0 : _this$toMethod.call(this);
} else {
object = this[toMethod]();
}
} else if (toProperty) {
object = this[toProperty];
}
if (optional) {
var _object;
subject = (_object = object) === null || _object === void 0 ? void 0 : _object[name];
if (subject) {
return apply$1.call(subject, object, arguments);
}
} else {
subject = object[name];
return apply$1.call(subject, object, arguments);
}
};
}
}
const parseProxyMethodExpression = function (expression) {
const match = expression.match(proxyMethodExpressionPattern);
if (!match) {
throw new Error("can't parse @proxyMethod expression: ".concat(expression));
}
const args = {
name: match[4]
};
if (match[2] != null) {
args.toMethod = match[1];
} else {
args.toProperty = match[1];
}
if (match[3] != null) {
args.optional = true;
}
return args;
};
const {
apply: apply$1
} = Function.prototype;
const proxyMethodExpressionPattern = new RegExp("\
^\
(.+?)\
(\\(\\))?\
(\\?)?\
\\.\
(.+?)\
$\
");
var _Array$from, _$codePointAt$1, _$1, _String$fromCodePoint;
class UTF16String extends BasicObject {
static box() {
let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
if (value instanceof this) {
return value;
} else {
return this.fromUCS2String(value === null || value === void 0 ? void 0 : value.toString());
}
}
static fromUCS2String(ucs2String) {
return new this(ucs2String, ucs2decode(ucs2String));
}
static fromCodepoints(codepoints) {
return new this(ucs2encode(codepoints), codepoints);
}
constructor(ucs2String, codepoints) {
super(...arguments);
this.ucs2String = ucs2String;
this.codepoints = codepoints;
this.length = this.codepoints.length;
this.ucs2Length = this.ucs2String.length;
}
offsetToUCS2Offset(offset) {
return ucs2encode(this.codepoints.slice(0, Math.max(0, offset))).length;
}
offsetFromUCS2Offset(ucs2Offset) {
return ucs2decode(this.ucs2String.slice(0, Math.max(0, ucs2Offset))).length;
}
slice() {
return this.constructor.fromCodepoints(this.codepoints.slice(...arguments));
}
charAt(offset) {
return this.slice(offset, offset + 1);
}
isEqualTo(value) {
return this.constructor.box(value).ucs2String === this.ucs2String;
}
toJSON() {
return this.ucs2String;
}
getCacheKey() {
return this.ucs2String;
}
toString() {
return this.ucs2String;
}
}
const hasArrayFrom = ((_Array$from = Array.from) === null || _Array$from === void 0 ? void 0 : _Array$from.call(Array, "\ud83d\udc7c").length) === 1;
const hasStringCodePointAt$1 = ((_$codePointAt$1 = (_$1 = " ").codePointAt) === null || _$codePointAt$1 === void 0 ? void 0 : _$codePointAt$1.call(_$1, 0)) != null;
const hasStringFromCodePoint = ((_String$fromCodePoint = String.fromCodePoint) === null || _String$fromCodePoint === void 0 ? void 0 : _String$fromCodePoint.call(String, 32, 128124)) === " \ud83d\udc7c";
// UCS-2 conversion helpers ported from Mathias Bynens' Punycode.js:
// https://github.com/bestiejs/punycode.js#punycodeucs2
let ucs2decode, ucs2encode;
// Creates an array containing the numeric code points of each Unicode
// character in the string. While JavaScript uses UCS-2 internally,
// this function will convert a pair of surrogate halves (each of which
// UCS-2 exposes as separate characters) into a single code point,
// matching UTF-16.
if (hasArrayFrom && hasStringCodePointAt$1) {
ucs2decode = string => Array.from(string).map(char => char.codePointAt(0));
} else {
ucs2decode = function (string) {
const output = [];
let counter = 0;
const {
length
} = string;
while (counter < length) {
let value = string.charCodeAt(counter++);
if (0xd800 <= value && value <= 0xdbff && counter < length) {
// high surrogate, and there is a next character
const extra = string.charCodeAt(counter++);
if ((extra & 0xfc00) === 0xdc00) {
// low surrogate
value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
} else {
// unmatched surrogate; only append this code unit, in case the
// next code unit is the high surrogate of a surrogate pair
counter--;
}
}
output.push(value);
}
return output;
};
}
// Creates a string based on an array of numeric code points.
if (hasStringFromCodePoint) {
ucs2encode = array => String.fromCodePoint(...Array.from(array || []));
} else {
ucs2encode = function (array) {
const characters = (() => {
const result = [];
Array.from(array).forEach(value => {
let output = "";
if (value > 0xffff) {
value -= 0x10000;
output += String.fromCharCode(value >>> 10 & 0x3ff | 0xd800);
value = 0xdc00 | value & 0x3ff;
}
result.push(output + String.fromCharCode(value));
});
return result;
})();
return characters.join("");
};
}
let id$2 = 0;
class TrixObject extends BasicObject {
static fromJSONString(jsonString) {
return this.fromJSON(JSON.parse(jsonString));
}
constructor() {
super(...arguments);
this.id = ++id$2;
}
hasSameConstructorAs(object) {
return this.constructor === (object === null || object === void 0 ? void 0 : object.constructor);
}
isEqualTo(object) {
return this === object;
}
inspect() {
const parts = [];
const contents = this.contentsForInspection() || {};
for (const key in contents) {
const value = contents[key];
parts.push("".concat(key, "=").concat(value));
}
return "#<".concat(this.constructor.name, ":").concat(this.id).concat(parts.length ? " ".concat(parts.join(", ")) : "", ">");
}
contentsForInspection() {}
toJSONString() {
return JSON.stringify(this);
}
toUTF16String() {
return UTF16String.box(this);
}
getCacheKey() {
return this.id.toString();
}
}
/* eslint-disable
id-length,
*/
const arraysAreEqual = function () {
let a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
if (a.length !== b.length) {
return false;
}
for (let index = 0; index < a.length; index++) {
const value = a[index];
if (value !== b[index]) {
return false;
}
}
return true;
};
const arrayStartsWith = function () {
let a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
return arraysAreEqual(a.slice(0, b.length), b);
};
const spliceArray = function (array) {
const result = array.slice(0);
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
result.splice(...args);
return result;
};
const summarizeArrayChange = function () {
let oldArray = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
let newArray = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
const added = [];
const removed = [];
const existingValues = new Set();
oldArray.forEach(value => {
existingValues.add(value);
});
const currentValues = new Set();
newArray.forEach(value => {
currentValues.add(value);
if (!existingValues.has(value)) {
added.push(value);
}
});
oldArray.forEach(value => {
if (!currentValues.has(value)) {
removed.push(value);
}
});
return {
added,
removed
};
};
// https://github.com/mathiasbynens/unicode-2.1.8/blob/master/Bidi_Class/Right_To_Left/regex.js
const RTL_PATTERN = /[\u05BE\u05C0\u05C3\u05D0-\u05EA\u05F0-\u05F4\u061B\u061F\u0621-\u063A\u0640-\u064A\u066D\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D5\u06E5\u06E6\u200F\u202B\u202E\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE72\uFE74\uFE76-\uFEFC]/;
const getDirection = function () {
const input = makeElement("input", {
dir: "auto",
name: "x",
dirName: "x.dir"
});
const textArea = makeElement("textarea", {
dir: "auto",
name: "y",
dirName: "y.dir"
});
const form = makeElement("form");
form.appendChild(input);
form.appendChild(textArea);
const supportsDirName = function () {
try {
return new FormData(form).has(textArea.dirName);
} catch (error) {
return false;
}
}();
const supportsDirSelector = function () {
try {
return input.matches(":dir(ltr),:dir(rtl)");
} catch (error) {
return false;
}
}();
if (supportsDirName) {
return function (string) {
textArea.value = string;
return new FormData(form).get(textArea.dirName);
};
} else if (supportsDirSelector) {
return function (string) {
input.value = string;
if (input.matches(":dir(rtl)")) {
return "rtl";
} else {
return "ltr";
}
};
} else {
return function (string) {
const char = string.trim().charAt(0);
if (RTL_PATTERN.test(char)) {
return "rtl";
} else {
return "ltr";
}
};
}
}();
let allAttributeNames = null;
let blockAttributeNames = null;
let textAttributeNames = null;
let listAttributeNames = null;
const getAllAttributeNames = () => {
if (!allAttributeNames) {
allAttributeNames = getTextAttributeNames().concat(getBlockAttributeNames());
}
return allAttributeNames;
};
const getBlockConfig = attributeName => attributes[attributeName];
const getBlockAttributeNames = () => {
if (!blockAttributeNames) {
blockAttributeNames = Object.keys(attributes);
}
return blockAttributeNames;
};
const getTextConfig = attributeName => text_attributes[attributeName];
const getTextAttributeNames = () => {
if (!textAttributeNames) {
textAttributeNames = Object.keys(text_attributes);
}
return textAttributeNames;
};
const getListAttributeNames = () => {
if (!listAttributeNames) {
listAttributeNames = [];
for (const key in attributes) {
const {
listAttribute
} = attributes[key];
if (listAttribute != null) {
listAttributeNames.push(listAttribute);
}
}
}
return listAttributeNames;
};
/* eslint-disable
*/
const installDefaultCSSForTagName = function (tagName, defaultCSS) {
const styleElement = insertStyleElementForTagName(tagName);
styleElement.textContent = defaultCSS.replace(/%t/g, tagName);
};
const insertStyleElementForTagName = function (tagName) {
const element = document.createElement("style");
element.setAttribute("type", "text/css");
element.setAttribute("data-tag-name", tagName.toLowerCase());
const nonce = getCSPNonce();
if (nonce) {
element.setAttribute("nonce", nonce);
}
document.head.insertBefore(element, document.head.firstChild);
return element;
};
const getCSPNonce = function () {
const element = getMetaElement("trix-csp-nonce") || getMetaElement("csp-nonce");
if (element) {
const {
nonce,
content
} = element;
return nonce == "" ? content : nonce;
}
};
const getMetaElement = name => document.head.querySelector("meta[name=".concat(name, "]"));
const testTransferData = {
"application/x-trix-feature-detection": "test"
};
const dataTransferIsPlainText = function (dataTransfer) {
const text = dataTransfer.getData("text/plain");
const html = dataTransfer.getData("text/html");
if (text && html) {
const {
body
} = new DOMParser().parseFromString(html, "text/html");
if (body.textContent === text) {
return !body.querySelector("*");
}
} else {
return text === null || text === void 0 ? void 0 : text.length;
}
};
const dataTransferIsMsOfficePaste = _ref => {
let {
dataTransfer
} = _ref;
return dataTransfer.types.includes("Files") && dataTransfer.types.includes("text/html") && dataTransfer.getData("text/html").includes("urn:schemas-microsoft-com:office:office");
};
const dataTransferIsWritable = function (dataTransfer) {
if (!(dataTransfer !== null && dataTransfer !== void 0 && dataTransfer.setData)) return false;
for (const key in testTransferData) {
const value = testTransferData[key];
try {
dataTransfer.setData(key, value);
if (!dataTransfer.getData(key) === value) return false;
} catch (error) {
return false;
}
}
return true;
};
const keyEventIsKeyboardCommand = function () {
if (/Mac|^iP/.test(navigator.platform)) {
return event => event.metaKey;
} else {
return event => event.ctrlKey;
}
}();
function shouldRenderInmmediatelyToDealWithIOSDictation(inputEvent) {
if (/iPhone|iPad/.test(navigator.userAgent)) {
// Handle garbled content and duplicated newlines when using dictation on iOS 18+. Upon dictation completion, iOS sends
// the list of insertText / insertParagraph events in a quick sequence. If we don't render
// the editor synchronously, the internal range fails to update and results in garbled content or duplicated newlines.
//
// This workaround is necessary because iOS doesn't send composing events as expected while dictating:
// https://bugs.webkit.org/show_bug.cgi?id=261764
return !inputEvent.inputType || inputEvent.inputType === "insertParagraph";
} else {
return false;
}
}
const defer = fn => setTimeout(fn, 1);
/* eslint-disable
id-length,
*/
const copyObject = function () {
let object = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
const result = {};
for (const key in object) {
const value = object[key];
result[key] = value;
}
return result;
};
const objectsAreEqual = function () {
let a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (Object.keys(a).length !== Object.keys(b).length) {
return false;
}
for (const key in a) {
const value = a[key];
if (value !== b[key]) {
return false;
}
}
return true;
};
const normalizeRange = function (range) {
if (range == null) return;
if (!Array.isArray(range)) {
range = [range, range];
}
return [copyValue(range[0]), copyValue(range[1] != null ? range[1] : range[0])];
};
const rangeIsCollapsed = function (range) {
if (range == null) return;
const [start, end] = normalizeRange(range);
return rangeValuesAreEqual(start, end);
};
const rangesAreEqual = function (leftRange, rightRange) {
if (leftRange == null || rightRange == null) return;
const [leftStart, leftEnd] = normalizeRange(leftRange);
const [rightStart, rightEnd] = normalizeRange(rightRange);
return rangeValuesAreEqual(leftStart, rightStart) && rangeValuesAreEqual(leftEnd, rightEnd);
};
const copyValue = function (value) {
if (typeof value === "number") {
return value;
} else {
return copyObject(value);
}
};
const rangeValuesAreEqual = function (left, right) {
if (typeof left === "number") {
return left === right;
} else {
return objectsAreEqual(left, right);
}
};
class SelectionChangeObserver extends BasicObject {
constructor() {
super(...arguments);
this.update = this.update.bind(this);
this.selectionManagers = [];
}
start() {
if (!this.started) {
this.started = true;
document.addEventListener("selectionchange", this.update, true);
}
}
stop() {
if (this.started) {
this.started = false;
return document.removeEventListener("selectionchange", this.update, true);
}
}
registerSelectionManager(selectionManager) {
if (!this.selectionManagers.includes(selectionManager)) {
this.selectionManagers.push(selectionManager);
return this.start();
}
}
unregisterSelectionManager(selectionManager) {
this.selectionManagers = this.selectionManagers.filter(sm => sm !== selectionManager);
if (this.selectionManagers.length === 0) {
return this.stop();
}
}
notifySelectionManagersOfSelectionChange() {
return this.selectionManagers.map(selectionManager => selectionManager.selectionDidChange());
}
update() {
this.notifySelectionManagersOfSelectionChange();
}
reset() {
this.update();
}
}
const selectionChangeObserver = new SelectionChangeObserver();
const getDOMSelection = function () {
const selection = window.getSelection();
if (selection.rangeCount > 0) {
return selection;
}
};
const getDOMRange = function () {
var _getDOMSelection;
const domRange = (_getDOMSelection = getDOMSelection()) === null || _getDOMSelection === void 0 ? void 0 : _getDOMSelection.getRangeAt(0);
if (domRange) {
if (!domRangeIsPrivate(domRange)) {
return domRange;
}
}
};
const setDOMRange = function (domRange) {
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(domRange);
return selectionChangeObserver.update();
};
// In Firefox, clicking certain <input> elements changes the selection to a
// private element used to draw its UI. Attempting to access properties of those
// elements throws an error.
// https://bugzilla.mozilla.org/show_bug.cgi?id=208427
const domRangeIsPrivate = domRange => nodeIsPrivate(domRange.startContainer) || nodeIsPrivate(domRange.endContainer);
const nodeIsPrivate = node => !Object.getPrototypeOf(node);
/* eslint-disable
id-length,
no-useless-escape,
*/
const normalizeSpaces = string => string.replace(new RegExp("".concat(ZERO_WIDTH_SPACE), "g"), "").replace(new RegExp("".concat(NON_BREAKING_SPACE), "g"), " ");
const normalizeNewlines = string => string.replace(/\r\n?/g, "\n");
const breakableWhitespacePattern = new RegExp("[^\\S".concat(NON_BREAKING_SPACE, "]"));
const squishBreakableWhitespace = string => string
// Replace all breakable whitespace characters with a space
.replace(new RegExp("".concat(breakableWhitespacePattern.source), "g"), " ")
// Replace two or more spaces with a single space
.replace(/\ {2,}/g, " ");
const summarizeStringChange = function (oldString, newString) {
let added, removed;
oldString = UTF16String.box(oldString);
newString = UTF16String.box(newString);
if (newString.length < oldString.length) {
[removed, added] = utf16StringDifferences(oldString, newString);
} else {
[added, removed] = utf16StringDifferences(newString, oldString);
}
return {
added,
removed
};
};
const utf16StringDifferences = function (a, b) {
if (a.isEqualTo(b)) {
return ["", ""];
}
const diffA = utf16StringDifference(a, b);
const {
length
} = diffA.utf16String;
let diffB;
if (length) {
const {
offset
} = diffA;
const codepoints = a.codepoints.slice(0, offset).concat(a.codepoints.slice(offset + length));
diffB = utf16StringDifference(b, UTF16String.fromCodepoints(codepoints));
} else {
diffB = utf16StringDifference(b, a);
}
return [diffA.utf16String.toString(), diffB.utf16String.toString()];
};
const utf16StringDifference = function (a, b) {
let leftIndex = 0;
let rightIndexA = a.length;
let rightIndexB = b.length;
while (leftIndex < rightIndexA && a.charAt(leftIndex).isEqualTo(b.charAt(leftIndex))) {
leftIndex++;
}
while (rightIndexA > leftIndex + 1 && a.charAt(rightIndexA - 1).isEqualTo(b.charAt(rightIndexB - 1))) {
rightIndexA--;
rightIndexB--;
}
return {
utf16String: a.slice(leftIndex, rightIndexA),
offset: leftIndex
};
};
class Hash extends TrixObject {
static fromCommonAttributesOfObjects() {
let objects = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
if (!objects.length) {
return new this();
}
let hash = box(objects[0]);
let keys = hash.getKeys();
objects.slice(1).forEach(object => {
keys = hash.getKeysCommonToHash(box(object));
hash = hash.slice(keys);
});
return hash;
}
static box(values) {
return box(values);
}
constructor() {
let values = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
super(...arguments);
this.values = copy(values);
}
add(key, value) {
return this.merge(object(key, value));
}
remove(key) {
return new Hash(copy(this.values, key));
}
get(key) {
return this.values[key];
}
has(key) {
return key in this.values;
}
merge(values) {
return new Hash(merge(this.values, unbox(values)));
}
slice(keys) {
const values = {};
Array.from(keys).forEach(key => {
if (this.has(key)) {
values[key] = this.values[key];
}
});
return new Hash(values);
}
getKeys() {
return Object.keys(this.values);
}
getKeysCommonToHash(hash) {
hash = box(hash);
return this.getKeys().filter(key => this.values[key] === hash.values[key]);
}
isEqualTo(values) {
return arraysAreEqual(this.toArray(), box(values).toArray());
}
isEmpty() {
return this.getKeys().length === 0;
}
toArray() {
if (!this.array) {
const result = [];
for (const key in this.values) {
const value = this.values[key];
result.push(result.push(key, value));
}
this.array = result.slice(0);
}
return this.array;
}
toObject() {
return copy(this.values);
}
toJSON() {
return this.toObject();
}
contentsForInspection() {
return {
values: JSON.stringify(this.values)
};
}
}
const object = function (key, value) {
const result = {};
result[key] = value;
return result;
};
const merge = function (object, values) {
const result = copy(object);
for (const key in values) {
const value = values[key];
result[key] = value;
}
return result;
};
const copy = function (object, keyToRemove) {
const result = {};
const sortedKeys = Object.keys(object).sort();
sortedKeys.forEach(key => {
if (key !== keyToRemove) {
result[key] = object[key];
}
});
return result;
};
const box = function (object) {
if (object instanceof Hash) {
return object;
} else {
return new Hash(object);
}
};
const unbox = function (object) {
if (object instanceof Hash) {
return object.values;
} else {
return object;
}
};
class ObjectGroup {
static groupObjects() {
let ungroupedObjects = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
let {
depth,
asTree
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
let group;
if (asTree) {
if (depth == null) {
depth = 0;
}
}
const objects = [];
Array.from(ungroupedObjects).forEach(object => {
var _object$canBeGrouped2;
if (group) {
var _object$canBeGrouped, _group$canBeGroupedWi, _group;
if ((_object$canBeGrouped = object.canBeGrouped) !== null && _object$canBeGrouped !== void 0 && _object$canBeGrouped.call(object, depth) && (_group$canBeGroupedWi = (_group = group[group.length - 1]).canBeGroupedWith) !== null && _group$canBeGroupedWi !== void 0 && _group$canBeGroupedWi.call(_group, object, depth)) {
group.push(object);
return;
} else {
objects.push(new this(group, {
depth,
asTree
}));
group = null;
}
}
if ((_object$canBeGrouped2 = object.canBeGrouped) !== null && _object$canBeGrouped2 !== void 0 && _object$canBeGrouped2.call(object, depth)) {
group = [object];
} else {
objects.push(object);
}
});
if (group) {
objects.push(new this(group, {
depth,
asTree
}));
}
return objects;
}
constructor() {
let objects = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
let {
depth,
asTree
} = arguments.length > 1 ? arguments[1] : undefined;
this.objects = objects;
if (asTree) {
this.depth = depth;
this.objects = this.constructor.groupObjects(this.objects, {
asTree,
depth: this.depth + 1
});
}
}
getObjects() {
return this.objects;
}
getDepth() {
return this.depth;
}
getCacheKey() {
const keys = ["objectGroup"];
Array.from(this.getObjects()).forEach(object => {
keys.push(object.getCacheKey());
});
return keys.join("/");
}
}
class ObjectMap extends BasicObject {
constructor() {
let objects = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
super(...arguments);
this.objects = {};
Array.from(objects).forEach(object => {
const hash = JSON.stringify(object);
if (this.objects[hash] == null) {
this.objects[hash] = object;
}
});
}
find(object) {
const hash = JSON.stringify(object);
return this.objects[hash];
}
}
class ElementStore {
constructor(elements) {
this.reset(elements);
}
add(element) {
const key = getKey(element);
this.elements[key] = element;
}
remove(element) {
const key = getKey(element);
const value = this.elements[key];
if (value) {
delete this.elements[key];
return value;
}
}
reset() {
let elements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
this.elements = {};
Array.from(elements).forEach(element => {
this.add(element);
});
return elements;
}
}
const getKey = element => element.dataset.trixStoreKey;
class Operation extends BasicObject {
isPerforming() {
return this.performing === true;
}
hasPerformed() {
return this.performed === true;
}
hasSucceeded() {
return this.performed && this.succeeded;
}
hasFailed() {
return this.performed && !this.succeeded;
}
getPromise() {
if (!this.promise) {
this.promise = new Promise((resolve, reject) => {
this.performing = true;
return this.perform((succeeded, result) => {
this.succeeded = succeeded;
this.performing = false;
this.performed = true;
if (this.succeeded) {
resolve(result);
} else {
reject(result);
}
});
});
}
return this.promise;
}
perform(callback) {
return callback(false);
}
release() {
var _this$promise, _this$promise$cancel;
(_this$promise = this.promise) === null || _this$promise === void 0 || (_this$promise$cancel = _this$promise.cancel) === null || _this$promise$cancel === void 0 || _this$promise$cancel.call(_this$promise);
this.promise = null;
this.performing = null;
this.performed = null;
this.succeeded = null;
}
}
Operation.proxyMethod("getPromise().then");
Operation.proxyMethod("getPromise().catch");
class ObjectView extends BasicObject {
constructor(object) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
super(...arguments);
this.object = object;
this.options = options;
this.childViews = [];
this.rootView = this;
}
getNodes() {
if (!this.nodes) {
this.nodes = this.createNodes();
}
return this.nodes.map(node => node.cloneNode(true));
}
invalidate() {
var _this$parentView;
this.nodes = null;
this.childViews = [];
return (_this$parentView = this.parentView) === null || _this$parentView === void 0 ? void 0 : _this$parentView.invalidate();
}
invalidateViewForObject(object) {
var _this$findViewForObje;
return (_this$findViewForObje = this.findViewForObject(object)) === null || _this$findViewForObje === void 0 ? void 0 : _this$findViewForObje.invalidate();
}
findOrCreateCachedChildView(viewClass, object, options) {
let view = this.getCachedViewForObject(object);
if (view) {
this.recordChildView(view);
} else {
view = this.createChildView(...arguments);
this.cacheViewForObject(view, object);
}
return view;
}
createChildView(viewClass, object) {
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
if (object instanceof ObjectGroup) {
options.viewClass = viewClass;
viewClass = ObjectGroupView;
}
const view = new viewClass(object, options);
return this.recordChildView(view);
}
recordChildView(view) {
view.parentView = this;
view.rootView = this.rootView;
this.childViews.push(view);
return view;
}
getAllChildViews() {
let views = [];
this.childViews.forEach(childView => {
views.push(childView);
views = views.concat(childView.getAllChildViews());
});
return views;
}
findElement() {
return this.findElementForObject(this.object);
}
findElementForObject(object) {
const id = object === null || object === void 0 ? void 0 : object.id;
if (id) {
return this.rootView.element.querySelector("[data-trix-id='".concat(id, "']"));
}
}
findViewForObject(object) {
for (const view of this.getAllChildViews()) {
if (view.object === object) {
return view;
}
}
}
getViewCache() {
if (this.rootView === this) {
if (this.isViewCachingEnabled()) {
if (!this.viewCache) {
this.viewCache = {};
}
return this.viewCache;
}
} else {
return this.rootView.getViewCache();
}
}
isViewCachingEnabled() {
return this.shouldCacheViews !== false;
}
enableViewCaching() {
this.shouldCacheViews = true;
}
disableViewCaching() {
this.shouldCacheViews = false;
}
getCachedViewForObject(object) {
var _this$getViewCache;
return (_this$getViewCache = this.getViewCache()) === null || _this$getViewCache === void 0 ? void 0 : _this$getViewCache[object.getCacheKey()];
}
cacheViewForObject(view, object) {
const cache = this.getViewCache();
if (cache) {
cache[object.getCacheKey()] = view;
}
}
garbageCollectCachedViews() {
const cache = this.getViewCache();
if (cache) {
const views = this.getAllChildViews().concat(this);
const objectKeys = views.map(view => view.object.getCacheKey());
for (const key in cache) {
if (!objectKeys.includes(key)) {
delete cache[key];
}
}
}
}
}
class ObjectGroupView extends ObjectView {
constructor() {
super(...arguments);
this.objectGroup = this.object;
this.viewClass = this.options.viewClass;
delete this.options.viewClass;
}
getChildViews() {
if (!this.childViews.length) {
Array.from(this.objectGroup.getObjects()).forEach(object => {
this.findOrCreateCachedChildView(this.viewClass, object, this.options);
});
}
return this.childViews;
}
createNodes() {
const element = this.createContainerElement();
this.getChildViews().forEach(view => {
Array.from(view.getNodes()).forEach(node => {
element.appendChild(node);
});
});
return [element];
}
createContainerElement() {
let depth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.objectGroup.getDepth();
return this.getChildViews()[0].createContainerElement(depth);
}
}
/*! @license DOMPurify 3.2.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.7/LICENSE */
const {
entries,
setPrototypeOf,
isFrozen,
getPrototypeOf,
getOwnPropertyDescriptor
} = Object;
let {
freeze,
seal,
create
} = Object; // eslint-disable-line import/no-mutable-exports
let {
apply,
construct
} = typeof Reflect !== 'undefined' && Reflect;
if (!freeze) {
freeze = function freeze(x) {
return x;
};
}
if (!seal) {
seal = function seal(x) {
return x;
};
}
if (!apply) {
apply = function apply(func, thisArg) {
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
args[_key - 2] = arguments[_key];
}
return func.apply(thisArg, args);
};
}
if (!construct) {
construct = function construct(Func) {
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
return new Func(...args);
};
}
const arrayForEach = unapply(Array.prototype.forEach);
const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
const arrayPop = unapply(Array.prototype.pop);
const arrayPush = unapply(Array.prototype.push);
const arraySplice = unapply(Array.prototype.splice);
const stringToLowerCase = unapply(String.prototype.toLowerCase);
const stringToString = unapply(String.prototype.toString);
const stringMatch = unapply(String.prototype.match);
const stringReplace = unapply(String.prototype.replace);
const stringIndexOf = unapply(String.prototype.indexOf);
const stringTrim = unapply(String.prototype.trim);
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
const regExpTest = unapply(RegExp.prototype.test);
const typeErrorCreate = unconstruct(TypeError);
/**
* Creates a new function that calls the given function with a specified thisArg and arguments.
*
* @param func - The function to be wrapped and called.
* @returns A new function that calls the given function with a specified thisArg and arguments.
*/
function unapply(func) {
return function (thisArg) {
if (thisArg instanceof RegExp) {
thisArg.lastIndex = 0;
}
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
args[_key3 - 1] = arguments[_key3];
}
return apply(func, thisArg, args);
};
}
/**
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
*
* @param func - The constructor function to be wrapped and called.
* @returns A new function that constructs an instance of the given constructor function with the provided arguments.
*/
function unconstruct(Func) {
return function () {
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
args[_key4] = arguments[_key4];
}
return construct(Func, args);
};
}
/**
* Add properties to a lookup table
*
* @param set - The set to which elements will be added.
* @param array - The array containing elements to be added to the set.
* @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
* @returns The modified set with added elements.
*/
function addToSet(set, array) {
let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
if (setPrototypeOf) {
// Make 'in' and truthy checks like Boolean(set.constructor)
// independent of any properties defined on Object.prototype.
// Prevent prototype setters from intercepting set as a this value.
setPrototypeOf(set, null);
}
let l = array.length;
while (l--) {
let element = array[l];
if (typeof element === 'string') {
const lcElement = transformCaseFunc(element);
if (lcElement !== element) {
// Config presets (e.g. tags.js, attrs.js) are immutable.
if (!isFrozen(array)) {
array[l] = lcElement;
}
element = lcElement;
}
}
set[element] = true;
}
return set;
}
/**
* Clean up an array to harden against CSPP
*
* @param array - The array to be cleaned.
* @returns The cleaned version of the array
*/
function cleanArray(array) {
for (let index = 0; index < array.length; index++) {
const isPropertyExist = objectHasOwnProperty(array, index);
if (!isPropertyExist) {
array[index] = null;
}
}
return array;
}
/**
* Shallow clone an object
*
* @param object - The object to be cloned.
* @returns A new object that copies the original.
*/
function clone(object) {
const newObject = create(null);
for (const [property, value] of entries(object)) {
const isPropertyExist = objectHasOwnProperty(object, property);
if (isPropertyExist) {
if (Array.isArray(value)) {
newObject[property] = cleanArray(value);
} else if (value && typeof value === 'object' && value.constructor === Object) {
newObject[property] = clone(value);
} else {
newObject[property] = value;
}
}
}
return newObject;
}
/**
* This method automatically checks if the prop is function or getter and behaves accordingly.
*
* @param object - The object to look up the getter function in its prototype chain.
* @param prop - The property name for which to find the getter function.
* @returns The getter function found in the prototype chain or a fallback function.
*/
function lookupGetter(object, prop) {
while (object !== null) {
const desc = getOwnPropertyDescriptor(object, prop);
if (desc) {
if (desc.get) {
return unapply(desc.get);
}
if (typeof desc.value === 'function') {
return unapply(desc.value);
}
}
object = getPrototypeOf(object);
}
function fallbackValue() {
return null;
}
return fallbackValue;
}
const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'slot', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
// List of SVG elements that are disallowed by default.
// We still need to know them so that we can do namespace
// checks properly in case one wants to add them to
// allow-list.
const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
// Similarly to SVG, we want to know all MathML elements,
// even those that we disallow by default.
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
const text = freeze(['#text']);
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
// eslint-disable-next-line unicorn/better-regex
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
);
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
);
const DOCTYPE_NAME = seal(/^html$/i);
const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
__proto__: null,
ARIA_ATTR: ARIA_ATTR,
ATTR_WHITESPACE: ATTR_WHITESPACE,
CUSTOM_ELEMENT: CUSTOM_ELEMENT,
DATA_ATTR: DATA_ATTR,
DOCTYPE_NAME: DOCTYPE_NAME,
ERB_EXPR: ERB_EXPR,
IS_ALLOWED_URI: IS_ALLOWED_URI,
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
MUSTACHE_EXPR: MUSTACHE_EXPR,
TMPLIT_EXPR: TMPLIT_EXPR
});
/* eslint-disable @typescript-eslint/indent */
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
const NODE_TYPE = {
element: 1,
attribute: 2,
text: 3,
cdataSection: 4,
entityReference: 5,
// Deprecated
entityNode: 6,
// Deprecated
progressingInstruction: 7,
comment: 8,
document: 9,
documentType: 10,
documentFragment: 11,
notation: 12 // Deprecated
};
const getGlobal = function getGlobal() {
return typeof window === 'undefined' ? null : window;
};
/**
* Creates a no-op policy for internal use only.
* Don't export this function outside this module!
* @param trustedTypes The policy factory.
* @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
* @return The policy created (or null, if Trusted Types
* are not supported or creating the policy failed).
*/
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
return null;
}
// Allow the callers to control the unique policy name
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
// Policy creation with duplicate names throws in Trusted Types.
let suffix = null;
const ATTR_NAME = 'data-tt-policy-suffix';
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
suffix = purifyHostElement.getAttribute(ATTR_NAME);
}
const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
try {
return trustedTypes.createPolicy(policyName, {
createHTML(html) {
return html;
},
createScriptURL(scriptUrl) {
return scriptUrl;
}
});
} catch (_) {
// Policy creation failed (most likely another DOMPurify script has
// already run). Skip creating the policy, as this will only cause errors
// if TT are enforced.
console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
return null;
}
};
const _createHooksMap = function _createHooksMap() {
return {
afterSanitizeAttributes: [],
afterSanitizeElements: [],
afterSanitizeShadowDOM: [],
beforeSanitizeAttributes: [],
beforeSanitizeElements: [],
beforeSanitizeShadowDOM: [],
uponSanitizeAttribute: [],
uponSanitizeElement: [],
uponSanitizeShadowNode: []
};
};
function createDOMPurify() {
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
const DOMPurify = root => createDOMPurify(root);
DOMPurify.version = '3.2.7';
DOMPurify.removed = [];
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
// Not running in a browser, provide a factory function
// so that you can pass your own Window
DOMPurify.isSupported = false;
return DOMPurify;
}
let {
document
} = window;
const originalDocument = document;
const currentScript = originalDocument.currentScript;
const {
DocumentFragment,
HTMLTemplateElement,
Node,
Element,
NodeFilter,
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
HTMLFormElement,
DOMParser,
trustedTypes
} = window;
const ElementPrototype = Element.prototype;
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
const remove = lookupGetter(ElementPrototype, 'remove');
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
// As per issue #47, the web-components registry is inherited by a
// new document created via createHTMLDocument. As per the spec
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
// a new empty registry is used when creating a template contents owner
// document, so we use that as our parent document to ensure nothing
// is inherited.
if (typeof HTMLTemplateElement === 'function') {
const template = document.createElement('template');
if (template.content && template.content.ownerDocument) {
document = template.content.ownerDocument;
}
}
let trustedTypesPolicy;
let emptyHTML = '';
const {
implementation,
createNodeIterator,
createDocumentFragment,
getElementsByTagName
} = document;
const {
importNode
} = originalDocument;
let hooks = _createHooksMap();
/**
* Expose whether this browser supports running the full DOMPurify.
*/
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
const {
MUSTACHE_EXPR,
ERB_EXPR,
TMPLIT_EXPR,
DATA_ATTR,
ARIA_ATTR,
IS_SCRIPT_OR_DATA,
ATTR_WHITESPACE,
CUSTOM_ELEMENT
} = EXPRESSIONS;
let {
IS_ALLOWED_URI: IS_ALLOWED_URI$1
} = EXPRESSIONS;
/**
* We consider the elements and attributes below to be safe. Ideally
* don't add any new ones but feel free to remove unwanted ones.
*/
/* allowed element names */
let ALLOWED_TAGS = null;
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
/* Allowed attribute names */
let ALLOWED_ATTR = null;
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
/*
* Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
*/
let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
tagNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
attributeNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
allowCustomizedBuiltInElements: {
writable: true,
configurable: false,
enumerable: true,
value: false
}
}));
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
let FORBID_TAGS = null;
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
let FORBID_ATTR = null;
/* Decide if ARIA attributes are okay */
let ALLOW_ARIA_ATTR = true;
/* Decide if custom data attributes are okay */
let ALLOW_DATA_ATTR = true;
/* Decide if unknown protocols are okay */
let ALLOW_UNKNOWN_PROTOCOLS = false;
/* Decide if self-closing tags in attributes are allowed.
* Usually removed due to a mXSS issue in jQuery 3.0 */
let ALLOW_SELF_CLOSE_IN_ATTR = true;
/* Output should be safe for common template engines.
* This means, DOMPurify removes data attributes, mustaches and ERB
*/
let SAFE_FOR_TEMPLATES = false;
/* Output should be safe even for XML used within HTML and alike.
* This means, DOMPurify removes comments when containing risky content.
*/
let SAFE_FOR_XML = true;
/* Decide if document with <html>... should be returned */
let WHOLE_DOCUMENT = false;
/* Track whether config is already set on this instance of DOMPurify. */
let SET_CONFIG = false;
/* Decide if all elements (e.g. style, script) must be children of
* document.body. By default, browsers might move them to document.head */
let FORCE_BODY = false;
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
* string (or a TrustedHTML object if Trusted Types are supported).
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
*/
let RETURN_DOM = false;
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
* string (or a TrustedHTML object if Trusted Types are supported) */
let RETURN_DOM_FRAGMENT = false;
/* Try to return a Trusted Type object instead of a string, return a string in
* case Trusted Types are not supported */
let RETURN_TRUSTED_TYPE = false;
/* Output should be free from DOM clobbering attacks?
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
*/
let SANITIZE_DOM = true;
/* Achieve full DOM Clobbering protection by isolating the namespace of named
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
*
* HTML/DOM spec rules that enable DOM Clobbering:
* - Named Access on Window (§7.3.3)
* - DOM Tree Accessors (§3.1.5)
* - Form Element Parent-Child Relations (§4.10.3)
* - Iframe srcdoc / Nested WindowProxies (§4.8.5)
* - HTMLCollection (§4.2.10.2)
*
* Namespace isolation is implemented by prefixing `id` and `name` attributes
* with a constant string, i.e., `user-content-`
*/
let SANITIZE_NAMED_PROPS = false;
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
/* Keep element content when removing element? */
let KEEP_CONTENT = true;
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
* of importing it into a new Document and returning a sanitized copy */
let IN_PLACE = false;
/* Allow usage of profiles like html, svg and mathMl */
let USE_PROFILES = {};
/* Tags to ignore content of when KEEP_CONTENT is true */
let FORBID_CONTENTS = null;
const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
/* Tags that are safe for data: URIs */
let DATA_URI_TAGS = null;
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
/* Attributes safe for values like "javascript:" */
let URI_SAFE_ATTRIBUTES = null;
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
/* Document namespace */
let NAMESPACE = HTML_NAMESPACE;
let IS_EMPTY_INPUT = false;
/* Allowed XHTML+XML namespaces */
let ALLOWED_NAMESPACES = null;
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
// Certain elements are allowed in both SVG and HTML
// namespace. We need to specify them explicitly
// so that they don't get erroneously deleted from
// HTML namespace.
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
/* Parsing of strict XHTML documents */
let PARSER_MEDIA_TYPE = null;
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
let transformCaseFunc = null;
/* Keep a reference to config to pass to hooks */
let CONFIG = null;
/* Ideally, do not touch anything below this line */
/* ______________________________________________ */
const formElement = document.createElement('form');
const isRegexOrFunction = function isRegexOrFunction(testValue) {
return testValue instanceof RegExp || testValue instanceof Function;
};
/**
* _parseConfig
*
* @param cfg optional config literal
*/
// eslint-disable-next-line complexity
const _parseConfig = function _parseConfig() {
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (CONFIG && CONFIG === cfg) {
return;
}
/* Shield configuration object from tampering */
if (!cfg || typeof cfg !== 'object') {
cfg = {};
}
/* Shield configuration object from prototype pollution */
cfg = clone(cfg);
PARSER_MEDIA_TYPE =
// eslint-disable-next-line unicorn/prefer-includes
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
/* Set configuration parameters */
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
IN_PLACE = cfg.IN_PLACE || false; // Default false
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
}
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
}
if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
}
if (SAFE_FOR_TEMPLATES) {
ALLOW_DATA_ATTR = false;
}
if (RETURN_DOM_FRAGMENT) {
RETURN_DOM = true;
}
/* Parse profile info */
if (USE_PROFILES) {
ALLOWED_TAGS = addToSet({}, text);
ALLOWED_ATTR = [];
if (USE_PROFILES.html === true) {
addToSet(ALLOWED_TAGS, html$1);
addToSet(ALLOWED_ATTR, html);
}
if (USE_PROFILES.svg === true) {
addToSet(ALLOWED_TAGS, svg$1);
addToSet(ALLOWED_ATTR, svg);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.svgFilters === true) {
addToSet(ALLOWED_TAGS, svgFilters);
addToSet(ALLOWED_ATTR, svg);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.mathMl === true) {
addToSet(ALLOWED_TAGS, mathMl$1);
addToSet(ALLOWED_ATTR, mathMl);
addToSet(ALLOWED_ATTR, xml);
}
}
/* Merge configuration parameters */
if (cfg.ADD_TAGS) {
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
ALLOWED_TAGS = clone(ALLOWED_TAGS);
}
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
}
if (cfg.ADD_ATTR) {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
ALLOWED_ATTR = clone(ALLOWED_ATTR);
}
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
}
if (cfg.ADD_URI_SAFE_ATTR) {
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
}
if (cfg.FORBID_CONTENTS) {
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
FORBID_CONTENTS = clone(FORBID_CONTENTS);
}
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
}
/* Add #text in case KEEP_CONTENT is set to true */
if (KEEP_CONTENT) {
ALLOWED_TAGS['#text'] = true;
}
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
if (WHOLE_DOCUMENT) {
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
}
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
if (ALLOWED_TAGS.table) {
addToSet(ALLOWED_TAGS, ['tbody']);
delete FORBID_TAGS.tbody;
}
if (cfg.TRUSTED_TYPES_POLICY) {
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
}
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
}
// Overwrite existing TrustedTypes policy.
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
// Sign local variables required by `sanitize`.
emptyHTML = trustedTypesPolicy.createHTML('');
} else {
// Uninitialized policy, attempt to initialize the internal dompurify policy.
if (trustedTypesPolicy === undefined) {
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
}
// If creating the internal policy succeeded sign internal variables.
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
emptyHTML = trustedTypesPolicy.createHTML('');
}
}
// Prevent further manipulation of configuration.
// Not available in IE8, Safari 5, etc.
if (freeze) {
freeze(cfg);
}
CONFIG = cfg;
};
/* Keep track of all possible SVG and MathML tags
* so that we can perform the namespace checks
* correctly. */
const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
/**
* @param element a DOM element whose namespace is being checked
* @returns Return false if the element has a
* namespace that a spec-compliant parser would never
* return. Return true otherwise.
*/
const _checkValidNamespace = function _checkValidNamespace(element) {
let parent = getParentNode(element);
// In JSDOM, if we're inside shadow DOM, then parentNode
// can be null. We just simulate parent in this case.
if (!parent || !parent.tagName) {
parent = {
namespaceURI: NAMESPACE,
tagName: 'template'
};
}
const tagName = stringToLowerCase(element.tagName);
const parentTagName = stringToLowerCase(parent.tagName);
if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
return false;
}
if (element.namespaceURI === SVG_NAMESPACE) {
// The only way to switch from HTML namespace to SVG
// is via <svg>. If it happens via any other tag, then
// it should be killed.
if (parent.namespaceURI === HTML_NAMESPACE) {
return tagName === 'svg';
}
// The only way to switch from MathML to SVG is via`
// svg if parent is either <annotation-xml> or MathML
// text integration points.
if (parent.namespaceURI === MATHML_NAMESPACE) {
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
}
// We only allow elements that are defined in SVG
// spec. All others are disallowed in SVG namespace.
return Boolean(ALL_SVG_TAGS[tagName]);
}
if (element.namespaceURI === MATHML_NAMESPACE) {
// The only way to switch from HTML namespace to MathML
// is via <math>. If it happens via any other tag, then
// it should be killed.
if (parent.namespaceURI === HTML_NAMESPACE) {
return tagName === 'math';
}
// The only way to switch from SVG to MathML is via
// <math> and HTML integration points
if (parent.namespaceURI === SVG_NAMESPACE) {
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
}
// We only allow elements that are defined in MathML
// spec. All others are disallowed in MathML namespace.
return Boolean(ALL_MATHML_TAGS[tagName]);
}
if (element.namespaceURI === HTML_NAMESPACE) {
// The only way to switch from SVG to HTML is via
// HTML integration points, and from MathML to HTML
// is via MathML text integration points
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
return false;
}
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
return false;
}
// We disallow tags that are specific for MathML
// or SVG and should never appear in HTML namespace
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
}
// For XHTML and XML documents that support custom namespaces
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
return true;
}
// The code should never reach this place (this means
// that the element somehow got namespace that is not
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
// Return false just in case.
return false;
};
/**
* _forceRemove
*
* @param node a DOM node
*/
const _forceRemove = function _forceRemove(node) {
arrayPush(DOMPurify.removed, {
element: node
});
try {
// eslint-disable-next-line unicorn/prefer-dom-node-remove
getParentNode(node).removeChild(node);
} catch (_) {
remove(node);
}
};
/**
* _removeAttribute
*
* @param name an Attribute name
* @param element a DOM node
*/
const _removeAttribute = function _removeAttribute(name, element) {
try {
arrayPush(DOMPurify.removed, {
attribute: element.getAttributeNode(name),
from: element
});
} catch (_) {
arrayPush(DOMPurify.removed, {
attribute: null,
from: element
});
}
element.removeAttribute(name);
// We void attribute values for unremovable "is" attributes
if (name === 'is') {
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
try {
_forceRemove(element);
} catch (_) {}
} else {
try {
element.setAttribute(name, '');
} catch (_) {}
}
}
};
/**
* _initDocument
*
* @param dirty - a string of dirty markup
* @return a DOM, filled with the dirty markup
*/
const _initDocument = function _initDocument(dirty) {
/* Create a HTML document */
let doc = null;
let leadingWhitespace = null;
if (FORCE_BODY) {
dirty = '<remove></remove>' + dirty;
} else {
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
leadingWhitespace = matches && matches[0];
}
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
}
const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
/*
* Use the DOMParser API by default, fallback later if needs be
* DOMParser not work for svg when has multiple root element.
*/
if (NAMESPACE === HTML_NAMESPACE) {
try {
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
} catch (_) {}
}
/* Use createHTMLDocument in case DOMParser is not available */
if (!doc || !doc.documentElement) {
doc = implementation.createDocument(NAMESPACE, 'template', null);
try {
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
} catch (_) {
// Syntax error if dirtyPayload is invalid xml
}
}
const body = doc.body || doc.documentElement;
if (dirty && leadingWhitespace) {
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
}
/* Work on whole document or just its body */
if (NAMESPACE === HTML_NAMESPACE) {
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
}
return WHOLE_DOCUMENT ? doc.documentElement : body;
};
/**
* Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
*
* @param root The root element or node to start traversing on.
* @return The created NodeIterator
*/
const _createNodeIterator = function _createNodeIterator(root) {
return createNodeIterator.call(root.ownerDocument || root, root,
// eslint-disable-next-line no-bitwise
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
};
/**
* _isClobbered
*
* @param element element to check for clobbering attacks
* @return true if clobbered, false if safe
*/
const _isClobbered = function _isClobbered(element) {
return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
};
/**
* Checks whether the given object is a DOM node.
*
* @param value object to check whether it's a DOM node
* @return true is object is a DOM node
*/
const _isNode = function _isNode(value) {
return typeof Node === 'function' && value instanceof Node;
};
function _executeHooks(hooks, currentNode, data) {
arrayForEach(hooks, hook => {
hook.call(DOMPurify, currentNode, data, CONFIG);
});
}
/**
* _sanitizeElements
*
* @protect nodeName
* @protect textContent
* @protect removeChild
* @param currentNode to check for permission to exist
* @return true if node was killed, false if left alive
*/
const _sanitizeElements = function _sanitizeElements(currentNode) {
let content = null;
/* Execute a hook if present */
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
/* Check if element is clobbered or can clobber */
if (_isClobbered(currentNode)) {
_forceRemove(currentNode);
return true;
}
/* Now let's check the element's type and name */
const tagName = transformCaseFunc(currentNode.nodeName);
/* Execute a hook if present */
_executeHooks(hooks.uponSanitizeElement, currentNode, {
tagName,
allowedTags: ALLOWED_TAGS
});
/* Detect mXSS attempts abusing namespace confusion */
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
_forceRemove(currentNode);
return true;
}
/* Remove any occurrence of processing instructions */
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
_forceRemove(currentNode);
return true;
}
/* Remove any kind of possibly harmful comments */
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
_forceRemove(currentNode);
return true;
}
/* Remove element if anything forbids its presence */
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
/* Check if we have a custom element to handle */
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
return false;
}
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
return false;
}
}
/* Keep content except for bad-listed elements */
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
if (childNodes && parentNode) {
const childCount = childNodes.length;
for (let i = childCount - 1; i >= 0; --i) {
const childClone = cloneNode(childNodes[i], true);
childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
parentNode.insertBefore(childClone, getNextSibling(currentNode));
}
}
}
_forceRemove(currentNode);
return true;
}
/* Check whether element has a valid namespace */
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
_forceRemove(currentNode);
return true;
}
/* Make sure that older browsers don't get fallback-tag mXSS */
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
_forceRemove(currentNode);
return true;
}
/* Sanitize element content to be template-safe */
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
/* Get the element's text content */
content = currentNode.textContent;
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
content = stringReplace(content, expr, ' ');
});
if (currentNode.textContent !== content) {
arrayPush(DOMPurify.removed, {
element: currentNode.cloneNode()
});
currentNode.textContent = content;
}
}
/* Execute a hook if present */
_executeHooks(hooks.afterSanitizeElements, currentNode, null);
return false;
};
/**
* _isValidAttribute
*
* @param lcTag Lowercase tag name of containing element.
* @param lcName Lowercase attribute name.
* @param value Attribute value.
* @return Returns true if `value` is valid, otherwise false.
*/
// eslint-disable-next-line complexity
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
/* Make sure attribute cannot clobber */
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
return false;
}
/* Allow valid data-* attributes: At least one character after "-"
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
We don't need to check the value; it's always URI safe. */
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ;else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ;else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
if (
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
_isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) ||
// Alternative, second condition checks if it's an `is`-attribute, AND
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ;else {
return false;
}
/* Check value is safe. First, is attr inert? If so, is safe */
} else if (URI_SAFE_ATTRIBUTES[lcName]) ;else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ;else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ;else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ;else if (value) {
return false;
} else ;
return true;
};
/**
* _isBasicCustomElement
* checks if at least one dash is included in tagName, and it's not the first char
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
*
* @param tagName name of the tag of the node to sanitize
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
*/
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
};
/**
* _sanitizeAttributes
*
* @protect attributes
* @protect nodeName
* @protect removeAttribute
* @protect setAttribute
*
* @param currentNode to sanitize
*/
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
/* Execute a hook if present */
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
const {
attributes
} = currentNode;
/* Check if we have attributes; if not we might have a text node */
if (!attributes || _isClobbered(currentNode)) {
return;
}
const hookEvent = {
attrName: '',
attrValue: '',
keepAttr: true,
allowedAttributes: ALLOWED_ATTR,
forceKeepAttr: undefined
};
let l = attributes.length;
/* Go backwards over all attributes; safely remove bad ones */
while (l--) {
const attr = attributes[l];
const {
name,
namespaceURI,
value: attrValue
} = attr;
const lcName = transformCaseFunc(name);
const initValue = attrValue;
let value = name === 'value' ? initValue : stringTrim(initValue);
/* Execute a hook if present */
hookEvent.attrName = lcName;
hookEvent.attrValue = value;
hookEvent.keepAttr = true;
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
value = hookEvent.attrValue;
/* Full DOM Clobbering protection via namespace isolation,
* Prefix id and name attributes with `user-content-`
*/
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
// Remove the attribute with this value
_removeAttribute(name, currentNode);
// Prefix the value and later re-create the attribute with the sanitized value
value = SANITIZE_NAMED_PROPS_PREFIX + value;
}
/* Work around a security issue with comments inside attributes */
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title|textarea)/i, value)) {
_removeAttribute(name, currentNode);
continue;
}
/* Make sure we cannot easily use animated hrefs, even if animations are allowed */
if (lcName === 'attributename' && stringMatch(value, 'href')) {
_removeAttribute(name, currentNode);
continue;
}
/* Did the hooks approve of the attribute? */
if (hookEvent.forceKeepAttr) {
continue;
}
/* Did the hooks approve of the attribute? */
if (!hookEvent.keepAttr) {
_removeAttribute(name, currentNode);
continue;
}
/* Work around a security issue in jQuery 3.0 */
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
_removeAttribute(name, currentNode);
continue;
}
/* Sanitize attribute content to be template-safe */
if (SAFE_FOR_TEMPLATES) {
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
value = stringReplace(value, expr, ' ');
});
}
/* Is `value` valid for this attribute? */
const lcTag = transformCaseFunc(currentNode.nodeName);
if (!_isValidAttribute(lcTag, lcName, value)) {
_removeAttribute(name, currentNode);
continue;
}
/* Handle attributes that require Trusted Types */
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
if (namespaceURI) ;else {
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
case 'TrustedHTML':
{
value = trustedTypesPolicy.createHTML(value);
break;
}
case 'TrustedScriptURL':
{
value = trustedTypesPolicy.createScriptURL(value);
break;
}
}
}
}
/* Handle invalid data-* attribute set by try-catching it */
if (value !== initValue) {
try {
if (namespaceURI) {
currentNode.setAttributeNS(namespaceURI, name, value);
} else {
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
currentNode.setAttribute(name, value);
}
if (_isClobbered(currentNode)) {
_forceRemove(currentNode);
} else {
arrayPop(DOMPurify.removed);
}
} catch (_) {
_removeAttribute(name, currentNode);
}
}
}
/* Execute a hook if present */
_executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
};
/**
* _sanitizeShadowDOM
*
* @param fragment to iterate over recursively
*/
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
let shadowNode = null;
const shadowIterator = _createNodeIterator(fragment);
/* Execute a hook if present */
_executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
while (shadowNode = shadowIterator.nextNode()) {
/* Execute a hook if present */
_executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
/* Sanitize tags and elements */
_sanitizeElements(shadowNode);
/* Check attributes next */
_sanitizeAttributes(shadowNode);
/* Deep shadow DOM detected */
if (shadowNode.content instanceof DocumentFragment) {
_sanitizeShadowDOM(shadowNode.content);
}
}
/* Execute a hook if present */
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
};
// eslint-disable-next-line complexity
DOMPurify.sanitize = function (dirty) {
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
let body = null;
let importedNode = null;
let currentNode = null;
let returnNode = null;
/* Make sure we have a string to sanitize.
DO NOT return early, as this will return the wrong type if
the user has requested a DOM object rather than a string */
IS_EMPTY_INPUT = !dirty;
if (IS_EMPTY_INPUT) {
dirty = '<!-->';
}
/* Stringify, in case dirty is an object */
if (typeof dirty !== 'string' && !_isNode(dirty)) {
if (typeof dirty.toString === 'function') {
dirty = dirty.toString();
if (typeof dirty !== 'string') {
throw typeErrorCreate('dirty is not a string, aborting');
}
} else {
throw typeErrorCreate('toString is not a function');
}
}
/* Return dirty HTML if DOMPurify cannot run */
if (!DOMPurify.isSupported) {
return dirty;
}
/* Assign config vars */
if (!SET_CONFIG) {
_parseConfig(cfg);
}
/* Clean up removed elements */
DOMPurify.removed = [];
/* Check if dirty is correctly typed for IN_PLACE */
if (typeof dirty === 'string') {
IN_PLACE = false;
}
if (IN_PLACE) {
/* Do some early pre-sanitization to avoid unsafe root nodes */
if (dirty.nodeName) {
const tagName = transformCaseFunc(dirty.nodeName);
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
}
}
} else if (dirty instanceof Node) {
/* If dirty is a DOM element, append to an empty document to avoid
elements being stripped by the parser */
body = _initDocument('<!---->');
importedNode = body.ownerDocument.importNode(dirty, true);
if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
/* Node is already a body, use as is */
body = importedNode;
} else if (importedNode.nodeName === 'HTML') {
body = importedNode;
} else {
// eslint-disable-next-line unicorn/prefer-dom-node-append
body.appendChild(importedNode);
}
} else {
/* Exit directly if we have nothing to do */
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
// eslint-disable-next-line unicorn/prefer-includes
dirty.indexOf('<') === -1) {
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
}
/* Initialize the document to work on */
body = _initDocument(dirty);
/* Check we have a DOM node from the data */
if (!body) {
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
}
}
/* Remove first element node (ours) if FORCE_BODY is set */
if (body && FORCE_BODY) {
_forceRemove(body.firstChild);
}
/* Get node iterator */
const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
/* Now start iterating over the created document */
while (currentNode = nodeIterator.nextNode()) {
/* Sanitize tags and elements */
_sanitizeElements(currentNode);
/* Check attributes next */
_sanitizeAttributes(currentNode);
/* Shadow DOM detected, sanitize it */
if (currentNode.content instanceof DocumentFragment) {
_sanitizeShadowDOM(currentNode.content);
}
}
/* If we sanitized `dirty` in-place, return it. */
if (IN_PLACE) {
return dirty;
}
/* Return sanitized string or DOM */
if (RETURN_DOM) {
if (RETURN_DOM_FRAGMENT) {
returnNode = createDocumentFragment.call(body.ownerDocument);
while (body.firstChild) {
// eslint-disable-next-line unicorn/prefer-dom-node-append
returnNode.appendChild(body.firstChild);
}
} else {
returnNode = body;
}
if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
/*
AdoptNode() is not used because internal state is not reset
(e.g. the past names map of a HTMLFormElement), this is safe
in theory but we would rather not risk another attack vector.
The state that is cloned by importNode() is explicitly defined
by the specs.
*/
returnNode = importNode.call(originalDocument, returnNode, true);
}
return returnNode;
}
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
/* Serialize doctype if allowed */
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
}
/* Sanitize final string template-safe */
if (SAFE_FOR_TEMPLATES) {
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
serializedHTML = stringReplace(serializedHTML, expr, ' ');
});
}
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
};
DOMPurify.setConfig = function () {
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_parseConfig(cfg);
SET_CONFIG = true;
};
DOMPurify.clearConfig = function () {
CONFIG = null;
SET_CONFIG = false;
};
DOMPurify.isValidAttribute = function (tag, attr, value) {
/* Initialize shared config vars if necessary. */
if (!CONFIG) {
_parseConfig({});
}
const lcTag = transformCaseFunc(tag);
const lcName = transformCaseFunc(attr);
return _isValidAttribute(lcTag, lcName, value);
};
DOMPurify.addHook = function (entryPoint, hookFunction) {
if (typeof hookFunction !== 'function') {
return;
}
arrayPush(hooks[entryPoint], hookFunction);
};
DOMPurify.removeHook = function (entryPoint, hookFunction) {
if (hookFunction !== undefined) {
const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
}
return arrayPop(hooks[entryPoint]);
};
DOMPurify.removeHooks = function (entryPoint) {
hooks[entryPoint] = [];
};
DOMPurify.removeAllHooks = function () {
hooks = _createHooksMap();
};
return DOMPurify;
}
var purify = createDOMPurify();
purify.addHook("uponSanitizeAttribute", function (node, data) {
if (data.attrName === "data-trix-serialized-attributes") {
data.keepAttr = false;
return;
}
const allowedAttributePattern = /^data-trix-/;
if (allowedAttributePattern.test(data.attrName)) {
data.forceKeepAttr = true;
}
});
const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height language class".split(" ");
const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ");
const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form noscript".split(" ");
class HTMLSanitizer extends BasicObject {
static setHTML(element, html, options) {
const sanitizedElement = new this(html, options).sanitize();
const sanitizedHtml = sanitizedElement.getHTML ? sanitizedElement.getHTML() : sanitizedElement.outerHTML;
element.innerHTML = sanitizedHtml;
}
static sanitize(html, options) {
const sanitizer = new this(html, options);
sanitizer.sanitize();
return sanitizer;
}
constructor(html) {
let {
allowedAttributes,
forbiddenProtocols,
forbiddenElements,
purifyOptions
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
super(...arguments);
this.allowedAttributes = allowedAttributes || DEFAULT_ALLOWED_ATTRIBUTES;
this.forbiddenProtocols = forbiddenProtocols || DEFAULT_FORBIDDEN_PROTOCOLS;
this.forbiddenElements = forbiddenElements || DEFAULT_FORBIDDEN_ELEMENTS;
this.purifyOptions = purifyOptions || {};
this.body = createBodyElementForHTML(html);
}
sanitize() {
this.sanitizeElements();
this.normalizeListElementNesting();
const purifyConfig = Object.assign({}, dompurify, this.purifyOptions);
purify.setConfig(purifyConfig);
this.body = purify.sanitize(this.body);
return this.body;
}
getHTML() {
return this.body.innerHTML;
}
getBody() {
return this.body;
}
// Private
sanitizeElements() {
const walker = walkTree(this.body);
const nodesToRemove = [];
while (walker.nextNode()) {
const node = walker.currentNode;
switch (node.nodeType) {
case Node.ELEMENT_NODE:
if (this.elementIsRemovable(node)) {
nodesToRemove.push(node);
} else {
this.sanitizeElement(node);
}
break;
case Node.COMMENT_NODE:
nodesToRemove.push(node);
break;
}
}
nodesToRemove.forEach(node => removeNode(node));
return this.body;
}
sanitizeElement(element) {
if (element.hasAttribute("href")) {
if (this.forbiddenProtocols.includes(element.protocol)) {
element.removeAttribute("href");
}
}
Array.from(element.attributes).forEach(_ref => {
let {
name
} = _ref;
if (!this.allowedAttributes.includes(name) && name.indexOf("data-trix") !== 0) {
element.removeAttribute(name);
}
});
return element;
}
normalizeListElementNesting() {
Array.from(this.body.querySelectorAll("ul,ol")).forEach(listElement => {
const previousElement = listElement.previousElementSibling;
if (previousElement) {
if (tagName(previousElement) === "li") {
previousElement.appendChild(listElement);
}
}
});
return this.body;
}
elementIsRemovable(element) {
if ((element === null || element === void 0 ? void 0 : element.nodeType) !== Node.ELEMENT_NODE) return;
return this.elementIsForbidden(element) || this.elementIsntSerializable(element);
}
elementIsForbidden(element) {
return this.forbiddenElements.includes(tagName(element));
}
elementIsntSerializable(element) {
return element.getAttribute("data-trix-serialize") === "false" && !nodeIsAttachmentElement(element);
}
}
const createBodyElementForHTML = function () {
let html = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
// Remove everything after </html>
html = html.replace(/<\/html[^>]*>[^]*$/i, "</html>");
const doc = document.implementation.createHTMLDocument("");
doc.documentElement.innerHTML = html;
Array.from(doc.head.querySelectorAll("style")).forEach(element => {
doc.body.appendChild(element);
});
return doc.body;
};
const {
css: css$2
} = config;
class AttachmentView extends ObjectView {
constructor() {
super(...arguments);
this.attachment = this.object;
this.attachment.uploadProgressDelegate = this;
this.attachmentPiece = this.options.piece;
}
createContentNodes() {
return [];
}
createNodes() {
let innerElement;
const figure = innerElement = makeElement({
tagName: "figure",
className: this.getClassName(),
data: this.getData(),
editable: false
});
const href = this.getHref();
if (href) {
innerElement = makeElement({
tagName: "a",
editable: false,
attributes: {
href,
tabindex: -1
}
});
figure.appendChild(innerElement);
}
if (this.attachment.hasContent()) {
HTMLSanitizer.setHTML(innerElement, this.attachment.getContent());
} else {
this.createContentNodes().forEach(node => {
innerElement.appendChild(node);
});
}
innerElement.appendChild(this.createCaptionElement());
if (this.attachment.isPending()) {
this.progressElement = makeElement({
tagName: "progress",
attributes: {
class: css$2.attachmentProgress,
value: this.attachment.getUploadProgress(),
max: 100
},
data: {
trixMutable: true,
trixStoreKey: ["progressElement", this.attachment.id].join("/")
}
});
figure.appendChild(this.progressElement);
}
return [createCursorTarget("left"), figure, createCursorTarget("right")];
}
createCaptionElement() {
const figcaption = makeElement({
tagName: "figcaption",
className: css$2.attachmentCaption
});
const caption = this.attachmentPiece.getCaption();
if (caption) {
figcaption.classList.add("".concat(css$2.attachmentCaption, "--edited"));
figcaption.textContent = caption;
} else {
let name, size;
const captionConfig = this.getCaptionConfig();
if (captionConfig.name) {
name = this.attachment.getFilename();
}
if (captionConfig.size) {
size = this.attachment.getFormattedFilesize();
}
if (name) {
const nameElement = makeElement({
tagName: "span",
className: css$2.attachmentName,
textContent: name
});
figcaption.appendChild(nameElement);
}
if (size) {
if (name) {
figcaption.appendChild(document.createTextNode(" "));
}
const sizeElement = makeElement({
tagName: "span",
className: css$2.attachmentSize,
textContent: size
});
figcaption.appendChild(sizeElement);
}
}
return figcaption;
}
getClassName() {
const names = [css$2.attachment, "".concat(css$2.attachment, "--").concat(this.attachment.getType())];
const extension = this.attachment.getExtension();
if (extension) {
names.push("".concat(css$2.attachment, "--").concat(extension));
}
return names.join(" ");
}
getData() {
const data = {
trixAttachment: JSON.stringify(this.attachment),
trixContentType: this.attachment.getContentType(),
trixId: this.attachment.id
};
const {
attributes
} = this.attachmentPiece;
if (!attributes.isEmpty()) {
data.trixAttributes = JSON.stringify(attributes);
}
if (this.attachment.isPending()) {
data.trixSerialize = false;
}
return data;
}
getHref() {
if (!htmlContainsTagName(this.attachment.getContent(), "a")) {
const href = this.attachment.getHref();
if (href && purify.isValidAttribute("a", "href", href)) {
return href;
}
}
}
getCaptionConfig() {
var _config$attachments$t;
const type = this.attachment.getType();
const captionConfig = copyObject((_config$attachments$t = attachments[type]) === null || _config$attachments$t === void 0 ? void 0 : _config$attachments$t.caption);
if (type === "file") {
captionConfig.name = true;
}
return captionConfig;
}
findProgressElement() {
var _this$findElement;
return (_this$findElement = this.findElement()) === null || _this$findElement === void 0 ? void 0 : _this$findElement.querySelector("progress");
}
// Attachment delegate
attachmentDidChangeUploadProgress() {
const value = this.attachment.getUploadProgress();
const progressElement = this.findProgressElement();
if (progressElement) {
progressElement.value = value;
}
}
}
const createCursorTarget = name => makeElement({
tagName: "span",
textContent: ZERO_WIDTH_SPACE,
data: {
trixCursorTarget: name,
trixSerialize: false
}
});
const htmlContainsTagName = function (html, tagName) {
const div = makeElement("div");
HTMLSanitizer.setHTML(div, html || "");
return div.querySelector(tagName);
};
class PreviewableAttachmentView extends AttachmentView {
constructor() {
super(...arguments);
this.attachment.previewDelegate = this;
}
createContentNodes() {
this.image = makeElement({
tagName: "img",
attributes: {
src: ""
},
data: {
trixMutable: true
}
});
this.refresh(this.image);
return [this.image];
}
createCaptionElement() {
const figcaption = super.createCaptionElement(...arguments);
if (!figcaption.textContent) {
figcaption.setAttribute("data-trix-placeholder", lang$1.captionPlaceholder);
}
return figcaption;
}
refresh(image) {
if (!image) {
var _this$findElement;
image = (_this$findElement = this.findElement()) === null || _this$findElement === void 0 ? void 0 : _this$findElement.querySelector("img");
}
if (image) {
return this.updateAttributesForImage(image);
}
}
updateAttributesForImage(image) {
const url = this.attachment.getURL();
const previewURL = this.attachment.getPreviewURL();
image.src = previewURL || url;
if (previewURL === url) {
image.removeAttribute("data-trix-serialized-attributes");
} else {
const serializedAttributes = JSON.stringify({
src: url
});
image.setAttribute("data-trix-serialized-attributes", serializedAttributes);
}
const width = this.attachment.getWidth();
const height = this.attachment.getHeight();
const alt = this.attachment.getAttribute("alt");
if (width != null) {
image.width = width;
}
if (height != null) {
image.height = height;
}
if (alt != null) {
image.alt = alt;
}
const storeKey = ["imageElement", this.attachment.id, image.src, image.width, image.height].join("/");
image.dataset.trixStoreKey = storeKey;
}
// Attachment delegate
attachmentDidChangeAttributes() {
this.refresh(this.image);
return this.refresh();
}
}
/* eslint-disable
no-useless-escape,
no-var,
*/
class PieceView extends ObjectView {
constructor() {
super(...arguments);
this.piece = this.object;
this.attributes = this.piece.getAttributes();
this.textConfig = this.options.textConfig;
this.context = this.options.context;
if (this.piece.attachment) {
this.attachment = this.piece.attachment;
} else {
this.string = this.piece.toString();
}
}
createNodes() {
let nodes = this.attachment ? this.createAttachmentNodes() : this.createStringNodes();
const element = this.createElement();
if (element) {
const innerElement = findInnerElement(element);
Array.from(nodes).forEach(node => {
innerElement.appendChild(node);
});
nodes = [element];
}
return nodes;
}
createAttachmentNodes() {
const constructor = this.attachment.isPreviewable() ? PreviewableAttachmentView : AttachmentView;
const view = this.createChildView(constructor, this.piece.attachment, {
piece: this.piece
});
return view.getNodes();
}
createStringNodes() {
var _this$textConfig;
if ((_this$textConfig = this.textConfig) !== null && _this$textConfig !== void 0 && _this$textConfig.plaintext) {
return [document.createTextNode(this.string)];
} else {
const nodes = [];
const iterable = this.string.split("\n");
for (let index = 0; index < iterable.length; index++) {
const substring = iterable[index];
if (index > 0) {
const element = makeElement("br");
nodes.push(element);
}
if (substring.length) {
const node = document.createTextNode(this.preserveSpaces(substring));
nodes.push(node);
}
}
return nodes;
}
}
createElement() {
let element, key, value;
const styles = {};
for (key in this.attributes) {
value = this.attributes[key];
const config = getTextConfig(key);
if (config) {
if (config.tagName) {
var innerElement;
const pendingElement = makeElement(config.tagName);
if (innerElement) {
innerElement.appendChild(pendingElement);
innerElement = pendingElement;
} else {
element = innerElement = pendingElement;
}
}
if (config.styleProperty) {
styles[config.styleProperty] = value;
}
if (config.style) {
for (key in config.style) {
value = config.style[key];
styles[key] = value;
}
}
}
}
if (Object.keys(styles).length) {
if (!element) {
element = makeElement("span");
}
for (key in styles) {
value = styles[key];
element.style[key] = value;
}
}
return element;
}
createContainerElement() {
for (const key in this.attributes) {
const value = this.attributes[key];
const config = getTextConfig(key);
if (config) {
if (config.groupTagName) {
const attributes = {};
attributes[key] = value;
return makeElement(config.groupTagName, attributes);
}
}
}
}
preserveSpaces(string) {
if (this.context.isLast) {
string = string.replace(/\ $/, NON_BREAKING_SPACE);
}
string = string.replace(/(\S)\ {3}(\S)/g, "$1 ".concat(NON_BREAKING_SPACE, " $2")).replace(/\ {2}/g, "".concat(NON_BREAKING_SPACE, " ")).replace(/\ {2}/g, " ".concat(NON_BREAKING_SPACE));
if (this.context.isFirst || this.context.followsWhitespace) {
string = string.replace(/^\ /, NON_BREAKING_SPACE);
}
return string;
}
}
/* eslint-disable
no-var,
*/
class TextView extends ObjectView {
constructor() {
super(...arguments);
this.text = this.object;
this.textConfig = this.options.textConfig;
}
createNodes() {
const nodes = [];
const pieces = ObjectGroup.groupObjects(this.getPieces());
const lastIndex = pieces.length - 1;
for (let index = 0; index < pieces.length; index++) {
const piece = pieces[index];
const context = {};
if (index === 0) {
context.isFirst = true;
}
if (index === lastIndex) {
context.isLast = true;
}
if (endsWithWhitespace(previousPiece)) {
context.followsWhitespace = true;
}
const view = this.findOrCreateCachedChildView(PieceView, piece, {
textConfig: this.textConfig,
context
});
nodes.push(...Array.from(view.getNodes() || []));
var previousPiece = piece;
}
return nodes;
}
getPieces() {
return Array.from(this.text.getPieces()).filter(piece => !piece.hasAttribute("blockBreak"));
}
}
const endsWithWhitespace = piece => /\s$/.test(piece === null || piece === void 0 ? void 0 : piece.toString());
const {
css: css$1
} = config;
class BlockView extends ObjectView {
constructor() {
super(...arguments);
this.block = this.object;
this.attributes = this.block.getAttributes();
}
createNodes() {
const comment = document.createComment("block");
const nodes = [comment];
if (this.block.isEmpty()) {
nodes.push(makeElement("br"));
} else {
var _getBlockConfig;
const textConfig = (_getBlockConfig = getBlockConfig(this.block.getLastAttribute())) === null || _getBlockConfig === void 0 ? void 0 : _getBlockConfig.text;
const textView = this.findOrCreateCachedChildView(TextView, this.block.text, {
textConfig
});
nodes.push(...Array.from(textView.getNodes() || []));
if (this.shouldAddExtraNewlineElement()) {
nodes.push(makeElement("br"));
}
}
if (this.attributes.length) {
return nodes;
} else {
let attributes$1;
const {
tagName
} = attributes.default;
if (this.block.isRTL()) {
attributes$1 = {
dir: "rtl"
};
}
const element = makeElement({
tagName,
attributes: attributes$1
});
nodes.forEach(node => element.appendChild(node));
return [element];
}
}
createContainerElement(depth) {
const attributes = {};
let className;
const attributeName = this.attributes[depth];
const {
tagName,
htmlAttributes = []
} = getBlockConfig(attributeName);
if (depth === 0 && this.block.isRTL()) {
Object.assign(attributes, {
dir: "rtl"
});
}
if (attributeName === "attachmentGallery") {
const size = this.block.getBlockBreakPosition();
className = "".concat(css$1.attachmentGallery, " ").concat(css$1.attachmentGallery, "--").concat(size);
}
Object.entries(this.block.htmlAttributes).forEach(_ref => {
let [name, value] = _ref;
if (htmlAttributes.includes(name)) {
attributes[name] = value;
}
});
return makeElement({
tagName,
className,
attributes
});
}
// A single <br> at the end of a block element has no visual representation
// so add an extra one.
shouldAddExtraNewlineElement() {
return /\n\n$/.test(this.block.toString());
}
}
class DocumentView extends ObjectView {
static render(document) {
const element = makeElement("div");
const view = new this(document, {
element
});
view.render();
view.sync();
return element;
}
constructor() {
super(...arguments);
this.element = this.options.element;
this.elementStore = new ElementStore();
this.setDocument(this.object);
}
setDocument(document) {
if (!document.isEqualTo(this.document)) {
this.document = this.object = document;
}
}
render() {
this.childViews = [];
this.shadowElement = makeElement("div");
if (!this.document.isEmpty()) {
const objects = ObjectGroup.groupObjects(this.document.getBlocks(), {
asTree: true
});
Array.from(objects).forEach(object => {
const view = this.findOrCreateCachedChildView(BlockView, object);
Array.from(view.getNodes()).map(node => this.shadowElement.appendChild(node));
});
}
}
isSynced() {
return elementsHaveEqualHTML(this.shadowElement, this.element);
}
sync() {
const render = (element, documentFragment) => {
while (element.lastChild) {
element.removeChild(element.lastChild);
}
element.appendChild(documentFragment);
};
const event = createEvent("trix-before-render", {
cancelable: false,
attributes: {
render
}
});
this.element.dispatchEvent(event);
const fragment = this.createDocumentFragmentForSync();
event.render(this.element, fragment);
return this.didSync();
}
// Private
didSync() {
this.elementStore.reset(findStoredElements(this.element));
return defer(() => this.garbageCollectCachedViews());
}
createDocumentFragmentForSync() {
const fragment = document.createDocumentFragment();
Array.from(this.shadowElement.childNodes).forEach(node => {
fragment.appendChild(node.cloneNode(true));
});
Array.from(findStoredElements(fragment)).forEach(element => {
const storedElement = this.elementStore.remove(element);
if (storedElement) {
element.parentNode.replaceChild(storedElement, element);
}
});
return fragment;
}
}
const findStoredElements = element => element.querySelectorAll("[data-trix-store-key]");
const elementsHaveEqualHTML = (element, otherElement) => ignoreSpaces(element.innerHTML) === ignoreSpaces(otherElement.innerHTML);
const ignoreSpaces = html => html.replace(/ /g, " ");
function _AsyncGenerator(e) {
var r, t;
function resume(r, t) {
try {
var n = e[r](t),
o = n.value,
u = o instanceof _OverloadYield;
Promise.resolve(u ? o.v : o).then(function (t) {
if (u) {
var i = "return" === r ? "return" : "next";
if (!o.k || t.done) return resume(i, t);
t = e[i](t).value;
}
settle(n.done ? "return" : "normal", t);
}, function (e) {
resume("throw", e);
});
} catch (e) {
settle("throw", e);
}
}
function settle(e, n) {
switch (e) {
case "return":
r.resolve({
value: n,
done: !0
});
break;
case "throw":
r.reject(n);
break;
default:
r.resolve({
value: n,
done: !1
});
}
(r = r.next) ? resume(r.key, r.arg) : t = null;
}
this._invoke = function (e, n) {
return new Promise(function (o, u) {
var i = {
key: e,
arg: n,
resolve: o,
reject: u,
next: null
};
t ? t = t.next = i : (r = t = i, resume(e, n));
});
}, "function" != typeof e.return && (this.return = void 0);
}
_AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function () {
return this;
}, _AsyncGenerator.prototype.next = function (e) {
return this._invoke("next", e);
}, _AsyncGenerator.prototype.throw = function (e) {
return this._invoke("throw", e);
}, _AsyncGenerator.prototype.return = function (e) {
return this._invoke("return", e);
};
function _OverloadYield(t, e) {
this.v = t, this.k = e;
}
function old_createMetadataMethodsForProperty(e, t, a, r) {
return {
getMetadata: function (o) {
old_assertNotFinished(r, "getMetadata"), old_assertMetadataKey(o);
var i = e[o];
if (void 0 !== i) if (1 === t) {
var n = i.public;
if (void 0 !== n) return n[a];
} else if (2 === t) {
var l = i.private;
if (void 0 !== l) return l.get(a);
} else if (Object.hasOwnProperty.call(i, "constructor")) return i.constructor;
},
setMetadata: function (o, i) {
old_assertNotFinished(r, "setMetadata"), old_assertMetadataKey(o);
var n = e[o];
if (void 0 === n && (n = e[o] = {}), 1 === t) {
var l = n.public;
void 0 === l && (l = n.public = {}), l[a] = i;
} else if (2 === t) {
var s = n.priv;
void 0 === s && (s = n.private = new Map()), s.set(a, i);
} else n.constructor = i;
}
};
}
function old_convertMetadataMapToFinal(e, t) {
var a = e[Symbol.metadata || Symbol.for("Symbol.metadata")],
r = Object.getOwnPropertySymbols(t);
if (0 !== r.length) {
for (var o = 0; o < r.length; o++) {
var i = r[o],
n = t[i],
l = a ? a[i] : null,
s = n.public,
c = l ? l.public : null;
s && c && Object.setPrototypeOf(s, c);
var d = n.private;
if (d) {
var u = Array.from(d.values()),
f = l ? l.private : null;
f && (u = u.concat(f)), n.private = u;
}
l && Object.setPrototypeOf(n, l);
}
a && Object.setPrototypeOf(t, a), e[Symbol.metadata || Symbol.for("Symbol.metadata")] = t;
}
}
function old_createAddInitializerMethod(e, t) {
return function (a) {
old_assertNotFinished(t, "addInitializer"), old_assertCallable(a, "An initializer"), e.push(a);
};
}
function old_memberDec(e, t, a, r, o, i, n, l, s) {
var c;
switch (i) {
case 1:
c = "accessor";
break;
case 2:
c = "method";
break;
case 3:
c = "getter";
break;
case 4:
c = "setter";
break;
default:
c = "field";
}
var d,
u,
f = {
kind: c,
name: l ? "#" + t : _toPropertyKey(t),
isStatic: n,
isPrivate: l
},
p = {
v: !1
};
if (0 !== i && (f.addInitializer = old_createAddInitializerMethod(o, p)), l) {
d = 2, u = Symbol(t);
var v = {};
0 === i ? (v.get = a.get, v.set = a.set) : 2 === i ? v.get = function () {
return a.value;
} : (1 !== i && 3 !== i || (v.get = function () {
return a.get.call(this);
}), 1 !== i && 4 !== i || (v.set = function (e) {
a.set.call(this, e);
})), f.access = v;
} else d = 1, u = t;
try {
return e(s, Object.assign(f, old_createMetadataMethodsForProperty(r, d, u, p)));
} finally {
p.v = !0;
}
}
function old_assertNotFinished(e, t) {
if (e.v) throw new Error("attempted to call " + t + " after decoration was finished");
}
function old_assertMetadataKey(e) {
if ("symbol" != typeof e) throw new TypeError("Metadata keys must be symbols, received: " + e);
}
function old_assertCallable(e, t) {
if ("function" != typeof e) throw new TypeError(t + " must be a function");
}
function old_assertValidReturnValue(e, t) {
var a = typeof t;
if (1 === e) {
if ("object" !== a || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
void 0 !== t.get && old_assertCallable(t.get, "accessor.get"), void 0 !== t.set && old_assertCallable(t.set, "accessor.set"), void 0 !== t.init && old_assertCallable(t.init, "accessor.init"), void 0 !== t.initializer && old_assertCallable(t.initializer, "accessor.initializer");
} else if ("function" !== a) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
}
function old_getInit(e) {
var t;
return null == (t = e.init) && (t = e.initializer) && "undefined" != typeof console && console.warn(".initializer has been renamed
gitextract_zvcmyhvl/ ├── .eslintrc ├── .github/ │ ├── ISSUE_TEMPLATE.md │ ├── stale.yml │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .node-version ├── .npmignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── action_text-trix/ │ ├── .gitignore │ ├── Gemfile │ ├── LICENSE │ ├── README.md │ ├── Rakefile │ ├── action_text-trix.gemspec │ ├── app/ │ │ └── assets/ │ │ ├── javascripts/ │ │ │ ├── .gitattributes │ │ │ └── trix.js │ │ └── stylesheets/ │ │ └── trix.css │ ├── bin/ │ │ └── rails │ ├── lib/ │ │ └── action_text/ │ │ ├── trix/ │ │ │ ├── engine.rb │ │ │ └── version.rb │ │ └── trix.rb │ └── test/ │ ├── application_system_test_case.rb │ ├── dummy/ │ │ ├── Rakefile │ │ ├── app/ │ │ │ ├── assets/ │ │ │ │ ├── images/ │ │ │ │ │ └── .keep │ │ │ │ └── stylesheets/ │ │ │ │ ├── actiontext.css │ │ │ │ └── application.css │ │ │ ├── controllers/ │ │ │ │ ├── application_controller.rb │ │ │ │ ├── concerns/ │ │ │ │ │ └── .keep │ │ │ │ └── messages_controller.rb │ │ │ ├── javascript/ │ │ │ │ └── application.js │ │ │ ├── models/ │ │ │ │ ├── application_record.rb │ │ │ │ ├── concerns/ │ │ │ │ │ └── .keep │ │ │ │ └── message.rb │ │ │ └── views/ │ │ │ ├── active_storage/ │ │ │ │ └── blobs/ │ │ │ │ └── _blob.html.erb │ │ │ ├── layouts/ │ │ │ │ ├── action_text/ │ │ │ │ │ └── contents/ │ │ │ │ │ └── _content.html.erb │ │ │ │ ├── application.html.erb │ │ │ │ ├── mailer.html.erb │ │ │ │ └── mailer.text.erb │ │ │ ├── messages/ │ │ │ │ ├── _form.html.erb │ │ │ │ ├── index.html.erb │ │ │ │ └── new.html.erb │ │ │ └── pwa/ │ │ │ ├── manifest.json.erb │ │ │ └── service-worker.js │ │ ├── bin/ │ │ │ ├── dev │ │ │ ├── importmap │ │ │ ├── rails │ │ │ ├── rake │ │ │ └── setup │ │ ├── config/ │ │ │ ├── application.rb │ │ │ ├── boot.rb │ │ │ ├── cable.yml │ │ │ ├── database.yml │ │ │ ├── environment.rb │ │ │ ├── environments/ │ │ │ │ ├── development.rb │ │ │ │ ├── production.rb │ │ │ │ └── test.rb │ │ │ ├── importmap.rb │ │ │ ├── initializers/ │ │ │ │ ├── assets.rb │ │ │ │ ├── content_security_policy.rb │ │ │ │ ├── filter_parameter_logging.rb │ │ │ │ └── inflections.rb │ │ │ ├── locales/ │ │ │ │ └── en.yml │ │ │ ├── puma.rb │ │ │ ├── routes.rb │ │ │ └── storage.yml │ │ ├── config.ru │ │ ├── db/ │ │ │ ├── migrate/ │ │ │ │ ├── 20250926170812_create_active_storage_tables.active_storage.rb │ │ │ │ ├── 20250926170813_create_action_text_tables.action_text.rb │ │ │ │ └── 20250926170921_create_messages.rb │ │ │ └── schema.rb │ │ └── public/ │ │ ├── 400.html │ │ ├── 404.html │ │ ├── 406-unsupported-browser.html │ │ ├── 422.html │ │ └── 500.html │ ├── fixtures/ │ │ └── action_text/ │ │ └── rich_texts.yml │ ├── system/ │ │ └── action_text_test.rb │ └── test_helper.rb ├── assets/ │ ├── index.html │ ├── test.html │ ├── trix/ │ │ ├── images/ │ │ │ └── README.md │ │ └── stylesheets/ │ │ ├── attachments.scss │ │ ├── content.scss │ │ ├── editor.scss │ │ ├── icons.scss │ │ ├── media-queries.scss │ │ ├── selection.scss │ │ └── toolbar.scss │ └── trix.scss ├── babel.config.json ├── bin/ │ ├── ci │ ├── sass-build │ └── setup ├── package.json ├── rollup.config.js ├── src/ │ ├── inspector/ │ │ ├── control_element.js │ │ ├── debugger.js │ │ ├── element.js │ │ ├── global.js │ │ ├── inspector.js │ │ ├── templates/ │ │ │ ├── debug.js │ │ │ ├── document.js │ │ │ ├── performance.js │ │ │ ├── render.js │ │ │ ├── selection.js │ │ │ └── undo.js │ │ ├── templates.js │ │ ├── view.js │ │ ├── views/ │ │ │ ├── debug_view.js │ │ │ ├── document_view.js │ │ │ ├── performance_view.js │ │ │ ├── render_view.js │ │ │ ├── selection_view.js │ │ │ └── undo_view.js │ │ ├── watchdog/ │ │ │ ├── deserializer.js │ │ │ ├── player.js │ │ │ ├── player_controller.js │ │ │ ├── player_element.js │ │ │ ├── player_view.js │ │ │ ├── recorder.js │ │ │ ├── recording.js │ │ │ └── serializer.js │ │ └── watchdog.js │ ├── test/ │ │ ├── system/ │ │ │ ├── accessibility_test.js │ │ │ ├── attachment_caption_test.js │ │ │ ├── attachment_gallery_test.js │ │ │ ├── attachment_test.js │ │ │ ├── basic_input_test.js │ │ │ ├── block_formatting_test.js │ │ │ ├── caching_test.js │ │ │ ├── canceled_input_test.js │ │ │ ├── composition_input_test.js │ │ │ ├── cursor_movement_test.js │ │ │ ├── custom_element_test.js │ │ │ ├── html_loading_test.js │ │ │ ├── html_reparsing_test.js │ │ │ ├── html_replacement_test.js │ │ │ ├── installation_process_test.js │ │ │ ├── level_2_input_test.js │ │ │ ├── list_formatting_test.js │ │ │ ├── morphing_test.js │ │ │ ├── mutation_input_test.js │ │ │ ├── pasting_test.js │ │ │ ├── text_formatting_test.js │ │ │ └── undo_test.js │ │ ├── system.js │ │ ├── test.js │ │ ├── test_helper.js │ │ ├── test_helpers/ │ │ │ ├── assertions.js │ │ │ ├── editor_helpers.js │ │ │ ├── event_helpers.js │ │ │ ├── fixtures/ │ │ │ │ ├── editor_default_aria_label.js │ │ │ │ ├── editor_empty.js │ │ │ │ ├── editor_html.js │ │ │ │ ├── editor_in_table.js │ │ │ │ ├── editor_with_block_styles.js │ │ │ │ ├── editor_with_bold_styles.js │ │ │ │ ├── editor_with_image.js │ │ │ │ ├── editor_with_labels.js │ │ │ │ ├── editor_with_styled_content.js │ │ │ │ ├── editor_with_toolbar_and_input.js │ │ │ │ ├── editors_with_forms.js │ │ │ │ ├── fixtures.js │ │ │ │ └── test_image_url.js │ │ │ ├── functions.js │ │ │ ├── input_helpers.js │ │ │ ├── selection_helpers.js │ │ │ ├── test_helpers.js │ │ │ ├── test_stubs.js │ │ │ ├── timing_helpers.js │ │ │ └── toolbar_helpers.js │ │ ├── unit/ │ │ │ ├── attachment_test.js │ │ │ ├── bidi_test.js │ │ │ ├── block_test.js │ │ │ ├── composition_test.js │ │ │ ├── document_test.js │ │ │ ├── document_view_test.js │ │ │ ├── helpers/ │ │ │ │ └── custom_elements_test.js │ │ │ ├── html_parser_test.js │ │ │ ├── html_sanitizer_test.js │ │ │ ├── location_mapper_test.js │ │ │ ├── mutation_observer_test.js │ │ │ ├── serialization_test.js │ │ │ ├── string_change_summary_test.js │ │ │ └── text_test.js │ │ └── unit.js │ └── trix/ │ ├── config/ │ │ ├── attachments.js │ │ ├── block_attributes.js │ │ ├── browser.js │ │ ├── css.js │ │ ├── dompurify.js │ │ ├── file_size_formatting.js │ │ ├── index.js │ │ ├── input.js │ │ ├── key_names.js │ │ ├── lang.js │ │ ├── parser.js │ │ ├── text_attributes.js │ │ ├── toolbar.js │ │ └── undo.js │ ├── constants.js │ ├── controllers/ │ │ ├── attachment_editor_controller.js │ │ ├── composition_controller.js │ │ ├── controller.js │ │ ├── editor_controller.js │ │ ├── index.js │ │ ├── input_controller.js │ │ ├── level_0_input_controller.js │ │ ├── level_2_input_controller.js │ │ └── toolbar_controller.js │ ├── core/ │ │ ├── basic_object.js │ │ ├── collections/ │ │ │ ├── element_store.js │ │ │ ├── hash.js │ │ │ ├── index.js │ │ │ ├── object_group.js │ │ │ └── object_map.js │ │ ├── helpers/ │ │ │ ├── arrays.js │ │ │ ├── bidi.js │ │ │ ├── config.js │ │ │ ├── custom_elements.js │ │ │ ├── dom.js │ │ │ ├── events.js │ │ │ ├── extend.js │ │ │ ├── functions.js │ │ │ ├── global.js │ │ │ ├── index.js │ │ │ ├── objects.js │ │ │ ├── ranges.js │ │ │ ├── selection.js │ │ │ └── strings.js │ │ ├── index.js │ │ ├── object.js │ │ ├── serialization.js │ │ ├── utilities/ │ │ │ ├── index.js │ │ │ ├── operation.js │ │ │ └── utf16_string.js │ │ └── utilities.js │ ├── elements/ │ │ ├── index.js │ │ ├── trix_editor_element.js │ │ └── trix_toolbar_element.js │ ├── filters/ │ │ ├── attachment_gallery_filter.js │ │ ├── filter.js │ │ └── index.js │ ├── models/ │ │ ├── attachment.js │ │ ├── attachment_manager.js │ │ ├── attachment_piece.js │ │ ├── block.js │ │ ├── composition.js │ │ ├── document.js │ │ ├── editor.js │ │ ├── flaky_android_keyboard_detector.js │ │ ├── html_parser.js │ │ ├── html_sanitizer.js │ │ ├── index.js │ │ ├── line_break_insertion.js │ │ ├── location_mapper.js │ │ ├── managed_attachment.js │ │ ├── piece.js │ │ ├── point_mapper.js │ │ ├── selection_manager.js │ │ ├── splittable_list.js │ │ ├── string_piece.js │ │ ├── text.js │ │ └── undo_manager.js │ ├── observers/ │ │ ├── index.js │ │ ├── mutation_observer.js │ │ └── selection_change_observer.js │ ├── operations/ │ │ ├── file_verification_operation.js │ │ ├── image_preload_operation.js │ │ └── index.js │ ├── trix.js │ └── views/ │ ├── attachment_view.js │ ├── block_view.js │ ├── document_view.js │ ├── index.js │ ├── object_view.js │ ├── piece_view.js │ ├── previewable_attachment_view.js │ └── text_view.js └── web-test-runner.config.mjs
SYMBOL INDEX (2465 symbols across 103 files)
FILE: action_text-trix/app/assets/javascripts/trix.js
method test (line 163) | test(element) {
method test (line 176) | test(element) {
method formatter (line 265) | formatter(number) {
method getLevel (line 581) | getLevel() {
method pickFiles (line 588) | pickFiles(callback) {
method parser (line 628) | parser(element) {
method parser (line 636) | parser(element) {
method parser (line 643) | parser(element) {
method getDefaultHTML (line 663) | getDefaultHTML() {
class BasicObject (line 689) | class BasicObject {
method proxyMethod (line 690) | static proxyMethod(expression) {
class UTF16String (line 755) | class UTF16String extends BasicObject {
method box (line 756) | static box() {
method fromUCS2String (line 764) | static fromUCS2String(ucs2String) {
method fromCodepoints (line 767) | static fromCodepoints(codepoints) {
method constructor (line 770) | constructor(ucs2String, codepoints) {
method offsetToUCS2Offset (line 777) | offsetToUCS2Offset(offset) {
method offsetFromUCS2Offset (line 780) | offsetFromUCS2Offset(ucs2Offset) {
method slice (line 783) | slice() {
method charAt (line 786) | charAt(offset) {
method isEqualTo (line 789) | isEqualTo(value) {
method toJSON (line 792) | toJSON() {
method getCacheKey (line 795) | getCacheKey() {
method toString (line 798) | toString() {
class TrixObject (line 868) | class TrixObject extends BasicObject {
method fromJSONString (line 869) | static fromJSONString(jsonString) {
method constructor (line 872) | constructor() {
method hasSameConstructorAs (line 876) | hasSameConstructorAs(object) {
method isEqualTo (line 879) | isEqualTo(object) {
method inspect (line 882) | inspect() {
method contentsForInspection (line 891) | contentsForInspection() {}
method toJSONString (line 892) | toJSONString() {
method toUTF16String (line 895) | toUTF16String() {
method getCacheKey (line 898) | getCacheKey() {
function shouldRenderInmmediatelyToDealWithIOSDictation (line 1127) | function shouldRenderInmmediatelyToDealWithIOSDictation(inputEvent) {
class SelectionChangeObserver (line 1203) | class SelectionChangeObserver extends BasicObject {
method constructor (line 1204) | constructor() {
method start (line 1209) | start() {
method stop (line 1215) | stop() {
method registerSelectionManager (line 1221) | registerSelectionManager(selectionManager) {
method unregisterSelectionManager (line 1227) | unregisterSelectionManager(selectionManager) {
method notifySelectionManagersOfSelectionChange (line 1233) | notifySelectionManagersOfSelectionChange() {
method update (line 1236) | update() {
method reset (line 1239) | reset() {
class Hash (line 1336) | class Hash extends TrixObject {
method fromCommonAttributesOfObjects (line 1337) | static fromCommonAttributesOfObjects() {
method box (line 1350) | static box(values) {
method constructor (line 1353) | constructor() {
method add (line 1358) | add(key, value) {
method remove (line 1361) | remove(key) {
method get (line 1364) | get(key) {
method has (line 1367) | has(key) {
method merge (line 1370) | merge(values) {
method slice (line 1373) | slice(keys) {
method getKeys (line 1382) | getKeys() {
method getKeysCommonToHash (line 1385) | getKeysCommonToHash(hash) {
method isEqualTo (line 1389) | isEqualTo(values) {
method isEmpty (line 1392) | isEmpty() {
method toArray (line 1395) | toArray() {
method toObject (line 1406) | toObject() {
method toJSON (line 1409) | toJSON() {
method contentsForInspection (line 1412) | contentsForInspection() {
class ObjectGroup (line 1456) | class ObjectGroup {
method groupObjects (line 1457) | static groupObjects() {
method constructor (line 1499) | constructor() {
method getObjects (line 1514) | getObjects() {
method getDepth (line 1517) | getDepth() {
method getCacheKey (line 1520) | getCacheKey() {
class ObjectMap (line 1529) | class ObjectMap extends BasicObject {
method constructor (line 1530) | constructor() {
method find (line 1541) | find(object) {
class ElementStore (line 1547) | class ElementStore {
method constructor (line 1548) | constructor(elements) {
method add (line 1551) | add(element) {
method remove (line 1555) | remove(element) {
method reset (line 1563) | reset() {
class Operation (line 1574) | class Operation extends BasicObject {
method isPerforming (line 1575) | isPerforming() {
method hasPerformed (line 1578) | hasPerformed() {
method hasSucceeded (line 1581) | hasSucceeded() {
method hasFailed (line 1584) | hasFailed() {
method getPromise (line 1587) | getPromise() {
method perform (line 1605) | perform(callback) {
method release (line 1608) | release() {
class ObjectView (line 1620) | class ObjectView extends BasicObject {
method constructor (line 1621) | constructor(object) {
method getNodes (line 1629) | getNodes() {
method invalidate (line 1635) | invalidate() {
method invalidateViewForObject (line 1641) | invalidateViewForObject(object) {
method findOrCreateCachedChildView (line 1645) | findOrCreateCachedChildView(viewClass, object, options) {
method createChildView (line 1655) | createChildView(viewClass, object) {
method recordChildView (line 1664) | recordChildView(view) {
method getAllChildViews (line 1670) | getAllChildViews() {
method findElement (line 1678) | findElement() {
method findElementForObject (line 1681) | findElementForObject(object) {
method findViewForObject (line 1687) | findViewForObject(object) {
method getViewCache (line 1694) | getViewCache() {
method isViewCachingEnabled (line 1706) | isViewCachingEnabled() {
method enableViewCaching (line 1709) | enableViewCaching() {
method disableViewCaching (line 1712) | disableViewCaching() {
method getCachedViewForObject (line 1715) | getCachedViewForObject(object) {
method cacheViewForObject (line 1719) | cacheViewForObject(view, object) {
method garbageCollectCachedViews (line 1725) | garbageCollectCachedViews() {
class ObjectGroupView (line 1738) | class ObjectGroupView extends ObjectView {
method constructor (line 1739) | constructor() {
method getChildViews (line 1745) | getChildViews() {
method createNodes (line 1753) | createNodes() {
method createContainerElement (line 1762) | createContainerElement() {
function unapply (line 1832) | function unapply(func) {
function unconstruct (line 1849) | function unconstruct(Func) {
function addToSet (line 1865) | function addToSet(set, array) {
function cleanArray (line 1896) | function cleanArray(array) {
function clone (line 1911) | function clone(object) {
function lookupGetter (line 1934) | function lookupGetter(object, prop) {
method createHTML (line 2041) | createHTML(html) {
method createScriptURL (line 2044) | createScriptURL(scriptUrl) {
function createDOMPurify (line 2069) | function createDOMPurify() {
class HTMLSanitizer (line 3133) | class HTMLSanitizer extends BasicObject {
method setHTML (line 3134) | static setHTML(element, html, options) {
method sanitize (line 3139) | static sanitize(html, options) {
method constructor (line 3144) | constructor(html) {
method sanitize (line 3158) | sanitize() {
method getHTML (line 3166) | getHTML() {
method getBody (line 3169) | getBody() {
method sanitizeElements (line 3175) | sanitizeElements() {
method sanitizeElement (line 3196) | sanitizeElement(element) {
method normalizeListElementNesting (line 3212) | normalizeListElementNesting() {
method elementIsRemovable (line 3223) | elementIsRemovable(element) {
method elementIsForbidden (line 3227) | elementIsForbidden(element) {
method elementIsntSerializable (line 3230) | elementIsntSerializable(element) {
class AttachmentView (line 3249) | class AttachmentView extends ObjectView {
method constructor (line 3250) | constructor() {
method createContentNodes (line 3256) | createContentNodes() {
method createNodes (line 3259) | createNodes() {
method createCaptionElement (line 3304) | createCaptionElement() {
method getClassName (line 3344) | getClassName() {
method getData (line 3352) | getData() {
method getHref (line 3369) | getHref() {
method getCaptionConfig (line 3377) | getCaptionConfig() {
method findProgressElement (line 3386) | findProgressElement() {
method attachmentDidChangeUploadProgress (line 3393) | attachmentDidChangeUploadProgress() {
class PreviewableAttachmentView (line 3415) | class PreviewableAttachmentView extends AttachmentView {
method constructor (line 3416) | constructor() {
method createContentNodes (line 3420) | createContentNodes() {
method createCaptionElement (line 3433) | createCaptionElement() {
method refresh (line 3440) | refresh(image) {
method updateAttributesForImage (line 3449) | updateAttributesForImage(image) {
method attachmentDidChangeAttributes (line 3479) | attachmentDidChangeAttributes() {
class PieceView (line 3489) | class PieceView extends ObjectView {
method constructor (line 3490) | constructor() {
method createNodes (line 3502) | createNodes() {
method createAttachmentNodes (line 3514) | createAttachmentNodes() {
method createStringNodes (line 3521) | createStringNodes() {
method createElement (line 3542) | createElement() {
method createContainerElement (line 3581) | createContainerElement() {
method preserveSpaces (line 3594) | preserveSpaces(string) {
class TextView (line 3609) | class TextView extends ObjectView {
method constructor (line 3610) | constructor() {
method createNodes (line 3615) | createNodes() {
method getPieces (line 3640) | getPieces() {
class BlockView (line 3649) | class BlockView extends ObjectView {
method constructor (line 3650) | constructor() {
method createNodes (line 3655) | createNodes() {
method createContainerElement (line 3691) | createContainerElement(depth) {
method shouldAddExtraNewlineElement (line 3723) | shouldAddExtraNewlineElement() {
class DocumentView (line 3728) | class DocumentView extends ObjectView {
method render (line 3729) | static render(document) {
method constructor (line 3738) | constructor() {
method setDocument (line 3744) | setDocument(document) {
method render (line 3749) | render() {
method isSynced (line 3762) | isSynced() {
method sync (line 3765) | sync() {
method didSync (line 3786) | didSync() {
method createDocumentFragmentForSync (line 3790) | createDocumentFragmentForSync() {
function _AsyncGenerator (line 3808) | function _AsyncGenerator(e) {
function _OverloadYield (line 3870) | function _OverloadYield(t, e) {
function old_createMetadataMethodsForProperty (line 3873) | function old_createMetadataMethodsForProperty(e, t, a, r) {
function old_convertMetadataMapToFinal (line 3899) | function old_convertMetadataMapToFinal(e, t) {
function old_createAddInitializerMethod (line 3921) | function old_createAddInitializerMethod(e, t) {
function old_memberDec (line 3926) | function old_memberDec(e, t, a, r, o, i, n, l, s) {
function old_assertNotFinished (line 3972) | function old_assertNotFinished(e, t) {
function old_assertMetadataKey (line 3975) | function old_assertMetadataKey(e) {
function old_assertCallable (line 3978) | function old_assertCallable(e, t) {
function old_assertValidReturnValue (line 3981) | function old_assertValidReturnValue(e, t) {
function old_getInit (line 3988) | function old_getInit(e) {
function old_applyMemberDec (line 3992) | function old_applyMemberDec(e, t, a, r, o, i, n, l, s) {
function old_applyMemberDecs (line 4048) | function old_applyMemberDecs(e, t, a, r, o) {
function old_pushInitializers (line 4070) | function old_pushInitializers(e, t) {
function old_applyClassDecs (line 4076) | function old_applyClassDecs(e, t, a, r) {
function _applyDecs (line 4099) | function _applyDecs(e, t, a) {
function applyDecs2203Factory (line 4105) | function applyDecs2203Factory() {
function _applyDecs2203 (line 4284) | function _applyDecs2203(e, t, r) {
function applyDecs2203RFactory (line 4287) | function applyDecs2203RFactory() {
function _applyDecs2203R (line 4471) | function _applyDecs2203R(e, t, r) {
function applyDecs2301Factory (line 4474) | function applyDecs2301Factory() {
function _applyDecs2301 (line 4688) | function _applyDecs2301(e, t, r, n) {
function _applyDecs2305 (line 4691) | function _applyDecs2305(e, t, r, n, o, a) {
function _asyncGeneratorDelegate (line 4819) | function _asyncGeneratorDelegate(t) {
function _asyncIterator (line 4841) | function _asyncIterator(r) {
function AsyncFromSyncIterator (line 4853) | function AsyncFromSyncIterator(r) {
function _awaitAsyncGenerator (line 4885) | function _awaitAsyncGenerator(e) {
function _callSuper (line 4888) | function _callSuper(t, o, e) {
function _checkInRHS (line 4891) | function _checkInRHS(e) {
function _construct (line 4895) | function _construct(t, e, r) {
function _defineAccessor (line 4902) | function _defineAccessor(e, r, n, t) {
function dispose_SuppressedError (line 4909) | function dispose_SuppressedError(r, e) {
function _dispose (line 4920) | function _dispose(r, e, s) {
function _importDeferProxy (line 4936) | function _importDeferProxy(e) {
function _getRequireWildcardCache (line 4962) | function _getRequireWildcardCache(e) {
function _interopRequireWildcard (line 4970) | function _interopRequireWildcard(e, r) {
function _isNativeReflectConstruct (line 4987) | function _isNativeReflectConstruct() {
function _iterableToArrayLimit (line 4995) | function _iterableToArrayLimit(r, l) {
function _iterableToArrayLimitLoose (line 5022) | function _iterableToArrayLimitLoose(e, r) {
function _jsx (line 5032) | function _jsx(e, r, E, l) {
function ownKeys (line 5052) | function ownKeys(e, r) {
function _objectSpread2 (line 5062) | function _objectSpread2(e) {
function _regeneratorRuntime (line 5073) | function _regeneratorRuntime() {
function _setFunctionName (line 5375) | function _setFunctionName(e, t, n) {
function _toPrimitive (line 5385) | function _toPrimitive(t, r) {
function _toPropertyKey (line 5395) | function _toPropertyKey(t) {
function _typeof (line 5399) | function _typeof(o) {
function _using (line 5408) | function _using(o, n, e) {
function _usingCtx (line 5419) | function _usingCtx() {
function _wrapRegExp (line 5462) | function _wrapRegExp() {
function _AwaitValue (line 5509) | function _AwaitValue(value) {
function _wrapAsyncGenerator (line 5512) | function _wrapAsyncGenerator(fn) {
function asyncGeneratorStep (line 5517) | function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, ar...
function _asyncToGenerator (line 5531) | function _asyncToGenerator(fn) {
function _classCallCheck (line 5547) | function _classCallCheck(instance, Constructor) {
function _defineProperties (line 5552) | function _defineProperties(target, props) {
function _createClass (line 5561) | function _createClass(Constructor, protoProps, staticProps) {
function _defineEnumerableProperties (line 5569) | function _defineEnumerableProperties(obj, descs) {
function _defaults (line 5588) | function _defaults(obj, defaults) {
function _defineProperty (line 5599) | function _defineProperty(obj, key, value) {
function _extends (line 5613) | function _extends() {
function _objectSpread (line 5627) | function _objectSpread(target) {
function _inherits (line 5642) | function _inherits(subClass, superClass) {
function _inheritsLoose (line 5658) | function _inheritsLoose(subClass, superClass) {
function _getPrototypeOf (line 5663) | function _getPrototypeOf(o) {
function _setPrototypeOf (line 5669) | function _setPrototypeOf(o, p) {
function _isNativeFunction (line 5676) | function _isNativeFunction(fn) {
function _wrapNativeSuper (line 5683) | function _wrapNativeSuper(Class) {
function _instanceof (line 5709) | function _instanceof(left, right) {
function _interopRequireDefault (line 5716) | function _interopRequireDefault(obj) {
function _newArrowCheck (line 5721) | function _newArrowCheck(innerThis, boundThis) {
function _objectDestructuringEmpty (line 5726) | function _objectDestructuringEmpty(obj) {
function _objectWithoutPropertiesLoose (line 5729) | function _objectWithoutPropertiesLoose(source, excluded) {
function _objectWithoutProperties (line 5741) | function _objectWithoutProperties(source, excluded) {
function _assertThisInitialized (line 5756) | function _assertThisInitialized(self) {
function _possibleConstructorReturn (line 5762) | function _possibleConstructorReturn(self, call) {
function _createSuper (line 5770) | function _createSuper(Derived) {
function _superPropBase (line 5784) | function _superPropBase(object, property) {
function _get (line 5791) | function _get() {
function set (line 5807) | function set(target, property, value, receiver) {
function _set (line 5838) | function _set(target, property, value, receiver, isStrict) {
function _taggedTemplateLiteral (line 5845) | function _taggedTemplateLiteral(strings, raw) {
function _taggedTemplateLiteralLoose (line 5855) | function _taggedTemplateLiteralLoose(strings, raw) {
function _readOnlyError (line 5862) | function _readOnlyError(name) {
function _writeOnlyError (line 5865) | function _writeOnlyError(name) {
function _classNameTDZError (line 5868) | function _classNameTDZError(name) {
function _temporalUndefined (line 5871) | function _temporalUndefined() {}
function _tdz (line 5872) | function _tdz(name) {
function _temporalRef (line 5875) | function _temporalRef(val, name) {
function _slicedToArray (line 5878) | function _slicedToArray(arr, i) {
function _slicedToArrayLoose (line 5881) | function _slicedToArrayLoose(arr, i) {
function _toArray (line 5884) | function _toArray(arr) {
function _toConsumableArray (line 5887) | function _toConsumableArray(arr) {
function _arrayWithoutHoles (line 5890) | function _arrayWithoutHoles(arr) {
function _arrayWithHoles (line 5893) | function _arrayWithHoles(arr) {
function _maybeArrayLike (line 5896) | function _maybeArrayLike(next, arr, i) {
function _iterableToArray (line 5903) | function _iterableToArray(iter) {
function _unsupportedIterableToArray (line 5906) | function _unsupportedIterableToArray(o, minLen) {
function _arrayLikeToArray (line 5914) | function _arrayLikeToArray(arr, len) {
function _nonIterableSpread (line 5919) | function _nonIterableSpread() {
function _nonIterableRest (line 5922) | function _nonIterableRest() {
function _createForOfIteratorHelper (line 5925) | function _createForOfIteratorHelper(o, allowArrayLike) {
function _createForOfIteratorHelperLoose (line 5976) | function _createForOfIteratorHelperLoose(o, allowArrayLike) {
function _skipFirstGeneratorNext (line 5994) | function _skipFirstGeneratorNext(fn) {
function _initializerWarningHelper (line 6001) | function _initializerWarningHelper(descriptor, context) {
function _initializerDefineProperty (line 6004) | function _initializerDefineProperty(target, property, descriptor, contex...
function _applyDecoratedDescriptor (line 6013) | function _applyDecoratedDescriptor(target, property, decorators, descrip...
function _classPrivateFieldLooseKey (line 6037) | function _classPrivateFieldLooseKey(name) {
function _classPrivateFieldLooseBase (line 6040) | function _classPrivateFieldLooseBase(receiver, privateKey) {
function _classPrivateFieldGet (line 6046) | function _classPrivateFieldGet(receiver, privateMap) {
function _classPrivateFieldSet (line 6050) | function _classPrivateFieldSet(receiver, privateMap, value) {
function _classPrivateFieldDestructureSet (line 6055) | function _classPrivateFieldDestructureSet(receiver, privateMap) {
function _classExtractFieldDescriptor (line 6059) | function _classExtractFieldDescriptor(receiver, privateMap, action) {
function _classStaticPrivateFieldSpecGet (line 6065) | function _classStaticPrivateFieldSpecGet(receiver, classConstructor, des...
function _classStaticPrivateFieldSpecSet (line 6070) | function _classStaticPrivateFieldSpecSet(receiver, classConstructor, des...
function _classStaticPrivateMethodGet (line 6076) | function _classStaticPrivateMethodGet(receiver, classConstructor, method) {
function _classStaticPrivateMethodSet (line 6080) | function _classStaticPrivateMethodSet() {
function _classApplyDescriptorGet (line 6083) | function _classApplyDescriptorGet(receiver, descriptor) {
function _classApplyDescriptorSet (line 6089) | function _classApplyDescriptorSet(receiver, descriptor, value) {
function _classApplyDescriptorDestructureSet (line 6099) | function _classApplyDescriptorDestructureSet(receiver, descriptor) {
function _classStaticPrivateFieldDestructureSet (line 6116) | function _classStaticPrivateFieldDestructureSet(receiver, classConstruct...
function _classCheckPrivateStaticAccess (line 6121) | function _classCheckPrivateStaticAccess(receiver, classConstructor) {
function _classCheckPrivateStaticFieldDescriptor (line 6126) | function _classCheckPrivateStaticFieldDescriptor(descriptor, action) {
function _decorate (line 6131) | function _decorate(decorators, factory, superClass, mixins) {
function _getDecoratorsApi (line 6145) | function _getDecoratorsApi() {
function _createElementDescriptor (line 6383) | function _createElementDescriptor(def) {
function _coalesceGetterSetter (line 6422) | function _coalesceGetterSetter(element, other) {
function _coalesceClassElements (line 6429) | function _coalesceClassElements(elements) {
function _hasDecorators (line 6458) | function _hasDecorators(element) {
function _isDataDescriptor (line 6461) | function _isDataDescriptor(desc) {
function _optionalCallableProperty (line 6464) | function _optionalCallableProperty(obj, name) {
function _classPrivateMethodGet (line 6471) | function _classPrivateMethodGet(receiver, privateSet, fn) {
function _checkPrivateRedeclaration (line 6477) | function _checkPrivateRedeclaration(obj, privateCollection) {
function _classPrivateFieldInitSpec (line 6482) | function _classPrivateFieldInitSpec(obj, privateMap, value) {
function _classPrivateMethodInitSpec (line 6486) | function _classPrivateMethodInitSpec(obj, privateSet) {
function _classPrivateMethodSet (line 6490) | function _classPrivateMethodSet() {
function _identity (line 6493) | function _identity(x) {
function _nullishReceiverError (line 6496) | function _nullishReceiverError(r) {
class Piece (line 6500) | class Piece extends TrixObject {
method registerType (line 6501) | static registerType(type, constructor) {
method fromJSON (line 6505) | static fromJSON(pieceJSON) {
method constructor (line 6511) | constructor(value) {
method copyWithAttributes (line 6516) | copyWithAttributes(attributes) {
method copyWithAdditionalAttributes (line 6519) | copyWithAdditionalAttributes(attributes) {
method copyWithoutAttribute (line 6522) | copyWithoutAttribute(attribute) {
method copy (line 6525) | copy() {
method getAttribute (line 6528) | getAttribute(attribute) {
method getAttributesHash (line 6531) | getAttributesHash() {
method getAttributes (line 6534) | getAttributes() {
method hasAttribute (line 6537) | hasAttribute(attribute) {
method hasSameStringValueAsPiece (line 6540) | hasSameStringValueAsPiece(piece) {
method hasSameAttributesAsPiece (line 6543) | hasSameAttributesAsPiece(piece) {
method isBlockBreak (line 6546) | isBlockBreak() {
method isEqualTo (line 6549) | isEqualTo(piece) {
method isEmpty (line 6552) | isEmpty() {
method isSerializable (line 6555) | isSerializable() {
method toJSON (line 6558) | toJSON() {
method contentsForInspection (line 6564) | contentsForInspection() {
method canBeGrouped (line 6573) | canBeGrouped() {
method canBeGroupedWith (line 6576) | canBeGroupedWith(piece) {
method getLength (line 6582) | getLength() {
method canBeConsolidatedWith (line 6585) | canBeConsolidatedWith(piece) {
class ImagePreloadOperation (line 6591) | class ImagePreloadOperation extends Operation {
method constructor (line 6592) | constructor(url) {
method perform (line 6596) | perform(callback) {
class Attachment (line 6608) | class Attachment extends TrixObject {
method attachmentForFile (line 6609) | static attachmentForFile(file) {
method attributesForFile (line 6615) | static attributesForFile(file) {
method fromJSON (line 6622) | static fromJSON(attachmentJSON) {
method constructor (line 6625) | constructor() {
method setAttribute (line 6632) | setAttribute(attribute, value) {
method getAttribute (line 6637) | getAttribute(attribute) {
method hasAttribute (line 6640) | hasAttribute(attribute) {
method getAttributes (line 6643) | getAttributes() {
method setAttributes (line 6646) | setAttributes() {
method didChangeAttributes (line 6657) | didChangeAttributes() {
method isPending (line 6662) | isPending() {
method isPreviewable (line 6665) | isPreviewable() {
method getType (line 6672) | getType() {
method getURL (line 6681) | getURL() {
method getHref (line 6684) | getHref() {
method getFilename (line 6687) | getFilename() {
method getFilesize (line 6690) | getFilesize() {
method getFormattedFilesize (line 6693) | getFormattedFilesize() {
method getExtension (line 6701) | getExtension() {
method getContentType (line 6705) | getContentType() {
method hasContent (line 6708) | hasContent() {
method getContent (line 6711) | getContent() {
method getWidth (line 6714) | getWidth() {
method getHeight (line 6717) | getHeight() {
method getFile (line 6720) | getFile() {
method setFile (line 6723) | setFile(file) {
method releaseFile (line 6729) | releaseFile() {
method getUploadProgress (line 6733) | getUploadProgress() {
method setUploadProgress (line 6736) | setUploadProgress(value) {
method toJSON (line 6743) | toJSON() {
method getCacheKey (line 6746) | getCacheKey() {
method getPreviewURL (line 6752) | getPreviewURL() {
method setPreviewURL (line 6755) | setPreviewURL(url) {
method preloadURL (line 6763) | preloadURL() {
method preloadFile (line 6766) | preloadFile() {
method releasePreloadedFile (line 6772) | releasePreloadedFile() {
method preload (line 6778) | preload(url, callback) {
class AttachmentPiece (line 6805) | class AttachmentPiece extends Piece {
method fromJSON (line 6806) | static fromJSON(pieceJSON) {
method constructor (line 6809) | constructor(attachment) {
method ensureAttachmentExclusivelyHasAttribute (line 6818) | ensureAttachmentExclusivelyHasAttribute(attribute) {
method removeProhibitedAttributes (line 6826) | removeProhibitedAttributes() {
method getValue (line 6832) | getValue() {
method isSerializable (line 6835) | isSerializable() {
method getCaption (line 6838) | getCaption() {
method isEqualTo (line 6841) | isEqualTo(piece) {
method toString (line 6845) | toString() {
method toJSON (line 6848) | toJSON() {
method getCacheKey (line 6853) | getCacheKey() {
method toConsole (line 6856) | toConsole() {
class StringPiece (line 6863) | class StringPiece extends Piece {
method fromJSON (line 6864) | static fromJSON(pieceJSON) {
method constructor (line 6867) | constructor(string) {
method getValue (line 6872) | getValue() {
method toString (line 6875) | toString() {
method isBlockBreak (line 6878) | isBlockBreak() {
method toJSON (line 6881) | toJSON() {
method canBeConsolidatedWith (line 6889) | canBeConsolidatedWith(piece) {
method consolidateWith (line 6892) | consolidateWith(piece) {
method splitAtOffset (line 6895) | splitAtOffset(offset) {
method toConsole (line 6909) | toConsole() {
class SplittableList (line 6924) | class SplittableList extends TrixObject {
method box (line 6925) | static box(objects) {
method constructor (line 6932) | constructor() {
method indexOf (line 6938) | indexOf(object) {
method splice (line 6941) | splice() {
method eachObject (line 6947) | eachObject(callback) {
method insertObjectAtIndex (line 6950) | insertObjectAtIndex(object, index) {
method insertSplittableListAtIndex (line 6953) | insertSplittableListAtIndex(splittableList, index) {
method insertSplittableListAtPosition (line 6956) | insertSplittableListAtPosition(splittableList, position) {
method editObjectAtIndex (line 6960) | editObjectAtIndex(index, callback) {
method replaceObjectAtIndex (line 6963) | replaceObjectAtIndex(object, index) {
method removeObjectAtIndex (line 6966) | removeObjectAtIndex(index) {
method getObjectAtIndex (line 6969) | getObjectAtIndex(index) {
method getSplittableListInRange (line 6972) | getSplittableListInRange(range) {
method selectSplittableList (line 6976) | selectSplittableList(test) {
method removeObjectsInRange (line 6980) | removeObjectsInRange(range) {
method transformObjectsInRange (line 6984) | transformObjectsInRange(range, transform) {
method splitObjectsAtRange (line 6989) | splitObjectsAtRange(range) {
method getObjectAtPosition (line 6995) | getObjectAtPosition(position) {
method splitObjectAtPosition (line 7001) | splitObjectAtPosition(position) {
method consolidate (line 7025) | consolidate() {
method consolidateFromIndexToIndex (line 7042) | consolidateFromIndexToIndex(startIndex, endIndex) {
method findIndexAndOffsetAtPosition (line 7048) | findIndexAndOffsetAtPosition(position) {
method findPositionAtIndexAndOffset (line 7067) | findPositionAtIndexAndOffset(index, offset) {
method getEndPosition (line 7080) | getEndPosition() {
method toString (line 7087) | toString() {
method toArray (line 7090) | toArray() {
method toJSON (line 7093) | toJSON() {
method isEqualTo (line 7096) | isEqualTo(splittableList) {
method contentsForInspection (line 7099) | contentsForInspection() {
class Text (line 7122) | class Text extends TrixObject {
method textForAttachmentWithAttributes (line 7123) | static textForAttachmentWithAttributes(attachment, attributes) {
method textForStringWithAttributes (line 7127) | static textForStringWithAttributes(string, attributes) {
method fromJSON (line 7131) | static fromJSON(textJSON) {
method constructor (line 7135) | constructor() {
method copy (line 7141) | copy() {
method copyWithPieceList (line 7144) | copyWithPieceList(pieceList) {
method copyUsingObjectMap (line 7147) | copyUsingObjectMap(objectMap) {
method appendText (line 7151) | appendText(text) {
method insertTextAtPosition (line 7154) | insertTextAtPosition(text, position) {
method removeTextAtRange (line 7157) | removeTextAtRange(range) {
method replaceTextAtRange (line 7160) | replaceTextAtRange(text, range) {
method moveTextFromRangeToPosition (line 7163) | moveTextFromRangeToPosition(range, position) {
method addAttributeAtRange (line 7172) | addAttributeAtRange(attribute, value, range) {
method addAttributesAtRange (line 7177) | addAttributesAtRange(attributes, range) {
method removeAttributeAtRange (line 7180) | removeAttributeAtRange(attribute, range) {
method setAttributesAtRange (line 7183) | setAttributesAtRange(attributes, range) {
method getAttributesAtPosition (line 7186) | getAttributesAtPosition(position) {
method getCommonAttributes (line 7190) | getCommonAttributes() {
method getCommonAttributesAtRange (line 7194) | getCommonAttributesAtRange(range) {
method getExpandedRangeForAttributeAtOffset (line 7197) | getExpandedRangeForAttributeAtOffset(attributeName, offset) {
method getTextAtRange (line 7209) | getTextAtRange(range) {
method getStringAtRange (line 7212) | getStringAtRange(range) {
method getStringAtPosition (line 7215) | getStringAtPosition(position) {
method startsWithString (line 7218) | startsWithString(string) {
method endsWithString (line 7221) | endsWithString(string) {
method getAttachmentPieces (line 7225) | getAttachmentPieces() {
method getAttachments (line 7228) | getAttachments() {
method getAttachmentAndPositionById (line 7231) | getAttachmentAndPositionById(attachmentId) {
method getAttachmentById (line 7248) | getAttachmentById(attachmentId) {
method getRangeOfAttachment (line 7254) | getRangeOfAttachment(attachment) {
method updateAttributesForAttachment (line 7262) | updateAttributesForAttachment(attributes, attachment) {
method getLength (line 7270) | getLength() {
method isEmpty (line 7273) | isEmpty() {
method isEqualTo (line 7276) | isEqualTo(text) {
method isBlockBreak (line 7280) | isBlockBreak() {
method eachPiece (line 7283) | eachPiece(callback) {
method getPieces (line 7286) | getPieces() {
method getPieceAtPosition (line 7289) | getPieceAtPosition(position) {
method contentsForInspection (line 7292) | contentsForInspection() {
method toSerializableText (line 7297) | toSerializableText() {
method toString (line 7301) | toString() {
method toJSON (line 7304) | toJSON() {
method toConsole (line 7307) | toConsole() {
method getDirection (line 7313) | getDirection() {
method isRTL (line 7316) | isRTL() {
class Block (line 7321) | class Block extends TrixObject {
method fromJSON (line 7322) | static fromJSON(blockJSON) {
method constructor (line 7326) | constructor(text, attributes, htmlAttributes) {
method isEmpty (line 7332) | isEmpty() {
method isEqualTo (line 7335) | isEqualTo(block) {
method copyWithText (line 7339) | copyWithText(text) {
method copyWithoutText (line 7342) | copyWithoutText() {
method copyWithAttributes (line 7345) | copyWithAttributes(attributes) {
method copyWithoutAttributes (line 7348) | copyWithoutAttributes() {
method copyUsingObjectMap (line 7351) | copyUsingObjectMap(objectMap) {
method addAttribute (line 7359) | addAttribute(attribute) {
method addHTMLAttribute (line 7363) | addHTMLAttribute(attribute, value) {
method removeAttribute (line 7369) | removeAttribute(attribute) {
method removeLastAttribute (line 7376) | removeLastAttribute() {
method getLastAttribute (line 7379) | getLastAttribute() {
method getAttributes (line 7382) | getAttributes() {
method getAttributeLevel (line 7385) | getAttributeLevel() {
method getAttributeAtLevel (line 7388) | getAttributeAtLevel(level) {
method hasAttribute (line 7391) | hasAttribute(attributeName) {
method hasAttributes (line 7394) | hasAttributes() {
method getLastNestableAttribute (line 7397) | getLastNestableAttribute() {
method getNestableAttributes (line 7400) | getNestableAttributes() {
method getNestingLevel (line 7403) | getNestingLevel() {
method decreaseNestingLevel (line 7406) | decreaseNestingLevel() {
method increaseNestingLevel (line 7414) | increaseNestingLevel() {
method getListItemAttributes (line 7424) | getListItemAttributes() {
method isListItem (line 7427) | isListItem() {
method isTerminalBlock (line 7431) | isTerminalBlock() {
method breaksOnReturn (line 7435) | breaksOnReturn() {
method findLineBreakInDirectionFromPosition (line 7439) | findLineBreakInDirectionFromPosition(direction, position) {
method contentsForInspection (line 7453) | contentsForInspection() {
method toString (line 7459) | toString() {
method toJSON (line 7462) | toJSON() {
method getDirection (line 7472) | getDirection() {
method isRTL (line 7475) | isRTL() {
method getLength (line 7481) | getLength() {
method canBeConsolidatedWith (line 7484) | canBeConsolidatedWith(block) {
method consolidateWith (line 7487) | consolidateWith(block) {
method splitAtOffset (line 7492) | splitAtOffset(offset) {
method getBlockBreakPosition (line 7506) | getBlockBreakPosition() {
method getTextWithoutBlockBreak (line 7509) | getTextWithoutBlockBreak() {
method canBeGrouped (line 7519) | canBeGrouped(depth) {
method canBeGroupedWith (line 7522) | canBeGroupedWith(otherBlock, depth) {
class Document (line 7602) | class Document extends TrixObject {
method fromJSON (line 7603) | static fromJSON(documentJSON) {
method fromString (line 7607) | static fromString(string, textAttributes) {
method constructor (line 7611) | constructor() {
method isEmpty (line 7619) | isEmpty() {
method copy (line 7623) | copy() {
method copyUsingObjectsFromDocument (line 7628) | copyUsingObjectsFromDocument(sourceDocument) {
method copyUsingObjectMap (line 7632) | copyUsingObjectMap(objectMap) {
method copyWithBaseBlockAttributes (line 7639) | copyWithBaseBlockAttributes() {
method replaceBlock (line 7647) | replaceBlock(oldBlock, newBlock) {
method insertDocumentAtRange (line 7654) | insertDocumentAtRange(document, range) {
method mergeDocumentAtRange (line 7674) | mergeDocumentAtRange(document, range) {
method insertTextAtRange (line 7705) | insertTextAtRange(text, range) {
method removeTextAtRange (line 7715) | removeTextAtRange(range) {
method moveTextFromRangeToPosition (line 7749) | moveTextFromRangeToPosition(range, position) {
method addAttributeAtRange (line 7779) | addAttributeAtRange(attribute, value, range) {
method addAttribute (line 7796) | addAttribute(attribute, value) {
method removeAttributeAtRange (line 7803) | removeAttributeAtRange(attribute, range) {
method updateAttributesForAttachment (line 7816) | updateAttributesForAttachment(attributes, attachment) {
method removeAttributeForAttachment (line 7825) | removeAttributeForAttachment(attribute, attachment) {
method setHTMLAttributeAtPosition (line 7829) | setHTMLAttributeAtPosition(position, name, value) {
method insertBlockBreakAtRange (line 7834) | insertBlockBreakAtRange(range) {
method applyBlockAttributeAtRange (line 7847) | applyBlockAttributeAtRange(attributeName, value, range) {
method removeLastListAttributeAtRange (line 7868) | removeLastListAttributeAtRange(range) {
method removeLastTerminalAttributeAtRange (line 7888) | removeLastTerminalAttributeAtRange(range) {
method removeBlockAttributesAtRange (line 7904) | removeBlockAttributesAtRange(range) {
method expandRangeToLineBreaksAndSplitBlocks (line 7915) | expandRangeToLineBreaksAndSplitBlocks(range) {
method convertLineBreaksToBlockBreaksInRange (line 7955) | convertLineBreaksToBlockBreaksInRange(range) {
method consolidateBlocksAtRange (line 7969) | consolidateBlocksAtRange(range) {
method getDocumentAtRange (line 7976) | getDocumentAtRange(range) {
method getStringAtRange (line 7981) | getStringAtRange(range) {
method getBlockAtIndex (line 7990) | getBlockAtIndex(index) {
method getBlockAtPosition (line 7993) | getBlockAtPosition(position) {
method getTextAtIndex (line 7999) | getTextAtIndex(index) {
method getTextAtPosition (line 8003) | getTextAtPosition(position) {
method getPieceAtPosition (line 8009) | getPieceAtPosition(position) {
method getCharacterAtPosition (line 8016) | getCharacterAtPosition(position) {
method getLength (line 8023) | getLength() {
method getBlocks (line 8026) | getBlocks() {
method getBlockCount (line 8029) | getBlockCount() {
method getEditCount (line 8032) | getEditCount() {
method eachBlock (line 8035) | eachBlock(callback) {
method eachBlockAtRange (line 8038) | eachBlockAtRange(range, callback) {
method getCommonAttributesAtRange (line 8067) | getCommonAttributesAtRange(range) {
method getCommonAttributesAtPosition (line 8084) | getCommonAttributesAtPosition(position) {
method getRangeOfCommonAttributeAtPosition (line 8108) | getRangeOfCommonAttributeAtPosition(attributeName, position) {
method getBaseBlockAttributes (line 8125) | getBaseBlockAttributes() {
method getAttachmentById (line 8143) | getAttachmentById(attachmentId) {
method getAttachmentPieces (line 8150) | getAttachmentPieces() {
method getAttachments (line 8160) | getAttachments() {
method getRangeOfAttachment (line 8163) | getRangeOfAttachment(attachment) {
method getLocationRangeOfAttachment (line 8177) | getLocationRangeOfAttachment(attachment) {
method getAttachmentPieceForAttachment (line 8181) | getAttachmentPieceForAttachment(attachment) {
method findRangesForBlockAttribute (line 8188) | findRangesForBlockAttribute(attributeName) {
method findRangesForTextAttribute (line 8200) | findRangesForTextAttribute(attributeName) {
method locationFromPosition (line 8227) | locationFromPosition(position) {
method positionFromLocation (line 8239) | positionFromLocation(location) {
method locationRangeFromPosition (line 8242) | locationRangeFromPosition(position) {
method locationRangeFromRange (line 8245) | locationRangeFromRange(range) {
method rangeFromLocationRange (line 8253) | rangeFromLocationRange(locationRange) {
method isEqualTo (line 8262) | isEqualTo(document) {
method getTexts (line 8265) | getTexts() {
method getPieces (line 8268) | getPieces() {
method getObjects (line 8275) | getObjects() {
method toSerializableDocument (line 8278) | toSerializableDocument() {
method toString (line 8283) | toString() {
method toJSON (line 8286) | toJSON() {
method toConsole (line 8289) | toConsole() {
class HTMLParser (line 8354) | class HTMLParser extends BasicObject {
method parse (line 8355) | static parse(html, options) {
method constructor (line 8360) | constructor(html) {
method getDocument (line 8373) | getDocument() {
method parse (line 8379) | parse() {
method createHiddenContainer (line 8396) | createHiddenContainer() {
method removeHiddenContainer (line 8413) | removeHiddenContainer() {
method processNode (line 8416) | processNode(node) {
method appendBlockForTextNode (line 8429) | appendBlockForTextNode(node) {
method appendBlockForElement (line 8443) | appendBlockForElement(element) {
method findParentBlockElement (line 8469) | findParentBlockElement(element) {
method processTextNode (line 8482) | processTextNode(node) {
method processElement (line 8493) | processElement(element) {
method appendBlockForAttributesWithElement (line 8539) | appendBlockForAttributesWithElement(attributes, element) {
method appendEmptyBlock (line 8546) | appendEmptyBlock() {
method appendStringWithAttributes (line 8549) | appendStringWithAttributes(string, attributes) {
method appendAttachmentWithAttributes (line 8552) | appendAttachmentWithAttributes(attachment, attributes) {
method appendPiece (line 8555) | appendPiece(piece) {
method appendStringToTextAtIndex (line 8561) | appendStringToTextAtIndex(string, index) {
method prependStringToTextAtIndex (line 8572) | prependStringToTextAtIndex(string, index) {
method getTextAttributes (line 8586) | getTextAttributes(element) {
method getBlockAttributes (line 8626) | getBlockAttributes(element) {
method getBlockHTMLAttributes (line 8647) | getBlockHTMLAttributes(element) {
method findBlockElementAncestors (line 8658) | findBlockElementAncestors(element) {
method isBlockElement (line 8672) | isBlockElement(element) {
method isInsignificantTextNode (line 8681) | isInsignificantTextNode(node) {
method isExtraBR (line 8693) | isExtraBR(element) {
method needsTableSeparator (line 8696) | needsTableSeparator(element) {
method translateBlockElementMarginsToNewlines (line 8708) | translateBlockElementMarginsToNewlines() {
method getMarginOfBlockElementAtIndex (line 8722) | getMarginOfBlockElementAtIndex(index) {
method getMarginOfDefaultBlockElement (line 8732) | getMarginOfDefaultBlockElement() {
class ManagedAttachment (line 8856) | class ManagedAttachment extends BasicObject {
method constructor (line 8857) | constructor(attachmentManager, attachment) {
method remove (line 8864) | remove() {
class AttachmentManager (line 8890) | class AttachmentManager extends BasicObject {
method constructor (line 8891) | constructor() {
method getAttachments (line 8899) | getAttachments() {
method manageAttachment (line 8907) | manageAttachment(attachment) {
method attachmentIsManaged (line 8913) | attachmentIsManaged(attachment) {
method requestRemovalOfAttachment (line 8916) | requestRemovalOfAttachment(attachment) {
method unmanageAttachment (line 8922) | unmanageAttachment(attachment) {
class LineBreakInsertion (line 8929) | class LineBreakInsertion {
method constructor (line 8930) | constructor(composition) {
method shouldInsertBlockBreak (line 8943) | shouldInsertBlockBreak() {
method shouldBreakFormattedBlock (line 8950) | shouldBreakFormattedBlock() {
method shouldDecreaseListLevel (line 8953) | shouldDecreaseListLevel() {
method shouldPrependListItem (line 8956) | shouldPrependListItem() {
method shouldRemoveLastBlockAttribute (line 8959) | shouldRemoveLastBlockAttribute() {
class Composition (line 8965) | class Composition extends BasicObject {
method constructor (line 8966) | constructor() {
method setDocument (line 8973) | setDocument(document) {
method getSnapshot (line 8985) | getSnapshot() {
method loadSnapshot (line 8991) | loadSnapshot(_ref) {
method insertText (line 9005) | insertText(text) {
method insertBlock (line 9020) | insertBlock() {
method insertDocument (line 9025) | insertDocument() {
method insertString (line 9034) | insertString(string, options) {
method insertBlockBreak (line 9039) | insertBlockBreak() {
method insertLineBreak (line 9047) | insertLineBreak() {
method insertHTML (line 9065) | insertHTML(html) {
method replaceHTML (line 9078) | replaceHTML(html) {
method insertFile (line 9087) | insertFile(file) {
method insertFiles (line 9090) | insertFiles(files) {
method insertAttachment (line 9101) | insertAttachment(attachment) {
method insertAttachments (line 9104) | insertAttachments(attachments$1) {
method shouldManageDeletingInDirection (line 9119) | shouldManageDeletingInDirection(direction) {
method deleteInDirection (line 9135) | deleteInDirection(direction) {
method moveTextFromRange (line 9181) | moveTextFromRange(range) {
method removeAttachment (line 9186) | removeAttachment(attachment) {
method removeLastBlockAttribute (line 9194) | removeLastBlockAttribute() {
method insertPlaceholder (line 9200) | insertPlaceholder() {
method selectPlaceholder (line 9204) | selectPlaceholder() {
method forgetPlaceholder (line 9210) | forgetPlaceholder() {
method hasCurrentAttribute (line 9216) | hasCurrentAttribute(attributeName) {
method toggleCurrentAttribute (line 9220) | toggleCurrentAttribute(attributeName) {
method canSetCurrentAttribute (line 9228) | canSetCurrentAttribute(attributeName) {
method canSetCurrentTextAttribute (line 9235) | canSetCurrentTextAttribute(attributeName) {
method canSetCurrentBlockAttribute (line 9245) | canSetCurrentBlockAttribute(attributeName) {
method setCurrentAttribute (line 9250) | setCurrentAttribute(attributeName, value) {
method setHTMLAtributeAtPosition (line 9259) | setHTMLAtributeAtPosition(position, attributeName, value) {
method setTextAttribute (line 9268) | setTextAttribute(attributeName, value) {
method setBlockAttribute (line 9283) | setBlockAttribute(attributeName, value) {
method removeCurrentAttribute (line 9290) | removeCurrentAttribute(attributeName) {
method removeTextAttribute (line 9300) | removeTextAttribute(attributeName) {
method removeBlockAttribute (line 9305) | removeBlockAttribute(attributeName) {
method canDecreaseNestingLevel (line 9310) | canDecreaseNestingLevel() {
method canIncreaseNestingLevel (line 9314) | canIncreaseNestingLevel() {
method decreaseNestingLevel (line 9327) | decreaseNestingLevel() {
method increaseNestingLevel (line 9332) | increaseNestingLevel() {
method canDecreaseBlockAttributeLevel (line 9337) | canDecreaseBlockAttributeLevel() {
method decreaseBlockAttributeLevel (line 9341) | decreaseBlockAttributeLevel() {
method decreaseListLevel (line 9348) | decreaseListLevel() {
method updateCurrentAttributes (line 9373) | updateCurrentAttributes() {
method getCurrentAttributes (line 9392) | getCurrentAttributes() {
method getCurrentTextAttributes (line 9395) | getCurrentTextAttributes() {
method freezeSelection (line 9410) | freezeSelection() {
method thawSelection (line 9413) | thawSelection() {
method hasFrozenSelection (line 9416) | hasFrozenSelection() {
method setSelection (line 9419) | setSelection(selectedRange) {
method getSelectedRange (line 9424) | getSelectedRange() {
method setSelectedRange (line 9430) | setSelectedRange(selectedRange) {
method getPosition (line 9434) | getPosition() {
method getLocationRange (line 9440) | getLocationRange(options) {
method withTargetLocationRange (line 9450) | withTargetLocationRange(locationRange, fn) {
method withTargetRange (line 9460) | withTargetRange(range, fn) {
method withTargetDOMRange (line 9464) | withTargetDOMRange(domRange, fn) {
method getExpandedRangeInDirection (line 9470) | getExpandedRangeInDirection(direction) {
method shouldManageMovingCursorInDirection (line 9490) | shouldManageMovingCursorInDirection(direction) {
method moveCursorInDirection (line 9497) | moveCursorInDirection(direction) {
method expandSelectionInDirection (line 9518) | expandSelectionInDirection(direction) {
method expandSelectionForEditing (line 9527) | expandSelectionForEditing() {
method expandSelectionAroundCommonAttribute (line 9532) | expandSelectionAroundCommonAttribute(attributeName) {
method selectionContainsAttachments (line 9537) | selectionContainsAttachments() {
method selectionIsInCursorTarget (line 9541) | selectionIsInCursorTarget() {
method positionIsCursorTarget (line 9544) | positionIsCursorTarget(position) {
method positionIsBlockBreak (line 9550) | positionIsBlockBreak(position) {
method getSelectedDocument (line 9554) | getSelectedDocument() {
method getSelectedAttachments (line 9560) | getSelectedAttachments() {
method getAttachments (line 9567) | getAttachments() {
method refreshAttachments (line 9570) | refreshAttachments() {
method attachmentDidChangeAttributes (line 9595) | attachmentDidChangeAttributes(attachment) {
method attachmentDidChangePreviewURL (line 9600) | attachmentDidChangePreviewURL(attachment) {
method editAttachment (line 9608) | editAttachment(attachment, options) {
method stopEditingAttachment (line 9615) | stopEditingAttachment() {
method updateAttributesForAttachment (line 9621) | updateAttributesForAttachment(attributes, attachment) {
method removeAttributeForAttachment (line 9624) | removeAttributeForAttachment(attribute, attachment) {
method breakFormattedBlock (line 9630) | breakFormattedBlock(insertion) {
method getPreviousBlock (line 9660) | getPreviousBlock() {
method getBlock (line 9671) | getBlock() {
method getAttachmentAtRange (line 9677) | getAttachmentAtRange(range) {
method notifyDelegateOfCurrentAttributesChange (line 9683) | notifyDelegateOfCurrentAttributesChange() {
method notifyDelegateOfInsertionAtRange (line 9687) | notifyDelegateOfInsertionAtRange(range) {
method translateUTF16PositionFromOffset (line 9691) | translateUTF16PositionFromOffset(position, offset) {
class UndoManager (line 9704) | class UndoManager extends BasicObject {
method constructor (line 9705) | constructor(composition) {
method recordUndoEntry (line 9711) | recordUndoEntry(description) {
method undo (line 9726) | undo() {
method redo (line 9734) | redo() {
method canUndo (line 9742) | canUndo() {
method canRedo (line 9745) | canRedo() {
method createEntry (line 9751) | createEntry() {
class Filter (line 9768) | class Filter {
method constructor (line 9769) | constructor(snapshot) {
method perform (line 9773) | perform() {
method getSnapshot (line 9777) | getSnapshot() {
method removeBlockAttribute (line 9786) | removeBlockAttribute() {
method applyBlockAttribute (line 9789) | applyBlockAttribute() {
method findRangesOfBlocks (line 9817) | findRangesOfBlocks() {
method findRangesOfPieces (line 9820) | findRangesOfPieces() {
method moveSelectedRangeForward (line 9825) | moveSelectedRangeForward() {
class Editor (line 9838) | class Editor {
method constructor (line 9839) | constructor(composition, selectionManager, element) {
method loadDocument (line 9847) | loadDocument(document) {
method loadHTML (line 9853) | loadHTML() {
method loadJSON (line 9860) | loadJSON(_ref) {
method loadSnapshot (line 9871) | loadSnapshot(snapshot) {
method getDocument (line 9875) | getDocument() {
method getSelectedDocument (line 9878) | getSelectedDocument() {
method getSnapshot (line 9881) | getSnapshot() {
method toJSON (line 9884) | toJSON() {
method deleteInDirection (line 9890) | deleteInDirection(direction) {
method insertAttachment (line 9893) | insertAttachment(attachment) {
method insertAttachments (line 9896) | insertAttachments(attachments) {
method insertDocument (line 9899) | insertDocument(document) {
method insertFile (line 9902) | insertFile(file) {
method insertFiles (line 9905) | insertFiles(files) {
method insertHTML (line 9908) | insertHTML(html) {
method insertString (line 9911) | insertString(string) {
method insertText (line 9914) | insertText(text) {
method insertLineBreak (line 9917) | insertLineBreak() {
method getSelectedRange (line 9923) | getSelectedRange() {
method getPosition (line 9926) | getPosition() {
method getClientRectAtPosition (line 9929) | getClientRectAtPosition(position) {
method expandSelectionInDirection (line 9933) | expandSelectionInDirection(direction) {
method moveCursorInDirection (line 9936) | moveCursorInDirection(direction) {
method setSelectedRange (line 9939) | setSelectedRange(selectedRange) {
method activateAttribute (line 9945) | activateAttribute(name) {
method attributeIsActive (line 9949) | attributeIsActive(name) {
method canActivateAttribute (line 9952) | canActivateAttribute(name) {
method deactivateAttribute (line 9955) | deactivateAttribute(name) {
method setHTMLAtributeAtPosition (line 9960) | setHTMLAtributeAtPosition(position, name, value) {
method canDecreaseNestingLevel (line 9966) | canDecreaseNestingLevel() {
method canIncreaseNestingLevel (line 9969) | canIncreaseNestingLevel() {
method decreaseNestingLevel (line 9972) | decreaseNestingLevel() {
method increaseNestingLevel (line 9977) | increaseNestingLevel() {
method canRedo (line 9985) | canRedo() {
method canUndo (line 9988) | canUndo() {
method recordUndoEntry (line 9991) | recordUndoEntry(description) {
method redo (line 10001) | redo() {
method undo (line 10006) | undo() {
class LocationMapper (line 10017) | class LocationMapper {
method constructor (line 10018) | constructor(element) {
method findLocationFromContainerAndOffset (line 10021) | findLocationFromContainerAndOffset(container, offset) {
method findContainerAndOffsetFromLocation (line 10082) | findContainerAndOffsetFromLocation(location) {
method findNodeAndOffsetFromLocation (line 10131) | findNodeAndOffsetFromLocation(location) {
method findAttachmentElementParentForNode (line 10158) | findAttachmentElementParentForNode(node) {
method getSignificantNodesForIndex (line 10166) | getSignificantNodesForIndex(index) {
class PointMapper (line 10233) | class PointMapper {
method createDOMRangeFromPoint (line 10234) | createDOMRangeFromPoint(_ref) {
method getClientRectsForDOMRange (line 10264) | getClientRectsForDOMRange(domRange) {
class SelectionManager (line 10274) | class SelectionManager extends BasicObject {
method constructor (line 10275) | constructor(element) {
method getLocationRange (line 10288) | getLocationRange() {
method setLocationRange (line 10300) | setLocationRange(locationRange) {
method setLocationRangeFromPointRange (line 10309) | setLocationRangeFromPointRange(pointRange) {
method getClientRectAtLocationRange (line 10315) | getClientRectAtLocationRange(locationRange) {
method locationIsCursorTarget (line 10321) | locationIsCursorTarget(location) {
method lock (line 10325) | lock() {
method unlock (line 10331) | unlock() {
method clearSelection (line 10342) | clearSelection() {
method selectionIsCollapsed (line 10346) | selectionIsCollapsed() {
method selectionIsExpanded (line 10350) | selectionIsExpanded() {
method createLocationRangeFromDOMRange (line 10353) | createLocationRangeFromDOMRange(domRange, options) {
method didMouseDown (line 10360) | didMouseDown() {
method pauseTemporarily (line 10363) | pauseTemporarily() {
method selectionDidChange (line 10382) | selectionDidChange() {
method updateCurrentLocationRange (line 10387) | updateCurrentLocationRange(locationRange) {
method createDOMRangeFromLocationRange (line 10396) | createDOMRangeFromLocationRange(locationRange) {
method getLocationAtPoint (line 10406) | getLocationAtPoint(point) {
method domRangeWithinElement (line 10413) | domRangeWithinElement(domRange) {
class AttachmentEditorController (line 10476) | class AttachmentEditorController extends BasicObject {
method constructor (line 10477) | constructor(attachmentPiece, _element, container) {
method install (line 10647) | install() {
method uninstall (line 10654) | uninstall() {
method savePendingCaption (line 10667) | savePendingCaption() {
method didClickToolbar (line 10684) | didClickToolbar(event) {
method didClickActionButton (line 10688) | didClickActionButton(event) {
method didKeyDownCaption (line 10696) | didKeyDownCaption(event) {
method didInputCaption (line 10704) | didInputCaption(event) {
method didChangeCaption (line 10707) | didChangeCaption(event) {
method didBlurCaption (line 10710) | didBlurCaption(event) {
class CompositionController (line 10715) | class CompositionController extends BasicObject {
method constructor (line 10716) | constructor(element, composition) {
method didFocus (line 10750) | didFocus(event) {
method didBlur (line 10761) | didBlur(event) {
method didClickAttachment (line 10774) | didClickAttachment(event, target) {
method getSerializableElement (line 10784) | getSerializableElement() {
method render (line 10791) | render() {
method rerenderViewForObject (line 10806) | rerenderViewForObject(object) {
method invalidateViewForObject (line 10810) | invalidateViewForObject(object) {
method isViewCachingEnabled (line 10813) | isViewCachingEnabled() {
method enableViewCaching (line 10816) | enableViewCaching() {
method disableViewCaching (line 10819) | disableViewCaching() {
method refreshViewCache (line 10822) | refreshViewCache() {
method isEditingAttachment (line 10828) | isEditingAttachment() {
method installAttachmentEditorForAttachment (line 10831) | installAttachmentEditorForAttachment(attachment, options) {
method uninstallAttachmentEditor (line 10841) | uninstallAttachmentEditor() {
method didUninstallAttachmentEditor (line 10848) | didUninstallAttachmentEditor() {
method attachmentEditorDidRequestUpdatingAttributesForAttachment (line 10852) | attachmentEditorDidRequestUpdatingAttributesForAttachment(attributes, ...
method attachmentEditorDidRequestRemovingAttributeForAttachment (line 10857) | attachmentEditorDidRequestRemovingAttributeForAttachment(attribute, at...
method attachmentEditorDidRequestRemovalOfAttachment (line 10862) | attachmentEditorDidRequestRemovalOfAttachment(attachment) {
method attachmentEditorDidRequestDeselectingAttachment (line 10866) | attachmentEditorDidRequestDeselectingAttachment(attachment) {
method canSyncDocumentView (line 10873) | canSyncDocumentView() {
method findAttachmentForElement (line 10876) | findAttachmentForElement(element) {
class Controller (line 10881) | class Controller extends BasicObject {}
class MutationObserver (line 10892) | class MutationObserver extends BasicObject {
method constructor (line 10893) | constructor(element) {
method start (line 10900) | start() {
method stop (line 10904) | stop() {
method didMutate (line 10907) | didMutate(mutations) {
method reset (line 10918) | reset() {
method findSignificantMutations (line 10921) | findSignificantMutations(mutations) {
method mutationIsSignificant (line 10926) | mutationIsSignificant(mutation) {
method nodeIsSignificant (line 10935) | nodeIsSignificant(node) {
method nodeIsMutable (line 10938) | nodeIsMutable(node) {
method nodesModifiedByMutation (line 10943) | nodesModifiedByMutation(mutation) {
method getMutationSummary (line 10964) | getMutationSummary() {
method getTextMutationSummary (line 10967) | getTextMutationSummary() {
method getMutationsByType (line 10990) | getMutationsByType(type) {
method getTextChangesFromChildList (line 10993) | getTextChangesFromChildList() {
method getTextChangesFromCharacterData (line 11016) | getTextChangesFromCharacterData() {
class FileVerificationOperation (line 11057) | class FileVerificationOperation extends Operation {
method constructor (line 11058) | constructor(file) {
method perform (line 11062) | perform(callback) {
class FlakyAndroidKeyboardDetector (line 11079) | class FlakyAndroidKeyboardDetector {
method constructor (line 11080) | constructor(element) {
method shouldIgnore (line 11083) | shouldIgnore(event) {
method checkSamsungKeyboardBuggyModeStart (line 11098) | checkSamsungKeyboardBuggyModeStart() {
method checkSamsungKeyboardBuggyModeEnd (line 11106) | checkSamsungKeyboardBuggyModeEnd() {
method insertingLongTextAfterUnidentifiedChar (line 11111) | insertingLongTextAfterUnidentifiedChar() {
method isBeforeInputInsertText (line 11115) | isBeforeInputInsertText() {
method previousEventWasUnidentifiedKeydown (line 11118) | previousEventWasUnidentifiedKeydown() {
class InputController (line 11129) | class InputController extends BasicObject {
method constructor (line 11130) | constructor(element) {
method elementDidMutate (line 11143) | elementDidMutate(mutationSummary) {}
method editorWillSyncDocumentView (line 11144) | editorWillSyncDocumentView() {
method editorDidSyncDocumentView (line 11147) | editorDidSyncDocumentView() {
method requestRender (line 11150) | requestRender() {
method requestReparse (line 11154) | requestReparse() {
method attachFiles (line 11159) | attachFiles(files) {
method handlerFor (line 11173) | handlerFor(eventName) {
method handleInput (line 11186) | handleInput(callback) {
method createLinkHTML (line 11196) | createLinkHTML(href, text) {
class Level0InputController (line 11211) | class Level0InputController extends InputController {
method constructor (line 11212) | constructor() {
method setInputSummary (line 11216) | setInputSummary() {
method resetInputSummary (line 11225) | resetInputSummary() {
method reset (line 11228) | reset() {
method elementDidMutate (line 11235) | elementDidMutate(mutationSummary) {
method mutationIsExpected (line 11252) | mutationIsExpected(_ref) {
method mutationIsSignificant (line 11277) | mutationIsSignificant(mutationSummary) {
method getCompositionInput (line 11286) | getCompositionInput() {
method isComposing (line 11293) | isComposing() {
method deleteInDirection (line 11296) | deleteInDirection(direction, event) {
method serializeSelectionToDataTransfer (line 11309) | serializeSelectionToDataTransfer(dataTransfer) {
method canAcceptDataTransfer (line 11318) | canAcceptDataTransfer(dataTransfer) {
method getPastedHTMLUsingHiddenElement (line 11325) | getPastedHTMLUsingHiddenElement(callback) {
method keydown (line 11349) | keydown(event) {
method keypress (line 11391) | keypress(event) {
method textInput (line 11406) | textInput(event) {
method dragenter (line 11425) | dragenter(event) {
method dragstart (line 11428) | dragstart(event) {
method dragover (line 11434) | dragover(event) {
method dragend (line 11448) | dragend(event) {
method drop (line 11454) | drop(event) {
method cut (line 11481) | cut(event) {
method copy (line 11495) | copy(event) {
method paste (line 11503) | paste(event) {
method compositionstart (line 11580) | compositionstart(event) {
method compositionupdate (line 11583) | compositionupdate(event) {
method compositionend (line 11586) | compositionend(event) {
method beforeinput (line 11589) | beforeinput(event) {
method input (line 11592) | input(event) {
method backspace (line 11598) | backspace(event) {
method delete (line 11603) | delete(event) {
method return (line 11608) | return(event) {
method tab (line 11616) | tab(event) {
method left (line 11625) | left(event) {
method right (line 11632) | right(event) {
method d (line 11640) | d(event) {
method h (line 11645) | h(event) {
method o (line 11650) | o(event) {
method return (line 11661) | return(event) {
method tab (line 11668) | tab(event) {
method left (line 11677) | left(event) {
method right (line 11683) | right(event) {
method backspace (line 11691) | backspace(event) {
method backspace (line 11700) | backspace(event) {
class CompositionInput (line 11756) | class CompositionInput extends BasicObject {
method constructor (line 11757) | constructor(inputController) {
method start (line 11765) | start(data) {
method update (line 11780) | update(data) {
method end (line 11790) | end(data) {
method getEndData (line 11812) | getEndData() {
method isEnded (line 11815) | isEnded() {
method isSignificant (line 11818) | isSignificant() {
method canApplyToDocument (line 11828) | canApplyToDocument() {
class Level2InputController (line 11841) | class Level2InputController extends InputController {
method constructor (line 11842) | constructor() {
method elementDidMutate (line 11846) | elementDidMutate() {
method scheduleRender (line 11856) | scheduleRender() {
method render (line 11859) | render() {
method reparse (line 11870) | reparse() {
method insertString (line 11877) | insertString() {
method toggleAttributeIfSupported (line 11887) | toggleAttributeIfSupported(attributeName) {
method activateAttributeIfSupported (line 11897) | activateAttributeIfSupported(attributeName, value) {
method deleteInDirection (line 11907) | deleteInDirection(direction) {
method withTargetDOMRange (line 11933) | withTargetDOMRange(domRange, fn) {
method getTargetDOMRange (line 11946) | getTargetDOMRange() {
method withEvent (line 11963) | withEvent(event, fn) {
method keydown (line 11975) | keydown(event) {
method paste (line 11998) | paste(event) {
method beforeinput (line 12034) | beforeinput(event) {
method input (line 12047) | input(event) {
method dragstart (line 12050) | dragstart(event) {
method dragenter (line 12061) | dragenter(event) {
method dragover (line 12066) | dragover(event) {
method drop (line 12079) | drop(event) {
method dragend (line 12095) | dragend() {
method compositionend (line 12102) | compositionend(event) {
method ArrowLeft (line 12110) | ArrowLeft() {
method ArrowRight (line 12118) | ArrowRight() {
method Backspace (line 12126) | Backspace() {
method Tab (line 12136) | Tab() {
method "Tab+Shift" (line 12145) | "Tab+Shift"() {
method deleteByComposition (line 12156) | deleteByComposition() {
method deleteByCut (line 12161) | deleteByCut() {
method deleteByDrag (line 12164) | deleteByDrag() {
method deleteCompositionText (line 12171) | deleteCompositionText() {
method deleteContent (line 12176) | deleteContent() {
method deleteContentBackward (line 12179) | deleteContentBackward() {
method deleteContentForward (line 12182) | deleteContentForward() {
method deleteEntireSoftLine (line 12185) | deleteEntireSoftLine() {
method deleteHardLineBackward (line 12188) | deleteHardLineBackward() {
method deleteHardLineForward (line 12191) | deleteHardLineForward() {
method deleteSoftLineBackward (line 12194) | deleteSoftLineBackward() {
method deleteSoftLineForward (line 12197) | deleteSoftLineForward() {
method deleteWordBackward (line 12200) | deleteWordBackward() {
method deleteWordForward (line 12203) | deleteWordForward() {
method formatBackColor (line 12206) | formatBackColor() {
method formatBold (line 12209) | formatBold() {
method formatFontColor (line 12212) | formatFontColor() {
method formatFontName (line 12215) | formatFontName() {
method formatIndent (line 12218) | formatIndent() {
method formatItalic (line 12227) | formatItalic() {
method formatJustifyCenter (line 12230) | formatJustifyCenter() {
method formatJustifyFull (line 12233) | formatJustifyFull() {
method formatJustifyLeft (line 12236) | formatJustifyLeft() {
method formatJustifyRight (line 12239) | formatJustifyRight() {
method formatOutdent (line 12242) | formatOutdent() {
method formatRemove (line 12251) | formatRemove() {
method formatSetBlockTextDirection (line 12259) | formatSetBlockTextDirection() {
method formatSetInlineTextDirection (line 12262) | formatSetInlineTextDirection() {
method formatStrikeThrough (line 12265) | formatStrikeThrough() {
method formatSubscript (line 12268) | formatSubscript() {
method formatSuperscript (line 12271) | formatSuperscript() {
method formatUnderline (line 12274) | formatUnderline() {
method historyRedo (line 12277) | historyRedo() {
method historyUndo (line 12281) | historyUndo() {
method insertCompositionText (line 12285) | insertCompositionText() {
method insertFromComposition (line 12289) | insertFromComposition() {
method insertFromDrop (line 12293) | insertFromDrop() {
method insertFromPaste (line 12305) | insertFromPaste() {
method insertFromYank (line 12377) | insertFromYank() {
method insertLineBreak (line 12380) | insertLineBreak() {
method insertLink (line 12383) | insertLink() {
method insertOrderedList (line 12386) | insertOrderedList() {
method insertParagraph (line 12389) | insertParagraph() {
method insertReplacementText (line 12397) | insertReplacementText() {
method insertText (line 12406) | insertText() {
method insertTranspose (line 12410) | insertTranspose() {
method insertUnorderedList (line 12413) | insertUnorderedList() {
class ToolbarController (line 12486) | class ToolbarController extends BasicObject {
method constructor (line 12487) | constructor(element) {
method didClickActionButton (line 12526) | didClickActionButton(event, element) {
method didClickAttributeButton (line 12538) | didClickAttributeButton(event, element) {
method didClickDialogButton (line 12551) | didClickDialogButton(event, element) {
method didKeyDownDialogInput (line 12558) | didKeyDownDialogInput(event, element) {
method updateActions (line 12575) | updateActions(actions) {
method refreshActionButtons (line 12579) | refreshActionButtons() {
method eachActionButton (line 12584) | eachActionButton(callback) {
method updateAttributes (line 12590) | updateAttributes(attributes) {
method refreshAttributeButtons (line 12594) | refreshAttributeButtons() {
method eachAttributeButton (line 12606) | eachAttributeButton(callback) {
method applyKeyboardCommand (line 12609) | applyKeyboardCommand(keys) {
method dialogIsVisible (line 12626) | dialogIsVisible(dialogName) {
method toggleDialog (line 12632) | toggleDialog(dialogName) {
method showDialog (line 12639) | showDialog(dialogName) {
method setAttribute (line 12659) | setAttribute(dialogElement) {
method isSafeAttribute (line 12675) | isSafeAttribute(input) {
method removeAttribute (line 12682) | removeAttribute(dialogElement) {
method hideDialog (line 12688) | hideDialog() {
method resetDialogInputs (line 12698) | resetDialogInputs() {
method getDialog (line 12705) | getDialog(dialogName) {
class EditorController (line 12711) | class EditorController extends Controller {
method constructor (line 12712) | constructor(_ref) {
method registerSelectionManager (line 12740) | registerSelectionManager() {
method unregisterSelectionManager (line 12743) | unregisterSelectionManager() {
method render (line 12746) | render() {
method reparse (line 12749) | reparse() {
method compositionDidChangeDocument (line 12755) | compositionDidChangeDocument(document) {
method compositionDidChangeCurrentAttributes (line 12761) | compositionDidChangeCurrentAttributes(currentAttributes) {
method compositionDidPerformInsertionAtRange (line 12769) | compositionDidPerformInsertionAtRange(range) {
method compositionShouldAcceptFile (line 12774) | compositionShouldAcceptFile(file) {
method compositionDidAddAttachment (line 12779) | compositionDidAddAttachment(attachment) {
method compositionDidEditAttachment (line 12785) | compositionDidEditAttachment(attachment) {
method compositionDidChangeAttachmentPreviewURL (line 12793) | compositionDidChangeAttachmentPreviewURL(attachment) {
method compositionDidRemoveAttachment (line 12797) | compositionDidRemoveAttachment(attachment) {
method compositionDidStartEditingAttachment (line 12803) | compositionDidStartEditingAttachment(attachment, options) {
method compositionDidStopEditingAttachment (line 12808) | compositionDidStopEditingAttachment(attachment) {
method compositionDidRequestChangingSelectionToLocationRange (line 12812) | compositionDidRequestChangingSelectionToLocationRange(locationRange) {
method compositionWillLoadSnapshot (line 12820) | compositionWillLoadSnapshot() {
method compositionDidLoadSnapshot (line 12823) | compositionDidLoadSnapshot() {
method getSelectionManager (line 12828) | getSelectionManager() {
method attachmentManagerDidRequestRemovalOfAttachment (line 12834) | attachmentManagerDidRequestRemovalOfAttachment(attachment) {
method compositionControllerWillSyncDocumentView (line 12840) | compositionControllerWillSyncDocumentView() {
method compositionControllerDidSyncDocumentView (line 12845) | compositionControllerDidSyncDocumentView() {
method compositionControllerDidRender (line 12851) | compositionControllerDidRender() {
method compositionControllerDidFocus (line 12866) | compositionControllerDidFocus() {
method compositionControllerDidBlur (line 12876) | compositionControllerDidBlur() {
method compositionControllerDidSelectAttachment (line 12879) | compositionControllerDidSelectAttachment(attachment, options) {
method compositionControllerDidRequestDeselectingAttachment (line 12883) | compositionControllerDidRequestDeselectingAttachment(attachment) {
method compositionControllerWillUpdateAttachment (line 12887) | compositionControllerWillUpdateAttachment(attachment) {
method compositionControllerDidRequestRemovalOfAttachment (line 12893) | compositionControllerDidRequestRemovalOfAttachment(attachment) {
method inputControllerWillHandleInput (line 12899) | inputControllerWillHandleInput() {
method inputControllerDidRequestRender (line 12903) | inputControllerDidRequestRender() {
method inputControllerDidHandleInput (line 12906) | inputControllerDidHandleInput() {
method inputControllerDidAllowUnhandledInput (line 12913) | inputControllerDidAllowUnhandledInput() {
method inputControllerDidRequestReparse (line 12916) | inputControllerDidRequestReparse() {
method inputControllerWillPerformTyping (line 12919) | inputControllerWillPerformTyping() {
method inputControllerWillPerformFormatting (line 12922) | inputControllerWillPerformFormatting(attributeName) {
method inputControllerWillCutText (line 12925) | inputControllerWillCutText() {
method inputControllerWillPaste (line 12928) | inputControllerWillPaste(paste) {
method inputControllerDidPaste (line 12935) | inputControllerDidPaste(paste) {
method inputControllerWillMoveText (line 12943) | inputControllerWillMoveText() {
method inputControllerWillAttachFiles (line 12946) | inputControllerWillAttachFiles() {
method inputControllerWillPerformUndo (line 12949) | inputControllerWillPerformUndo() {
method inputControllerWillPerformRedo (line 12952) | inputControllerWillPerformRedo() {
method inputControllerDidReceiveKeyboardCommand (line 12955) | inputControllerDidReceiveKeyboardCommand(keys) {
method inputControllerDidStartDrag (line 12958) | inputControllerDidStartDrag() {
method inputControllerDidReceiveDragOverPoint (line 12961) | inputControllerDidReceiveDragOverPoint(point) {
method inputControllerDidCancelDrag (line 12964) | inputControllerDidCancelDrag() {
method locationRangeDidChange (line 12971) | locationRangeDidChange(locationRange) {
method toolbarDidClickButton (line 12982) | toolbarDidClickButton() {
method toolbarDidInvokeAction (line 12990) | toolbarDidInvokeAction(actionName, invokingElement) {
method toolbarDidToggleAttribute (line 12993) | toolbarDidToggleAttribute(attributeName) {
method toolbarDidUpdateAttribute (line 13001) | toolbarDidUpdateAttribute(attributeName, value) {
method toolbarDidRemoveAttribute (line 13009) | toolbarDidRemoveAttribute(attributeName) {
method toolbarWillShowDialog (line 13017) | toolbarWillShowDialog(dialogElement) {
method toolbarDidShowDialog (line 13021) | toolbarDidShowDialog(dialogName) {
method toolbarDidHideDialog (line 13026) | toolbarDidHideDialog(dialogName) {
method freezeSelection (line 13036) | freezeSelection() {
method thawSelection (line 13044) | thawSelection() {
method canInvokeAction (line 13052) | canInvokeAction(actionName) {
method invokeAction (line 13060) | invokeAction(actionName, invokingElement) {
method actionIsExternal (line 13071) | actionIsExternal(actionName) {
method getCurrentActions (line 13074) | getCurrentActions() {
method updateCurrentActions (line 13081) | updateCurrentActions() {
method runEditorFilters (line 13094) | runEditorFilters() {
method updateInputElement (line 13116) | updateInputElement() {
method notifyEditorElement (line 13121) | notifyEditorElement(message, data) {
method removeAttachment (line 13141) | removeAttachment(attachment) {
method recordFormattingUndoEntry (line 13146) | recordFormattingUndoEntry(attributeName) {
method recordTypingUndoEntry (line 13156) | recordTypingUndoEntry() {
method getUndoContext (line 13162) | getUndoContext() {
method getLocationContext (line 13168) | getLocationContext() {
method getTimeContext (line 13176) | getTimeContext() {
method isFocused (line 13183) | isFocused() {
method isFocusedInvisibly (line 13190) | isFocusedInvisibly() {
method actions (line 13193) | get actions() {
method test (line 13199) | test() {
method perform (line 13202) | perform() {
method test (line 13207) | test() {
method perform (line 13210) | perform() {
method test (line 13215) | test() {
method test (line 13220) | test() {
method perform (line 13223) | perform() {
method test (line 13228) | test() {
method perform (line 13231) | perform() {
method test (line 13236) | test() {
method perform (line 13239) | perform() {
class TrixToolbarElement (line 13272) | class TrixToolbarElement extends HTMLElement {
method connectedCallback (line 13275) | connectedCallback() {
method editorElements (line 13283) | get editorElements() {
method editorElement (line 13292) | get editorElement() {
method withCallback (line 13316) | withCallback() {
class ElementInternalsDelegate (line 13396) | class ElementInternalsDelegate {
method constructor (line 13397) | constructor(element) {
method connectedCallback (line 13412) | connectedCallback() {
method disconnectedCallback (line 13415) | disconnectedCallback() {}
method form (line 13416) | get form() {
method name (line 13419) | get name() {
method name (line 13422) | set name(value) {
method labels (line 13425) | get labels() {
method disabled (line 13428) | get disabled() {
method disabled (line 13431) | set disabled(value) {
method required (line 13434) | get required() {
method required (line 13437) | set required(value) {
method validity (line 13441) | get validity() {
method validationMessage (line 13444) | get validationMessage() {
method willValidate (line 13447) | get willValidate() {
method formDisabledCallback (line 13450) | formDisabledCallback(disabled) {
method setFormValue (line 13453) | setFormValue(value) {
method checkValidity (line 13458) | checkValidity() {
method reportValidity (line 13461) | reportValidity() {
method setCustomValidity (line 13464) | setCustomValidity(validationMessage) {
function _validate2 (line 13468) | function _validate2() {
class LegacyDelegate (line 13488) | class LegacyDelegate {
method constructor (line 13489) | constructor(element) {
method connectedCallback (line 13517) | connectedCallback() {
method disconnectedCallback (line 13522) | disconnectedCallback() {
method labels (line 13528) | get labels() {
method form (line 13543) | get form() {
method name (line 13547) | get name() {
method name (line 13551) | set name(value) {
method disabled (line 13554) | get disabled() {
method disabled (line 13558) | set disabled(value) {
method required (line 13561) | get required() {
method required (line 13565) | set required(value) {
method validity (line 13568) | get validity() {
method validationMessage (line 13572) | get validationMessage() {
method willValidate (line 13576) | get willValidate() {
method formDisabledCallback (line 13580) | formDisabledCallback(value) {}
method setFormValue (line 13581) | setFormValue(value) {}
method checkValidity (line 13582) | checkValidity() {
method reportValidity (line 13586) | reportValidity() {
method setCustomValidity (line 13590) | setCustomValidity(validationMessage) {
class TrixEditorElement (line 13595) | class TrixEditorElement extends HTMLElement {
method constructor (line 13596) | constructor() {
method trixId (line 13608) | get trixId() {
method labels (line 13616) | get labels() {
method disabled (line 13619) | get disabled() {
method disabled (line 13629) | set disabled(value) {
method required (line 13638) | get required() {
method required (line 13641) | set required(value) {
method validity (line 13644) | get validity() {
method validationMessage (line 13647) | get validationMessage() {
method willValidate (line 13650) | get willValidate() {
method type (line 13653) | get type() {
method toolbarElement (line 13656) | get toolbarElement() {
method form (line 13672) | get form() {
method inputElement (line 13682) | get inputElement() {
method editor (line 13690) | get editor() {
method name (line 13694) | get name() {
method name (line 13704) | set name(value) {
method value (line 13714) | get value() {
method value (line 13724) | set value(defaultValue) {
method attributeChangedCallback (line 13732) | attributeChangedCallback(name, oldValue, newValue) {
method notify (line 13740) | notify(message, data) {
method setFormValue (line 13748) | setFormValue(value) {
method connectedCallback (line 13760) | connectedCallback() {
method disconnectedCallback (line 13792) | disconnectedCallback() {
method reconnect (line 13798) | reconnect() {
method removeInternalToolbar (line 13803) | removeInternalToolbar() {
method checkValidity (line 13811) | checkValidity() {
method reportValidity (line 13814) | reportValidity() {
method setCustomValidity (line 13817) | setCustomValidity(validationMessage) {
method formDisabledCallback (line 13820) | formDisabledCallback(disabled) {
method formResetCallback (line 13830) | formResetCallback() {
method reset (line 13833) | reset() {
function start (line 13867) | function start() {
FILE: action_text-trix/lib/action_text/trix/engine.rb
type Trix (line 1) | module Trix
class Engine (line 2) | class Engine < ::Rails::Engine
FILE: action_text-trix/lib/action_text/trix/version.rb
type Trix (line 1) | module Trix
FILE: action_text-trix/test/application_system_test_case.rb
class ApplicationSystemTestCase (line 5) | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
FILE: action_text-trix/test/dummy/app/controllers/application_controller.rb
class ApplicationController (line 1) | class ApplicationController < ActionController::Base
FILE: action_text-trix/test/dummy/app/controllers/messages_controller.rb
class MessagesController (line 1) | class MessagesController < ApplicationController
method index (line 2) | def index
method new (line 6) | def new
method create (line 10) | def create
method message_params (line 17) | def message_params
FILE: action_text-trix/test/dummy/app/models/application_record.rb
class ApplicationRecord (line 1) | class ApplicationRecord < ActiveRecord::Base
FILE: action_text-trix/test/dummy/app/models/message.rb
class Message (line 1) | class Message < ApplicationRecord
FILE: action_text-trix/test/dummy/config/application.rb
type Dummy (line 9) | module Dummy
class Application (line 10) | class Application < Rails::Application
FILE: action_text-trix/test/dummy/db/migrate/20250926170812_create_active_storage_tables.active_storage.rb
class CreateActiveStorageTables (line 2) | class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
method change (line 3) | def change
method primary_and_foreign_key_types (line 50) | def primary_and_foreign_key_types
FILE: action_text-trix/test/dummy/db/migrate/20250926170813_create_action_text_tables.action_text.rb
class CreateActionTextTables (line 2) | class CreateActionTextTables < ActiveRecord::Migration[6.0]
method change (line 3) | def change
method primary_and_foreign_key_types (line 19) | def primary_and_foreign_key_types
FILE: action_text-trix/test/dummy/db/migrate/20250926170921_create_messages.rb
class CreateMessages (line 1) | class CreateMessages < ActiveRecord::Migration[7.2]
method change (line 2) | def change
FILE: action_text-trix/test/system/action_text_test.rb
class ActionTextTest (line 5) | class ActionTextTest < ApplicationSystemTestCase
FILE: src/inspector/control_element.js
constant KEY_EVENTS (line 1) | const KEY_EVENTS = "keydown keypress input".split(" ")
constant COMPOSITION_EVENTS (line 2) | const COMPOSITION_EVENTS = "compositionstart compositionupdate compositi...
constant OBSERVER_OPTIONS (line 3) | const OBSERVER_OPTIONS = {
class ControlElement (line 11) | class ControlElement {
method constructor (line 12) | constructor(editorElement) {
method install (line 18) | install() {
method uninstall (line 24) | uninstall() {
method createElement (line 29) | createElement() {
method logInputEvents (line 38) | logInputEvents() {
method logMutations (line 50) | logMutations() {
method didMutate (line 55) | didMutate(mutations) {
FILE: src/inspector/debugger.js
constant DEBUG_METHODS (line 9) | const DEBUG_METHODS = {
method addErrorListener (line 58) | addErrorListener(listener) {
method removeErrorListener (line 64) | removeErrorListener(listener) {
FILE: src/inspector/element.js
class TrixInspector (line 65) | class TrixInspector extends HTMLElement {
method connectedCallback (line 66) | connectedCallback() {
method disconnectedCallback (line 81) | disconnectedCallback() {
method createViews (line 85) | createViews() {
method reposition (line 91) | reposition() {
FILE: src/inspector/global.js
method registerView (line 4) | registerView(constructor) {
method install (line 8) | install(editorElement) {
FILE: src/inspector/view.js
class View (line 3) | class View {
method constructor (line 4) | constructor(editorElement) {
method installEventHandlers (line 35) | installEventHandlers() {
method didToggle (line 48) | didToggle(event) {
method isOpen (line 53) | isOpen() {
method getTitle (line 57) | getTitle() {
method render (line 61) | render() {
method renderTitle (line 68) | renderTitle() {
method getSetting (line 72) | getSetting(key) {
method saveSetting (line 77) | saveSetting(key, value) {
method getSettingsKey (line 84) | getSettingsKey(key) {
method title (line 88) | get title() {
method template (line 92) | get template() {
method events (line 96) | get events() {
FILE: src/inspector/views/debug_view.js
class DebugView (line 5) | class DebugView extends View {
method constructor (line 9) | constructor() {
method didToggleViewCaching (line 38) | didToggleViewCaching({ target }) {
method didClickRenderButton (line 46) | didClickRenderButton() {
method didClickParseButton (line 50) | didClickParseButton() {
method didToggleControlElement (line 54) | didToggleControlElement({ target }) {
FILE: src/inspector/views/document_view.js
class DocumentView (line 3) | class DocumentView extends View {
method render (line 12) | render() {
FILE: src/inspector/views/performance_view.js
class PerformanceView (line 4) | class PerformanceView extends View {
method constructor (line 8) | constructor() {
method track (line 21) | track(methodPath) {
method record (line 44) | record(methodPath, timing) {
method round (line 56) | round(ms) {
FILE: src/inspector/views/render_view.js
class RenderView (line 3) | class RenderView extends View {
method constructor (line 18) | constructor() {
method getTitle (line 24) | getTitle() {
FILE: src/inspector/views/selection_view.js
class SelectionView (line 4) | class SelectionView extends View {
method render (line 16) | render() {
method getCharacters (line 24) | getCharacters() {
method getTitle (line 41) | getTitle() {
FILE: src/inspector/views/undo_view.js
class UndoView (line 3) | class UndoView extends View {
method render (line 12) | render() {
FILE: src/inspector/watchdog/deserializer.js
class Deserializer (line 1) | class Deserializer {
method constructor (line 2) | constructor(document, snapshot) {
method deserializeTree (line 11) | deserializeTree() {
method deserializeNode (line 16) | deserializeNode(serializedNode) {
method deserializeTextNode (line 34) | deserializeTextNode({ value }) {
method deserializeComment (line 38) | deserializeComment({ value }) {
method deserializeChildren (line 42) | deserializeChildren(serializedNode) {
method deserializeElement (line 47) | deserializeElement(serializedNode) {
method deserializeSelection (line 63) | deserializeSelection() {
method getElement (line 76) | getElement() {
method getRange (line 80) | getRange() {
FILE: src/inspector/watchdog/player.js
class Player (line 3) | class Player {
method constructor (line 4) | constructor(recording) {
method play (line 12) | play() {
method tick (line 22) | tick() {
method seek (line 32) | seek(index) {
method stop (line 48) | stop() {
method isPlaying (line 56) | isPlaying() {
method hasEnded (line 60) | hasEnded() {
method getSnapshot (line 64) | getSnapshot() {
method getEvents (line 68) | getEvents() {
method getTimeToNextFrame (line 72) | getTimeToNextFrame() {
FILE: src/inspector/watchdog/player_controller.js
class PlayerController (line 4) | class PlayerController {
method constructor (line 5) | constructor(element, recording) {
method play (line 18) | play() {
method stop (line 22) | stop() {
method playerViewDidClickPlayButton (line 26) | playerViewDidClickPlayButton() {
method playerViewDidChangeSliderValue (line 34) | playerViewDidChangeSliderValue(value) {
method playerDidSeekToIndex (line 38) | playerDidSeekToIndex(index) {
method playerDidStartPlaying (line 52) | playerDidStartPlaying() {
method playerDidStopPlaying (line 56) | playerDidStopPlaying() {
FILE: src/inspector/watchdog/player_element.js
class PlayerElement (line 13) | class PlayerElement extends HTMLElement {
method observedAttributes (line 14) | static get observedAttributes() { return [ "src" ] }
method connectedCallback (line 16) | connectedCallback() {
method attributeChangedCallback (line 23) | attributeChangedCallback(attributeName, oldValue, newValue) {
method fetchRecordingAtURL (line 29) | fetchRecordingAtURL(url) {
method loadRecording (line 43) | loadRecording(recording) {
FILE: src/inspector/watchdog/player_view.js
class PlayerView (line 22) | class PlayerView extends View {
method constructor (line 26) | constructor(element) {
method renderSnapshot (line 66) | renderSnapshot(snapshot) {
method renderEvents (line 77) | renderEvents(events) {
method setIndex (line 84) | setIndex(index) {
method setLength (line 89) | setLength(length) {
method playerDidStartPlaying (line 93) | playerDidStartPlaying() {
method playerDidStopPlaying (line 98) | playerDidStopPlaying() {
method frameDidLoadDefaultDocument (line 103) | frameDidLoadDefaultDocument() {
method frameDidLoadStylesheet (line 123) | frameDidLoadStylesheet() {
method frameDidLoseFocus (line 127) | frameDidLoseFocus() {
method didClickPlayButton (line 133) | didClickPlayButton() {
method didChangeSliderValue (line 137) | didChangeSliderValue() {
method renderEvent (line 142) | renderEvent(event, index) {
method deserializeSnapshot (line 163) | deserializeSnapshot(snapshot) {
method updateFrame (line 171) | updateFrame() {
FILE: src/inspector/watchdog/recorder.js
class Recorder (line 4) | class Recorder {
method constructor (line 5) | constructor(element, { snapshotLimit } = {}) {
method start (line 13) | start() {
method stop (line 22) | stop() {
method log (line 30) | log(message) {
method installMutationObserver (line 34) | installMutationObserver() {
method uninstallMutationObserver (line 44) | uninstallMutationObserver() {
method recordSnapshotDuringNextAnimationFrame (line 49) | recordSnapshotDuringNextAnimationFrame() {
method installEventListeners (line 59) | installEventListeners() {
method uninstallEventListeners (line 65) | uninstallEventListeners() {
method handleEvent (line 71) | handleEvent(event) {
method recordInputEvent (line 82) | recordInputEvent(event) {
method recordKeypressEvent (line 86) | recordKeypressEvent(event) {
method recordSnapshot (line 99) | recordSnapshot() {
method getSnapshot (line 106) | getSnapshot() {
FILE: src/inspector/watchdog/recording.js
class Recording (line 1) | class Recording {
method fromJSON (line 2) | static fromJSON({ snapshots, frames }) {
method constructor (line 6) | constructor(snapshots = [], frames = []) {
method recordSnapshot (line 11) | recordSnapshot(snapshot) {
method recordEvent (line 20) | recordEvent(event) {
method getSnapshotAtIndex (line 25) | getSnapshotAtIndex(index) {
method getSnapshotAtFrameIndex (line 31) | getSnapshotAtFrameIndex(frameIndex) {
method getTimestampAtFrameIndex (line 36) | getTimestampAtFrameIndex(index) {
method getSnapshotIndexAtFrameIndex (line 40) | getSnapshotIndexAtFrameIndex(index) {
method getEventAtFrameIndex (line 44) | getEventAtFrameIndex(index) {
method getEventsUpToFrameIndex (line 48) | getEventsUpToFrameIndex(index) {
method getFrameCount (line 52) | getFrameCount() {
method getTimestamp (line 56) | getTimestamp() {
method truncateToSnapshotCount (line 60) | truncateToSnapshotCount(snapshotCount) {
method toJSON (line 74) | toJSON() {
FILE: src/inspector/watchdog/serializer.js
class Serializer (line 1) | class Serializer {
method constructor (line 2) | constructor(element) {
method serializeTree (line 9) | serializeTree() {
method serializeNode (line 14) | serializeNode(node) {
method serializeElementToObject (line 33) | serializeElementToObject(node, object) {
method serializeElementChildrenToObject (line 53) | serializeElementChildrenToObject(node, object) {
method serializeNodeValueToObject (line 59) | serializeNodeValueToObject(node, object) {
method serializeSelection (line 63) | serializeSelection() {
method getSnapshot (line 79) | getSnapshot() {
FILE: src/test/system/attachment_gallery_test.js
constant ORC (line 15) | const ORC = OBJECT_REPLACEMENT_CHARACTER
FILE: src/test/system/attachment_test.js
function insertToolbarButton (line 45) | function insertToolbarButton(event) {
FILE: src/test/system/canceled_input_test.js
method setup (line 5) | setup() {
method teardown (line 16) | teardown() {
FILE: src/test/system/level_2_input_test.js
method setup (line 26) | setup() {
method teardown (line 30) | teardown() {
FILE: src/test/system/morphing_test.js
function renderWithMorph (line 6) | function renderWithMorph(event) {
FILE: src/test/test_helpers/fixtures/test_image_url.js
constant TEST_IMAGE_URL (line 1) | const TEST_IMAGE_URL = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAAC...
FILE: src/test/test_helpers/input_helpers.js
method getAsFile (line 71) | getAsFile() {
method getData (line 182) | getData(format) {
method setData (line 190) | setData(format, data) {
FILE: src/test/test_helpers/test_stubs.js
class TestCompositionDelegate (line 3) | class TestCompositionDelegate {
method compositionDidRequestChangingSelectionToLocationRange (line 4) | compositionDidRequestChangingSelectionToLocationRange() {
method getSelectionManager (line 8) | getSelectionManager() {
class TestSelectionManager (line 14) | class TestSelectionManager {
method constructor (line 15) | constructor() {
method getLocationRange (line 19) | getLocationRange() {
method setLocationRange (line 23) | setLocationRange(locationRange) {
method preserveSelection (line 27) | preserveSelection(block) {
method setLocationRangeFromPoint (line 33) | setLocationRangeFromPoint(point) {}
method locationIsCursorTarget (line 35) | locationIsCursorTarget() {
method selectionIsExpanded (line 39) | selectionIsExpanded() {
FILE: src/test/test_helpers/timing_helpers.js
function nextFrame (line 1) | function nextFrame() {
function nextIdle (line 5) | function nextIdle() {
function delay (line 9) | function delay(ms = 1) {
FILE: src/test/unit/html_parser_test.js
method parser (line 347) | parser(element) {
FILE: src/test/unit/mutation_observer_test.js
method elementDidMutate (line 17) | elementDidMutate(summary) {
FILE: src/trix/config/block_attributes.js
method test (line 33) | test(element) {
method test (line 46) | test(element) {
FILE: src/trix/config/file_size_formatting.js
method formatter (line 12) | formatter(number) {
FILE: src/trix/config/input.js
method getLevel (line 7) | getLevel() {
method pickFiles (line 14) | pickFiles(callback) {
FILE: src/trix/config/text_attributes.js
method parser (line 7) | parser(element) {
method parser (line 15) | parser(element) {
method parser (line 22) | parser(element) {
FILE: src/trix/config/toolbar.js
method getDefaultHTML (line 4) | getDefaultHTML() {
FILE: src/trix/constants.js
constant ZERO_WIDTH_SPACE (line 1) | const ZERO_WIDTH_SPACE = "\uFEFF"
constant NON_BREAKING_SPACE (line 2) | const NON_BREAKING_SPACE = "\u00A0"
constant OBJECT_REPLACEMENT_CHARACTER (line 3) | const OBJECT_REPLACEMENT_CHARACTER = "\uFFFC"
FILE: src/trix/controllers/attachment_editor_controller.js
class AttachmentEditorController (line 20) | class AttachmentEditorController extends BasicObject {
method constructor (line 21) | constructor(attachmentPiece, element, container, options = {}) {
method install (line 40) | install() {
method uninstall (line 48) | uninstall() {
method savePendingCaption (line 60) | savePendingCaption() {
method undo (line 198) | undo() {
method didClickToolbar (line 207) | didClickToolbar(event) {
method didClickActionButton (line 212) | didClickActionButton(event) {
method didKeyDownCaption (line 220) | didKeyDownCaption(event) {
method didInputCaption (line 228) | didInputCaption(event) {
method didChangeCaption (line 232) | didChangeCaption(event) {
method didBlurCaption (line 236) | didBlurCaption(event) {
FILE: src/trix/controllers/composition_controller.js
class CompositionController (line 8) | class CompositionController extends BasicObject {
method constructor (line 9) | constructor(element, composition) {
method didFocus (line 34) | didFocus(event) {
method didBlur (line 45) | didBlur(event) {
method didClickAttachment (line 58) | didClickAttachment(event, target) {
method getSerializableElement (line 64) | getSerializableElement() {
method render (line 72) | render() {
method rerenderViewForObject (line 88) | rerenderViewForObject(object) {
method invalidateViewForObject (line 93) | invalidateViewForObject(object) {
method isViewCachingEnabled (line 97) | isViewCachingEnabled() {
method enableViewCaching (line 101) | enableViewCaching() {
method disableViewCaching (line 105) | disableViewCaching() {
method refreshViewCache (line 109) | refreshViewCache() {
method isEditingAttachment (line 115) | isEditingAttachment() {
method installAttachmentEditorForAttachment (line 119) | installAttachmentEditorForAttachment(attachment, options) {
method uninstallAttachmentEditor (line 130) | uninstallAttachmentEditor() {
method didUninstallAttachmentEditor (line 136) | didUninstallAttachmentEditor() {
method attachmentEditorDidRequestUpdatingAttributesForAttachment (line 141) | attachmentEditorDidRequestUpdatingAttributesForAttachment(attributes, ...
method attachmentEditorDidRequestRemovingAttributeForAttachment (line 146) | attachmentEditorDidRequestRemovingAttributeForAttachment(attribute, at...
method attachmentEditorDidRequestRemovalOfAttachment (line 151) | attachmentEditorDidRequestRemovalOfAttachment(attachment) {
method attachmentEditorDidRequestDeselectingAttachment (line 155) | attachmentEditorDidRequestDeselectingAttachment(attachment) {
method canSyncDocumentView (line 161) | canSyncDocumentView() {
method findAttachmentForElement (line 165) | findAttachmentForElement(element) {
FILE: src/trix/controllers/controller.js
class Controller (line 4) | class Controller extends BasicObject {}
FILE: src/trix/controllers/editor_controller.js
class EditorController (line 23) | class EditorController extends Controller {
method test (line 26) | test() {
method perform (line 29) | perform() {
method test (line 34) | test() {
method perform (line 37) | perform() {
method test (line 42) | test() {
method test (line 47) | test() {
method perform (line 50) | perform() {
method test (line 55) | test() {
method perform (line 58) | perform() {
method test (line 63) | test() {
method perform (line 66) | perform() {
method constructor (line 72) | constructor({ editorElement, document, html }) {
method registerSelectionManager (line 106) | registerSelectionManager() {
method unregisterSelectionManager (line 110) | unregisterSelectionManager() {
method render (line 114) | render() {
method reparse (line 118) | reparse() {
method compositionDidChangeDocument (line 124) | compositionDidChangeDocument(document) {
method compositionDidChangeCurrentAttributes (line 131) | compositionDidChangeCurrentAttributes(currentAttributes) {
method compositionDidPerformInsertionAtRange (line 138) | compositionDidPerformInsertionAtRange(range) {
method compositionShouldAcceptFile (line 144) | compositionShouldAcceptFile(file) {
method compositionDidAddAttachment (line 148) | compositionDidAddAttachment(attachment) {
method compositionDidEditAttachment (line 153) | compositionDidEditAttachment(attachment) {
method compositionDidChangeAttachmentPreviewURL (line 160) | compositionDidChangeAttachmentPreviewURL(attachment) {
method compositionDidRemoveAttachment (line 165) | compositionDidRemoveAttachment(attachment) {
method compositionDidStartEditingAttachment (line 170) | compositionDidStartEditingAttachment(attachment, options) {
method compositionDidStopEditingAttachment (line 176) | compositionDidStopEditingAttachment(attachment) {
method compositionDidRequestChangingSelectionToLocationRange (line 181) | compositionDidRequestChangingSelectionToLocationRange(locationRange) {
method compositionWillLoadSnapshot (line 190) | compositionWillLoadSnapshot() {
method compositionDidLoadSnapshot (line 194) | compositionDidLoadSnapshot() {
method getSelectionManager (line 200) | getSelectionManager() {
method attachmentManagerDidRequestRemovalOfAttachment (line 206) | attachmentManagerDidRequestRemovalOfAttachment(attachment) {
method compositionControllerWillSyncDocumentView (line 212) | compositionControllerWillSyncDocumentView() {
method compositionControllerDidSyncDocumentView (line 218) | compositionControllerDidSyncDocumentView() {
method compositionControllerDidRender (line 225) | compositionControllerDidRender() {
method compositionControllerDidFocus (line 243) | compositionControllerDidFocus() {
method compositionControllerDidBlur (line 251) | compositionControllerDidBlur() {
method compositionControllerDidSelectAttachment (line 255) | compositionControllerDidSelectAttachment(attachment, options) {
method compositionControllerDidRequestDeselectingAttachment (line 260) | compositionControllerDidRequestDeselectingAttachment(attachment) {
method compositionControllerWillUpdateAttachment (line 265) | compositionControllerWillUpdateAttachment(attachment) {
method compositionControllerDidRequestRemovalOfAttachment (line 269) | compositionControllerDidRequestRemovalOfAttachment(attachment) {
method inputControllerWillHandleInput (line 275) | inputControllerWillHandleInput() {
method inputControllerDidRequestRender (line 280) | inputControllerDidRequestRender() {
method inputControllerDidHandleInput (line 284) | inputControllerDidHandleInput() {
method inputControllerDidAllowUnhandledInput (line 292) | inputControllerDidAllowUnhandledInput() {
method inputControllerDidRequestReparse (line 296) | inputControllerDidRequestReparse() {
method inputControllerWillPerformTyping (line 300) | inputControllerWillPerformTyping() {
method inputControllerWillPerformFormatting (line 304) | inputControllerWillPerformFormatting(attributeName) {
method inputControllerWillCutText (line 308) | inputControllerWillCutText() {
method inputControllerWillPaste (line 312) | inputControllerWillPaste(paste) {
method inputControllerDidPaste (line 318) | inputControllerDidPaste(paste) {
method inputControllerWillMoveText (line 325) | inputControllerWillMoveText() {
method inputControllerWillAttachFiles (line 329) | inputControllerWillAttachFiles() {
method inputControllerWillPerformUndo (line 333) | inputControllerWillPerformUndo() {
method inputControllerWillPerformRedo (line 337) | inputControllerWillPerformRedo() {
method inputControllerDidReceiveKeyboardCommand (line 341) | inputControllerDidReceiveKeyboardCommand(keys) {
method inputControllerDidStartDrag (line 345) | inputControllerDidStartDrag() {
method inputControllerDidReceiveDragOverPoint (line 349) | inputControllerDidReceiveDragOverPoint(point) {
method inputControllerDidCancelDrag (line 353) | inputControllerDidCancelDrag() {
method locationRangeDidChange (line 360) | locationRangeDidChange(locationRange) {
method toolbarDidClickButton (line 371) | toolbarDidClickButton() {
method toolbarDidInvokeAction (line 377) | toolbarDidInvokeAction(actionName, invokingElement) {
method toolbarDidToggleAttribute (line 381) | toolbarDidToggleAttribute(attributeName) {
method toolbarDidUpdateAttribute (line 390) | toolbarDidUpdateAttribute(attributeName, value) {
method toolbarDidRemoveAttribute (line 399) | toolbarDidRemoveAttribute(attributeName) {
method toolbarWillShowDialog (line 408) | toolbarWillShowDialog(dialogElement) {
method toolbarDidShowDialog (line 413) | toolbarDidShowDialog(dialogName) {
method toolbarDidHideDialog (line 417) | toolbarDidHideDialog(dialogName) {
method freezeSelection (line 425) | freezeSelection() {
method thawSelection (line 434) | thawSelection() {
method canInvokeAction (line 443) | canInvokeAction(actionName) {
method invokeAction (line 451) | invokeAction(actionName, invokingElement) {
method actionIsExternal (line 459) | actionIsExternal(actionName) {
method getCurrentActions (line 463) | getCurrentActions() {
method updateCurrentActions (line 471) | updateCurrentActions() {
method runEditorFilters (line 482) | runEditorFilters() {
method updateInputElement (line 503) | updateInputElement() {
method notifyEditorElement (line 509) | notifyEditorElement(message, data) {
method removeAttachment (line 531) | removeAttachment(attachment) {
method recordFormattingUndoEntry (line 537) | recordFormattingUndoEntry(attributeName) {
method recordTypingUndoEntry (line 545) | recordTypingUndoEntry() {
method getUndoContext (line 552) | getUndoContext(...context) {
method getLocationContext (line 556) | getLocationContext() {
method getTimeContext (line 565) | getTimeContext() {
method isFocused (line 573) | isFocused() {
method isFocusedInvisibly (line 579) | isFocusedInvisibly() {
method actions (line 583) | get actions() {
FILE: src/trix/controllers/input_controller.js
class InputController (line 8) | class InputController extends BasicObject {
method constructor (line 12) | constructor(element) {
method elementDidMutate (line 23) | elementDidMutate(mutationSummary) {}
method editorWillSyncDocumentView (line 25) | editorWillSyncDocumentView() {
method editorDidSyncDocumentView (line 29) | editorDidSyncDocumentView() {
method requestRender (line 33) | requestRender() {
method requestReparse (line 37) | requestReparse() {
method attachFiles (line 42) | attachFiles(files) {
method handlerFor (line 55) | handlerFor(eventName) {
method handleInput (line 70) | handleInput(callback) {
method createLinkHTML (line 79) | createLinkHTML(href, text) {
FILE: src/trix/controllers/level_0_input_controller.js
class Level0InputController (line 23) | class Level0InputController extends InputController {
method keydown (line 26) | keydown(event) {
method keypress (line 68) | keypress(event) {
method textInput (line 81) | textInput(event) {
method dragenter (line 94) | dragenter(event) {
method dragstart (line 98) | dragstart(event) {
method dragover (line 104) | dragover(event) {
method dragend (line 115) | dragend(event) {
method drop (line 121) | drop(event) {
method cut (line 146) | cut(event) {
method copy (line 160) | copy(event) {
method paste (line 168) | paste(event) {
method compositionstart (line 236) | compositionstart(event) {
method compositionupdate (line 240) | compositionupdate(event) {
method compositionend (line 244) | compositionend(event) {
method beforeinput (line 248) | beforeinput(event) {
method input (line 252) | input(event) {
method backspace (line 259) | backspace(event) {
method delete (line 264) | delete(event) {
method return (line 269) | return(event) {
method tab (line 275) | tab(event) {
method left (line 283) | left(event) {
method right (line 290) | right(event) {
method d (line 298) | d(event) {
method h (line 303) | h(event) {
method o (line 308) | o(event) {
method return (line 317) | return(event) {
method tab (line 324) | tab(event) {
method left (line 332) | left(event) {
method right (line 339) | right(event) {
method backspace (line 348) | backspace(event) {
method backspace (line 355) | backspace(event) {
method constructor (line 362) | constructor() {
method setInputSummary (line 367) | setInputSummary(summary = {}) {
method resetInputSummary (line 376) | resetInputSummary() {
method reset (line 380) | reset() {
method elementDidMutate (line 387) | elementDidMutate(mutationSummary) {
method mutationIsExpected (line 404) | mutationIsExpected({ textAdded, textDeleted }) {
method mutationIsSignificant (line 433) | mutationIsSignificant(mutationSummary) {
method getCompositionInput (line 441) | getCompositionInput() {
method isComposing (line 449) | isComposing() {
method deleteInDirection (line 453) | deleteInDirection(direction, event) {
method serializeSelectionToDataTransfer (line 464) | serializeSelectionToDataTransfer(dataTransfer) {
method canAcceptDataTransfer (line 474) | canAcceptDataTransfer(dataTransfer) {
method getPastedHTMLUsingHiddenElement (line 482) | getPastedHTMLUsingHiddenElement(callback) {
class CompositionInput (line 555) | class CompositionInput extends BasicObject {
method constructor (line 556) | constructor(inputController) {
method start (line 565) | start(data) {
method update (line 582) | update(data) {
method end (line 594) | end(data) {
method getEndData (line 615) | getEndData() {
method isEnded (line 619) | isEnded() {
method isSignificant (line 623) | isSignificant() {
method canApplyToDocument (line 633) | canApplyToDocument() {
FILE: src/trix/controllers/level_2_input_controller.js
class Level2InputController (line 9) | class Level2InputController extends InputController {
method constructor (line 10) | constructor(...args) {
method keydown (line 16) | keydown(event) {
method paste (line 39) | paste(event) {
method beforeinput (line 73) | beforeinput(event) {
method input (line 91) | input(event) {
method dragstart (line 95) | dragstart(event) {
method dragenter (line 106) | dragenter(event) {
method dragover (line 112) | dragover(event) {
method drop (line 125) | drop(event) {
method dragend (line 140) | dragend() {
method compositionend (line 147) | compositionend(event) {
method ArrowLeft (line 156) | ArrowLeft() {
method ArrowRight (line 163) | ArrowRight() {
method Backspace (line 170) | Backspace() {
method Tab (line 179) | Tab() {
method "Tab+Shift" (line 187) | "Tab+Shift"() {
method deleteByComposition (line 197) | deleteByComposition() {
method deleteByCut (line 201) | deleteByCut() {
method deleteByDrag (line 205) | deleteByDrag() {
method deleteCompositionText (line 212) | deleteCompositionText() {
method deleteContent (line 216) | deleteContent() {
method deleteContentBackward (line 220) | deleteContentBackward() {
method deleteContentForward (line 224) | deleteContentForward() {
method deleteEntireSoftLine (line 228) | deleteEntireSoftLine() {
method deleteHardLineBackward (line 232) | deleteHardLineBackward() {
method deleteHardLineForward (line 236) | deleteHardLineForward() {
method deleteSoftLineBackward (line 240) | deleteSoftLineBackward() {
method deleteSoftLineForward (line 244) | deleteSoftLineForward() {
method deleteWordBackward (line 248) | deleteWordBackward() {
method deleteWordForward (line 252) | deleteWordForward() {
method formatBackColor (line 256) | formatBackColor() {
method formatBold (line 260) | formatBold() {
method formatFontColor (line 264) | formatFontColor() {
method formatFontName (line 268) | formatFontName() {
method formatIndent (line 272) | formatIndent() {
method formatItalic (line 280) | formatItalic() {
method formatJustifyCenter (line 284) | formatJustifyCenter() {
method formatJustifyFull (line 288) | formatJustifyFull() {
method formatJustifyLeft (line 292) | formatJustifyLeft() {
method formatJustifyRight (line 296) | formatJustifyRight() {
method formatOutdent (line 300) | formatOutdent() {
method formatRemove (line 308) | formatRemove() {
method formatSetBlockTextDirection (line 316) | formatSetBlockTextDirection() {
method formatSetInlineTextDirection (line 320) | formatSetInlineTextDirection() {
method formatStrikeThrough (line 324) | formatStrikeThrough() {
method formatSubscript (line 328) | formatSubscript() {
method formatSuperscript (line 332) | formatSuperscript() {
method formatUnderline (line 336) | formatUnderline() {
method historyRedo (line 340) | historyRedo() {
method historyUndo (line 344) | historyUndo() {
method insertCompositionText (line 348) | insertCompositionText() {
method insertFromComposition (line 353) | insertFromComposition() {
method insertFromDrop (line 358) | insertFromDrop() {
method insertFromPaste (line 369) | insertFromPaste() {
method insertFromYank (line 430) | insertFromYank() {
method insertLineBreak (line 434) | insertLineBreak() {
method insertLink (line 438) | insertLink() {
method insertOrderedList (line 442) | insertOrderedList() {
method insertParagraph (line 446) | insertParagraph() {
method insertReplacementText (line 453) | insertReplacementText() {
method insertText (line 462) | insertText() {
method insertTranspose (line 466) | insertTranspose() {
method insertUnorderedList (line 470) | insertUnorderedList() {
method elementDidMutate (line 475) | elementDidMutate() {
method scheduleRender (line 485) | scheduleRender() {
method render (line 489) | render() {
method reparse (line 499) | reparse() {
method insertString (line 505) | insertString(string = "", options) {
method toggleAttributeIfSupported (line 512) | toggleAttributeIfSupported(attributeName) {
method activateAttributeIfSupported (line 521) | activateAttributeIfSupported(attributeName, value) {
method deleteInDirection (line 530) | deleteInDirection(direction, { recordUndoEntry } = { recordUndoEntry: ...
method withTargetDOMRange (line 545) | withTargetDOMRange(domRange, fn) {
method getTargetDOMRange (line 558) | getTargetDOMRange({ minLength } = { minLength: 0 }) {
method withEvent (line 570) | withEvent(event, fn) {
FILE: src/trix/controllers/toolbar_controller.js
class ToolbarController (line 24) | class ToolbarController extends BasicObject {
method constructor (line 25) | constructor(element) {
method didClickActionButton (line 61) | didClickActionButton(event, element) {
method didClickAttributeButton (line 73) | didClickAttributeButton(event, element) {
method didClickDialogButton (line 87) | didClickDialogButton(event, element) {
method didKeyDownDialogInput (line 93) | didKeyDownDialogInput(event, element) {
method updateActions (line 110) | updateActions(actions) {
method refreshActionButtons (line 115) | refreshActionButtons() {
method eachActionButton (line 121) | eachActionButton(callback) {
method updateAttributes (line 129) | updateAttributes(attributes) {
method refreshAttributeButtons (line 134) | refreshAttributeButtons() {
method eachAttributeButton (line 147) | eachAttributeButton(callback) {
method applyKeyboardCommand (line 153) | applyKeyboardCommand(keys) {
method dialogIsVisible (line 168) | dialogIsVisible(dialogName) {
method toggleDialog (line 175) | toggleDialog(dialogName) {
method showDialog (line 183) | showDialog(dialogName) {
method setAttribute (line 207) | setAttribute(dialogElement) {
method isSafeAttribute (line 224) | isSafeAttribute(input) {
method removeAttribute (line 232) | removeAttribute(dialogElement) {
method hideDialog (line 238) | hideDialog() {
method resetDialogInputs (line 248) | resetDialogInputs() {
method getDialog (line 256) | getDialog(dialogName) {
FILE: src/trix/core/basic_object.js
class BasicObject (line 1) | class BasicObject {
method proxyMethod (line 2) | static proxyMethod(expression) {
FILE: src/trix/core/collections/element_store.js
class ElementStore (line 1) | class ElementStore {
method constructor (line 2) | constructor(elements) {
method add (line 6) | add(element) {
method remove (line 11) | remove(element) {
method reset (line 20) | reset(elements = []) {
FILE: src/trix/core/collections/hash.js
class Hash (line 4) | class Hash extends TrixObject {
method fromCommonAttributesOfObjects (line 5) | static fromCommonAttributesOfObjects(objects = []) {
method box (line 20) | static box(values) {
method constructor (line 24) | constructor(values = {}) {
method add (line 29) | add(key, value) {
method remove (line 33) | remove(key) {
method get (line 37) | get(key) {
method has (line 41) | has(key) {
method merge (line 45) | merge(values) {
method slice (line 49) | slice(keys) {
method getKeys (line 61) | getKeys() {
method getKeysCommonToHash (line 65) | getKeysCommonToHash(hash) {
method isEqualTo (line 70) | isEqualTo(values) {
method isEmpty (line 74) | isEmpty() {
method toArray (line 78) | toArray() {
method toObject (line 91) | toObject() {
method toJSON (line 95) | toJSON() {
method contentsForInspection (line 99) | contentsForInspection() {
FILE: src/trix/core/collections/object_group.js
class ObjectGroup (line 1) | class ObjectGroup {
method groupObjects (line 2) | static groupObjects(ungroupedObjects = [], { depth, asTree } = {}) {
method constructor (line 35) | constructor(objects = [], { depth, asTree }) {
method getObjects (line 43) | getObjects() {
method getDepth (line 47) | getDepth() {
method getCacheKey (line 51) | getCacheKey() {
FILE: src/trix/core/collections/object_map.js
class ObjectMap (line 3) | class ObjectMap extends BasicObject {
method constructor (line 4) | constructor(objects = []) {
method find (line 16) | find(object) {
FILE: src/trix/core/helpers/bidi.js
constant RTL_PATTERN (line 4) | const RTL_PATTERN =
FILE: src/trix/core/helpers/events.js
function shouldRenderInmmediatelyToDealWithIOSDictation (line 47) | function shouldRenderInmmediatelyToDealWithIOSDictation(inputEvent) {
FILE: src/trix/core/object.js
class TrixObject (line 6) | class TrixObject extends BasicObject {
method fromJSONString (line 7) | static fromJSONString(jsonString) {
method constructor (line 11) | constructor() {
method hasSameConstructorAs (line 16) | hasSameConstructorAs(object) {
method isEqualTo (line 20) | isEqualTo(object) {
method inspect (line 24) | inspect() {
method contentsForInspection (line 36) | contentsForInspection() {}
method toJSONString (line 38) | toJSONString() {
method toUTF16String (line 42) | toUTF16String() {
method getCacheKey (line 46) | getCacheKey() {
FILE: src/trix/core/utilities/operation.js
class Operation (line 3) | class Operation extends BasicObject {
method isPerforming (line 4) | isPerforming() {
method hasPerformed (line 8) | hasPerformed() {
method hasSucceeded (line 12) | hasSucceeded() {
method hasFailed (line 16) | hasFailed() {
method getPromise (line 20) | getPromise() {
method perform (line 41) | perform(callback) {
method release (line 45) | release() {
FILE: src/trix/core/utilities/utf16_string.js
class UTF16String (line 3) | class UTF16String extends BasicObject {
method box (line 4) | static box(value = "") {
method fromUCS2String (line 12) | static fromUCS2String(ucs2String) {
method fromCodepoints (line 16) | static fromCodepoints(codepoints) {
method constructor (line 20) | constructor(ucs2String, codepoints) {
method offsetToUCS2Offset (line 28) | offsetToUCS2Offset(offset) {
method offsetFromUCS2Offset (line 32) | offsetFromUCS2Offset(ucs2Offset) {
method slice (line 36) | slice() {
method charAt (line 40) | charAt(offset) {
method isEqualTo (line 44) | isEqualTo(value) {
method toJSON (line 48) | toJSON() {
method getCacheKey (line 52) | getCacheKey() {
method toString (line 56) | toString() {
FILE: src/trix/elements/trix_editor_element.js
method withCallback (line 35) | withCallback() {
class ElementInternalsDelegate (line 163) | class ElementInternalsDelegate {
method constructor (line 168) | constructor(element) {
method connectedCallback (line 174) | connectedCallback() {
method disconnectedCallback (line 178) | disconnectedCallback() {
method form (line 181) | get form() {
method name (line 185) | get name() {
method name (line 189) | set name(value) {
method labels (line 193) | get labels() {
method disabled (line 197) | get disabled() {
method disabled (line 201) | set disabled(value) {
method required (line 205) | get required() {
method required (line 209) | set required(value) {
method validity (line 214) | get validity() {
method validationMessage (line 218) | get validationMessage() {
method willValidate (line 222) | get willValidate() {
method formDisabledCallback (line 226) | formDisabledCallback(disabled) {
method setFormValue (line 230) | setFormValue(value) {
method checkValidity (line 236) | checkValidity() {
method reportValidity (line 240) | reportValidity() {
method setCustomValidity (line 244) | setCustomValidity(validationMessage) {
method #validate (line 248) | #validate(customValidationMessage = "") {
class LegacyDelegate (line 259) | class LegacyDelegate {
method constructor (line 262) | constructor(element) {
method connectedCallback (line 266) | connectedCallback() {
method disconnectedCallback (line 272) | disconnectedCallback() {
method labels (line 278) | get labels() {
method form (line 294) | get form() {
method name (line 300) | get name() {
method name (line 306) | set name(value) {
method disabled (line 310) | get disabled() {
method disabled (line 316) | set disabled(value) {
method required (line 320) | get required() {
method required (line 326) | set required(value) {
method validity (line 330) | get validity() {
method validationMessage (line 335) | get validationMessage() {
method willValidate (line 341) | get willValidate() {
method formDisabledCallback (line 347) | formDisabledCallback(value) {
method setFormValue (line 350) | setFormValue(value) {
method checkValidity (line 353) | checkValidity() {
method reportValidity (line 359) | reportValidity() {
method setCustomValidity (line 365) | setCustomValidity(validationMessage) {
class TrixEditorElement (line 388) | class TrixEditorElement extends HTMLElement {
method constructor (line 395) | constructor() {
method trixId (line 405) | get trixId() {
method labels (line 414) | get labels() {
method disabled (line 418) | get disabled() {
method disabled (line 428) | set disabled(value) {
method required (line 437) | get required() {
method required (line 441) | set required(value) {
method validity (line 445) | get validity() {
method validationMessage (line 449) | get validationMessage() {
method willValidate (line 453) | get willValidate() {
method type (line 457) | get type() {
method toolbarElement (line 461) | get toolbarElement() {
method form (line 475) | get form() {
method inputElement (line 485) | get inputElement() {
method editor (line 493) | get editor() {
method name (line 497) | get name() {
method name (line 507) | set name(value) {
method value (line 517) | get value() {
method value (line 527) | set value(defaultValue) {
method attributeChangedCallback (line 534) | attributeChangedCallback(name, oldValue, newValue) {
method notify (line 542) | notify(message, data) {
method setFormValue (line 548) | setFormValue(value) {
method connectedCallback (line 559) | connectedCallback() {
method disconnectedCallback (line 587) | disconnectedCallback() {
method reconnect (line 593) | reconnect() {
method removeInternalToolbar (line 599) | removeInternalToolbar() {
method checkValidity (line 606) | checkValidity() {
method reportValidity (line 610) | reportValidity() {
method setCustomValidity (line 614) | setCustomValidity(validationMessage) {
method formDisabledCallback (line 618) | formDisabledCallback(disabled) {
method formResetCallback (line 628) | formResetCallback() {
method reset (line 632) | reset() {
FILE: src/trix/elements/trix_toolbar_element.js
class TrixToolbarElement (line 26) | class TrixToolbarElement extends HTMLElement {
method connectedCallback (line 30) | connectedCallback() {
method editorElements (line 38) | get editorElements() {
method editorElement (line 48) | get editorElement() {
FILE: src/trix/filters/filter.js
constant BLOCK_ATTRIBUTE_NAME (line 1) | const BLOCK_ATTRIBUTE_NAME = "attachmentGallery"
constant TEXT_ATTRIBUTE_NAME (line 2) | const TEXT_ATTRIBUTE_NAME = "presentation"
constant TEXT_ATTRIBUTE_VALUE (line 3) | const TEXT_ATTRIBUTE_VALUE = "gallery"
class Filter (line 5) | class Filter {
method constructor (line 6) | constructor(snapshot) {
method perform (line 11) | perform() {
method getSnapshot (line 16) | getSnapshot() {
method removeBlockAttribute (line 22) | removeBlockAttribute() {
method applyBlockAttribute (line 26) | applyBlockAttribute() {
method findRangesOfBlocks (line 59) | findRangesOfBlocks() {
method findRangesOfPieces (line 63) | findRangesOfPieces() {
method moveSelectedRangeForward (line 67) | moveSelectedRangeForward() {
FILE: src/trix/models/attachment.js
class Attachment (line 6) | class Attachment extends TrixObject {
method attachmentForFile (line 9) | static attachmentForFile(file) {
method attributesForFile (line 16) | static attributesForFile(file) {
method fromJSON (line 24) | static fromJSON(attachmentJSON) {
method constructor (line 28) | constructor(attributes = {}) {
method setAttribute (line 35) | setAttribute(attribute, value) {
method getAttribute (line 39) | getAttribute(attribute) {
method hasAttribute (line 43) | hasAttribute(attribute) {
method getAttributes (line 47) | getAttributes() {
method setAttributes (line 51) | setAttributes(attributes = {}) {
method didChangeAttributes (line 61) | didChangeAttributes() {
method isPending (line 67) | isPending() {
method isPreviewable (line 71) | isPreviewable() {
method getType (line 79) | getType() {
method getURL (line 89) | getURL() {
method getHref (line 93) | getHref() {
method getFilename (line 97) | getFilename() {
method getFilesize (line 101) | getFilesize() {
method getFormattedFilesize (line 105) | getFormattedFilesize() {
method getExtension (line 114) | getExtension() {
method getContentType (line 120) | getContentType() {
method hasContent (line 124) | hasContent() {
method getContent (line 128) | getContent() {
method getWidth (line 132) | getWidth() {
method getHeight (line 136) | getHeight() {
method getFile (line 140) | getFile() {
method setFile (line 144) | setFile(file) {
method releaseFile (line 151) | releaseFile() {
method getUploadProgress (line 156) | getUploadProgress() {
method setUploadProgress (line 160) | setUploadProgress(value) {
method toJSON (line 167) | toJSON() {
method getCacheKey (line 171) | getCacheKey() {
method getPreviewURL (line 177) | getPreviewURL() {
method setPreviewURL (line 181) | setPreviewURL(url) {
method preloadURL (line 189) | preloadURL() {
method preloadFile (line 193) | preloadFile() {
method releasePreloadedFile (line 200) | releasePreloadedFile() {
method preload (line 207) | preload(url, callback) {
FILE: src/trix/models/attachment_manager.js
class AttachmentManager (line 4) | class AttachmentManager extends BasicObject {
method constructor (line 5) | constructor(attachments = []) {
method getAttachments (line 13) | getAttachments() {
method manageAttachment (line 22) | manageAttachment(attachment) {
method attachmentIsManaged (line 29) | attachmentIsManaged(attachment) {
method requestRemovalOfAttachment (line 33) | requestRemovalOfAttachment(attachment) {
method unmanageAttachment (line 39) | unmanageAttachment(attachment) {
FILE: src/trix/models/attachment_piece.js
class AttachmentPiece (line 6) | class AttachmentPiece extends Piece {
method fromJSON (line 9) | static fromJSON(pieceJSON) {
method constructor (line 13) | constructor(attachment) {
method ensureAttachmentExclusivelyHasAttribute (line 23) | ensureAttachmentExclusivelyHasAttribute(attribute) {
method removeProhibitedAttributes (line 32) | removeProhibitedAttributes() {
method getValue (line 39) | getValue() {
method isSerializable (line 43) | isSerializable() {
method getCaption (line 47) | getCaption() {
method isEqualTo (line 51) | isEqualTo(piece) {
method toString (line 55) | toString() {
method toJSON (line 59) | toJSON() {
method getCacheKey (line 65) | getCacheKey() {
method toConsole (line 69) | toConsole() {
FILE: src/trix/models/block.js
class Block (line 12) | class Block extends TrixObject {
method fromJSON (line 13) | static fromJSON(blockJSON) {
method constructor (line 18) | constructor(text, attributes, htmlAttributes) {
method isEmpty (line 25) | isEmpty() {
method isEqualTo (line 29) | isEqualTo(block) {
method copyWithText (line 35) | copyWithText(text) {
method copyWithoutText (line 39) | copyWithoutText() {
method copyWithAttributes (line 43) | copyWithAttributes(attributes) {
method copyWithoutAttributes (line 47) | copyWithoutAttributes() {
method copyUsingObjectMap (line 51) | copyUsingObjectMap(objectMap) {
method addAttribute (line 60) | addAttribute(attribute) {
method addHTMLAttribute (line 65) | addHTMLAttribute(attribute, value) {
method removeAttribute (line 70) | removeAttribute(attribute) {
method removeLastAttribute (line 76) | removeLastAttribute() {
method getLastAttribute (line 80) | getLastAttribute() {
method getAttributes (line 84) | getAttributes() {
method getAttributeLevel (line 88) | getAttributeLevel() {
method getAttributeAtLevel (line 92) | getAttributeAtLevel(level) {
method hasAttribute (line 96) | hasAttribute(attributeName) {
method hasAttributes (line 100) | hasAttributes() {
method getLastNestableAttribute (line 104) | getLastNestableAttribute() {
method getNestableAttributes (line 108) | getNestableAttributes() {
method getNestingLevel (line 112) | getNestingLevel() {
method decreaseNestingLevel (line 116) | decreaseNestingLevel() {
method increaseNestingLevel (line 125) | increaseNestingLevel() {
method getListItemAttributes (line 136) | getListItemAttributes() {
method isListItem (line 140) | isListItem() {
method isTerminalBlock (line 144) | isTerminalBlock() {
method breaksOnReturn (line 148) | breaksOnReturn() {
method findLineBreakInDirectionFromPosition (line 152) | findLineBreakInDirectionFromPosition(direction, position) {
method contentsForInspection (line 168) | contentsForInspection() {
method toString (line 175) | toString() {
method toJSON (line 179) | toJSON() {
method getDirection (line 189) | getDirection() {
method isRTL (line 193) | isRTL() {
method getLength (line 199) | getLength() {
method canBeConsolidatedWith (line 203) | canBeConsolidatedWith(block) {
method consolidateWith (line 207) | consolidateWith(block) {
method splitAtOffset (line 213) | splitAtOffset(offset) {
method getBlockBreakPosition (line 228) | getBlockBreakPosition() {
method getTextWithoutBlockBreak (line 232) | getTextWithoutBlockBreak() {
method canBeGrouped (line 242) | canBeGrouped(depth) {
method canBeGroupedWith (line 246) | canBeGroupedWith(otherBlock, depth) {
FILE: src/trix/models/composition.js
constant PLACEHOLDER (line 25) | const PLACEHOLDER = " "
class Composition (line 27) | class Composition extends BasicObject {
method constructor (line 28) | constructor() {
method setDocument (line 36) | setDocument(document) {
method getSnapshot (line 47) | getSnapshot() {
method loadSnapshot (line 54) | loadSnapshot({ document, selectedRange }) {
method insertText (line 63) | insertText(text, { updatePosition } = { updatePosition: true }) {
method insertBlock (line 76) | insertBlock(block = new Block()) {
method insertDocument (line 81) | insertDocument(document = new Document()) {
method insertString (line 92) | insertString(string, options) {
method insertBlockBreak (line 98) | insertBlockBreak() {
method insertLineBreak (line 109) | insertLineBreak() {
method insertHTML (line 129) | insertHTML(html) {
method replaceHTML (line 142) | replaceHTML(html) {
method insertFile (line 150) | insertFile(file) {
method insertFiles (line 154) | insertFiles(files) {
method insertAttachment (line 167) | insertAttachment(attachment) {
method insertAttachments (line 171) | insertAttachments(attachments) {
method shouldManageDeletingInDirection (line 190) | shouldManageDeletingInDirection(direction) {
method deleteInDirection (line 207) | deleteInDirection(direction, { length } = {}) {
method moveTextFromRange (line 255) | moveTextFromRange(range) {
method removeAttachment (line 261) | removeAttachment(attachment) {
method removeLastBlockAttribute (line 270) | removeLastBlockAttribute() {
method insertPlaceholder (line 277) | insertPlaceholder() {
method selectPlaceholder (line 282) | selectPlaceholder() {
method forgetPlaceholder (line 289) | forgetPlaceholder() {
method hasCurrentAttribute (line 295) | hasCurrentAttribute(attributeName) {
method toggleCurrentAttribute (line 300) | toggleCurrentAttribute(attributeName) {
method canSetCurrentAttribute (line 309) | canSetCurrentAttribute(attributeName) {
method canSetCurrentTextAttribute (line 317) | canSetCurrentTextAttribute(attributeName) {
method canSetCurrentBlockAttribute (line 328) | canSetCurrentBlockAttribute(attributeName) {
method setCurrentAttribute (line 334) | setCurrentAttribute(attributeName, value) {
method setHTMLAtributeAtPosition (line 344) | setHTMLAtributeAtPosition(position, attributeName, value) {
method setTextAttribute (line 354) | setTextAttribute(attributeName, value) {
method setBlockAttribute (line 369) | setBlockAttribute(attributeName, value) {
method removeCurrentAttribute (line 377) | removeCurrentAttribute(attributeName) {
method removeTextAttribute (line 388) | removeTextAttribute(attributeName) {
method removeBlockAttribute (line 394) | removeBlockAttribute(attributeName) {
method canDecreaseNestingLevel (line 400) | canDecreaseNestingLevel() {
method canIncreaseNestingLevel (line 404) | canIncreaseNestingLevel() {
method decreaseNestingLevel (line 417) | decreaseNestingLevel() {
method increaseNestingLevel (line 423) | increaseNestingLevel() {
method canDecreaseBlockAttributeLevel (line 429) | canDecreaseBlockAttributeLevel() {
method decreaseBlockAttributeLevel (line 433) | decreaseBlockAttributeLevel() {
method decreaseListLevel (line 440) | decreaseListLevel() {
method updateCurrentAttributes (line 460) | updateCurrentAttributes() {
method getCurrentAttributes (line 480) | getCurrentAttributes() {
method getCurrentTextAttributes (line 484) | getCurrentTextAttributes() {
method freezeSelection (line 499) | freezeSelection() {
method thawSelection (line 503) | thawSelection() {
method hasFrozenSelection (line 507) | hasFrozenSelection() {
method setSelection (line 511) | setSelection(selectedRange) {
method getSelectedRange (line 516) | getSelectedRange() {
method setSelectedRange (line 523) | setSelectedRange(selectedRange) {
method getPosition (line 528) | getPosition() {
method getLocationRange (line 535) | getLocationRange(options) {
method withTargetLocationRange (line 543) | withTargetLocationRange(locationRange, fn) {
method withTargetRange (line 554) | withTargetRange(range, fn) {
method withTargetDOMRange (line 559) | withTargetDOMRange(domRange, fn) {
method getExpandedRangeInDirection (line 564) | getExpandedRangeInDirection(direction, { length } = {}) {
method shouldManageMovingCursorInDirection (line 582) | shouldManageMovingCursorInDirection(direction) {
method moveCursorInDirection (line 590) | moveCursorInDirection(direction) {
method expandSelectionInDirection (line 614) | expandSelectionInDirection(direction, { length } = {}) {
method expandSelectionForEditing (line 619) | expandSelectionForEditing() {
method expandSelectionAroundCommonAttribute (line 625) | expandSelectionAroundCommonAttribute(attributeName) {
method selectionContainsAttachments (line 631) | selectionContainsAttachments() {
method selectionIsInCursorTarget (line 635) | selectionIsInCursorTarget() {
method positionIsCursorTarget (line 639) | positionIsCursorTarget(position) {
method positionIsBlockBreak (line 646) | positionIsBlockBreak(position) {
method getSelectedDocument (line 650) | getSelectedDocument() {
method getSelectedAttachments (line 657) | getSelectedAttachments() {
method getAttachments (line 663) | getAttachments() {
method refreshAttachments (line 667) | refreshAttachments() {
method attachmentDidChangeAttributes (line 691) | attachmentDidChangeAttributes(attachment) {
method attachmentDidChangePreviewURL (line 696) | attachmentDidChangePreviewURL(attachment) {
method editAttachment (line 703) | editAttachment(attachment, options) {
method stopEditingAttachment (line 710) | stopEditingAttachment() {
method updateAttributesForAttachment (line 716) | updateAttributesForAttachment(attributes, attachment) {
method removeAttributeForAttachment (line 720) | removeAttributeForAttachment(attribute, attachment) {
method breakFormattedBlock (line 726) | breakFormattedBlock(insertion) {
method getPreviousBlock (line 755) | getPreviousBlock() {
method getBlock (line 765) | getBlock() {
method getAttachmentAtRange (line 772) | getAttachmentAtRange(range) {
method notifyDelegateOfCurrentAttributesChange (line 779) | notifyDelegateOfCurrentAttributesChange() {
method notifyDelegateOfInsertionAtRange (line 783) | notifyDelegateOfInsertionAtRange(range) {
method translateUTF16PositionFromOffset (line 787) | translateUTF16PositionFromOffset(position, offset) {
FILE: src/trix/models/document.js
class Document (line 12) | class Document extends TrixObject {
method fromJSON (line 13) | static fromJSON(documentJSON) {
method fromString (line 18) | static fromString(string, textAttributes) {
method constructor (line 23) | constructor(blocks = []) {
method isEmpty (line 31) | isEmpty() {
method copy (line 36) | copy(options = {}) {
method copyUsingObjectsFromDocument (line 42) | copyUsingObjectsFromDocument(sourceDocument) {
method copyUsingObjectMap (line 47) | copyUsingObjectMap(objectMap) {
method copyWithBaseBlockAttributes (line 55) | copyWithBaseBlockAttributes(blockAttributes = []) {
method replaceBlock (line 64) | replaceBlock(oldBlock, newBlock) {
method insertDocumentAtRange (line 72) | insertDocumentAtRange(document, range) {
method mergeDocumentAtRange (line 91) | mergeDocumentAtRange(document, range) {
method insertTextAtRange (line 126) | insertTextAtRange(text, range) {
method removeTextAtRange (line 139) | removeTextAtRange(range) {
method moveTextFromRangeToPosition (line 188) | moveTextFromRangeToPosition(range, position) {
method addAttributeAtRange (line 225) | addAttributeAtRange(attribute, value, range) {
method addAttribute (line 245) | addAttribute(attribute, value) {
method removeAttributeAtRange (line 253) | removeAttributeAtRange(attribute, range) {
method updateAttributesForAttachment (line 267) | updateAttributesForAttachment(attributes, attachment) {
method removeAttributeForAttachment (line 280) | removeAttributeForAttachment(attribute, attachment) {
method setHTMLAttributeAtPosition (line 285) | setHTMLAttributeAtPosition(position, name, value) {
method insertBlockBreakAtRange (line 291) | insertBlockBreakAtRange(range) {
method applyBlockAttributeAtRange (line 306) | applyBlockAttributeAtRange(attributeName, value, range) {
method removeLastListAttributeAtRange (line 328) | removeLastListAttributeAtRange(range, options = {}) {
method removeLastTerminalAttributeAtRange (line 346) | removeLastTerminalAttributeAtRange(range) {
method removeBlockAttributesAtRange (line 361) | removeBlockAttributesAtRange(range) {
method expandRangeToLineBreaksAndSplitBlocks (line 371) | expandRangeToLineBreaksAndSplitBlocks(range) {
method convertLineBreaksToBlockBreaksInRange (line 413) | convertLineBreaksToBlockBreaksInRange(range) {
method consolidateBlocksAtRange (line 427) | consolidateBlocksAtRange(range) {
method getDocumentAtRange (line 435) | getDocumentAtRange(range) {
method getStringAtRange (line 441) | getStringAtRange(range) {
method getBlockAtIndex (line 451) | getBlockAtIndex(index) {
method getBlockAtPosition (line 455) | getBlockAtPosition(position) {
method getTextAtIndex (line 460) | getTextAtIndex(index) {
method getTextAtPosition (line 464) | getTextAtPosition(position) {
method getPieceAtPosition (line 469) | getPieceAtPosition(position) {
method getCharacterAtPosition (line 474) | getCharacterAtPosition(position) {
method getLength (line 479) | getLength() {
method getBlocks (line 483) | getBlocks() {
method getBlockCount (line 487) | getBlockCount() {
method getEditCount (line 491) | getEditCount() {
method eachBlock (line 495) | eachBlock(callback) {
method eachBlockAtRange (line 499) | eachBlockAtRange(range, callback) {
method getCommonAttributesAtRange (line 530) | getCommonAttributesAtRange(range) {
method getCommonAttributesAtPosition (line 552) | getCommonAttributesAtPosition(position) {
method getRangeOfCommonAttributeAtPosition (line 577) | getRangeOfCommonAttributeAtPosition(attributeName, position) {
method getBaseBlockAttributes (line 587) | getBaseBlockAttributes() {
method getAttachmentById (line 609) | getAttachmentById(attachmentId) {
method getAttachmentPieces (line 617) | getAttachmentPieces() {
method getAttachments (line 623) | getAttachments() {
method getRangeOfAttachment (line 627) | getRangeOfAttachment(attachment) {
method getLocationRangeOfAttachment (line 640) | getLocationRangeOfAttachment(attachment) {
method getAttachmentPieceForAttachment (line 645) | getAttachmentPieceForAttachment(attachment) {
method findRangesForBlockAttribute (line 653) | findRangesForBlockAttribute(attributeName) {
method findRangesForTextAttribute (line 668) | findRangesForTextAttribute(attributeName, { withValue } = {}) {
method locationFromPosition (line 696) | locationFromPosition(position) {
method positionFromLocation (line 706) | positionFromLocation(location) {
method locationRangeFromPosition (line 710) | locationRangeFromPosition(position) {
method locationRangeFromRange (line 714) | locationRangeFromRange(range) {
method rangeFromLocationRange (line 724) | rangeFromLocationRange(locationRange) {
method isEqualTo (line 734) | isEqualTo(document) {
method getTexts (line 738) | getTexts() {
method getPieces (line 742) | getPieces() {
method getObjects (line 752) | getObjects() {
method toSerializableDocument (line 756) | toSerializableDocument() {
method toString (line 762) | toString() {
method toJSON (line 766) | toJSON() {
method toConsole (line 770) | toConsole() {
FILE: src/trix/models/editor.js
constant DEFAULT_FILTERS (line 6) | const DEFAULT_FILTERS = [ attachmentGalleryFilter ]
class Editor (line 8) | class Editor {
method constructor (line 9) | constructor(composition, selectionManager, element) {
method loadDocument (line 18) | loadDocument(document) {
method loadHTML (line 22) | loadHTML(html = "") {
method loadJSON (line 27) | loadJSON({ document, selectedRange }) {
method loadSnapshot (line 32) | loadSnapshot(snapshot) {
method getDocument (line 37) | getDocument() {
method getSelectedDocument (line 41) | getSelectedDocument() {
method getSnapshot (line 45) | getSnapshot() {
method toJSON (line 49) | toJSON() {
method deleteInDirection (line 55) | deleteInDirection(direction) {
method insertAttachment (line 59) | insertAttachment(attachment) {
method insertAttachments (line 63) | insertAttachments(attachments) {
method insertDocument (line 67) | insertDocument(document) {
method insertFile (line 71) | insertFile(file) {
method insertFiles (line 75) | insertFiles(files) {
method insertHTML (line 79) | insertHTML(html) {
method insertString (line 83) | insertString(string) {
method insertText (line 87) | insertText(text) {
method insertLineBreak (line 91) | insertLineBreak() {
method getSelectedRange (line 97) | getSelectedRange() {
method getPosition (line 101) | getPosition() {
method getClientRectAtPosition (line 105) | getClientRectAtPosition(position) {
method expandSelectionInDirection (line 110) | expandSelectionInDirection(direction) {
method moveCursorInDirection (line 114) | moveCursorInDirection(direction) {
method setSelectedRange (line 118) | setSelectedRange(selectedRange) {
method activateAttribute (line 124) | activateAttribute(name, value = true) {
method attributeIsActive (line 128) | attributeIsActive(name) {
method canActivateAttribute (line 132) | canActivateAttribute(name) {
method deactivateAttribute (line 136) | deactivateAttribute(name) {
method setHTMLAtributeAtPosition (line 141) | setHTMLAtributeAtPosition(position, name, value) {
method canDecreaseNestingLevel (line 147) | canDecreaseNestingLevel() {
method canIncreaseNestingLevel (line 151) | canIncreaseNestingLevel() {
method decreaseNestingLevel (line 155) | decreaseNestingLevel() {
method increaseNestingLevel (line 161) | increaseNestingLevel() {
method canRedo (line 169) | canRedo() {
method canUndo (line 173) | canUndo() {
method recordUndoEntry (line 177) | recordUndoEntry(description, { context, consolidatable } = {}) {
method redo (line 181) | redo() {
method undo (line 187) | undo() {
FILE: src/trix/models/flaky_android_keyboard_detector.js
class FlakyAndroidKeyboardDetector (line 7) | class FlakyAndroidKeyboardDetector {
method constructor (line 8) | constructor(element) {
method shouldIgnore (line 12) | shouldIgnore(event) {
method checkSamsungKeyboardBuggyModeStart (line 30) | checkSamsungKeyboardBuggyModeStart() {
method checkSamsungKeyboardBuggyModeEnd (line 38) | checkSamsungKeyboardBuggyModeEnd() {
method insertingLongTextAfterUnidentifiedChar (line 44) | insertingLongTextAfterUnidentifiedChar() {
method isBeforeInputInsertText (line 48) | isBeforeInputInsertText() {
method previousEventWasUnidentifiedKeydown (line 52) | previousEventWasUnidentifiedKeydown() {
FILE: src/trix/models/html_parser.js
class HTMLParser (line 62) | class HTMLParser extends BasicObject {
method parse (line 63) | static parse(html, options) {
method constructor (line 69) | constructor(html, { referenceElement, purifyOptions } = {}) {
method getDocument (line 79) | getDocument() {
method parse (line 85) | parse() {
method createHiddenContainer (line 99) | createHiddenContainer() {
method removeHiddenContainer (line 112) | removeHiddenContainer() {
method processNode (line 116) | processNode(node) {
method appendBlockForTextNode (line 130) | appendBlockForTextNode(node) {
method appendBlockForElement (line 144) | appendBlockForElement(element) {
method findParentBlockElement (line 172) | findParentBlockElement(element) {
method processTextNode (line 184) | processTextNode(node) {
method processElement (line 195) | processElement(element) {
method appendBlockForAttributesWithElement (line 238) | appendBlockForAttributesWithElement(attributes, element, htmlAttribute...
method appendEmptyBlock (line 245) | appendEmptyBlock() {
method appendStringWithAttributes (line 249) | appendStringWithAttributes(string, attributes) {
method appendAttachmentWithAttributes (line 253) | appendAttachmentWithAttributes(attachment, attributes) {
method appendPiece (line 257) | appendPiece(piece) {
method appendStringToTextAtIndex (line 264) | appendStringToTextAtIndex(string, index) {
method prependStringToTextAtIndex (line 275) | prependStringToTextAtIndex(string, index) {
method getTextAttributes (line 288) | getTextAttributes(element) {
method getBlockAttributes (line 334) | getBlockAttributes(element) {
method getBlockHTMLAttributes (line 355) | getBlockHTMLAttributes(element) {
method findBlockElementAncestors (line 369) | findBlockElementAncestors(element) {
method isBlockElement (line 383) | isBlockElement(element) {
method isInsignificantTextNode (line 392) | isInsignificantTextNode(node) {
method isExtraBR (line 401) | isExtraBR(element) {
method needsTableSeparator (line 405) | needsTableSeparator(element) {
method translateBlockElementMarginsToNewlines (line 416) | translateBlockElementMarginsToNewlines() {
method getMarginOfBlockElementAtIndex (line 433) | getMarginOfBlockElementAtIndex(index) {
method getMarginOfDefaultBlockElement (line 444) | getMarginOfDefaultBlockElement() {
FILE: src/trix/models/html_sanitizer.js
constant DEFAULT_ALLOWED_ATTRIBUTES (line 19) | const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height language...
constant DEFAULT_FORBIDDEN_PROTOCOLS (line 20) | const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ")
constant DEFAULT_FORBIDDEN_ELEMENTS (line 21) | const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form noscript".split(" ")
class HTMLSanitizer (line 23) | class HTMLSanitizer extends BasicObject {
method setHTML (line 24) | static setHTML(element, html, options) {
method sanitize (line 30) | static sanitize(html, options) {
method constructor (line 36) | constructor(html, { allowedAttributes, forbiddenProtocols, forbiddenEl...
method sanitize (line 45) | sanitize() {
method getHTML (line 55) | getHTML() {
method getBody (line 59) | getBody() {
method sanitizeElements (line 65) | sanitizeElements() {
method sanitizeElement (line 90) | sanitizeElement(element) {
method normalizeListElementNesting (line 106) | normalizeListElementNesting() {
method elementIsRemovable (line 119) | elementIsRemovable(element) {
method elementIsForbidden (line 124) | elementIsForbidden(element) {
method elementIsntSerializable (line 128) | elementIsntSerializable(element) {
FILE: src/trix/models/line_break_insertion.js
class LineBreakInsertion (line 1) | class LineBreakInsertion {
method constructor (line 2) | constructor(composition) {
method shouldInsertBlockBreak (line 18) | shouldInsertBlockBreak() {
method shouldBreakFormattedBlock (line 26) | shouldBreakFormattedBlock() {
method shouldDecreaseListLevel (line 34) | shouldDecreaseListLevel() {
method shouldPrependListItem (line 38) | shouldPrependListItem() {
method shouldRemoveLastBlockAttribute (line 42) | shouldRemoveLastBlockAttribute() {
FILE: src/trix/models/location_mapper.js
class LocationMapper (line 19) | class LocationMapper {
method constructor (line 20) | constructor(element) {
method findLocationFromContainerAndOffset (line 24) | findLocationFromContainerAndOffset(container, offset, { strict } = { s...
method findContainerAndOffsetFromLocation (line 78) | findContainerAndOffsetFromLocation(location) {
method findNodeAndOffsetFromLocation (line 133) | findNodeAndOffsetFromLocation(location) {
method findAttachmentElementParentForNode (line 164) | findAttachmentElementParentForNode(node) {
method getSignificantNodesForIndex (line 173) | getSignificantNodesForIndex(index) {
FILE: src/trix/models/managed_attachment.js
class ManagedAttachment (line 4) | class ManagedAttachment extends BasicObject {
method constructor (line 5) | constructor(attachmentManager, attachment) {
method remove (line 13) | remove() {
FILE: src/trix/models/piece.js
class Piece (line 4) | class Piece extends TrixObject {
method registerType (line 7) | static registerType(type, constructor) {
method fromJSON (line 12) | static fromJSON(pieceJSON) {
method constructor (line 19) | constructor(value, attributes = {}) {
method copyWithAttributes (line 24) | copyWithAttributes(attributes) {
method copyWithAdditionalAttributes (line 28) | copyWithAdditionalAttributes(attributes) {
method copyWithoutAttribute (line 32) | copyWithoutAttribute(attribute) {
method copy (line 36) | copy() {
method getAttribute (line 40) | getAttribute(attribute) {
method getAttributesHash (line 44) | getAttributesHash() {
method getAttributes (line 48) | getAttributes() {
method hasAttribute (line 52) | hasAttribute(attribute) {
method hasSameStringValueAsPiece (line 56) | hasSameStringValueAsPiece(piece) {
method hasSameAttributesAsPiece (line 60) | hasSameAttributesAsPiece(piece) {
method isBlockBreak (line 64) | isBlockBreak() {
method isEqualTo (line 68) | isEqualTo(piece) {
method isEmpty (line 77) | isEmpty() {
method isSerializable (line 81) | isSerializable() {
method toJSON (line 85) | toJSON() {
method contentsForInspection (line 92) | contentsForInspection() {
method canBeGrouped (line 101) | canBeGrouped() {
method canBeGroupedWith (line 105) | canBeGroupedWith(piece) {
method getLength (line 111) | getLength() {
method canBeConsolidatedWith (line 115) | canBeConsolidatedWith(piece) {
FILE: src/trix/models/point_mapper.js
class PointMapper (line 7) | class PointMapper {
method createDOMRangeFromPoint (line 8) | createDOMRangeFromPoint({ x, y }) {
method getClientRectsForDOMRange (line 32) | getClientRectsForDOMRange(domRange) {
FILE: src/trix/models/selection_manager.js
class SelectionManager (line 21) | class SelectionManager extends BasicObject {
method constructor (line 22) | constructor(element) {
method getLocationRange (line 33) | getLocationRange(options = {}) {
method setLocationRange (line 45) | setLocationRange(locationRange) {
method setLocationRangeFromPointRange (line 56) | setLocationRangeFromPointRange(pointRange) {
method getClientRectAtLocationRange (line 63) | getClientRectAtLocationRange(locationRange) {
method locationIsCursorTarget (line 70) | locationIsCursorTarget(location) {
method lock (line 75) | lock() {
method unlock (line 82) | unlock() {
method clearSelection (line 92) | clearSelection() {
method selectionIsCollapsed (line 96) | selectionIsCollapsed() {
method selectionIsExpanded (line 100) | selectionIsExpanded() {
method createLocationRangeFromDOMRange (line 104) | createLocationRangeFromDOMRange(domRange, options) {
method didMouseDown (line 117) | didMouseDown() {
method pauseTemporarily (line 121) | pauseTemporarily() {
method selectionDidChange (line 145) | selectionDidChange() {
method updateCurrentLocationRange (line 151) | updateCurrentLocationRange(locationRange) {
method createDOMRangeFromLocationRange (line 160) | createDOMRangeFromLocationRange(locationRange) {
method getLocationAtPoint (line 174) | getLocationAtPoint(point) {
method domRangeWithinElement (line 181) | domRangeWithinElement(domRange) {
FILE: src/trix/models/splittable_list.js
class SplittableList (line 8) | class SplittableList extends TrixObject {
method box (line 9) | static box(objects) {
method constructor (line 17) | constructor(objects = []) {
method indexOf (line 23) | indexOf(object) {
method splice (line 27) | splice(...args) {
method eachObject (line 31) | eachObject(callback) {
method insertObjectAtIndex (line 35) | insertObjectAtIndex(object, index) {
method insertSplittableListAtIndex (line 39) | insertSplittableListAtIndex(splittableList, index) {
method insertSplittableListAtPosition (line 43) | insertSplittableListAtPosition(splittableList, position) {
method editObjectAtIndex (line 48) | editObjectAtIndex(index, callback) {
method replaceObjectAtIndex (line 52) | replaceObjectAtIndex(object, index) {
method removeObjectAtIndex (line 56) | removeObjectAtIndex(index) {
method getObjectAtIndex (line 60) | getObjectAtIndex(index) {
method getSplittableListInRange (line 64) | getSplittableListInRange(range) {
method selectSplittableList (line 69) | selectSplittableList(test) {
method removeObjectsInRange (line 74) | removeObjectsInRange(range) {
method transformObjectsInRange (line 79) | transformObjectsInRange(range, transform) {
method splitObjectsAtRange (line 87) | splitObjectsAtRange(range) {
method getObjectAtPosition (line 95) | getObjectAtPosition(position) {
method splitObjectAtPosition (line 100) | splitObjectAtPosition(position) {
method consolidate (line 123) | consolidate() {
method consolidateFromIndexToIndex (line 143) | consolidateFromIndexToIndex(startIndex, endIndex) {
method findIndexAndOffsetAtPosition (line 150) | findIndexAndOffsetAtPosition(position) {
method findPositionAtIndexAndOffset (line 164) | findPositionAtIndexAndOffset(index, offset) {
method getEndPosition (line 178) | getEndPosition() {
method toString (line 187) | toString() {
method toArray (line 191) | toArray() {
method toJSON (line 195) | toJSON() {
method isEqualTo (line 199) | isEqualTo(splittableList) {
method contentsForInspection (line 203) | contentsForInspection() {
FILE: src/trix/models/string_piece.js
class StringPiece (line 5) | class StringPiece extends Piece {
method fromJSON (line 6) | static fromJSON(pieceJSON) {
method constructor (line 10) | constructor(string) {
method getValue (line 16) | getValue() {
method toString (line 20) | toString() {
method isBlockBreak (line 24) | isBlockBreak() {
method toJSON (line 28) | toJSON() {
method canBeConsolidatedWith (line 36) | canBeConsolidatedWith(piece) {
method consolidateWith (line 40) | consolidateWith(piece) {
method splitAtOffset (line 44) | splitAtOffset(offset) {
method toConsole (line 59) | toConsole() {
FILE: src/trix/models/text.js
class Text (line 12) | class Text extends TrixObject {
method textForAttachmentWithAttributes (line 13) | static textForAttachmentWithAttributes(attachment, attributes) {
method textForStringWithAttributes (line 18) | static textForStringWithAttributes(string, attributes) {
method fromJSON (line 23) | static fromJSON(textJSON) {
method constructor (line 28) | constructor(pieces = []) {
method copy (line 34) | copy() {
method copyWithPieceList (line 38) | copyWithPieceList(pieceList) {
method copyUsingObjectMap (line 42) | copyUsingObjectMap(objectMap) {
method appendText (line 47) | appendText(text) {
method insertTextAtPosition (line 51) | insertTextAtPosition(text, position) {
method removeTextAtRange (line 55) | removeTextAtRange(range) {
method replaceTextAtRange (line 59) | replaceTextAtRange(text, range) {
method moveTextFromRangeToPosition (line 63) | moveTextFromRangeToPosition(range, position) {
method addAttributeAtRange (line 73) | addAttributeAtRange(attribute, value, range) {
method addAttributesAtRange (line 79) | addAttributesAtRange(attributes, range) {
method removeAttributeAtRange (line 85) | removeAttributeAtRange(attribute, range) {
method setAttributesAtRange (line 91) | setAttributesAtRange(attributes, range) {
method getAttributesAtPosition (line 97) | getAttributesAtPosition(position) {
method getCommonAttributes (line 101) | getCommonAttributes() {
method getCommonAttributesAtRange (line 106) | getCommonAttributesAtRange(range) {
method getExpandedRangeForAttributeAtOffset (line 110) | getExpandedRangeForAttributeAtOffset(attributeName, offset) {
method getTextAtRange (line 125) | getTextAtRange(range) {
method getStringAtRange (line 129) | getStringAtRange(range) {
method getStringAtPosition (line 133) | getStringAtPosition(position) {
method startsWithString (line 137) | startsWithString(string) {
method endsWithString (line 141) | endsWithString(string) {
method getAttachmentPieces (line 146) | getAttachmentPieces() {
method getAttachments (line 150) | getAttachments() {
method getAttachmentAndPositionById (line 154) | getAttachmentAndPositionById(attachmentId) {
method getAttachmentById (line 165) | getAttachmentById(attachmentId) {
method getRangeOfAttachment (line 170) | getRangeOfAttachment(attachment) {
method updateAttributesForAttachment (line 179) | updateAttributesForAttachment(attributes, attachment) {
method getLength (line 188) | getLength() {
method isEmpty (line 192) | isEmpty() {
method isEqualTo (line 196) | isEqualTo(text) {
method isBlockBreak (line 200) | isBlockBreak() {
method eachPiece (line 204) | eachPiece(callback) {
method getPieces (line 208) | getPieces() {
method getPieceAtPosition (line 212) | getPieceAtPosition(position) {
method contentsForInspection (line 216) | contentsForInspection() {
method toSerializableText (line 220) | toSerializableText() {
method toString (line 225) | toString() {
method toJSON (line 229) | toJSON() {
method toConsole (line 233) | toConsole() {
method getDirection (line 239) | getDirection() {
method isRTL (line 243) | isRTL() {
FILE: src/trix/models/undo_manager.js
class UndoManager (line 3) | class UndoManager extends BasicObject {
method constructor (line 4) | constructor(composition) {
method recordUndoEntry (line 11) | recordUndoEntry(description, { context, consolidatable } = {}) {
method undo (line 21) | undo() {
method redo (line 30) | redo() {
method canUndo (line 39) | canUndo() {
method canRedo (line 43) | canRedo() {
method createEntry (line 49) | createEntry({ description, context } = {}) {
FILE: src/trix/observers/mutation_observer.js
class MutationObserver (line 23) | class MutationObserver extends BasicObject {
method constructor (line 24) | constructor(element) {
method start (line 32) | start() {
method stop (line 37) | stop() {
method didMutate (line 41) | didMutate(mutations) {
method reset (line 52) | reset() {
method findSignificantMutations (line 56) | findSignificantMutations(mutations) {
method mutationIsSignificant (line 62) | mutationIsSignificant(mutation) {
method nodeIsSignificant (line 72) | nodeIsSignificant(node) {
method nodeIsMutable (line 76) | nodeIsMutable(node) {
method nodesModifiedByMutation (line 80) | nodesModifiedByMutation(mutation) {
method getMutationSummary (line 102) | getMutationSummary() {
method getTextMutationSummary (line 106) | getTextMutationSummary() {
method getMutationsByType (line 133) | getMutationsByType(type) {
method getTextChangesFromChildList (line 137) | getTextChangesFromChildList() {
method getTextChangesFromCharacterData (line 164) | getTextChangesFromCharacterData() {
FILE: src/trix/observers/selection_change_observer.js
class SelectionChangeObserver (line 3) | class SelectionChangeObserver extends BasicObject {
method constructor (line 4) | constructor() {
method start (line 10) | start() {
method stop (line 17) | stop() {
method registerSelectionManager (line 24) | registerSelectionManager(selectionManager) {
method unregisterSelectionManager (line 31) | unregisterSelectionManager(selectionManager) {
method notifySelectionManagersOfSelectionChange (line 38) | notifySelectionManagersOfSelectionChange() {
method update (line 42) | update() {
method reset (line 46) | reset() {
FILE: src/trix/operations/file_verification_operation.js
class FileVerificationOperation (line 6) | class FileVerificationOperation extends Operation {
method constructor (line 7) | constructor(file) {
method perform (line 12) | perform(callback) {
FILE: src/trix/operations/image_preload_operation.js
class ImagePreloadOperation (line 3) | class ImagePreloadOperation extends Operation {
method constructor (line 4) | constructor(url) {
method perform (line 9) | perform(callback) {
FILE: src/trix/trix.js
function start (line 29) | function start() {
FILE: src/trix/views/attachment_view.js
class AttachmentView (line 10) | class AttachmentView extends ObjectView {
method constructor (line 11) | constructor() {
method createContentNodes (line 18) | createContentNodes() {
method createNodes (line 22) | createNodes() {
method createCaptionElement (line 67) | createCaptionElement() {
method getClassName (line 100) | getClassName() {
method getData (line 109) | getData() {
method getHref (line 128) | getHref() {
method getCaptionConfig (line 137) | getCaptionConfig() {
method findProgressElement (line 146) | findProgressElement() {
method attachmentDidChangeUploadProgress (line 152) | attachmentDidChangeUploadProgress() {
FILE: src/trix/views/block_view.js
class BlockView (line 8) | class BlockView extends ObjectView {
method constructor (line 9) | constructor() {
method createNodes (line 15) | createNodes() {
method createContainerElement (line 44) | createContainerElement(depth) {
method shouldAddExtraNewlineElement (line 71) | shouldAddExtraNewlineElement() {
FILE: src/trix/views/document_view.js
class DocumentView (line 10) | class DocumentView extends ObjectView {
method render (line 11) | static render(document) {
method constructor (line 19) | constructor() {
method setDocument (line 26) | setDocument(document) {
method render (line 32) | render() {
method isSynced (line 47) | isSynced() {
method sync (line 51) | sync() {
method didSync (line 69) | didSync() {
method createDocumentFragmentForSync (line 74) | createDocumentFragmentForSync() {
FILE: src/trix/views/object_view.js
class ObjectView (line 4) | class ObjectView extends BasicObject {
method constructor (line 5) | constructor(object, options = {}) {
method getNodes (line 13) | getNodes() {
method invalidate (line 18) | invalidate() {
method invalidateViewForObject (line 24) | invalidateViewForObject(object) {
method findOrCreateCachedChildView (line 28) | findOrCreateCachedChildView(viewClass, object, options) {
method createChildView (line 39) | createChildView(viewClass, object, options = {}) {
method recordChildView (line 49) | recordChildView(view) {
method getAllChildViews (line 56) | getAllChildViews() {
method findElement (line 67) | findElement() {
method findElementForObject (line 71) | findElementForObject(object) {
method findViewForObject (line 78) | findViewForObject(object) {
method getViewCache (line 86) | getViewCache() {
method isViewCachingEnabled (line 97) | isViewCachingEnabled() {
method enableViewCaching (line 101) | enableViewCaching() {
method disableViewCaching (line 105) | disableViewCaching() {
method getCachedViewForObject (line 109) | getCachedViewForObject(object) {
method cacheViewForObject (line 113) | cacheViewForObject(view, object) {
method garbageCollectCachedViews (line 120) | garbageCollectCachedViews() {
class ObjectGroupView (line 134) | class ObjectGroupView extends ObjectView {
method constructor (line 135) | constructor() {
method getChildViews (line 142) | getChildViews() {
method createNodes (line 151) | createNodes() {
method createContainerElement (line 163) | createContainerElement(depth = this.objectGroup.getDepth()) {
FILE: src/trix/views/piece_view.js
class PieceView (line 13) | class PieceView extends ObjectView {
method constructor (line 14) | constructor() {
method createNodes (line 28) | createNodes() {
method createAttachmentNodes (line 41) | createAttachmentNodes() {
method createStringNodes (line 48) | createStringNodes() {
method createElement (line 70) | createElement() {
method createContainerElement (line 113) | createContainerElement() {
method preserveSpaces (line 127) | preserveSpaces(string) {
FILE: src/trix/views/previewable_attachment_view.js
class PreviewableAttachmentView (line 6) | class PreviewableAttachmentView extends AttachmentView {
method constructor (line 7) | constructor() {
method createContentNodes (line 12) | createContentNodes() {
method createCaptionElement (line 27) | createCaptionElement() {
method refresh (line 35) | refresh(image) {
method updateAttributesForImage (line 42) | updateAttributesForImage(image) {
method attachmentDidChangeAttributes (line 74) | attachmentDidChangeAttributes() {
FILE: src/trix/views/text_view.js
class TextView (line 8) | class TextView extends ObjectView {
method constructor (line 9) | constructor() {
method createNodes (line 15) | createNodes() {
method getPieces (line 41) | getPieces() {
FILE: web-test-runner.config.mjs
function translateStack (line 15) | function translateStack(stack) {
method onTestRunFinished (line 157) | onTestRunFinished({ sessions }) {
Condensed preview — 282 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,364K chars).
[
{
"path": ".eslintrc",
"chars": 1509,
"preview": "{\n \"parser\": \"babel-eslint\",\n \"extends\": \"eslint:recommended\",\n \"rules\": {\n \"array-bracket-spacing\": [\"error\", \"al"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 153,
"preview": "Describe the bug or issue here…\n\n##### Steps to Reproduce\n\n1. \n2. \n3. \n\n##### Details\n\n* Trix version: \n* Browser name a"
},
{
"path": ".github/stale.yml",
"chars": 834,
"preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 90\n# Number of days of inactivity before a "
},
{
"path": ".github/workflows/ci.yml",
"chars": 4068,
"preview": "name: CI\n\nconcurrency:\n group: \"${{github.workflow}}-${{github.ref}}\"\n cancel-in-progress: true\n\non:\n workflow_dispat"
},
{
"path": ".gitignore",
"chars": 58,
"preview": "yarn-error.log\npackage-lock.json\n/dist\n/node_modules\n/tmp\n"
},
{
"path": ".node-version",
"chars": 8,
"preview": "18.18.0\n"
},
{
"path": ".npmignore",
"chars": 71,
"preview": ".DS_Store\n/node_modules\n/.github\n/bin\n/assets\nyarn-error.log\nyarn.lock\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3338,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "LICENSE",
"chars": 1053,
"preview": "Copyright (c) 37signals, LLC\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this softw"
},
{
"path": "README.md",
"chars": 30738,
"preview": "# Trix\n### A Rich Text Editor for Everyday Writing\n\n**Compose beautifully formatted text in your web application.** Trix"
},
{
"path": "action_text-trix/.gitignore",
"chars": 44,
"preview": "Gemfile.lock\npkg\ntmp/\nlog/\nstorage/\nvendor/\n"
},
{
"path": "action_text-trix/Gemfile",
"chars": 404,
"preview": "source \"https://rubygems.org\"\n\n# Specify your gem's dependencies in trix.gemspec.\ngemspec\n\nbranch = ENV.fetch(\"RAILS_BRA"
},
{
"path": "action_text-trix/LICENSE",
"chars": 1053,
"preview": "Copyright (c) 37signals, LLC\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this softw"
},
{
"path": "action_text-trix/README.md",
"chars": 182,
"preview": "## Building the Trix Ruby gem\n\n1. `cd action_text-trix`\n2. `bundle exec rake sync` (updates files which must be committe"
},
{
"path": "action_text-trix/Rakefile",
"chars": 688,
"preview": "require \"bundler/gem_tasks\"\nrequire \"rake/clean\"\n\nif defined?(Rails)\n APP_RAKEFILE = File.expand_path(\"test/dummy/Rakef"
},
{
"path": "action_text-trix/action_text-trix.gemspec",
"chars": 820,
"preview": "require_relative \"lib/action_text/trix/version\"\n\nGem::Specification.new do |spec|\n spec.name = \"action_text-trix\"\n "
},
{
"path": "action_text-trix/app/assets/javascripts/.gitattributes",
"chars": 38,
"preview": "trix.js linguist-vendored -whitespace\n"
},
{
"path": "action_text-trix/app/assets/javascripts/trix.js",
"chars": 519891,
"preview": "/*\nTrix 2.1.17\nCopyright © 2026 37signals, LLC\n */\n(function (global, factory) {\n typeof exports === 'object' && typeof"
},
{
"path": "action_text-trix/app/assets/stylesheets/trix.css",
"chars": 19636,
"preview": "@charset \"UTF-8\";\ntrix-editor {\n border: 1px solid #bbb;\n border-radius: 3px;\n margin: 0;\n padding: 0.4em 0.6em;\n m"
},
{
"path": "action_text-trix/bin/rails",
"chars": 595,
"preview": "#!/usr/bin/env ruby\n# This command will automatically be run when you run \"rails\" with Rails gems\n# installed from the r"
},
{
"path": "action_text-trix/lib/action_text/trix/engine.rb",
"chars": 215,
"preview": "module Trix\n class Engine < ::Rails::Engine\n initializer \"trix.asset\" do |app|\n if app.config.respond_to?(:asse"
},
{
"path": "action_text-trix/lib/action_text/trix/version.rb",
"chars": 37,
"preview": "module Trix\n VERSION = \"2.1.17\"\nend\n"
},
{
"path": "action_text-trix/lib/action_text/trix.rb",
"chars": 63,
"preview": "require_relative \"trix/version\"\nrequire_relative \"trix/engine\"\n"
},
{
"path": "action_text-trix/test/application_system_test_case.rb",
"chars": 277,
"preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nclass ApplicationSystemTestCase < ActionDispatch::SystemTestCase\n "
},
{
"path": "action_text-trix/test/dummy/Rakefile",
"chars": 227,
"preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
},
{
"path": "action_text-trix/test/dummy/app/assets/images/.keep",
"chars": 0,
"preview": ""
},
{
"path": "action_text-trix/test/dummy/app/assets/stylesheets/actiontext.css",
"chars": 20947,
"preview": "/*\n * Default Trix editor styles. See Action Text overwrites below.\n*/\n\ntrix-editor {\n border: 1px solid #bbb;\n border"
},
{
"path": "action_text-trix/test/dummy/app/assets/stylesheets/application.css",
"chars": 736,
"preview": "/*\n * This is a manifest file that'll be compiled into application.css, which will include all the files\n * listed below"
},
{
"path": "action_text-trix/test/dummy/app/controllers/application_controller.rb",
"chars": 204,
"preview": "class ApplicationController < ActionController::Base\n # Only allow modern browsers supporting webp images, web push, ba"
},
{
"path": "action_text-trix/test/dummy/app/controllers/concerns/.keep",
"chars": 0,
"preview": ""
},
{
"path": "action_text-trix/test/dummy/app/controllers/messages_controller.rb",
"chars": 457,
"preview": "class MessagesController < ApplicationController\n def index\n @messages = Message.all\n end\n\n def new\n @message ="
},
{
"path": "action_text-trix/test/dummy/app/javascript/application.js",
"chars": 119,
"preview": "// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails\nimport \"trix\"\n"
},
{
"path": "action_text-trix/test/dummy/app/models/application_record.rb",
"chars": 74,
"preview": "class ApplicationRecord < ActiveRecord::Base\n primary_abstract_class\nend\n"
},
{
"path": "action_text-trix/test/dummy/app/models/concerns/.keep",
"chars": 0,
"preview": ""
},
{
"path": "action_text-trix/test/dummy/app/models/message.rb",
"chars": 63,
"preview": "class Message < ApplicationRecord\n has_rich_text :content\nend\n"
},
{
"path": "action_text-trix/test/dummy/app/views/active_storage/blobs/_blob.html.erb",
"chars": 605,
"preview": "<figure class=\"attachment attachment--<%= blob.representable? ? \"preview\" : \"file\" %> attachment--<%= blob.filename.exte"
},
{
"path": "action_text-trix/test/dummy/app/views/layouts/action_text/contents/_content.html.erb",
"chars": 50,
"preview": "<div class=\"trix-content\">\n <%= yield -%>\n</div>\n"
},
{
"path": "action_text-trix/test/dummy/app/views/layouts/application.html.erb",
"chars": 892,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <title><%= content_for(:title) || \"Dummy\" %></title>\n <meta name=\"viewport\" conte"
},
{
"path": "action_text-trix/test/dummy/app/views/layouts/mailer.html.erb",
"chars": 227,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <style>\n "
},
{
"path": "action_text-trix/test/dummy/app/views/layouts/mailer.text.erb",
"chars": 13,
"preview": "<%= yield %>\n"
},
{
"path": "action_text-trix/test/dummy/app/views/messages/_form.html.erb",
"chars": 221,
"preview": "<%= form_with(model: message) do |form| %>\n <%= form.label :subject %> <br>\n <%= form.text_field :subject %> <br>\n\n <"
},
{
"path": "action_text-trix/test/dummy/app/views/messages/index.html.erb",
"chars": 299,
"preview": "<h1>Messages</h1>\n\n<table>\n <thead>\n <tr>\n <th>Subject</th>\n <th>Content</th>\n </tr>\n </thead>\n\n <tbo"
},
{
"path": "action_text-trix/test/dummy/app/views/messages/new.html.erb",
"chars": 62,
"preview": "<h1>New Message</h1>\n\n<%= render \"form\", message: @message %>\n"
},
{
"path": "action_text-trix/test/dummy/app/views/pwa/manifest.json.erb",
"chars": 393,
"preview": "{\n \"name\": \"Dummy\",\n \"icons\": [\n {\n \"src\": \"/icon.png\",\n \"type\": \"image/png\",\n \"sizes\": \"512x512\"\n "
},
{
"path": "action_text-trix/test/dummy/app/views/pwa/service-worker.js",
"chars": 876,
"preview": "// Add a service worker for processing Web Push notifications:\n//\n// self.addEventListener(\"push\", async (event) => {\n//"
},
{
"path": "action_text-trix/test/dummy/bin/dev",
"chars": 56,
"preview": "#!/usr/bin/env ruby\nexec \"./bin/rails\", \"server\", *ARGV\n"
},
{
"path": "action_text-trix/test/dummy/bin/importmap",
"chars": 91,
"preview": "#!/usr/bin/env ruby\n\nrequire_relative \"../config/application\"\nrequire \"importmap/commands\"\n"
},
{
"path": "action_text-trix/test/dummy/bin/rails",
"chars": 141,
"preview": "#!/usr/bin/env ruby\nAPP_PATH = File.expand_path(\"../config/application\", __dir__)\nrequire_relative \"../config/boot\"\nrequ"
},
{
"path": "action_text-trix/test/dummy/bin/rake",
"chars": 90,
"preview": "#!/usr/bin/env ruby\nrequire_relative \"../config/boot\"\nrequire \"rake\"\nRake.application.run\n"
},
{
"path": "action_text-trix/test/dummy/bin/setup",
"chars": 1010,
"preview": "#!/usr/bin/env ruby\nrequire \"fileutils\"\n\nAPP_ROOT = File.expand_path(\"..\", __dir__)\n\ndef system!(*args)\n system(*args, "
},
{
"path": "action_text-trix/test/dummy/config/application.rb",
"chars": 1111,
"preview": "require_relative \"boot\"\n\nrequire \"rails/all\"\n\n# Require the gems listed in Gemfile, including any gems\n# you've limited "
},
{
"path": "action_text-trix/test/dummy/config/boot.rb",
"chars": 233,
"preview": "# Set up gems listed in the Gemfile.\nENV[\"BUNDLE_GEMFILE\"] ||= File.expand_path(\"../../../Gemfile\", __dir__)\n\nrequire \"b"
},
{
"path": "action_text-trix/test/dummy/config/cable.yml",
"chars": 186,
"preview": "development:\n adapter: async\n\ntest:\n adapter: test\n\nproduction:\n adapter: redis\n url: <%= ENV.fetch(\"REDIS_URL\") { \""
},
{
"path": "action_text-trix/test/dummy/config/database.yml",
"chars": 992,
"preview": "# SQLite. Versions 3.8.0 and up are supported.\n# gem install sqlite3\n#\n# Ensure the SQLite 3 gem is defined in your "
},
{
"path": "action_text-trix/test/dummy/config/environment.rb",
"chars": 128,
"preview": "# Load the Rails application.\nrequire_relative \"application\"\n\n# Initialize the Rails application.\nRails.application.init"
},
{
"path": "action_text-trix/test/dummy/config/environments/development.rb",
"chars": 2576,
"preview": "require \"active_support/core_ext/integer/time\"\n\nRails.application.configure do\n # Settings specified here will take pre"
},
{
"path": "action_text-trix/test/dummy/config/environments/production.rb",
"chars": 3661,
"preview": "require \"active_support/core_ext/integer/time\"\n\nRails.application.configure do\n # Settings specified here will take pre"
},
{
"path": "action_text-trix/test/dummy/config/environments/test.rb",
"chars": 1971,
"preview": "# The test environment is used exclusively to run your application's\n# test suite. You never need to work with it otherw"
},
{
"path": "action_text-trix/test/dummy/config/importmap.rb",
"chars": 77,
"preview": "# Pin npm packages by running ./bin/importmap\n\npin \"application\"\n\npin \"trix\"\n"
},
{
"path": "action_text-trix/test/dummy/config/initializers/assets.rb",
"chars": 296,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Version of your assets, change this if you want to expire"
},
{
"path": "action_text-trix/test/dummy/config/initializers/content_security_policy.rb",
"chars": 1071,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Define an application-wide content security policy.\n# See"
},
{
"path": "action_text-trix/test/dummy/config/initializers/filter_parameter_logging.rb",
"chars": 468,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Configure parameters to be partially matched (e.g. passw "
},
{
"path": "action_text-trix/test/dummy/config/initializers/inflections.rb",
"chars": 649,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format. Infl"
},
{
"path": "action_text-trix/test/dummy/config/locales/en.yml",
"chars": 908,
"preview": "# Files in the config/locales directory are used for internationalization and\n# are automatically loaded by Rails. If yo"
},
{
"path": "action_text-trix/test/dummy/config/puma.rb",
"chars": 1833,
"preview": "# This configuration file will be evaluated by Puma. The top-level methods that\n# are invoked here are part of Puma's co"
},
{
"path": "action_text-trix/test/dummy/config/routes.rb",
"chars": 59,
"preview": "Rails.application.routes.draw do\n resources :messages\nend\n"
},
{
"path": "action_text-trix/test/dummy/config/storage.yml",
"chars": 1152,
"preview": "test:\n service: Disk\n root: <%= Rails.root.join(\"tmp/storage\") %>\n\nlocal:\n service: Disk\n root: <%= Rails.root.join("
},
{
"path": "action_text-trix/test/dummy/config.ru",
"chars": 160,
"preview": "# This file is used by Rack-based servers to start the application.\n\nrequire_relative \"config/environment\"\n\nrun Rails.ap"
},
{
"path": "action_text-trix/test/dummy/db/migrate/20250926170812_create_active_storage_tables.active_storage.rb",
"chars": 2197,
"preview": "# This migration comes from active_storage (originally 20170806125915)\nclass CreateActiveStorageTables < ActiveRecord::M"
},
{
"path": "action_text-trix/test/dummy/db/migrate/20250926170813_create_action_text_tables.action_text.rb",
"chars": 982,
"preview": "# This migration comes from action_text (originally 20180528164100)\nclass CreateActionTextTables < ActiveRecord::Migrati"
},
{
"path": "action_text-trix/test/dummy/db/migrate/20250926170921_create_messages.rb",
"chars": 159,
"preview": "class CreateMessages < ActiveRecord::Migration[7.2]\n def change\n create_table :messages do |t|\n t.text :subject"
},
{
"path": "action_text-trix/test/dummy/db/schema.rb",
"chars": 2667,
"preview": "# This file is auto-generated from the current state of the database. Instead\n# of editing this file, please use the mig"
},
{
"path": "action_text-trix/test/dummy/public/400.html",
"chars": 6683,
"preview": "<!doctype html>\n\n<html lang=\"en\">\n\n <head>\n\n <title>The server cannot process the request due to a client error (400"
},
{
"path": "action_text-trix/test/dummy/public/404.html",
"chars": 4830,
"preview": "<!doctype html>\n\n<html lang=\"en\">\n\n <head>\n\n <title>The page you were looking for doesn’t exist (404 Not found)</tit"
},
{
"path": "action_text-trix/test/dummy/public/406-unsupported-browser.html",
"chars": 6912,
"preview": "<!doctype html>\n\n<html lang=\"en\">\n\n <head>\n\n <title>Your browser is not supported (406 Not Acceptable)</title>\n\n "
},
{
"path": "action_text-trix/test/dummy/public/422.html",
"chars": 8376,
"preview": "<!doctype html>\n\n<html lang=\"en\">\n\n <head>\n\n <title>The change you wanted was rejected (422 Unprocessable Entity)</t"
},
{
"path": "action_text-trix/test/dummy/public/500.html",
"chars": 7912,
"preview": "<!doctype html>\n\n<html lang=\"en\">\n\n <head>\n\n <title>We’re sorry, but something went wrong (500 Internal Server Error"
},
{
"path": "action_text-trix/test/fixtures/action_text/rich_texts.yml",
"chars": 114,
"preview": "# one:\n# record: name_of_fixture (ClassOfFixture)\n# name: content\n# body: <p>In a <i>million</i> stars!</p>\n"
},
{
"path": "action_text-trix/test/system/action_text_test.rb",
"chars": 342,
"preview": "# frozen_string_literal: true\n\nrequire \"application_system_test_case\"\n\nclass ActionTextTest < ApplicationSystemTestCase\n"
},
{
"path": "action_text-trix/test/test_helper.rb",
"chars": 721,
"preview": "# Configure Rails Environment\nENV[\"RAILS_ENV\"] = \"test\"\n\nrequire_relative \"../test/dummy/config/environment\"\nActiveRecor"
},
{
"path": "assets/index.html",
"chars": 2327,
"preview": "<!doctype html>\n<html>\n <head>\n <meta charset=\"UTF-8\">\n <title>Trix</title>\n <meta name=\"viewport\" content=\"wi"
},
{
"path": "assets/test.html",
"chars": 424,
"preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<title>Test Suite</title>\n<link rel=\"icon\" href=\"data:,\">\n<link rel=\"stylesheet\" "
},
{
"path": "assets/trix/images/README.md",
"chars": 332,
"preview": "# Trix Icons\n\nTrix's toolbar uses [Material Design Icons by Google][1], which are licensed under the [Creative Commons A"
},
{
"path": "assets/trix/stylesheets/attachments.scss",
"chars": 3367,
"preview": "@import \"./icons\";\n@import \"./selection\";\n\ntrix-editor {\n [data-trix-mutable],\n [data-trix-cursor-target] {\n @exten"
},
{
"path": "assets/trix/stylesheets/content.scss",
"chars": 2084,
"preview": "$quote-border-width: 0.3em;\n$quote-margin-start: 0.3em;\n$quote-padding-start: 0.6em;\n\n.trix-content {\n line-height: 1.5"
},
{
"path": "assets/trix/stylesheets/editor.scss",
"chars": 137,
"preview": "trix-editor {\n border: 1px solid #bbb;\n border-radius: 3px;\n margin: 0;\n padding: 0.4em 0.6em;\n min-height: 5em;\n "
},
{
"path": "assets/trix/stylesheets/icons.scss",
"chars": 727,
"preview": "$icon-attach: svg('trix/images/attach.svg');\n$icon-bold: svg('trix/images/bold.svg');\n$icon-bullets: svg('trix/images/bu"
},
{
"path": "assets/trix/stylesheets/media-queries.scss",
"chars": 97,
"preview": "$phone-width: 768px;\n\n@mixin phone {\n @media (max-width: #{$phone-width}) {\n @content;\n }\n}\n"
},
{
"path": "assets/trix/stylesheets/selection.scss",
"chars": 342,
"preview": "%disable-selection {\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none"
},
{
"path": "assets/trix/stylesheets/toolbar.scss",
"chars": 4341,
"preview": "@import \"./media-queries\";\n@import \"./icons\";\n\n$font-size-normal: 0.75em;\n$opacity-normal: 0.6;\n$opacity-disabled: 0.125"
},
{
"path": "assets/trix.scss",
"chars": 147,
"preview": "@import \"trix/stylesheets/editor\";\n@import \"trix/stylesheets/toolbar\";\n@import \"trix/stylesheets/attachments\";\n@import \""
},
{
"path": "babel.config.json",
"chars": 206,
"preview": "{\n \"presets\": [\n [\"@babel/preset-env\",\n {\n \"targets\": {\n \"chrome\": \"80\",\n \"safari\": \"1"
},
{
"path": "bin/ci",
"chars": 429,
"preview": "#!/usr/bin/env bash\nset -e\n\nif [ -n \"$CI\" ]; then\n echo \"GITHUB_WORKFLOW: $GITHUB_WORKFLOW\"\n echo \"GITHUB_RUN_NUMBER: "
},
{
"path": "bin/sass-build",
"chars": 1476,
"preview": "#!/usr/bin/env node\n\nconst path = require(\"path\")\nconst fs = require(\"fs\")\nconst sass = require(\"sass\")\nconst { optimize"
},
{
"path": "bin/setup",
"chars": 1588,
"preview": "#!/usr/bin/env bash\nset -eo pipefail\n\n# Use binstubs. Work from the root dir.\napp_root=\"$( cd \"$(dirname \"$0\")/..\"; pwd "
},
{
"path": "package.json",
"chars": 2704,
"preview": "{\n \"name\": \"trix\",\n \"version\": \"2.1.17\",\n \"description\": \"A rich text editor for everyday writing\",\n \"main\": \"dist/t"
},
{
"path": "rollup.config.js",
"chars": 2400,
"preview": "import json from \"@rollup/plugin-json\"\nimport includePaths from \"rollup-plugin-includepaths\"\nimport commonjs from \"@roll"
},
{
"path": "src/inspector/control_element.js",
"chars": 2504,
"preview": "const KEY_EVENTS = \"keydown keypress input\".split(\" \")\nconst COMPOSITION_EVENTS = \"compositionstart compositionupdate co"
},
{
"path": "src/inspector/debugger.js",
"chars": 3343,
"preview": "/* eslint-disable\n id-length,\n no-empty,\n*/\n\n// This file is not included in the main Trix bundle and\n// should be"
},
{
"path": "src/inspector/element.js",
"chars": 2071,
"preview": "/* eslint-disable\n id-length,\n*/\nimport { installDefaultCSSForTagName } from \"trix/core/helpers\"\n\ninstallDefaultCSSFo"
},
{
"path": "src/inspector/global.js",
"chars": 351,
"preview": "window.Trix.Inspector = {\n views: [],\n\n registerView(constructor) {\n return this.views.push(constructor)\n },\n\n in"
},
{
"path": "src/inspector/inspector.js",
"chars": 346,
"preview": "import \"inspector/element\"\nimport \"inspector/global\"\nimport \"inspector/templates\"\nimport \"inspector/control_element\"\nimp"
},
{
"path": "src/inspector/templates/debug.js",
"chars": 533,
"preview": "if (!window.JST) window.JST = {}\n\nwindow.JST[\"trix/inspector/templates/debug\"] = function() {\n return `<p>\n <label>\n "
},
{
"path": "src/inspector/templates/document.js",
"chars": 1249,
"preview": "if (!window.JST) window.JST = {}\n\nwindow.JST[\"trix/inspector/templates/document\"] = function() {\n const details = this."
},
{
"path": "src/inspector/templates/performance.js",
"chars": 572,
"preview": "if (!window.JST) window.JST = {}\n\nwindow.JST[\"trix/inspector/templates/performance\"] = function() {\n return Object.keys"
},
{
"path": "src/inspector/templates/render.js",
"chars": 115,
"preview": "if (!window.JST) window.JST = {}\n\nwindow.JST[\"trix/inspector/templates/render\"] = () => `Syncs: ${this.syncCount}`\n"
},
{
"path": "src/inspector/templates/selection.js",
"chars": 474,
"preview": "if (!window.JST) window.JST = {}\n\nwindow.JST[\"trix/inspector/templates/selection\"] = function() {\n return `Location ran"
},
{
"path": "src/inspector/templates/undo.js",
"chars": 490,
"preview": "if (!window.JST) window.JST = {}\n\nwindow.JST[\"trix/inspector/templates/undo\"] = () =>\n `<h4>Undo stack</h4>\n <ol cla"
},
{
"path": "src/inspector/templates.js",
"chars": 223,
"preview": "import \"inspector/templates/debug\"\nimport \"inspector/templates/document\"\nimport \"inspector/templates/performance\"\nimport"
},
{
"path": "src/inspector/view.js",
"chars": 2370,
"preview": "import { handleEvent } from \"trix/core/helpers\"\n\nexport default class View {\n constructor(editorElement) {\n this.edi"
},
{
"path": "src/inspector/views/debug_view.js",
"chars": 1781,
"preview": "import View from \"inspector/view\"\n\nimport { handleEvent } from \"trix/core/helpers\"\n\nclass DebugView extends View {\n sta"
},
{
"path": "src/inspector/views/document_view.js",
"chars": 365,
"preview": "import View from \"inspector/view\"\n\nclass DocumentView extends View {\n static title = \"Document\"\n static template = \"do"
},
{
"path": "src/inspector/views/performance_view.js",
"chars": 1563,
"preview": "import View from \"inspector/view\"\nconst now = window.performance?.now ? () => performance.now() : () => new Date().getTi"
},
{
"path": "src/inspector/views/render_view.js",
"chars": 548,
"preview": "import View from \"inspector/view\"\n\nexport default class RenderView extends View {\n static title = \"Renders\"\n static te"
},
{
"path": "src/inspector/views/selection_view.js",
"chars": 1255,
"preview": "import View from \"inspector/view\"\nimport UTF16String from \"trix/core/utilities/utf16_string\"\n\nclass SelectionView extend"
},
{
"path": "src/inspector/views/undo_view.js",
"chars": 421,
"preview": "import View from \"inspector/view\"\n\nclass UndoView extends View {\n static title = \"Undo\"\n static template = \"undo\"\n st"
},
{
"path": "src/inspector/watchdog/deserializer.js",
"chars": 2116,
"preview": "export default class Deserializer {\n constructor(document, snapshot) {\n this.document = document\n this.snapshot ="
},
{
"path": "src/inspector/watchdog/player.js",
"chars": 1720,
"preview": "import \"inspector/watchdog/recording\"\n\nexport default class Player {\n constructor(recording) {\n this.tick = this.tic"
},
{
"path": "src/inspector/watchdog/player_controller.js",
"chars": 1256,
"preview": "import Player from \"inspector/watchdog/player\"\nimport PlayerView from \"inspector/watchdog/player_view\"\n\nexport default c"
},
{
"path": "src/inspector/watchdog/player_element.js",
"chars": 1509,
"preview": "import { installDefaultCSSForTagName } from \"trix/core/helpers\"\n\nimport Recording from \"inspector/watchdog/recording\"\nim"
},
{
"path": "src/inspector/watchdog/player_view.js",
"chars": 5067,
"preview": "import Deserializer from \"inspector/watchdog/deserializer\"\nimport View from \"../view\"\n\nconst clear = (element) => {\n wh"
},
{
"path": "src/inspector/watchdog/recorder.js",
"chars": 3308,
"preview": "import Recording from \"inspector/watchdog/recording\"\nimport Serializer from \"inspector/watchdog/serializer\"\n\nexport defa"
},
{
"path": "src/inspector/watchdog/recording.js",
"chars": 1824,
"preview": "export default class Recording {\n static fromJSON({ snapshots, frames }) {\n return new this(snapshots, frames)\n }\n\n"
},
{
"path": "src/inspector/watchdog/serializer.js",
"chars": 2017,
"preview": "export default class Serializer {\n constructor(element) {\n this.element = element\n this.id = 0\n this.serialize"
},
{
"path": "src/inspector/watchdog.js",
"chars": 100,
"preview": "import \"inspector/watchdog/recorder\"\nimport \"inspector/watchdog/player_element\"\n\nTrix.Watchdog = {}\n"
},
{
"path": "src/test/system/accessibility_test.js",
"chars": 2412,
"preview": "import { assert, insertImageAttachment, skipIf, test, testGroup, triggerEvent } from \"test/test_helper\"\nimport { delay }"
},
{
"path": "src/test/system/attachment_caption_test.js",
"chars": 1898,
"preview": "import * as config from \"trix/config\"\nimport { assert, insertImageAttachment, test, testGroup } from \"test/test_helper\"\n"
},
{
"path": "src/test/system/attachment_gallery_test.js",
"chars": 2094,
"preview": "import {\n assert,\n clickToolbarButton,\n createImageAttachment,\n expectDocument,\n insertAttachments,\n pressKey,\n t"
},
{
"path": "src/test/system/attachment_test.js",
"chars": 5784,
"preview": "import * as config from \"trix/config\"\nimport { OBJECT_REPLACEMENT_CHARACTER } from \"trix/constants\"\n\nimport {\n assert,\n"
},
{
"path": "src/test/system/basic_input_test.js",
"chars": 3764,
"preview": "import * as config from \"trix/config\"\nimport {\n assert,\n dragToCoordinates,\n expandSelection,\n expectDocument,\n ins"
},
{
"path": "src/test/system/block_formatting_test.js",
"chars": 23790,
"preview": "import Text from \"trix/models/text\"\nimport Block from \"trix/models/block\"\nimport Document from \"trix/models/document\"\n\ni"
},
{
"path": "src/test/system/caching_test.js",
"chars": 887,
"preview": "import { assert, clickToolbarButton, moveCursor, test, testGroup, typeCharacters } from \"test/test_helper\"\n\ntestGroup(\"V"
},
{
"path": "src/test/system/canceled_input_test.js",
"chars": 1534,
"preview": "import { expectDocument, pressKey, test, testGroup, typeCharacters } from \"test/test_helper\"\n\nconst testOptions = {\n te"
},
{
"path": "src/test/system/composition_input_test.js",
"chars": 7584,
"preview": "import * as config from \"trix/config\"\n\nimport {\n assert,\n clickToolbarButton,\n endComposition,\n expectDocument,\n in"
},
{
"path": "src/test/system/cursor_movement_test.js",
"chars": 2229,
"preview": "import {\n assert,\n createFile,\n expandSelection,\n insertFile,\n insertString,\n moveCursor,\n test,\n testGroup,\n} f"
},
{
"path": "src/test/system/custom_element_test.js",
"chars": 30345,
"preview": "import { makeElement, rangesAreEqual } from \"trix/core/helpers\"\nimport TrixEditorElement from \"trix/elements/trix_editor"
},
{
"path": "src/test/system/html_loading_test.js",
"chars": 4404,
"preview": "import { TEST_IMAGE_URL, assert, expectDocument, test, testGroup } from \"test/test_helper\"\nimport { OBJECT_REPLACEMENT_C"
},
{
"path": "src/test/system/html_reparsing_test.js",
"chars": 1192,
"preview": "import { assert, expectDocument, test, testGroup } from \"test/test_helper\"\nimport { nextFrame } from \"../test_helpers/ti"
},
{
"path": "src/test/system/html_replacement_test.js",
"chars": 4772,
"preview": "import * as config from \"trix/config\"\n\nimport { assert, expectDocument, testGroup, testIf, triggerEvent } from \"test/tes"
},
{
"path": "src/test/system/installation_process_test.js",
"chars": 4437,
"preview": "import EditorController from \"trix/controllers/editor_controller\"\n\nimport { assert, setFixtureHTML, test, testGroup } fr"
},
{
"path": "src/test/system/level_2_input_test.js",
"chars": 12505,
"preview": "import * as config from \"trix/config\"\nimport { OBJECT_REPLACEMENT_CHARACTER } from \"trix/constants\"\n\nimport {\n assert,\n"
},
{
"path": "src/test/system/list_formatting_test.js",
"chars": 4262,
"preview": "import * as config from \"trix/config\"\n\nimport {\n assert,\n clickToolbarButton,\n expectDocument,\n moveCursor,\n pressK"
},
{
"path": "src/test/system/morphing_test.js",
"chars": 2893,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\nimport { nextFrame } from \"../test_helpers/timing_helpers\"\n\ni"
},
{
"path": "src/test/system/mutation_input_test.js",
"chars": 4663,
"preview": "import * as config from \"trix/config\"\n\nimport {\n TEST_IMAGE_URL,\n assert,\n clickToolbarButton,\n expectDocument,\n in"
},
{
"path": "src/test/system/pasting_test.js",
"chars": 16696,
"preview": "import * as config from \"trix/config\"\nimport { OBJECT_REPLACEMENT_CHARACTER } from \"trix/constants\"\n\nimport {\n TEST_IMA"
},
{
"path": "src/test/system/text_formatting_test.js",
"chars": 8624,
"preview": "import * as config from \"trix/config\"\nimport { makeElement } from \"trix/core/helpers\"\nimport Text from \"trix/models/text"
},
{
"path": "src/test/system/undo_test.js",
"chars": 2439,
"preview": "import {\n assert,\n clickToolbarButton,\n expandSelection,\n moveCursor,\n test,\n testGroup,\n typeCharacters,\n} from "
},
{
"path": "src/test/system.js",
"chars": 885,
"preview": "import \"test/system/accessibility_test\"\nimport \"test/system/attachment_caption_test\"\nimport \"test/system/attachment_gall"
},
{
"path": "src/test/test.js",
"chars": 152,
"preview": "/* eslint-disable\n*/\nimport Trix from \"trix/trix\"\n\nimport \"trix/core/helpers/global\"\nimport \"test/test_helper\"\n\nimport \""
},
{
"path": "src/test/test_helper.js",
"chars": 1119,
"preview": "import Trix from \"trix/trix\"\n\nexport * from \"trix/core/helpers/functions\"\nexport * from \"trix/core/helpers/global\"\nexpor"
},
{
"path": "src/test/test_helpers/assertions.js",
"chars": 2071,
"preview": "import DocumentView from \"trix/views/document_view\"\nimport { normalizeRange } from \"trix/core/helpers\"\n\nconst { assert }"
},
{
"path": "src/test/test_helpers/editor_helpers.js",
"chars": 1376,
"preview": "import { TEST_IMAGE_URL } from \"test/test_helpers/fixtures/test_image_url\"\nimport Attachment from \"trix/models/attachmen"
},
{
"path": "src/test/test_helpers/event_helpers.js",
"chars": 370,
"preview": "export const createEvent = function (type, properties = {}) {\n const event = document.createEvent(\"Events\")\n event.ini"
},
{
"path": "src/test/test_helpers/fixtures/editor_default_aria_label.js",
"chars": 909,
"preview": "export default () =>\n `<trix-editor id=\"editor-without-labels\"></trix-editor>\n\n <label for=\"editor-with-aria-label\"><s"
},
{
"path": "src/test/test_helpers/fixtures/editor_empty.js",
"chars": 90,
"preview": "export default () => \"<trix-editor autofocus placeholder=\\\"Say hello...\\\"></trix-editor>\"\n"
},
{
"path": "src/test/test_helpers/fixtures/editor_html.js",
"chars": 188,
"preview": "export default () =>\n `<input id=\"my_input\" type=\"hidden\" value=\"<div>Hello world</div>\">\n <trix-editor in"
},
{
"path": "src/test/test_helpers/fixtures/editor_in_table.js",
"chars": 122,
"preview": "export default () =>\n `<table>\n <tr>\n <td>\n <trix-editor></trix-editor>\n </td>\n </tr>\n </table>"
},
{
"path": "src/test/test_helpers/fixtures/editor_with_block_styles.js",
"chars": 181,
"preview": "export default () =>\n `<style type=\"text/css\">\n blockquote { font-style: italic; }\n li { font-weight: bold; }\n <"
},
{
"path": "src/test/test_helpers/fixtures/editor_with_bold_styles.js",
"chars": 211,
"preview": "export default () =>\n `<style type=\"text/css\">\n strong { font-weight: 500; }\n span { font-weight: 600; }\n arti"
},
{
"path": "src/test/test_helpers/fixtures/editor_with_image.js",
"chars": 295,
"preview": "import { TEST_IMAGE_URL } from \"./test_image_url\"\n\nexport default () =>\n `<trix-editor input=\"my_input\" autofocus place"
},
{
"path": "src/test/test_helpers/fixtures/editor_with_labels.js",
"chars": 221,
"preview": "export default () =>\n `<label id=\"label-1\" for=\"editor\"><span>Label 1</span></label>\n <label id=\"label-2\">Label 2</la"
},
{
"path": "src/test/test_helpers/fixtures/editor_with_styled_content.js",
"chars": 185,
"preview": "export default () =>\n `<style type=\"text/css\">\n .trix-content figure.attachment {\n display: inline-block;\n }"
},
{
"path": "src/test/test_helpers/fixtures/editor_with_toolbar_and_input.js",
"chars": 320,
"preview": "export default () =>\n `<ul id=\"my_editor\">\n <li><trix-toolbar id=\"my_toolbar\"></trix-toolbar></li>\n <li><trix-edi"
},
{
"path": "src/test/test_helpers/fixtures/editors_with_forms.js",
"chars": 451,
"preview": "export default () =>\n `<form id=\"ancestor-form\">\n <trix-editor id=\"editor-with-ancestor-form\" name=\"editor-with-ance"
},
{
"path": "src/test/test_helpers/fixtures/fixtures.js",
"chars": 24732,
"preview": "import * as config from \"trix/config\"\nimport { ZERO_WIDTH_SPACE } from \"trix/constants\"\nimport { makeElement } from \"tri"
},
{
"path": "src/test/test_helpers/fixtures/test_image_url.js",
"chars": 103,
"preview": "export const TEST_IMAGE_URL = \"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=\"\n"
},
{
"path": "src/test/test_helpers/functions.js",
"chars": 227,
"preview": "export const extend = function (properties) {\n for (const key in properties) {\n const value = properties[key]\n th"
},
{
"path": "src/test/test_helpers/input_helpers.js",
"chars": 8303,
"preview": "import * as config from \"trix/config\"\nimport { delay, nextFrame } from \"./timing_helpers\"\nimport { triggerEvent } from \""
},
{
"path": "src/test/test_helpers/selection_helpers.js",
"chars": 3600,
"preview": "import * as config from \"trix/config\"\n\nimport { triggerEvent } from \"event_helpers\"\nimport { selectionChangeObserver } f"
},
{
"path": "src/test/test_helpers/test_helpers.js",
"chars": 2208,
"preview": "import { fixtureTemplates } from \"test/test_helpers/fixtures/fixtures\"\nimport { removeNode } from \"trix/core/helpers\"\n\ne"
},
{
"path": "src/test/test_helpers/test_stubs.js",
"chars": 967,
"preview": "import { normalizeRange, rangeIsCollapsed } from \"trix/core/helpers\"\n\nexport class TestCompositionDelegate {\n compositi"
},
{
"path": "src/test/test_helpers/timing_helpers.js",
"chars": 263,
"preview": "export function nextFrame() {\n return new Promise(requestAnimationFrame)\n}\n\nexport function nextIdle() {\n return new P"
},
{
"path": "src/test/test_helpers/toolbar_helpers.js",
"chars": 2064,
"preview": "import { triggerEvent } from \"./event_helpers\"\nimport { selectionChangeObserver } from \"trix/observers/selection_change_"
},
{
"path": "src/test/unit/attachment_test.js",
"chars": 1091,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\nimport Attachment from \"trix/models/attachment\"\n\ntestGroup(\"A"
},
{
"path": "src/test/unit/bidi_test.js",
"chars": 274,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\nimport { getDirection } from \"trix/core/helpers\"\n\ntestGroup(\""
},
{
"path": "src/test/unit/block_test.js",
"chars": 1190,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\n\nimport Text from \"trix/models/text\"\nimport Block from \"trix/"
},
{
"path": "src/test/unit/composition_test.js",
"chars": 618,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\n\nimport Composition from \"trix/models/composition\"\nimport { T"
},
{
"path": "src/test/unit/document_test.js",
"chars": 2377,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\n\nimport Text from \"trix/models/text\"\nimport Block from \"trix/"
},
{
"path": "src/test/unit/document_view_test.js",
"chars": 243,
"preview": "import { assert, eachFixture, test, testGroup } from \"test/test_helper\"\n\ntestGroup(\"DocumentView\", () => {\n eachFixture"
},
{
"path": "src/test/unit/helpers/custom_elements_test.js",
"chars": 1889,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\nimport { installDefaultCSSForTagName, makeElement } from \"tri"
},
{
"path": "src/test/unit/html_parser_test.js",
"chars": 17947,
"preview": "import {\n TEST_IMAGE_URL,\n assert,\n createCursorTarget,\n eachFixture,\n fixtures,\n getHTML,\n test,\n testGroup,\n} "
},
{
"path": "src/test/unit/html_sanitizer_test.js",
"chars": 1910,
"preview": "import {\n assert,\n test,\n testGroup,\n} from \"test/test_helper\"\n\nimport { HTMLSanitizer } from \"../../trix/models\"\nimp"
},
{
"path": "src/test/unit/location_mapper_test.js",
"chars": 7384,
"preview": "import { TEST_IMAGE_URL, assert, test, testGroup } from \"test/test_helper\"\n\nimport DocumentView from \"trix/views/documen"
},
{
"path": "src/test/unit/mutation_observer_test.js",
"chars": 2758,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\n\nimport MutationObserver from \"trix/observers/mutation_observ"
},
{
"path": "src/test/unit/serialization_test.js",
"chars": 399,
"preview": "import { serializeToContentType } from \"trix/core/serialization\"\nimport { assert, eachFixture, test, testGroup } from \"t"
},
{
"path": "src/test/unit/string_change_summary_test.js",
"chars": 2021,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\n\nimport { summarizeStringChange } from \"trix/core/helpers\"\n\nt"
},
{
"path": "src/test/unit/text_test.js",
"chars": 1029,
"preview": "import { assert, test, testGroup } from \"test/test_helper\"\n\nimport Text from \"trix/models/text\"\nimport StringPiece from "
},
{
"path": "src/test/unit.js",
"chars": 519,
"preview": "import \"test/unit/attachment_test\"\nimport \"test/unit/bidi_test\"\nimport \"test/unit/block_test\"\nimport \"test/unit/composit"
},
{
"path": "src/trix/config/attachments.js",
"chars": 271,
"preview": "export const attachmentSelector = \"[data-trix-attachment]\"\n\nconst attachments = {\n preview: {\n presentation: \"galler"
},
{
"path": "src/trix/config/block_attributes.js",
"chars": 1142,
"preview": "const attributes = {\n default: {\n tagName: \"div\",\n parse: false,\n },\n quote: {\n tagName: \"blockquote\",\n n"
},
{
"path": "src/trix/config/browser.js",
"chars": 1168,
"preview": "const androidVersionMatch = navigator.userAgent.match(/android\\s([0-9]+.*Chrome)/i)\nconst androidVersion = androidVersio"
},
{
"path": "src/trix/config/css.js",
"chars": 468,
"preview": "export default {\n attachment: \"attachment\",\n attachmentCaption: \"attachment__caption\",\n attachmentCaptionEditor: \"att"
},
{
"path": "src/trix/config/dompurify.js",
"chars": 89,
"preview": "export default {\n ADD_ATTR: [ \"language\" ],\n SAFE_FOR_XML: false,\n RETURN_DOM: true\n}\n"
},
{
"path": "src/trix/config/file_size_formatting.js",
"chars": 853,
"preview": "/* eslint-disable\n no-case-declarations,\n*/\nimport lang from \"trix/config/lang\"\n\nconst sizes = [ lang.bytes, lang.KB,"
},
{
"path": "src/trix/config/index.js",
"chars": 646,
"preview": "export { default as attachments } from \"./attachments\"\nexport { default as blockAttributes } from \"./block_attributes\"\ne"
},
{
"path": "src/trix/config/input.js",
"chars": 657,
"preview": "import browser from \"trix/config/browser\"\nimport { makeElement, removeNode } from \"trix/core/helpers/dom\"\n\nconst input ="
},
{
"path": "src/trix/config/key_names.js",
"chars": 159,
"preview": "export default {\n 8: \"backspace\",\n 9: \"tab\",\n 13: \"return\",\n 27: \"escape\",\n 37: \"left\",\n 39: \"right\",\n 46: \"delet"
},
{
"path": "src/trix/config/lang.js",
"chars": 541,
"preview": "export default {\n attachFiles: \"Attach Files\",\n bold: \"Bold\",\n bullets: \"Bullets\",\n byte: \"Byte\",\n bytes: \"Bytes\",\n"
},
{
"path": "src/trix/config/parser.js",
"chars": 107,
"preview": "export default {\n removeBlankTableCells: false,\n tableCellSeparator: \" | \",\n tableRowSeparator: \"\\n\",\n}\n"
},
{
"path": "src/trix/config/text_attributes.js",
"chars": 846,
"preview": "import { attachmentSelector } from \"trix/config/attachments\"\n\nexport default {\n bold: {\n tagName: \"strong\",\n inhe"
}
]
// ... and 82 more files (download for full content)
About this extraction
This page contains the full source code of the basecamp/trix GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 282 files (1.2 MB), approximately 337.6k tokens, and a symbol index with 2465 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.