diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index d721e6f73..464afbb7e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,3 @@ -# These are supported funding model platforms - -github: [Alex-D] +github: Alex-D patreon: AlexandreDemode +custom: https://paypal.me/demodealexandre diff --git a/BACKERS.md b/BACKERS.md index b47b90486..a8e797b06 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -2,10 +2,10 @@ Trumbowyg is an MIT-licensed open source project and completely free to use. -However, the amount of effort needed to maintain and develop new features for -the project is not sustainable without proper financial backing. +However, the amount of effort needed to maintain and develop new features for +the project is not sustainable without proper financial backing. You can support it's ongoing development by being a backer or a sponsor: - + - [Become a backer or sponsor on Patreon](https://www.patreon.com/alexandredemode) - [One-time donation via PayPal](https://www.paypal.me/demodealexandre/20eur) @@ -17,12 +17,6 @@ You can support it's ongoing development by being a backer or a sponsor:

-

- - BookingNinja - -

-

Become a Sponsor diff --git a/README.md b/README.md index 9587493f3..01068e98e 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,10 @@ Trumbowyg is an MIT-licensed open source project and completely free to use. -However, the amount of effort needed to maintain and develop new features for -the project is not sustainable without proper financial backing. +However, the amount of effort needed to maintain and develop new features for +the project is not sustainable without proper financial backing. You can support it's ongoing development by being a backer or a sponsor: - + - [Become a backer or sponsor on Patreon](https://www.patreon.com/alexandredemode) - [One-time donation via PayPal](https://www.paypal.me/demodealexandre/20eur) @@ -32,10 +32,6 @@ You can support it's ongoing development by being a backer or a sponsor: avot® -       - - BookingNinja -

