MediaWiki:FileContentsByBot.js
Jump to navigation
Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
Documentation for this user script can be added at MediaWiki:FileContentsByBot. |
/**
* - FileContentsByBot -
* Script to transform, read and show hidden information by bot
* used by on [[Template:FileContentsByBot]]
*
* (c) Copyright 2012 by Rainer Rillke
* Attribution of redistributed code must be in
* EULA or UI.
* Use it for good, not for evil.
*
* @rev 3 (2012-08-01)
* @rev 4 (2012-11-12) Introduced API
* @author Rillke, 2012
*/
// Invoke automated jsHint-validation on save: A feature on WikimediaCommons
// Interested? See [[:commons:MediaWiki:JSValidator.js]].
/*global jQuery:false, mediaWiki:false*/
/*jshint curly:false*/
(function($, mw, storeKey) {
'use strict';
if (6 !== mw.config.get('wgNamespaceNumber') && 'User:DrTrigon/User:DrTrigonBot/logging' !== mw.config.get('wgPageName')) return;
var defaultGroups = {},
groups = $.extend(true, groups, defaultGroups),
groupDefinitionPrefix = '.bot-group-',
groupDefinitionMatrix = {
key: 'name',
toolTip: 'toolTip',
border: 'border',
multiple: 'multiple',
children: 'children'
},
getGroupParams = function($g) {
var gps = {};
$.each(groupDefinitionMatrix, function(key, def) {
gps[key] = $g.children(groupDefinitionPrefix + def).text();
});
return gps;
},
readGroups = function() {
var $groups = $('.bot-groupdefinition');
$groups.each(function(i, $g) {
$g = $($g);
var gps = getGroupParams($g);
if (!gps.key) return;
groups[gps.key] = gps;
if (gps.children) {
gps.children = {};
var $childGroups = $groups.children('.bot-child-groupdefinition');
$childGroups.each(function(i, $gc) {
$gc = $($gc);
var gpsc = getGroupParams($gc);
if (!gpsc.key) return;
gps.children[gpsc.key] = gpsc;
});
}
});
};
// Template has specified "groups".
// Extract them from HTML now
// For more information, please confer to
// https://commons.wikimedia.org/wiki/Template:FileContentsByBot/API
readGroups();
// Show the template/ infos, Reference to the file-div
var $table = $('#FileContentsByBot').show(),
$file = $('#file').find('a > img').parents('div:first'),
options = {},
optionCheckboxes = {},
$optButtonContainer = $('<div>', {
css: {
position: 'absolute',
bottom: '0px',
right: '0px',
margin: '5px',
padding: '5px',
border: '1px dotted black',
'background-color': 'rgba(220,220,220,0.7)',
overflow: 'hidden'
}
}),
$hoverPane = $('<div>', {
css: {
padding: '3px',
background: 'rgba(100,25,200,0.4)',
color: 'white',
'min-height': '10px',
'text-shadow': '0 1px 0 rgba(150,150,150,0.5)',
cursor: 'pointer'
},
text: " Save…"
}).appendTo($optButtonContainer),
$saveGroup = $('<fieldset>').append($('<legend>').text("Save selection into the")).appendTo($optButtonContainer),
$removeGroup = $('<fieldset>').append($('<legend>').text("Remove saved selection from")).hide().appendTo($optButtonContainer),
$saveAccount = $('<button>', {
title: "Save your selection in your user namespace",
text: "Account"
}).appendTo($saveGroup),
$saveBrowser = $('<button>', {
title: "Save your selection in your web browser",
text: "Browser"
}).appendTo($saveGroup),
prefs,
remoteOption;
// Hide the reminder/ hint that there are infos
$('#FileContentsByBot-Advertiser').remove();
mw.util.addCSS(
'div.growlUI { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACfFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBUAAAAAAAAAAAAAAAAAAAAAAAALdRwTgSMAAAANeR8ReyAUgCMMfhweiC0XgyZgsmgPgRxhtWcZgyhRpVc6mkVMplUahCkYgicMdBYUgCMOeiJ5w3oVgTEahCkTgSAdhyotkTlbr2MMdhsWgCWJ04sUfiMdhyyCyoQNeR8RfSBnt20zkT4Udi1wvHUkijB1v3cchisJexwNeSFIolFxu3QTfSIpiTRVq10tjzkUfiMniTMWfiV1v3kNdx9ksmkOfCAAgAAVfSRksml7w30ehi0QfiBLoVMjiTFVp1sNexo1k0AQeh0ZgSgNfSIkiDJ2vnhxvXRHn1IQcCAYgidtt3AtjzlzvXMSfiEJGgATeyJZqV84lEMIVBVhs2lCnE12vnkcVgAehi1BnUo5l0QObhlAmEhtt28Pcx15wXxfsWUVgSQAbgAVgSR8xnwLVRYhhS8afiYFGQkTfSJisGdAsEBPv09Lu0tJuUlWxlZUxFRGuEZYyFhCskJEtkQwojAzozN+xoA5qzl3wXdQuFB2xnRQulA6qjpfy19vzW9JtEZYuFhStFJBr0F6xnqK1Ipculxbu1s7rTtvx29703uI0ohOtE41pzV5w3qX25dKrUeEzoRx0XF5wXlPtU9KtEpawFp1wXN0xHJatFpKukqG0IRkxmR1xXN503mF1YVNvU1lvWVxx3FRwVFhyWF8zHxitmJLt0tlv2VbxlhfvV9SsFI8rDx5xXd3w3c+rj43qTdlx2U/qz+J04k2pjYuoC5ftV9sxmqN1438JI1wAAAAhnRSTlMAAxAYCggNHAwBIBQTBiMEFgQHCxonKhsYkiwmPHQrxanxRPG77Obqpq0WjEn8DMFQwt7vKaD+WtH+E1j14w313PzRGyjr+Xbq7eTo3dD7J/VZBq70/NJ+7tTwTeY/wSfb/vnrEMf64v6qCqXz6CLv5/4D1Ovnfe78nPr0rges/l7s1TVe8XMkZZgAAAGWSURBVHhexdBTkyUxGIDhtA6NsW3btte2bRt9rLFtG2vb+4e2u+ZiqvuczO0+F0mq3lTlq4D/Jdrfd90eGjjq5+UJ4LwTWyb+lgTzYd0taMVoNA6crQIQUd3vdDrdk1g5pLvHter1+pdZSQAi+ccLyuB22Ahp6Utqtfqbz25Il2cvPqWMxwAIjwMzGo3mT0A8pEcefaXVahdSQlghNSx89eAS0WQwGPrPOTP7hYsjlzzo7nz5udlsfrPZBTAl3GhovHnrNgB37raZTKbljExmf/S4lyTf5+Tm5Re8JUlyurAIMBXPfaFM1ZaW1ZLU4VM5+5MrKtv7KJ1d53uobai6BrBs2LjpWR3tI7183gJsbd022/x1VccOd2DHzl3134dpP+v3ALv27ts/ZqXMH3QD9h06fOSDxWI9dhzS+ciJk6de//p9+owSJxQIn1kRMc5BRbIrVyevXXdSYTIRysHFyFqXEjxUiHEFknv3Hzx0dJAIuJgQ5RFS2wsOjq6ujAusJzCVE5fLeIIxpILAlTwOh2cz5Pr+AdZMhGvAEGFPAAAAAElFTkSuQmCC") no-repeat 10px 10px } div.growlUI h1, div.growlUI h2 {color: white; padding: 5px 5px 5px 75px; text-align: left }'
);
var process = function() {
$optButtonContainer.appendTo($table.parent().css('position', 'relative'));
var group,
// padding: 3*2
hoverPaneHeight = $hoverPane.height() + 8,
// padding: 5*2
buttonContainerHeight = $optButtonContainer.height() + 10;
$optButtonContainer.height(hoverPaneHeight).hide();
var __onOver = function() {
$optButtonContainer.stop(true).animate({ height: buttonContainerHeight }, function() { $optButtonContainer.css('height', 'auto'); });
};
// Event handlers for the UI
$optButtonContainer.hoverIntent({
interval: 300,
over: __onOver,
out: function() { $optButtonContainer.stop(true).animate({ height: hoverPaneHeight }); },
timeout: 800
});
$hoverPane.prepend($.createIcon('ui-icon-close').css('cursor', 'pointer').attr('title', "close button pane").click(function() {
// Remove event handler to prevent stopping the removal
$optButtonContainer.off();
$optButtonContainer.slideUp();
})).click(__onOver);
if ($table.length !== 1 || $file.length !== 1) {
$('.hproduct-by-bot > table').show();
return;
}
// Prepare options
for (group in groups) {
if (groups.hasOwnProperty(group)) {
options[group] = true;
}
}
// Get options from local storage
prefs = $.jStorage.get(storeKey);
if (prefs) {
$.extend(options, prefs);
$('<button>', { text: "Browser", title: "Remove saved preferences from browser" }).click(function() {
$.jStorage.deleteKey(storeKey);
$(this).fadeOut();
}).button().appendTo($removeGroup.show());
}
// Get option from user JS
remoteOption = mw.libs.settingsManager.option( {
saveAt: storeKey,
editSummary: '[[MediaWiki:FileContentsByBot.js]] is updating preferences'
} );
remoteOption.fetchValue(function(remoteValue) {
if (!remoteValue) return;
$.extend(options, remoteValue);
for (var key in optionCheckboxes) {
if (optionCheckboxes.hasOwnProperty(key)) {
if (!options[key]) {
optionCheckboxes[key][0].checked = false;
optionCheckboxes[key].triggerHandler('change');
}
}
}
$('<button>', { text: "Account", title: "Remove saved preferences from account" }).click(function() {
var $btn = $(this),
oldText = $btn.text();
$btn.button({ disabled: true, label: "Removing…" });
remoteOption.setValue('').save().done(function() {
$btn.button({ disabled: false, label: oldText });
$btn.fadeOut();
});
}).button().appendTo($removeGroup.show());
});
// Show little face-icons
var $faceIcons = $('div.bot-Faces-Position-icon');
$faceIcons.each(function (i, el) {
var $el = $(el), // turn DOM-node into jQuery-object (array-like-object)
$scaleDiv = $el.children('div:first'), // find scale-div
$img = $scaleDiv.find('a.image > img'), // find image
ratio = parseFloat($scaleDiv.attr('class'), 10); // Making explicit we want a float
// Prevent running twice
if ($el.is(':visible')) return false;
// Scaling
$img.width($img.width() * ratio);
$img.height($img.height() * ratio);
$el.find('a').click(function(e) {
e.preventDefault();
});
}).show(); // Finally show the image
// Retrieve scale
var dimX = parseInt($table.find('#FileContentsByBot-DimX').text(), 10),
dimY = parseInt($table.find('#FileContentsByBot-DimY').text(), 10),
wRatio = $file.find('img').width()/dimX,
hRatio = $file.find('img').height()/dimY;
mw.util.addCSS('.botHighlighted { background: #cce !important; }');
$file.css('position', 'relative');
var _noteHoverIn = function(e) {
var $note = $(this),
$accociated = $note.data('botData_highlight');
$note.children('div').css('border', 'none').css('background', $note.data('botData_color')).stop(true).fadeTo(0, 0).fadeTo(500, 0.5);
if ($accociated) $accociated.css('background', '#dbb');
};
var _noteHoverOut = function(e) {
var $note = $(this),
$accociated = $note.data('botData_highlight');
$note.children('div').css('border', '2px solid #555').css('background', 'none').stop(true).fadeTo(0, 1);
if ($accociated) $accociated.css('background', 'none');
};
var _noteClick = function(e) {
var $el = $(this),
$accociated = $el.data('botData_highlight'),
jumpTo = $el.data('botData_jumpTo') || '#file',
removeOnly = $el.hasClass('botHighlighted');
$('.botHighlighted').removeClass('botHighlighted');
if (removeOnly) return;
$el.addClass('botHighlighted');
if ($accociated) $accociated.addClass('botHighlighted');
window.location.hash = jumpTo;
};
var _switchNotes = function(e) {
var $chb = $(this),
method = this.checked ? 'show' : 'hide';
$.each($chb.data('botData_notes_affected'), function(i, $note) {
$note[method]();
});
options[$chb.data('bot_option')] = this.checked;
};
var legends = {}, hasSave;
var addSaveButton = function() {
if (hasSave) return;
hasSave = true;
$saveAccount.button({ disabled: mw.user.isAnon() });
$saveBrowser.button().appendTo($saveGroup);
$optButtonContainer.show();
$saveAccount.click(function() {
var $btn = $(this),
oldText = $btn.text();
$btn.button({ disabled: true, label: "Saving…" });
remoteOption.setValue(options).save().done(function() {
$btn.button({ disabled: false, label: oldText });
$.growlUI("Saved", "Your selection was saved in your user namespace and will be automatically applied in future");
});
});
$saveBrowser.click(function() {
$.jStorage.set(storeKey, options);
$.growlUI("Saved", "Your selection was saved to the current browser and will be automatically applied in future");
});
};
var botImageNote = function(x, y, w, h, content, color, $colorNode, $toHighlight, toJumpTo, border, background, $legend, key) {
if (!w || !h) return;
var _getColor = function() {
return Math.round(Math.random()*255);
};
if (!color && $colorNode) {
color = 'rgb(' + _getColor() + ',' + _getColor() + ',' + _getColor() + ')';
}
if (!$toHighlight && $colorNode) $toHighlight = $colorNode;
if (!color) color = 'yellow';
if (!border) border = '2px solid';
if (!background) background = 'none';
$colorNode.css('border', border + ' ' + color);
var pos = 'top:' + Math.round(y*hRatio) + 'px; left:' + Math.round(x*wRatio) + 'px; height:' + Math.round(h*hRatio) + 'px; width:' + Math.round(w*wRatio) + 'px';
var $note = $('<div>', { style: 'position:absolute; ' + pos + '; background:' + background + '; border:' + border + ' ' + color + '; cursor:pointer;' }).appendTo($file);
var $content = $('<div>', { style: 'height:100%; width:100%; border:solid 1px #555;', title: content }).appendTo($note);
$note.data('botData_color', color).data('botData_highlight', $toHighlight).hover(_noteHoverIn, _noteHoverOut);
if ($toHighlight) {
$toHighlight.css('cursor', 'pointer');
$toHighlight.data('botData_highlight', $note);
$note.data('botData_jumpTo', toJumpTo);
$toHighlight.click(_noteClick);
$toHighlight.attr('title', 'click to highlight in image');
$note.click(_noteClick);
}
if ($legend) {
var s = $legend.selector,
checked = options[key] ? 'checked="checked"' : '';
if (!checked) $note.hide();
if (!legends[s]) {
legends[s] = [$note];
optionCheckboxes[key] = $('<input type="checkbox" ' + checked + ' title="Click to toggle image notes">')
.change(_switchNotes).data('bot_option', key).data('botData_notes_affected', legends[s]).appendTo($legend);
} else {
legends[s].push($note);
}
}
// Save-button
addSaveButton();
return $note;
};
$.each(groups, function(groupName, groupProperties) {
var pfx = '.bot-' + groupName,
groupSelector = pfx,
positionSelector = pfx + '-Position',
posLeft = pfx + '-Position-left',
posTop = pfx + '-Position-top',
posWidth = pfx + '-Position-width',
posHeight = pfx + '-Position-height',
idSelector = pfx + '-ID',
colorSelector = pfx + '-Color',
rgbSelector = pfx + '-RGB',
$wholeSection = $table.find('#FileContentsByBot-' + groupName),
$legend = $wholeSection.find(pfx + '-legend'),
hashLink = '#FileContentsByBot-' + groupName;
$wholeSection.find(groupSelector).each(function(i, el) {
var $el = $(el),
$pos = $el.find(positionSelector),
$rgb = $el.find(rgbSelector);
if (0 === $pos.length) return;
botImageNote(
$pos.find(posLeft).text(),
$pos.find(posTop).text(),
$pos.find(posWidth).text(),
$pos.find(posHeight).text(),
groupProperties.toolTip
.replace('%ID%', $el.find(idSelector).text())
.replace('%COLOR%', $el.find(colorSelector).text()),
$rgb.length ? 'rgb' + $rgb.text() : '',
$pos,
null,
hashLink,
groupProperties.border,
null,
$legend,
groupName
);
// Prevent undefined-error
if (!groupProperties.children) groupProperties.children = [];
// Let's do not overcomplicate it with recursive children-processing
$.each(groupProperties.children, function(groupName_c, groupProperties_c) {
groupProperties_c.multiple = groupProperties_c.multiple || 1;
var pfx_c = '.bot-' + groupName_c,
ms = groupProperties_c.multiple > 1 ? '-%NO%' : '',
groupSelector_c = pfx_c,
positionSelector_c = pfx_c + '-Position',
posLeft_c = pfx_c + ms + '-Position-left',
posTop_c = pfx_c + ms + '-Position-top',
posWidth_c = pfx_c + ms + '-Position-width',
posHeight_c = pfx_c + ms + '-Position-height',
colorSelector_c = pfx_c + '-Color',
rgbSelector_c = pfx_c + 'RGB';
$el.find(groupSelector_c).each(function(c_number, child) {
var $child = $(child),
$rgb = $child.find(rgbSelector);
for (var counter = 1; counter < groupProperties_c.multiple + 1; counter++) {
botImageNote(
$child.find(posLeft_c.replace('%NO%', counter)).text(),
$child.find(posTop_c.replace('%NO%', counter)).text(),
$child.find(posWidth_c.replace('%NO%', counter)).text(),
$child.find(posHeight_c.replace('%NO%', counter)).text(),
groupProperties_c.toolTip
.replace('%ID%', $el.find(idSelector).text())
.replace('%NO%', counter)
.replace('%COLOR%', $child.find(colorSelector).text()),
$rgb.length ? 'rgb' + $rgb.text() : '',
$child,
null,
hashLink,
groupProperties_c.border,
null,
$legend,
groupName
);
}
});
});
});
});
$(document).triggerHandler('scriptLoaded', ['FileContentsByBot']);
};
$(function() {
mw.loader.using([
'mediawiki.user',
'jquery.hoverIntent',
'jquery.jStorage',
'ext.gadget.SettingsManager',
'ext.gadget.jquery.blockUI',
'ext.gadget.libJQuery'
], process);
});
})(jQuery, mediaWiki, 'FileContentsByBotOpt');