GetCourse — кнопка редактирования рассылки (userscript)
Что делает
В редакторе CMS-страниц GetCourse рядом со ссылками на рассылки (/notifications/control/mailings/update/id/<id>) добавляет маленькую оранжевую иконку карандаша. Клик по иконке открывает в новой вкладке новый редактор той же рассылки по адресу /pl/notifications/control/mailings/editor?id=<id> — без необходимости копировать ID и переходить вручную.

Код
// ==UserScript==
// @name GetCourse — кнопка редактирования рассылки
// @namespace fitnessmama.school
// @version 1.0
// @description Добавляет кнопку "редактировать" рядом со ссылками на рассылки в редакторе CMS GetCourse
// @match https://fitnessmama.school/pl/*
// @match https://*.getcourse.ru/pl/*
// @run-at document-idle
// @grant none
// ==/UserScript==
(function () {
'use strict';
const BTN_CLASS = 'gc-edit-mailing-btn';
const PROCESSED_ATTR = 'data-gc-edit-added';
const HREF_PATTERN = /\/notifications\/control\/mailings\/update\/id\/(\d+)/;
const style = document.createElement('style');
style.textContent = `
.${BTN_CLASS} {
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
padding: 0;
margin: 0 0 0 4px;
border: none;
border-radius: 4px;
background: transparent;
color: #8a96a8;
cursor: pointer;
vertical-align: -4px;
opacity: 0.7;
transition: background .15s ease, color .15s ease, opacity .15s ease;
text-decoration: none;
}
.${BTN_CLASS}:hover {
opacity: 1;
background: #fff4e5;
color: #e8730c;
text-decoration: none;
}
.${BTN_CLASS}:active { background: #ffe0b2; }
.${BTN_CLASS} svg { width: 13px; height: 13px; display: block; }
`;
document.head.appendChild(style);
const SVG_NS = 'http://www.w3.org/2000/svg';
function buildPencil() {
const s = document.createElementNS(SVG_NS, 'svg');
s.setAttribute('viewBox', '0 0 24 24');
s.setAttribute('fill', 'none');
s.setAttribute('stroke', 'currentColor');
s.setAttribute('stroke-width', '2');
s.setAttribute('stroke-linecap', 'round');
s.setAttribute('stroke-linejoin', 'round');
const p1 = document.createElementNS(SVG_NS, 'path');
p1.setAttribute('d', 'M12 20h9');
const p2 = document.createElementNS(SVG_NS, 'path');
p2.setAttribute('d', 'M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z');
s.appendChild(p1);
s.appendChild(p2);
return s;
}
function makeButton(editUrl) {
const a = document.createElement('a');
a.className = BTN_CLASS;
a.href = editUrl;
a.target = '_blank';
a.rel = 'noopener';
a.title = 'Редактировать рассылку';
a.setAttribute('aria-label', 'Редактировать рассылку: ' + editUrl);
a.appendChild(buildPencil());
return a;
}
function process(root) {
if (!root || root.nodeType !== 1) root = document.body;
const links = root.querySelectorAll('a[href*="/notifications/control/mailings/update/id/"]');
links.forEach((a) => {
if (a.hasAttribute(PROCESSED_ATTR)) return;
const href = a.getAttribute('href') || '';
const m = HREF_PATTERN.exec(href);
if (!m) return;
const id = m[1];
const editUrl = '/pl/notifications/control/mailings/editor?id=' + id;
a.setAttribute(PROCESSED_ATTR, '1');
const btn = makeButton(editUrl);
if (a.nextSibling) a.parentNode.insertBefore(btn, a.nextSibling);
else a.parentNode.appendChild(btn);
});
}
process(document.body);
const observer = new MutationObserver((mutations) => {
for (const m of mutations) {
m.addedNodes.forEach((node) => {
if (node.nodeType === 1) process(node);
});
}
});
observer.observe(document.body, { childList: true, subtree: true });
})();