123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230 |
- /* ===========================================================
- * 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 = $('<div/>', {
- 'class': this.o.prefix + 'box ' + this.o.prefix + this.o.lang + ' trumbowyg'
- });
- this.isTextarea = true;
- if(this.$e.is('textarea'))
- this.$editor = $('<div/>');
- 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("<br>", "</p><p>")
- .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 $('<textarea/>', {
- 'name': this.$e.attr('id'),
- 'height': this.height
- });
- },
- // Build button pane, use o.btns and o.btnsAdd options
- buildBtnPane: function(){
- var t = this;
- if(t.o.btns === false) return;
- var pfx = t.o.prefix;
- t.$btnPane = $('<ul/>', {
- 'class': pfx + 'button-pane'
- });
- $.each(t.o.btns.concat(t.o.btnsAdd), $.proxy(function(i, btn){
- // Managment of group of buttons
- try {
- var b = btn.split('btnGrp-');
- if(b[1] != undefined)
- btn = $.trumbowyg.btnsGrps[b[1]];
- } catch(e){}
- if(!$.isArray(btn)) btn = [btn];
- $.each(btn, $.proxy(function(i, btn){
- try { // Prevent buildBtn error
- var $li = $('<li/>');
- if(btn === '|') // It's a separator
- $li.addClass(pfx + 'separator');
- else if(t.isSupportedBtn(btn)){ // It's a supported button
- if(btn === 'viewHTML')
- $li.addClass(pfx + 'not-disable');
- $li.append(t.buildBtn(btn));
- }
- t.$btnPane.append($li);
- } catch(e){}
- }, t));
- }, t));
- // Build right li for fullscreen and close buttons
- var $liRight = $('<li/>', {
- 'class': pfx + 'not-disable ' + pfx + 'buttons-right'
- });
- // Add the fullscreen button
- if(t.o.fullscreenable)
- $liRight
- .append(t.buildRightBtn('fullscreen')
- .on('click', $.proxy(function(e){
- var cssClass = pfx + 'fullscreen';
- t.$box.toggleClass(cssClass);
- if(t.$box.hasClass(cssClass)){
- $('body').css('overflow', 'hidden');
- t.$box.css({
- position: 'fixed',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- margin: 0,
- padding: 0,
- zIndex: 99999
- });
- $([t.$editor, t.$e]).each(function(){
- $(this).css({
- height: '100%',
- overflow: 'auto'
- });
- });
- t.$btnPane.css('width', '100%');
- } else {
- $('body').css('overflow', 'auto');
- t.$box.removeAttr('style');
- if(!t.o.autogrow){
- h = t.height;
- $([t.$editor, t.$e]).each(function(i, $el){
- $el.css('height', h);
- });
- }
- }
- $(window).trigger('scroll');
- }, t)));
- // Build and add close button
- if(t.o.closable)
- $liRight
- .append(t.buildRightBtn('close')
- .on('click', $.proxy(function(e){
- var cssClass = pfx + 'fullscreen';
- if(t.$box.hasClass(cssClass))
- $('body').css('overflow', 'auto');
- t.destroy();
- }, t)));
- // Add right li only if isn't empty
- if($liRight.not(':empty'))
- t.$btnPane.append($liRight);
- t.$box.prepend(t.$btnPane);
- },
- // Build a button and his action
- buildBtn: function(name){
- var pfx = this.o.prefix,
- btnDef = this.o.btnsDef[name],
- t = this,
- textDef = this.lang[name] || name.charAt(0).toUpperCase() + name.slice(1);
- var $btn = $('<button/>', {
- 'type': 'button',
- 'class': pfx + name +'-button' + (btnDef.ico ? ' '+ pfx + btnDef.ico +'-button' : ''),
- 'text': btnDef.text || btnDef.title || textDef,
- 'title': btnDef.title || btnDef.text || textDef,
- 'mousedown': function(e){
- if(!btnDef.dropdown || t.$box.find('.'+name+'-'+pfx + 'dropdown').is(':hidden'))
- $('body').trigger('mousedown');
- if(t.$btnPane.hasClass(pfx + 'disable')
- && !$(this).parent().hasClass(pfx + 'not-disable'))
- return false;
- t.execCommand((btnDef.dropdown ? 'dropdown' : false) || btnDef.func || name,
- btnDef.param || name);
- e.stopPropagation();
- e.preventDefault();
- return false;
- }
- });
- if(btnDef.dropdown){
- $btn.addClass(pfx + 'open-dropdown');
- var cssClass = pfx + 'dropdown';
- var dropdown = $('<div/>', {
- 'class': name + '-' + cssClass + ' ' + cssClass + ' ' + pfx + 'fixed-top'
- });
- for(var i = 0, c = btnDef.dropdown.length; i < c; i++){
- if(t.o.btnsDef[btnDef.dropdown[i]] && t.isSupportedBtn(btnDef.dropdown[i]))
- dropdown.append(t.buildSubBtn(btnDef.dropdown[i]));
- }
- this.$box.append(dropdown.hide());
- }
- return $btn;
- },
- // Build a button for dropdown menu
- buildSubBtn: function(name){
- var btnDef = this.o.btnsDef[name];
- return $('<button/>', {
- 'type': 'button',
- 'text': btnDef.text || btnDef.title || this.lang[name] || name,
- 'mousedown': $.proxy(function(e){
- $('body').trigger('mousedown');
- this.execCommand(btnDef.func || name,
- btnDef.param || name);
- e.stopPropagation();
- e.preventDefault();
- return false;
- }, this)
- });
- },
- // Build a button for right li
- buildRightBtn: function(name){
- return $('<button/>', {
- 'type': 'button',
- 'class': this.o.prefix + name+'-button',
- 'title': this.lang[name],
- 'text': this.lang[name]
- });
- },
- // Check if button is supported
- isSupportedBtn: function(btn){
- return typeof this.o.btnsDef[btn].isSupported !== 'function' || this.o.btnsDef[btn].isSupported()
- },
- // Build overlay for modal box
- buildOverlay: function(){
- return this.$overlay = $('<div/>', {
- 'class': this.o.prefix + 'overlay'
- }).css({
- top: this.$btnPane.outerHeight(),
- height: (parseInt(this.$editor.outerHeight()) + 1) + 'px'
- }).appendTo(this.$box);
- },
- showOverlay: function(){
- $(window).trigger('scroll');
- this.$overlay.fadeIn(this.o.duration);
- this.$box.addClass(this.o.prefix + 'box-blur');
- },
- hideOverlay: function(){
- this.$overlay.fadeOut(this.o.duration/4);
- this.$box.removeClass(this.o.prefix + 'box-blur');
- },
- // Management of fixed button pane
- fixedBtnPaneEvents: function(){
- if(!this.o.fixedBtnPane)
- return;
- this.isFixed = false;
- $(window).on('scroll', $.proxy(function(e){
- if(!this.$box)
- return;
- this.syncCode();
- var wScroll = $(window).scrollTop(),
- offset = this.$box.offset().top + 1,
- toFixed = (wScroll - offset > 0) && ((wScroll - offset - parseInt(this.height)) < 0);
- if(toFixed){
- if(!this.isFixed){
- this.isFixed = true;
- this.$btnPane.css({
- position: 'fixed',
- top: 0,
- left: (this.o.fixedFullWidth) ? '0' : 'auto',
- width: (this.o.fixedFullWidth) ? '100%' : ((parseInt(this.$box.css('width'))-1) + 'px'),
- zIndex: 7
- });
- this.$editor.css({ marginTop: this.$btnPane.css('height') });
- this.$e.css({ marginTop: this.$btnPane.css('height') });
- }
- $('.' + this.o.prefix + 'fixed-top', this.$box).css({
- position: this.o.fixedFullWidth ? 'fixed' : 'absolute',
- top: this.o.fixedFullWidth ? this.$btnPane.outerHeight() : parseInt(this.$btnPane.outerHeight()) + (wScroll - offset) + 'px',
- zIndex: 15
- });
- } else if(this.isFixed) {
- this.isFixed = false;
- this.$btnPane.css({ position: 'relative' });
- this.$editor.css({ marginTop: 0 });
- this.$e.css({ marginTop: 0 });
- $('.' + this.o.prefix + 'fixed-top', this.$box).css({
- position: 'absolute',
- top: this.$btnPane.outerHeight()
- });
- }
- }, this));
- },
- // Destroy the editor
- destroy: function(){
- var html = this.html();
- if(this.isTextarea)
- this.$box.after(this.$e.css({height: this.height})
- .val(html)
- .removeClass(this.o.prefix + 'textarea')
- .show());
- else
- this.$box.after(this.$editor.css({height: this.height})
- .removeClass(this.o.prefix + 'editor')
- .attr('contenteditable', false)
- .html(html)
- .show());
- this.$box.remove();
- this.$creator.removeData('trumbowyg');
- },
- // Empty the editor
- empty: function(){
- this.$e.val('');
- this.syncCode(true);
- },
- // Function call when click on viewHTML button
- toggle: function(){
- this.semanticCode(false, true);
- this.$editor.toggle();
- this.$e.toggle();
- this.$btnPane.toggleClass(this.o.prefix + 'disable');
- this.$btnPane.find('.'+this.o.prefix + 'viewHTML-button').toggleClass(this.o.prefix + 'active');
- },
- // Open dropdown when click on a button which open that
- dropdown: function(name){
- var pfx = this.o.prefix;
- var $dropdown = this.$box.find('.'+name+'-'+pfx + 'dropdown'),
- $btn = this.$btnPane.find('.'+pfx+name+'-button');
- if($dropdown.is(':hidden')){
- $btn.addClass(this.o.prefix + 'active');
- $dropdown.css({
- position: 'absolute',
- top: this.$btnPane.outerHeight(),
- left: (this.o.fixedFullWidth && this.isFixed) ? $btn.offset().left+'px' : ($btn.offset().left - this.$btnPane.offset().left)+'px'
- }).show();
- $(window).trigger('scroll');
- $('body').on('mousedown', $.proxy(function(e){
- $('.' + pfx + 'dropdown').hide();
- $('.' + pfx + 'active').removeClass(pfx + 'active');
- $('body').off('mousedown');
- }, this));
- } else {
- $('body').trigger('mousedown');
- }
- },
- // HTML Code management
- html: function(html){
- if(html){
- this.$e.val(html);
- this.syncCode(true);
- return tbw;
- } else
- return this.$e.val();
- },
- syncCode: function(force){
- if(!force && this.$editor.is(':visible'))
- this.$e.val(this.$editor.html());
- else
- this.$editor.html(this.$e.val());
- if(this.o.autogrow){
- this.height = this.$editor.css('height');
- this.$e.css({ height: this.height });
- }
- },
- // Analyse and update to semantic code
- // @param force : force to sync code from textarea
- // @param full : wrap text nodes in <p>
- semanticCode: function(force, full){
- this.syncCode(force);
- if(this.o.semantic){
- this.semanticTag('b', 'strong');
- this.semanticTag('i', 'em');
- this.semanticTag('strike', 'del');
- if(full){
- // Wrap text nodes in p
- this.$editor.contents()
- .filter(function(){
- // Only non-empty text nodes
- return this.nodeType === 3 && $.trim(this.nodeValue).length > 0;
- }).wrap('<p></p>').end()
- // Remove all br
- .filter("br").remove();
- this.saveSelection();
- this.semanticTag('div', 'p');
- this.restoreSelection();
- }
- this.$e.val(this.$editor.html());
- }
- },
- semanticTag: function(oldTag, newTag){
- $(oldTag, this.$editor).each(function(){
- $(this).replaceWith(function(){ return '<'+newTag+'>' + $(this).html() + '</'+newTag+'>'; });
- });
- },
- // Function call when user click on « Insert Link »
- createLink: function(){
- var that = this;
- this.saveSelection();
- this.openModalInsert(this.lang.createLink, {
- url: {
- label: 'URL',
- value: 'http://',
- required: true
- },
- title: {
- label: this.lang.title,
- value: this.selection
- },
- text: {
- label: this.lang.text,
- value: this.selection
- }
- }, function(values){
- that.execCommand('createLink', values['url']);
- var link = $(['a[href="', values['url'], '"]:not([title])'].join(''), that.$box);
- if($.trim(values['text']).length !== 0)
- link.text(values['text']);
- if($.trim(values['title']).length !== 0)
- link.attr('title', values['title']);
- return true;
- });
- },
- insertImage: function(){
- var that = this;
- this.saveSelection();
- this.openModalInsert(this.lang.insertImage, {
- url: {
- label: 'URL',
- value: 'http://',
- required: true
- },
- alt: {
- label: 'description',
- value: this.selection
- }
- }, function(values){
- that.execCommand('insertImage', values['url']);
- $(['img[src="', values['url'], '"]:not([alt])'].join(''), that.$box).attr('alt', values['alt']);
- return true;
- });
- },
- /*
- * Call method of trumbowyg if exist
- * else try to call anonymous function
- * and finaly native execCommand
- */
- execCommand: function(cmd, param){
- if(cmd != 'dropdown')
- this.$editor.focus();
- try {
- this[cmd](param);
- } catch(e){
- try {
- cmd(param, this);
- } catch(e){
- this.$editor.focus();
- if(cmd == 'insertHorizontalRule')
- param = null;
- document.execCommand(cmd, false, param);
- }
- }
- this.syncCode();
- },
- formatBlock: function(param){
- if($.browser.msie)
- param = '<' + param + '>';
- document.execCommand('formatBlock', false, param);
- },
- // Open a modal box
- openModal: function(title, content){
- var pfx = this.o.prefix;
- // No open a modal box when exist other modal box
- if($('.' + pfx + 'modal-box', this.$box).size() > 0)
- return false;
- this.saveSelection();
- this.showOverlay();
- // Disable all btnPane btns
- this.$btnPane.addClass(pfx + 'disable');
- $('.' + pfx + 'not-disable', this.$btnPane)
- .not('.' + pfx + 'buttons-right')
- .removeClass(pfx + 'not-disable')
- .addClass(pfx + 'not-disable-old');
- // Build out of ModalBox, it's the mask for animations
- var $modal = $('<div/>', {
- 'class': pfx + 'modal ' + pfx + 'fixed-top'
- }).css({
- top: (parseInt(this.$btnPane.css('height')) + 1) + 'px'
- }).appendTo(this.$box);
- // Click on overflay close modal by cancelling them
- this.$overlay.one('click', function(e){
- e.preventDefault();
- $modal.trigger(pfx + 'cancel');
- });
- $e = this.$editor;
- // Build the form
- $form = $('<form/>', {
- action: 'javascript:void(null);',
- html: content
- })
- .on('submit', function(e){
- e.preventDefault();
- $modal.trigger(pfx + 'confirm');
- })
- .on('reset', function(e){
- e.preventDefault();
- $modal.trigger(pfx + 'cancel');
- });
- // Build ModalBox and animate to show them
- var $modalBox = $('<div/>', {
- 'class': pfx + 'modal-box',
- html: $form
- })
- .css({
- top: '-' + parseInt(this.$btnPane.outerHeight()) + 'px',
- opacity: 0
- })
- .appendTo($modal)
- .animate({
- top: 0,
- opacity: 1
- }, this.o.duration / 2);
- // Append title
- $('<span/>', {
- text: title,
- 'class': pfx + 'modal-title'
- }).prependTo($modalBox);
- // Focus in modal box
- $modalBox.find('input:first').focus();
- // Append Confirm and Cancel buttons
- this.buildModalBtn('submit', $modalBox);
- this.buildModalBtn('reset', $modalBox);
- $('body').trigger('scroll');
- return $modal;
- },
- buildModalBtn: function(name, modal){
- return $('<button/>', {
- 'class': this.o.prefix + 'modal-button ' + this.o.prefix + 'modal-' + name,
- 'type': name,
- 'text': this.lang[name] || name
- }).appendTo(modal.find('form'));
- },
- // close current modal box
- closeModal: function(){
- var pfx = this.o.prefix;
- this.$btnPane.removeClass(pfx + 'disable');
- this.$overlay.off();
- $('.' + this.o.prefix + 'not-disable-old', this.$btnPane)
- .removeClass(pfx + 'not-disable-old')
- .addClass(pfx + 'not-disable');
- var that = this,
- $modalBox = $('.' + pfx + 'modal-box', this.$box);
- $modalBox.animate({
- top: '-' + $modalBox.css('height')
- }, this.o.duration/2, function(){
- $(this).parent().remove();
- that.hideOverlay();
- });
- },
- // Preformated build and management modal
- openModalInsert: function(title, fields, cmd){
- var html = '',
- pfx = this.o.prefix;
- for(f in fields){
- var fd = fields[f];
- label = (fd.label == undefined)
- ? (this.lang[f] ? this.lang[f] : f.charAt(0).toUpperCase() + f.slice(1))
- : (this.lang[fd.label] ? this.lang[fd.label] : fd.label)
- ;
- if(fd.name == undefined)
- fd.name = f;
- if(!fd.pattern && f == 'url'){
- fd.pattern = /^(http|https):\/\/([\w~#!:.?+=&%@!\-\/]+)$/;
- fd.patternError = this.lang.invalidUrl;
- }
- html += '<label><input type="'+(fd.type || 'text')+'" name="'+fd.name+'" value="'+(fd.value || '')+'"><span class="'+pfx+'input-infos"><span>'+label+'</span></span></label>';
- }
- var modBox = this.openModal(title, html),
- that = this;
- modBox
- .on(pfx + 'confirm', function(){
- var $form = $(this).find('form'),
- valid = true,
- values = {};
- for(f in fields) {
- var $field = $('input[name="'+f+'"]', $form);
- values[f] = $field.val();
- // Validate value
- if(fields[f].required && (values[f] == null || values[f] == undefined || $.trim(values[f]) == "")) {
- valid = false;
- that.addErrorOnModalField($field, that.lang.required);
- } else if(fields[f].pattern && !fields[f].pattern.test(values[f])) {
- valid = false;
- that.addErrorOnModalField($field, fields[f].patternError);
- }
- }
- if(valid) {
- that.restoreSelection();
- if(cmd(values, fields)) {
- that.syncCode();
- that.closeModal();
- modBox.off(pfx + 'confirm');
- }
- }
- })
- .one(pfx + 'cancel', function(){
- modBox.off(pfx + 'confirm');
- that.closeModal();
- that.restoreSelection();
- });
- return modBox;
- },
- addErrorOnModalField: function($field, err){
- var $label = $field.parent(),
- pfx = this.o.prefix;
- $label.addClass(pfx + 'input-error');
- $field.on('change keyup', function(){ $label.removeClass(pfx + 'input-error'); });
- $label.find('input+span').append('<span class="'+ pfx +'msg-error">'+ err +'</span>');
- },
- // Selection management
- saveSelection: function(){
- this.selection = null;
- if(window.getSelection){
- var sel = window.getSelection();
- if(sel.getRangeAt && sel.rangeCount)
- this.selection = sel.getRangeAt(0);
- } else if(document.selection && document.selection.createRange){
- this.selection = document.selection.createRange();
- }
- },
- restoreSelection: function(){
- range = this.selection;
- if(range){
- if(window.getSelection){
- var sel = window.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);
- } else if(document.selection && range.select){
- range.select();
- }
- }
- },
- // Return true if must enable Trumbowyg on this mobile device
- isEnabled: function(){
- var mobile = "iPhone|iPod|Android|BlackBerry|Windows\sPhone|ZuneWP7";
- var exprTablet = new RegExp("(iPad|webOS)");
- var exprMobile = new RegExp("("+mobile+")");
- return (this.o.tablet === true && exprTablet.test(navigator.userAgent))
- || (this.o.mobile === true && exprMobile.test(navigator.userAgent));
- }
- };
- /* isObject */
- var toString = Object.prototype.toString, hasOwnProp = Object.prototype.hasOwnProperty;
- $.isObject = function(obj) { if(toString.call(obj) !== "[object Object]") return false; var key; for(key in obj){} return !key || hasOwnProp.call(obj, key); };
- $.isString = function(str){ return typeof(str) === 'string' };
- })(jQuery);
- /* ===========================================================
- * trumbowyg.upload.js v1.0
- * Upload plugin for Trumbowyg
- * http://alex-d.github.com/Trumbowyg
- * ===========================================================
- * Author : Alexandre Demode (Alex-D)
- * Twitter : @AlexandreDemode
- * Website : alex-d.fr
- */
- (function($){
- addXhrProgressEvent();
- $.extend(true, $.trumbowyg, {
- langs: {
- en: {
- upload: "Envoi d'un fichier",
- file: "Fichier",
- uploadError: "Erreur"
- }
- },
- upload: {
- serverPath: './trumbowyg.upload.php'
- },
- opts: {
- btnsDef: {
- upload: {
- func: function(params, tbw){
- var file,
- pfx = tbw.o.prefix;
- var $modal = tbw.openModalInsert(
- // Title
- tbw.lang['upload'],
- // Fields
- {
- file: {
- type: 'file',
- required: true
- }
- },
- // Callback
- function(values, fields){
- var data = new FormData();
- data.append('file', file);
- if($('.' + pfx +'progress', $modal).length == 0)
- $('.' + pfx + 'modal-title', $modal)
- .after(
- $('<div/>', {
- 'class': pfx +'progress'
- })
- .append(
- $('<div/>', {
- 'class': pfx +'progress-bar'
- })
- )
- );
- $.ajax({
- url: $.trumbowyg.upload.serverPath,
- type: 'POST',
- data: data,
- cache: false,
- dataType: 'json',
- processData: false,
- contentType: false,
- progressUpload: function(e){
- $('.' + pfx + 'progress-bar').stop().animate({
- width: Math.round(e.loaded * 100 / e.total) + '%'
- }, 200);
- },
- success: function(data){
- if(data.error.length == 0) {
- if(data.file.ext == 'jpg' || data.file.ext == 'jpeg' || data.file.ext == 'gif' || data.file.ext == 'png' || data.file.ext == 'bmp'){
- tbw.execCommand('insertImage', data.file.url);
- }else{
- tbw.execCommand("InsertHTML", '<a href="'+data.file.url+'">'+data.file.name+'</a>');
- }
- setTimeout(function(){
- tbw.closeModal();
- }, 250);
- } else {
- alert(data.error.join('\n-'));
- tbw.addErrorOnModalField(
- $('input[type=file]', $modal),'Erreur'
- );
- }
- },
- error: function(data){
- tbw.addErrorOnModalField(
- $('input[type=file]', $modal),
- tbw.lang['uploadError']
- );
- }
- });
- }
- );
- $('input[type=file]').on('change', function(e){
- file = e.target.files[0];
- });
- }
- }
- }
- }
- });
- function addXhrProgressEvent(){
- var originalXhr = $.ajaxSettings.xhr;
- $.ajaxSetup({
- xhr: function() {
- var req = originalXhr(),
- that = this;
- if(req && typeof req.upload == "object" && that.progressUpload !== undefined)
- req.upload.addEventListener("progress", function(e){
- that.progressUpload(e);
- }, false);
- return req;
- }
- });
- }
- })(jQuery);
|