/* =========================================================== * trumbowyg.js v1.0 * Core code of Trumbowyg plugin * http://alex-d.github.com/Trumbowyg * =========================================================== * Author : Alexandre Demode (Alex-D) * Twitter : @AlexandreDemode * Website : alex-d.fr */ $.trumbowyg = { langs: { en: { viewHTML: "Voir le HTML", formatting: "Format", p: "Paragraphe", blockquote: "Citation", code: "Code", header: "Titre", bold: "Gras", italic: "Italique", strikethrough: "Rayé", underline: "Souligné", strong: "Fort", em: "Emphase", del: "Supprimé", unorderedList: "Liste à puces", orderedList: "Liste ordonnée", insertImage: "Insérer une image", insertVideo: "Insérer une video", link: "Lien", createLink: "Insérer un lien", unlink: "Supprimer le lien", justifyLeft: "Aligner à gauche", justifyCenter: "Centrer", justifyRight: "Aligner à droite", justifyFull: "Justifier", horizontalRule: "Insérer un séparateur horizontal", fullscreen: "Plein écran", close: "Fermer", submit: "Valider", reset: "Annuler", invalidUrl: "URL invalide", required: "Obligatoire", description: "Description", title: "Title", text: "Text" } }, // User default options opts: {}, btnsGrps: { design: ['bold', 'italic', 'underline', 'strikethrough', 'upload'], semantic: ['strong', 'em', 'del'], justify: ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'], lists: ['unorderedList', 'orderedList'] } }; (function($){ $.fn.trumbowyg = function(opts, params){ if($.isObject(opts) || opts == null){ return this.each(function(){ if(!$(this).data('trumbowyg')) $(this).data('trumbowyg', new Trumbowyg(this, opts)); }); } else if(this.length == 1){ try { var t = $(this).data('trumbowyg'); switch(opts){ // Modal box case 'openModal': return t.openModal(params.title, params.content); case 'closeModal': return t.closeModal(); case 'openModalInsert': return t.openModalInsert(params.title, params.fields, params.callback); // Selection case 'saveSelection': return t.saveSelection(); case 'getSelection': return t.selection; case 'getSelectedText': return t.selection+''; case 'restoreSelection': return t.restoreSelection(); // Destroy case 'destroy': return t.destroy(); // Empty case 'empty': return t.empty(); // Public options case 'lang': return t.lang; case 'duration': return t.o.duration; // HTML case 'html': return t.html(params); } } catch(e){} } return false; }; var Trumbowyg = function(editorElem, opts){ // jQuery object of the editor this.$e = $(editorElem); this.$creator = $(editorElem); // Extend with options opts = $.extend(true, {}, opts, $.trumbowyg.opts); // Localization management if(typeof opts.lang === 'undefined' || typeof $.trumbowyg.langs[opts.lang] === 'undefined') this.lang = $.trumbowyg.langs['en']; else this.lang = $.extend(true, {}, $.trumbowyg.langs['en'], $.trumbowyg.langs[opts.lang]); // Defaults Options this.o = $.extend(true, { lang: 'en', dir: 'ltr', duration: 200, // Duration of modal box animations mobile: false, tablet: true, closable: false, fullscreenable: true, fixedBtnPane: false, fixedFullWidth: false, semantic: false, resetCss: false, autogrow: false, prefix: 'trumbowyg-', convertLink: true, btns: [//'viewHTML', //'|', 'formatting', '|', $.trumbowyg.btnsGrps.design, '|', 'link', '|', $.trumbowyg.btnsGrps.justify, '|', $.trumbowyg.btnsGrps.lists, '|', 'horizontalRule'], btnsAdd: [], /** * When the button is associated to a empty object * func and title attributs are defined from the button key value * * For example * foo: {} * is equivalent to : * foo: { * func: 'foo', * title: this.lang.foo * } */ btnsDef: { viewHTML: { func: 'toggle' }, p: { func: 'formatBlock' }, blockquote: { func: 'formatBlock' }, h1: { func: 'formatBlock', title: this.lang.header + ' 1' }, h2: { func: 'formatBlock', title: this.lang.header + ' 2' }, h3: { func: 'formatBlock', title: this.lang.header + ' 3' }, h4: { func: 'formatBlock', title: this.lang.header + ' 4' }, bold: {}, italic: {}, underline: {}, strikethrough: {}, strong: { func: 'bold' }, em: { func: 'italic' }, del: { func: 'strikethrough' }, createLink: {}, unlink: {}, insertImage: {}, justifyLeft: {}, justifyCenter: {}, justifyRight: {}, justifyFull: {}, unorderedList: { func: 'insertUnorderedList' }, orderedList: { func: 'insertOrderedList' }, horizontalRule: { func: 'insertHorizontalRule' }, // Dropdowns formatting: { dropdown: ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4'] }, link: { dropdown: ['createLink', 'unlink'] } } }, opts); if(this.o.semantic && !opts.btns) this.o.btns = [ 'viewHTML', '|', 'formatting', '|', $.trumbowyg.btnsGrps.semantic, '|', 'link', '|', 'insertImage', '|', $.trumbowyg.btnsGrps.justify, '|', $.trumbowyg.btnsGrps.lists, '|', 'horizontalRule' ]; else if(opts && opts.btns) this.o.btns = opts.btns; this.init(); } Trumbowyg.prototype = { init: function(){ this.height = this.$e.css('height'); if(this.isEnabled()){ this.buildEditor(true); return; } this.buildEditor(); this.buildBtnPane(); this.fixedBtnPaneEvents(); this.buildOverlay(); }, buildEditor: function(disable){ if(disable === true){ if(!this.$e.is('textarea')){ var textarea = this.buildTextarea().val(this.$e.val()); this.$e.hide().after(textarea); } return; } this.$box = $('
', { 'class': this.o.prefix + 'box ' + this.o.prefix + this.o.lang + ' trumbowyg' }); this.isTextarea = true; if(this.$e.is('textarea')) this.$editor = $('
'); else { this.$editor = this.$e; this.$e = this.buildTextarea().val(this.$e.val()); this.isTextarea = false; } this.$e.hide() .addClass(this.o.prefix + 'textarea'); var html = ''; if(this.isTextarea){ html = this.$e.val(); this.$box.insertAfter(this.$e) .append(this.$editor) .append(this.$e); } else { html = this.$editor.html(); this.$box.insertAfter(this.$editor) .append(this.$e) .append(this.$editor); this.syncCode(); } this.$editor.addClass(this.o.prefix + 'editor') .attr('contenteditable', true) .attr('dir', this.o.dir) .html(html); if(this.o.resetCss) this.$editor.addClass(this.o.prefix + 'reset-css'); if(!this.o.autogrow){ $.each([this.$editor, this.$e], $.proxy(function(i, $el){ $el.css({ height: this.height, overflow: 'auto' }); }, this)); } if(this.o.semantic){ this.$editor.html( this.$editor.html() .replace("
", "

") .replace("&nsbp;", "") ); this.semanticCode(); } var that = this; this.$editor .on('dblclick', 'img', function(){ var $img = $(this); that.openModalInsert(that.lang.insertImage, { url: { label: 'URL', value: $img.attr('src'), required: true }, alt: { label: 'description', value: $img.attr('alt') } }, function(values){ $img.attr('src', values['url']); $img.attr('alt', values['alt']); }); return false; }) .on('keyup', function(e){ that.semanticCode(false, e.which === 13); }) .on('blur', function(){ that.syncCode(); }); }, // Build the Textarea which contain HTML generated code buildTextarea: function(){ return $('