├── .editorconfig
├── .eslintignore
├── .github
├── dependabot.yml
└── workflows
│ └── nodejs.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── appveyor.yml
├── babel.config.js
├── build
├── rollup.config.base.js
├── rollup.config.es.js
└── rollup.config.unpkg.js
├── dist
├── demo.html
├── vue-trix.common.js
├── vue-trix.common.js.map
├── vue-trix.css
├── vue-trix.esm.js
├── vue-trix.esm.js.map
├── vue-trix.min.js
├── vue-trix.min.js.map
├── vue-trix.umd.js
├── vue-trix.umd.js.map
├── vue-trix.umd.min.js
└── vue-trix.umd.min.js.map
├── example
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.vue
│ ├── assets
│ ├── logo.png
│ ├── vue-trix-editor.png
│ ├── vue-trix-form.png
│ ├── vue-trix-in-prod.png
│ └── vue-trix-simple.png
│ ├── components
│ └── Editor.vue
│ └── main.js
├── jest.config.js
├── jest
└── htmlSnapshotBeautifier.js
├── package-lock.json
├── package.json
├── src
├── components
│ └── VueTrix.vue
├── index.js
└── mixins
│ ├── EmitAttachmentAdd.js
│ ├── EmitAttachmentRemove.js
│ ├── EmitBeforeInitialize.js
│ ├── EmitDroppedFile.js
│ ├── EmitFileAccept.js
│ ├── EmitInitialize.js
│ ├── EmitSelectionChange.js
│ └── ProcessEditorFocusAndBlur.js
└── tests
└── unit
├── .eslintrc.js
└── VueTrix.spec.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | indent_style = space
4 | indent_size = 2
5 | end_of_line = lf
6 | insert_final_newline = true
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /dist
2 | /node_modules
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/"
5 | schedule:
6 | interval: weekly
7 | time: "20:00"
8 | open-pull-requests-limit: 10
9 | ignore:
10 | - dependency-name: y18n
11 | versions:
12 | - 4.0.1
13 | - dependency-name: "@vue/cli-plugin-babel"
14 | versions:
15 | - 4.5.11
16 | - dependency-name: "@vue/test-utils"
17 | versions:
18 | - 1.1.3
19 | - dependency-name: js-beautify
20 | versions:
21 | - 1.13.4
22 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | name: Node CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | matrix:
12 | node-version: [16.x, 18.x]
13 |
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: Use Node.js ${{ matrix.node-version }}
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | - name: npm install, build, and test
21 | run: |
22 | npm install
23 | npm run build --if-present
24 | npm run test:unit
25 | env:
26 | CI: true
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /coverage
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at tranduchanh.ms@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Hanh D. TRAN
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vue-Trix Text Editor
2 |
3 | [](https://www.npmjs.com/package/vue-trix) [](https://ci.appveyor.com/project/tranduchanh/vue-trix/branch/master)
4 |
5 | Simple and lightweight [Trix](https://www.npmjs.com/package/trix) rich-text editor Vue.js component for writing daily
6 |
7 | ## Table of Contents
8 |
9 | - [Vue-Trix Text Editor](#vue-trix-text-editor)
10 | - [Table of Contents](#table-of-contents)
11 | - [Getting started](#getting-started)
12 | - [Demo page](#demo-page)
13 | - [Integrate into the form](#integrate-into-the-form)
14 | - [Features](#features)
15 | - [Installation](#installation)
16 | - [NPM](#npm)
17 | - [YARN](#yarn)
18 | - [Or directly from latest Github repo](#or-directly-from-latest-github-repo)
19 | - [Mount](#mount)
20 | - [Mount with global](#mount-with-global)
21 | - [Mount with component](#mount-with-component)
22 | - [Setup with Nuxt.js (SSR)](#setup-with-nuxtjs-ssr)
23 | - [Component Usages](#component-usages)
24 | - [Create a simple editor in your single component file](#create-a-simple-editor-in-your-single-component-file)
25 | - [Integrating with Forms](#integrating-with-forms)
26 | - [Props descriptions](#props-descriptions)
27 | - [Populating editor content](#populating-editor-content)
28 | - [Init loading content into the editor](#init-loading-content-into-the-editor)
29 | - [Track data changes](#track-data-changes)
30 | - [Binding attachment events](#binding-attachment-events)
31 | - [Process uploading attachment to remote server](#process-uploading-attachment-to-remote-server)
32 | - [Trix document](#trix-document)
33 | - [Contributing](#contributing)
34 |
35 | ## Getting started
36 |
37 | ### [Demo page](/example)
38 |
39 | 
40 |
41 | ### Integrate into the form
42 |
43 | 
44 |
45 | ## Features
46 |
47 | - A simple and lightweight rich-text editor for writing daily.
48 | - Two-ways binding with `v-model` easily.
49 | - Auto-save editor data temporally what you has typed into the form input in case something goes wrong (for example, the browser could crash or you could accidentally refresh the page without submit saving).
50 |
51 | ## Installation
52 |
53 | ### NPM
54 |
55 | ```Shell
56 | npm install --save vue-trix
57 | ```
58 |
59 | ### YARN
60 |
61 | ```Shell
62 | yarn add vue-trix
63 | ```
64 |
65 | ### Or directly from latest Github repo
66 |
67 | ```Shell
68 | npm install --save hanhdt/vue-trix
69 | ```
70 |
71 | ## Mount
72 |
73 | ### Mount with global
74 |
75 | in the `main.js`, import the package as a global component.
76 |
77 | ```javascript
78 | import "vue-trix";
79 | ```
80 |
81 | ### Mount with component
82 |
83 | ```javascript
84 | import VueTrix from "vue-trix";
85 |
86 | export default {
87 | // ...
88 | components: {
89 | VueTrix
90 | }
91 | };
92 | ```
93 |
94 | ### Setup with Nuxt.js (SSR)
95 |
96 | Create mounting plugin file
97 |
98 | ```javascript
99 | // plugins/vue_trix.js
100 | import Vue from "vue";
101 | import VueTrix from "vue-trix";
102 |
103 | Vue.use(VueTrix);
104 | ```
105 |
106 | Update Nuxt.js config file
107 |
108 | ```javascript
109 | // nuxt.config.js
110 | plugins: [{ src: "~/plugins/vue_trix", mode: "client" }];
111 | ```
112 |
113 | ## Component Usages
114 |
115 | ### Create a simple editor in your single component file
116 |
117 | Add `VueTrix` component into `*.vue` template
118 |
119 | ```XML
120 |
121 |
122 |
123 |
124 |
125 | ```
126 |
127 | ### Integrating with Forms
128 |
129 | ```XML
130 |
133 | ```
134 |
135 | ### Props descriptions
136 |
137 | - `inputId`: This is referenced `id` of the hidden input field defined, it is optional.
138 | - `inputName`: This is referenced `name` of the hidden input field defined, default value is `content`.
139 | - `placeholder`: The placeholder option attribute specifies a short hint that describes the expected value of a editor.
140 | - `autofocus`: Automatically focus the editor when it loads
141 | - `disabledEditor`: This prop will put the editor in read-only mode.
142 | - `localStorage`: The boolean attribute allows saving editor state into browser's localStorage (optional, default is `false`).
143 |
144 | ### Populating editor content
145 |
146 | #### Init loading content into the editor
147 |
148 | In case, you want to load initial data from database then display into the editor. you can use `v-model` directive with local component's state.
149 |
150 | ```javascript
151 | // Declare local component's state is loaded from database
152 | export default {
153 | // ...
154 | data() {
155 | return {
156 | editorContent: "Editor contents "
157 | };
158 | }
159 | // ...
160 | };
161 | ```
162 |
163 | ```HTML
164 | // Assign to v-model directive
165 |
166 |
167 |
168 |
169 |
170 | ```
171 |
172 | #### Track data changes
173 |
174 | The local component's state will be changed reactively when you modified contents inside the trix editor UI. Therefore, you need to `watch` the local state for updating content back to database
175 |
176 | ```javascript
177 | export default {
178 | // ...
179 | methods: {
180 | updateEditorContent(value) {
181 | // Update new content into the database via state mutations.
182 | }
183 | },
184 | watch: {
185 | editorContent: {
186 | handler: "updateEditorContent"
187 | }
188 | }
189 | // ...
190 | };
191 | ```
192 |
193 | ### Binding attachment events
194 |
195 | The ` ` element emits several events which you can use to observe and respond to changes in editor state.
196 |
197 | - `@trix-file-accept` fires before an attachment is added to the document. If you don’t want to accept dropped or pasted files, call preventDefault() on this event.
198 |
199 | - `@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.
200 |
201 | - `@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.
202 |
203 | ### Process uploading attachment to remote server
204 |
205 | Add binding event listener to `trix-attachment-add`
206 |
207 | ```HTML
208 |
209 |
210 |
211 |
212 |
213 | ```
214 |
215 | In Javascript
216 |
217 | ```Javascript
218 | const remoteHost = 'your remote host';
219 |
220 | function handleAttachmentChanges(event) {
221 | // 1. get file object
222 | let file = event.attachment.file;
223 |
224 | // 2. upload file to remote server with FormData
225 | // ...
226 |
227 | // 3. if upload success, set back the attachment's URL attribute
228 | // @param object data from remote server response data after upload.
229 | let attributes = {
230 | url: remoteHost + data.path,
231 | href: remoteHost + data.path
232 | };
233 | event.attachment.setAttributes(attributes);
234 | }
235 | ```
236 |
237 | ## Trix document
238 |
239 | [Full documentation](https://github.com/basecamp/trix#readme)
240 |
241 | ## Contributing
242 |
243 | If you're interested in contributing to Vue-Trix or share your opinions, please consider to submitting a [**pull request**](https://github.com/hanhdt/vue-trix/pulls) or post [**issues**](https://github.com/hanhdt/vue-trix/issues). Also, I will try to code-self documentation.
244 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | nodejs_version: "10"
3 |
4 | install:
5 | - ps: Install-Product node $env:nodejs_version
6 | - npm install
7 |
8 | test_script:
9 | - node --version
10 | - npm --version
11 | - npm run test:unit
12 |
13 | cache:
14 | - node_modules -> package-lock.json
15 |
16 | build: off
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/build/rollup.config.base.js:
--------------------------------------------------------------------------------
1 | import vue from 'rollup-plugin-vue'
2 | import replace from 'rollup-plugin-replace'
3 | import buble from 'rollup-plugin-buble'
4 | import commonjs from 'rollup-plugin-commonjs'
5 |
6 | const config = require('../package.json')
7 |
8 | export default {
9 | input: 'src/index.js',
10 | name: 'VueTrix',
11 | plugins: [
12 | commonjs(),
13 | vue({
14 | compileTemplate: true,
15 | css: true
16 | }),
17 | replace({
18 | VERSION: JSON.stringify(config.version)
19 | }),
20 | buble()
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/build/rollup.config.es.js:
--------------------------------------------------------------------------------
1 | import base from './rollup.config.base'
2 | const globals = { vue: 'Vue' }
3 |
4 | const config = Object.assign({}, base, {
5 | output: {
6 | globals,
7 | file: 'dist/vue-trix.esm.js',
8 | format: 'esm',
9 | sourcemap: true
10 | }
11 | })
12 |
13 | export default config
14 |
--------------------------------------------------------------------------------
/build/rollup.config.unpkg.js:
--------------------------------------------------------------------------------
1 | import base from './rollup.config.base'
2 | import uglify from 'rollup-plugin-uglify'
3 | import { minify } from 'uglify-es'
4 | const globals = { vue: 'Vue' }
5 |
6 | const config = Object.assign({}, base, {
7 | output: {
8 | globals,
9 | name: 'VueTrix',
10 | file: 'dist/vue-trix.min.js',
11 | format: 'iife',
12 | sourcemap: true
13 | }
14 | })
15 |
16 | config.plugins.push(uglify.uglify({}, minify))
17 |
18 | export default config
19 |
--------------------------------------------------------------------------------
/dist/demo.html:
--------------------------------------------------------------------------------
1 |
2 | vue-trix demo
3 |
4 |
5 |
6 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/dist/vue-trix.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";trix-editor{border:1px solid #bbb;border-radius:3px;margin:0;padding:.4em .6em;min-height:5em;outline:none}trix-toolbar *{-webkit-box-sizing:border-box;box-sizing:border-box}trix-toolbar .trix-button-row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;overflow-x:auto}trix-toolbar .trix-button-group{display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:10px;border:1px solid #bbb;border-top-color:#ccc;border-bottom-color:#888;border-radius:3px}trix-toolbar .trix-button-group:not(:first-child){margin-left:1.5vw}@media (max-device-width:768px){trix-toolbar .trix-button-group:not(:first-child){margin-left:0}}trix-toolbar .trix-button-group-spacer{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}@media (max-device-width:768px){trix-toolbar .trix-button-group-spacer{display:none}}trix-toolbar .trix-button{position:relative;float:left;color:rgba(0,0,0,.6);font-size:.75em;font-weight:600;white-space:nowrap;padding:0 .5em;margin:0;outline:none;border:none;border-bottom:1px solid #ddd;border-radius:0;background:transparent}trix-toolbar .trix-button:not(:first-child){border-left:1px solid #ccc}trix-toolbar .trix-button.trix-active{background:#cbeefa;color:#000}trix-toolbar .trix-button:not(:disabled){cursor:pointer}trix-toolbar .trix-button:disabled{color:rgba(0,0,0,.125)}@media (max-device-width:768px){trix-toolbar .trix-button{letter-spacing:-.01em;padding:0 .3em}}trix-toolbar .trix-button--icon{font-size:inherit;width:2.6em;height:1.6em;max-width:calc(.8em + 4vw);text-indent:-9999px}@media (max-device-width:768px){trix-toolbar .trix-button--icon{height:2em;max-width:calc(.8em + 3.5vw)}}trix-toolbar .trix-button--icon:before{display:inline-block;position:absolute;top:0;right:0;bottom:0;left:0;opacity:.6;content:"";background-position:50%;background-repeat:no-repeat;background-size:contain}@media (max-device-width:768px){trix-toolbar .trix-button--icon:before{right:6%;left:6%}}trix-toolbar .trix-button--icon.trix-active:before{opacity:1}trix-toolbar .trix-button--icon:disabled:before{opacity:.125}trix-toolbar .trix-button--icon-attach:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M16.5 6v11.5a4 4 0 11-8 0V5a2.5 2.5 0 015 0v10.5a1 1 0 11-2 0V6H10v9.5a2.5 2.5 0 005 0V5a4 4 0 10-8 0v12.5a5.5 5.5 0 0011 0V6h-1.5z'/%3E%3C/svg%3E");top:8%;bottom:4%}trix-toolbar .trix-button--icon-bold:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M15.6 11.8c1-.7 1.6-1.8 1.6-2.8a4 4 0 00-4-4H7v14h7c2.1 0 3.7-1.7 3.7-3.8 0-1.5-.8-2.8-2.1-3.4zM10 7.5h3a1.5 1.5 0 110 3h-3v-3zm3.5 9H10v-3h3.5a1.5 1.5 0 110 3z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-italic:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M10 5v3h2.2l-3.4 8H6v3h8v-3h-2.2l3.4-8H18V5h-8z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-link:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M9.88 13.7a4.3 4.3 0 010-6.07l3.37-3.37a4.26 4.26 0 016.07 0 4.3 4.3 0 010 6.06l-1.96 1.72a.91.91 0 11-1.3-1.3l1.97-1.71a2.46 2.46 0 00-3.48-3.48l-3.38 3.37a2.46 2.46 0 000 3.48.91.91 0 11-1.3 1.3z'/%3E%3Cpath d='M4.25 19.46a4.3 4.3 0 010-6.07l1.93-1.9a.91.91 0 111.3 1.3l-1.93 1.9a2.46 2.46 0 003.48 3.48l3.37-3.38c.96-.96.96-2.52 0-3.48a.91.91 0 111.3-1.3 4.3 4.3 0 010 6.07l-3.38 3.38a4.26 4.26 0 01-6.07 0z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-strike:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M12.73 14l.28.14c.26.15.45.3.57.44.12.14.18.3.18.5 0 .3-.15.56-.44.75-.3.2-.76.3-1.39.3A13.52 13.52 0 017 14.95v3.37a10.64 10.64 0 004.84.88c1.26 0 2.35-.19 3.28-.56.93-.37 1.64-.9 2.14-1.57s.74-1.45.74-2.32c0-.26-.02-.51-.06-.75h-5.21zm-5.5-4c-.08-.34-.12-.7-.12-1.1 0-1.29.52-2.3 1.58-3.02 1.05-.72 2.5-1.08 4.34-1.08 1.62 0 3.28.34 4.97 1l-1.3 2.93c-1.47-.6-2.73-.9-3.8-.9-.55 0-.96.08-1.2.26-.26.17-.38.38-.38.64 0 .27.16.52.48.74.17.12.53.3 1.05.53H7.23zM3 13h18v-2H3v2z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-quote:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg version='1' xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-heading-1:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg version='1' xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M12 9v3H9v7H6v-7H3V9h9zM8 4h14v3h-6v12h-3V7H8V4z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-code:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M18.2 12L15 15.2l1.4 1.4L21 12l-4.6-4.6L15 8.8l3.2 3.2zM5.8 12L9 8.8 7.6 7.4 3 12l4.6 4.6L9 15.2 5.8 12z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-bullet-list:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg version='1' xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M4 4a2 2 0 100 4 2 2 0 000-4zm0 6a2 2 0 100 4 2 2 0 000-4zm0 6a2 2 0 100 4 2 2 0 000-4zm4 3h14v-2H8v2zm0-6h14v-2H8v2zm0-8v2h14V5H8z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-number-list:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-undo:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M12.5 8c-2.6 0-5 1-6.9 2.6L2 7v9h9l-3.6-3.6A8 8 0 0120 16l2.4-.8a10.5 10.5 0 00-10-7.2z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-redo:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M18.4 10.6a10.5 10.5 0 00-16.9 4.6L4 16a8 8 0 0112.7-3.6L13 16h9V7l-3.6 3.6z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-decrease-nesting-level:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M3 19h19v-2H3v2zm7-6h12v-2H10v2zm-8.3-.3l2.8 2.9L6 14.2 4 12l2-2-1.4-1.5L1 12l.7.7zM3 5v2h19V5H3z'/%3E%3C/svg%3E")}trix-toolbar .trix-button--icon-increase-nesting-level:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M3 19h19v-2H3v2zm7-6h12v-2H10v2zm-6.9-1L1 14.2l1.4 1.4L6 12l-.7-.7-2.8-2.8L1 9.9 3.1 12zM3 5v2h19V5H3z'/%3E%3C/svg%3E")}trix-toolbar .trix-dialogs{position:relative}trix-toolbar .trix-dialog{position:absolute;top:0;left:0;right:0;font-size:.75em;padding:15px 10px;background:#fff;-webkit-box-shadow:0 .3em 1em #ccc;box-shadow:0 .3em 1em #ccc;border-top:2px solid #888;border-radius:5px;z-index:5}trix-toolbar .trix-input--dialog{font-size:inherit;font-weight:400;padding:.5em .8em;margin:0 10px 0 0;border-radius:3px;border:1px solid #bbb;background-color:#fff;-webkit-box-shadow:none;box-shadow:none;outline:none;-webkit-appearance:none;-moz-appearance:none}trix-toolbar .trix-input--dialog.validate:invalid{-webkit-box-shadow:red 0 0 1.5px 1px;box-shadow:0 0 1.5px 1px red}trix-toolbar .trix-button--dialog{font-size:inherit;padding:.5em;border-bottom:none}trix-toolbar .trix-dialog--link{max-width:600px}trix-toolbar .trix-dialog__link-fields{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}trix-toolbar .trix-dialog__link-fields .trix-input{-webkit-box-flex:1;-ms-flex:1;flex:1}trix-toolbar .trix-dialog__link-fields .trix-button-group{-webkit-box-flex:0;-ms-flex:0 0 content;flex:0 0 content;margin:0}trix-editor [data-trix-mutable]:not(.attachment__caption-editor){-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}trix-editor [data-trix-cursor-target]::-moz-selection,trix-editor [data-trix-mutable]::-moz-selection,trix-editor [data-trix-mutable] ::-moz-selection{background:none}trix-editor [data-trix-cursor-target]::selection,trix-editor [data-trix-mutable]::selection,trix-editor [data-trix-mutable] ::selection{background:none}trix-editor [data-trix-mutable].attachment__caption-editor:focus::-moz-selection{background:highlight}trix-editor [data-trix-mutable].attachment__caption-editor:focus::selection{background:highlight}trix-editor [data-trix-mutable].attachment.attachment--file{border-color:transparent}trix-editor [data-trix-mutable].attachment.attachment--file,trix-editor [data-trix-mutable].attachment img{-webkit-box-shadow:0 0 0 2px highlight;box-shadow:0 0 0 2px highlight}trix-editor .attachment{position:relative}trix-editor .attachment:hover{cursor:default}trix-editor .attachment--preview .attachment__caption:hover{cursor:text}trix-editor .attachment__progress{position:absolute;z-index:1;height:20px;top:calc(50% - 10px);left:5%;width:90%;opacity:.9;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}trix-editor .attachment__progress[value="100"]{opacity:0}trix-editor .attachment__caption-editor{display:inline-block;width:100%;margin:0;padding:0;font-size:inherit;font-family:inherit;line-height:inherit;color:inherit;text-align:center;vertical-align:top;border:none;outline:none;-webkit-appearance:none;-moz-appearance:none}trix-editor .attachment__toolbar{position:absolute;z-index:1;top:-.9em;left:0;width:100%;text-align:center}trix-editor .trix-button-group{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}trix-editor .trix-button{position:relative;float:left;color:#666;white-space:nowrap;font-size:80%;padding:0 .8em;margin:0;outline:none;border:none;border-radius:0;background:transparent}trix-editor .trix-button:not(:first-child){border-left:1px solid #ccc}trix-editor .trix-button.trix-active{background:#cbeefa}trix-editor .trix-button:not(:disabled){cursor:pointer}trix-editor .trix-button--remove{text-indent:-9999px;display:inline-block;padding:0;outline:none;width:1.8em;height:1.8em;line-height:1.8em;border-radius:50%;background-color:#fff;border:2px solid highlight;-webkit-box-shadow:1px 1px 6px rgba(0,0,0,.25);box-shadow:1px 1px 6px rgba(0,0,0,.25)}trix-editor .trix-button--remove:before{display:inline-block;position:absolute;top:0;right:0;bottom:0;left:0;opacity:.7;content:"";background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg height='24' width='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19 6.4L17.6 5 12 10.6 6.4 5 5 6.4l5.6 5.6L5 17.6 6.4 19l5.6-5.6 5.6 5.6 1.4-1.4-5.6-5.6z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:90%}trix-editor .trix-button--remove:hover{border-color:#333}trix-editor .trix-button--remove:hover:before{opacity:1}trix-editor .attachment__metadata-container{position:relative}trix-editor .attachment__metadata{position:absolute;left:50%;top:2em;-webkit-transform:translate(-50%);transform:translate(-50%);max-width:90%;padding:.1em .6em;font-size:.8em;color:#fff;background-color:rgba(0,0,0,.7);border-radius:3px}trix-editor .attachment__metadata .attachment__name{display:inline-block;max-width:100%;vertical-align:bottom;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}trix-editor .attachment__metadata .attachment__size{margin-left:.2em;white-space:nowrap}.trix-content{line-height:1.5}.trix-content *{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0}.trix-content h1{font-size:1.2em;line-height:1.2}.trix-content blockquote{border:0 solid #ccc;border-left-width:.3em;margin-left:.3em;padding-left:.6em}.trix-content [dir=rtl] blockquote,.trix-content blockquote[dir=rtl]{border-width:0;border-right-width:.3em;margin-right:.3em;padding-right:.6em}.trix-content li{margin-left:1em}.trix-content [dir=rtl] li{margin-right:1em}.trix-content pre{display:inline-block;width:100%;vertical-align:top;font-family:monospace;font-size:.9em;padding:.5em;white-space:pre;background-color:#eee;overflow-x:auto}.trix-content img{max-width:100%;height:auto}.trix-content .attachment{display:inline-block;position:relative;max-width:100%}.trix-content .attachment a{color:inherit;text-decoration:none}.trix-content .attachment a:hover,.trix-content .attachment a:visited:hover{color:inherit}.trix-content .attachment__caption{text-align:center}.trix-content .attachment__caption .attachment__name+.attachment__size:before{content:" · "}.trix-content .attachment--preview{width:100%;text-align:center}.trix-content .attachment--preview .attachment__caption{color:#666;font-size:.9em;line-height:1.2}.trix-content .attachment--file{color:#333;line-height:1;margin:0 2px 2px 2px;padding:.4em 1em;border:1px solid #bbb;border-radius:5px}.trix-content .attachment-gallery{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;position:relative}.trix-content .attachment-gallery .attachment{-webkit-box-flex:1;-ms-flex:1 0 33%;flex:1 0 33%;padding:0 .5em;max-width:33%}.trix-content .attachment-gallery.attachment-gallery--2 .attachment,.trix-content .attachment-gallery.attachment-gallery--4 .attachment{-ms-flex-preferred-size:50%;flex-basis:50%;max-width:50%}.VueTrix_trix_container_5Bcya{max-width:100%;height:auto}.VueTrix_trix_container_5Bcya .VueTrix_trix-button-group_2D-Jd,.VueTrix_trix_container_5Bcya .VueTrix_trix-content_1TD_D{background-color:#fff}
--------------------------------------------------------------------------------
/dist/vue-trix.esm.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Trix from 'trix';
3 | import 'trix/dist/trix.css';
4 |
5 | /**
6 | *
7 | * @param {*} component
8 | */
9 | function EmitFileAccept (component) {
10 | return {
11 | methods: {
12 | emitFileAccept: function emitFileAccept (file) {
13 | this.$emit('trix-file-accept', file);
14 | }
15 | }
16 | }
17 | }
18 |
19 | /**
20 | *
21 | * @param {*} component
22 | */
23 | function EmitInitialize (component) {
24 | return {
25 | methods: {
26 | emitInitialize: function emitInitialize (editor) {
27 | this.$emit('trix-initialize', this.$refs.trix.editor, event);
28 | }
29 | }
30 | }
31 | }
32 |
33 | /**
34 | *
35 | * @param {*} component
36 | */
37 | function EmitAttachmentAdd (component) {
38 | return {
39 | methods: {
40 | emitAttachmentAdd: function emitAttachmentAdd (file) {
41 | this.$emit('trix-attachment-add', file);
42 | }
43 | }
44 | }
45 | }
46 |
47 | /**
48 | *
49 | * @param {*} component
50 | */
51 | function EmitSelectionChange (component) {
52 | return {
53 | methods: {
54 | emitSelectionChange: function emitSelectionChange (event) {
55 | this.$emit('trix-selection-change', this.$refs.trix.editor, event);
56 | }
57 | }
58 | }
59 | }
60 |
61 | /**
62 | *
63 | * @param {*} component
64 | */
65 | function EmitAttachmentRemove (component) {
66 | return {
67 | methods: {
68 | emitAttachmentRemove: function emitAttachmentRemove (file) {
69 | this.$emit('trix-attachment-remove', file);
70 | }
71 | }
72 | }
73 | }
74 |
75 | /**
76 | *
77 | * @param {*} component
78 | */
79 | function EmitBeforeInitialize (component) {
80 | return {
81 | methods: {
82 | emitBeforeInitialize: function emitBeforeInitialize (event) {
83 | this.$emit('trix-before-initialize', this.$refs.trix.editor, event);
84 | }
85 | }
86 | }
87 | }
88 |
89 | function ProcessEditorFocusAndBlur (component) {
90 | return {
91 | methods: {
92 | processTrixFocus: function processTrixFocus (event) {
93 | if (this.$refs.trix) {
94 | this.isActived = true;
95 | this.$emit('trix-focus', this.$refs.trix.editor, event);
96 | }
97 | },
98 | processTrixBlur: function processTrixBlur (event) {
99 | if (this.$refs.trix) {
100 | this.isActived = false;
101 | this.$emit('trix-blur', this.$refs.trix.editor, event);
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 | //
109 |
110 | var script = {
111 | name: 'vue-trix',
112 | mixins: [
113 | EmitFileAccept(),
114 | EmitInitialize(),
115 | EmitAttachmentAdd(),
116 | EmitSelectionChange(),
117 | EmitAttachmentRemove(),
118 | EmitBeforeInitialize(),
119 | ProcessEditorFocusAndBlur()
120 | ],
121 | model: {
122 | prop: 'srcContent',
123 | event: 'update'
124 | },
125 | props: {
126 | /**
127 | * This prop will put the editor in read-only mode
128 | */
129 | disabledEditor: {
130 | type: Boolean,
131 | required: false,
132 | default: function default$1 () {
133 | return false
134 | }
135 | },
136 | /**
137 | * This is referenced `id` of the hidden input field defined.
138 | * It is optional and will be a random string by default.
139 | */
140 | inputId: {
141 | type: String,
142 | required: false,
143 | default: function default$2 () {
144 | return ''
145 | }
146 | },
147 | /**
148 | * This is referenced `name` of the hidden input field defined,
149 | * default value is `content`.
150 | */
151 | inputName: {
152 | type: String,
153 | required: false,
154 | default: function default$3 () {
155 | return 'content'
156 | }
157 | },
158 | /**
159 | * The placeholder attribute specifies a short hint
160 | * that describes the expected value of a editor.
161 | */
162 | placeholder: {
163 | type: String,
164 | required: false,
165 | default: function default$4 () {
166 | return ''
167 | }
168 | },
169 | /**
170 | * The source content is associcated to v-model directive.
171 | */
172 | srcContent: {
173 | type: String,
174 | required: false,
175 | default: function default$5 () {
176 | return ''
177 | }
178 | },
179 | /**
180 | * The boolean attribute allows saving editor state into browser's localStorage
181 | * (optional, default is `false`).
182 | */
183 | localStorage: {
184 | type: Boolean,
185 | required: false,
186 | default: function default$6 () {
187 | return false
188 | }
189 | },
190 | /**
191 | * Focuses cursor in the editor when attached to the DOM
192 | * (optional, default is `false`).
193 | */
194 | autofocus: {
195 | type: Boolean,
196 | required: false,
197 | default: function default$7 () {
198 | return false
199 | }
200 | },
201 | /**
202 | * Object to override default editor configuration
203 | */
204 | config: {
205 | type: Object,
206 | required: false,
207 | default: function default$8 () {
208 | return {}
209 | }
210 | }
211 | },
212 | mounted: function mounted () {
213 | var this$1 = this;
214 |
215 | /** Override editor configuration */
216 | this.overrideConfig(this.config);
217 | /** Check if editor read-only mode is required */
218 | this.decorateDisabledEditor(this.disabledEditor);
219 | this.$nextTick(function () {
220 | /**
221 | * If localStorage is enabled,
222 | * then load editor's content from the beginning.
223 | */
224 | if (this$1.localStorage) {
225 | var savedValue = localStorage.getItem(this$1.storageId('VueTrix'));
226 | if (savedValue && !this$1.srcContent) {
227 | this$1.$refs.trix.editor.loadJSON(JSON.parse(savedValue));
228 | }
229 | }
230 | });
231 | },
232 | data: function data () {
233 | return {
234 | editorContent: this.srcContent,
235 | isActived: null
236 | }
237 | },
238 | methods: {
239 | handleContentChange: function handleContentChange (event) {
240 | this.editorContent = event.srcElement ? event.srcElement.value : event.target.value;
241 | this.$emit('input', this.editorContent);
242 | },
243 | handleInitialize: function handleInitialize (event) {
244 | /**
245 | * If autofocus is true, manually set focus to
246 | * beginning of content (consistent with Trix behavior)
247 | */
248 | if (this.autofocus) {
249 | this.$refs.trix.editor.setSelectedRange(0);
250 | }
251 |
252 | this.$emit('trix-initialize', this.emitInitialize);
253 | },
254 | handleInitialContentChange: function handleInitialContentChange (newContent, oldContent) {
255 | newContent = newContent === undefined ? '' : newContent;
256 |
257 | if (this.$refs.trix.editor && this.$refs.trix.editor.innerHTML !== newContent) {
258 | /* Update editor's content when initial content changed */
259 | this.editorContent = newContent;
260 |
261 | /**
262 | * If user are typing, then don't reload the editor,
263 | * hence keep cursor's position after typing.
264 | */
265 | if (!this.isActived) {
266 | this.reloadEditorContent(this.editorContent);
267 | }
268 | }
269 | },
270 | emitEditorState: function emitEditorState (value) {
271 | /**
272 | * If localStorage is enabled,
273 | * then save editor's content into storage
274 | */
275 | if (this.localStorage) {
276 | localStorage.setItem(
277 | this.storageId('VueTrix'),
278 | JSON.stringify(this.$refs.trix.editor)
279 | );
280 | }
281 | this.$emit('update', this.editorContent);
282 | },
283 | storageId: function storageId (component) {
284 | if (this.inputId) {
285 | return (component + "." + (this.inputId) + ".content")
286 | } else {
287 | return (component + ".content")
288 | }
289 | },
290 | reloadEditorContent: function reloadEditorContent (newContent) {
291 | // Reload HTML content
292 | this.$refs.trix.editor.loadHTML(newContent);
293 |
294 | // Move cursor to end of new content updated
295 | this.$refs.trix.editor.setSelectedRange(this.getContentEndPosition());
296 | },
297 | getContentEndPosition: function getContentEndPosition () {
298 | return this.$refs.trix.editor.getDocument().toString().length - 1
299 | },
300 | decorateDisabledEditor: function decorateDisabledEditor (editorState) {
301 | /** Disable toolbar and editor by pointer events styling */
302 | if (editorState) {
303 | this.$refs.trix.toolbarElement.style['pointer-events'] = 'none';
304 | this.$refs.trix.contentEditable = false;
305 | this.$refs.trix.style['background'] = '#e9ecef';
306 | } else {
307 | this.$refs.trix.toolbarElement.style['pointer-events'] = 'unset';
308 | this.$refs.trix.style['pointer-events'] = 'unset';
309 | this.$refs.trix.style['background'] = 'transparent';
310 | }
311 | },
312 | overrideConfig: function overrideConfig (config) {
313 | Trix.config = this.deepMerge(Trix.config, config);
314 | },
315 | deepMerge: function deepMerge (target, override) {
316 | // deep merge the object into the target object
317 | for (var prop in override) {
318 | if (override.hasOwnProperty(prop)) {
319 | if (Object.prototype.toString.call(override[prop]) === '[object Object]') {
320 | // if the property is a nested object
321 | target[prop] = this.deepMerge(target[prop], override[prop]);
322 | } else {
323 | // for regular property
324 | target[prop] = override[prop];
325 | }
326 | }
327 | }
328 |
329 | return target
330 | }
331 | },
332 | computed: {
333 | /**
334 | * Compute a random id of hidden input
335 | * when it haven't been specified.
336 | */
337 | generateId: function generateId () {
338 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
339 | var r = Math.random() * 16 | 0;
340 | var v = c === 'x' ? r : (r & 0x3 | 0x8);
341 | return v.toString(16)
342 | })
343 | },
344 | computedId: function computedId () {
345 | return this.inputId || this.generateId
346 | },
347 | initialContent: function initialContent () {
348 | return this.srcContent
349 | },
350 | isDisabled: function isDisabled () {
351 | return this.disabledEditor
352 | }
353 | },
354 | watch: {
355 | editorContent: {
356 | handler: 'emitEditorState'
357 | },
358 | initialContent: {
359 | handler: 'handleInitialContentChange'
360 | },
361 | isDisabled: {
362 | handler: 'decorateDisabledEditor'
363 | },
364 | config: {
365 | handler: 'overrideConfig',
366 | deep: true
367 | }
368 | }
369 | };
370 |
371 | function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
372 | if (typeof shadowMode !== 'boolean') {
373 | createInjectorSSR = createInjector;
374 | createInjector = shadowMode;
375 | shadowMode = false;
376 | }
377 | // Vue.extend constructor export interop.
378 | var options = typeof script === 'function' ? script.options : script;
379 | // render functions
380 | if (template && template.render) {
381 | options.render = template.render;
382 | options.staticRenderFns = template.staticRenderFns;
383 | options._compiled = true;
384 | // functional template
385 | if (isFunctionalTemplate) {
386 | options.functional = true;
387 | }
388 | }
389 | // scopedId
390 | if (scopeId) {
391 | options._scopeId = scopeId;
392 | }
393 | var hook;
394 | if (moduleIdentifier) {
395 | // server build
396 | hook = function (context) {
397 | // 2.3 injection
398 | context =
399 | context || // cached call
400 | (this.$vnode && this.$vnode.ssrContext) || // stateful
401 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional
402 | // 2.2 with runInNewContext: true
403 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
404 | context = __VUE_SSR_CONTEXT__;
405 | }
406 | // inject component styles
407 | if (style) {
408 | style.call(this, createInjectorSSR(context));
409 | }
410 | // register component module identifier for async chunk inference
411 | if (context && context._registeredComponents) {
412 | context._registeredComponents.add(moduleIdentifier);
413 | }
414 | };
415 | // used by ssr in case component is cached and beforeCreate
416 | // never gets called
417 | options._ssrRegister = hook;
418 | }
419 | else if (style) {
420 | hook = shadowMode
421 | ? function (context) {
422 | style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
423 | }
424 | : function (context) {
425 | style.call(this, createInjector(context));
426 | };
427 | }
428 | if (hook) {
429 | if (options.functional) {
430 | // register for functional component in vue file
431 | var originalRender = options.render;
432 | options.render = function renderWithStyleInjection(h, context) {
433 | hook.call(context);
434 | return originalRender(h, context);
435 | };
436 | }
437 | else {
438 | // inject component registration as beforeCreate hook
439 | var existing = options.beforeCreate;
440 | options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
441 | }
442 | }
443 | return script;
444 | }
445 |
446 | var isOldIE = typeof navigator !== 'undefined' &&
447 | /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase());
448 | function createInjector(context) {
449 | return function (id, style) { return addStyle(id, style); };
450 | }
451 | var HEAD;
452 | var styles = {};
453 | function addStyle(id, css) {
454 | var group = isOldIE ? css.media || 'default' : id;
455 | var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] });
456 | if (!style.ids.has(id)) {
457 | style.ids.add(id);
458 | var code = css.source;
459 | if (css.map) {
460 | // https://developer.chrome.com/devtools/docs/javascript-debugging
461 | // this makes source maps inside style tags work properly in Chrome
462 | code += '\n/*# sourceURL=' + css.map.sources[0] + ' */';
463 | // http://stackoverflow.com/a/26603875
464 | code +=
465 | '\n/*# sourceMappingURL=data:application/json;base64,' +
466 | btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) +
467 | ' */';
468 | }
469 | if (!style.element) {
470 | style.element = document.createElement('style');
471 | style.element.type = 'text/css';
472 | if (css.media)
473 | { style.element.setAttribute('media', css.media); }
474 | if (HEAD === undefined) {
475 | HEAD = document.head || document.getElementsByTagName('head')[0];
476 | }
477 | HEAD.appendChild(style.element);
478 | }
479 | if ('styleSheet' in style.element) {
480 | style.styles.push(code);
481 | style.element.styleSheet.cssText = style.styles
482 | .filter(Boolean)
483 | .join('\n');
484 | }
485 | else {
486 | var index = style.ids.size - 1;
487 | var textNode = document.createTextNode(code);
488 | var nodes = style.element.childNodes;
489 | if (nodes[index])
490 | { style.element.removeChild(nodes[index]); }
491 | if (nodes.length)
492 | { style.element.insertBefore(textNode, nodes[index]); }
493 | else
494 | { style.element.appendChild(textNode); }
495 | }
496 | }
497 | }
498 |
499 | /* script */
500 | var __vue_script__ = script;
501 |
502 | /* template */
503 | var __vue_render__ = function() {
504 | var _vm = this;
505 | var _h = _vm.$createElement;
506 | var _c = _vm._self._c || _h;
507 | return _c(
508 | "div",
509 | { class: [_vm.$style.trix_container] },
510 | [
511 | _c("trix-editor", {
512 | ref: "trix",
513 | class: ["trix-content"],
514 | attrs: {
515 | contenteditable: !_vm.disabledEditor,
516 | input: _vm.computedId,
517 | placeholder: _vm.placeholder
518 | },
519 | on: {
520 | "trix-change": _vm.handleContentChange,
521 | "trix-file-accept": _vm.emitFileAccept,
522 | "trix-attachment-add": _vm.emitAttachmentAdd,
523 | "trix-attachment-remove": _vm.emitAttachmentRemove,
524 | "trix-selection-change": _vm.emitSelectionChange,
525 | "trix-initialize": _vm.handleInitialize,
526 | "trix-before-initialize": _vm.emitBeforeInitialize,
527 | "trix-focus": _vm.processTrixFocus,
528 | "trix-blur": _vm.processTrixBlur
529 | }
530 | }),
531 | _vm._v(" "),
532 | _c("input", {
533 | attrs: { type: "hidden", name: _vm.inputName, id: _vm.computedId },
534 | domProps: { value: _vm.editorContent }
535 | })
536 | ],
537 | 1
538 | )
539 | };
540 | var __vue_staticRenderFns__ = [];
541 | __vue_render__._withStripped = true;
542 |
543 | /* style */
544 | var __vue_inject_styles__ = function (inject) {
545 | if (!inject) { return }
546 | inject("data-v-501b9774_0", { source: "\n.src-components-trix_container-5Bcy {\n max-width: 100%;\n height: auto;\n}\n.src-components-trix_container-5Bcy .src-components-trix-button-group-2D-J {\n background-color: white;\n}\n.src-components-trix_container-5Bcy .src-components-trix-content-1TD_ {\n background-color: white;\n}\n", map: {"version":3,"sources":["/home/hanh/side-projects/vue-trix/src/components/VueTrix.vue"],"names":[],"mappings":";AA2SA;EACA,eAAA;EACA,YAAA;AACA;AACA;EACA,uBAAA;AACA;AACA;EACA,uBAAA;AACA","file":"VueTrix.vue","sourcesContent":["\n \n \n \n
\n \n\n\n\n\n"]}, media: undefined });
547 | Object.defineProperty(this, "$style", { value: {"trix_container":"src-components-trix_container-5Bcy","trix-button-group":"src-components-trix-button-group-2D-J","trix-content":"src-components-trix-content-1TD_"} });
548 |
549 | };
550 | /* scoped */
551 | var __vue_scope_id__ = undefined;
552 | /* module identifier */
553 | var __vue_module_identifier__ = undefined;
554 | /* functional template */
555 | var __vue_is_functional_template__ = false;
556 | /* style inject SSR */
557 |
558 | /* style inject shadow dom */
559 |
560 |
561 |
562 | var __vue_component__ = /*#__PURE__*/normalizeComponent(
563 | { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
564 | __vue_inject_styles__,
565 | __vue_script__,
566 | __vue_scope_id__,
567 | __vue_is_functional_template__,
568 | __vue_module_identifier__,
569 | false,
570 | createInjector,
571 | undefined,
572 | undefined
573 | );
574 |
575 | /*
576 | * Vue-Trix index.js
577 | * Author: tranduchanh.ms@gmail.com
578 | * Github: https://github.com/hanhdt/vue-trix
579 | */
580 | Vue.config.ignoredElements = ['trix-editor'];
581 |
582 | Vue.component(__vue_component__.name, __vue_component__);
583 |
584 | export default __vue_component__;
585 | //# sourceMappingURL=vue-trix.esm.js.map
586 |
--------------------------------------------------------------------------------
/dist/vue-trix.esm.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"vue-trix.esm.js","sources":["../src/mixins/EmitFileAccept.js","../src/mixins/EmitInitialize.js","../src/mixins/EmitAttachmentAdd.js","../src/mixins/EmitSelectionChange.js","../src/mixins/EmitAttachmentRemove.js","../src/mixins/EmitBeforeInitialize.js","../src/mixins/ProcessEditorFocusAndBlur.js","../src/components/VueTrix.vue","../node_modules/vue-runtime-helpers/dist/normalize-component.mjs","../node_modules/vue-runtime-helpers/dist/inject-style/browser.mjs","../src/index.js"],"sourcesContent":["/**\n *\n * @param {*} component\n */\nexport default function (component) {\n return {\n methods: {\n emitFileAccept (file) {\n this.$emit('trix-file-accept', file)\n }\n }\n }\n}\n","/**\n *\n * @param {*} component\n */\nexport default function (component) {\n return {\n methods: {\n emitInitialize (editor) {\n this.$emit('trix-initialize', this.$refs.trix.editor, event)\n }\n }\n }\n}\n","/**\n *\n * @param {*} component\n */\nexport default function (component) {\n return {\n methods: {\n emitAttachmentAdd (file) {\n this.$emit('trix-attachment-add', file)\n }\n }\n }\n}\n","/**\n *\n * @param {*} component\n */\nexport default function (component) {\n return {\n methods: {\n emitSelectionChange (event) {\n this.$emit('trix-selection-change', this.$refs.trix.editor, event)\n }\n }\n }\n}\n","/**\n *\n * @param {*} component\n */\nexport default function (component) {\n return {\n methods: {\n emitAttachmentRemove (file) {\n this.$emit('trix-attachment-remove', file)\n }\n }\n }\n}\n","/**\n *\n * @param {*} component\n */\nexport default function (component) {\n return {\n methods: {\n emitBeforeInitialize (event) {\n this.$emit('trix-before-initialize', this.$refs.trix.editor, event)\n }\n }\n }\n}\n","export default function (component) {\n return {\n methods: {\n processTrixFocus (event) {\n if (this.$refs.trix) {\n this.isActived = true\n this.$emit('trix-focus', this.$refs.trix.editor, event)\n }\n },\n processTrixBlur (event) {\n if (this.$refs.trix) {\n this.isActived = false\n this.$emit('trix-blur', this.$refs.trix.editor, event)\n }\n }\n }\n }\n}\n","\n \n \n \n
\n \n\n\n\n\n","function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {\r\n if (typeof shadowMode !== 'boolean') {\r\n createInjectorSSR = createInjector;\r\n createInjector = shadowMode;\r\n shadowMode = false;\r\n }\r\n // Vue.extend constructor export interop.\r\n const options = typeof script === 'function' ? script.options : script;\r\n // render functions\r\n if (template && template.render) {\r\n options.render = template.render;\r\n options.staticRenderFns = template.staticRenderFns;\r\n options._compiled = true;\r\n // functional template\r\n if (isFunctionalTemplate) {\r\n options.functional = true;\r\n }\r\n }\r\n // scopedId\r\n if (scopeId) {\r\n options._scopeId = scopeId;\r\n }\r\n let hook;\r\n if (moduleIdentifier) {\r\n // server build\r\n hook = function (context) {\r\n // 2.3 injection\r\n context =\r\n context || // cached call\r\n (this.$vnode && this.$vnode.ssrContext) || // stateful\r\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional\r\n // 2.2 with runInNewContext: true\r\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\r\n context = __VUE_SSR_CONTEXT__;\r\n }\r\n // inject component styles\r\n if (style) {\r\n style.call(this, createInjectorSSR(context));\r\n }\r\n // register component module identifier for async chunk inference\r\n if (context && context._registeredComponents) {\r\n context._registeredComponents.add(moduleIdentifier);\r\n }\r\n };\r\n // used by ssr in case component is cached and beforeCreate\r\n // never gets called\r\n options._ssrRegister = hook;\r\n }\r\n else if (style) {\r\n hook = shadowMode\r\n ? function (context) {\r\n style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));\r\n }\r\n : function (context) {\r\n style.call(this, createInjector(context));\r\n };\r\n }\r\n if (hook) {\r\n if (options.functional) {\r\n // register for functional component in vue file\r\n const originalRender = options.render;\r\n options.render = function renderWithStyleInjection(h, context) {\r\n hook.call(context);\r\n return originalRender(h, context);\r\n };\r\n }\r\n else {\r\n // inject component registration as beforeCreate hook\r\n const existing = options.beforeCreate;\r\n options.beforeCreate = existing ? [].concat(existing, hook) : [hook];\r\n }\r\n }\r\n return script;\r\n}\n\nexport default normalizeComponent;\n//# sourceMappingURL=normalize-component.mjs.map\n","const isOldIE = typeof navigator !== 'undefined' &&\r\n /msie [6-9]\\\\b/.test(navigator.userAgent.toLowerCase());\r\nfunction createInjector(context) {\r\n return (id, style) => addStyle(id, style);\r\n}\r\nlet HEAD;\r\nconst styles = {};\r\nfunction addStyle(id, css) {\r\n const group = isOldIE ? css.media || 'default' : id;\r\n const style = styles[group] || (styles[group] = { ids: new Set(), styles: [] });\r\n if (!style.ids.has(id)) {\r\n style.ids.add(id);\r\n let code = css.source;\r\n if (css.map) {\r\n // https://developer.chrome.com/devtools/docs/javascript-debugging\r\n // this makes source maps inside style tags work properly in Chrome\r\n code += '\\n/*# sourceURL=' + css.map.sources[0] + ' */';\r\n // http://stackoverflow.com/a/26603875\r\n code +=\r\n '\\n/*# sourceMappingURL=data:application/json;base64,' +\r\n btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) +\r\n ' */';\r\n }\r\n if (!style.element) {\r\n style.element = document.createElement('style');\r\n style.element.type = 'text/css';\r\n if (css.media)\r\n style.element.setAttribute('media', css.media);\r\n if (HEAD === undefined) {\r\n HEAD = document.head || document.getElementsByTagName('head')[0];\r\n }\r\n HEAD.appendChild(style.element);\r\n }\r\n if ('styleSheet' in style.element) {\r\n style.styles.push(code);\r\n style.element.styleSheet.cssText = style.styles\r\n .filter(Boolean)\r\n .join('\\n');\r\n }\r\n else {\r\n const index = style.ids.size - 1;\r\n const textNode = document.createTextNode(code);\r\n const nodes = style.element.childNodes;\r\n if (nodes[index])\r\n style.element.removeChild(nodes[index]);\r\n if (nodes.length)\r\n style.element.insertBefore(textNode, nodes[index]);\r\n else\r\n style.element.appendChild(textNode);\r\n }\r\n }\r\n}\n\nexport default createInjector;\n//# sourceMappingURL=browser.mjs.map\n","/*\n * Vue-Trix index.js\n * Author: tranduchanh.ms@gmail.com\n * Github: https://github.com/hanhdt/vue-trix\n */\n\nimport Vue from 'vue'\nimport VueTrix from './components/VueTrix.vue'\nVue.config.ignoredElements = ['trix-editor']\n\nVue.component(VueTrix.name, VueTrix)\n\nexport default VueTrix\n"],"names":["const","let","VueTrix"],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/vue-trix.min.js:
--------------------------------------------------------------------------------
1 | var VueTrix=function(e,t){"use strict";e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e,t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var n={name:"vue-trix",mixins:[{methods:{emitFileAccept:function(e){this.$emit("trix-file-accept",e)}}},{methods:{emitInitialize:function(){this.$emit("trix-initialize",this.$refs.trix.editor,event)}}},{methods:{emitAttachmentAdd:function(e){this.$emit("trix-attachment-add",e)}}},{methods:{emitSelectionChange:function(e){this.$emit("trix-selection-change",this.$refs.trix.editor,e)}}},{methods:{emitAttachmentRemove:function(e){this.$emit("trix-attachment-remove",e)}}},{methods:{emitBeforeInitialize:function(e){this.$emit("trix-before-initialize",this.$refs.trix.editor,e)}}},{methods:{processTrixFocus:function(e){this.$refs.trix&&(this.isActived=!0,this.$emit("trix-focus",this.$refs.trix.editor,e))},processTrixBlur:function(e){this.$refs.trix&&(this.isActived=!1,this.$emit("trix-blur",this.$refs.trix.editor,e))}}}],model:{prop:"srcContent",event:"update"},props:{disabledEditor:{type:Boolean,required:!1,default:function(){return!1}},inputId:{type:String,required:!1,default:function(){return""}},inputName:{type:String,required:!1,default:function(){return"content"}},placeholder:{type:String,required:!1,default:function(){return""}},srcContent:{type:String,required:!1,default:function(){return""}},localStorage:{type:Boolean,required:!1,default:function(){return!1}},autofocus:{type:Boolean,required:!1,default:function(){return!1}},config:{type:Object,required:!1,default:function(){return{}}}},mounted:function(){var t=this;this.overrideConfig(this.config),this.decorateDisabledEditor(this.disabledEditor),this.$nextTick(function(){if(t.localStorage){var e=localStorage.getItem(t.storageId("VueTrix"));e&&!t.srcContent&&t.$refs.trix.editor.loadJSON(JSON.parse(e))}})},data:function(){return{editorContent:this.srcContent,isActived:null}},methods:{handleContentChange:function(e){this.editorContent=e.srcElement?e.srcElement.value:e.target.value,this.$emit("input",this.editorContent)},handleInitialize:function(){this.autofocus&&this.$refs.trix.editor.setSelectedRange(0),this.$emit("trix-initialize",this.emitInitialize)},handleInitialContentChange:function(e){e=void 0===e?"":e,this.$refs.trix.editor&&this.$refs.trix.editor.innerHTML!==e&&(this.editorContent=e,this.isActived||this.reloadEditorContent(this.editorContent))},emitEditorState:function(){this.localStorage&&localStorage.setItem(this.storageId("VueTrix"),JSON.stringify(this.$refs.trix.editor)),this.$emit("update",this.editorContent)},storageId:function(e){return this.inputId?e+"."+this.inputId+".content":e+".content"},reloadEditorContent:function(e){this.$refs.trix.editor.loadHTML(e),this.$refs.trix.editor.setSelectedRange(this.getContentEndPosition())},getContentEndPosition:function(){return this.$refs.trix.editor.getDocument().toString().length-1},decorateDisabledEditor:function(e){e?(this.$refs.trix.toolbarElement.style["pointer-events"]="none",this.$refs.trix.contentEditable=!1,this.$refs.trix.style.background="#e9ecef"):(this.$refs.trix.toolbarElement.style["pointer-events"]="unset",this.$refs.trix.style["pointer-events"]="unset",this.$refs.trix.style.background="transparent")},overrideConfig:function(e){t.config=this.deepMerge(t.config,e)},deepMerge:function(e,t){for(var n in t)t.hasOwnProperty(n)&&("[object Object]"===Object.prototype.toString.call(t[n])?e[n]=this.deepMerge(e[n],t[n]):e[n]=t[n]);return e}},computed:{generateId:function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)})},computedId:function(){return this.inputId||this.generateId},initialContent:function(){return this.srcContent},isDisabled:function(){return this.disabledEditor}},watch:{editorContent:{handler:"emitEditorState"},initialContent:{handler:"handleInitialContentChange"},isDisabled:{handler:"decorateDisabledEditor"},config:{handler:"overrideConfig",deep:!0}}};function i(e,t,n,i,r,o,s,a,d,c){"boolean"!=typeof s&&(d=a,a=s,s=!1);var l,u="function"==typeof n?n.options:n;if(e&&e.render&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns,u._compiled=!0,r&&(u.functional=!0)),i&&(u._scopeId=i),o?(l=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),t&&t.call(this,d(e)),e&&e._registeredComponents&&e._registeredComponents.add(o)},u._ssrRegister=l):t&&(l=s?function(e){t.call(this,c(e,this.$root.$options.shadowRoot))}:function(e){t.call(this,a(e))}),l)if(u.functional){var h=u.render;u.render=function(e,t){return l.call(t),h(e,t)}}else{var f=u.beforeCreate;u.beforeCreate=f?[].concat(f,l):[l]}return n}var d,c="undefined"!=typeof navigator&&/msie [6-9]\\b/.test(navigator.userAgent.toLowerCase());function r(e){return function(e,t){return function(e,t){var n=c?t.media||"default":e,i=l[n]||(l[n]={ids:new Set,styles:[]});if(!i.ids.has(e)){i.ids.add(e);var r=t.source;if(t.map&&(r+="\n/*# sourceURL="+t.map.sources[0]+" */",r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(t.map))))+" */"),i.element||(i.element=document.createElement("style"),i.element.type="text/css",t.media&&i.element.setAttribute("media",t.media),void 0===d&&(d=document.head||document.getElementsByTagName("head")[0]),d.appendChild(i.element)),"styleSheet"in i.element)i.styles.push(r),i.element.styleSheet.cssText=i.styles.filter(Boolean).join("\n");else{var o=i.ids.size-1,s=document.createTextNode(r),a=i.element.childNodes;a[o]&&i.element.removeChild(a[o]),a.length?i.element.insertBefore(s,a[o]):i.element.appendChild(s)}}}(e,t)}}var l={};function o(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{class:[e.$style.trix_container]},[n("trix-editor",{ref:"trix",class:["trix-content"],attrs:{contenteditable:!e.disabledEditor,input:e.computedId,placeholder:e.placeholder},on:{"trix-change":e.handleContentChange,"trix-file-accept":e.emitFileAccept,"trix-attachment-add":e.emitAttachmentAdd,"trix-attachment-remove":e.emitAttachmentRemove,"trix-selection-change":e.emitSelectionChange,"trix-initialize":e.handleInitialize,"trix-before-initialize":e.emitBeforeInitialize,"trix-focus":e.processTrixFocus,"trix-blur":e.processTrixBlur}}),e._v(" "),n("input",{attrs:{type:"hidden",name:e.inputName,id:e.computedId},domProps:{value:e.editorContent}})],1)}var s=n,a=(o._withStripped=!0,i({render:o,staticRenderFns:[]},function(e){e&&(e("data-v-501b9774_0",{source:"\n.src-components-trix_container-5Bcy {\n max-width: 100%;\n height: auto;\n}\n.src-components-trix_container-5Bcy .src-components-trix-button-group-2D-J {\n background-color: white;\n}\n.src-components-trix_container-5Bcy .src-components-trix-content-1TD_ {\n background-color: white;\n}\n",map:{version:3,sources:["/home/hanh/side-projects/vue-trix/src/components/VueTrix.vue"],names:[],mappings:";AA2SA;EACA,eAAA;EACA,YAAA;AACA;AACA;EACA,uBAAA;AACA;AACA;EACA,uBAAA;AACA",file:"VueTrix.vue",sourcesContent:["\n \n \n \n
\n \n\n\n\n\n","/*\n * Vue-Trix index.js\n * Author: tranduchanh.ms@gmail.com\n * Github: https://github.com/hanhdt/vue-trix\n */\n\nimport Vue from 'vue'\nimport VueTrix from './components/VueTrix.vue'\nVue.config.ignoredElements = ['trix-editor']\n\nVue.component(VueTrix.name, VueTrix)\n\nexport default VueTrix\n"],"names":["methods","emitFileAccept","file","this","$emit","emitInitialize","$refs","trix","editor","event","emitAttachmentAdd","emitSelectionChange","emitAttachmentRemove","emitBeforeInitialize","processTrixFocus","isActived","processTrixBlur","normalizeComponent","template","style","script","scopeId","isFunctionalTemplate","moduleIdentifier","shadowMode","createInjector","createInjectorSSR","createInjectorShadow","const","hook","options","render","staticRenderFns","_compiled","functional","_scopeId","context","$vnode","ssrContext","parent","__VUE_SSR_CONTEXT__","call","_registeredComponents","add","_ssrRegister","$root","$options","shadowRoot","originalRender","h","existing","beforeCreate","concat","HEAD","isOldIE","navigator","test","userAgent","toLowerCase","id","css","group","media","styles","ids","Set","has","let","code","source","map","sources","btoa","unescape","encodeURIComponent","JSON","stringify","element","document","createElement","type","setAttribute","undefined","head","getElementsByTagName","appendChild","push","styleSheet","cssText","filter","Boolean","join","index","size","textNode","createTextNode","nodes","childNodes","removeChild","length","insertBefore","addStyle","Vue","config","ignoredElements","component","VueTrix","name"],"mappings":"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"}
--------------------------------------------------------------------------------
/example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanhdt/vue-trix/b0ab9a4504f56c0a15aa169746ad76090a7fd96c/example/public/favicon.ico
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | vue-trix
9 |
10 |
11 |
12 | We're sorry but vue-trix doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/example/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Vue-Trix editor examples
4 |
5 |
6 |
7 |
8 |
18 |
19 |
28 |
--------------------------------------------------------------------------------
/example/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanhdt/vue-trix/b0ab9a4504f56c0a15aa169746ad76090a7fd96c/example/src/assets/logo.png
--------------------------------------------------------------------------------
/example/src/assets/vue-trix-editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanhdt/vue-trix/b0ab9a4504f56c0a15aa169746ad76090a7fd96c/example/src/assets/vue-trix-editor.png
--------------------------------------------------------------------------------
/example/src/assets/vue-trix-form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanhdt/vue-trix/b0ab9a4504f56c0a15aa169746ad76090a7fd96c/example/src/assets/vue-trix-form.png
--------------------------------------------------------------------------------
/example/src/assets/vue-trix-in-prod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanhdt/vue-trix/b0ab9a4504f56c0a15aa169746ad76090a7fd96c/example/src/assets/vue-trix-in-prod.png
--------------------------------------------------------------------------------
/example/src/assets/vue-trix-simple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanhdt/vue-trix/b0ab9a4504f56c0a15aa169746ad76090a7fd96c/example/src/assets/vue-trix-simple.png
--------------------------------------------------------------------------------
/example/src/components/Editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
1. A simple text editor
5 |
16 |
17 |
18 |
19 |
2. Integrating with Forms
20 |
25 |
26 |
27 |
28 |
3. Text editor disabled
29 |
40 |
41 |
42 |
43 |
4. Override default configuration
44 |
55 |
56 |
57 |
58 |
59 |
120 |
121 |
122 |
147 |
--------------------------------------------------------------------------------
/example/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import App from './App.vue';
3 |
4 | const app = createApp(App);
5 | app.mount('#app')
6 |
7 | export default app;
8 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleFileExtensions: [
3 | 'js',
4 | 'json',
5 | 'vue'
6 | ],
7 | testEnvironment: 'jsdom',
8 | transform: {
9 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
10 | "^.+\\.vue$": ["vue-jest", {
11 | compilerOptions: {
12 | isCustomElement: tag => tag === 'trix-editor'
13 | }
14 | }],
15 | "^.+\\js$": "babel-jest"
16 | },
17 | transformIgnorePatterns: [
18 | '/node_modules/.*'
19 | ],
20 | moduleNameMapper: {
21 | '^@/(.*)$': '/src/$1',
22 | '\\.(css|less|scss)$': 'identity-obj-proxy'
23 | },
24 | snapshotSerializers: [
25 | 'jest-serializer-vue',
26 | '/jest/htmlSnapshotBeautifier.js'
27 | ],
28 | testMatch: [
29 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
30 | ],
31 | collectCoverage: true,
32 | coverageReporters: ['html', 'text-summary'],
33 | collectCoverageFrom: [
34 | 'src/**/*.{js,vue}',
35 | '!**/node_modules/**',
36 | '!src/index.js',
37 | '!src/mixins/**'
38 | ],
39 | globals: {},
40 | }
41 |
--------------------------------------------------------------------------------
/jest/htmlSnapshotBeautifier.js:
--------------------------------------------------------------------------------
1 | const snapshot = require('jest-snapshot')
2 | const beautify = require('js-beautify').html
3 |
4 | module.exports = {
5 | test (object) {
6 | return typeof object == 'string' && object[0] === '<'
7 | },
8 | print (val, print, opts, colors) {
9 | return beautify(val, {})
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-trix",
3 | "version": "1.3.0",
4 | "description": "Lightweight and simple Trix rich-text editor component for Vue.js",
5 | "main": "dist/vue-trix.umd.js",
6 | "module": "dist/vue-trix.esm.js",
7 | "unpkg": "dist/vue-trix.min.js",
8 | "browser": {
9 | "./sfc": "src/components/VueTrix.vue"
10 | },
11 | "files": [
12 | "example/*",
13 | "dist/*",
14 | "src/*",
15 | "*.json",
16 | "*.js"
17 | ],
18 | "homepage": "https://github.com/hanhdt/vue-trix",
19 | "bugs": "https://github.com/hanhdt/vue-trix/issues",
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/hanhdt/vue-trix.git"
23 | },
24 | "author": {
25 | "name": "Hanh D. TRAN",
26 | "email": "tranduchanh.ms@gmail.com",
27 | "url": "https://hanhdt.github.io"
28 | },
29 | "license": "MIT",
30 | "keywords": [
31 | "vue",
32 | "trix",
33 | "text editor",
34 | "vue text editor",
35 | "js",
36 | "javascript"
37 | ],
38 | "scripts": {
39 | "build": "vue-cli-service build --target lib --name vue-trix ./src/index.js",
40 | "build:es": "rollup --config build/rollup.config.es.js",
41 | "build:unpkg": "rollup --config build/rollup.config.unpkg.js",
42 | "build:example": "vue-cli-service build ./example/src/main.js",
43 | "dev": "vue-cli-service serve ./example/src/main.js --open",
44 | "lint": "vue-cli-service lint --fix",
45 | "test:unit": "vue-cli-service test:unit"
46 | },
47 | "dependencies": {
48 | "trix": "^1.3.1"
49 | },
50 | "devDependencies": {
51 | "@vue/cli-plugin-babel": "^3.12.1",
52 | "@vue/cli-plugin-eslint": "^3.12.1",
53 | "@vue/cli-plugin-unit-jest": "^4.5.6",
54 | "@vue/cli-service": "^4.5.8",
55 | "@vue/compiler-dom": "^3.2.30",
56 | "@vue/test-utils": "^2.0.0-rc.18",
57 | "babel-core": "~7.0.0-bridge.0",
58 | "babel-eslint": "^10.0.1",
59 | "babel-jest": "^25.2.6",
60 | "identity-obj-proxy": "^3.0.0",
61 | "jest-serializer-vue": "^2.0.2",
62 | "jest-transform-stub": "^2.0.0",
63 | "js-beautify": "^1.13.0",
64 | "rollup": "^1.32.1",
65 | "rollup-plugin-alias": "^2.2.0",
66 | "rollup-plugin-babel": "^4.4.0",
67 | "rollup-plugin-buble": "^0.19.6",
68 | "rollup-plugin-commonjs": "^10.0.1",
69 | "rollup-plugin-node-resolve": "^5.2.0",
70 | "rollup-plugin-replace": "^2.2.0",
71 | "rollup-plugin-sass": "^1.2.2",
72 | "rollup-plugin-uglify": "^6.0.2",
73 | "rollup-plugin-vue": "^5.1.9",
74 | "sass-loader": "^10.0.3",
75 | "uglify-es": "^3.3.9",
76 | "vue": "^3.2.30",
77 | "vue-jest": "^5.0.0-alpha.10",
78 | "vue-template-compiler": "^2.6.12"
79 | },
80 | "eslintConfig": {
81 | "root": true,
82 | "env": {
83 | "node": true
84 | },
85 | "extends": [
86 | "plugin:vue/essential"
87 | ],
88 | "rules": {},
89 | "parserOptions": {
90 | "parser": "babel-eslint"
91 | }
92 | },
93 | "postcss": {
94 | "plugins": {
95 | "autoprefixer": {}
96 | }
97 | },
98 | "browserslist": [
99 | "> 1%",
100 | "last 2 versions",
101 | "not ie <= 8"
102 | ]
103 | }
104 |
--------------------------------------------------------------------------------
/src/components/VueTrix.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
25 |
26 |
27 |
28 |
298 |
299 |
311 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Vue-Trix index.js
3 | * Author: tranduchanh.ms@gmail.com
4 | * Github: https://github.com/hanhdt/vue-trix
5 | */
6 |
7 | import VueTrix from './components/VueTrix.vue'
8 |
9 | const VueTrixPlugin = {
10 | install (app, options) {
11 | if (!options) {
12 | options = {};
13 | }
14 | app.config.compilerOptions.isCustomElement = tag => tag === 'trix-editor'
15 | app.config.ignoredElements = ['trix-editor']
16 |
17 | app.component('vue-trix', VueTrix);
18 | }
19 | };
20 |
21 | export default VueTrixPlugin;
22 |
--------------------------------------------------------------------------------
/src/mixins/EmitAttachmentAdd.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} component
4 | */
5 | export default function (component) {
6 | return {
7 | methods: {
8 | emitAttachmentAdd (file) {
9 | this.$emit('trix-attachment-add', file)
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mixins/EmitAttachmentRemove.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} component
4 | */
5 | export default function (component) {
6 | return {
7 | methods: {
8 | emitAttachmentRemove (file) {
9 | this.$emit('trix-attachment-remove', file)
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mixins/EmitBeforeInitialize.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} component
4 | */
5 | export default function (component) {
6 | return {
7 | methods: {
8 | emitBeforeInitialize (event) {
9 | // this.$emit('trix-before-initialize', this.$refs.trix.editor, event)
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mixins/EmitDroppedFile.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} component
4 | */
5 | export default function (component) {
6 | return {
7 | methods: {
8 | emitHandleFile (file) {
9 | this.$emit('trix-attachment-add', file)
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mixins/EmitFileAccept.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} component
4 | */
5 | export default function (component) {
6 | return {
7 | methods: {
8 | emitFileAccept (file) {
9 | this.$emit('trix-file-accept', file)
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mixins/EmitInitialize.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} component
4 | */
5 | export default function (component) {
6 | return {
7 | methods: {
8 | emitInitialize (editor) {
9 | this.$emit('trix-initialize', this.$refs.trix.editor, event)
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mixins/EmitSelectionChange.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} component
4 | */
5 | export default function (component) {
6 | return {
7 | methods: {
8 | emitSelectionChange (event) {
9 | this.$emit('trix-selection-change', this.$refs.trix.editor, event)
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mixins/ProcessEditorFocusAndBlur.js:
--------------------------------------------------------------------------------
1 | export default function (component) {
2 | return {
3 | methods: {
4 | processTrixFocus (event) {
5 | if (this.$refs.trix) {
6 | this.isActivated = true
7 | this.$emit('trix-focus', this.$refs.trix.editor, event)
8 | }
9 | },
10 | processTrixBlur (event) {
11 | if (this.$refs.trix) {
12 | this.isActivated = false
13 | this.$emit('trix-blur', this.$refs.trix.editor, event)
14 | }
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | },
5 | rules: {
6 | 'import/no-extraneous-dependencies': 'off'
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/unit/VueTrix.spec.js:
--------------------------------------------------------------------------------
1 | import {
2 | shallowMount,
3 | mount
4 | } from '@vue/test-utils'
5 | import VueTrix from '../../src/components/VueTrix.vue'
6 |
7 | describe('VueTrix.vue', () => {
8 | it('renders valid elements', () => {
9 | const wrapper = mount(VueTrix)
10 |
11 | // assert the component is rendered
12 | expect(wrapper.getComponent(VueTrix).exists()).toBe(true)
13 |
14 | // assert the trix-editor is rendered
15 | expect(wrapper.find('trix-editor').exists()).toBe(true)
16 | expect(wrapper.find('trix-editor').attributes().input).toBeDefined()
17 |
18 | // assert the hidden input is rendered
19 | expect(wrapper.find('input').exists()).toBe(true)
20 | // expect(wrapper.find('input').attributes('id')).toBeDefined()
21 | })
22 |
23 | it('has initial props', () => {
24 | const props = {
25 | inputId: 'inputId',
26 | inputName: 'content',
27 | placeholder: 'placeholder',
28 | srcContent: 'srcContent',
29 | localStorage: true,
30 | autofocus: true
31 | }
32 |
33 | const wrapper = shallowMount(VueTrix, { props })
34 |
35 | // assert component props correctly
36 | Object.keys(props).forEach(key => {
37 | expect(wrapper.props()[key]).toBe(props[key])
38 | })
39 | })
40 |
41 | it('has valid hidden input', () => {
42 | const wrapper = mount(VueTrix, {
43 | props: {
44 | inputId: 'inputId',
45 | inputName: 'content',
46 | srcContent: 'srcContent',
47 | placeholder: 'placeholder'
48 | }
49 | })
50 |
51 | // get hidden input element
52 | const inputWrapper = wrapper.find('input')
53 | const inputEl = inputWrapper.element
54 |
55 | // assert hidden input attributes
56 | expect(inputEl.value).toEqual('srcContent')
57 | expect(inputEl.id).toEqual('inputId')
58 | expect(inputEl.name).toEqual('content')
59 | })
60 |
61 | it('has valid trix-editor attributes', () => {
62 | const wrapper = mount(VueTrix, {
63 | props: {
64 | inputId: 'inputId',
65 | inputName: 'content',
66 | initContent: 'initContent',
67 | placeholder: 'placeholder'
68 | }
69 | })
70 |
71 | // get trix-editor element
72 | const trixWrapper = wrapper.find('trix-editor')
73 |
74 | // assert attributes
75 | expect(trixWrapper.attributes().class).toBe('trix-content')
76 | expect(trixWrapper.attributes().role).toBe('textbox')
77 | expect(trixWrapper.attributes().placeholder).toBe('placeholder')
78 | })
79 |
80 | it('works with v-model directive', () => {
81 | const wrapper = mount(VueTrix, {
82 | props: {
83 | srcContent: 'init content'
84 | }
85 | })
86 |
87 | const inputWrapper = wrapper.find('input[type="hidden"]')
88 |
89 | // Has the connect starting value
90 | expect(wrapper.props().srcContent).toEqual('init content')
91 | expect(inputWrapper.element.value).toEqual('init content')
92 |
93 | // Sets the input to the correct value when props change
94 | wrapper.setProps({ srcContent: 'new content' })
95 | expect(wrapper.vm.initialContent).toEqual('new content')
96 | })
97 |
98 | it('overrides config', () => {
99 | const propsData = {
100 | config: {
101 | blockAttributes: {
102 | heading2: {
103 | tagName: 'h2',
104 | terminal: true,
105 | breakOnReturn: true,
106 | group: false
107 | }}}}
108 |
109 |
110 | const wrapper = shallowMount(VueTrix, { propsData })
111 |
112 | // assert component props correctly
113 | expect(wrapper.props().config.blockAttributes.heading2.tagName).toBe('h2')
114 | })
115 |
116 | })
117 |
--------------------------------------------------------------------------------