User:BrandonXLF/sandbox.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:BrandonXLF/sandbox and an accompanying .css page at User:BrandonXLF/sandbox.css. |
(function() {
function loadScripts() {
var requests = [null, null], // Force $.when to return arrays
enabledScripts = [],
js = '',
scripts = JSON.parse(mw.user.options.get('userjs-scriptmanager-scripts') || '[]'),
i;
for (i = 0; i < scripts.length; i++) {
var script = scripts[i];
if (script.enabled && (script.conds ? eval(script.conds) : true) && script.name !== 'User:BrandonXLF/sandbox.js') {
enabledScripts.push(script.name);
js += script.vars + '\n';
}
}
for (i = 0; i < enabledScripts.length; i += 50) {
requests.push(new mw.Api().get({
action: 'query',
prop: 'revisions',
titles: enabledScripts.slice(i, i + 50).join('|'),
rvprop: 'content',
rvslots: 'main',
formatversion: 2
}));
}
$.when.apply(null, requests).then(function() {
for (i = 2; i < arguments.length; i++) {
arguments[i][0].query.pages.forEach(function(page) {
if (page.revisions) {
js += '/* ' + page.title + ' */\n' + page.revisions[0].slots.main.content;
} else {
console.warn('Failed to load revision for script ' + page.title);
}
});
}
var script = document.createElement('script');
script.text = js;
document.head.appendChild(script);
});
}
function manageScripts(e) {
e.preventDefault();
function ScriptGroup(items) {
ScriptGroup.super.call(this);
OO.ui.mixin.DraggableGroupElement.call(this, {
$group: this.$element,
items: items
});
}
OO.inheritClass(ScriptGroup, OO.ui.Widget);
OO.mixinClass(ScriptGroup, OO.ui.mixin.DraggableGroupElement);
function ScriptWidget(data, dialog) {
var widget = this;
ScriptWidget.super.call(this, {data: data});
OO.ui.mixin.IconElement.call(this, {icon: 'draggable'});
OO.ui.mixin.LabelElement.call(this, {label: data.name});
OO.ui.mixin.DraggableElement.call(this, {$handle: this.$icon});
this.toggle = new OO.ui.ButtonWidget({
framed: false,
label: widget.data.enabled ? 'Disable' : 'Enable'
});
this.toggle.on('click', function() {
widget.data.enabled = !widget.data.enabled;
widget.toggle.setLabel(widget.data.enabled ? 'Disable' : 'Enable');
widget.$label.toggleClass('userscript-disabled', !widget.data.enabled);
});
this.remove = new OO.ui.ButtonWidget({
framed: false,
flags: 'destructive',
label: 'Remove'
});
this.remove.on('click', function() {
widget.getElementGroup().removeItems([widget]);
dialog.updateSize();
});
this.$label.toggleClass('userscript-disabled', !this.data.enabled);
this.$element.append(
this.$icon,
this.$label,
new OO.ui.ButtonGroupWidget({
items: [this.toggle, this.remove]
}).$element
);
this.$element.addClass('userscript-listing');
this.$label.addClass('userscript-label');
}
OO.inheritClass(ScriptWidget, OO.ui.Widget);
OO.mixinClass(ScriptWidget, OO.ui.mixin.IconElement);
OO.mixinClass(ScriptWidget, OO.ui.mixin.LabelElement);
OO.mixinClass(ScriptWidget, OO.ui.mixin.DraggableElement);
function ManagerDialog(config) {
ManagerDialog.super.call(this, config);
}
OO.inheritClass(ManagerDialog, OO.ui.ProcessDialog);
ManagerDialog.static.name = 'manageuserscripts';
ManagerDialog.static.title = 'Manage user scripts';
ManagerDialog.static.actions = [
{
label: 'Close',
flags: ['safe', 'close'],
modes: ['list']
},
{
label: 'Save',
flags: ['primary', 'progressive'],
modes: ['list'],
action: 'save'
},
{
label: 'Add new script',
flags: ['safe'],
modes: ['list'],
action: 'add'
},
{
label: 'Import scripts',
flags: ['safe'],
modes: ['list'],
action: 'import'
},
{
label: 'Back',
flags: ['safe', 'back'],
modes: ['add'],
action: 'add-back'
},
{
label: 'Continue',
flags: ['primary', 'progressive'],
modes: ['add'],
action: 'add-continue'
},
];
ManagerDialog.prototype.initialize = function() {
ManagerDialog.super.prototype.initialize.apply(this, arguments);
var widgets = [],
scripts = JSON.parse(mw.user.options.get('userjs-scriptmanager-scripts') || '[]');
for (var i = 0; i < scripts.length; i++) {
widgets.push(new ScriptWidget(scripts[i], this));
}
this.listPanel = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
this.addNewPanel = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
this.group = new ScriptGroup(widgets);
this.panels = new OO.ui.StackLayout();
this.addNewInput = new OO.ui.TextInputWidget();
this.addNewLayout = new OO.ui.FieldLayout(this.addNewInput, {
align: 'top',
label: 'Enter script title'
});
this.listPanel.$element.append(this.group.$element);
this.addNewPanel.$element.append(this.addNewLayout.$element);
this.panels.addItems([this.listPanel, this.addNewPanel]);
this.$body.append(this.panels.$element);
};
ManagerDialog.prototype.getSetupProcess = function(data) {
return ManagerDialog.super.prototype.getSetupProcess.call(this, data).next(function() {
this.panels.setItem(this.listPanel);
this.actions.setMode('list');
}, this);
};
ManagerDialog.prototype.showErrors = function(errors) {
ManagerDialog.super.prototype.showErrors.call(this, errors);
this.actions.setAbilities({
'add-continue': true
});
this.updateSize();
};
ManagerDialog.prototype.showAddNewError = function(error) {
this.addNewLayout.setErrors(error ? [error] : []);
this.updateSize();
};
ManagerDialog.prototype.getActionProcess = function(action) {
var dialog = this;
return new OO.ui.Process(function() {
if (!action) return dialog.close();
if (action == 'add') {
dialog.panels.setItem(dialog.addNewPanel);
dialog.actions.setMode('add');
dialog.addNewInput.setValue('');
dialog.showAddNewError();
} else if (action == 'add-back') {
dialog.panels.setItem(dialog.listPanel);
dialog.actions.setMode('list');
} else if (action == 'add-continue') {
var name = dialog.addNewInput.getValue();
if (!name) return dialog.showAddNewError('Name is required.');
return new mw.Api().get({
action: 'query',
titles: name,
prop: 'info',
formatversion: 2
}).then(function(res) {
var info = res.query.pages[0];
if (info.missing) return dialog.showAddNewError('Script does not exist.');
if (info.ns !== 2 && info.ns !== 8) return dialog.showAddNewError('Script must be in the User or MediaWiki namespaces.');
if (info.contentmodel !== 'javascript') return dialog.showAddNewError('Script must have the JavaScript content model.');
var items = dialog.group.getItems();
for (var i = 0; i < items.length; i++) {
if (items[i].getData().name == info.title) return dialog.showAddNewError('A script with the name is already added.');
}
dialog.showAddNewError();
dialog.group.addItems([
new ScriptWidget({name: info.title, enabled: true}, dialog)
]);
dialog.panels.setItem(dialog.listPanel);
dialog.actions.setMode('list');
});
} else if (action == 'save') {
var items = dialog.group.getItems(),
scripts = [];
for (var i = 0; i < items.length; i++) {
scripts.push(items[i].getData());
}
return new mw.Api().saveOption('userjs-scriptmanager-scripts', JSON.stringify(scripts)).then(function() {
mw.user.options.set('userjs-scriptmanager-scripts', JSON.stringify(scripts));
dialog.close();
});
} else if (action == 'import') {
var skins = ['common', 'monobook', 'minerva', 'vector', 'cologneblue', 'timeless'],
skinScripts = [];
for (var i = 0; i < skins.length; i++) {
skinScripts.push('User:' + mw.config.get('wgUserName') + '/' + skins[i] + '.js');
}
return new mw.Api().get({
action: 'query',
prop: 'revisions',
titles: skinScripts.join('|'),
rvprop: 'content',
rvslots: 'main',
formatversion: 2
}).then(function(res) {
for (var i = 0; i < res.query.pages.length; i++) {
var re = /(\/\/|)importScript\('(.*)'\)/g,
match,
page = res.query.pages[i];
if (!page.revisions) continue;
while (true) {
match = re.exec(page.revisions[0].slots.main.content);
if (!match) break;
// Normalize title
var title = new mw.Title(match[2]).getPrefixedText(),
items = dialog.group.getItems(),
duplicate = false;
for (var j = 0; j < items.length; j++) {
// Script is already added, skip
if (items[j].getData().name == title) {
duplicate = true;
break;
}
}
if (duplicate) continue;
dialog.group.addItems([new ScriptWidget({
name: title,
enabled: !match[1]
}, dialog)]);
}
}
});
}
});
};
var windowManager = new OO.ui.WindowManager(),
dialog = new ManagerDialog({
size: 'large'
});
$(document.body).append(windowManager.$element);
windowManager.addWindows([dialog]);
windowManager.openWindow(dialog);
mw.loader.addStyleTag(
'.userscript-listing { display: block; position: relative; }' +
'.userscript-listing.oo-ui-iconElement { padding-left: 2.5em; }' +
'.userscript-listing.oo-ui-iconElement .oo-ui-iconElement-icon { position: absolute; left: 0.6em; }' +
'.userscript-listing > * { vertical-align: middle; }' +
'.userscript-disabled { text-decoration: line-through; }' +
'.userscript-label { margin-right: 1em; }'
);
}
mw.loader.using('mediawiki.api').then(function() {
loadScripts();
});
['', '-sticky-header'].forEach(suffix => {
var portletLink = mw.util.addPortletLink(
'p-personal' + suffix,
'#',
'Scripts',
'scriptmanager',
'Manage user scripts',
'',
'#pt-watchlist' + suffix
);
if (portletLink) portletLink.addEventListener('click', manageScripts);
});
})();