diff --git a/js/comment-toolbar.js b/js/comment-toolbar.js index 74654868..7ae11a73 100644 --- a/js/comment-toolbar.js +++ b/js/comment-toolbar.js @@ -8,379 +8,253 @@ * $config['additional_javascript'][] = 'js/comment-toolbar.js'; */ if (active_page == 'thread' || active_page == 'index') { - var formatText = (function($){ - "use strict"; - var self = {}; - self.rules = { - spoiler: { - text: 'Spoiler', - key: 's', - multiline: false, - exclusiveline: false, - prefix:'**', - suffix:'**' + $(document).ready(function () { + 'use strict'; + var formats = { + bold: { + displayText: 'B', + altText: 'bold', + styleCSS: 'font-weight: bold;', + options: { + prefix: "'''", + suffix: "'''" + }, + edit: function (box, options) { + wrapSelection(box, options); + }, + shortcutKey: 'b' }, italics: { - text: 'Italics', - key: 'i', - multiline: false, - exclusiveline: false, - prefix: "''", - suffix: "''" + displayText: 'i', + altText: 'italics', + styleCSS: 'font-style: italic;', + options: { + prefix: "''", + suffix: "''" + }, + edit: function (box, options) { + wrapSelection(box, options); + }, + shortcutKey: 'i' }, - bold: { - text: 'Bold', - key: 'b', - multiline: false, - exclusiveline: false, - prefix: "'''", - suffix: "'''" + under: { + displayText: 'U', + altText: 'underline', + styleCSS: 'text-decoration: underline;', + options: { + prefix: '__', + suffix: '__' + }, + edit: function (box, options) { + wrapSelection(box, options); + }, + shortcutKey: 'u' }, - underline: { - text: 'Underline', - key: 'u', - multiline: false, - exclusiveline: false, - prefix:'__', - suffix:'__' + spoiler: { + displayText: 'spoiler', + altText: 'mark as spoiler', + styleCSS: '', + options: { + prefix: '[spoiler]', + suffix: '[/spoiler]' + }, + edit: function (box, options) { + wrapSelection(box, options); + }, + shortcutKey: 's' }, code: { - text: 'Code', - key: 'f', - multiline: true, - exclusiveline: false, - prefix: '[code]', - suffix: '[/code]' + displayText: 'code', + altText: "code formatting", + styleCSS: 'font-family: "Courier New", Courier, monospace;', + options: { + prefix: '[code]', + suffix: '[/code]', + multiline: true + }, + edit: function (box, options) { + wrapSelection(box, options); + }, + shortcutKey: 'd' }, strike: { - text: 'Strike', - key: 'd', - multiline:false, - exclusiveline:false, - prefix:'~~', - suffix:'~~' + displayText: 'strike', + altText: 'strikethrough', + styleCSS: 'text-decoration: line-through;', + options: { + prefix: '~~', + suffix: '~~' + }, + edit: function (box, options) { + wrapSelection(box, options); + } }, heading: { - text: 'Heading', - key: 'r', - multiline:false, - exclusiveline:true, - prefix:'==', - suffix:'==' + displayText: 'heading', + altText: 'redtext', + styleCSS: 'color: #AF0A0F; font-weight: bold;', + options: { + prefix: '==', + suffix: '==', + exclusiveLine: true + }, + edit: function (box, options) { + wrapSelection(box, options); + } } }; - - self.toolbar_wrap = function(node) { - if (!localStorage.formatText_enable || localStorage.formatText_enable == 'false') return; - var parent = $(node).parents('form[name="post"]'); - self.wrap(parent.find('#body')[0],'textarea[name="body"]', parent.find('.format-text > select')[0].value, false); - }; - - self.wrap = function(ref, target, option, expandedwrap) { - if (!localStorage.formatText_enable || localStorage.formatText_enable == 'false') return; - // clean and validate arguments - if (ref == null) return; - var settings = {multiline: false, exclusiveline: false, prefix:'', suffix: null}; - $.extend(settings,JSON.parse(localStorage.formatText_rules)[option]); - - // resolve targets into array of proper node elements - // yea, this is overly verbose, oh well. - var res = []; - if (target instanceof Array) { - for (var indexa in target) { - if (target.hasOwnProperty(indexa)) { - if (typeof target[indexa] == 'string') { - var nodes = $(target[indexa]); - for (var indexb in nodes) { - if (indexa.hasOwnProperty(indexb)) res.push(nodes[indexb]); - } - } else { - res.push(target[indexa]); - } - } - } - } else { - if (typeof target == 'string') { - var nodes = $(target); - for (var index in nodes) { - if (nodes.hasOwnProperty(index)) res.push(nodes[index]); - } - } else { - res.push(target); - } + + var key, name, altText, ele; + var strBuilder = []; + var subStr = ''; + var styleRules = ''; + + //not exactly mine + var wrapSelection = function (box, options) { + if (box == null) { + return; } - target = res; - //record scroll top to restore it later. - var scrollTop = ref.scrollTop; + var prefix = options.prefix; + var suffix = options.suffix; + var multiline = options.multiline || false; + var exclusiveLine = options.exclusiveLine || false; - //We will restore the selection later, so record the current selection - var selectionStart = ref.selectionStart; - var selectionEnd = ref.selectionEnd; + //record scroll top to restore it later. + var scrollTop = box.scrollTop; + var selectionStart = box.selectionStart; + var selectionEnd = box.selectionEnd; + var text = box.value; + var beforeSelection = text.substring(0, selectionStart); + var selectedText = text.substring(selectionStart, selectionEnd); + var afterSelection = text.substring(selectionEnd); - var text = ref.value; - var before = text.substring(0, selectionStart); - var selected = text.substring(selectionStart, selectionEnd); - var after = text.substring(selectionEnd); - var whiteSpace = [" ","\t"]; var breakSpace = ["\r","\n"]; - var cursor; - - // handles multiline selections on formatting that doesn't support spanning over multiple lines - if (!settings.multiline) selected = selected.replace(/(\r|\n|\r\n)/g,settings.suffix +"$1"+ settings.prefix); - - // handles formatting that requires it to be on it's own line OR if the user wishes to expand the wrap to the nearest linebreak - if (settings.exclusiveline || expandedwrap) { + var trailingSpace = ""; + var cursor = selectedText.length - 1; + + //remove trailing space + while (cursor > 0 && selectedText[cursor] === " ") { + trailingSpace += " "; + cursor--; + } + selectedText = selectedText.substring(0, cursor + 1); + + if (!multiline) + selectedText = selectedText.replace(/(\r|\n|\r\n)/g, suffix +"$1"+ prefix); + + if (exclusiveLine) { // buffer the begining of the selection until a linebreak - cursor = before.length -1; - while (cursor >= 0 && breakSpace.indexOf(before.charAt(cursor)) == -1) { + cursor = beforeSelection.length -1; + while (cursor >= 0 && breakSpace.indexOf(beforeSelection.charAt(cursor)) == -1) { cursor--; } - selected = before.substring(cursor +1) + selected; - before = before.substring(0, cursor +1); + selectedText = beforeSelection.substring(cursor +1) + selectedText; + beforeSelection = beforeSelection.substring(0, cursor +1); // buffer the end of the selection until a linebreak cursor = 0; - while (cursor < after.length && breakSpace.indexOf(after.charAt(cursor)) == -1) { + while (cursor < afterSelection.length && breakSpace.indexOf(afterSelection.charAt(cursor)) == -1) { cursor++; } - selected += after.substring(0, cursor); - after = after.substring(cursor); + selectedText += afterSelection.substring(0, cursor); + afterSelection = afterSelection.substring(cursor); } - - // set values - var res = before + settings.prefix + selected + settings.suffix + after; - $(target).val(res); - - // restore the selection area and scroll of the reference - ref.selectionEnd = before.length + settings.prefix.length + selected.length; + + box.value = beforeSelection + prefix + selectedText + suffix + trailingSpace + afterSelection; + + box.selectionEnd = beforeSelection.length + prefix.length + selectedText.length; if (selectionStart === selectionEnd) { - ref.selectionStart = ref.selectionEnd; + box.selectionStart = box.selectionEnd; } else { - ref.selectionStart = before.length + settings.prefix.length; + box.selectionStart = beforeSelection.length + prefix.length; } - ref.scrollTop = scrollTop; + box.scrollTop = scrollTop; }; - - self.build_toolbars = function(){ - if (!localStorage.formatText_enable || localStorage.formatText_enable == 'false') return; - if (localStorage.formatText_toolbar == 'true'){ - // remove existing toolbars - if ($('.format-text').length > 0) $('.format-text').remove(); - - // Place toolbar above each textarea input - var name, options = '', rules = JSON.parse(localStorage.formatText_rules); - for (var index in rules) { - if (!rules.hasOwnProperty(index)) continue; - name = rules[index].text; - //add hint if key exists - if (rules[index].key) { - name += ' (CTRL + '+ rules[index].key.toUpperCase() +')'; + /* Generate the HTML for the toolbar + */ + for (ele in formats) { + if (formats.hasOwnProperty(ele) && formats[ele].displayText != null) { + name = formats[ele].displayText; + altText = formats[ele].altText || ''; + key = formats[ele].shortcutKey; + + //add tooltip text + if (altText) { + if (key) { + altText += ' (ctrl+'+ key +')'; } - options += ''; - } - $('[name="body"]').before('
Wrap
'); - $('body').append(''); - } - }; - - self.add_rule = function(rule, index){ - if (rule === undefined) rule = { - text: 'New Rule', - key: '', - multiline:false, - exclusiveline:false, - prefix:'', - suffix:'' - } - - // generate an id for the rule - if (index === undefined) { - var rules = JSON.parse(localStorage.formatText_rules); - while (rules[index] || index === undefined) { - index = '' - index +='abcdefghijklmnopqrstuvwxyz'.substr(Math.floor(Math.random()*26),1); - index +='abcdefghijklmnopqrstuvwxyz'.substr(Math.floor(Math.random()*26),1); - index +='abcdefghijklmnopqrstuvwxyz'.substr(Math.floor(Math.random()*26),1); + altText = 'title="'+ altText +'"'; } + + subStr = ''+ name +''; + strBuilder.push(subStr); + } else { + continue; } - if (window.Options && Options.get_tab('formatting')){ - var html = $('
').html('\ - \ - \ - \ - \ - \ - \ - \ - '); - - if ($('.format_rule').length > 0) { - $('.format_rule').last().after(html); - } else { - Options.extend_tab('formatting', html); + } + + $( 'textarea[name="body"]' ).before( '
' ); + $( '.tf-toolbar' ).html( strBuilder.join(' | ') ); + + /* Sets the CSS style + */ + styleRules = '\n/* generated by 8chan Formatting Tools */'+ + '\n.tf-toolbar {padding: 0px 5px 1px 5px;}'+ + '\n.tf-toolbar :link {text-decoration: none;}'; + for (ele in formats) { + if (formats.hasOwnProperty(ele) && formats[ele].styleCSS) { + styleRules += ' \n#tf-' + ele + ' {' + formats[ele].styleCSS + '}'; } } - }; - - self.save_rules = function(){ - var newrules = {}, rules = $('.format_rule'); - for (var index=0;rules[index];index++) { - newrules[$(rules[index]).attr('name')] = { - text: $(rules[index]).find('[name="text"]').val(), - key: $(rules[index]).find('[name="key"]').val(), - prefix: $(rules[index]).find('[name="prefix"]').val(), - suffix: $(rules[index]).find('[name="suffix"]').val(), - multiline: $(rules[index]).find('[name="multiline"]').is(':checked'), - exclusiveline: $(rules[index]).find('[name="exclusiveline"]').is(':checked') - }; - } - localStorage.formatText_rules = JSON.stringify(newrules); - self.build_toolbars(); - }; - - self.reset_rules = function() { - localStorage.formatText_rules = JSON.stringify(self.rules); - }; - - // store default rules for customizing - if (!localStorage.formatText_rules) self.reset_rules(); - - // Add settings to Options panel general tab - if (window.Options && Options.get_tab('general')) { - var s1 = '#formatText_enable>input', s2 = '#formatText_keybinds>input', s3 = '#formatText_toolbar>input', e = 'change'; - Options.extend_tab('general', '\ -
\ - Formatting Options\ - \ - \ - \ -
\ - '); - } else { - var s1 = '#formatText_enable', s2 = '#formatText_keybinds', s3 = '#formatText_toolbar', e = 'click'; - $('hr:first').before('
'+ _('Enable post formatting') +'
'); - $('hr:first').before('
'+ _('Enable formatting keybinds') +'
'); - $('hr:first').before('
'+ _('Show formatting toolbar') +'
'); - } - - // setting for enableing text formatting - $(s1).on(e, function(e) { - if (!localStorage.formatText_enable || localStorage.formatText_enable == 'false') { - localStorage.formatText_enable = 'true'; - if (window.Options && Options.get_tab('general')) e.target.checked = true; + //add CSS rule to user's custom CSS if it exist + if ($( '.user-css' ).length !== 0) { + $( '.user-css' ).append( styleRules ); } else { - localStorage.formatText_enable = 'false'; - if (window.Options && Options.get_tab('general')) e.target.checked = false; + $( 'body' ).append( '' ); } - }); - - // setting for enableing formatting keybinds - $(s2).on(e, function(e) { - if (!localStorage.formatText_keybinds || localStorage.formatText_keybinds == 'false') { - localStorage.formatText_keybinds = 'true'; - if (window.Options && Options.get_tab('general')) e.target.checked = true; - } else { - localStorage.formatText_keybinds = 'false'; - if (window.Options && Options.get_tab('general')) e.target.checked = false; + + /* Attach event listeners + */ + $( 'body' ).on( 'keydown', 'textarea[name="body"]', {formats: formats}, function (e) { + //shortcuts + if (e.ctrlKey) { + var ch = String.fromCharCode(e.which).toLowerCase(); + var box = e.target; + var formats = e.data.formats; + for (var ele in formats) { + if (formats.hasOwnProperty(ele) && (ch === formats[ele].shortcutKey)) { + formats[ele].edit(box, formats[ele].options); + e.preventDefault(); + } + } } }); - - // setting for toolbar injection - $(s3).on(e, function(e) { - if (!localStorage.formatText_toolbar || localStorage.formatText_toolbar == 'false') { - localStorage.formatText_toolbar = 'true'; - if (window.Options && Options.get_tab('general')) e.target.checked = true; - formatText.build_toolbars(); - } else { - localStorage.formatText_toolbar = 'false'; - if (window.Options && Options.get_tab('general')) e.target.checked = false; - $('.format-text').remove(); + $( 'body' ).on( 'keydown', '#quick-reply textarea[name="body"]', {formats: formats}, function (e) { + //close quick reply when esc is prssed + if (e.which === 27) { + $( '.close-btn' ).trigger( 'click' ); } }); - - // make sure the tab settings are switch properly at loadup - if (window.Options && Options.get_tab('general')) { - if (localStorage.formatText_enable == 'true') $(s1)[0].checked = true; - else $(s1)[0].checked = false; - if (localStorage.formatText_keybinds == 'true') $(s2)[0].checked = true; - else $(s2)[0].checked = false; - if (localStorage.formatText_toolbar == 'true') $(s2)[0].checked = true; - else $(s3)[0].checked = false; - } - - // add the tab for customizing the format settings - if (window.Options && !Options.get_tab('formatting')) { - Options.add_tab('formatting', 'angle-right', 'Customize Formatting'); - Options.extend_tab('formatting', '\ - \ - '); - - // Data control row - Options.extend_tab('formatting', '\ - \ - \ - \ - '); - - // Descriptor row - Options.extend_tab('formatting', '\ - Name\ - ML\ - EL\ - Prefix\ - Suffix\ - Key\ - '); - - // Rule rows - var rules = JSON.parse(localStorage.formatText_rules); - for (var index in rules){ - if (!rules.hasOwnProperty(index)) continue; - self.add_rule(rules[index], index); - } - } - - return self; - })(jQuery); - - // run initial toolbar injection - formatText.build_toolbars(); - - //attach listeners to so it also works on quick-reply box - $('body').on('keydown', '#body, #quick-reply #body', function(e) { - if (!localStorage.formatText_enable || localStorage.formatText_enable == 'false') return; - if (!localStorage.formatText_keybinds || localStorage.formatText_keybinds == 'false') return; - var key = String.fromCharCode(e.which).toLowerCase(); - var rules = JSON.parse(localStorage.formatText_rules); - for (var index in rules) { - if (!rules.hasOwnProperty(index)) continue; - if (key === rules[index].key && e.ctrlKey) { - e.preventDefault(); - if (e.shiftKey) { - formatText.wrap(e.target, 'textarea[name="body"]', index, true); - } else { - formatText.wrap(e.target, 'textarea[name="body"]', index, false); + $( 'body' ).on( 'click', '.tf-toolbar a[id]', {formats: formats}, function (e) { + //toolbar buttons + var formats = e.data.formats; + var box = $(e.target).parent().next()[0]; + + for (var ele in formats) { + if (formats.hasOwnProperty(ele) && (e.target.id === 'tf-' + ele)) { + formats[ele].edit(box, formats[ele].options); } } - } + }); + // $( 'body' ).on( 'keydown', function (e) { + // if (e.which === 67 && + // e.target.nodeName !== 'INPUT' && //The C, the whole C, and nothing but the C + // e.target.nodeName !== 'TEXTAREA' && + // !(e.ctrlKey || e.altKey || e.shiftKey)) { + // document.location.href = '//'+ document.location.host +'/'+ board_name +'/catalog.html'; + // } + // }); + }); - $(document).trigger('formatText'); -} \ No newline at end of file +} diff --git a/stylesheets/style.css b/stylesheets/style.css index ec07fe0a..0e56f442 100644 --- a/stylesheets/style.css +++ b/stylesheets/style.css @@ -896,7 +896,6 @@ div.thread:hover { right: 0px; text-align: left; font-size: 12px; - overflow-y: auto; } .options_tab h2 {