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:
-- - - -
-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: - - - -
@@ -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 @@
- 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 @@', + '', '', ].join(''); @@ -36,14 +36,20 @@ '' + Prism.highlight(text, Prism.languages[language]) + '
', '', ' ', '', + '', + ' ', + '' ].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 {