// ==UserScript== // @name stackexchange-quickcomment2 // @namespace http://keyboardfire.com/ // @grant none // @license MIT // @description Quick SE comments for quick SE people. (Vastly improved) // @version 1.0.0 // @match *://*.stackexchange.com/* // @match *://*.stackoverflow.com/* // @match *://*.superuser.com/* // @match *://*.serverfault.com/* // @match *://*.askububtu.com/* // @match *://*.stackapps.com/* // @match *://*.mathoverflow.net/* // ==/UserScript== var userscript = function($) { var qc2; function updateLS() { localStorage.qc2 = JSON.stringify(qc2); } if (localStorage.qc2) { qc2 = JSON.parse(localStorage.qc2); } else { qc2 = { trigger: { altKey: true, ctrlKey: false, shiftKey: false, which: 88 }, data: { naa: 'This is not an answer.', welcome: 'Welcome to $SITENAME!', lorem: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' } }; updateLS(); } $(function() { $('<style>' + '.qc2_selected { background-color: #FF0; }' + '.qc2_popup { background-color: #E0EAF1; text-align: left; }' + '.qc2_popup > * { margin: 5px; word-wrap: break-word; }' + '</style>').appendTo('head'); var dialog = $('<div>') .attr('id', 'qc2_dialog') .appendTo(document.body) .css({ position: 'absolute', width: '250px', height: '350px', textAlign: 'left', overflowX: 'hidden', overflowY: 'scroll' }) .addClass('qc2_popup') .append($('<button>') .text('settings') .mousedown(showSettings) ) .append($('<input>') .attr('type', 'text') .keydown(function(e) { switch (e.which) { case 27: // esc hideDialog(); break; case 40: // down arrow e.preventDefault(); var toChange = $('.qc2_selected').nextAll('div:visible').eq(0); if (toChange.length) { $('.qc2_selected').removeClass('qc2_selected'); toChange.addClass('qc2_selected'); } break; case 38: // up arrow e.preventDefault(); var toChange = $('.qc2_selected').prevAll('div:visible').eq(0); if (toChange.length) { $('.qc2_selected').removeClass('qc2_selected'); toChange.addClass('qc2_selected'); } break; } }) .keyup(function(e) { if (e.which === 13) { // enter var cmt = dialog.data('comment'); var str = $('span:last', '.qc2_selected').text() .replace(/\$SITENAME/g, StackExchange.options.site.name) .replace(/\$SITEURL/g, window.location.hostname); cmt.val(cmt.val() + str); hideDialog(); } else if (e.which !== 40 && e.which !== 38) { var txt = $('input', dialog).val(), needToUpdateSelected = !$('>div:visible').length; $('>div span:first-child', dialog).each(function() { if (this.textContent.indexOf(txt) === -1) { $(this).parent().hide(); if ($(this).parent().hasClass('qc2_selected')) { needToUpdateSelected = true; } } else { $(this).parent().show(); } }); if (needToUpdateSelected) { $('.qc2_selected').removeClass('qc2_selected'); $('>div:visible:first', dialog).addClass('qc2_selected'); } } }) .blur(hideDialog) ) .hide(); // I don't know why I have to do this // but it works, so I'll just go with it dialog[0].scrollTop = 0; reloadDialogData(); $(document).on('keydown', 'textarea[name="comment"]', function(e) { if (qc2.trigger.altKey === e.altKey && qc2.trigger.ctrlKey === e.ctrlKey && qc2.trigger.shiftKey === e.shiftKey && qc2.trigger.which === e.which) { e.preventDefault(); showDialog($(this)); } }); }); function showDialog(commentBox) { $('#qc2_dialog').data('comment', commentBox).css({ top: commentBox.offset().top, left: commentBox.offset().left }).show('fast'); $('#qc2_dialog input').focus(); } function hideDialog() { $('#qc2_dialog>div').show().removeClass('qc2_selected'); $('#qc2_dialog>div:first').addClass('qc2_selected'); $('#qc2_dialog input').val(''); $('#qc2_dialog').hide().data('comment').focus(); } function reloadDialogData() { $('#qc2_dialog>div').remove(); for (var k in qc2.data) { var v = qc2.data[k]; $('#qc2_dialog').append(kvpair(k, v)); } $('#qc2_dialog>div:first').addClass('qc2_selected'); } function showSettings() { var settingsDiv = $('<div>') .css({ position: 'fixed', top: '50%', left: '50%', width: '400px', height: '400px', margin: '-200px 0px 0px -200px', overflowX: 'hidden', overflowY: 'scroll' }) .addClass('qc2_popup') .appendTo(document.body) .append($('<button>') .text('Done') .click(function() { settingsDiv.remove(); }) ) .append($('<br>')) .append($('<label>') .attr('for', 'qc2_trigger_input') .text('Trigger:') ) .append($('<input>') .attr('id', 'qc2_trigger_input') .attr('type', 'text') .val(triggerStr()) .keydown(function(e) { e.preventDefault(); qc2.trigger = { altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, which: e.which }; updateLS(); $(this).val(triggerStr()); }) ); for (var k in qc2.data) { var v = qc2.data[k]; settingsDiv.append(kvpair(k, v) .append(linkbtn('edit', function(e) { settingsDiv.remove(); var editKey = $(e.target).siblings(':first').text(); getStr('New value for ' + editKey + ':', function(str) { qc2.data[editKey] = str; updateLS(); reloadDialogData(); showSettings(); }, qc2.data[editKey]); }) ) .append(linkbtn('delete', function(e) { settingsDiv.remove(); var editKey = $(e.target).siblings(':first').text(); getStr('Are you sure you want to remove ' + editKey + '? (yes/no)', function(str) { if (str === 'yes') { delete qc2.data[editKey]; updateLS(); reloadDialogData(); } showSettings(); }); }) ) ); } settingsDiv.append(linkbtn('new...', function() { settingsDiv.remove(); getStr('New shortcut key:', function(newKey) { getStr('New value for ' + newKey + ':', function(newVal) { qc2.data[newKey] = newVal; updateLS(); reloadDialogData(); showSettings(); }); }); }) ) .append(linkbtn('export...', function() { settingsDiv.remove(); getStr('Copy the following text:', function() {}, JSON.stringify(qc2)); }) ) .append(linkbtn('import...', function() { settingsDiv.remove(); getStr('Paste exported text here:', function(str) { qc2 = JSON.parse(str); updateLS(); reloadDialogData(); }); }) ); } function triggerStr() { return ( (qc2.trigger.altKey ? 'Alt+' : '') + (qc2.trigger.ctrlKey ? 'Ctrl+' : '') + (qc2.trigger.shiftKey ? 'Shift+' : '') + String.fromCharCode(qc2.trigger.which) ); } function getStr(query, callback, placeholder) { if (!placeholder) placeholder = ''; var getDiv = $('<div>') .css({ position: 'fixed', top: '50%', left: '50%', width: '400px', marginLeft: '-200px' }) .addClass('qc2_popup') .appendTo(document.body) .append($('<div>') .text(query) ) .append($('<input>') .val(placeholder) .attr('type', 'text') .keydown(function(e) { if (e.which === 13) { $(this).parent().remove(); callback($(this).val()); } }) ); getDiv.css({ height: getDiv.height() + 'px', marginTop: '-' + (getDiv.height() / 2) + 'px' }); $('input', getDiv).focus().select(); } function linkbtn(text, callback) { return $('<a>') .attr('href', '#') .text(text) .css('padding-left', '5px') .click(function(e) { e.preventDefault(); callback(e); }); } function kvpair(k, v) { return $('<div>') .css({ borderBottom: '1px dotted grey', padding: '2px 0px' }) .append($('<span>') .text(k) .css({ fontWeight: 'bold', paddingRight: '5px' }) ) .append($('<span>') .text(v) .css({ color: 'grey' }) ); } }; var el = document.createElement('script'); el.type = 'text/javascript'; el.text = '(' + userscript + ')(jQuery);'; document.head.appendChild(el);