MediaWiki:Imagemap-Highlight.js: mudanças entre as edições
Ir para navegação
Ir para pesquisar
(Criou página com 'mw.loader.load('//he.wikipedia.org/w/index.php?title=Mediawiki:Scripts/Imagemap-Highlight.js&action=raw&ctype=text/javascript');') |
Sem resumo de edição |
||
Linha 1: | Linha 1: | ||
mw. | $(function() { | ||
var | |||
//add this class to all elements created by the script. the reason is that we call the script again on | |||
//window resize, and use the class to remove all the "artefacts" we created in the previous run. | |||
myClassName = 'imageMapHighlighterArtefacts', | |||
liHighlightClass = 'liHighlighting', | |||
specialAreaMark = 'area_mark', | |||
specialLiClassesMark = 'list_classes', | |||
specialAreaMarkFile = 'area_mark_file', | |||
// "2d context" attributes used for highlighting. | |||
areaHighLighting = { | |||
fillStyle: 'rgba(0,0,0,0.35)', | |||
strokeStyle: 'yellow', | |||
lineJoin: 'round', | |||
lineWidth: 2 | |||
}, | |||
//every imagemap that wants highlighting, should reside in a div of this 'class': | |||
hilightDivMarker = '.imageMapHighlighter', | |||
// specifically for wikis - redlinks tooltip adds this message | |||
pt = mw && mw.config && mw.config.get('wgUserLanguage') == 'pt', | |||
expandLegend = pt ? 'mostrar links por texto' : 'show links as text', | |||
collapseLegend = pt ? 'ocultar links com texto' : 'hide links as text', | |||
files = []; | |||
function drawMarker(context, areas) { // this is where the magic is done. | |||
function drawPoly(coords) { | |||
context.moveTo(coords.shift(), coords.shift()); | |||
while (coords.length) | |||
context.lineTo(coords.shift(), coords.shift()); | |||
} | |||
for (var i in areas) { | |||
var coords = areas[i].coords.split(','); | |||
context.beginPath(); | |||
switch (areas[i].shape) { | |||
case 'rect': | |||
drawPoly([coords[0], coords[1], coords[0], coords[3], coords[2], coords[ | |||
3], coords[2], coords[1]]); | |||
break; | |||
case 'circle': | |||
context.arc(coords[0], coords[1], coords[2], 0, Math.PI * 2); | |||
break; //x,y,r,startAngle,endAngle | |||
case 'poly': | |||
drawPoly(coords); | |||
break; | |||
} | |||
context.closePath(); | |||
context.stroke(); | |||
context.fill(); | |||
} | |||
} | |||
function mouseAction(e) { | |||
var $this = $(this), | |||
activate = e.type == 'mouseover', | |||
caption = $this.text(), | |||
ol = $this.parent(), | |||
context = ol.data('context'), | |||
special = ol.data(specialAreaMark), | |||
specialFile = ol.data(specialAreaMarkFile); //read JSON file addition | |||
if (specialFile) { | |||
if (files[specialFile]) { | |||
$.extend(special, files[specialFile]); | |||
always(activate, caption, context, ol, special, $this); | |||
} else { | |||
$.get(mw.util.wikiScript(), { | |||
title: specialFile, | |||
action: 'raw' | |||
}) | |||
.done(function(data) { | |||
files[specialFile] = JSON.parse(data); | |||
$.extend(special, files[specialFile]); | |||
}) | |||
.always(function() { | |||
always(activate, caption, context, ol, special, $this); | |||
}); | |||
} | |||
} else | |||
always(activate, caption, context, ol, special, $this); | |||
} | |||
function always(activate, caption, context, ol, special, $this) { | |||
$this.toggleClass(liHighlightClass, activate); // mark/unmark the list item. | |||
context.clearRect(0, 0, context.canvas.width, context.canvas.height); // prepare for a new day. | |||
ol.find('li') | |||
.each(function() { | |||
var $li = $(this); | |||
var licap = $li.text(); | |||
var param; | |||
if (activate && licap === caption) { // highlight!!! | |||
param = special && (special.hover && special.hover[licap] | |||
|| getblocks(special, licap)) || areaHighLighting; | |||
} else { | |||
param = special && special.nover && (special.nover[licap] || special.nover | |||
.default); | |||
} | |||
if (param) { | |||
$.extend(context, param); | |||
drawMarker(context, $li.data('areas')); | |||
} | |||
}); | |||
} | |||
function getblocks(special, licap) { | |||
if (special.hoverblocks) { | |||
if (special.hoverblocks[licap]) | |||
return special.hoverblocks[licap].value; | |||
for (var key in special.hoverblocks) | |||
if (special.hoverblocks[key] && special.hoverblocks[key].list.indexOf(licap) >=0 ) | |||
return special.hoverblocks[key].value; | |||
} | |||
if (special.hover) | |||
return special.hover.default; | |||
} | |||
function handleOneMap() { | |||
var img = $(this), | |||
w = img.width(), | |||
h = img.height(), | |||
infoIcon = img.next(), | |||
parent = img.parent(), | |||
map = img.siblings('map:first'), | |||
dims = { | |||
position: 'absolute', | |||
width: w + 'px', | |||
height: h + 'px', | |||
border: 0, | |||
top: 0, | |||
left: 0 | |||
}, | |||
specialHighlight = img.closest(hilightDivMarker) | |||
.data(specialAreaMark), | |||
specialLiClasses = img.closest(hilightDivMarker) | |||
.data(specialLiClassesMark), | |||
specialHover = img.closest(hilightDivMarker) | |||
.data(specialAreaMarkFile); | |||
if (!('area', map) | |||
.length) | |||
return; //not an imagemap. inside "each" anonymous function, 'return' means "continue". | |||
var jcanvas = $('<canvas>', { | |||
'class': myClassName | |||
}) | |||
.css(dims) | |||
.attr({ | |||
width: w, | |||
height: h | |||
}); | |||
var bgimg = $('<img>', { | |||
'class': myClassName, | |||
src: img.attr('src') | |||
}) | |||
.css(dims); //completely inert image. this is what we see. | |||
var context = $.extend(jcanvas[0].getContext("2d"), areaHighLighting); | |||
// this is where the magic is done: prepare a sandwich of the inert bgimg at the bottom, | |||
// the canvas above it, and the original image on top, | |||
// so canvas won't steal the mouse events. | |||
// pack them all TIGHTLY in a newly minted "relative" div, so when page chnage | |||
// (other scripts adding elements, window resize etc.), canvas and imagese remain aligned. | |||
var div = $('<div>') | |||
.css({ | |||
position: 'relative', | |||
width: w + 'px', | |||
height: h + 'px' | |||
}); | |||
img.before(div); // put the div just above the image, and ... | |||
div.append(bgimg) // place the background image in the div | |||
.append(jcanvas) // and the canvas. both are "absolute", so they don't occupy space in the div | |||
.append(img); // now yank the original image from the window and place it on the div. | |||
img.fadeTo(1, 0); // make the image transparent - we see canvas and bgimg through it. | |||
// the original, now transparent image is creating our mouse events | |||
infoIcon.css({ | |||
position: 'relative' | |||
}); // set position to info icon | |||
var ol = $('<ol>', { | |||
'class': myClassName | |||
}) | |||
.css({ | |||
clear: 'both', | |||
margin: 0, | |||
listStyle: 'none', | |||
maxWidth: w + 'px', | |||
position: 'relative' | |||
}) | |||
.data(specialAreaMark, specialHighlight) | |||
.data(specialAreaMarkFile, specialHover) | |||
.data('context', context); | |||
var oldiv = $('<div>') | |||
.html(ol) | |||
.css({ | |||
clear: 'both', | |||
margin: 0, | |||
listStyle: 'none', | |||
maxWidth: w + 'px', | |||
position: 'relative' | |||
}) | |||
.attr({ | |||
'data-expandtext': expandLegend, | |||
'data-collapsetext': collapseLegend | |||
}); | |||
// ol below image parent, hr below ol. original caption pushed below hr. | |||
var $hr = $('<hr>', { 'class': myClassName }).css('clear', 'both'); | |||
parent.after($hr).after(oldiv); | |||
$hr.clone().insertBefore($(oldiv)); | |||
var lis = {}; //collapse areas with same caption to one list item | |||
var someli; // select arbitrary one | |||
$('area', map) | |||
.each(function() { | |||
var text = this.title; | |||
var li = lis[text]; // title already met? use the same li | |||
if (!li) { //no? create a new one. | |||
var href = this.href; | |||
lis[text] = li = $('<li>', { | |||
'class': myClassName | |||
}) | |||
.append($('<a>', { | |||
href: href, | |||
text: text | |||
})) | |||
.on('mouseover mouseout', mouseAction) | |||
.data('areas', []) | |||
.addClass(specialLiClasses && (specialLiClasses[text] || | |||
specialLiClasses['default'])) | |||
.appendTo(ol); | |||
if (specialLiClasses && specialLiClasses[text + ' super']) | |||
li.find('a') | |||
.addClass(specialLiClasses[text + ' super']); | |||
} | |||
li.data('areas') | |||
.push(this); //add the area to the li | |||
someli = li; // whichever - we just want one... | |||
$(this) | |||
.on('mouseover mouseout', function(e) { | |||
li.trigger(e); | |||
}); | |||
}); | |||
if (specialLiClasses && specialLiClasses.order) { | |||
specialLiClasses.order.forEach(function(elem) { | |||
var what = $(elem.what); | |||
if (elem.dir === 'before') { | |||
what.each(function(inner){$(what[inner]) | |||
.insertBefore($(what[inner]).parent().find(elem.where))}); | |||
} else { | |||
what.each(function(inner){$(what[inner]) | |||
.insertAfter($(what[inner]).parent().find(elem.where))}); | |||
} | |||
}); | |||
} | |||
if (specialLiClasses && specialLiClasses.todefault) { | |||
specialLiClasses.todefault.forEach(function(elem) { | |||
$(elem).addClass(specialLiClasses.default); | |||
}); | |||
} | |||
if (someli) { | |||
someli.trigger('mouseout'); | |||
} | |||
oldiv.addClass('mw-collapsed') | |||
.makeCollapsible(); | |||
ol.attr('style', ol.attr('style') | |||
.replace('none', 'disc')); | |||
} | |||
function init() { | |||
mw.util.addCSS('li.' + myClassName + | |||
'{white-space:nowrap; font-size:88.36%;}\n' + //css for li element | |||
'li.' + liHighlightClass + '{background-color:yellow;}\n' + //css for highlighted li element. | |||
'.rtl li.' + myClassName + '{float: right; margin-left: 1.5em;}\n' + | |||
'.ltr li.' + myClassName + '{float: left; margin-right: 1.5em;}\n' + | |||
hilightDivMarker + ' .mw-collapsible-toggle {float: none}'); | |||
$(hilightDivMarker + ' img') | |||
.each(handleOneMap); | |||
} | |||
//has at least one "imagehighlight" div, and canvas-capable browser: | |||
if ( $(hilightDivMarker).length && $('<canvas>')[0].getContext ) { | |||
mw.loader.using(['jquery.makeCollapsible', 'mediawiki.util']) | |||
.done(init); | |||
} | |||
}); |
Edição das 14h22min de 2 de agosto de 2022
$(function() {
var
//add this class to all elements created by the script. the reason is that we call the script again on
//window resize, and use the class to remove all the "artefacts" we created in the previous run.
myClassName = 'imageMapHighlighterArtefacts',
liHighlightClass = 'liHighlighting',
specialAreaMark = 'area_mark',
specialLiClassesMark = 'list_classes',
specialAreaMarkFile = 'area_mark_file',
// "2d context" attributes used for highlighting.
areaHighLighting = {
fillStyle: 'rgba(0,0,0,0.35)',
strokeStyle: 'yellow',
lineJoin: 'round',
lineWidth: 2
},
//every imagemap that wants highlighting, should reside in a div of this 'class':
hilightDivMarker = '.imageMapHighlighter',
// specifically for wikis - redlinks tooltip adds this message
pt = mw && mw.config && mw.config.get('wgUserLanguage') == 'pt',
expandLegend = pt ? 'mostrar links por texto' : 'show links as text',
collapseLegend = pt ? 'ocultar links com texto' : 'hide links as text',
files = [];
function drawMarker(context, areas) { // this is where the magic is done.
function drawPoly(coords) {
context.moveTo(coords.shift(), coords.shift());
while (coords.length)
context.lineTo(coords.shift(), coords.shift());
}
for (var i in areas) {
var coords = areas[i].coords.split(',');
context.beginPath();
switch (areas[i].shape) {
case 'rect':
drawPoly([coords[0], coords[1], coords[0], coords[3], coords[2], coords[
3], coords[2], coords[1]]);
break;
case 'circle':
context.arc(coords[0], coords[1], coords[2], 0, Math.PI * 2);
break; //x,y,r,startAngle,endAngle
case 'poly':
drawPoly(coords);
break;
}
context.closePath();
context.stroke();
context.fill();
}
}
function mouseAction(e) {
var $this = $(this),
activate = e.type == 'mouseover',
caption = $this.text(),
ol = $this.parent(),
context = ol.data('context'),
special = ol.data(specialAreaMark),
specialFile = ol.data(specialAreaMarkFile); //read JSON file addition
if (specialFile) {
if (files[specialFile]) {
$.extend(special, files[specialFile]);
always(activate, caption, context, ol, special, $this);
} else {
$.get(mw.util.wikiScript(), {
title: specialFile,
action: 'raw'
})
.done(function(data) {
files[specialFile] = JSON.parse(data);
$.extend(special, files[specialFile]);
})
.always(function() {
always(activate, caption, context, ol, special, $this);
});
}
} else
always(activate, caption, context, ol, special, $this);
}
function always(activate, caption, context, ol, special, $this) {
$this.toggleClass(liHighlightClass, activate); // mark/unmark the list item.
context.clearRect(0, 0, context.canvas.width, context.canvas.height); // prepare for a new day.
ol.find('li')
.each(function() {
var $li = $(this);
var licap = $li.text();
var param;
if (activate && licap === caption) { // highlight!!!
param = special && (special.hover && special.hover[licap]
|| getblocks(special, licap)) || areaHighLighting;
} else {
param = special && special.nover && (special.nover[licap] || special.nover
.default);
}
if (param) {
$.extend(context, param);
drawMarker(context, $li.data('areas'));
}
});
}
function getblocks(special, licap) {
if (special.hoverblocks) {
if (special.hoverblocks[licap])
return special.hoverblocks[licap].value;
for (var key in special.hoverblocks)
if (special.hoverblocks[key] && special.hoverblocks[key].list.indexOf(licap) >=0 )
return special.hoverblocks[key].value;
}
if (special.hover)
return special.hover.default;
}
function handleOneMap() {
var img = $(this),
w = img.width(),
h = img.height(),
infoIcon = img.next(),
parent = img.parent(),
map = img.siblings('map:first'),
dims = {
position: 'absolute',
width: w + 'px',
height: h + 'px',
border: 0,
top: 0,
left: 0
},
specialHighlight = img.closest(hilightDivMarker)
.data(specialAreaMark),
specialLiClasses = img.closest(hilightDivMarker)
.data(specialLiClassesMark),
specialHover = img.closest(hilightDivMarker)
.data(specialAreaMarkFile);
if (!('area', map)
.length)
return; //not an imagemap. inside "each" anonymous function, 'return' means "continue".
var jcanvas = $('<canvas>', {
'class': myClassName
})
.css(dims)
.attr({
width: w,
height: h
});
var bgimg = $('<img>', {
'class': myClassName,
src: img.attr('src')
})
.css(dims); //completely inert image. this is what we see.
var context = $.extend(jcanvas[0].getContext("2d"), areaHighLighting);
// this is where the magic is done: prepare a sandwich of the inert bgimg at the bottom,
// the canvas above it, and the original image on top,
// so canvas won't steal the mouse events.
// pack them all TIGHTLY in a newly minted "relative" div, so when page chnage
// (other scripts adding elements, window resize etc.), canvas and imagese remain aligned.
var div = $('<div>')
.css({
position: 'relative',
width: w + 'px',
height: h + 'px'
});
img.before(div); // put the div just above the image, and ...
div.append(bgimg) // place the background image in the div
.append(jcanvas) // and the canvas. both are "absolute", so they don't occupy space in the div
.append(img); // now yank the original image from the window and place it on the div.
img.fadeTo(1, 0); // make the image transparent - we see canvas and bgimg through it.
// the original, now transparent image is creating our mouse events
infoIcon.css({
position: 'relative'
}); // set position to info icon
var ol = $('<ol>', {
'class': myClassName
})
.css({
clear: 'both',
margin: 0,
listStyle: 'none',
maxWidth: w + 'px',
position: 'relative'
})
.data(specialAreaMark, specialHighlight)
.data(specialAreaMarkFile, specialHover)
.data('context', context);
var oldiv = $('<div>')
.html(ol)
.css({
clear: 'both',
margin: 0,
listStyle: 'none',
maxWidth: w + 'px',
position: 'relative'
})
.attr({
'data-expandtext': expandLegend,
'data-collapsetext': collapseLegend
});
// ol below image parent, hr below ol. original caption pushed below hr.
var $hr = $('<hr>', { 'class': myClassName }).css('clear', 'both');
parent.after($hr).after(oldiv);
$hr.clone().insertBefore($(oldiv));
var lis = {}; //collapse areas with same caption to one list item
var someli; // select arbitrary one
$('area', map)
.each(function() {
var text = this.title;
var li = lis[text]; // title already met? use the same li
if (!li) { //no? create a new one.
var href = this.href;
lis[text] = li = $('<li>', {
'class': myClassName
})
.append($('<a>', {
href: href,
text: text
}))
.on('mouseover mouseout', mouseAction)
.data('areas', [])
.addClass(specialLiClasses && (specialLiClasses[text] ||
specialLiClasses['default']))
.appendTo(ol);
if (specialLiClasses && specialLiClasses[text + ' super'])
li.find('a')
.addClass(specialLiClasses[text + ' super']);
}
li.data('areas')
.push(this); //add the area to the li
someli = li; // whichever - we just want one...
$(this)
.on('mouseover mouseout', function(e) {
li.trigger(e);
});
});
if (specialLiClasses && specialLiClasses.order) {
specialLiClasses.order.forEach(function(elem) {
var what = $(elem.what);
if (elem.dir === 'before') {
what.each(function(inner){$(what[inner])
.insertBefore($(what[inner]).parent().find(elem.where))});
} else {
what.each(function(inner){$(what[inner])
.insertAfter($(what[inner]).parent().find(elem.where))});
}
});
}
if (specialLiClasses && specialLiClasses.todefault) {
specialLiClasses.todefault.forEach(function(elem) {
$(elem).addClass(specialLiClasses.default);
});
}
if (someli) {
someli.trigger('mouseout');
}
oldiv.addClass('mw-collapsed')
.makeCollapsible();
ol.attr('style', ol.attr('style')
.replace('none', 'disc'));
}
function init() {
mw.util.addCSS('li.' + myClassName +
'{white-space:nowrap; font-size:88.36%;}\n' + //css for li element
'li.' + liHighlightClass + '{background-color:yellow;}\n' + //css for highlighted li element.
'.rtl li.' + myClassName + '{float: right; margin-left: 1.5em;}\n' +
'.ltr li.' + myClassName + '{float: left; margin-right: 1.5em;}\n' +
hilightDivMarker + ' .mw-collapsible-toggle {float: none}');
$(hilightDivMarker + ' img')
.each(handleOneMap);
}
//has at least one "imagehighlight" div, and canvas-capable browser:
if ( $(hilightDivMarker).length && $('<canvas>')[0].getContext ) {
mw.loader.using(['jquery.makeCollapsible', 'mediawiki.util'])
.done(init);
}
});