diff --git a/README.md b/README.md index 76a714b..799a923 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Join the chat at https://gitter.im/soscripted/sox](https://badges.gitter.im/soscripted/sox.svg)](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: -![newdialog](https://cloud.githubusercontent.com/assets/12533449/14296194/c732b1b2-fb2d-11e5-9563-1e34b12eada9.png) +![newdialog](https://i.stack.imgur.com/q93pM.jpg) ## 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 @@ -
+

sox settings v1.0.3dev diff --git a/sox.dialog.js b/sox.dialog.js index 8c5b0b9..4ce7827 100644 --- a/sox.dialog.js +++ b/sox.dialog.js @@ -3,7 +3,10 @@ sox.dialog = { init: function(options) { - if (!$('.top-bar').length) return; + + if (!$('.top-bar').length) { + return; + } sox.debug('initializing SOX dialog'); var version = options.version, @@ -255,50 +258,6 @@ class: 'fa fa-cogs' }); - //open dialog on hover if another dialog is already open - $soxSettingsButton.hover(function() { //https://github.com/soscripted/sox/issues/44, open on hover, just like the normal dropdowns - if ($('.topbar-icon').not('#soxSettingsButton').hasClass('topbar-icon-on')) { - $('.topbar-dialog').hide(); - $('.topbar-icon-on').removeClass('topbar-icon-on').removeClass('icon-site-switcher-on'); - $(this).addClass('topbar-icon-on'); - $soxSettingsDialog.show(); - } - }, function() { - $('.topbar-icon').not('#soxSettingsButton').hover(function(e) { - var $button = $(this); - if ($('#soxSettingsButton').hasClass('topbar-icon-on')) { - $soxSettingsDialog.hide(); - $('#soxSettingsButton').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'); - //repeated clicks are INTENDED, hacky fix for https://github.com/soscripted/sox/issues/272 - $button[0].click(); - $button[0].click(); - } else { - if ($(this).css('top') != '34px') { - $('.siteSwitcher-dialog').css('top', '34px').css('left', '0px'); - } - $('.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) - } - } else { - if (!$(e.toElement).is('.icon-site-switcher')) { - if ($('.siteSwitcher-dialog').is(':visible')) { - $('.siteSwitcher-dialog').hide(); - } - } - } - }, function(e) { - if ($(e.toElement).is('.topbar-icon')) { //only hide the StackExchange dialog if the un-hover is onto another topbar dialog button - if ($('.siteSwitcher-dialog').is(':visible')) { - $('.siteSwitcher-dialog').hide(); - } - } - }); - }); - //close dialog if clicked outside it $(document).click(function(e) { //close dialog if clicked outside it var $target = $(e.target), @@ -347,14 +306,17 @@ // add dialog to corral and sox button to topbar $soxSettingsButton.append($icon); - if (sox.NEW_TOPBAR) { - console.log('asd'); - $('.secondary-nav .-list').prepend($('
  • ').addClass('-item').append($soxSettingsButton)); - $soxSettingsDialog.addClass('new-topbar'); - } else { - $soxSettingsButton.appendTo('div.network-items'); - $soxSettingsDialog.css('left', $('#soxSettingsButton').position().left); + $('.top-bar .-container .-secondary .-item:eq(1)').after($('
  • ').addClass('-item').append($soxSettingsButton)); //https://github.com/soscripted/sox/issues/310 + if (sox.site.href.indexOf('area51.meta') !== -1) { //area 51 discussions is different + $soxSettingsButton.parent().css({ + 'top': '7px', + 'left': '9px' + }); } + $soxSettingsDialog.addClass('new-topbar'); + $soxSettingsDialog.css('top', $('.top-bar').height()); + + //'$('#soxSettingsButton').position().left' from @IStoleThePies: https://github.com/soscripted/sox/issues/120#issuecomment-267857625: //only add dialog if button was added successfully @@ -363,4 +325,4 @@ } }; -})(window.sox = window.sox || {}, jQuery); +})(window.sox = window.sox || {}, jQuery); \ No newline at end of file diff --git a/sox.enhanced_editor.js b/sox.enhanced_editor.js deleted file mode 100644 index 55a37aa..0000000 --- a/sox.enhanced_editor.js +++ /dev/null @@ -1,254 +0,0 @@ -/*jshint multistr: true */ -(function(sox, $, undefined) { - 'use strict'; - - sox.enhancedEditor = { - initLoop: function() { - $('textarea[id^="wmd-input"].processed').each(function() { - sox.enhancedEditor.init($(this).attr('id')); - }); - - $('.edit-post').click(function() { - var $that = $(this); - sox.helpers.observe('#wmd-redo-button-' + $that.attr('href').split('/')[2], function() { - sox.enhancedEditor.init($that.parents('table').find('.inline-editor textarea.processed').attr('id')); - }); - }); - }, - - startFeature: function() { - $(document).on('sox-edit-window', sox.enhancedEditor.initLoop); - sox.enhancedEditor.initLoop(); - }, - - init: function(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('.enhancedEditor-toolbar').length) return; - sox.enhancedEditor.startInsertLink(s); - sox.enhancedEditor.betterTabKey(s); - sox.enhancedEditor.keyboardShortcuts(s); - $('.wmd-button-bar').css('margin-top', '0'); //https://github.com/soscripted/sox/issues/203 - - $(s).before(" Find & Replace | Auto correct"); - - $('#findReplace').click(function(e) { - sox.enhancedEditor.findReplace($(this).parent().attr('id').split('|')[1]); - e.preventDefault(); - e.stopPropagation(); - }); - $('#autoCorrect').click(function(e) { - sox.enhancedEditor.autoCorrect($(this).parent().attr('id').split('|')[1]); - e.preventDefault(); - e.stopPropagation(); - }); - $(document).on('click', '.enhancedEditor-closeDialog', function() { - $(this).parent().hide(); - }); - - $(document).click(function(event) { - //doesn't work with #enhancedEditor-aceEditor for some reason... so skip it - if (!$(event.target).closest('#enhancedEditor-insertLinkDialog, #enhancedEditor-insertImageDialog').length) { - $('#enhancedEditor-insertLinkDialog, #enhancedEditor-insertImageDialog').hide(); - } - }); - }, - - startInsertLink: function(s) { - var linkDiv = ""; - $('body').append(linkDiv); - - setTimeout(function() { - $('#wmd-link-button > span').click(function(e) { - $('#DDG-header').html(''); - $('#DDG-text').html(''); - $('#DDG-credit a').attr('href', 'http://google.com'); - $('#enhancedEditor-insertLinkDialog').show(500); - setTimeout(function() { - var query = $(s).getSelection(); - - $.getJSON("http://api.duckduckgo.com/?q=" + query.text + "&format=json&t=stackExchangeEditorPro&callback=?", function(json) { - $('#DDG-header').append("" + json.Heading + ""); - $('#DDG-text').append(json.Abstract); - $('.DDG-credit a').attr('href', json.AbstractURL); - }); - - $('#ownGo').click(function() { - sox.enhancedEditor.addLink(query, $(this).prev().val(), s); - }); - $('#suggestGo').click(function() { - sox.enhancedEditor.addLink(query, $('#DDG-header a').attr('href'), s); - }); - }, 1000); - e.stopPropagation(); - e.preventDefault(); - return false; - }); - }, 3000); - }, - - betterTabKey: function(s) { - $(s).on('keydown', function(e) { - if (e.which === 9) { //http://stackoverflow.com/a/25430815/3541881 - e.preventDefault(); - var start = this.selectionStart; - var end = this.selectionEnd; - var val = this.value; - var selected = val.substring(start, end); - var re = /^/gm; - var count = selected.match(re).length; - - - this.value = val.substring(0, start) + selected.replace(re, '\t') + val.substring(end); - this.selectionStart = start; - this.selectionEnd = end + count; - } - }); - }, - - findReplace: function(s) { - if ($('.enhancedEditor-toolbar.findReplace').length) { - $('.enhancedEditor-toolbar.findReplace').remove(); - } else { - $(s).prev().after("
    "); - } - $(document).on('click', '.findReplace #replaceGo', function() { - var regex = new RegExp($('.findReplace #find').val(), $('.findReplace #modifier').val()); - var oldval = $(s).val(); - var newval = oldval.replace(regex, $('.findReplace #replace').val()); - $(s).val(newval); - sox.enhancedEditor.refreshPreview(); - }); - }, - - autoCorrect: function(s) { - var oldVal = $(s).val(); - var newVal = oldVal.replace(/\bi\b/g, "I") //capitalise 'I' - .replace(/\.{3,}/gi, "...") //truncate ellipses - .replace(/(\.{3,})?([,.!?;:])(\S)/g, "$1 $2") //add space after punctuation - .replace(/\s(\?|!)/g, "$1") //remove space before !/? - .replace(/\bwud\b/gi, "would") //wud->would - .replace(/\bcud\b/gi, "could") //cud->could - .replace(/\bshud\b/gi, "should") //shud->should - .replace(/\b(plz|pls)\b/gi, "please") //plz/pls->please - .replace(/\bi'(ve|ll|m|d)\b/gi, "I'$1") //i'(anything)->I'(anything) - .replace(/\bu\b/gi, "you") //u->you - .replace(/\bure?\b/gi, "your") //ur(e)->your - .replace(/\b(d)ont\b/gi, "$1on't") - .replace(/\b(t)eh\b/gi, "$1he") - .replace(/\b(()?:ubunto|ubunut|ubunutu|ubunu|ubntu|ubutnu|uuntu|unbuntu|ubunt|ubutu)\b/gi, "$1buntu") - .replace(/\b(a)rent\b/gi, "$1ren't") - .replace(/\b(c)ant\b/gi, "$1an't") - .replace(/\b(c)ouldnt\b/gi, "$1ouldn't") - .replace(/\b(d)idnt\b/gi, "$1idn't") - .replace(/\b(d)oesnt\b/gi, "$1oesn't") - .replace(/\b(d)ont\b/gi, "$1on't") - .replace(/\b(h)adnt\b/gi, "$1adn't") - .replace(/\b(h)asnt\b/gi, "$1asn't") - .replace(/\b(h)avent\b/gi, "$1aven't") - .replace(/\b(h)ed\b/gi, "$1e'd") - .replace(/\b(h)es\b/gi, "$1e's") - .replace(/\b(I)d\b/gi, "$1'd") - .replace(/\b(I)m\b/gi, "$1'm") - .replace(/\b(I)ve\b/gi, "$1've") - .replace(/\b(i)snt\b/gi, "$1sn't") - .replace(/\b(m)ightnt\b/gi, "$1ightn't") - .replace(/\b(m)ustnt\b/gi, "$1ustn't") - .replace(/\b(s)hant\b/gi, "$1han't") - .replace(/\b(s)hes\b/gi, "$1he's") - .replace(/\b(s)houldnt\b/gi, "$1houldn't") - .replace(/\b(t)hats\b/gi, "$1hat's") - .replace(/\b(t)heres\b/gi, "$1here's") - .replace(/\b(t)heyd\b/gi, "$1hey'd") - .replace(/\b(t)heyll\b/gi, "$1hey'll") - .replace(/\b(t)heyre\b/gi, "$1hey're") - .replace(/\b(t)heyve\b/gi, "$1hey've") - .replace(/\b(w)eve\b/gi, "$1e've") - .replace(/\b(w)erent\b/gi, "$1eren't") - .replace(/\b(w)hatll\b/gi, "$1hat'll") - .replace(/\b(w)hatre\b/gi, "$1hat're") - .replace(/\b(w)hats\b/gi, "$1hat's") - .replace(/\b(w)hatve\b/gi, "$1hat've") - .replace(/\b(w)heres\b/gi, "$1here's") - .replace(/\b(w)hod\b/gi, "$1ho'd") - .replace(/\b(w)holl\b/gi, "$1ho'll") - .replace(/\b(w)hove\b/gi, "$1ho've") - .replace(/\b(w)ont\b/gi, "$1on't") - .replace(/\b(w)ouldnt\b/gi, "$1ouldn't") - .replace(/\b(y)oud\b/gi, "$1ou'd") - .replace(/\b(y)oull\b/gi, "$1ou'll") - .replace(/\b(y)oure\b/gi, "$1ou're") - .replace(/\b(y)ouve\b/gi, "$1ou've") - .replace(/(^.)/gm, function(txt) { //Capitalise new line first character - return txt.toUpperCase(); - }) - .replace(/.+?[\.\?\!](\s|$)/g, function(txt) { //Fix capitalisation. http://stackoverflow.com/a/20442069/3541881 - return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); - }); - $(s).val(newVal); - - sox.enhancedEditor.refreshPreview(); - }, - - addLink: function(query, url, s) { - $(s).replaceSelectedText('[' + query.text + '](' + url + ')'); - $('#enhancedEditor-insertLinkDialog').hide(); - sox.enhancedEditor.refreshPreview(); - }, - - keyboardShortcuts: function(s) { - //Replace default SE bindings - $(document).keydown(function(e) { - if (e.which == 71 && e.ctrlKey) { //ctrl+g (images) - $('#enhancedEditor-insertImageDialog').show(500); - e.stopPropagation(); - e.preventDefault(); - return false; - } - if (e.which == 76 && e.ctrlKey && e.altKey) { //ctrl+alt+l (links) - $('#enhancedEditor-insertLinkDialog').show(500); - e.stopPropagation(); - e.preventDefault(); - return false; - } - }); - $(s).keydown(function(e) { - if (e.which == 70 && e.ctrlKey) { //ctrl+f (find+replace) - $('#findReplace').trigger('click'); - e.stopPropagation(); - e.preventDefault(); - return false; - } - }); - }, - - refreshPreview: function() { - var Stack = (typeof StackExchange === "undefined" ? window.eval('StackExchange') : StackExchange); - if (Stack.MarkdownEditor) { - Stack.MarkdownEditor.refreshAllPreviews(); - } - } - }; -})(window.sox = window.sox || {}, jQuery); diff --git a/sox.features.info.json b/sox.features.info.json index f003b2b..b7521a2 100644 --- a/sox.features.info.json +++ b/sox.features.info.json @@ -98,7 +98,7 @@ }, { "name": "scrollToTop", "desc": "Add Scroll To Top button", - "extended_description": "This feature adds a 'scroll to top' button at the bottom left of your screen that will jump to the top of the page when clicked", + "extended_description": "This feature adds an up arrow at the bottom-right of your screen, that will jump to the top of the page when clicked", "meta": "", "match": "", "exclude": "*://chat.*.com/*" @@ -133,6 +133,12 @@ "meta": "http://meta.stackexchange.com/questions/249808/add-a-way-to-reveal-all-spoiler-blocks-in-a-post-at-once", "match": "*://*/questions*", "exclude": "SE1.0" + }, { + "name": "addTimelineAndRevisionLinks", + "desc": "Add timeline and revision links to the bottom of each post for quick access to them", + "meta": "", + "match": "*://*/questions*,*://*/review*", + "exclude": "" }], "Comments": [{ "name": "autoShowCommentImages", @@ -200,7 +206,7 @@ }, { "name": "editComment", "desc": "Pre-defined edit comment options (checkboxes)", - "extended_description": "Adds checkboxes to add canned messages for edit revisions when editing. You can make your own canned responses by clicking the 'Edit Reasons' button that is added to the Help dropdown menu in the topbar", + "extended_description": "Adds checkboxes to add canned messages for edit revisions when editing. You can make *your own* canned responses by clicking the 'Edit Reasons' button that is added to the Help dropdown menu in the topbar", "meta": "http://meta.stackexchange.com/questions/190461/improve-the-editing-flow-with-predefined-options-for-edit-summary", "match": "", "exclude": "*://chat.*.com/*,SE1.0" @@ -212,9 +218,9 @@ "match": "*://*/questions*,*://*/review*", "exclude": "SE1.0" }, { - "name": "enhancedEditor", - "desc": "Add more features to the markdown editor", - "extended_description": "Adds find/replace, changes the TAB key behaviour, adds DuckDuckGo integration, and basic auto-correct features.", + "name": "findAndReplace", + "desc": "Add a find & replace feature to the markdown editor", + "extended_description": "", "meta": "", "match": "*://*/questions*,*://*/review*", "exclude": "SE1.0" @@ -243,7 +249,7 @@ "desc": "Add a notification to your inbox when a question you downvote is edited", "meta": "http://meta.stackexchange.com/q/165962/260841", "match": "", - "exclude": "" + "exclude": "SE1.0" }], "Flags": [{ "name": "flagOutcomeTime", @@ -353,20 +359,14 @@ "match": "*://*/questions*,*://*/review*", "exclude": "SE1.0" }, { - "name": "grayOutVotes", - "desc": "Gray out deleted vote buttons", - "meta": "http://meta.stackexchange.com/a/174806/260841", - "match": "*://*/questions*", - "exclude": "SE1.0" - }, { "name": "stickyVoteButtons", "desc": "Make vote buttons next to posts sticky whilst scrolling on that post", "meta": "http://meta.stackexchange.com/a/35047/260841", "match": "*://*/questions*,*://*/review*", "exclude": "SE1.0" }, { - "name": "disableOwnPostVoteButtons", - "desc": "Disable vote buttons on your own posts", + "name": "disableVoteButtons", + "desc": "Disable vote buttons on posts you cannot vote on", "meta": "", "match": "*://*/questions*", "exclude": "SE1.0" @@ -472,6 +472,7 @@ }, { "name": "openLinksInNewTab", "desc": "Open any links to the specified sites in a new tab by default", + "extended_description": "You need to set the sites yourself by clicking the button next to this feature", "meta": "", "match": "*://*/questions*", "exclude": "", @@ -482,7 +483,7 @@ }] }, { "name": "showQuestionStateInSuggestedEditReviewQueue", - "desc": "Show question's state in the suggested edit review queue", + "desc": "Show question's current state in the suggested edit review queue", "meta": "", "match": "*://*/review*", "exclude": "" diff --git a/sox.features.js b/sox.features.js index 9c6cbe3..b932609 100644 --- a/sox.features.js +++ b/sox.features.js @@ -2,15 +2,6 @@ 'use strict'; sox.features = { //SOX functions must go in here - - grayOutVotes: function() { - // Description: Grays out votes AND vote count - - if ($('.deleted-answer').length) { - $('.deleted-answer .vote-down-off, .deleted-answer .vote-up-off, .deleted-answer .vote-count-post').css('opacity', '0.5'); - } - }, - moveBounty: function() { // Description: For moving bounty to the top @@ -262,7 +253,10 @@ function colour() { $('.answercell').each(function(i, obj) { - $(this).parent().next().find('.comment-user:contains("' + $.trim($(this).find('.user-details').last().clone().children('.-flair').remove().end().text()) + '")').css({'background-color': '#f9e2b6', 'padding': '1px 5px'}); //Find the comments on each post that contain the answerer's name. Also, .last() is necessary, or else it will use the name of someone who edits the answer. + $(this).parent().next().find('.comment-user:contains("' + $.trim($(this).find('.user-details').last().clone().children('.-flair').remove().end().text()) + '")').css({ + 'background-color': '#f9e2b6', + 'padding': '1px 5px' + }); //Find the comments on each post that contain the answerer's name. Also, .last() is necessary, or else it will use the name of someone who edits the answer. }); } @@ -375,9 +369,9 @@ $('#reasons input[type="checkbox"]').change(function() { if (this.checked) { //Add it to the summary if (!editCommentField.val()) { - editCommentField.val(toLocaleSentenceCase($(this).val()).replace(/on$/g, '')); + editCommentField.val(toLocaleSentenceCase($(this).val())); } else { - editCommentField.val(editCommentField.val() + '; ' + $(this).val().replace(/on$/g, '')); + editCommentField.val(editCommentField.val() + '; ' + $(this).val()); } var newEditComment = editCommentField.val(); //Remove the last space and last semicolon editCommentField.val(newEditComment).focus(); @@ -498,7 +492,7 @@ var popup = $('.share-tip'); var origHtml = popup.html(); if (origHtml.indexOf(toRemove) == -1) return; //don't do anything if the function's already done its thing - popup.html(function () { + popup.html(function() { return origHtml.replace(toRemove, ''); }); @@ -587,7 +581,7 @@ if (!$(this).find('.soxReplyLink').length) { //if the link doesn't already exist if ($('.topbar-links a span:eq(0)').text() != $(this).find('.comment-text a.comment-user').text()) { //make sure the link is not added to your own comments $(this).find('.comment-text').css('overflow-x', 'hidden'); - $(this).append(''); + $(this).find('.comment-text .comment-body').append(''); } } }); @@ -595,7 +589,7 @@ $(document).on('click', 'span.soxReplyLink', function() { var parentDiv = $(this).parent().parent().parent().parent(); - var textToAdd = '@' + $(this).parent().find('.comment-text a.comment-user').text().replace(/\s/g, '').replace(/♦/, ''); //eg. @USERNAME + var textToAdd = '@' + $(this).parent().find('a.comment-user').text().replace(/\s/g, '').replace(/♦/, ''); //eg. @USERNAME if (!parentDiv.find('textarea').length) parentDiv.next('div').find('a.js-add-link')[0].click(); //show the textarea, http://stackoverflow.com/a/10559680/ var $textarea = parentDiv.find('textarea'); @@ -774,15 +768,19 @@ } }, - autoShowCommentImages: function() { + autoShowCommentImages: function() { // Description: For auto-inlining any links to imgur images in comments - + function showImages() { $('.comment .comment-text .comment-copy a').each(function() { - if ($(this).attr('href') && ($(this).attr('href').indexOf('i.imgur.com') != -1 || $(this).attr('href').indexOf('i.stack.imgur.com') != -1)) { //https://github.com/soscripted/sox/issues/219 - var src = $(this).attr('href'); - if (!$(this).parent().find('img[src="' + src + '"]').length) { - $(this).parent().append('
    '); //add image to end of comments, but keep link in same position + var href = this.getAttribute('href'), + parent = this.parentNode; + + if (href && (/i(\.stack)?\.imgur\.com/.test(href))) { + if (!parent.querySelectorAll('img[src="' + href + '"]').length) { + //add image to end of comments, but keep link in same position + parent.innerHTML += '
    '; + parent.removeChild(this); } } }); @@ -882,7 +880,7 @@ $voteCell.css('min-width', Math.floor($vote.width())); if ($vote.length) //This value strangely alternates between existing and not existing. This if statement ensures we only get its value when it exists, so no errors. - endPos = $voteCell.next().find('.fw').offset().top; //I think a bit above the end of the post (where the "edit", "delete", etc. buttons lie) is a good place to stop the stickiness. + endPos = $voteCell.next().find('.fw, .fw-wrap').offset().top; //I think a bit above the end of the post (where the "edit", "delete", etc. buttons lie) is a good place to stop the stickiness. $voteCell.on('DOMNodeInserted', function() { //Fix dismissable message boxes, like "Please consider adding a comment if you think this post can be improved." when downvoting $vote.find('.message-dismissable').css({ @@ -892,6 +890,7 @@ }); if (vcOfset.top + 1.5 * $vote.outerHeight() < endPos && vcOfset.top < scrollTop + offset) { //Left condition is to get rid of a sticky zone on extremely short posts. Right condition allows stickiness unless we're above the post. + $vote.parent().css('margin-right', '15px'); if (scrollTop + offset + $vote.outerHeight() < endPos) { //Allow stickiness unless we've scrolled down past the post. $vote.css({ position: 'fixed', @@ -907,6 +906,7 @@ } } else { $vote.removeAttr('style'); //Remove any stickiness + $vote.parent().removeAttr('style'); //Remove any stickiness } }); } @@ -974,7 +974,7 @@ //All sites have either a chat link or meta link $(this).find('.rep-score').stop(true).delay(135).fadeOut(20); - $(this).prepend('
  • ').addClass('-item').append($diamond)); - $('.js-topbar-dialog-corral').append($dialog); - $diamond.css({ - 'background-image': 'url(//cdn.sstatic.net/img/share-sprite-new.svg?v=78be252218f3)', - 'background-position': '-218px -76px' - }).addClass('-link'); - $dialog.addClass('new-topbar').css({ - 'width': '377px', - 'right': '205px', - 'left': 'auto', - 'top': '57px', - }); + $('.top-bar .-container .-secondary .-item:eq(1)').after($('
  • ').addClass('-item').append($diamond)); } else { - $('#soxSettingsButton').after($diamond); - $dialog.css('left', $('#metaNewQuestionAlertButton').position().left).prependTo('.js-topbar-dialog-corral'); + $diamond.appendTo('div.network-items'); } - - $('#metaNewQuestionAlertButton').hover(function() { //open on hover, just like the normal dropdowns - if ($('.topbar-icon').not('#metaNewQuestionAlertButton').hasClass('topbar-icon-on')) { - $('.topbar-dialog').hide(); - $('.topbar-icon').removeClass('topbar-icon-on').removeClass('icon-site-switcher-on'); - $(this).addClass('topbar-icon-on'); - $('#metaNewQuestionAlertDialog').show(); - } - }, function() { - $('.topbar-icon').not('#metaNewQuestionAlertButton').hover(function() { - if ($('#metaNewQuestionAlertButton').hasClass('topbar-icon-on')) { - $('#metaNewQuestionAlertDialog').hide(); - $('#metaNewQuestionAlertButton').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) - } - } - }); - }); + $dialog.css('top', $('.top-bar').height()); + if ($('#metaNewQuestionAlertButton').length) $('.js-topbar-dialog-corral').append($dialog); $(document).mouseup(function(e) { if (!$dialog.is(e.target) && @@ -1634,7 +1602,7 @@ Toggle SBS?
  • '; // Description: Hide just the 'Hot Meta Posts' sections in the Community Bulletin var $hotMetaPostsHeader = $('#sidebar .community-bulletin .related').find('div:contains("Hot Meta Posts")'); - if($hotMetaPostsHeader.length) { + if ($hotMetaPostsHeader.length) { $hotMetaPostsHeader.nextAll().remove(); $hotMetaPostsHeader.remove(); } @@ -1652,13 +1620,6 @@ Toggle SBS?
    '; $('#sidebar #newsletter-ad').parent().remove(); }, - enhancedEditor: function() { - // Description: Add a bunch of features to the standard markdown editor (autocorrect, find+replace, Ace editor, and more!) - - sox.enhancedEditor.startFeature(); - - }, - downvotedPostsEditAlert: function() { // Description: Adds a notification to the inbox if a question you downvoted and watched is edited @@ -1714,7 +1675,7 @@ Toggle SBS?
    '; var $dialog = $('
    ', { id: 'downvotedPostsEditAlertDialog', - 'class': 'topbar-dialog achievements-dialog dno' + 'class': 'topbar-dialog dno new-topbar' }), $header = $('
    ', { 'class': 'header' @@ -1730,18 +1691,14 @@ Toggle SBS?
    '; }), $button = $('
    ', { id: 'downvotedPostsEditAlertButton', - class: 'topbar-icon yes-hover downvotedPostsEditAlert-buttonOff', + class: '-link downvotedPostsEditAlert-buttonOff', title: 'Watched posts that have been edited', - 'style': 'color: #858c93; background-image: none; height: 24px;', + 'style': 'color: #858c93; background-image: none;', href: '#', click: function(e) { e.preventDefault(); - $('#downvotedPostsEditAlertDialog').toggle(); - if ($('#downvotedPostsEditAlertDialog').is(':visible')) { - $(this).addClass('topbar-icon-on'); - } else { - $(this).removeClass('topbar-icon-on'); - } + $button.toggleClass('topbar-icon-on'); + $dialog.toggle(); } }), $icon = $('', { @@ -1752,34 +1709,16 @@ Toggle SBS?
    '; '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("
    Find & Replace
    "); + + $(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