diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 18d8bec..1b8b2ef 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,4 +1,4 @@
-### Installed Version: 1.X.X Environment: Chrome/Tampermonkey
+e### Installed Version: 1.X.X Environment: Chrome/Tampermonkey
### Current Behaviour
diff --git a/sox.common.js b/sox.common.js
index 8eeb007..182f40e 100644
--- a/sox.common.js
+++ b/sox.common.js
@@ -45,7 +45,6 @@
}
};
- //var Stack = (typeof StackExchange === "undefined" ? window.eval('if (typeof StackExchange != "undefined") StackExchange') : StackExchange) | undefined;
let Chat;
let Stack;
if (location.href.indexOf('github.com') === -1) { //need this so it works on FF -- CSP blocks window.eval() it seems
@@ -256,6 +255,50 @@
const siteMatch = link.replace(/https?:\/\//, '').match(siteRegex);
return siteMatch ? siteMatch[1] : null;
},
+ createModal: function (params) {
+ const $dialog = $('', {
+ 'class': 's-modal js-modal-overlay js-modal-close js-stacks-managed-popup js-fades-with-aria-hidden sox-custom-dialog',
+ 'role': 'dialog',
+ 'aria-hidden': false,
+ });
+ if (params.css) $dialog.css(params.css);
+ const $dialogInnerContainer = $('
', {
+ 'class': 's-modal--dialog js-modal-dialog ',
+ 'style': 'min-width: 568px;',// top: 227.736px; left: 312.653px;',
+ });
+ const $header = $('', {
+ 'class': 's-modal--header fs-headline1 fw-bold mr48 js-first-tabbable',
+ 'text': params.header,
+ });
+ const $mainContent = $('', {
+ 'class': 's-modal--body sox-custom-dialog-content',
+ });
+ if (params.html) $mainContent.html(params.html);
+ const $closeButton = $('', {
+ 'class': 's-modal--close s-btn s-btn__muted js-modal-close js-last-tabbable',
+ 'click': () => $('.sox-custom-dialog').remove(),
+ }).append($(''));
+
+ $dialogInnerContainer.append($header).append($mainContent).append($closeButton);
+ $dialog.append($dialogInnerContainer);
+
+ return $dialog;
+ },
+ addButtonToHelpMenu: function (params) {
+ const $li = $('');
+ const $a = $('', {
+ 'href': 'javascript:void(0)',
+ 'id': params.id,
+ 'text': params.linkText,
+ });
+ const $span = $('', {
+ 'class': 'item-summary',
+ 'text': params.summary,
+ 'click': params.click,
+ });
+ $li.append($a.append($span));
+ $('.topbar-dialog.help-dialog.js-help-dialog > .modal-content ul').append($li);
+ },
};
sox.site = {
@@ -335,7 +378,7 @@
let matchScheme = matchSplit[0];
let matchHost = matchSplit[2];
let matchPath = matchSplit.slice(-(matchSplit.length - 3)).join('/');
-
+
matchScheme = matchScheme.replace(/\*/g, '.*');
matchHost = matchHost.replace(/\./g, '\\.').replace(/\*\\\./g, '.*.?').replace(/\\\.\*/g, '.*').replace(/\*$/g, '.*');
matchPath = '^/' + matchPath.replace(/\//g, '\\/').replace(/\*/g, '.*');
diff --git a/sox.css b/sox.css
index 6995b6a..66c38f1 100644
--- a/sox.css
+++ b/sox.css
@@ -285,6 +285,7 @@
}
.fixedTopbar-linksList {
+ box-sizing: border-box;
-moz-box-sizing: border-box;
background: none repeat scroll 0 0 #fff;
}
@@ -350,7 +351,7 @@ li.fixedTopbar-siteLink {
}
.post-editor.sbs-on {
- width: 1360px !important; //width: 1060px !important;
+ width: 1360px !important;
}
.sbs-on-left-side {
@@ -615,4 +616,19 @@ li.fixedTopbar-siteLink {
/* editComment -- for the checkboxes shown when editin */
.sox-editComment-reason {
display: inline-block !important;
+}
+
+/* customMagicLinks -- for the settings table in the dialog */
+.sox-customMagicLinks-settings-table {
+ margin-bottom: 10px;
+}
+
+.sox-customMagicLinks-settings-table td,
+.sox-customMagicLinks-settings-table th {
+ border: 1px solid #ddd;
+ padding: 8px;
+}
+
+.sox-customMagicLinks-settings-table th {
+ font-weight: bold;
}
\ No newline at end of file
diff --git a/sox.features.info.json b/sox.features.info.json
index e4c55a2..279b327 100644
--- a/sox.features.info.json
+++ b/sox.features.info.json
@@ -538,6 +538,14 @@
"meta": "",
"match": "",
"exclude": "*://chat.*.com/*,SE1.0"
+ }, {
+ "name": "customMagicLinks",
+ "desc": "Add custom magic links to comments and posts",
+ "extended_description": "Allows you to create your own magic links ('[text]' auto-converts to a link of your choice). Links can use the placeholders $BASEURL, $METABASEURL, $QUESTIONID, and $ANSWERID which are auto-replaced with the respective data. You can set the reasons by clicking the 'Magic Links' button added to the 'Help' dropdown at the top-right of the page. See https://stackapps.com/q/6650 for more details.",
+ "meta": "",
+ "match": "*://*/questions*",
+ "exclude": "",
+ "feature_packs": ["power_user"]
}]
}
}
diff --git a/sox.features.js b/sox.features.js
index aadf321..86f703b 100644
--- a/sox.features.js
+++ b/sox.features.js
@@ -429,20 +429,22 @@
//reset textbox values to empty
$('#displayReason').val('');
$('#actualReason').val('');
-
}
});
- setTimeout(() => {
- addCheckboxes();
- //Add the button to update and view the values in the help menu:
- $('.topbar-dialog.help-dialog.js-help-dialog > .modal-content ul').append('Edit Reasons \
- Edit your personal edit reasons for SE sites');
- $('.topbar-dialog.help-dialog.js-help-dialog > .modal-content ul #editReasonsLink').on('click', () => {
+ addCheckboxes();
+
+ //Add the button to update and view the values in the help menu:
+ sox.helpers.addButtonToHelpMenu({
+ 'id': 'editReasonsLink',
+ 'linkText': 'Edit Reasons',
+ 'summary': 'Edit your personal edit reasons for SE sites',
+ 'click': function () {
displayDeleteValues();
$('#dialogEditReasons').show(500); //Show the dialog to view and update values
- });
- }, 500);
+ },
+ });
+
$(document).on('sox-edit-window', addCheckboxes);
$('.post-menu > .edit-post').click(() => {
@@ -690,7 +692,7 @@
function updateTS() {
const utcTimestamp = $(this).attr('title');
- const matches = utcTimestamp.match(/^([\d]{4})-([\d]{2})-([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2}) ?(?:Z|UTC|GMT(?:[+\-]00:?00))$/);
+ const matches = utcTimestamp.match(/^([\d]{4})-([\d]{2})-([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2}) ?(?:Z|UTC|GMT(?:[+-]00:?00))$/);
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
if (!matches) return;
@@ -2478,5 +2480,137 @@
$('.top-bar .related-links').find('a').eq(0).replaceWith('on-topic');
},
+ customMagicLinks: function () {
+ // Description: Adds custom magic links to the post and comment editors
+
+ var magicLinks = JSON.parse(GM_getValue('SOX-customMagicLinks', '[]'));
+ // magicLinks = [ { text: 'edit/q', replacement: 'Edit Question', link: '$BASEURL$/posts/$QUESTIONID$/edit' }];
+
+ function updateGMValue(magicLinks) {
+ GM_setValue('SOX-customMagicLinks', JSON.stringify(magicLinks));
+ }
+
+ function generateSettingsTableHtml(magicLinks) {
+ const $magicLinksTable = $(`
+
+
+ Text |
+ Replacement |
+ Link |
+
+
`);
+ for (let i = 0; i < magicLinks.length; i++) {
+ const currentLink = magicLinks[i];
+ const $saveButton = $('', {
+ 'text': 'save',
+ 'click': function () {
+ const $parentTr = $(this).parent().parent();
+ const index = $parentTr.attr('data-magic-link-index');
+ magicLinks[index].text = $parentTr.find('.magic-link-text').text();
+ magicLinks[index].replacement = $parentTr.find('.magic-link-replacement').text();
+ magicLinks[index].link = $parentTr.find('.magic-link-link').text();
+ window.alert('Your changes were saved!');
+ updateGMValue(magicLinks);
+ },
+ });
+ const $deleteButton = $('', {
+ 'text': 'delete',
+ 'click': function () {
+ magicLinks.splice($(this).parent().attr('data-magic-link-index'), 1);
+ $(this).parent().parent().remove();
+ updateGMValue(magicLinks);
+ },
+ });
+ const $linkDetails = $(
+ `
+ ${currentLink.text} |
+ ${currentLink.replacement} |
+ ${currentLink.link} |
+
`);
+ $linkDetails.append($(' | ').append($saveButton)).append($(' | ').append($deleteButton));
+ $magicLinksTable.append($linkDetails);
+ }
+ return $magicLinksTable;
+ }
+
+ function replacePlaceholders(text, $textarea) {
+ const baseUrl = $(location).attr('protocol') + '//' + $(location).attr('hostname');
+ const localMetaBase = $(location).attr('protocol') + '//meta.' + $(location).attr('hostname');
+ const questionId = $('.question').data('questionid');
+ const answerId = $textarea.closest('.answer').data('answerid');
+
+ return text
+ .replace(/\$BASEURL\$/ig, baseUrl)
+ .replace(/\$METABASEURL\$/ig, localMetaBase)
+ .replace(/\$QUESTIONID\$/ig, questionId)
+ .replace(/\$ANSWERID\$/ig, answerId);
+ }
+
+ function magicLink($el) {
+ const $textarea = $el.is('textarea') ? $el : $el.parents('form').find('textarea').eq(0);
+ var newVal = $textarea.val();
+ for (let i = 0; i < magicLinks.length; i++) {
+ const currentMagicLink = magicLinks[i];
+ const replacementText = currentMagicLink.replacement;
+ const url = replacePlaceholders(currentMagicLink.link, $textarea);
+ const regex = new RegExp('\\[' + currentMagicLink.text + '\\]', 'g');
+ newVal = newVal.replace(regex, '[' + replacementText + '](' + url + ')');
+ }
+ $textarea.val(newVal);
+ }
+
+ $(document).on('keydown', '.comment-form textarea', function (e) {
+ if (e.keyCode == 13) magicLink($(this));
+ });
+ $(document).on('click', '.comment-form input[type="submit"], .form-submit #submit-button, form.inline-post button[id*="submit-button-"]', function (e) {
+ magicLink($(this));
+ });
+
+ function createSettingsDialog(magicLinks) {
+ const $settingsDialog = sox.helpers.createModal({
+ 'header': 'SOX: Magic Link Settings',
+ 'css': {
+ 'min- width': '50%',
+ },
+ 'html': 'the table cells below are editable; be sure to save any changes!
',
+ });
+ const $settingsDialogContent = $settingsDialog.find('.sox-custom-dialog-content');
+
+ const $newMagicLinkButton = $('', {
+ 'text': 'new link',
+ 'click': function () {
+ const text = window.prompt('Enter the magic link text (e.g. edit/q)');
+ const replacement = window.prompt('Enter the text you would like the link to show as (e.g. Edit Question)');
+ const link = window.prompt('Enter the replacement link, using the placeholders as required');
+
+ if (text && replacement && link) {
+ magicLinks.push({
+ text,
+ replacement,
+ link,
+ });
+ updateGMValue(magicLinks);
+ $settingsDialogContent.find('.table-container table').remove();
+ $settingsDialogContent.find('.table-container').append(generateSettingsTableHtml(magicLinks));
+ } else {
+ window.alert('Please enter details for all three fields');
+ }
+ },
+ });
+ $settingsDialogContent.find('.table-container').append(generateSettingsTableHtml(magicLinks));
+ $settingsDialogContent.append($newMagicLinkButton);
+
+ $('body').append($settingsDialog);
+ }
+
+ sox.helpers.addButtonToHelpMenu({
+ 'id': 'magicLinksSettingsLink',
+ 'linkText': 'Magic Links',
+ 'summary': 'Edit your custom magic links for SE sites',
+ 'click': function () {
+ createSettingsDialog(magicLinks);
+ },
+ });
+ },
};
})(window.sox = window.sox || {}, jQuery);
\ No newline at end of file
diff --git a/sox.user.js b/sox.user.js
index 1f3b267..53d10fd 100644
--- a/sox.user.js
+++ b/sox.user.js
@@ -3,7 +3,7 @@
// @namespace https://github.com/soscripted/sox
// @homepage https://github.com/soscripted/sox
// @homepageURL https://github.com/soscripted/sox
-// @version 2.3.20 DEV
+// @version 2.3.21 DEV
// @description Extra optional features for Stack Overflow and Stack Exchange sites
// @contributor ᴉʞuǝ (https://stackoverflow.com/users/1454538/, https://github.com/mezmi)
// @contributor ᔕᖺᘎᕊ (https://stackexchange.com/users/4337810/, https://github.com/shu8)