@@ -80,11 +76,10 @@ Thanks to `node` and `gulp`, you can improve core script, style or icons easily. First, fork and clone the repository ```bash -cd Trumbowyg # to go into the project's root directory -npm install # to install development dependencies -npm install -g bower gulp # to install bower and gulp command if you don't have them already -bower install # to install Trumbowyg dependencies (ie: jQuery) -gulp build # to build the project +cd Trumbowyg # go into the project's root directory +npm install # install development dependencies +npm run dev # watch mode +npm run build # to build the project ``` `gulp` command launch default Gulp task watcher and rebuild on the fly. diff --git a/bower.json b/bower.json index 48c70a24d..07c0ba123 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "trumbowyg", - "version": "2.21.0", + "version": "2.22.0", "homepage": "https://github.com/Alex-D/Trumbowyg", "authors": [ { diff --git a/docs/demos/plugins/resizimg.html b/docs/demos/plugins/resizimg.html index 46abac9d2..a6af61ef2 100644 --- a/docs/demos/plugins/resizimg.html +++ b/docs/demos/plugins/resizimg.html @@ -14,7 +14,7 @@

Resizimg plugin

Basic usage

- Images can be resized by click over the image and dragging their bottom-right corner (the red ones). + Images can be resized by click over the image and dragging their bottom-right corner (the white ones).

Read resizimg plugin documentation diff --git a/docs/index.html b/docs/index.html index 6b3d26a98..0a58b3991 100644 --- a/docs/index.html +++ b/docs/index.html @@ -808,9 +808,6 @@ avot® - - BookingNinja -

diff --git a/gulpfile.js b/gulpfile.js index e588c9b4c..599498c03 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -40,29 +40,29 @@ const bannerLight = [ ].join(''); -gulp.task('clean', function () { +const clean = function () { return gulp.src('dist/*') .pipe(vinylPaths(del)); -}); +}; -gulp.task('test', ['test-scripts', 'test-plugins-scripts', 'test-langs']); -gulp.task('test-scripts', function () { +const testScripts = function () { return gulp.src(paths.scripts) .pipe($.jshint()) .pipe($.jshint.reporter('jshint-stylish')); -}); -gulp.task('test-plugins-scripts', function () { +}; +const testPluginsScripts = function () { return gulp.src(paths.pluginsScripts) .pipe($.jshint()) .pipe($.jshint.reporter('jshint-stylish')); -}); -gulp.task('test-langs', function () { +}; +const testLangs = function () { return gulp.src(paths.langs) .pipe($.jshint()) .pipe($.jshint.reporter('jshint-stylish')); -}); +}; +const test = gulp.parallel(testScripts, testPluginsScripts, testLangs); -gulp.task('scripts', ['test-scripts'], function () { +const scripts = gulp.series(testScripts, function scripts() { return gulp.src(paths.scripts) .pipe($.header(banner, {pkg: pkg, description: 'Trumbowyg core file'})) .pipe($.newer('dist/trumbowyg.js')) @@ -76,7 +76,7 @@ gulp.task('scripts', ['test-scripts'], function () { .pipe($.size({title: 'trumbowyg.min.js'})); }); -gulp.task('plugins-scripts', ['test-scripts'], function () { +const pluginsScripts = gulp.series(testPluginsScripts, function pluginsScripts() { return gulp.src(paths.pluginsScripts) .pipe(gulp.dest('dist/plugins/')) .pipe($.rename({suffix: '.min'})) @@ -84,7 +84,7 @@ gulp.task('plugins-scripts', ['test-scripts'], function () { .pipe(gulp.dest('dist/plugins/')); }); -gulp.task('langs', ['test-langs'], function () { +const langs = gulp.series(testLangs, function langs() { return gulp.src(paths.langs) .pipe(gulp.dest('dist/langs/')) .pipe($.rename({suffix: '.min'})) @@ -95,16 +95,16 @@ gulp.task('langs', ['test-langs'], function () { }); -gulp.task('icons', function () { +const icons = function () { return gulp.src(paths.icons) .pipe($.rename({prefix: 'trumbowyg-'})) .pipe($.svgmin()) .pipe($.svgstore({inlineSvg: true})) .pipe(gulp.dest('dist/ui/')); -}); +}; -gulp.task('styles', function () { +const styles = function () { return gulp.src(paths.styles) .pipe($.sass()) .pipe($.autoprefixer(['last 1 version', '> 1%', 'ff >= 20', 'ie >= 9', 'opera >= 12', 'Android >= 2.2'], {cascade: true})) @@ -116,15 +116,15 @@ gulp.task('styles', function () { .pipe($.header(bannerLight, {pkg: pkg})) .pipe(gulp.dest('dist/ui/')) .pipe($.size({title: 'trumbowyg.min.css'})); -}); +}; -gulp.task('sass-dist', ['styles'], function () { +const sassDist = gulp.series(styles, function sassDist() { return gulp.src(paths.styles) .pipe($.header(banner, {pkg: pkg, description: 'Default stylesheet for Trumbowyg editor'})) .pipe(gulp.dest('dist/ui/sass')); }); -gulp.task('plugins-styles', function () { +const pluginsStyles = function () { return gulp.src(paths.pluginsStyles) .pipe($.sass()) .pipe($.autoprefixer(['last 1 version', '> 1%', 'ff >= 20', 'ie >= 9', 'opera >= 12', 'Android >= 2.2'], {cascade: true})) @@ -138,30 +138,36 @@ gulp.task('plugins-styles', function () { .pipe($.header(bannerLight, {pkg: pkg})) .pipe(gulp.dest('dist/plugins/')) .pipe($.size({title: 'Plugins styles'})); -}); +}; -gulp.task('plugins-sass-dist', ['plugins-styles'], function () { +const pluginsSassDist = gulp.series(pluginsStyles, function pluginsSassDist() { return gulp.src(paths.pluginsStyles) .pipe($.header(banner, {pkg: pkg, description: 'Default stylesheet for Trumbowyg editor plugin'})) .pipe(gulp.dest('dist/plugins')); }); -gulp.task('watch', function () { - gulp.watch(paths.icons, ['icons']); - gulp.watch(paths.scripts, ['scripts']); - gulp.watch(paths.langs, ['langs']); - gulp.watch(paths.pluginsScripts, ['plugins-scripts']); - gulp.watch(paths.pluginsStyles, ['plugins-styles']); - gulp.watch(paths.styles, ['styles']); +const watch = function () { + gulp.watch(paths.icons, icons); + gulp.watch(paths.scripts, scripts); + gulp.watch(paths.langs, langs); + gulp.watch(paths.pluginsScripts, pluginsScripts); + gulp.watch(paths.pluginsStyles, pluginsStyles); + gulp.watch(paths.styles, styles); gulp.watch(['dist/**', 'dist/*/**'], function (file) { $.livereload.changed(file); }); $.livereload.listen(); -}); +}; -gulp.task('build', ['scripts', 'plugins-scripts', 'langs', 'icons', 'sass-dist', 'plugins-sass-dist']); +const build = gulp.parallel(scripts, pluginsScripts, langs, icons, sassDist, pluginsSassDist); -gulp.task('default', ['build', 'watch']); +module.exports = { + default: gulp.series(build, watch), + clean, + build, + test, + watch, +} diff --git a/package.json b/package.json index 3822ecc7c..521d24282 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "trumbowyg", "title": "Trumbowyg", "description": "A lightweight WYSIWYG editor", - "version": "2.21.0", + "version": "2.22.0", "main": "dist/trumbowyg.js", "homepage": "http://alex-d.github.io/Trumbowyg", "author": { @@ -20,7 +20,7 @@ "license": "MIT", "devDependencies": { "del": "2.0.2", - "gulp": "3.9.1", + "gulp": "4.0.2", "gulp-autoprefixer": "2.2.0", "gulp-concat": "2.6.0", "gulp-header": "1.7.1", @@ -41,10 +41,10 @@ "vinyl-paths": "2.1.0" }, "peerDependencies": { - "jQuery": ">=1.8" + "jquery": ">=1.8" }, "scripts": { - "start": "gulp", + "dev": "gulp", "build": "gulp build", "clean": "gulp clean", "test": "gulp test" diff --git a/plugins/base64/trumbowyg.base64.js b/plugins/base64/trumbowyg.base64.js index 41f9f2e18..633e37870 100644 --- a/plugins/base64/trumbowyg.base64.js +++ b/plugins/base64/trumbowyg.base64.js @@ -26,6 +26,10 @@ errFileReaderNotSupported: 'FileReader is not supported by your browser.', errInvalidImage: 'Invalid image file.' }, + cs: { + base64: 'Vložit obrázek', + file: 'Soubor' + }, da: { base64: 'Billede som base64', file: 'Fil', @@ -36,13 +40,23 @@ base64: 'Image en base64', file: 'Fichier' }, - cs: { - base64: 'Vložit obrázek', - file: 'Soubor' + hu: { + base64: 'Kép beszúrás inline', + file: 'Fájl', + errFileReaderNotSupported: 'Ez a böngésző nem támogatja a FileReader funkciót.', + errInvalidImage: 'Érvénytelen képfájl.' }, - zh_cn: { - base64: '图片(Base64编码)', - file: '文件' + ja: { + base64: '画像 (Base64形式)', + file: 'ファイル', + errFileReaderNotSupported: 'あなたのブラウザーはFileReaderをサポートしていません', + errInvalidImage: '画像形式が正しくありません' + }, + ko: { + base64: '그림 넣기(base64)', + file: '파일', + errFileReaderNotSupported: 'FileReader가 현재 브라우저를 지원하지 않습니다.', + errInvalidImage: '유효하지 않은 파일' }, nl: { base64: 'Afbeelding inline', @@ -50,42 +64,34 @@ errFileReaderNotSupported: 'Uw browser ondersteunt deze functionaliteit niet.', errInvalidImage: 'De gekozen afbeelding is ongeldig.' }, + pt_br: { + base64: 'Imagem em base64', + file: 'Arquivo', + errFileReaderNotSupported: 'FileReader não é suportado pelo seu navegador.', + errInvalidImage: 'Arquivo de imagem inválido.' + }, ru: { base64: 'Изображение как код в base64', file: 'Файл', errFileReaderNotSupported: 'FileReader не поддерживается вашим браузером.', errInvalidImage: 'Недопустимый файл изображения.' }, - ja: { - base64: '画像 (Base64形式)', - file: 'ファイル', - errFileReaderNotSupported: 'あなたのブラウザーはFileReaderをサポートしていません', - errInvalidImage: '画像形式が正しくありません' - }, tr: { base64: 'Base64 olarak resim', file: 'Dosya', errFileReaderNotSupported: 'FileReader tarayıcınız tarafından desteklenmiyor.', errInvalidImage: 'Geçersiz resim dosyası.' }, + zh_cn: { + base64: '图片(Base64编码)', + file: '文件' + }, zh_tw: { base64: '圖片(base64編碼)', file: '檔案', errFileReaderNotSupported: '你的瀏覽器不支援FileReader', errInvalidImage: '不正確的檔案格式' }, - pt_br: { - base64: 'Imagem em base64', - file: 'Arquivo', - errFileReaderNotSupported: 'FileReader não é suportado pelo seu navegador.', - errInvalidImage: 'Arquivo de imagem inválido.' - }, - ko: { - base64: '그림 넣기(base64)', - file: '파일', - errFileReaderNotSupported: 'FileReader가 현재 브라우저를 지원하지 않습니다.', - errInvalidImage: '유효하지 않은 파일' - }, }, // jshint camelcase:true diff --git a/plugins/cleanpaste/trumbowyg.cleanpaste.js b/plugins/cleanpaste/trumbowyg.cleanpaste.js index 861605470..444fd5f9c 100644 --- a/plugins/cleanpaste/trumbowyg.cleanpaste.js +++ b/plugins/cleanpaste/trumbowyg.cleanpaste.js @@ -96,12 +96,48 @@ plugins: { cleanPaste: { init: function (trumbowyg) { - trumbowyg.pasteHandlers.push(function () { + trumbowyg.pasteHandlers.push(function (pasteEvent) { setTimeout(function () { - try { - trumbowyg.$ed.html(cleanIt(trumbowyg.$ed.html())); - } catch (c) { - } + try { + trumbowyg.saveRange(); + + var clipboardData = (pasteEvent.originalEvent || pasteEvent).clipboardData, + pastedData = clipboardData.getData('Text'), + node = trumbowyg.doc.getSelection().focusNode, + range = trumbowyg.doc.createRange(), + cleanedPaste = cleanIt(pastedData.trim()), + newNode = $(cleanedPaste)[0] || trumbowyg.doc.createTextNode(cleanedPaste); + + if (trumbowyg.$ed.html() === '') { + // simply append if there is no content in editor + trumbowyg.$ed[0].appendChild(newNode); + } else { + // insert pasted content behind last focused node + range.setStartAfter(node); + range.setEndAfter(node); + trumbowyg.doc.getSelection().removeAllRanges(); + trumbowyg.doc.getSelection().addRange(range); + + trumbowyg.range.insertNode(newNode); + } + + // now set cursor right after pasted content + range = trumbowyg.doc.createRange(); + range.setStartAfter(newNode); + range.setEndAfter(newNode); + trumbowyg.doc.getSelection().removeAllRanges(); + trumbowyg.doc.getSelection().addRange(range); + + // prevent defaults + pasteEvent.stopPropagation(); + pasteEvent.preventDefault(); + + // save new node as focused node + trumbowyg.saveRange(); + trumbowyg.syncCode(); + trumbowyg.$c.trigger('tbwchange'); + } catch (c) { + } }, 0); }); } diff --git a/plugins/colors/trumbowyg.colors.js b/plugins/colors/trumbowyg.colors.js index f01b95f2f..e544beaf5 100644 --- a/plugins/colors/trumbowyg.colors.js +++ b/plugins/colors/trumbowyg.colors.js @@ -14,67 +14,73 @@ $.extend(true, $.trumbowyg, { langs: { // jshint camelcase:false - cs: { - foreColor: 'Barva textu', - backColor: 'Barva pozadí' - }, en: { foreColor: 'Text color', backColor: 'Background color', foreColorRemove: 'Remove text color', backColorRemove: 'Remove background color' }, + cs: { + foreColor: 'Barva textu', + backColor: 'Barva pozadí' + }, da: { foreColor: 'Tekstfarve', backColor: 'Baggrundsfarve' }, + de: { + foreColor: 'Textfarbe', + backColor: 'Hintergrundfarbe' + }, fr: { foreColor: 'Couleur du texte', backColor: 'Couleur de fond', foreColorRemove: 'Supprimer la couleur du texte', backColorRemove: 'Supprimer la couleur de fond' }, - de: { - foreColor: 'Textfarbe', - backColor: 'Hintergrundfarbe' + hu: { + foreColor: 'Betű szín', + backColor: 'Háttér szín', + foreColorRemove: 'Betű szín eltávolítása', + backColorRemove: 'Háttér szín eltávolítása' + }, + ja: { + foreColor: '文字色', + backColor: '背景色' + }, + ko: { + foreColor: '글자색', + backColor: '배경색', + foreColorRemove: '글자색 지우기', + backColorRemove: '배경색 지우기' }, nl: { foreColor: 'Tekstkleur', backColor: 'Achtergrondkleur' }, - sk: { - foreColor: 'Farba textu', - backColor: 'Farba pozadia' - }, - zh_cn: { - foreColor: '文字颜色', - backColor: '背景颜色' - }, - zh_tw: { - foreColor: '文字顏色', - backColor: '背景顏色' + pt_br: { + foreColor: 'Cor de fonte', + backColor: 'Cor de fundo' }, ru: { foreColor: 'Цвет текста', backColor: 'Цвет выделения текста' }, - ja: { - foreColor: '文字色', - backColor: '背景色' + sk: { + foreColor: 'Farba textu', + backColor: 'Farba pozadia' }, tr: { foreColor: 'Yazı rengi', backColor: 'Arkaplan rengi' }, - pt_br: { - foreColor: 'Cor de fonte', - backColor: 'Cor de fundo' + zh_cn: { + foreColor: '文字颜色', + backColor: '背景颜色' }, - ko: { - foreColor: '글자색', - backColor: '배경색', - foreColorRemove: '글자색 지우기', - backColorRemove: '배경색 지우기' + zh_tw: { + foreColor: '文字顏色', + backColor: '背景顏色' }, } }); diff --git a/plugins/emoji/trumbowyg.emoji.js b/plugins/emoji/trumbowyg.emoji.js index d4b456b35..7d464f740 100644 --- a/plugins/emoji/trumbowyg.emoji.js +++ b/plugins/emoji/trumbowyg.emoji.js @@ -90,6 +90,8 @@ '💙', '💜', '🖤', + '🤎', + '🤍', '💔', '💕', '💞', @@ -116,7 +118,6 @@ '♏', '🆔', '⚛', - '♾', '🉑', '📴', '📳', @@ -241,6 +242,7 @@ '🔃', '🎵', '🎶', + '♾', '💲', '💱', '©', @@ -257,6 +259,11 @@ '⚫', '🔴', '🔵', + '🟤', + '🟣', + '🟢', + '🟡', + '🟠', '🔺', '🔻', '🔸', @@ -273,6 +280,13 @@ '◻', '⬛', '⬜', + '🟧', + '🟦', + '🟥', + '🟫', + '🟪', + '🟩', + '🟨', '🔈', '🔇', '🔉', @@ -321,25 +335,26 @@ '🎾', '🏐', '🏉', + '🥏', '🎱', '🏓', '🏸', - '🥅', '🏒', '🏑', - '🏏', '🥍', + '🏏', + '🥅', '⛳', - '🥏', '🏹', '🎣', '🥊', '🥋', '🎽', '🛹', + '🛷', + '🪂', '⛸', '🥌', - '🛷', '🎿', '⛷', '🏂', @@ -381,13 +396,18 @@ '🥁', '🎷', '🎺', + '🪕', '🎸', '🎻', '🎲', + '♟', '🎯', + '🪁', + '🪀', '🎳', '🎮', '🎰', + '🧩', '⌚', '📱', '📲', @@ -397,8 +417,6 @@ '🖱', '🖲', '🕹', - '♟', - '🧩', '🗜', '💽', '💾', @@ -420,6 +438,7 @@ '🎙', '🎚', '🎛', + '🧭', '⏱', '⏲', '⏰', @@ -427,15 +446,12 @@ '⌛', '⏳', '📡', - '🧭', '🔋', '🔌', - '🧲', '💡', '🔦', '🕯', '🧯', - '🗑', '🛢', '💸', '💵', @@ -445,17 +461,20 @@ '💰', '💳', '💎', - '🧿', - '🧱', '🧰', '🔧', '🔨', '🛠', '⛏', '🔩', + '🧱', '⛓', + '🧲', '🔫', '💣', + '🧨', + '🪓', + '🪒', '🔪', '🗡', '🛡', @@ -463,32 +482,37 @@ '⚰', '⚱', '🏺', + '🪔', '🔮', '📿', + '🧿', '💈', - '🧪', - '🧫', - '🧬', - '🧮', '🔭', '🔬', '🕳', + '🦯', + '🩺', + '🩹', '💊', '💉', + '🩸', + '🧬', + '🦠', + '🧫', + '🧪', '🌡', + '🪑', + '🧹', + '🧺', + '🧻', '🚽', '🚰', '🚿', '🛁', '🛀', - '🧹', - '🧺', - '🧻', '🧼', '🧽', '🧴', - '🧵', - '🧶', '🛎', '🔑', '🗝', @@ -527,8 +551,8 @@ '📜', '📃', '📄', - '🧾', '📑', + '🧾', '📊', '📈', '📉', @@ -536,6 +560,7 @@ '🗓', '📆', '📅', + '🗑', '📇', '🗃', '🗳', @@ -556,12 +581,13 @@ '📚', '📖', '🔖', + '🧷', '🔗', '📎', '🖇', '📐', '📏', - '🧷', + '🧮', '📌', '📍', '🖊', @@ -574,17 +600,16 @@ '🔎', '🔏', '🔐', + '🔒', + '🔓', '🐶', '🐱', '🐭', '🐹', '🐰', '🦊', - '🦝', '🐻', '🐼', - '🦘', - '🦡', '🐨', '🐯', '🦁', @@ -604,11 +629,8 @@ '🐣', '🐥', '🦆', - '🦢', '🦅', '🦉', - '🦜', - '🦚', '🦇', '🐺', '🐗', @@ -621,12 +643,11 @@ '🐚', '🐞', '🐜', + '🦟', '🦗', '🕷', '🕸', '🦂', - '🦟', - '🦠', '🐢', '🐍', '🦎', @@ -635,8 +656,9 @@ '🐙', '🦑', '🦐', - '🦀', '🦞', + '🦪', + '🦀', '🐡', '🐠', '🐟', @@ -649,29 +671,41 @@ '🐆', '🦓', '🦍', + '🦧', '🐘', - '🦏', '🦛', + '🦏', '🐪', '🐫', '🦒', - '🦙', + '🦘', '🐃', '🐂', '🐄', '🐎', '🐖', '🐏', + '🦙', '🐑', '🐐', '🦌', '🐕', + '🦮', '🐩', '🐈', '🐓', '🦃', + '🦚', + '🦜', + '🦢', + '🦩', '🕊', '🐇', + '🦥', + '🦦', + '🦨', + '🦝', + '🦡', '🐁', '🐀', '🐿', @@ -719,6 +753,7 @@ '🌎', '🌍', '🌏', + '🪐', '💫', '⭐', '🌟', @@ -767,17 +802,20 @@ '🌶', '🌽', '🥕', + '🧅', + '🧄', '🥔', '🍠', '🥐', + '🥯', '🍞', '🥖', '🥨', - '🥯', '🧀', '🥚', '🍳', '🥞', + '🧇', '🥓', '🥩', '🍗', @@ -787,6 +825,7 @@ '🍟', '🍕', '🥪', + '🧆', '🥙', '🌮', '🌯', @@ -799,38 +838,41 @@ '🍛', '🍣', '🍱', + '🥟', '🍤', '🍙', '🍚', '🍘', '🍥', '🥠', + '🥮', '🍢', '🍡', '🍧', '🍨', '🍦', '🥧', + '🧁', '🍰', '🎂', - '🥮', - '🧁', '🍮', '🍭', '🍬', '🍫', '🍿', - '🧂', '🍩', - '🥟', '🍪', '🌰', '🥜', '🍯', + '🧈', '🥛', '🍼', '🍵', + '🧉', '🥤', + '🧃', + '🧊', '🍶', '🍺', '🍻', @@ -846,6 +888,7 @@ '🥣', '🥡', '🥢', + '🧂', '😀', '😃', '😄', @@ -862,8 +905,8 @@ '😉', '😌', '😍', - '😘', '🥰', + '😘', '😗', '😙', '😚', @@ -889,6 +932,7 @@ '😖', '😫', '😩', + '🥺', '😢', '😭', '😤', @@ -897,17 +941,17 @@ '🤬', '🤯', '😳', + '🥵', + '🥶', '😱', '😨', '😰', - '🥵', - '🥶', - '🥺', '😥', '😓', '🤗', '🤔', '🤭', + '🥱', '🤫', '🤥', '😶', @@ -971,6 +1015,7 @@ '🤟', '🤘', '👌', + '🤏', '👈', '👉', '👆', @@ -983,23 +1028,25 @@ '👋', '🤙', '💪', - '🦵', - '🦶', + '🦾', '🖕', '✍', '🙏', - '💍', + '🦶', + '🦵', + '🦿', '💄', '💋', '👄', + '🦷', + '🦴', '👅', '👂', + '🦻', '👃', '👣', '👀', '🧠', - '🦴', - '🦷', '🗣', '👤', '👥', @@ -1026,10 +1073,10 @@ '🤵', '👸', '🤴', - '🤶', - '🎅', '🦸', '🦹', + '🤶', + '🎅', '🧙', '🧝', '🧛', @@ -1045,6 +1092,7 @@ '🙅', '🙆', '🙋', + '🧏', '🤦', '🤷', '🙎', @@ -1060,28 +1108,38 @@ '🕴', '🚶', '🏃', + '🧍', + '🧎', '👫', '👭', '👬', '💑', '💏', '👪', + '🧶', + '🧵', '🧥', + '🥼', + '🦺', '👚', '👕', '👖', + '🩳', '👔', '👗', '👙', + '🩱', '👘', - '🥼', + '🥻', + '🥿', '👠', '👡', '👢', + '🩰', '👞', '👟', '🥾', - '🥿', + '🩲', '🧦', '🧤', '🧣', @@ -1091,45 +1149,22 @@ '🎓', '⛑', '👑', + '💍', '👝', '👛', '👜', '💼', '🎒', + '🧳', '👓', '🕶', '🥽', + '🤿', '🌂', - '🦰', '🦱', + '🦰', '🦳', '🦲', - '🇿', - '🇾', - '🇽', - '🇼', - '🇻', - '🇺', - '🇹', - '🇸', - '🇷', - '🇶', - '🇵', - '🇴', - '🇳', - '🇲', - '🇱', - '🇰', - '🇯', - '🇮', - '🇭', - '🇬', - '🇫', - '🇪', - '🇩', - '🇨', - '🇧', - '🇦', '🚗', '🚕', '🚙', @@ -1143,10 +1178,13 @@ '🚚', '🚛', '🚜', - '🛴', - '🚲', + '🛺', '🛵', '🏍', + '🛴', + '🚲', + '🦼', + '🦽', '🚨', '🚔', '🚍', @@ -1171,7 +1209,6 @@ '🛬', '🛩', '💺', - '🧳', '🛰', '🚀', '🛸', @@ -1229,6 +1266,7 @@ '🏛', '⛪', '🕌', + '🛕', '🕍', '🕋', '⛩', @@ -1242,16 +1280,39 @@ '🌠', '🎇', '🎆', - '🧨', '🌇', '🌆', '🏙', '🌃', '🌌', '🌉', - '🔒', - '🔓', '🌁', + '🇿', + '🇾', + '🇽', + '🇼', + '🇻', + '🇺', + '🇹', + '🇸', + '🇷', + '🇶', + '🇵', + '🇴', + '🇳', + '🇲', + '🇱', + '🇰', + '🇯', + '🇮', + '🇭', + '🇬', + '🇫', + '🇪', + '🇩', + '🇨', + '🇧', + '🇦', '🏳', '🏴', '🏁', @@ -1281,20 +1342,23 @@ fr: { emoji: 'Ajouter un emoji' }, - zh_cn: { - emoji: '添加表情' - }, - ru: { - emoji: 'Вставить emoji' + hu: { + emoji: 'Emoji beszúrás' }, ja: { emoji: '絵文字の挿入' }, + ko: { + emoji: '이모지 넣기' + }, + ru: { + emoji: 'Вставить emoji' + }, tr: { emoji: 'Emoji ekle' }, - ko: { - emoji: '이모지 넣기' + zh_cn: { + emoji: '添加表情' }, }, // jshint camelcase:true diff --git a/plugins/fontfamily/trumbowyg.fontfamily.js b/plugins/fontfamily/trumbowyg.fontfamily.js index b23f860c3..00003a1a9 100644 --- a/plugins/fontfamily/trumbowyg.fontfamily.js +++ b/plugins/fontfamily/trumbowyg.fontfamily.js @@ -13,27 +13,30 @@ da: { fontFamily: 'Skrifttype' }, + de: { + fontFamily: 'Schriftart' + }, fr: { fontFamily: 'Police' }, - de: { - fontFamily: 'Schriftart' + hu: { + fontFamily: 'Betűtípus' + }, + ko: { + fontFamily: '글꼴' }, nl: { fontFamily: 'Lettertype' }, + pt_br: { + fontFamily: 'Fonte', + }, tr: { fontFamily: 'Yazı Tipi' }, zh_tw: { fontFamily: '字體', }, - pt_br: { - fontFamily: 'Fonte', - }, - ko: { - fontFamily: '글꼴' - }, } }); // jshint camelcase:true diff --git a/plugins/fontsize/trumbowyg.fontsize.js b/plugins/fontsize/trumbowyg.fontsize.js index 03bcbc4c1..cfa55beb1 100644 --- a/plugins/fontsize/trumbowyg.fontsize.js +++ b/plugins/fontsize/trumbowyg.fontsize.js @@ -20,6 +20,33 @@ value: '48px' } }, + da: { + fontsize: 'Skriftstørrelse', + fontsizes: { + 'x-small': 'Ekstra lille', + 'small': 'Lille', + 'medium': 'Normal', + 'large': 'Stor', + 'x-large': 'Ekstra stor', + 'custom': 'Brugerdefineret' + } + }, + de: { + fontsize: 'Schriftgröße', + fontsizes: { + 'x-small': 'Sehr klein', + 'small': 'Klein', + 'medium': 'Normal', + 'large': 'Groß', + 'x-large': 'Sehr groß', + 'custom': 'Benutzerdefiniert' + }, + fontCustomSize: { + title: 'Benutzerdefinierte Schriftgröße', + label: 'Schriftgröße', + value: '48px' + } + }, es: { fontsize: 'Tamaño de Fuente', fontsizes: { @@ -36,17 +63,6 @@ value: '48px' } }, - da: { - fontsize: 'Skriftstørrelse', - fontsizes: { - 'x-small': 'Ekstra lille', - 'small': 'Lille', - 'medium': 'Normal', - 'large': 'Stor', - 'x-large': 'Ekstra stor', - 'custom': 'Brugerdefineret' - } - }, fr: { fontsize: 'Taille de la police', fontsizes: { @@ -63,19 +79,51 @@ value: '48px' } }, - de: { - fontsize: 'Schriftgröße', + hu: { + fontsize: 'Betű méret', fontsizes: { - 'x-small': 'Sehr klein', - 'small': 'Klein', - 'medium': 'Normal', - 'large': 'Groß', - 'x-large': 'Sehr groß', - 'custom': 'Benutzerdefiniert' + 'x-small': 'Extra kicsi', + 'small': 'Kicsi', + 'medium': 'Normális', + 'large': 'Nagy', + 'x-large': 'Extra nagy', + 'custom': 'Egyedi' }, fontCustomSize: { - title: 'Benutzerdefinierte Schriftgröße', - label: 'Schriftgröße', + title: 'Egyedi betű méret', + label: 'Betű méret', + value: '48px' + } + }, + it: { + fontsize: 'Dimensioni del testo', + fontsizes: { + 'x-small': 'Molto piccolo', + 'small': 'piccolo', + 'regular': 'normale', + 'large': 'grande', + 'x-large': 'Molto grande', + 'custom': 'Personalizzato' + }, + fontCustomSize: { + title: 'Dimensioni del testo personalizzato', + label: 'Dimensioni del testo', + value: '48px' + } + }, + ko: { + fontsize: '글꼴 크기', + fontsizes: { + 'x-small': '아주 작게', + 'small': '작게', + 'medium': '보통', + 'large': '크게', + 'x-large': '아주 크게', + 'custom': '사용자 지정' + }, + fontCustomSize: { + title: '사용자 지정 글꼴 크기', + label: '글꼴 크기', value: '48px' } }, @@ -90,6 +138,22 @@ 'custom': 'Tilpasset' } }, + pt_br: { + fontsize: 'Tamanho da fonte', + fontsizes: { + 'x-small': 'Extra pequeno', + 'small': 'Pequeno', + 'regular': 'Médio', + 'large': 'Grande', + 'x-large': 'Extra grande', + 'custom': 'Personalizado' + }, + fontCustomSize: { + title: 'Tamanho de Fonte Personalizado', + label: 'Tamanho de Fonte', + value: '48px' + } + }, tr: { fontsize: 'Yazı Boyutu', fontsizes: { @@ -117,54 +181,6 @@ value: '48px' } }, - pt_br: { - fontsize: 'Tamanho da fonte', - fontsizes: { - 'x-small': 'Extra pequeno', - 'small': 'Pequeno', - 'regular': 'Médio', - 'large': 'Grande', - 'x-large': 'Extra grande', - 'custom': 'Personalizado' - }, - fontCustomSize: { - title: 'Tamanho de Fonte Personalizado', - label: 'Tamanho de Fonte', - value: '48px' - } - }, - it: { - fontsize: 'Dimensioni del testo', - fontsizes: { - 'x-small': 'Molto piccolo', - 'small': 'piccolo', - 'regular': 'normale', - 'large': 'grande', - 'x-large': 'Molto grande', - 'custom': 'Personalizzato' - }, - fontCustomSize: { - title: 'Dimensioni del testo personalizzato', - label: 'Dimensioni del testo', - value: '48px' - } - }, - ko: { - fontsize: '글꼴 크기', - fontsizes: { - 'x-small': '아주 작게', - 'small': '작게', - 'medium': '보통', - 'large': '크게', - 'x-large': '아주 크게', - 'custom': '사용자 지정' - }, - fontCustomSize: { - title: '사용자 지정 글꼴 크기', - label: '글꼴 크기', - value: '48px' - } - }, } }); // jshint camelcase:true @@ -201,17 +217,24 @@ function setFontSize(trumbowyg, size) { trumbowyg.$ed.focus(); trumbowyg.saveRange(); - var text = trumbowyg.range.startContainer.parentElement; - var selectedText = trumbowyg.getRangeText(); - if ($(text).html() === selectedText) { - $(text).css('font-size', size); - } else { - trumbowyg.range.deleteContents(); - var html = '' + selectedText + ''; - var node = $(html)[0]; - trumbowyg.range.insertNode(node); - } + + // Temporary size + trumbowyg.execCmd('fontSize', '1'); + + // Find elements that were added and change to with chosen size + trumbowyg.$ed.find('font[size="1"]').replaceWith(function() { + return $('', { + css: { 'font-size': size }, + html: this.innerHTML, + }); + }); + + // Remove and leftover elements + $(trumbowyg.range.startContainer.parentElement).find('span[style=""]').contents().unwrap(); + trumbowyg.restoreRange(); + trumbowyg.syncCode(); + trumbowyg.$c.trigger('tbwchange'); } function buildDropdown(trumbowyg) { diff --git a/plugins/giphy/trumbowyg.giphy.js b/plugins/giphy/trumbowyg.giphy.js index 4c3dc75e5..f4ce91bc7 100644 --- a/plugins/giphy/trumbowyg.giphy.js +++ b/plugins/giphy/trumbowyg.giphy.js @@ -10,11 +10,14 @@ fr: { giphy: 'Insérer un GIF', }, + hu: { + giphy: 'GIF beszúrás', + }, // jshint camelcase:true } }); - var giphyLogo = ''; + var giphyLogo = ''; // jshint ignore:line var CANCEL_EVENT = 'tbwcancel'; diff --git a/plugins/highlight/trumbowyg.highlight.js b/plugins/highlight/trumbowyg.highlight.js index 1ca737ca7..4873892c1 100644 --- a/plugins/highlight/trumbowyg.highlight.js +++ b/plugins/highlight/trumbowyg.highlight.js @@ -5,9 +5,9 @@ // My plugin default options var defaultOptions = {}; - function highlightIt(text, language) { + function highlightIt(text, language, lineHighlight) { return [ - '
',
+            '
',
             '' + Prism.highlight(text, Prism.languages[language]) + '',
             '
', ].join(''); @@ -36,14 +36,20 @@ '
', ' ', '
', + '
', + ' ', + '
' ].join('\n')), $language = $modal.find('.language'), - $code = $modal.find('.code'); + $code = $modal.find('.code'), + $lineHighlight = $modal.find('.trumbowyg-line-highlight'); // Listen clicks on modal box buttons $modal.on('tbwconfirm', function () { trumbowyg.restoreRange(); - trumbowyg.execCmd('insertHTML', highlightIt($code.val(), $language.val())); + trumbowyg.execCmd('insertHTML', highlightIt($code.val(), $language.val(), $lineHighlight.val())); trumbowyg.execCmd('insertHTML', '


'); trumbowyg.closeModal(); @@ -61,14 +67,24 @@ langs: { // jshint camelcase:false en: { - highlight: 'Code syntax highlight' + highlight: 'Code syntax highlight', + highlightLine: 'Highlight lines, e.g.: 1,3-5', + prismHighlightPluginAlert: 'You must have Prism Line Highlight plugin installed' }, - pt_br: { - highlight: 'Realçar sintaxe de código' + es: { + highlight: 'Resaltado de sintaxis de código', + highlightLine: 'Resaltar lineas, ej: 1,3-5', + prismHighlightPluginAlert: 'Debes de tener el plugin Prism Line Highlight instalado' + }, + hu: { + highlight: 'Kód kiemelés' }, ko: { highlight: '코드 문법 하이라이트' }, + pt_br: { + highlight: 'Realçar sintaxe de código' + }, // jshint camelcase:true }, // Add our plugin to Trumbowyg registered plugins diff --git a/plugins/history/trumbowyg.history.js b/plugins/history/trumbowyg.history.js index a66769932..4a495c743 100644 --- a/plugins/history/trumbowyg.history.js +++ b/plugins/history/trumbowyg.history.js @@ -11,12 +11,6 @@ $.extend(true, $.trumbowyg, { langs: { // jshint camelcase:false - de: { - history: { - redo: 'Wiederholen', - undo: 'Rückgängig' - } - }, en: { history: { redo: 'Redo', @@ -29,22 +23,22 @@ undo: 'Fortryd' } }, + de: { + history: { + redo: 'Wiederholen', + undo: 'Rückgängig' + } + }, fr: { history: { redo: 'Annuler', undo: 'Rétablir' } }, - zh_tw: { - history: { - redo: '重做', - undo: '復原' - } - }, - pt_br: { + hu: { history: { - redo: 'Refazer', - undo: 'Desfazer' + redo: 'Visszállít', + undo: 'Visszavon' } }, ko: { @@ -53,6 +47,18 @@ undo: '되돌리기' } }, + pt_br: { + history: { + redo: 'Refazer', + undo: 'Desfazer' + } + }, + zh_tw: { + history: { + redo: '重做', + undo: '復原' + } + }, // jshint camelcase:true }, plugins: { diff --git a/plugins/insertaudio/trumbowyg.insertaudio.js b/plugins/insertaudio/trumbowyg.insertaudio.js index 821c315e5..62c65834e 100644 --- a/plugins/insertaudio/trumbowyg.insertaudio.js +++ b/plugins/insertaudio/trumbowyg.insertaudio.js @@ -43,20 +43,23 @@ fr: { insertAudio: 'Insérer un son' }, - ru: { - insertAudio: 'Вставить аудио' + hu: { + insertAudio: 'Audio beszúrás' }, ja: { insertAudio: '音声の挿入' }, - tr: { - insertAudio: 'Ses Ekle' + ko: { + insertAudio: '소리 넣기' }, pt_br: { insertAudio: 'Inserir áudio' }, - ko: { - insertAudio: '소리 넣기' + ru: { + insertAudio: 'Вставить аудио' + }, + tr: { + insertAudio: 'Ses Ekle' }, // jshint camelcase:true }, diff --git a/plugins/lineheight/trumbowyg.lineheight.js b/plugins/lineheight/trumbowyg.lineheight.js index 148a4a6e8..5425983a7 100644 --- a/plugins/lineheight/trumbowyg.lineheight.js +++ b/plugins/lineheight/trumbowyg.lineheight.js @@ -31,6 +31,33 @@ '2.0': 'Très grande' } }, + hu: { + lineheight: 'Line height', + lineheights: { + '0.9': 'Small', + 'normal': 'Regular', + '1.5': 'Large', + '2.0': 'Extra large' + } + }, + it: { + lineheight: 'Altezza linea', + lineheights: { + '0.9': 'Bassa', + 'normal': 'Normale', + '1.5': 'Alta', + '2.0': 'Molto alta' + } + }, + ko: { + lineheight: '줄 간격', + lineheights: { + '0.9': '좁게', + 'normal': '보통', + '1.5': '넓게', + '2.0': '아주 넓게' + } + }, nl: { lineheight: 'Regelhoogte', lineheights: { @@ -40,6 +67,15 @@ '2.0': 'Extra groot' } }, + pt_br: { + lineheight: 'Altura de linha', + lineheights: { + '0.9': 'Pequena', + 'normal': 'Regular', + '1.5': 'Grande', + '2.0': 'Extra grande' + } + }, tr: { lineheight: 'Satır yüksekliği', lineheights: { @@ -58,33 +94,6 @@ '2.0': '特大' } }, - pt_br: { - lineheight: 'Altura de linha', - lineheights: { - '0.9': 'Pequena', - 'normal': 'Regular', - '1.5': 'Grande', - '2.0': 'Extra grande' - } - }, - it: { - lineheight: 'Altezza linea', - lineheights: { - '0.9': 'Bassa', - 'normal': 'Normale', - '1.5': 'Alta', - '2.0': 'Molto alta' - } - }, - ko: { - lineheight: '줄 간격', - lineheights: { - '0.9': '좁게', - 'normal': '보통', - '1.5': '넓게', - '2.0': '아주 넓게' - } - }, } }); // jshint camelcase:true diff --git a/plugins/mathml/trumbowyg.mathml.js b/plugins/mathml/trumbowyg.mathml.js index f3fee8a46..7deba1e2f 100644 --- a/plugins/mathml/trumbowyg.mathml.js +++ b/plugins/mathml/trumbowyg.mathml.js @@ -27,6 +27,21 @@ formulas: 'Formule', inline: 'En ligne' }, + hu: { + mathml: 'Formulák beszúrás', + formulas: 'Formulák', + inline: 'Inline' + }, + ko: { + mathml: '수식 넣기', + formulas: '수식', + inline: '글 안에 넣기' + }, + pt_br: { + mathml: 'Inserir fórmulas', + formulas: 'Fórmulas', + inline: 'Em linha' + }, tr: { mathml: 'Formül Ekle', formulas: 'Formüller', @@ -37,16 +52,6 @@ formulas: '方程式', inline: '內嵌' }, - pt_br: { - mathml: 'Inserir fórmulas', - formulas: 'Fórmulas', - inline: 'Em linha' - }, - ko: { - mathml: '수식 넣기', - formulas: '수식', - inline: '글 안에 넣기' - }, }, // jshint camelcase:true diff --git a/plugins/mention/trumbowyg.mention.js b/plugins/mention/trumbowyg.mention.js index 379fd0041..24c13805f 100644 --- a/plugins/mention/trumbowyg.mention.js +++ b/plugins/mention/trumbowyg.mention.js @@ -29,6 +29,15 @@ fr: { mention: 'Mentionner' }, + hu: { + mention: 'Említ' + }, + ko: { + mention: '언급' + }, + pt_br: { + mention: 'Menção' + }, ru: { mention: 'Упомянуть' }, @@ -38,12 +47,6 @@ zh_tw: { mention: '標記' }, - pt_br: { - mention: 'Menção' - }, - ko: { - mention: '언급' - }, // jshint camelcase:true }, diff --git a/plugins/noembed/trumbowyg.noembed.js b/plugins/noembed/trumbowyg.noembed.js index 212d6784f..3bc69d503 100644 --- a/plugins/noembed/trumbowyg.noembed.js +++ b/plugins/noembed/trumbowyg.noembed.js @@ -24,23 +24,35 @@ noembed: 'Noembed', noembedError: 'Error' }, + cs: { + noembedError: 'Chyba' + }, da: { noembedError: 'Fejl' }, - sk: { - noembedError: 'Chyba' - }, fr: { noembedError: 'Erreur' }, - cs: { - noembedError: 'Chyba' + hu: { + noembed: 'Noembed', + noembedError: 'Hiba' + }, + ja: { + noembedError: 'エラー' + }, + ko: { + noembed: 'oEmbed 넣기', + noembedError: '에러' + }, + pt_br: { + noembed: 'Incorporar', + noembedError: 'Erro' }, ru: { noembedError: 'Ошибка' }, - ja: { - noembedError: 'エラー' + sk: { + noembedError: 'Chyba' }, tr: { noembedError: 'Hata' @@ -49,14 +61,6 @@ noembed: '插入影片', noembedError: '錯誤' }, - pt_br: { - noembed: 'Incorporar', - noembedError: 'Erro' - }, - ko: { - noembed: 'oEmbed 넣기', - noembedError: '에러' - }, // jshint camelcase:true }, diff --git a/plugins/preformatted/trumbowyg.preformatted.js b/plugins/preformatted/trumbowyg.preformatted.js index a42de4bb5..2c36ad85a 100644 --- a/plugins/preformatted/trumbowyg.preformatted.js +++ b/plugins/preformatted/trumbowyg.preformatted.js @@ -22,30 +22,33 @@ fr: { preformatted: 'Exemple de code
'
             },
+            hu: {
+                preformatted: 'Kód minta 
'
+            },
             it: {
                 preformatted: 'Codice 
'
             },
-            zh_cn: {
-                preformatted: '代码示例 
'
+            ja: {
+                preformatted: 'コードサンプル 
'
+            },
+            ko: {
+                preformatted: '코드 예제 
'
+            },
+            pt_br: {
+                preformatted: 'Exemple de código 
'
             },
             ru: {
                 preformatted: 'Пример кода 
'
             },
-            ja: {
-                preformatted: 'コードサンプル 
'
-            },
             tr: {
                 preformatted: 'Kod örneği 
'
             },
+            zh_cn: {
+                preformatted: '代码示例 
'
+            },
             zh_tw: {
                 preformatted: '代碼範例 
'
             },
-            pt_br: {
-                preformatted: 'Exemple de código 
'
-            },
-            ko: {
-                preformatted: '코드 예제 
'
-            },
         },
         // jshint camelcase:true
 
diff --git a/plugins/resizimg/trumbowyg.resizimg.js b/plugins/resizimg/trumbowyg.resizimg.js
index d62356985..3a0e4b232 100644
--- a/plugins/resizimg/trumbowyg.resizimg.js
+++ b/plugins/resizimg/trumbowyg.resizimg.js
@@ -1,4 +1,4 @@
-;(function ($) {
+; (function ($) {
     'use strict';
 
     var defaultOptions = {
@@ -11,7 +11,7 @@
         e.preventDefault();
     }
 
-    var ResizeWithCanvas = function () {
+    var ResizeWithCanvas = function (trumbowyg) {
         // variable to create canvas and save img in resize mode
         this.resizeCanvas = document.createElement('canvas');
         // to allow canvas to get focus
@@ -24,8 +24,13 @@
             obj.reset();
         };
         this.pressBackspaceOrDelete = function (obj) {
-            $(obj.resizeCanvas).replaceWith('');
+            $(obj.resizeCanvas).remove();
             obj.resizeImg = null;
+            if (trumbowyg !== null){
+                trumbowyg.syncCode();
+                // notify changes
+                trumbowyg.$c.trigger('tbwchange');
+            }
         };
 
         // PRIVATE FUNCTION
@@ -40,15 +45,6 @@
             offsetY = BB.top;
         };
 
-        var drawRect = function (shapeData, ctx) {
-            // Inner
-            ctx.beginPath();
-            ctx.fillStyle = 'rgb(255, 255, 255)';
-            ctx.rect(shapeData.points.x, shapeData.points.y, shapeData.points.width, shapeData.points.height);
-            ctx.fill();
-            ctx.stroke();
-        };
-
         var updateCanvas = function (canvas, ctx, img, canvasWidth, canvasHeight) {
             ctx.translate(0.5, 0.5);
             ctx.lineWidth = 1;
@@ -109,10 +105,8 @@
                 return;
             }
 
-            this.resizeImg.width = this.resizeCanvas.clientWidth - 10;
-            this.resizeImg.height = this.resizeCanvas.clientHeight - 10;
-            // clear style of image to avoid issue on resize because this attribute have priority over width and height attribute
-            this.resizeImg.removeAttribute('style');
+            // set style of image to avoid issue on resize because this attribute have priority over width and height attribute
+            this.resizeImg.setAttribute('style', 'width: 100%; max-width: ' + (this.resizeCanvas.clientWidth - 10) + 'px; height: auto; max-height: ' + (this.resizeCanvas.clientHeight - 10) + 'px;');
 
             $(this.resizeCanvas).replaceWith($(this.resizeImg));
 
@@ -172,7 +166,16 @@
                         _this.pressBackspaceOrDelete(_this);
                     }
                 })
-                .on('focus', preventDefault);
+                .on('focus', preventDefault)
+                .on('blur', function () {
+                    _this.reset();
+                    // save changes
+                    if (trumbowyg !== null){
+                        trumbowyg.syncCode();
+                        // notify changes
+                        trumbowyg.$c.trigger('tbwchange');
+                    }
+                });
 
             this.resizeCanvas.focus();
 
@@ -191,25 +194,28 @@
         };
     };
 
-    // object to interact with canvas
-    var resizeWithCanvas = new ResizeWithCanvas();
-
-    function destroyResizable(trumbowyg) {
-        // clean html code
-        trumbowyg.$ed.find('canvas.resizable')
-            .resizable('destroy')
-            .off('mousedown', preventDefault)
-            .removeClass('resizable');
-
-        resizeWithCanvas.reset();
-
-        trumbowyg.syncCode();
-    }
-
     $.extend(true, $.trumbowyg, {
         plugins: {
             resizimg: {
+                destroyResizable: function () {},
                 init: function (trumbowyg) {
+                    var destroyResizable = this.destroyResizable;
+
+                    // object to interact with canvas
+                    var resizeWithCanvas = new ResizeWithCanvas(trumbowyg);
+
+                    this.destroyResizable = function () {
+                        // clean html code
+                        trumbowyg.$ed.find('canvas.resizable')
+                            .resizable('destroy')
+                            .off('mousedown', preventDefault)
+                            .removeClass('resizable');
+
+                        resizeWithCanvas.reset();
+
+                        trumbowyg.syncCode();
+                    };
+
                     trumbowyg.o.plugins.resizimg = $.extend(true, {},
                         defaultOptions,
                         trumbowyg.o.plugins.resizimg || {},
@@ -269,8 +275,9 @@
 
                             preventDefault(e);
                             resizeWithCanvas.reset();
-
-                            // save changes
+                            //sync
+                            trumbowyg.syncCode();
+                            // notify changes
                             trumbowyg.$c.trigger('tbwchange');
                         });
 
@@ -286,16 +293,17 @@
 
                     // Destroy
                     trumbowyg.$c.on('tbwblur', function () {
-                        // if I have already focused the canvas avoid destroy
+                        // when canvas is created the tbwblur is called
+                        // this code avoid to destroy the canvas that allow the image resizing
                         if (resizeWithCanvas.isFocusedNow()) {
                             resizeWithCanvas.blurNow();
                         } else {
-                            destroyResizable(trumbowyg);
+                            destroyResizable();
                         }
                     });
                 },
-                destroy: function (trumbowyg) {
-                    destroyResizable(trumbowyg);
+                destroy: function () {
+                    this.destroyResizable();
                 }
             }
         }
diff --git a/plugins/ruby/trumbowyg.ruby.js b/plugins/ruby/trumbowyg.ruby.js
index ac1bd4705..5392c2f21 100644
--- a/plugins/ruby/trumbowyg.ruby.js
+++ b/plugins/ruby/trumbowyg.ruby.js
@@ -29,6 +29,11 @@
                 rubyModal: 'Modale ruby',
                 rubyText: 'Texte ruby'
             },
+            hu: {
+                ruby: 'Ruby szöveg hozzáadás',
+                rubyModal: 'Ruby modal',
+                rubyText: 'Ruby szöveg'
+            },
             id: {
                 ruby: 'Sisipkan teks ruby',
                 rubyModal: 'Modal teks ruby',
diff --git a/plugins/specialchars/trumbowyg.specialchars.js b/plugins/specialchars/trumbowyg.specialchars.js
index a341b0795..d9649c0f4 100644
--- a/plugins/specialchars/trumbowyg.specialchars.js
+++ b/plugins/specialchars/trumbowyg.specialchars.js
@@ -31,6 +31,9 @@
             fr: {
                 specialChars: 'Caractères spéciaux'
             },
+            hu: {
+                specialChars: 'Speciális karakterek'
+            },
             ko: {
                 specialChars: '특수문자'
             },
diff --git a/plugins/table/trumbowyg.table.js b/plugins/table/trumbowyg.table.js
index f04f5a42c..5e6aa2ee8 100644
--- a/plugins/table/trumbowyg.table.js
+++ b/plugins/table/trumbowyg.table.js
@@ -29,6 +29,14 @@
                 tableDestroy: 'Delete table',
                 error: 'Error'
             },
+            cs: {
+                table: 'Vytvořit příkaz Table',
+                tableAddRow: 'Přidat řádek',
+                tableAddRowAbove: 'Přidat řádek',
+                tableAddColumnLeft: 'Přidat sloupec',
+                tableAddColumn: 'Přidat sloupec',
+                error: 'Chyba'
+            },
             da: {
                 table: 'Indsæt tabel',
                 tableAddRow: 'Tilføj række',
@@ -51,14 +59,6 @@
                 tableDestroy: 'Tabelle löschen',
                 error: 'Error'
             },
-            sk: {
-                table: 'Vytvoriť tabuľky',
-                tableAddRow: 'Pridať riadok',
-                tableAddRowAbove: 'Pridať riadok',
-                tableAddColumnLeft: 'Pridať stĺpec',
-                tableAddColumn: 'Pridať stĺpec',
-                error: 'Chyba'
-            },
             fr: {
                 table: 'Insérer un tableau',
                 tableAddRow: 'Ajouter des lignes',
@@ -70,13 +70,57 @@
                 tableDestroy: 'Effacer le tableau',
                 error: 'Erreur'
             },
-            cs: {
-                table: 'Vytvořit příkaz Table',
-                tableAddRow: 'Přidat řádek',
-                tableAddRowAbove: 'Přidat řádek',
-                tableAddColumnLeft: 'Přidat sloupec',
-                tableAddColumn: 'Přidat sloupec',
-                error: 'Chyba'
+            hu: {
+                table: 'Táblázat beszúrás',
+                tableAddRow: 'Sor hozzáadás',
+                tableAddRowAbove: 'Sor beszúrás fönt',
+                tableAddColumnLeft: 'Sor beszúrás balra',
+                tableAddColumn: 'Sor beszúrás jobbra',
+                tableDeleteRow: 'Sor törlés',
+                tableDeleteColumn: 'Oszlop törlés',
+                tableDestroy: 'Táblázat törlés',
+                error: 'Hiba'
+            },
+            id: {
+                table: 'Sisipkan tabel',
+                tableAddRow: 'Sisipkan baris',
+                tableAddRowAbove: 'Sisipkan baris',
+                tableAddColumnLeft: 'Sisipkan kolom',
+                tableAddColumn: 'Sisipkan kolom',
+                tableDeleteRow: 'Hapus baris',
+                tableDeleteColumn: 'Hapus kolom',
+                tableDestroy: 'Hapus tabel',
+                error: 'Galat'
+            },
+            ja: {
+                table: '表の挿入',
+                tableAddRow: '行の追加',
+                tableAddRowAbove: '行の追加',
+                tableAddColumnLeft: '列の追加',
+                tableAddColumn: '列の追加',
+                error: 'エラー'
+            },
+            ko: {
+                table: '표 넣기',
+                tableAddRow: '줄 추가',
+                tableAddRowAbove: '줄 추가',
+                tableAddColumnLeft: '칸 추가',
+                tableAddColumn: '칸 추가',
+                tableDeleteRow: '줄 삭제',
+                tableDeleteColumn: '칸 삭제',
+                tableDestroy: '표 지우기',
+                error: '에러'
+            },
+            pt_br: {
+                table: 'Inserir tabela',
+                tableAddRow: 'Adicionar linha',
+                tableAddRowAbove: 'Adicionar linha',
+                tableAddColumnLeft: 'Adicionar coluna',
+                tableAddColumn: 'Adicionar coluna',
+                tableDeleteRow: 'Deletar linha',
+                tableDeleteColumn: 'Deletar coluna',
+                tableDestroy: 'Deletar tabela',
+                error: 'Erro'
             },
             ru: {
                 table: 'Вставить таблицу',
@@ -89,13 +133,13 @@
                 tableDestroy: 'Удалить таблицу',
                 error: 'Ошибка'
             },
-            ja: {
-                table: '表の挿入',
-                tableAddRow: '行の追加',
-                tableAddRowAbove: '行の追加',
-                tableAddColumnLeft: '列の追加',
-                tableAddColumn: '列の追加',
-                error: 'エラー'
+            sk: {
+                table: 'Vytvoriť tabuľky',
+                tableAddRow: 'Pridať riadok',
+                tableAddRowAbove: 'Pridať riadok',
+                tableAddColumnLeft: 'Pridať stĺpec',
+                tableAddColumn: 'Pridať stĺpec',
+                error: 'Chyba'
             },
             tr: {
                 table: 'Tablo ekle',
@@ -116,39 +160,6 @@
                 tableDestroy: '刪除表格',
                 error: '錯誤'
             },
-            id: {
-                table: 'Sisipkan tabel',
-                tableAddRow: 'Sisipkan baris',
-                tableAddRowAbove: 'Sisipkan baris',
-                tableAddColumnLeft: 'Sisipkan kolom',
-                tableAddColumn: 'Sisipkan kolom',
-                tableDeleteRow: 'Hapus baris',
-                tableDeleteColumn: 'Hapus kolom',
-                tableDestroy: 'Hapus tabel',
-                error: 'Galat'
-            },
-            pt_br: {
-                table: 'Inserir tabela',
-                tableAddRow: 'Adicionar linha',
-                tableAddRowAbove: 'Adicionar linha',
-                tableAddColumnLeft: 'Adicionar coluna',
-                tableAddColumn: 'Adicionar coluna',
-                tableDeleteRow: 'Deletar linha',
-                tableDeleteColumn: 'Deletar coluna',
-                tableDestroy: 'Deletar tabela',
-                error: 'Erro'
-            },
-            ko: {
-                table: '표 넣기',
-                tableAddRow: '줄 추가',
-                tableAddRowAbove: '줄 추가',
-                tableAddColumnLeft: '칸 추가',
-                tableAddColumn: '칸 추가',
-                tableDeleteRow: '줄 삭제',
-                tableDeleteColumn: '칸 삭제',
-                tableDestroy: '표 지우기',
-                error: '에러'
-            },
             // jshint camelcase:true
         },
 
diff --git a/plugins/template/trumbowyg.template.js b/plugins/template/trumbowyg.template.js
index b23f111da..5e92e2d87 100644
--- a/plugins/template/trumbowyg.template.js
+++ b/plugins/template/trumbowyg.template.js
@@ -17,6 +17,9 @@
             fr: {
                 template: 'Patron'
             },
+            hu: {
+                template: 'Sablon'
+            },
             ja: {
                 template: 'テンプレート'
             },
diff --git a/plugins/upload/trumbowyg.upload.js b/plugins/upload/trumbowyg.upload.js
index 54f75090e..d63fd8883 100644
--- a/plugins/upload/trumbowyg.upload.js
+++ b/plugins/upload/trumbowyg.upload.js
@@ -21,7 +21,7 @@
         headers: {},                    // Additional headers
         xhrFields: {},                  // Additional fields
         urlPropertyName: 'file',        // How to get url from the json response (for instance 'url' for {url: ....})
-        statusPropertyName: 'success',  // How to get status from the json response 
+        statusPropertyName: 'success',  // How to get status from the json response
         success: undefined,             // Success callback: function (data, trumbowyg, $modal, values) {}
         error: undefined,               // Error callback: function () {}
         imageWidthModalEdit: false      // Add ability to edit image width
@@ -53,6 +53,11 @@
                 file: 'File',
                 uploadError: 'Error'
             },
+            cs: {
+                upload: 'Nahrát obrázek',
+                file: 'Soubor',
+                uploadError: 'Chyba'
+            },
             da: {
                 upload: 'Upload',
                 file: 'Fil',
@@ -63,55 +68,55 @@
                 file: 'Datei',
                 uploadError: 'Fehler'
             },
-            sk: {
-                upload: 'Nahrať',
-                file: 'Súbor',
-                uploadError: 'Chyba'
-            },
             fr: {
                 upload: 'Envoi',
                 file: 'Fichier',
                 uploadError: 'Erreur'
             },
-            cs: {
-                upload: 'Nahrát obrázek',
-                file: 'Soubor',
-                uploadError: 'Chyba'
-            },
-            zh_cn: {
-                upload: '上传',
-                file: '文件',
-                uploadError: '错误'
-            },
-            zh_tw: {
-                upload: '上傳',
-                file: '文件',
-                uploadError: '錯誤'
-            },
-            ru: {
-                upload: 'Загрузка',
-                file: 'Файл',
-                uploadError: 'Ошибка'
+            hu: {
+                upload: 'Feltöltés',
+                file: 'Fájl',
+                uploadError: 'Hiba'
             },
             ja: {
                 upload: 'アップロード',
                 file: 'ファイル',
                 uploadError: 'エラー'
             },
+            ko: {
+                upload: '그림 올리기',
+                file: '파일',
+                uploadError: '에러'
+            },
             pt_br: {
                 upload: 'Enviar do local',
                 file: 'Arquivo',
                 uploadError: 'Erro'
             },
+            ru: {
+                upload: 'Загрузка',
+                file: 'Файл',
+                uploadError: 'Ошибка'
+            },
+            sk: {
+                upload: 'Nahrať',
+                file: 'Súbor',
+                uploadError: 'Chyba'
+            },
             tr: {
                 upload: 'Yükle',
                 file: 'Dosya',
                 uploadError: 'Hata'
             },
-            ko: {
-                upload: '그림 올리기',
-                file: '파일',
-                uploadError: '에러'
+            zh_cn: {
+                upload: '上传',
+                file: '文件',
+                uploadError: '错误'
+            },
+            zh_tw: {
+                upload: '上傳',
+                file: '文件',
+                uploadError: '錯誤'
             },
         },
         // jshint camelcase:true
@@ -147,6 +152,9 @@
                                 };
                             }
 
+                            // Prevent multiple submissions while uploading
+                            var isUploading = false;
+
                             var $modal = trumbowyg.openModalInsert(
                                 // Title
                                 trumbowyg.lang.upload,
@@ -156,6 +164,11 @@
 
                                 // Callback
                                 function (values) {
+                                    if (isUploading) {
+                                        return;
+                                    }
+                                    isUploading = true;
+
                                     var data = new FormData();
                                     data.append(trumbowyg.o.plugins.upload.fileFieldName, file);
 
@@ -206,7 +219,7 @@
                                                     trumbowyg.execCmd('insertImage', url, false, true);
                                                     var $img = $('img[src="' + url + '"]:not([alt])', trumbowyg.$box);
                                                     $img.attr('alt', values.alt);
-                                                    if (trumbowyg.o.imageWidthModalEdit && parseInt(values.width) > 0) {
+                                                    if (trumbowyg.o.plugins.upload.imageWidthModalEdit && parseInt(values.width) > 0) {
                                                         $img.attr({
                                                             width: values.width
                                                         });
@@ -223,6 +236,8 @@
                                                     trumbowyg.$c.trigger('tbwuploaderror', [trumbowyg, data]);
                                                 }
                                             }
+
+                                            isUploading = false;
                                         },
 
                                         error: trumbowyg.o.plugins.upload.error || function () {
@@ -231,6 +246,8 @@
                                                 trumbowyg.lang.uploadError
                                             );
                                             trumbowyg.$c.trigger('tbwuploaderror', [trumbowyg]);
+
+                                            isUploading = false;
                                         }
                                     });
                                 }
diff --git a/sponsors/bookingninja.png b/sponsors/bookingninja.png
deleted file mode 100644
index 9cf0f87b3..000000000
Binary files a/sponsors/bookingninja.png and /dev/null differ
diff --git a/src/langs/ko.js b/src/langs/ko.js
index 2047b38bf..4fc0282fd 100644
--- a/src/langs/ko.js
+++ b/src/langs/ko.js
@@ -5,6 +5,8 @@
  * ===========================================================
  * Author : SeungWoo Chae (SDuck4)
  *          Github : https://github.com/SDuck4
+ *          Victor Chanil Park (opdev1004)
+ *          Github : https://github.com/opdev1004
  */
 
 jQuery.trumbowyg.langs.ko = {
@@ -34,7 +36,8 @@ jQuery.trumbowyg.langs.ko = {
     unorderedList: '기호 목록',
     orderedList: '번호 목록',
 
-    insertImage: '그림 넣기',
+    insertImage: '이미지 넣기',
+    insertVideo: '비디오 넣기',
     link: '링크',
     createLink: '링크 넣기',
     unlink: '링크 지우기',
diff --git a/src/langs/tr.js b/src/langs/tr.js
index 0a16604d9..0aef137ff 100644
--- a/src/langs/tr.js
+++ b/src/langs/tr.js
@@ -5,6 +5,9 @@
  * ===========================================================
  * Author : Emrah Bilbay (munzur)
  *          Github : https://github.com/munzur
+ *
+ *          Özgür Görgülü (ozgurg)
+ *          Github : https://github.com/ozgurg
  */
 
 jQuery.trumbowyg.langs.tr = {
@@ -51,5 +54,8 @@ jQuery.trumbowyg.langs.tr = {
     required: 'Gerekli',
     description: 'Açıklama',
     title: 'Başlık',
-    text: 'Metin'
+    text: 'Metin',
+    
+    undo: 'Geri al',
+    redo: 'İleri al'
 };
diff --git a/src/trumbowyg.js b/src/trumbowyg.js
index 5464a3c73..0f806edc4 100644
--- a/src/trumbowyg.js
+++ b/src/trumbowyg.js
@@ -61,6 +61,7 @@ jQuery.trumbowyg = {
 
     // SVG Path globally
     svgPath: null,
+    svgAbsoluteUseHref: false,
 
     hideButtonTexts: null
 };
@@ -77,7 +78,14 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
         imageWidthModalEdit: false,
 
         prefix: 'trumbowyg-',
-
+        // classes for inputs
+        tagClasses:{
+            h1: null,
+            h2: null,
+            h3: null,
+            h4: null,
+            p: null,
+        },
         semantic: true,
         semanticKeepAttributes: false,
         resetCss: false,
@@ -217,42 +225,48 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
         // SVG path
         var svgPathOption = $trumbowyg.svgPath != null ? $trumbowyg.svgPath : options.svgPath;
         t.hasSvg = svgPathOption !== false;
-        t.svgPath = !!t.doc.querySelector('base') ? window.location.href.split('#')[0] : '';
-        if ($('#' + trumbowygIconsId, t.doc).length === 0 && svgPathOption !== false) {
+
+        if (svgPathOption !== false && ($trumbowyg.svgAbsoluteUseHref || $('#' + trumbowygIconsId, t.doc).length === 0)) {
             if (svgPathOption == null) {
                 // Hack to get svgPathOption based on trumbowyg.js path
-                var scriptElements = document.getElementsByTagName('script');
-                for (var i = 0; i < scriptElements.length; i += 1) {
-                    var source = scriptElements[i].src;
+                var $scriptElements = $('script[src]');
+                $scriptElements.each(function (i, scriptElement) {
+                    var source = scriptElement.src;
                     var matches = source.match('trumbowyg(\.min)?\.js');
                     if (matches != null) {
                         svgPathOption = source.substring(0, source.indexOf(matches[0])) + 'ui/icons.svg';
                     }
-                }
-                if (svgPathOption == null) {
-                    console.warn('You must define svgPath: https://goo.gl/CfTY9U'); // jshint ignore:line
-                }
+                })
             }
 
-            var div = t.doc.createElement('div');
-            div.id = trumbowygIconsId;
-            t.doc.body.insertBefore(div, t.doc.body.childNodes[0]);
-            $.ajax({
-                async: true,
-                type: 'GET',
-                contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
-                dataType: 'xml',
-                crossDomain: true,
-                url: svgPathOption,
-                data: null,
-                beforeSend: null,
-                complete: null,
-                success: function (data) {
-                    div.innerHTML = new XMLSerializer().serializeToString(data.documentElement);
-                }
-            });
+            // Do not merge with previous if block: svgPathOption can be redefined in it.
+            // Here we are checking that we find a match
+            if (svgPathOption == null) {
+                console.warn('You must define svgPath: https://goo.gl/CfTY9U'); // jshint ignore:line
+            } else if (!$trumbowyg.svgAbsoluteUseHref) {
+                var div = t.doc.createElement('div');
+                div.id = trumbowygIconsId;
+                t.doc.body.insertBefore(div, t.doc.body.childNodes[0]);
+                $.ajax({
+                    async: true,
+                    type: 'GET',
+                    contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
+                    dataType: 'xml',
+                    crossDomain: true,
+                    url: svgPathOption,
+                    data: null,
+                    beforeSend: null,
+                    complete: null,
+                    success: function (data) {
+                        div.innerHTML = new XMLSerializer().serializeToString(data.documentElement);
+                    }
+                });
+            }
         }
 
+        var baseHref = !!t.doc.querySelector('base') ? window.location.href.split(/[?#]/)[0] : '';
+        t.svgPath = $trumbowyg.svgAbsoluteUseHref ? svgPathOption : baseHref;
+
 
         /**
          * When the button is associated to a empty object
@@ -407,7 +421,7 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
             }
         };
 
-        // Defaults Options
+        // Default Options
         t.o = $.extend(true, {}, $trumbowyg.defaultOptions, options);
         if (!t.o.hasOwnProperty('imgDblClickHandler')) {
             t.o.imgDblClickHandler = t.getDefaultImgDblClickHandler();
@@ -496,7 +510,7 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
                 return;
             }
 
-            if (typeof(protocol) !== 'string') {
+            if (typeof (protocol) !== 'string') {
                 return 'https://';
             }
             return protocol.replace('://', '') + '://';
@@ -584,6 +598,11 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
             t.$ed
                 .on('dblclick', 'img', t.o.imgDblClickHandler)
                 .on('keydown', function (e) {
+                    // append flags to differentiate Chrome spans
+                    var keyCode = e.which;
+                    if (keyCode === 8 || keyCode === 13 || keyCode === 46) {
+                        t.toggleSpan(true);
+                    }
                     if ((e.ctrlKey || e.metaKey) && !e.altKey) {
                         ctrl = true;
                         var key = t.keys[String.fromCharCode(e.which).toUpperCase()];
@@ -591,7 +610,8 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
                         try {
                             t.execCmd(key.fn, key.param);
                             return false;
-                        } catch (c) {}
+                        } catch (c) {
+                        }
                     } else {
                         if (t.o.tabToIndent && e.key === 'Tab') {
                             try {
@@ -601,7 +621,8 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
                                     t.execCmd('indent', true, null);
                                 }
                                 return false;
-                            } catch (c) {}
+                            } catch (c) {
+                            }
                         }
                     }
                 })
@@ -621,6 +642,11 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
                         return;
                     }
 
+                    // remove Chrome generated span tags
+                    if (keyCode === 8 || keyCode === 13 || keyCode === 46) {
+                        t.toggleSpan();
+                    }
+
                     if ((e.ctrlKey || e.metaKey) && (keyCode === 89 || keyCode === 90)) {
                         t.semanticCode(false, true);
                         t.$c.trigger('tbwchange');
@@ -659,15 +685,14 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', {
                         if (e.type === 'focus') {
                             t.autogrowOnEnterWasFocused = true;
                             t.autogrowEditorOnEnter();
-                        }
-                        else if (!t.o.autogrow) {
+                        } else if (!t.o.autogrow) {
                             t.$ed.css({height: t.$ed.css('min-height')});
                             t.$c.trigger('tbwresize');
                         }
                     }
                 })
                 .on('keyup focus', function () {
-                    if (!t.$ta.val().match(/<.*>/)) {
+                  if (!t.$ta.val().match(/<.*>/) && !t.$ed.html().match(/<.*>/)) {
                         setTimeout(function () {
                             var block = t.isIE ? '

' : 'p'; t.doc.execCommand('formatBlock', false, block); @@ -872,8 +897,8 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { type: 'button', class: prefix + btnName + '-dropdown-button ' + (btn.class || '') + (btn.ico ? ' ' + prefix + btn.ico + '-button' : ''), html: t.hasSvg && hasIcon ? - '' + (btn.text || btn.title || t.lang[btnName] || btnName) : - (btn.text || btn.title || t.lang[btnName] || btnName), + '' + (btn.text || btn.title || t.lang[btnName] || btnName) : + (btn.text || btn.title || t.lang[btnName] || btnName), title: (btn.key ? '(' + (t.isMac ? 'Cmd' : 'Ctrl') + ' + ' + btn.key + ')' : null), style: btn.style || null, mousedown: function () { @@ -1061,6 +1086,22 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { }, 0); }, + // Remove or add flags to span tags to remove Chrome generated spans + toggleSpan: function (addFlag) { + var t = this; + t.$ed.find('span').each(function () { + if (addFlag === true) { + $(this).attr('data-tbw-flag', true); + } else { + if ($(this).attr('data-tbw-flag')) { + $(this).removeAttr('data-tbw-flag'); + } else { + $(this).contents().unwrap(); + } + } + }); + }, + // Open dropdown when click on a button which open that dropdown: function (name) { var t = this, @@ -1151,6 +1192,11 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { t.saveRange(); t.syncCode(force); + var restoreRange = true; + if (t.range && t.range.collapsed) { + restoreRange = false; + } + if (t.o.semantic) { t.semanticTag('b', t.o.semanticKeepAttributes); t.semanticTag('i', t.o.semanticKeepAttributes); @@ -1186,7 +1232,7 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { t.$ed.find('p:empty').remove(); } - if (!keepRange) { + if (!keepRange && restoreRange) { t.restoreRange(); } @@ -1194,8 +1240,9 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { } }, - semanticTag: function (oldTag, copyAttributes) { - var newTag; + semanticTag: function (oldTag, copyAttributes, revert) { + var newTag, t = this; + var tmpTag = oldTag; if (this.o.semantic != null && typeof this.o.semantic === 'object' && this.o.semantic.hasOwnProperty(oldTag)) { newTag = this.o.semantic[oldTag]; @@ -1205,19 +1252,34 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { return; } + if(revert) { + oldTag = newTag; + newTag = tmpTag; + } + $(oldTag, this.$ed).each(function () { + var resetRange = false; var $oldTag = $(this); - if($oldTag.contents().length === 0) { + if ($oldTag.contents().length === 0) { return false; } - $oldTag.wrap('<' + newTag + '/>'); + if(t.range.startContainer.parentNode && t.range.startContainer.parentNode === this) { + resetRange = true; + } + var $newTag = $('<' + newTag + '/>'); + $newTag.insertBefore($oldTag); if (copyAttributes) { $.each($oldTag.prop('attributes'), function () { - $oldTag.parent().attr(this.name, this.value); + $newTag.attr(this.name, this.value); }); } - $oldTag.contents().unwrap(); + $newTag.html($oldTag.html()); + $oldTag.remove(); + if(resetRange === true) { + t.range.selectNodeContents($newTag.get(0)); + t.range.collapse(false); + } }); }, @@ -1254,7 +1316,7 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { var options = { url: { - label: 'URL', + label: t.lang.linkUrl || 'URL', required: true, value: url }, @@ -1412,6 +1474,10 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { t.$ed.focus(); } + if(cmd === 'strikethrough' && t.o.semantic) { + t.semanticTag('strike', t.o.semanticKeepAttributes, true); // browsers cannot undo e.g. as they expect + } + try { t.doc.execCommand('styleWithCSS', false, forceCss || false); } catch (c) { @@ -1433,6 +1499,21 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { t.syncCode(); t.semanticCode(false, true); + try { + var listId = window.getSelection().focusNode; + if(!$(window.getSelection().focusNode.parentNode).hasClass('trumbowyg-editor')){ + listId = window.getSelection().focusNode.parentNode; + } + var arr = t.o.tagClasses[param]; + if (arr) { + for (var i = 0; i < arr.length; i+=1) { + $(listId).addClass(arr[i]); + } + } + } catch (e) { + + } + } if (cmd !== 'dropdown') { @@ -1485,19 +1566,19 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { action: '', html: content }) - .on('submit', function () { - $modal.trigger(CONFIRM_EVENT); - return false; - }) - .on('reset', function () { - $modal.trigger(CANCEL_EVENT); - return false; - }) - .on('submit reset', function () { - if (t.o.autogrowOnEnter) { - t.autogrowOnEnterDontClose = false; - } - }); + .on('submit', function () { + $modal.trigger(CONFIRM_EVENT); + return false; + }) + .on('reset', function () { + $modal.trigger(CANCEL_EVENT); + return false; + }) + .on('submit reset', function () { + if (t.o.autogrowOnEnter) { + t.autogrowOnEnterDontClose = false; + } + }); } else { formOrContent = content; } @@ -1809,9 +1890,9 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { clearButtonPaneStatus: function () { var t = this, - prefix = t.o.prefix, - activeClasses = prefix + 'active-button ' + prefix + 'active', - originalIconClass = prefix + 'original-icon'; + prefix = t.o.prefix, + activeClasses = prefix + 'active-button ' + prefix + 'active', + originalIconClass = prefix + 'original-icon'; // Reset all buttons and dropdown state $('.' + prefix + 'active-button', t.$btnPane).removeClass(activeClasses); @@ -1849,12 +1930,12 @@ Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { if (t.o.changeActiveDropdownIcon && $btnSvgUse.length > 0) { // Save original icon $dropdownBtn - .addClass(originalIconClass) - .data(originalIconClass, $dropdownBtnSvgUse.attr('xlink:href')); + .addClass(originalIconClass) + .data(originalIconClass, $dropdownBtnSvgUse.attr('xlink:href')); // Put the active sub-button's icon $dropdownBtnSvgUse - .attr('xlink:href', $btnSvgUse.attr('xlink:href')); + .attr('xlink:href', $btnSvgUse.attr('xlink:href')); } } catch (e) { } diff --git a/src/ui/sass/trumbowyg.scss b/src/ui/sass/trumbowyg.scss index 7b205cfd6..3d79ca829 100644 --- a/src/ui/sass/trumbowyg.scss +++ b/src/ui/sass/trumbowyg.scss @@ -41,7 +41,6 @@ $slow-transition-duration: 300ms !default; border: 1px solid #DDD; width: 100%; min-height: 300px; - margin: 17px auto; } .trumbowyg-box .trumbowyg-editor { @@ -132,6 +131,7 @@ $slow-transition-duration: 300ms !default; content: attr(placeholder); color: #999; pointer-events: none; + white-space: break-spaces; } .trumbowyg-button-pane {