├── .babelrc
├── .editorconfig
├── .gitignore
├── .gitmodules
├── .npmignore
├── LICENSE
├── README.md
├── build
├── build.js
├── dev-client.js
├── dev-server.js
├── utils.js
├── vue-loader.conf.js
├── webpack.base.conf.js
├── webpack.demo.conf.js
├── webpack.dev.conf.js
└── webpack.prod.conf.js
├── config
├── dev.env.js
├── index.js
└── prod.env.js
├── index.html
├── package.json
├── src
├── App.vue
├── editor
│ ├── Button.vue
│ ├── Editr.vue
│ ├── bus.js
│ ├── examples
│ │ ├── customLocale.js
│ │ ├── customModule.vue
│ │ └── customModule_simple.js
│ ├── index.js
│ ├── locales
│ │ ├── dutch.js
│ │ ├── english.js
│ │ ├── german.js
│ │ ├── hungarian.js
│ │ ├── index.js
│ │ ├── italian.js
│ │ ├── portuguese.js
│ │ └── spanish.js
│ └── modules
│ │ ├── alignCenter.js
│ │ ├── alignLeft.js
│ │ ├── alignRight.js
│ │ ├── bold.js
│ │ ├── code.js
│ │ ├── headings.vue
│ │ ├── hyperlink.vue
│ │ ├── image.vue
│ │ ├── italic.js
│ │ ├── list_ordered.js
│ │ ├── list_unordered.js
│ │ ├── removeFormat.js
│ │ ├── separator.js
│ │ ├── table.vue
│ │ └── underline.js
└── main.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["es2015", { "modules": false }],
4 | "stage-2"
5 | ],
6 | "plugins": ["transform-runtime"],
7 | "comments": false,
8 | "env": {
9 | "test": {
10 | "plugins": [ "istanbul" ]
11 | },
12 | "production": {
13 | "presets": ["babili"]
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | demo/
4 | npm-debug.log
5 | src/App.vue
6 | dist
7 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "demo"]
2 | path = demo
3 | url = git://github.com/chmln/vue-wysiwyg.git
4 | branch = gh-pages
5 |
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | *
2 | !dist/vueWysiwyg.js
3 | !dist/vueWysiwyg.css
4 | !src
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://chmln.github.io/vue-wysiwyg/)
2 |
3 |
4 | ## Usage
5 |
6 |
7 | ### Install vue-wysiwyg
8 |
9 | ``` bash
10 | npm install vue-wysiwyg --save
11 | ```
12 | OR
13 |
14 | ``` bash
15 | yarn add vue-wysiwyg
16 | ```
17 |
18 | In your `main.js`:
19 |
20 | ```js
21 | import wysiwyg from "vue-wysiwyg";
22 | Vue.use(wysiwyg, {}); // config is optional. more below
23 | ```
24 |
25 | Also make sure to load the stylesheet.
26 | The exact syntax will depend on what preprocessor you use.
27 |
28 | ```css
29 | @import "~vue-wysiwyg/dist/vueWysiwyg.css";
30 | ```
31 |
32 | In your components:
33 | ```html
34 |
35 | ```
36 |
37 | ## Config options
38 |
39 | All keys are optional.
40 |
41 | ```js
42 | {
43 | // { [module]: boolean (set true to hide) }
44 | hideModules: { "bold": true },
45 |
46 | // you can override icons too, if desired
47 | // just keep in mind that you may need custom styles in your application to get everything to align
48 | iconOverrides: { "bold": "" },
49 |
50 | // if the image option is not set, images are inserted as base64
51 | image: {
52 | uploadURL: "/api/myEndpoint",
53 | dropzoneOptions: {}
54 | },
55 |
56 | // limit content height if you wish. If not set, editor size will grow with content.
57 | maxHeight: "500px",
58 |
59 | // set to 'true' this will insert plain text without styling when you paste something into the editor.
60 | forcePlainTextOnPaste: true,
61 |
62 | // specify editor locale, if you don't specify this, the editor will default to english.
63 | locale: 'hu'
64 | }
65 | ```
66 | Available Modules:
67 | - bold
68 | - italic
69 | - underline
70 | - justifyLeft
71 | - justifyCenter
72 | - justifyRight
73 | - headings
74 | - link
75 | - code
76 | - orderedList
77 | - unorderedList
78 | - image
79 | - table
80 | - removeFormat
81 | - separator
82 |
83 | Available Locales:
84 | - english (default)
85 | - hungarian
86 | - dutch
87 | - german
88 |
89 | Note on the image upload API endpoint:
90 | - Image is uploaded by `multipart/form-data`
91 | - Your endpoint must respond back with a string, the URL for the image - e.g. `http://myapp.com/images/12345.jpg`
92 |
--------------------------------------------------------------------------------
/build/build.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'production'
2 |
3 | var ora = require('ora')
4 | var path = require('path')
5 | var chalk = require('chalk')
6 | var shell = require('shelljs')
7 | var webpack = require('webpack')
8 | var config = require('../config')
9 | var webpackConfig = require(`./webpack.${process.env.BUILD}.conf`)
10 |
11 | var spinner = ora('building for production...')
12 | spinner.start()
13 |
14 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
15 | shell.rm('-rf', assetsPath)
16 | shell.mkdir('-p', assetsPath)
17 | shell.config.silent = true
18 | shell.cp('-R', 'static/*', assetsPath)
19 | shell.config.silent = false
20 |
21 | webpack(webpackConfig, function (err, stats) {
22 | spinner.stop()
23 | if (err) throw err
24 | process.stdout.write(stats.toString({
25 | colors: true,
26 | modules: false,
27 | children: false,
28 | chunks: false,
29 | chunkModules: false
30 | }) + '\n\n')
31 |
32 | console.log(chalk.cyan(' Build complete.\n'))
33 | console.log(chalk.yellow(
34 | ' Tip: built files are meant to be served over an HTTP server.\n' +
35 | ' Opening index.html over file:// won\'t work.\n'
36 | ))
37 | })
38 |
--------------------------------------------------------------------------------
/build/dev-client.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | require('eventsource-polyfill')
3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
4 |
5 | hotClient.subscribe(function (event) {
6 | if (event.action === 'reload') {
7 | window.location.reload()
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/build/dev-server.js:
--------------------------------------------------------------------------------
1 | var config = require('../config')
2 | if (!process.env.NODE_ENV) {
3 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
4 | }
5 |
6 | var opn = require('opn')
7 | var path = require('path')
8 | var express = require('express')
9 | var webpack = require('webpack')
10 | var proxyMiddleware = require('http-proxy-middleware')
11 | var webpackConfig = require('./webpack.dev.conf')
12 |
13 | // default port where dev server listens for incoming traffic
14 | var port = process.env.PORT || config.dev.port
15 | // automatically open browser, if not set will be false
16 | var autoOpenBrowser = !!config.dev.autoOpenBrowser
17 | // Define HTTP proxies to your custom API backend
18 | // https://github.com/chimurai/http-proxy-middleware
19 | var proxyTable = config.dev.proxyTable
20 |
21 | var app = express()
22 | var compiler = webpack(webpackConfig)
23 |
24 | var devMiddleware = require('webpack-dev-middleware')(compiler, {
25 | publicPath: webpackConfig.output.publicPath,
26 | quiet: true
27 | })
28 |
29 | var hotMiddleware = require('webpack-hot-middleware')(compiler, {
30 | log: () => {}
31 | })
32 | // force page reload when html-webpack-plugin template changes
33 | compiler.plugin('compilation', function (compilation) {
34 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
35 | hotMiddleware.publish({ action: 'reload' })
36 | cb()
37 | })
38 | })
39 |
40 | // proxy api requests
41 | Object.keys(proxyTable).forEach(function (context) {
42 | var options = proxyTable[context]
43 | if (typeof options === 'string') {
44 | options = { target: options }
45 | }
46 | app.use(proxyMiddleware(options.filter || context, options))
47 | })
48 |
49 | // handle fallback for HTML5 history API
50 | app.use(require('connect-history-api-fallback')())
51 |
52 | // serve webpack bundle output
53 | app.use(devMiddleware)
54 |
55 | // enable hot-reload and state-preserving
56 | // compilation error display
57 | app.use(hotMiddleware)
58 |
59 | // serve pure static assets
60 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
61 | app.use(staticPath, express.static('./static'))
62 |
63 | var uri = 'http://localhost:' + port
64 |
65 | devMiddleware.waitUntilValid(function () {
66 | console.log('> Listening at ' + uri + '\n')
67 | })
68 |
69 | module.exports = app.listen(port, function (err) {
70 | if (err) {
71 | console.log(err)
72 | return
73 | }
74 |
75 | // when env is testing, don't need open it
76 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
77 | opn(uri)
78 | }
79 | })
80 |
--------------------------------------------------------------------------------
/build/utils.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
4 |
5 | exports.assetsPath = function (_path) {
6 | var assetsSubDirectory = process.env.NODE_ENV === 'production'
7 | ? config.build.assetsSubDirectory
8 | : config.dev.assetsSubDirectory
9 | return path.posix.join(assetsSubDirectory, _path)
10 | }
11 |
12 | exports.cssLoaders = function (options) {
13 | options = options || {}
14 | // generate loader string to be used with extract text plugin
15 | function generateLoaders (loaders) {
16 | var sourceLoader = loaders.map(function (loader) {
17 | var extraParamChar
18 | if (/\?/.test(loader)) {
19 | loader = loader.replace(/\?/, '-loader?')
20 | extraParamChar = '&'
21 | } else {
22 | loader = loader + '-loader'
23 | extraParamChar = '?'
24 | }
25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
26 | }).join('!')
27 |
28 | // Extract CSS when that option is specified
29 | // (which is the case during production build)
30 | if (options.extract) {
31 | return ExtractTextPlugin.extract({
32 | use: sourceLoader,
33 | fallback: 'vue-style-loader'
34 | })
35 | } else {
36 | return ['vue-style-loader', sourceLoader].join('!')
37 | }
38 | }
39 |
40 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
41 | return {
42 | css: generateLoaders(['css']),
43 | postcss: generateLoaders(['css']),
44 | less: generateLoaders(['css', 'less']),
45 | sass: generateLoaders(['css', 'sass?indentedSyntax']),
46 | scss: generateLoaders(['css', 'sass']),
47 | stylus: generateLoaders(['css', 'stylus']),
48 | styl: generateLoaders(['css', 'stylus'])
49 | }
50 | }
51 |
52 | // Generate loaders for standalone style files (outside of .vue)
53 | exports.styleLoaders = function (options) {
54 | var output = []
55 | var loaders = exports.cssLoaders(options)
56 | for (var extension in loaders) {
57 | var loader = loaders[extension]
58 | output.push({
59 | test: new RegExp('\\.' + extension + '$'),
60 | loader: loader
61 | })
62 | }
63 | return output
64 | }
65 |
--------------------------------------------------------------------------------
/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils')
2 | var config = require('../config')
3 | var isProduction = process.env.NODE_ENV === 'production'
4 |
5 | module.exports = {
6 | loaders: utils.cssLoaders({
7 | sourceMap: isProduction
8 | ? config.build.productionSourceMap
9 | : config.dev.cssSourceMap,
10 | extract: isProduction
11 | }),
12 | postcss: [
13 | require('autoprefixer')({
14 | browsers: ['last 2 versions']
15 | })
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var utils = require('./utils')
3 | var config = require('../config')
4 | var vueLoaderConfig = require('./vue-loader.conf')
5 |
6 | function resolve (dir) {
7 | return path.join(__dirname, '..', dir)
8 | }
9 |
10 | console.log(config.build.assetsRoot)
11 |
12 | module.exports = {
13 | entry: {
14 | app: './src/main.js'
15 | },
16 | output: {
17 | path: config.build.assetsRoot,
18 | filename: '[name].js',
19 | publicPath: process.env.NODE_ENV === 'production'
20 | ? config.build.assetsPublicPath
21 | : config.dev.assetsPublicPath
22 | },
23 | resolve: {
24 | extensions: ['.js', '.vue', '.json'],
25 | modules: [
26 | resolve('src'),
27 | resolve('node_modules')
28 | ],
29 | alias: {
30 | 'vue$': 'vue/dist/vue.common.js',
31 | 'src': resolve('src'),
32 | 'assets': resolve('src/assets'),
33 | 'components': resolve('src/components')
34 | }
35 | },
36 | module: {
37 | rules: [
38 | {
39 | test: /\.vue$/,
40 | loader: 'vue-loader',
41 | options: vueLoaderConfig
42 | },
43 | {
44 | test: /\.js$/,
45 | loader: 'babel-loader',
46 | include: [resolve('src'), resolve('test')]
47 | },
48 | {
49 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
50 | loader: 'url-loader',
51 | query: {
52 | limit: 10000,
53 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
54 | }
55 | },
56 | {
57 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
58 | loader: 'url-loader',
59 | query: {
60 | limit: 10000,
61 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
62 | }
63 | }
64 | ]
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/build/webpack.demo.conf.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils')
2 | var webpack = require('webpack')
3 | var config = require('../config')
4 | var merge = require('webpack-merge')
5 | var baseWebpackConfig = require('./webpack.base.conf')
6 | var HtmlWebpackPlugin = require('html-webpack-plugin')
7 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
8 |
9 |
10 |
11 | module.exports = merge(baseWebpackConfig, {
12 | module: {
13 | rules: utils.styleLoaders({ sourceMap: false })
14 | },
15 | // cheap-module-eval-source-map is faster for development
16 | devtool: false,
17 | plugins: [
18 | new webpack.DefinePlugin({
19 | 'process.env': {
20 | NODE_ENV: '"production"'
21 | }
22 | }),
23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
24 | new webpack.HotModuleReplacementPlugin(),
25 | new webpack.NoEmitOnErrorsPlugin(),
26 | // https://github.com/ampedandwired/html-webpack-plugin
27 | new HtmlWebpackPlugin({
28 | filename: 'index.html',
29 | template: 'index.html',
30 | inject: true
31 | }),
32 | new ExtractTextPlugin({
33 | filename: 'style.css'
34 | }),
35 | new webpack.optimize.UglifyJsPlugin()
36 | ]
37 | })
38 |
--------------------------------------------------------------------------------
/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils')
2 | var webpack = require('webpack')
3 | var config = require('../config')
4 | var merge = require('webpack-merge')
5 | var baseWebpackConfig = require('./webpack.base.conf')
6 | var HtmlWebpackPlugin = require('html-webpack-plugin')
7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
8 |
9 | // add hot-reload related code to entry chunks
10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) {
11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
12 | })
13 |
14 | module.exports = merge(baseWebpackConfig, {
15 | module: {
16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
17 | },
18 | // cheap-module-eval-source-map is faster for development
19 | devtool: 'source-map',
20 | plugins: [
21 | new webpack.DefinePlugin({
22 | 'process.env': config.dev.env
23 | }),
24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
25 | new webpack.HotModuleReplacementPlugin(),
26 | new webpack.NoEmitOnErrorsPlugin(),
27 | // https://github.com/ampedandwired/html-webpack-plugin
28 | new HtmlWebpackPlugin({
29 | filename: 'index.html',
30 | template: 'index.html',
31 | inject: true
32 | }),
33 | new FriendlyErrorsPlugin()
34 | ]
35 | })
36 |
--------------------------------------------------------------------------------
/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var utils = require('./utils')
3 | var webpack = require('webpack')
4 | var config = require('../config')
5 | var merge = require('webpack-merge')
6 | var baseWebpackConfig = require('./webpack.base.conf')
7 | var HtmlWebpackPlugin = require('html-webpack-plugin')
8 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
9 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
10 | var env = config.build.env
11 |
12 | var webpackConfig = merge(baseWebpackConfig, {
13 | module: {
14 | rules: utils.styleLoaders({
15 | sourceMap: config.build.productionSourceMap,
16 | extract: true
17 | })
18 | },
19 | entry: [path.resolve('src/editor/index.js')],
20 | devtool: false,
21 | output: {
22 | path: config.build.assetsRoot,
23 | library: "vueWysiwyg",
24 | libraryTarget: "umd",
25 | filename: "vueWysiwyg.js",
26 | umdNamedDefine: true
27 | // filename: utils.assetsPath('js/[name].[chunkhash].js'),
28 | // chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
29 | },
30 | plugins: [
31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
32 | new webpack.DefinePlugin({
33 | 'process.env': env
34 | }),
35 | new UglifyJsPlugin({
36 | parallel: true,
37 | uglifyOptions: {
38 | compress: {
39 | warnings: false
40 | },
41 | output: {
42 | comments: false
43 | },
44 | sourceMap: false
45 | }
46 | }),
47 | // extract css into its own file
48 | new ExtractTextPlugin({
49 | filename: 'vueWysiwyg.css'
50 | })
51 | ]
52 | })
53 |
54 |
55 | if (config.build.bundleAnalyzerReport) {
56 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
57 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
58 | }
59 |
60 | module.exports = webpackConfig
61 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../' + (process.env.DIR || "dist")),
9 | assetsSubDirectory: './',
10 | assetsPublicPath: '/vue-wysiwyg/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css'],
18 | // Run the build command with an extra argument to
19 | // View the bundle analyzer report after build finishes:
20 | // `npm run build --report`
21 | // Set to `true` or `false` to always turn it on or off
22 | bundleAnalyzerReport: process.env.npm_config_report
23 | },
24 | dev: {
25 | env: require('./dev.env'),
26 | port: 8080,
27 | autoOpenBrowser: true,
28 | assetsSubDirectory: 'static',
29 | assetsPublicPath: '/',
30 | proxyTable: {},
31 | // CSS Sourcemaps off by default because relative paths are "buggy"
32 | // with this option, according to the CSS-Loader README
33 | // (https://github.com/webpack/css-loader#sourcemaps)
34 | // In our experience, they generally work as expected,
35 | // just be aware of this issue when enabling this option.
36 | cssSourceMap: false
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | html-editor
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-wysiwyg",
3 | "version": "1.7.2",
4 | "description": "A WYSIWYG HTML editor for Vue.js",
5 | "keywords": [
6 | "vue",
7 | "vue2",
8 | "wysiwyg",
9 | "html",
10 | "editor",
11 | "localization"
12 | ],
13 | "author": "Gregory ",
14 | "license": "MIT",
15 | "main": "dist/vueWysiwyg.js",
16 | "style": "dist/vueWysiwyg.css",
17 | "scripts": {
18 | "dev": "node build/dev-server.js",
19 | "build": "npm run build:prod",
20 | "build:demo": "BABEL_ENV=production BUILD=demo DIR=demo node build/build.js",
21 | "build:prod": "rm -rf dist/* && BABEL_ENV=production BUILD=prod node build/build.js"
22 | },
23 | "dependencies": {
24 | "debounce": "^1.1.0",
25 | "vue": "^2.5.13",
26 | "vue2-dropzone": "^3.0.4"
27 | },
28 | "devDependencies": {
29 | "autoprefixer": "^8.0.0",
30 | "babel-core": "^6.26.0",
31 | "babel-loader": "^7.1.2",
32 | "babel-plugin-transform-runtime": "^6.23.0",
33 | "babel-preset-babili": "^0.1.4",
34 | "babel-preset-es2015": "^6.24.1",
35 | "babel-preset-stage-2": "^6.24.1",
36 | "babel-register": "^6.26.0",
37 | "chalk": "^2.3.1",
38 | "connect-history-api-fallback": "^1.5.0",
39 | "css-loader": "^0.28.9",
40 | "eventsource-polyfill": "^0.9.6",
41 | "express": "^4.16.2",
42 | "extract-text-webpack-plugin": "^3.0.2",
43 | "file-loader": "^1.1.6",
44 | "friendly-errors-webpack-plugin": "^1.6.1",
45 | "function-bind": "^1.1.1",
46 | "html-webpack-plugin": "^2.30.1",
47 | "http-proxy-middleware": "^0.17.4",
48 | "opn": "^5.2.0",
49 | "ora": "^1.4.0",
50 | "pug": "^2.0.0-rc.4",
51 | "semver": "^5.5.0",
52 | "shelljs": "^0.8.1",
53 | "stylus": "^0.54.5",
54 | "stylus-loader": "^3.0.1",
55 | "uglifyjs-webpack-plugin": "^1.2.0",
56 | "url-loader": "^0.6.2",
57 | "vue-loader": "^14.1.1",
58 | "vue-style-loader": "^4.0.2",
59 | "vue-template-compiler": "^2.5.13",
60 | "webpack": "^3.11.0",
61 | "webpack-bundle-analyzer": "^2.10.0",
62 | "webpack-dev-middleware": "^2.0.5",
63 | "webpack-hot-middleware": "^2.21.0",
64 | "webpack-merge": "^4.1.1"
65 | },
66 | "engines": {
67 | "node": ">= 4.0.0",
68 | "npm": ">= 3.0.0"
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 | .wrapper
3 | wysiwyg(v-model="msg")
4 |
5 |
6 |
53 |
54 |
85 |
--------------------------------------------------------------------------------
/src/editor/Button.vue:
--------------------------------------------------------------------------------
1 |
2 | div(@mousedown="onBtnClick")
3 | a(:class="'vw-btn-'+module.title", v-html="module.icon")
4 |
5 | .dashboard(
6 | v-show="showDashboard",
7 | ref="dashboard"
8 | )
9 | component(
10 | v-if="module.render",
11 | v-once,
12 | ref="moduleDashboard",
13 | :is="module",
14 | @exec="exec",
15 | :uid="uid"
16 | :options="options"
17 | )
18 |
19 |
20 |
72 |
--------------------------------------------------------------------------------
/src/editor/Editr.vue:
--------------------------------------------------------------------------------
1 |
2 | .editr
3 | .editr--toolbar
4 | Btn(
5 | v-for="(module,i) in modules",
6 | :module="module",
7 | :options="mergedOptions",
8 | :key="module.title + i",
9 |
10 | :ref="'btn-'+module.title",
11 | :title="mergedOptions.locale[module.title] || module.description || ''"
12 | )
13 |
14 | .editr--content(ref="content", contenteditable="!disabled", tabindex="1", :placeholder="placeholder")
15 |
16 |
17 |
18 |
240 |
241 |
352 |
--------------------------------------------------------------------------------
/src/editor/bus.js:
--------------------------------------------------------------------------------
1 | import english from './locales/english';
2 |
3 | function Emitter() {
4 | const self = {
5 | listeners: {},
6 | on: (eventName, handler) => {
7 | if (self.listeners[eventName] === undefined)
8 | self.listeners[eventName] = [];
9 | self.listeners[eventName].push(handler);
10 | },
11 | emit: (eventName, ...args) => {
12 | if (self.listeners[eventName] !== undefined)
13 | self.listeners[eventName].forEach(handler => handler.apply(args));
14 | }
15 | }
16 |
17 | return self;
18 | }
19 |
20 | const emitter = new Emitter();
21 |
22 | emitter.options = {
23 | image: {
24 | uploadURL: "None",
25 | dropzoneOptions: {}
26 | },
27 | hideModules: {},
28 | paragraphSeparator: "div",
29 | maxHeight: undefined,
30 | customModules: [],
31 | locale: english
32 | }
33 |
34 | emitter.utils = {
35 | getHTMLOfSelection () {
36 | if (window.getSelection !== undefined) {
37 | const selection = window.getSelection();
38 | if (selection.rangeCount > 0) {
39 | const clonedSelection = selection.getRangeAt(0).cloneContents();
40 | const div = document.createElement('div');
41 | div.appendChild(clonedSelection);
42 | return div.innerHTML;
43 | }
44 | }
45 |
46 | return '';
47 | }
48 | }
49 |
50 | export default emitter;
51 |
--------------------------------------------------------------------------------
/src/editor/examples/customLocale.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: 'English',
3 | locale_shorthand: ['en', 'english'],
4 | // Translations:
5 | justifyCenter: 'Center',
6 | justifyLeft: 'Justify Left',
7 | justifyRight: 'Justify Right',
8 | bold: 'Bold',
9 | code: 'Code',
10 | headings: 'Headings (h1-h6)',
11 | link: 'Hyperlink',
12 | image: 'Insert Image',
13 | italic: 'Italic',
14 | orderedList: 'Ordered List (1, 2, 3, ...)',
15 | unorderedList: 'Bullet List',
16 | removeFormat: 'Remove formatting.\nClears headings, bold, italic, underlined text, etc.',
17 | separator: null,
18 | table: 'Insert Table',
19 | underline: 'Underline'
20 | }
--------------------------------------------------------------------------------
/src/editor/examples/customModule.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
30 |
--------------------------------------------------------------------------------
/src/editor/examples/customModule_simple.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "blockquoteBoldItalic",
3 | customAction (utils) {
4 | const sel = utils.getHTMLOfSelection();
5 |
6 | // wrap selection in custom html tags
7 | return [
8 | ["insertHTML", `${sel}
`, true],
9 | ]
10 | },
11 | icon: ''
12 | }
13 |
--------------------------------------------------------------------------------
/src/editor/index.js:
--------------------------------------------------------------------------------
1 | import Editr from "./Editr.vue";
2 | import bus from 'src/editor/bus.js';
3 | import locales from "./locales";
4 |
5 | const localeArray = Object.values(locales);
6 |
7 | export default {
8 | install: (Vue, userOptions = {}) => {
9 | if(userOptions.locale)
10 | {
11 | if(typeof userOptions.locale == 'string')
12 | {
13 | let userLocale = localeArray.find(
14 | x => x.locale_shorthand.includes(
15 | userOptions.locale.toLowerCase()
16 | )
17 | );
18 | userOptions.locale = userLocale;
19 | }
20 | }
21 | bus.options = { ...bus.options, ...userOptions };
22 | Vue.component("wysiwyg", Editr);
23 | },
24 |
25 | component: Editr
26 | }
27 |
--------------------------------------------------------------------------------
/src/editor/locales/dutch.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: 'Dutch',
3 | locale_shorthand: ['nl', 'dutch'],
4 | // Translations:
5 | justifyCenter: 'Gecentreerd uitlijnen',
6 | justifyLeft: 'Links uitlijnen',
7 | justifyRight: 'Rechts uitlijnen',
8 | bold: 'Vet',
9 | code: 'Code',
10 | headings: 'Titels (h1-h6)',
11 | link: 'Hyperlink',
12 | image: 'Afbeelding invoegen',
13 | italic: 'Cursief',
14 | orderedList: 'Nummering (1, 2, 3, ...)',
15 | unorderedList: 'Opsomming',
16 | removeFormat: 'Opmaak verwijderen.\nMaakt titels, vetgedrukt, cursief, onderstreept etc. ongedaan.',
17 | separator: null,
18 | table: 'Tabel invoegen',
19 | underline: 'Onderstrepen'
20 | }
--------------------------------------------------------------------------------
/src/editor/locales/english.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: 'English',
3 | locale_shorthand: ['en', 'english'],
4 | // Translations:
5 | justifyCenter: 'Center',
6 | justifyLeft: 'Justify Left',
7 | justifyRight: 'Justify Right',
8 | bold: 'Bold',
9 | code: 'Code',
10 | headings: 'Headings (h1-h6)',
11 | link: 'Hyperlink',
12 | image: 'Insert Image',
13 | italic: 'Italic',
14 | orderedList: 'Ordered List (1, 2, 3, ...)',
15 | unorderedList: 'Bullet List',
16 | removeFormat: 'Remove formatting.\nClears headings, bold, italic, underlined text, etc.',
17 | separator: null,
18 | table: 'Insert Table',
19 | underline: 'Underline'
20 | }
--------------------------------------------------------------------------------
/src/editor/locales/german.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: 'Deutsch',
3 | locale_shorthand: ['de', 'deutsch'],
4 | // Translations:
5 | justifyCenter: 'Zentriert',
6 | justifyLeft: 'Linksbündig',
7 | justifyRight: 'Rechtsbündig',
8 | bold: 'Fett',
9 | code: 'Programmcode',
10 | headings: 'Überschriften (h1-h6)',
11 | link: 'Link',
12 | image: 'Bild einfügen',
13 | italic: 'Kursiv',
14 | orderedList: 'Nummerierung (1, 2, 3, ...)',
15 | unorderedList: 'Aufzählung',
16 | removeFormat: 'Formatierung entfernen.\nEntfernt Überschriften, fett, kursiv, unterstrichen, usw.',
17 | separator: 'Querstrich',
18 | table: 'Tabelle einfügen',
19 | underline: 'Unterstrichen'
20 | }
21 |
--------------------------------------------------------------------------------
/src/editor/locales/hungarian.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: 'Magyar',
3 | locale_shorthand: ['hu', 'magyar'],
4 | // Translations:
5 | justifyCenter: 'Középre Igazított',
6 | justifyLeft: 'Balra Igazított',
7 | justifyRight: 'Jobbra Igazított',
8 | bold: 'Félkövér',
9 | code: 'Kód',
10 | headings: 'Bekezdéscímek (h1-h6)',
11 | link: 'Hivatkozás',
12 | image: 'Kép beszúrása',
13 | italic: 'Dőlt',
14 | orderedList: 'Rendezett Lista (1, 2, 3, ...)',
15 | unorderedList: 'Felsorolás',
16 | removeFormat: 'Formázás törlése.\nEltávolítja a bekezdéscímeket, félkövér, dőlt, stb. formázásokat.',
17 | separator: null,
18 | table: 'Táblázat beszúrása',
19 | underline: 'Aláhúzott'
20 | }
--------------------------------------------------------------------------------
/src/editor/locales/index.js:
--------------------------------------------------------------------------------
1 | import dutch from "./dutch";
2 | import hungarian from "./hungarian";
3 | import english from "./english";
4 | import portuguese from "./portuguese";
5 | import italian from "./italian";
6 | import spanish from "./spanish";
7 |
8 | export default {
9 | dutch,
10 | hungarian,
11 | german,
12 | english,
13 | portuguese,
14 | spanish,
15 | }
16 |
--------------------------------------------------------------------------------
/src/editor/locales/italian.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: 'Italiano',
3 | locale_shorthand: ['it', 'italiano'],
4 | // Translations:
5 | justifyCenter: 'Centrato',
6 | justifyLeft: 'Allinea a Sinistra',
7 | justifyRight: 'Allinea a Destra',
8 | bold: 'Grassetto',
9 | code: 'Codice',
10 | headings: 'Intestazioni (h1-h6)',
11 | link: 'Collegamento',
12 | image: 'Inserisci Immagine',
13 | italic: 'Corsivo',
14 | orderedList: 'Elenco Ordinato (1, 2, 3, ...)',
15 | unorderedList: 'Elenco',
16 | removeFormat: 'Rimuovi formattazione.\nPulisci il test da intestazione, grassetto, corsivo, sottolineato, ecc.',
17 | separator: null,
18 | table: 'Inserisci Tabella',
19 | underline: 'Sottolineato'
20 | }
21 |
--------------------------------------------------------------------------------
/src/editor/locales/portuguese.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: "Português",
3 | locale_shorthand: ["pt", "portuguese"],
4 | // Traduções:
5 | justifyCenter: "Centralizar",
6 | justifyLeft: "Justificar à Esquerda",
7 | justifyRight: "Justificar à Direita",
8 | bold: "Negrito",
9 | code: "Código",
10 | headings: "Cabeçalhos (h1-h6)",
11 | link: "Hiperlink",
12 | image: "Inserir Imagem",
13 | italic: "Itálico",
14 | orderedList: "Lista Ordenada (1, 2, 3, ...)",
15 | unorderedList: "Lista Desordenada",
16 | removeFormat:
17 | "Remove formatação.\nLimpa cabeçalhos, negrito, itálico, texto sublinhado, etc.",
18 | separator: null,
19 | table: "Inserir Tabela",
20 | underline: "Sublinhado",
21 | };
22 |
--------------------------------------------------------------------------------
/src/editor/locales/spanish.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | locale_name: 'Español',
3 | locale_shorthand: ['es', 'español'],
4 | // Translations:
5 | justifyCenter: 'Centrar',
6 | justifyLeft: 'Justificar a la izquierda',
7 | justifyRight: 'Justificar a la derecha',
8 | bold: 'Negrita',
9 | code: 'Código',
10 | headings: 'Encabezados (h1-h6)',
11 | link: 'Hipervínculo',
12 | image: 'Insertar imagen',
13 | italic: 'Cursiva',
14 | orderedList: 'Lista ordenada',
15 | unorderedList: 'Lista desordenada',
16 | removeFormat: 'Eliminar formato.\nBorra encabezados, negritas, cursiva, subrayado, etc.',
17 | separator: null,
18 | table: 'Insertar tabla',
19 | underline: 'Subrayado'
20 | }
21 |
--------------------------------------------------------------------------------
/src/editor/modules/alignCenter.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "justifyCenter",
3 | action: ["justifyCenter"],
4 | description: "Center",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/alignLeft.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "justifyLeft",
3 | action: ["justifyLeft"],
4 | description: "Justify Left",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/alignRight.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "justifyRight",
3 | action: ["justifyRight"],
4 | description: "Justify Right",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/bold.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "bold",
3 | action: ["bold"],
4 | description: "Bold",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/code.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "code",
3 | icon: '',
4 | description: "Code",
5 | action: ["formatBlock", "pre"]
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/src/editor/modules/headings.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
27 |
28 |
--------------------------------------------------------------------------------
/src/editor/modules/hyperlink.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
17 |
53 |
54 |
--------------------------------------------------------------------------------
/src/editor/modules/image.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
71 |
72 |
--------------------------------------------------------------------------------
/src/editor/modules/italic.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "italic",
3 | description: "Italic",
4 | action: ["italic"],
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/list_ordered.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "orderedList",
3 | action: ["insertOrderedList"],
4 | description: "Ordered List (1, 2, 3)",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/list_unordered.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "unorderedList",
3 | action: ["insertUnorderedList"],
4 | description: "Bullet List",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/removeFormat.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "removeFormat",
3 | action: ["removeFormat"],
4 | description: "Remove formatting.\nClears headings, bold, italic, underlined text, etc.",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/editor/modules/separator.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "separator",
3 | icon: ""
4 | }
5 |
--------------------------------------------------------------------------------
/src/editor/modules/table.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
44 |
53 |
--------------------------------------------------------------------------------
/src/editor/modules/underline.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: "underline",
3 | action: ["underline"],
4 | description: "Underline",
5 | icon: ''
6 | }
7 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import App from './App.vue';
3 |
4 | import wysiwyg from "./editor";
5 | Vue.use(wysiwyg, {
6 | hideModules: {
7 | bold: false,
8 | },
9 | locale: 'hu'
10 | });
11 |
12 | new Vue({
13 | el: '#app',
14 | render: h => h(App)
15 | })
16 |
--------------------------------------------------------------------------------