1
0
mirror of https://github.com/vichan-devel/vichan.git synced 2024-11-29 01:34:31 +01:00
vichan/js/comment-toolbar.js

261 lines
7.1 KiB
JavaScript

/*
* comment-toolbar.js
* - Adds a toolbar above the commenting area containing most of 8Chan's formatting options
* - Press Esc to close quick-reply window when it's in focus
*
* Usage:
* $config['additional_javascript'][] = 'js/jquery.min.js';
* $config['additional_javascript'][] = 'js/comment-toolbar.js';
*/
if (active_page == 'thread' || active_page == 'index') {
$(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: {
displayText: 'i',
altText: 'italics',
styleCSS: 'font-style: italic;',
options: {
prefix: "''",
suffix: "''"
},
edit: function (box, options) {
wrapSelection(box, options);
},
shortcutKey: 'i'
},
under: {
displayText: 'U',
altText: 'underline',
styleCSS: 'text-decoration: underline;',
options: {
prefix: '__',
suffix: '__'
},
edit: function (box, options) {
wrapSelection(box, options);
},
shortcutKey: 'u'
},
spoiler: {
displayText: 'spoiler',
altText: 'mark as spoiler',
styleCSS: '',
options: {
prefix: '[spoiler]',
suffix: '[/spoiler]'
},
edit: function (box, options) {
wrapSelection(box, options);
},
shortcutKey: 's'
},
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: {
displayText: 'strike',
altText: 'strikethrough',
styleCSS: 'text-decoration: line-through;',
options: {
prefix: '~~',
suffix: '~~'
},
edit: function (box, options) {
wrapSelection(box, options);
}
},
heading: {
displayText: 'heading',
altText: 'redtext',
styleCSS: 'color: #AF0A0F; font-weight: bold;',
options: {
prefix: '==',
suffix: '==',
exclusiveLine: true
},
edit: function (box, options) {
wrapSelection(box, options);
}
}
};
var key, name, altText, ele;
var strBuilder = [];
var subStr = '';
var styleRules = '';
//not exactly mine
var wrapSelection = function (box, options) {
if (box == null) {
return;
}
var prefix = options.prefix;
var suffix = options.suffix;
var multiline = options.multiline || false;
var exclusiveLine = options.exclusiveLine || false;
//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 breakSpace = ["\r","\n"];
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 = beforeSelection.length -1;
while (cursor >= 0 && breakSpace.indexOf(beforeSelection.charAt(cursor)) == -1) {
cursor--;
}
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 < afterSelection.length && breakSpace.indexOf(afterSelection.charAt(cursor)) == -1) {
cursor++;
}
selectedText += afterSelection.substring(0, cursor);
afterSelection = afterSelection.substring(cursor);
}
box.value = beforeSelection + prefix + selectedText + suffix + trailingSpace + afterSelection;
box.selectionEnd = beforeSelection.length + prefix.length + selectedText.length;
if (selectionStart === selectionEnd) {
box.selectionStart = box.selectionEnd;
} else {
box.selectionStart = beforeSelection.length + prefix.length;
}
box.scrollTop = scrollTop;
};
/* 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 +')';
}
altText = 'title="'+ altText +'"';
}
subStr = '<a href="javascript:void(0)" '+ altText +' id="tf-'+ ele +'">'+ name +'</a>';
strBuilder.push(subStr);
} else {
continue;
}
}
$( 'textarea[name="body"]' ).before( '<div class="tf-toolbar"></div>' );
$( '.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 + '}';
}
}
//add CSS rule to user's custom CSS if it exist
if ($( '.user-css' ).length !== 0) {
$( '.user-css' ).append( styleRules );
} else {
$( 'body' ).append( '<style>'+ styleRules +'\n</style>' );
}
/* 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();
}
}
}
});
$( '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' );
}
});
$( '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';
// }
// });
});
}