User:Newslinger/Notifier.js
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// <nowiki>
// Notifier (beta)
// Notifies other talk pages of a discussion on the current page
// Please provide feedback at [[User talk:Newslinger/Notifier]]
$(function () {
var api, log, pageName, texts, windowManager
var dialogReady = false
var talkNamespaceRegex = /(Talk|User talk|Wikipedia|Wikipedia talk|File talk|MediaWiki talk|Template talk|Help talk|Category talk|Portal talk|Draft talk|TimedText talk|Module talk):/
function init () {
mw.loader.using('mediawiki.util', function () {
pageName = mw.config.get('wgPageName').replace(/_/g, ' ')
if (pageName === 'Wikipedia:Reliable sources/Noticeboard' && $('body.skin-vector').length) {
markHeadings()
} else if (pageName.search(talkNamespaceRegex) === 0) {
var markLink = mw.util.addPortletLink('p-cactions', '#', 'Notifier', 'ca-notifier',
'Notify other talk pages of a discussion on this page')
$(markLink).click(function (event) {
event.preventDefault()
markHeadings()
})
}
})
}
function initDialog () {
OO.inheritClass(Dialog, OO.ui.ProcessDialog)
Dialog.static.name = 'notifierDialog'
Dialog.static.title = 'Notifier'
Dialog.static.actions = [
{
action: 'notify',
label: 'Notify',
flags: ['primary', 'progressive']
}, {
label: 'Cancel',
flags: 'safe'
}
]
Dialog.prototype.initialize = function () {
Dialog.super.prototype.initialize.call(this)
this.$notifyingLabel = $('<div>Notifying of discussion:</div>')
this.$discussionName = $('<div style="font-weight: bold" />')
this.$info = $('<p />')
this.$info.append(this.$notifyingLabel, this.$discussionName)
this.targetPages = new OO.ui.MultilineTextInputWidget({rows: 5})
this.targetPagesField = new OO.ui.FieldLayout(this.targetPages, {
label: 'Pages to notify',
align: 'top',
help: 'One page per line (maximum 90 pages). Only pages in talk and project namespaces are allowed. Subject to the rate limit on your account (90 edits/minute if autoconfirmed, and 8 edits/minute if not). Edits exceeding the limit will fail.',
helpInline: true
})
this.targetPages.on('change', (function (value) {
var pageCount = value.trim().split('\n').length
var countLabel = ''
if (pageCount > 90) {
countLabel = ' (' + pageCount + ' pages; exceeds maximum of 90)'
} else if (value) {
countLabel = ' (' + pageCount + ' page' + (pageCount > 1 ? 's' : '') + ')'
}
this.targetPagesField.setLabel('Pages to notify' + countLabel)
}).bind(this))
this.messageTitle = new OO.ui.TextInputWidget({})
this.messageTitleField = new OO.ui.FieldLayout(this.messageTitle, {
label: 'Message title',
align: 'top'
})
this.message = new OO.ui.MultilineTextInputWidget({rows: 5})
this.messageField = new OO.ui.FieldLayout(this.message, {
label: 'Message',
align: 'top',
help: 'Signature not needed. Your signature will be added if not present at the end of the message.',
helpInline: true
})
this.log = new OO.ui.MultilineTextInputWidget({
readOnly: true,
rows: 5,
value: log
})
this.logField = new OO.ui.FieldLayout(this.log, {
label: 'Log',
align: 'top'
})
this.notificationTemplate = new OO.ui.TextInputWidget({readOnly: true})
this.notificationTemplateField = new OO.ui.FieldLayout(this.notificationTemplate, {
label: 'Notification template',
align: 'top',
help: 'After notifying, paste this template into the end of the original discussion.',
helpInline: true
})
this.panel = new OO.ui.PanelLayout({
padded: true,
expanded: false
})
this.panel.$element.append(this.$info, this.targetPagesField.$element, this.messageTitleField.$element,
this.messageField.$element, this.logField.$element, this.notificationTemplateField.$element)
this.$body.append(this.panel.$element)
}
Dialog.prototype.getSetupProcess = function (data) {
data = data || {}
return Dialog.super.prototype.getSetupProcess.call(this, data)
.next(function () {
this.$discussionName.text(pageName + ' § ' + texts[data.id])
this.message.setValue('{{slink|' + pageName + '|' + texts[data.id] + '}}')
}, this)
}
Dialog.prototype.getActionProcess = function (action) {
if (action === 'notify') {
sendMessages(this)
}
return Dialog.super.prototype.getActionProcess.call(this, action)
}
Dialog.prototype.getBodyHeight = function () {
return this.panel.$element.outerHeight(true)
}
windowManager = new OO.ui.WindowManager()
$(document.body).append(windowManager.$element)
dialogReady = true
}
function Dialog (config) {
Dialog.super.call(this, config)
}
function markHeadings () {
texts = {}
var $headings = $('#mw-content-text h2:not(.toctitle h2)')
$headings.each(function (index) {
var $headline = $(this).children('.mw-headline')
var id = $headline.attr('id')
var text = $headline.contents().not($headline.children('.mw-headline-number')).text().trim()
createLink($(this), id, text)
texts[id] = text
})
}
function createLink ($heading, id, text) {
var $link = $('<a href="#">notify</a>')
var $leftBracket = $('<span class="mw-editsection-bracket">[</span>')
var $rightBracket = $('<span class="mw-editsection-bracket">]</span>')
var $editSection = $('<span class="mw-editsection" />')
$link.click(function (event) {
event.preventDefault()
promptNotify(id)
})
$editSection.append($leftBracket, $link, $rightBracket)
$heading.append($editSection)
return $link
}
function promptNotify (id) {
mw.loader.using(['oojs', 'oojs-ui'], function () {
if (!dialogReady) {
initDialog()
}
log = 'Ready to notify'
var dialog = new Dialog()
windowManager.addWindows([dialog])
windowManager.openWindow(dialog, {id: id})
})
}
function sendMessages (dialog) {
api = api || new mw.Api()
var targetPages = dialog.targetPages.getValue().trim().split('\n').map(function (targetPage) {
return targetPage.trim()
})
var messageTitle = dialog.messageTitle.getValue().trim()
var message = dialog.message.getValue().trim()
if (message.slice(-4) !== '~~' + '~~') {
message += ' ~~' + '~~'
}
var notificationTemplate = '{{subst' + ':notified|' + targetPages.join('|') + '}}'
dialog.notificationTemplate.setValue(notificationTemplate)
var tasks = []
$.each(targetPages, function(index, targetPage) {
addLog(dialog, 'Notifying: ' + targetPage)
if (targetPage.search(talkNamespaceRegex) != 0) {
addLog(dialog, 'Failed to notify: ' + targetPage)
addLog(dialog, 'Error: Pages outside of talk and project namespaces are not allowed.')
return
}
var task = api.newSection(targetPage, messageTitle, message, { redirect: true })
.then(function () {
addLog(dialog, 'Successfully notified: ' + targetPage)
}, function(error) {
addLog(dialog, 'Failed to notify: ' + targetPage)
addLog(dialog, 'Error: ' + error)
})
tasks.push(task)
})
$.when.apply(null, tasks).then(function () {
addLog(dialog, 'Finished!')
})
}
function addLog (dialog, message) {
log += '\n' + message
dialog.log.setValue(log)
}
init()
})
// </nowiki>