$(function ($) { 'use strict'; var mybbCmd = { align: ['left', 'center', 'right', 'justify'], fsStr: ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'], fSize: [9, 12, 15, 17, 23, 31], video: { 'Dailymotion': { 'match': /(dailymotion\.com\/video\/|dai\.ly\/)([^\/]+)/, 'url': '//www.dailymotion.com/embed/video/', 'html': '' }, 'Facebook': { 'match': /facebook\.com\/(?:photo.php\?v=|video\/video.php\?v=|video\/embed\?video_id=|v\/?)(\d+)/, 'url': 'https://www.facebook.com/video/embed?video_id=', 'html': '' }, 'Liveleak': { 'match': /liveleak\.com\/(?:view\?[a-z]=)([^\/]+)/, 'url': 'http://www.liveleak.com/ll_embed?i=', 'html': '' }, 'MetaCafe': { 'match': /metacafe\.com\/watch\/([^\/]+)/, 'url': 'http://www.metacafe.com/embed/', 'html': '' }, 'Mixer': { 'match': /mixer\.com\/([^\/]+)/, 'url': '//mixer.com/embed/player/', 'html': '' }, 'Vimeo': { 'match': /vimeo.com\/(\d+)($|\/)/, 'url': '//player.vimeo.com/video/', 'html': '' }, 'Youtube': { 'match': /(?:v=|v\/|embed\/|youtu\.be\/)(.{11})/, 'url': '//www.youtube-nocookie.com/embed/', 'html': '' }, 'Twitch': { 'match': /twitch\.tv\/(?:[\w+_-]+)\/v\/(\d+)/, 'url': '//player.twitch.tv/?video=v', 'html': '' } } }; for (var i in mybbCmd.video) { var item = mybbCmd.video[i]; $.sceditor.defaultOptions.allowedIframeUrls.push(item.url); } // Add custom MyBB CSS $('').appendTo('body'); // Update editor to use align= as alignment $.sceditor.formats.bbcode .set('align', { html: function (element, attrs, content) { return '
' + content + '
'; }, isInline: false }); $.each(mybbCmd.align, function (i, val) { $.sceditor.formats.bbcode.set(val, { format: '[align=' + val + ']{0}[/align]' }); $.sceditor.command .set(val, { txtExec: ['[align=' + val + ']', '[/align]'] }); }); // Update font to support MyBB's BBCode dialect $.sceditor.formats.bbcode .set('list', { html: function (element, attrs, content) { var type = (attrs.defaultattr === '1' ? 'ol' : 'ul'); if (attrs.defaultattr === 'a') type = 'ol type="a"'; return '<' + type + '>' + content + ''; }, isInline: false, skipLastLineBreak: true, breakStart: true, breakAfter: true, }) .set('ul', { format: '[list]{0}[/list]', isInline: false, skipLastLineBreak: true, breakStart: true, breakAfter: true, }) .set('ol', { format: function ($elm, content) { var type = ($($elm).attr('type') === 'a' ? 'a' : '1'); return '[list=' + type + ']' + content + '[/list]'; }, isInline: false, skipLastLineBreak: true, breakStart: true, breakAfter: true, }) .set('li', { format: '[*]{0}', isInline: false, skipLastLineBreak: true, }) .set('*', { html: '
  • {0}
  • ', isInline: false, excludeClosing: true, skipLastLineBreak: true, breakAfter: false, }); $.sceditor.command .set('bulletlist', { txtExec: function (caller, selected) { var content = ''; $.each(selected.split(/\r?\n/), function () { content += (content ? '\n' : '') + '[*]' + this; }); this.insertText('[list]\n' + content + '\n[/list]'); } }) .set('orderedlist', { txtExec: function (caller, selected) { var content = ''; $.each(selected.split(/\r?\n/), function () { content += (content ? '\n' : '') + '[*]' + this; }); this.insertText('[list=1]\n' + content + '\n[/list]'); } }); // Update size tag to use xx-small-xx-large instead of 1-7 $.sceditor.formats.bbcode.set('size', { format: function ($elm, content) { var fontsize = 1, scefontsize = $($elm).data('scefontsize'), parsed = parseInt(scefontsize, 10), size = parseInt($($elm).attr('size'), 10), iframe = $('.sceditor-container iframe'), editor_body = $('body', iframe.contents()); if ($($elm).css('font-size') == editor_body.css('font-size')) { // Eliminate redundant [size] tags for unformatted text. // Part of the fix for the browser-dependent bug of issue #4184. // Also fixes the browser-dependent bug described here: // fontsize = -1; } else if (!isNaN(size) && size >= 1 && size <= mybbCmd.fsStr.length) { fontsize = mybbCmd.fsStr[size - 1]; } else if ($.inArray(scefontsize, mybbCmd.fsStr) !== -1) { fontsize = scefontsize; } else if (!isNaN(parsed)) { fontsize = parsed; } return fontsize != -1 ? '[size=' + fontsize + ']' + content + '[/size]' : content; }, html: function (token, attrs, content) { var size = 0, units = "", parsed = parseInt(attrs.defaultattr, 10); if (!isNaN(parsed)) { size = parsed; if (size < 1) { size = 1; } else if (size > 50) { size = 50; } units = "pt"; } else { var fsStrPos = $.inArray(attrs.defaultattr, mybbCmd.fsStr); if (fsStrPos !== -1) { size = attrs.defaultattr; } } return '' + content + ''; } }); $.sceditor.command.set('size', { _dropDown: function (editor, caller, callback) { var content = $('
    '), clickFunc = function (e) { callback($(this).data('size')); editor.closeDropDown(true); e.preventDefault(); }; for (var i = 1; i <= 7; i++) content.append($('' + i + '').on('click', clickFunc)); editor.createDropDown(caller, 'fontsize-picker', content.get(0)); }, exec: function (caller) { var editor = this; $.sceditor.command.get('size')._dropDown( editor, caller, function (fontSize) { editor.execCommand('fontsize', fontSize); } ); }, txtExec: function (caller) { var editor = this; $.sceditor.command.get('size')._dropDown( editor, caller, function (size) { size = (~~size); size = (size > 7) ? 7 : ((size < 1) ? 1 : size); editor.insertText('[size=' + mybbCmd.fsStr[size - 1] + ']', '[/size]'); } ); } }); // Update quote to support pid and dateline $.sceditor.formats.bbcode.set('quote', { format: function (element, content) { var author = '', $elm = $(element), $cite = $elm.children('cite').first(); if ($cite.length === 1 || $elm.data('author')) { author = $cite.text() || $elm.data('author'); $elm.data('author', author); $cite.remove(); content = this.elementToBbcode(element); author = '=' + author.replace(/(^\s+|\s+$)/g, ''); $elm.prepend($cite); } if ($elm.data('pid')) author += " pid='" + $elm.data('pid') + "'"; if ($elm.data('dateline')) author += " dateline='" + $elm.data('dateline') + "'"; return '[quote' + author + ']' + content + '[/quote]'; }, html: function (token, attrs, content) { var data = ''; if (attrs.pid) data += ' data-pid="' + $.sceditor.escapeEntities(attrs.pid) + '"'; if (attrs.dateline) data += ' data-dateline="' + $.sceditor.escapeEntities(attrs.dateline) + '"'; if (typeof attrs.defaultattr !== "undefined") content = '' + $.sceditor.escapeEntities(attrs.defaultattr).replace(/ /g, ' ') + '' + content; return '' + content + ''; }, quoteType: function (val, name) { var quoteChar = val.indexOf('"') !== -1 ? "'" : '"'; return quoteChar + val + quoteChar; }, breakStart: true, breakEnd: true }); // Update font tag to allow limiting to only first in stack $.sceditor.formats.bbcode.set('font', { format: function (element, content) { var font; if (element.nodeName.toLowerCase() !== 'font' || !(font = $(element).attr('face'))) font = $(element).css('font-family'); var iframe = $('.sceditor-container iframe'); var editor_body = $('body', iframe.contents()); if (typeof font == 'string' && font != '' && font != 'defaultattr' && // Eliminate redundant [font] tags for unformatted text. // Part of the fix for the browser-dependent bug of issue #4184. font != editor_body.css('font-family')) { font = font.trim(); // Strip all-enclosing double quotes from fonts so long as // they are the only double quotes present... if (font[0] == '"' && font[font.length-1] == '"' && (font.match(/"/g) || []).length == 2) { font = font.substr(1, font.length-2); } // ...and then replace any other occurrence(s) of double quotes // in fonts with single quotes. // This is the client-side aspect of the fix for // the browser-independent bug of issue #4182. font = font.replace(/"/g, "'"); return '[font=' + font + ']' + content + '[/font]'; } else { return content; } }, html: function (token, attrs, content) { if (typeof attrs.defaultattr == 'string' && attrs.defaultattr != '' && attrs.defaultattr != '{defaultattr}') { return '' + content + ''; } else { return content; } } }); $.sceditor.formats.bbcode.set('color', { format: function (element, content) { var color, defaultColor; var iframe = $('.sceditor-container iframe'); var editor_body = $('body', iframe.contents()); if (element.nodeName.toLowerCase() != 'font' || !(color = $(element).attr('color'))) { color = $(element).css('color'); } color = _normaliseColour(color); defaultColor = _normaliseColour(editor_body.css('color')); // Eliminate redundant [color] tags for unformatted text. // Part of the fix for the browser-dependent bug of issue #4184. return color != defaultColor ? '[color=' + color + ']' + content + '[/color]' : content; }, html: function (token, attrs, content) { return '' + content + ''; } }); // Add MyBB PHP command $.sceditor.formats.bbcode.set('php', { allowsEmpty: true, isInline: false, allowedChildren: ['#', '#newline'], format: '[php]{0}[/php]', html: '{0}' }); $.sceditor.command.set("php", { _dropDown: function (editor, caller) { var $content; $content = $( '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + '
    ' ); setTimeout(function () { $content.find('#php').trigger('focus'); }, 100); $content.find('.button').on('click', function (e) { var val = $content.find('#php').val(), before = '[php]', end = '[/php]'; if (val) { before = before + val + end; end = null; } editor.insert(before, end); editor.closeDropDown(true); e.preventDefault(); }); editor.createDropDown(caller, 'insertphp', $content.get(0)); }, exec: function (caller) { if ($.trim(this.getRangeHelper().selectedRange())) { this.insert('[php]', '[/php]'); return; } $.sceditor.command.get('php')._dropDown(this, caller); }, txtExec: ['[php]', '[/php]'], tooltip: "PHP" }); // Update code to support PHP $.sceditor.formats.bbcode.set('code', { allowsEmpty: true, tags: { code: null }, isInline: false, allowedChildren: ['#', '#newline'], format: function (element, content) { if ($(element).hasClass('phpcodeblock')) { return '[php]' + content + '[/php]'; } return '[code]' + content + '[/code]'; }, html: '{0}' }); $.sceditor.command.set("code", { _dropDown: function (editor, caller) { var $content; $content = $( '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + '
    ' ); setTimeout(function () { $content.find('#code').trigger('focus'); }, 100); $content.find('.button').on('click', function (e) { var val = $content.find('#code').val(), before = '[code]', end = '[/code]'; if (val) { before = before + val + end; end = null; } editor.insert(before, end); editor.closeDropDown(true); e.preventDefault(); }); editor.createDropDown(caller, 'insertcode', $content.get(0)); }, exec: function (caller) { if ($.trim(this.getRangeHelper().selectedRange())) { this.insert('[code]', '[/code]'); return; } $.sceditor.command.get('code')._dropDown(this, caller); }, txtExec: ['[code]', '[/code]'], }); // Update email to support description $.sceditor.command.set('email', { _dropDown: function (editor, caller) { var $content; $content = $( '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + '
    ' ); $content.find('.button').on('click', function (e) { var val = $content.find('#email').val(), description = $content.find('#des').val(); if (val) { // needed for IE to reset the last range $(editor).trigger('focus'); if (!editor.getRangeHelper().selectedHtml() || description) { if (!description) description = val; editor.insert('[email=' + val + ']' + description + '[/email]'); } else editor.execCommand('createlink', 'mailto:' + val); } editor.closeDropDown(true); e.preventDefault(); }); editor.createDropDown(caller, 'insertemail', $content.get(0)); }, exec: function (caller) { $.sceditor.command.get('email')._dropDown(this, caller); } }); // Add MyBB video command $.sceditor.formats.bbcode.set('video', { allowsEmpty: true, allowedChildren: ['#', '#newline'], tags: { iframe: { 'data-mybb-vt': null } }, format: function ($element, content) { return '[video=' + $($element).data('mybb-vt') + ']' + $($element).data('mybb-vsrc') + '[/video]'; }, html: function (token, attrs, content) { var params = mybbCmd.video[Object.keys(mybbCmd.video).find(key => key.toLowerCase() === attrs.defaultattr)]; var matches, url; var n = (attrs.defaultattr == 'dailymotion') ? 2 : 1; if (typeof params !== "undefined") { matches = content.match(params['match']); url = matches ? params['url'] + matches[n] : false; } if (url) { return params['html'].replace('{url}', url).replace('{src}', content).replace('{type}', attrs.defaultattr); } return $.sceditor.escapeEntities(token.val + content + (token.closing ? token.closing.val : '')); } }); $.sceditor.command.set('video', { _dropDown: function (editor, caller) { var $content, videourl, videotype, videoOpts; $.each(mybbCmd.video, function (provider, data) { videoOpts += ''; }); $content = $( '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + '
    ' ); $content.find('.button').on('click', function (e) { videourl = $content.find('#videourl').val(); videotype = $content.find('#videotype').val(); if (videourl !== '' && videourl !== 'http://') editor.insert('[video=' + videotype + ']' + videourl + '[/video]'); editor.closeDropDown(true); e.preventDefault(); }); editor.createDropDown(caller, 'insertvideo', $content.get(0)); }, exec: function (caller) { $.sceditor.command.get('video')._dropDown(this, caller); }, txtExec: function (caller) { $.sceditor.command.get('video')._dropDown(this, caller); }, tooltip: 'Insert a video' }); // Update image command to support MyBB syntax $.sceditor.formats.bbcode.set('img', { format: function (element, content) { if ($(element).data('sceditor-emoticon')) return content; var url = $(element).attr('src'), width = $(element).attr('width'), height = $(element).attr('height'), align = $(element).data('scealign'); var attrs = width !== undefined && height !== undefined && width > 0 && height > 0 ? '=' + width + 'x' + height : '' ; if (align === 'left' || align === 'right') attrs += ' align='+align return '[img' + attrs + ']' + url + '[/img]'; }, html: function (token, attrs, content) { var width, height, match, align = attrs.align, attribs = ''; // handle [img=340x240]url[/img] if (attrs.defaultattr) { match = attrs.defaultattr.split(/x/i); width = match[0]; height = (match.length === 2 ? match[1] : match[0]); if (width !== undefined && height !== undefined && width > 0 && height > 0) { attribs += ' width="' + $.sceditor.escapeEntities(width, true) + '"' + ' height="' + $.sceditor.escapeEntities(height, true) + '"'; } } if (align === 'left' || align === 'right') attribs += ' style="float: ' + align + '" data-scealign="' + align + '"'; return ''; } }) $.sceditor.command.set('image', { _dropDown: function (editor, caller) { var $content; $content = $( '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + ' ' + '' + '
    ' + '
    ' + '' + '
    ' + '
    ' ); $content.find('.button').on('click', function (e) { var url = $content.find('#image').val(), width = $content.find('#width').val(), height = $content.find('#height').val() ; var attrs = width !== undefined && height !== undefined && width > 0 && height > 0 ? '=' + width + 'x' + height : '' ; if (url) editor.insert('[img' + attrs + ']' + url + '[/img]'); editor.closeDropDown(true); e.preventDefault(); }); editor.createDropDown(caller, 'insertimage', $content.get(0)); }, exec: function (caller) { $.sceditor.command.get('image')._dropDown(this, caller); }, txtExec: function (caller) { $.sceditor.command.get('image')._dropDown(this, caller); }, }); // Remove last bits of table, superscript/subscript, youtube and ltr/rtl support $.sceditor.command .remove('table').remove('subscript').remove('superscript').remove('youtube').remove('ltr').remove('rtl'); $.sceditor.formats.bbcode .remove('table').remove('tr').remove('th').remove('td').remove('sub').remove('sup').remove('youtube').remove('ltr').remove('rtl'); // Remove code and quote if in partial mode if (partialmode) { $.sceditor.formats.bbcode.remove('code').remove('php').remove('quote').remove('video').remove('img'); $.sceditor.command .set('quote', { exec: function () { this.insert('[quote]', '[/quote]'); } }); } // Fix url code $.sceditor.formats.bbcode.set('url', { html: function (token, attrs, content) { if (!attrs.defaultattr) attrs.defaultattr = content; return '' + content + ''; } }); /** * Converts a number 0-255 to hex. * * Will return 00 if number is not a valid number. * * Copied from the SCEditor's src/formats/bbcode.js file * where it is unfortunately defined as private. * * @param {any} number * @return {string} */ function toHex(number) { number = parseInt(number, 10); if (isNaN(number)) { return '00'; } number = Math.max(0, Math.min(number, 255)).toString(16); return number.length < 2 ? '0' + number : number; } /** * Normalises a CSS colour to hex #xxxxxx format * * Copied from the SCEditor's src/formats/bbcode.js file * where it is unfortunately defined as private. * * @param {string} colorStr * @return {string} */ function _normaliseColour(colorStr) { var match; colorStr = colorStr || '#000'; // rgb(n,n,n); if ((match = colorStr.match(/rgb\((\d{1,3}),\s*?(\d{1,3}),\s*?(\d{1,3})\)/i))) { return '#' + toHex(match[1]) + toHex(match[2]) + toHex(match[3]); } // rgba(n,n,n,f.p); if ((match = colorStr.match(/rgba\((\d{1,3}),\s*?(\d{1,3}),\s*?(\d{1,3}),\s*?(\d*\.?\d+\s*)\)/i))) { return '#' + toHex(match[1]) + toHex(match[2]) + toHex(match[3]); } // expand shorthand if ((match = colorStr.match(/#([0-f])([0-f])([0-f])\s*?$/i))) { return '#' + match[1] + match[1] + match[2] + match[2] + match[3] + match[3]; } return colorStr; } });