├── .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://user-images.githubusercontent.com/11352152/30252159-1bbb9cfe-963b-11e7-966c-b44116c74a86.png)](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 | 5 | 6 | 53 | 54 | 85 | -------------------------------------------------------------------------------- /src/editor/Button.vue: -------------------------------------------------------------------------------- 1 | 20 | 72 | -------------------------------------------------------------------------------- /src/editor/Editr.vue: -------------------------------------------------------------------------------- 1 | 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 | 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 | 11 | 12 | 27 | 28 | -------------------------------------------------------------------------------- /src/editor/modules/hyperlink.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 53 | 54 | -------------------------------------------------------------------------------- /src/editor/modules/image.vue: -------------------------------------------------------------------------------- 1 | 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 | 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 | --------------------------------------------------------------------------------