diff --git a/README.md b/README.md index 76a714b..799a923 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [](https://gitter.im/soscripted/sox?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -### SOX v2.1.0 +### SOX v2.2.0 Stack Overflow Extras (*SOX*) is a project that stemmed from the [Stack Overflow Optional Features (SOOF)](https://github.com/shu8/Stack-Overflow-Optional-Features) project. @@ -16,9 +16,9 @@ Note: This project has no relation to Stack Overflow or Stack Exchange; it is si - Official Version: [install](https://github.com/soscripted/sox/raw/v2.1.0/sox.user.js). [view source](https://github.com/soscripted/sox/blob/v2.1.0/sox.user.js) - Development Version: [install](https://github.com/soscripted/sox/raw/dev/sox.user.js). [view source](https://github.com/soscripted/sox/blob/dev/sox.user.js) -3. Go to any site in the Stack Exchange Network (eg. [Super User](http://superuser.com/) or [Stack Overflow](http://stackoverflow.com/)). You will automatically be asked to choose and save your settings. A toggle button (gears icon) will be added to your topbar where you can change these later on: +3. Go to any site in the Stack Exchange Network (e.g. [Super User](http://superuser.com/) or [Stack Overflow](http://stackoverflow.com/)). You will automatically be asked to choose and save your settings. A toggle button (gears icon) will be added to your topbar where you can change these later on: - + ## What features are included? @@ -28,6 +28,10 @@ A full list of all the features is available on the SOX wiki page [here](https:/ Please post bugs and feature requests as issues on [Github](https://github.com/soscripted/sox), where we can track them easily and push updates quickly. Please **do not** post them as answers on Stack Apps -- they are much harder to manage! +## Contribute + +Pull requests to add new features or improve the existing ones, etc. are welcome! Please head to the [Contributing](https://github.com/soscripted/sox/wiki/Contributing) wiki page to get started. + ## Changes Please see the change log [at Stack Apps](http://stackapps.com/a/6358). diff --git a/sox.common.js b/sox.common.js index dbda215..a7b2f0a 100644 --- a/sox.common.js +++ b/sox.common.js @@ -129,7 +129,7 @@ sox.error('SOX Error: BACKOFF: ' + d.backoff); } else if (d.error_id == 502) { sox.error('THROTTLE VIOLATION', d); - } else if (d.error_id == 403) { + } else if (d.error_id == 403) { sox.warn('Access token invalid! Opening window to get new one'); window.open('https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/'); alert('Your access token is no longer valid. A window has been opened to request a new one.'); @@ -271,9 +271,9 @@ matchWithPattern: function(pattern, urlToMatchWith) { //commented version @ https://jsfiddle.net/shub01/t90kx2dv/ if (pattern == 'SE1.0') { //SE.com && Area51.SE.com special checking if (urlToMatchWith) { - if (urlToMatchWith.match(/https?:\/\/stackexchange\.com\/?/) || sox.location.matchWithPattern('*://area51.stackexchange.com/*')) return true; + if (urlToMatchWith.match(/https?:\/\/stackexchange\.com\/?/) || (sox.location.matchWithPattern('*://area51.stackexchange.com/*') && sox.site.href.indexOf('.meta.') === -1)) return true; } else { - if (location.href.match(/https?:\/\/stackexchange\.com\/?/) || sox.location.matchWithPattern('*://area51.stackexchange.com/*')) return true; + if (location.href.match(/https?:\/\/stackexchange\.com\/?/) || (sox.location.matchWithPattern('*://area51.stackexchange.com/*') && sox.site.href.indexOf('.meta.') === -1)) return true; } return false; } @@ -324,7 +324,7 @@ if (sox.site.type == sox.site.types.chat) { return Chat.RoomUsers.current().name; } else { - var $uname = sox.NEW_TOPBAR ? $('body > header > div > div.-actions > a > div.gravatar-wrapper-24') : $('body > div.topbar > div > div.topbar-links > a > div.gravatar-wrapper-24'); + var $uname = $('.top-bar div.gravatar-wrapper-24'); //used to be $('body > div.topbar > div > div.topbar-links > a > div.gravatar-wrapper-24'); return ($uname.length ? $uname.attr('title') : false); } }, @@ -340,4 +340,4 @@ } }; -})(window.sox = window.sox || {}, jQuery); +})(window.sox = window.sox || {}, jQuery); \ No newline at end of file diff --git a/sox.css b/sox.css index 5374385..5721d88 100644 --- a/sox.css +++ b/sox.css @@ -2,16 +2,13 @@ #sox-settings-dialog { top: 34px; - left: 230px; + right: 208px; min-height: calc(100vh - 90px); width: 550px; display: none; } #sox-settings-dialog.new-topbar { - right: 192px; - left: inherit !important; - top: 50px; min-height: calc(100vh - 75px); } @@ -208,16 +205,16 @@ } .metaNewQuestionAlert-diamondOn { - background-position: -218px -86px; + background-position: -218px -82px; } .metaNewQuestionAlert-diamondOff { - background-position: -138px -86px; + background-position: -138px -82px; } #metaNewQuestionAlertDialog { - top: 34px; - left: 264px; + top: 50px; + right: 242px; width: 377px; } @@ -403,64 +400,8 @@ li.fixedTopbar-siteLink { } -/*enhancedEditor (enhanced_editor folder)*/ - -.enhancedEditor-centered { - width: 40%; - z-index: 1001; - top: 190px; - left: 615.5px; - display: inline-block; - margin-top: -95.5px; - margin-left: -216px; - overflow: auto; - height: 70%; -} - -.ownURL, .ownImage { - border-radius: 5px; - width: 70%; - padding: 5px; -} - -.go { - padding: 5px; - border-radius: 5px; - color: black; - background-color: lightgreen; -} - -.DDG-go { - float: right; -} - -hr.or { - border: 0; - border-top: 1px solid whitesmoke; - text-align: center; -} - -hr.or:after { - content: "or..."; - display: inline-block; - position: relative; - top: -0.7em; - font-size: 1.1em; - padding: 0.2em; - background: whitesmoke; -} - -.DDG-container { - background-color: whitesmoke; - border-radius: 10px; - padding: 2%; -} - -.DDG-credit { - font-size: 0.8em; -} - -.enhancedEditor-toolbar { +/*findAndReplace*/ +.findReplaceToolbar { display: block; background-color: transparent; padding: 0 12px; @@ -469,36 +410,20 @@ hr.or:after { border-top: 0; } -.enhancedEditor-toolbar>span { - cursor: pointer; -} - -.enhancedEditor-toolbar>span+span { - margin-left: 2px; -} - -.enhancedEditor-closeDialog { - float: left; - margin-right: 10px; - font-size: 1.2em; +#findReplace { cursor: pointer; } -.enhancedEditor-toolbar.findReplace>input[type='text'] { +.findReplaceToolbar.findReplace>input[type='text'] { height: 10px; width: 25%; } -.enhancedEditor-toolbar.findReplace>input[type='button'] { +.findReplaceToolbar.findReplace>input[type='button'] { width: 10%; height: 100%; } -.enhancedEditor-asLinkContainer { - display: block; -} - - /*chatEasyAccess - for the links (b elements)*/ .chatEasyAccess b { @@ -528,10 +453,8 @@ hr.or:after { #downvotedPostsEditAlertButton { background-image: none; - padding-top: 10px; font-size: 14px; color: #858c93; - height: 24px !important; min-width: 34px; cursor: pointer; } @@ -553,8 +476,7 @@ hr.or:after { } #downvotedPostsEditAlertDialog { - top: 34px; - left: 264px; + right: 273px; width: 377px; display: none; } @@ -569,6 +491,7 @@ hr.or:after { .soxReplyLink { cursor: pointer; + float: right; } diff --git a/sox.dialog.html b/sox.dialog.html index 9f03ce3..fb58f5d 100644 --- a/sox.dialog.html +++ b/sox.dialog.html @@ -1,4 +1,4 @@ -
'; 'style': 'display:none' }); - if ($('#metaNewQuestionAlertDialog').length) $dialog.css('left', '297px'); - $button.append($count).append($icon).appendTo('div.network-items'); - - $dialog.css('left', $('#downvotedPostsEditAlertButton').position().left).append($header).append($content.append($posts)).prependTo('.js-topbar-dialog-corral'); + $button.append($count).append($icon); - $('#downvotedPostsEditAlertButton').hover(function() { //open on hover, just like the normal dropdowns - if ($('.topbar-icon').not('#downvotedPostsEditAlertButton').hasClass('topbar-icon-on')) { - $('.topbar-dialog').hide(); - $('.topbar-icon').removeClass('topbar-icon-on').removeClass('icon-site-switcher-on'); - $(this).addClass('topbar-icon-on'); - $('#downvotedPostsEditAlertDialog').show(); - } - }, function() { - $('.topbar-icon').not('#downvotedPostsEditAlertButton').hover(function() { - if ($('#downvotedPostsEditAlertButton').hasClass('topbar-icon-on')) { - $('#downvotedPostsEditAlertDialog').hide(); - $('#downvotedPostsEditAlertButton').removeClass('topbar-icon-on'); - var which = $(this).attr('class').match(/js[\w-]*\b/)[0].split('-')[1]; - if (which != 'site') { //site-switcher dropdown is slightly different - $('.' + which + '-dialog').not('#sox-settings-dialog, #metaNewQuestionAlertDialog, #downvotedPostsEditAlertDialog').show(); - $(this).addClass('topbar-icon-on'); - } else { - $('.siteSwitcher-dialog').show(); - $(this).addClass('topbar-icon-on').addClass('icon-site-switcher-on'); //icon-site-switcher-on is special to the site-switcher dropdown (StackExchange button) - } - } - }); - }); + if (sox.NEW_TOPBAR) { + $('.top-bar .-container .-secondary .-item:eq(1)').after($('').addClass('-item').append($button)); + } else { + $button.appendTo('div.network-items'); + $dialog.css('left', $('#downvotedPostsEditAlertButton').position().left); + } + $dialog.css('top', $('.top-bar').height()); + if ($('#downvotedPostsEditAlertButton').length) $('.js-topbar-dialog-corral').append($dialog); $(document).click(function(e) { //close dialog if clicked outside it var $target = $(e.target), @@ -1793,7 +1732,6 @@ Toggle SBS?'; } }); - var websocketSiteCodes = { "3dprinting": "640", "academia": "415", @@ -2051,6 +1989,7 @@ Toggle SBS?'; addEditNotification(o.url, o.title, o.sitename, i, false, o.editor, o.editor_link, o.edit_date, o.type, postsToCheck); }); + console.log(postsToCheck); if (!$.isEmptyObject(postsToCheck)) { sox.debug(postsToCheck); $.each(postsToCheck, function(i, o) { @@ -2089,6 +2028,8 @@ Toggle SBS?'; }; } }); + } else { + $dialog.text('empty'); } }, @@ -2494,8 +2435,8 @@ Toggle SBS?'; var div = $('', { id: 'loggedInReminder', - style: 'position: fixed; right: 0; bottom: 50px; background-color: rgba(200, 200, 200, 1); width: 200px; height: 35px; text-align: center; padding: 3px; color: red;', - html: 'You are not logged in. You should log in to continue enjoying SE.' + style: 'position: fixed; right: 0; bottom: 50px; background-color: rgba(200, 200, 200, 1); width: 200px; text-align: center; padding: 5px; color: black; font-weight:bold', + html: 'SOX: You are not logged in. You should log in to continue enjoying SE.' }); function checkAndAddReminder() { @@ -2509,9 +2450,20 @@ Toggle SBS?'; setInterval(checkAndAddReminder, 300000); //5 mins }, - disableOwnPostVoteButtons: function() { - // Description: disables vote buttons on your own posts + disableVoteButtons: function() { + // Description: disables vote buttons on posts you cannot vote on + // https://github.com/soscripted/sox/issues/309 + + //Grays out votes, vote count for deleted posts + if ($('.deleted-answer').length) { + $('.deleted-answer .vote-down-off, .deleted-answer .vote-up-off, .deleted-answer .vote-count-post').css({ + 'cursor': 'default', + 'opacity': '0.5', + 'pointer-events': 'none' //disables the anchor tag (jQuery off() doesn't work) + }); + } + //Grays out votes on own posts $('.answer, .question') .find('.user-details:last a') .filter('a[href*=' + sox.user.id + ']') @@ -2524,7 +2476,29 @@ Toggle SBS?'; 'opacity': '0.5', 'pointer-events': 'none' //disables the anchor tag (jQuery off() doesn't work) }) - .attr('title', 'You cannot vote on your own posts.'); + .parent().attr('title', 'You cannot vote on your own posts.'); //.parent() is to add the title to the .vote div + + //Grays out votes on posts which haven't been edited in the last 5 minutes + $('.answer, .question').not('.owner').each(function() { + if ($(this).find('.post-signature').length === 2) { //if there's only 1, that's the post owner, no edits have been made yet! + if (!$(this).find('.vote-up-on, .vote-down-on').length) return; //if they haven't voted, no point checking + var $timeSpan = $(this).find('.user-action-time:first span:last'), + lastEditedTime = new Date($timeSpan.attr('title')), + timeDifference = new Date() - lastEditedTime; + if (timeDifference / 1000 / 60 > 5) { //divide by 1000 to get seconds, divide by 60 to get minutes + $(this).find('.votecell .vote a[class*="vote"]') + .not('[id*="vote-accept"]') + .removeClass('sox-better-css') + .css({ + 'cursor': 'default', + 'opacity': '0.5', + 'pointer-events': 'none' //disables the anchor tag (jQuery off() doesn't work) + }); + $(this).find('.vote').attr('title', 'You cannot change your vote on posts that were last edited more than 5 minutes ago.'); + } + } + }); + }, replyToOwnChatMessages: function() { @@ -2753,7 +2727,12 @@ Toggle SBS?'; }, openLinksInNewTab: function(settings) { - settings = settings.linksToOpenInNewTab.replace(' ', '').split(','); + // Description: Open any links to the specified sites in a new tab by default + + settings = settings.linksToOpenInNewTab; + if (!settings) return; + + settings = settings.replace(' ', '').split(','); if (settings.length) { //https://github.com/soscripted/sox/issues/300 $('.post-text a').each(function() { var href = $(this).attr('href'); @@ -2768,6 +2747,8 @@ Toggle SBS?'; }, showQuestionStateInSuggestedEditReviewQueue: function() { + // Description: Show question's current state in the suggested edit review queue (duplicate, off-topic, etc.) + $(document).on('sox-new-review-post-appeared', function() { if ($('#sox-showQuestionStateInSuggestedEditReviewQueue-checked').length) return; //already checked var postId = $('.summary h2 a').attr('href').split('/')[2]; @@ -2788,6 +2769,76 @@ Toggle SBS?'; } }, 'creation&filter=!-MOiNm40B3fle5H6oLVI3nx6UQo(vNstn'); }); + }, + + addTimelineAndRevisionLinks: function() { + // Description: Add timeline and revision links to the bottom of each post for quick access to them + + $('.question, .answer').each(function() { + $(this).find('.post-menu').append($('', { + 'href': '//' + sox.site.url + '/posts/' + sox.site.href.split('/')[4] + '/revisions', + 'text': 'revisions' + })).append($('', { + 'href': '//' + sox.site.url + '/posts/' + sox.site.href.split('/')[4] + '/timeline', + 'text': 'timeline' + })); + }); + }, + + findAndReplace: function() { //Salvaged from old 'enhanced editor' feature + // Description: adds a 'find and replace' option to the markdown editor + + function startLoop() { + $('textarea[id^="wmd-input"].processed').each(function() { + main($(this).attr('id')); + }); + + $('.edit-post').click(function() { + var $that = $(this); + sox.helpers.observe('#wmd-redo-button-' + $that.attr('href').split('/')[2], function() { + main($that.parents('table').find('.inline-editor textarea.processed').attr('id')); + }); + }); + } + + function main(wmd) { + var s = '#' + wmd; //s is the selector we pass onto each function so the action is applied to the correct textarea (and not, for example the 'add answer' textarea *and* the 'edit' textarea!) + if ($(s).parents('.wmd-container').find('#findReplace').length) return; + + $('.wmd-button-bar').css('margin-top', '0'); //https://github.com/soscripted/sox/issues/203 + + $(s).before(""); + + $(document).on('click', '#findReplace', function(e) { + if ($('.findReplaceInputs').length) { + $('.findReplaceInputs').remove(); + } else { + $(this).parent().append(""); + } + $(document).on('click', '.findReplaceToolbar #replaceGo', function() { + var regex = new RegExp($('.findReplaceToolbar #find').val(), $('.findReplaceToolbar #modifier').val()); + var oldval = $(this).parent().parent().parent().find('textarea').val(); + var newval = oldval.replace(regex, $('.findReplaceToolbar #replace').val()); + $(this).parent().parent().parent().find('textarea').val(newval); + + var Stack = (typeof StackExchange === "undefined" ? window.eval('StackExchange') : StackExchange); + if (Stack.MarkdownEditor) Stack.MarkdownEditor.refreshAllPreviews(); + }); + e.preventDefault(); + e.stopPropagation(); + }); + + $(s).keydown(function(e) { + if (e.which == 70 && e.ctrlKey) { //ctrl+f (find+replace) + $('#findReplace').trigger('click'); + e.stopPropagation(); + e.preventDefault(); + return false; + } + }); + } + $(document).on('sox-edit-window', startLoop); + startLoop(); } }; })(window.sox = window.sox || {}, jQuery); diff --git a/sox.user.js b/sox.user.js index dac8934..8cf8b10 100644 --- a/sox.user.js +++ b/sox.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name Stack Overflow Extras (SOX) // @namespace https://github.com/soscripted/sox -// @version 2.1.0 +// @version 2.2.0 // @description Extra optional features for Stack Overflow and Stack Exchange sites // @contributor ᴉʞuǝ (stackoverflow.com/users/1454538/) // @contributor ᔕᖺᘎᕊ (stackexchange.com/users/4337810/) @@ -92,6 +92,7 @@ featureInfo = JSON.parse(GM_getResourceText('featuresJSON')); try { + sox.debug('init', sox, sox.dialog); sox.dialog.init({ version: sox.info.version, features: featureInfo, @@ -193,10 +194,10 @@ //and detects that page and saves it automatically. //this seems to be a much cleaner and easier-to-debug method! - window.open('https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/'); - alert('To complete the SOX installation please follow the instructions in the window that has been opened for you to receive your access token'); + var askUserToAuthorise = window.confirm('To complete the SOX installation, you need to get an access token! Please press "OK" to continue and follow the instructions in the window that opens.'); + if (askUserToAuthorise) window.open('https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/'); sox.warn('Please go to the following URL to get your access token for certain SOX features', 'https://stackexchange.com/oauth/dialog?client_id=7138&scope=no_expiry&redirect_uri=http://soscripted.github.io/sox/'); } } sox.ready(init); -})(window.sox = window.sox || {}, jQuery); +})(window.sox = window.sox || {}, jQuery); \ No newline at end of file