User:isaacl/script/copy-comment-link-to-clipboard.js

(function(){

let fShowCopyCommentLinkTriggers = false;

function copyLinkToClipboard(event)

{

let link = event.target.dataset.link2clipboardCommentLink;

navigator.clipboard.writeText(link).then( () => {

showLinkCopiedNotification();

});

}

function htmlEncode(text)

{

return text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>');

}

function addCopyCommentLinkTrigger(commentIdElem, label, description, linkType)

{

let labelText = '';

if (label != null)

labelText = label;

let descriptionText = '';

if (description != null)

{

descriptionText = description.concat(' ');

}

descriptionText = descriptionText.concat('link');

if (linkType == null || linkType != 'original')

{

linkType = 'permalink';

}

let id = commentIdElem.getAttribute("id");

let linkElem = document.createElement("span");

linkElem.dataset.link2clipboardTrigger = '';

linkElem.style.textDecorationLine = 'underline';

linkElem.style.textDecorationStyle = 'dotted';

let permalink = 'Special:GoToComment';

let link = mw.config.get('wgPageName');

link = link.replaceAll('_', ' ');

let idLinkText = id.replaceAll('_', ' ');

link = link.concat('#', idLinkText);

permalink = permalink.concat('/', idLinkText);

if (linkType == 'permalink')

{

linkElem.dataset.link2clipboardCommentLink = permalink;

}

else

{

linkElem.dataset.link2clipboardCommentLink = link;

}

let triggerText = "";

triggerText = triggerText.concat("<", labelText, "/> ");

linkElem.appendChild(document.createTextNode(triggerText));

let permalinkHTML = htmlEncode(permalink);

let originalLinkHTML = htmlEncode(link);

let popupContent = '

';

if (linkType == 'permalink')

{

popupContent = popupContent.concat(permalinkHTML,

'

original page link: ',

originalLinkHTML, '

');

}

else

{

popupContent = popupContent.concat(originalLinkHTML, '

');

}

let popupWidget = new OO.ui.PopupWidget({

$content: $(popupContent),

$floatableContainer: $(linkElem),

classes: [ 'link2clipboardPopup' ],

head:true,

padded:true

});

OO.ui.getTeleportTarget().append(popupWidget.$element[0]);

let titleText = "";

titleText = titleText.concat('Copy ', descriptionText, ' to clipboard');

linkElem.title = titleText;

linkElem.addEventListener('click', function(event) {

popupWidget.toggle(true);

copyLinkToClipboard(event);

});

let parent = commentIdElem.parentNode;

let insertBeforeElem = commentIdElem;

if (parent.tagName == 'A' && parent.href != "")

{

insertBeforeElem = parent;

parent = parent.parentNode;

}

parent.insertBefore(linkElem, insertBeforeElem);

}

function showCommentLinks()

{

let commentStartSpans = document.querySelectorAll("span[data-mw-comment-start]");

for (let commentStartElem of commentStartSpans)

{

if (commentStartElem.hasAttribute("id"))

{

addCopyCommentLinkTrigger(commentStartElem);

}

}

// Legacy structure for headlines: span element inside a heading element

let headlineIdSpans = document.getElementsByClassName('mw-headline');

for (let headlineIdElem of headlineIdSpans)

{

if (headlineIdElem.hasAttribute("id"))

{

addCopyCommentLinkTrigger(headlineIdElem, "h", "heading", "original");

}

}

// Current structure for headlines: div element wrapping heading element.

let headingNameList = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ];

for (let headingName of headingNameList)

{

let selector = "div.mw-heading ".concat(headingName.concat("[id]"));

let headingElements = document.querySelectorAll(selector);

for (let headingElem of headingElements)

{

addCopyCommentLinkTrigger(headingElem, "h", "heading", "original");

}

}

}

function hideCommentLinks()

{

let linkElems = document.querySelectorAll("span[data-link2clipboard-trigger]");

for (let linkElem of linkElems)

{

linkElem.remove();

}

let popupElems = document.querySelectorAll('.link2clipboardPopup');

for (let popupElem of popupElems)

{

popupElem.remove();

}

}

function showLinkCopiedNotification()

{

mw.loader.using(['mediawiki.notification']).then( () => {

mw.notification.notify("Copied link to clipboard.");

});

}

function showEnabledNotification()

{

mw.loader.using(['mediawiki.notification']).then( () => {

mw.notification.notify("Enabled copying links to clipboard.");

});

}

function showDisabledNotification()

{

mw.loader.using(['mediawiki.notification']).then( () => {

mw.notification.notify("Disabled copying links to clipboard.");

});

}

function clickEventListener(event)

{

event.preventDefault();

event.stopPropagation();

hideCommentLinks();

if (fShowCopyCommentLinkTriggers)

{

showDisabledNotification();

}

else

{

showCommentLinks();

showEnabledNotification();

}

fShowCopyCommentLinkTriggers = !fShowCopyCommentLinkTriggers;

return false;

}

let portletItemDropDownMenuConfig = [

{ portletName: 'p-personal', id: 'link2clipboard-PortletItem-personal' },

{ portletName: 'p-personal-sticky-header', id: 'link2clipboard-PortletItem-personal-sticky-header' },

];

let portletItemSidebarConfig = [

{ portletName: 'p-tb', id: 'link2clipboard-PortletItem-tb' },

];

let skinsWithDropDownMenu = [ 'vector2022', 'timeless', 'minerva' ];

let portletItemConfig = portletItemSidebarConfig;

// TODO: mw.config.skin is returning undefined, and not the skin name

//console.log("Using skin: ", mw.config.skin);

//if (skinsWithDropDownMenu.includes(mw.config.skin))

// portletItemConfig = portletItemDropDownMenuConfig;

let portletItemText = "Toggle link2clipboard";

function addPortletLinkEventHandler(item, options)

{

for (let portletItemInfo of portletItemConfig)

{

if (options.id == portletItemInfo.id)

{

mw.loader.using('oojs-ui-core').done( function() {

item.addEventListener('click', clickEventListener);

});

}

}

}

function initializePortletItem()

{

mw.hook('util.addPortletLink').add(addPortletLinkEventHandler);

mw.loader.using( [ 'mediawiki.util' ] ).then( function () {

for (let portletItemInfo of portletItemConfig)

{

let portletItem = document.getElementById(portletItemInfo.id);

if (portletItem == null)

{

mw.util.addPortletLink(portletItemInfo.portletName, '#', portletItemText, portletItemInfo.id);

}

}

} );

return;

}

initializePortletItem();

})();