/**
* Stockphoto - shows download and attribution buttons
*
* Revision: 2026-03-27
* Dependencies: mediawiki.util, mediawiki.user
* Source: https://commons.wikimedia.org/wiki/MediaWiki:Gadget-Stockphoto.js
*
* Copyright 2010 by Magnus Manske
* Copyright 2011 Timo Tijhof
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* eslint-env browser */
/* global $, mw */
(function () {
'use strict';
var stockPhoto, modalLoad;
if (
// Already loaded
window.stockPhoto
// Unsupported skin
|| !/^(?:vector|vector-2022|monobook|timeless)$/.test(mw.config.get('skin'))
// Not a file page
|| mw.config.get('wgCanonicalNamespace') !== 'File'
// Not regular view
|| mw.config.get('wgAction') !== 'view'
) {
// Do not load
return;
}
/**
* @param {string} opt.pageName
* @param {string} opt.originalUrl
* @param {jQuery} opt.dom Keys $aut, $src, $attr, $credit, $licenseAut, $creator
* @param {jQuery} opt.$licenses
*/
function File(opt) {
var re, file = this;
// Try the SDC caption first. This might usefully be enhanced to try
// languages other than the user's preferred one.
var caption = ( mw.config.get('wbEntity') || { labels: {} } ).labels[mw.config.get('wgUserLanguage')];
if (caption != undefined) {
file.title = caption.value;
} else {
// Fall back to file name
// Strip namespace prefix and file suffix, use spaces for underscore.
file.title = opt.pageName.replace(/^[^:]+:|\.[^.]+$/g, '').replace(/_+/g, ' ');
}
file.url = opt.originalUrl;
// Remove any "_" or "utm" params (T414338)
const urlObj = new URL(opt.originalUrl);
urlObj.search = '?download';
file.downloadUrl = urlObj.toString();
file.backlink = 'https://commons.wikimedia.org/wiki/' + mw.util.wikiUrlencode(opt.pageName);
file.audio = opt.dom.$file.find('audio').length > 0;
file.video = opt.dom.$file.find('video').length > 0;
file.audio_or_video = opt.dom.$file.find('audio, video').length > 0;
file.embedDefaultChoice = 300;
// Grab other resolution options from the DOM
//
// These are generated by MediaWiki based on $wgImageLimits and $wgThumbnailSteps for
// raster images, SVGs, and videos (so long as the original is wider than 320px, per
// the first value in $wgImageLimits).
//
// Also include `.mw-filepage-resolutioninfo` ("Size of this preview") so that
// images with small nominal size (e.g. SVG icons, small vectors) offer a small
// embed choice as well.
//
// Test cases:
// * Photo (3840px step is out of range) - https://commons.wikimedia.org/wiki/File:Adam_Simmons,_Swaffham_Raceway,_2017-03-11.JPG
// * Photo (original is web safe, small enough to be used preview, big enough to have 320px and 640px sizes) - https://commons.wikimedia.org/wiki/File:CorusSteelworks.jpg
// * Large vector - https://commons.wikimedia.org/wiki/File:Example.svg
// * Small vector - https://commons.wikimedia.org/wiki/File:Tango-style_info_icon.svg
// * Video high res - https://commons.wikimedia.org/wiki/File:Big_Buck_Bunny_4K.webm
// * Video low res - https://commons.wikimedia.org/wiki/File:Video_Biel_Barcel%C3%B3.ogv
// * Audo - https://commons.wikimedia.org/wiki/File:Air_(Bach).ogg
//
//
// These are not available for audio files.
//
// For videos we mostly ignore these because they are thumbnails of the video poster,
// which follow $wgThumbnailSteps instead of transcode sizes. Use file.videoPlayers instead.
const widths = new Map();
let largestThumbInfo = null;
const previewThumb = opt.dom.$file.find('img').get(0);
const previewThumbInfo = previewThumb ? mw.util.parseImageUrl(previewThumb.src) : null;
const thumbs = opt.dom.$file.find('.mw-filepage-resolutioninfo a.mw-thumbnail-link[href], .mw-filepage-other-resolutions a.mw-thumbnail-link[href]')
.toArray()
.map((element) => {
// Extract "300" from "upload.wikimedia.org/xx/300px-thumb.svg.png"
let info = mw.util.parseImageUrl(element.href);
if (!info || !info.width || !info.resizeUrl) {
// FIXME (March 2026).
// Video poster thumbnails have a double dash like "500px--thumb.webm.jpg",
// which mw.util.parseImageUrl can't parse. Try again.
// TODO: Remove once either TimedMediaHandler or mw.util is fixed?
const altHref = element.href.replace('px--', 'px-');
if (altHref !== element.href) {
info = mw.util.parseImageUrl(altHref);
}
}
if (info && info.width && info.resizeUrl) {
return { info, href: element.href };
}
})
.filter(Boolean)
.sort((a, b) => a.info.width - b.info.width);
// T421557: If the original is smaller than 800px (or `$wgImageLimits[user.options.get('imagesize')]`),
// and if the original is safe and compatible for <img> (i.e. JPEG/GIF/PNG, not TIFF/PDF/SVG),
// then MediaWiki omits "other-resolutions" links. MediaWiki uses the original as preview in that
// case, which we can take as fallback
if (!thumbs.length && previewThumb && previewThumbInfo && !previewThumbInfo.width) {
// Reduce default 300px as needed to avoid blurry upscaling
file.embedDefaultChoice = Math.min(file.embedDefaultChoice, previewThumb.width);
// Strip any "?_=timestamp" parameter
const srcUrl = new URL(previewThumb.src);
srcUrl.searchParams.delete('_');
widths.set(file.embedDefaultChoice, srcUrl.toString());
}
for (const { info, href } of thumbs) {
widths.set(info.width, href);
largestThumbInfo = info;
// "width <= img.width()" is insufficient because thumbnail steps means we generally round up,
// so the thumbnail we display in the preview area actually larger than the CSS width of the
// preview area. Compare to the parsed thumb info instead and default to selecting that one.
if (previewThumbInfo ? (info.width <= previewThumbInfo.width) : (info.width <= opt.dom.$file.find('img').width())) {
file.embedDefaultChoice = info.width;
}
}
file.widths = widths;
if (file.video) {
// Transcode sizes (e.g. 240P, 360P, 480P, 720P, or 1080P).
//
// We exclude 2K and above because this is about the size of the inline embed player
// (not quality of download, stream, or fullscreen playback). All players offer all sizes,
// and there is no need for a 2K or 4K inline player at 1dppx.
//
// Compute corresponding poster thumbnails for "Use this file on the web > BBCode",
// which links an image to a web page.
file.videoPlayers = new Set();
for (const element of $('.mw-filepage-transcodestatus tbody tr td:first-child').toArray().reverse()) {
const m = element.textContent.trim().match(/(\d\d+)P$/);
const width = Number(m && m[1]);
if (width && width <= 1080) {
file.videoPlayers.add(width);
file.widths.set(
width,
// Fallback to default poster on low res videos
largestThumbInfo
? largestThumbInfo.resizeUrl(
mw.util.adjustThumbWidthForSteps(width, largestThumbInfo.width)
)
: $('#file video').attr('poster')
);
if (width < 1000) {
file.embedDefaultChoice = width;
}
}
}
}
file.gfdlNote = false;
file.attrRequired = true;
file.computeMetadata(opt.dom, opt.$licenses);
}
File.prototype.getLicenseLabel = function (short) {
if (/^cc[- ]/i.test(short)) {
// CC-BY-SA-3.0 -> CC BY-SA 3.0
// CC BY-SA 3.0 -> CC BY-SA 3.0
return short.toUpperCase()
.replace(/^(CC)-/, '$1 ')
.replace(/[- ]([\d.]+)$/, ' $1');
}
return short;
};
File.prototype.getLicensePrio = function (short) {
// 1. Public domain or CC 0
return /^(public domain|cc0)/i.test(short) ? 1 :
// 2. Creative Commons, e.g. "CC-BY-SA-#" (most templates),
// or "CC BY-SA #" (some templates)
/^cc[- ]by(-sa)?[- ]\d/i.test(short) ? 2 :
// 3. Eveything else (e.g. GFDL)
3;
};
// Set #author, #attribution, and #licenses
File.prototype.computeMetadata = function (dom, $licenses) {
var credit, creditHtml, attribution, licenses,
via = stockPhoto.i18n.via_wikimedia_commons,
file = this,
author = dom.$aut.text().trim(),
source = dom.$src.text().trim();
// Clean up 'author'
if (dom.$aut.find('.boilerplate').length) {
author = '';
}
// Detect manual "unknown", or {{Unknown}}, or {{Unknown|author}} with its display-none duplicate
if (author.match(/^([Uu]nknown( author)?|Unknown authorUnknown author)$/)) {
author = '';
}
author = author.replace(/\s*\(talk\)$/i, '');
if (author.indexOf('Original uploader was') !== -1) {
author = author.replace(/\s*Original uploader was\s*/g, '');
}
if (author.slice(0, 3) === '[▼]') {
author = author.slice(3); // ▼ (Black Down-Pointing Triangle)
author = author.split('Description')[0].trim();
}
// Clean up 'source'
if (dom.$src.find('.boilerplate').length) {
source = '';
}
if (dom.$src.find('.int-own-work').length) {
source = '';
}
// Fallback
if (!author && source.length < 50) {
author = source;
}
// Parse licenses
licenses = [];
$licenses.each(function () {
var $tpl = $(this),
short = $tpl.find('.licensetpl_short').text().trim();
if (!short) { return; }
licenses.push({
link: $tpl.find('.licensetpl_link').text().trim(),
short: short,
label: file.getLicenseLabel(short),
prio: file.getLicensePrio(short),
link_req: $tpl.find('.licensetpl_link_req').text().trim(),
attr_req: $tpl.find('.licensetpl_attr_req').text().trim()
});
});
// Use prefered if possible (like CommonsMetadata API)
licenses.sort(function (a, b) { return a.prio - b.prio; });
if (licenses[0] && licenses[0].prio < 3) {
licenses.splice(1);
}
file.licenses = licenses.map(function (v) {
if (v.attr_req === 'false') {
file.attrRequired = false;
}
if (v.short.indexOf('GFDL') !== -1) {
file.gfdlNote = true;
}
if (v.link_req === 'true' && v.link) {
return {
html: '<a href="' + v.link + '">' + mw.html.escape(v.label) + '</a>',
txt: v.label + ' <' + v.link + '>'
};
} else {
return { html: mw.html.escape(v.label), txt: v.label };
}
});
// Determine the credit line
if (dom.$credit.length) {
// Custom credit line
credit = dom.$credit.text();
creditHtml = dom.$credit.html();
}
if (!credit) {
// No custom credit line
// Default credit line: attribution + (if required) license + via promo
if (dom.$attr.length) {
attribution = dom.$attr.text().trim();
} else if (dom.$licenseAut.length) {
attribution = dom.$licenseAut.text().trim();
} else if (dom.$creator.length) {
attribution = dom.$creator.text().trim();
}
if (!attribution) {
// No custom attribution
// Default attribution: author or (short) source.
// If no author/source, point to the file description page instead.
attribution = (author || stockPhoto.i18n.see_page_for_author);
}
credit = attribution + file.getLicense() + ', ' + via;
creditHtml = mw.html.element('a', {
href: file.backlink
}, attribution) + file.getLicense(true) + ', ' + mw.html.escape(via || '');
}
file.credit = credit;
file.creditHtml = creditHtml;
};
File.prototype.getLicense = function (useHtml) {
var l1, l2,
licenses = this.licenses.map(function (l) {
return useHtml ? l.html : l.txt;
});
if (!licenses.length) {
return ', ' + stockPhoto.i18n.see_page_for_license;
}
if (licenses.length === 1) {
return ', ' + licenses[0];
}
if (licenses.length >= 2) {
l2 = licenses.pop();
l1 = licenses.pop();
licenses.push(l1 + ' ' + stockPhoto.i18n.or + ' ' + l2);
}
return ' (' + licenses.join(', ') + ')';
};
stockPhoto = {
ui_icon_download: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/92/Gnome-document-save.svg/60px-Gnome-document-save.svg.png',
ui_icon_web: 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Gnome-emblem-web.svg/60px-Gnome-emblem-web.svg.png',
ui_icon_wiki: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Tango_style_Wikipedia_Icon.svg/60px-Tango_style_Wikipedia_Icon.svg.png',
ui_icon_email: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/ee/Gnome-mail-send.svg/60px-Gnome-mail-send.svg.png',
ui_icon_help: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Dialog-information_on.svg/60px-Dialog-information_on.svg.png',
ui_icon_remove: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Emblem-unreadable.svg/40px-Emblem-unreadable.svg.png',
information_template_hints: ['fileinfotpl_desc', 'fileinfotpl_src'],
horizontal_ui: ['pdf', 'djvu'],
// For "Use on the web > BBCode"
// Test case: https://commons.wikimedia.org/wiki/File:Air_(Bach).ogg
ogg_icon: new URL('/w/resources/assets/file-type-icons/fileicon-ogg.png', location).toString(),
init: function () {
var $enable, $orgItems, has_information, $imgBox, xoff, yoff, horizontal, html, $base, re;
// Original filetoc items
$orgItems = $('#filetoc').find('a[href="#file"], a[href="#filehistory"], a[href="#filelinks"], a[href="#metadata"], a[href="#globalusage"]').parent();
if ($.cookie('StockPhotoDisabled')) {
$enable = $('<li>')
.append($('<a href="#"></a>').text(stockPhoto.i18n.reuse))
.click(function (e){
e.preventDefault();
$(this).remove();
$.cookie('StockPhotoDisabled', null, {
path: '/'
});
stockPhoto.init();
});
$('#filetoc').append($enable);
$orgItems = $orgItems.add($enable);
return;
}
if (!$('#file').length) {
return;
}
has_information = stockPhoto.information_template_hints.some(function (v) {
return document.querySelector('#' + v);
});
// No {{Information}}
if (!has_information) {
return;
}
// Has one or more problemtags
// Changed to also include renames and normal deletes
if (document.querySelector('.nuke')) {
return;
}
// * ".multipageimage": For paged tiff files.
// * "#file img": For all other images (e.g. JPEG, PNG, SVG, etc.).
$imgBox = $('.multipageimage, #file img, #file video, #file audio');
xoff = $imgBox.width() + 40;
yoff = $('#file').position().top + 5;
stockPhoto.small_horizontal_layout = (
// Small for logged-in
!mw.user.isAnon()
// Small for media with short height
|| ($imgBox.height() < 300)
);
re = new RegExp('\\.(?:' + stockPhoto.horizontal_ui.map(mw.util.escapeRegExp).join('|') + ')$', 'i');
// Given a viewport of 1300px wide, how much outside content area (sidebars, fixed width, empty space, etc)
const skinNonContentWidth = mw.config.get('skin') === 'vector-2022' ? 540 : 220;
const stockphotoVertWidth = 160;
const availableWidth = document.documentElement.clientWidth - skinNonContentWidth - $imgBox.width();
horizontal = (
// Anything small
stockPhoto.small_horizontal_layout
|| re.test(mw.config.get('wgTitle'))
// Skin layout and viewport width
|| availableWidth < stockphotoVertWidth
);
// Initialize values
stockPhoto.share_this(-1);
html = '<div class="';
html += (horizontal ? 'stockphoto-layout-horizontal' : 'stockphoto-layout-vertical');
html += (stockPhoto.small_horizontal_layout ? ' stockphoto-layout-horizontal-small' : '');
html += '"';
if (!horizontal) {
if (document.querySelector('body.rtl')) {
html += ' style="right: ' + xoff + 'px; top:' + yoff + 'px;"';
} else {
html += ' style="left: ' + xoff + 'px; top:' + yoff + 'px;"';
}
}
html += '></div>';
$base = $(html).append(
stockPhoto.add_button_row(stockPhoto.ui_icon_download, stockPhoto.call_download, stockPhoto.i18n.download, stockPhoto.i18n.all_sizes),
stockPhoto.add_button_row(stockPhoto.ui_icon_web, stockPhoto.call_web, stockPhoto.i18n.use_this_file_web_short, stockPhoto.i18n.on_a_website),
stockPhoto.add_button_row(stockPhoto.ui_icon_wiki, stockPhoto.call_wiki, stockPhoto.i18n.use_this_file_wiki_short, stockPhoto.i18n.on_a_wiki),
stockPhoto.add_button_row(stockPhoto.ui_icon_email,
'mailto:?subject=' + encodeURIComponent(stockPhoto.file.title) + '&body=' +
encodeURIComponent(stockPhoto.file.backlink + '\n\n' + stockPhoto.file.credit),
stockPhoto.i18n.email_link_short, stockPhoto.i18n.to_this_file),
stockPhoto.add_button_row(stockPhoto.ui_icon_help,
mw.util.getUrl('Special:MyLanguage/Commons:Reusing_content_outside_Wikimedia'),
stockPhoto.i18n.information, stockPhoto.i18n.about_reusing),
$('<span class="stockphoto_buttonrow"><a title="' + stockPhoto.i18n.remove_icons + '" class="stockphoto_buttonrow_icon"><img width="20" src="' + stockPhoto.ui_icon_remove + '"></a></span>')
.click(function () {
$.cookie('StockPhotoDisabled', true, {
expires: 60, // days
path: '/'
});
$base.remove();
$orgItems.show();
})
);
if (stockPhoto.small_horizontal_layout) {
$orgItems.hide();
$('#filetoc').append($base);
} else {
$('#filetoc').after($base);
}
},
add_button_row: function (icon_url, fn, txt, html) {
var ret,
size = 50, realSize = 60;
if (stockPhoto.small_horizontal_layout) {
size = 20, realSize = 20;
}
// HiDPI "Retina" icon
if (window.devicePixelRatio > 1.0) {
realSize *= 2;
}
icon_url = icon_url.replace('/60px-', '/' + realSize + 'px-');
ret = document.createElement('a');
ret.className = 'stockphoto_buttonrow';
ret.title = txt + ' ' + html;
if (typeof fn === 'string') {
ret.href = fn;
} else {
ret.role = 'button';
ret.tabIndex = 0;
ret.onclick = function (e) { e.preventDefault(); fn(); };
}
ret.innerHTML = '<span class="stockphoto_buttonrow_icon"><img width="' + size + '" height="' + size + '" src="' + icon_url + '"></span>' +
'<span class="stockphoto_buttonrow_text"><span class="stockphoto_link">' + txt + '</span><small>' + html + '</small></span>';
return ret;
},
stockphoto_get_download_url: function (url) {
var urlObj = new URL(url);
// Remove any "_" or "utm" params (T414338)
urlObj.search = '?download';
return urlObj.toString();
},
make_html_textarea: function () {
var width = Number($('#stockphoto_html_select').val());
var type = $('input[name="stockphoto_code_type"]:checked').val();
var t;
// Iframe share for media player
if (stockPhoto.file.audio_or_video && type === 'html') {
let height;
if (stockPhoto.file.audio) {
// For audio that has zero height
height = 20;
} else {
// Apply aspect ratio from the video element
const $element = $('#file video, #file audio');
height = width * ($element.height() / $element.width());
}
t = '<iframe src="' + stockPhoto.file.backlink +
'?embedplayer=yes" width="' + width + '" height="'+ height + '" frameborder="0" loading="lazy" allow="autoplay; picture-in-picture" allowfullscreen></iframe>';
} else {
var thumb_url = stockPhoto.file.widths.get(width) || stockPhoto.ogg_icon;
if (type === 'html') {
t = '<a title="' + mw.html.escape(stockPhoto.file.credit) +
'" href="' + stockPhoto.file.backlink + '"><img width="' + width + '" alt="' +
mw.html.escape(stockPhoto.file.title) + '" src="' + thumb_url + '"></a>';
} else if (type === 'bbcode') {
t = '[url=' + stockPhoto.file.backlink + '][img]' +
thumb_url + '[/img][/url]\n[url=' + stockPhoto.file.backlink + ']' +
stockPhoto.file.title + '[/url]\n' + stockPhoto.file.credit;
}
}
$('#stockphoto_html').text(t);
},
// Event 'change' on input#stockphoto_attribution_html
refresh_attribution: function () {
$('#stockphoto_attribution').val(stockPhoto.file[this.checked ? 'creditHtml' : 'credit']);
},
createDialogRow: function (label, prefill, id, prepend, append) {
var idtext = id ? ('id="' + id + '"') : '';
return '<div class="stockphoto_dialog_row"><b>' + label + ':</b><br>' + (prepend || '') + '<input type="text" readonly ' + idtext + ' onclick="select()" value="' + mw.html.escape(prefill) + '">' + (append || '') + '</div>';
},
share_this: function (ui_mode) {
stockPhoto.file = new File({
pageName: mw.config.get('wgPageName'),
originalUrl: $('div.fullMedia a').prop('href') || '',
dom: {
$file: $('#file').eq(0),
$src: $('#fileinfotpl_src + td'),
$aut: $('#fileinfotpl_aut + td'),
$attr: $('.licensetpl_attr').eq(0),
$credit: $('#fileinfotpl_credit + td'),
$creator: $('#creator'),
$licenseAut: $('.licensetpl_aut').eq(0)
},
$licenses: $('.licensetpl')
});
if (ui_mode === -1) {
return;
}
modalLoad = modalLoad || mw.loader.using('jquery.ui');
var html = '';
html += stockPhoto.createDialogRow(stockPhoto.i18n.page_url, stockPhoto.file.backlink);
html += stockPhoto.createDialogRow(stockPhoto.i18n.file_url, stockPhoto.file.url);
html += stockPhoto.createDialogRow(stockPhoto.i18n.attribution, stockPhoto.file.credit,
'stockphoto_attribution',
'<blockquote class="stockphoto_attribution_preview" onclick="nextSibling.select();return false;">' + stockPhoto.file.creditHtml + '</blockquote>',
' <input id="stockphoto_attribution_html" type="checkbox"> <label for="stockphoto_attribution_html">' + stockPhoto.i18n.html + '</label>'
);
if (stockPhoto.file.gfdlNote) {
html += '<span class="stockphoto_note">' + stockPhoto.i18n.gfdl_warning + '</span>';
}
if (!stockPhoto.file.attrRequired) {
html += '<br><span class="stockphoto_note">' + stockPhoto.i18n.no_attr + '</span>';
}
var dtitle;
switch (ui_mode) {
case 1:
dtitle = stockPhoto.i18n.download_this_file;
if (stockPhoto.file.downloadUrl) {
html += '<div><b>' + stockPhoto.i18n.download_image_file + ':</b><br>';
const dl_links = [];
// Skip for audio/video, as they'd be downloading an icon or poster instead
if (!stockPhoto.file.audio_or_video) {
for (const [v, url] of stockPhoto.file.widths) {
const downloadUrl = stockPhoto.stockphoto_get_download_url(url);
// Avoid duplicate when original is preview (images <= 800px wide)
// Test case:
// https://commons.wikimedia.org/wiki/File:CorusSteelworks.jpg
// https://commons.wikimedia.org/wiki/File:Ravenscar_-_geograph.org.uk_-_401270.jpg
if (downloadUrl !== stockPhoto.file.downloadUrl) {
dl_links.push('<a href="' + downloadUrl + '" download>' + v + 'px</a>');
}
}
}
dl_links.push('<a href="' + stockPhoto.file.downloadUrl + '" download>' + stockPhoto.i18n.full_resolution + '</a>');
if (dl_links.length) {
html += dl_links.join(' | ');
} else {
html += '<i>' + stockPhoto.i18n.not_available + '</i>';
}
html += '</div>';
}
break;
case 2:
dtitle = stockPhoto.i18n.use_this_file_web;
html += '<div class="stockphoto_dialog_row"><div style="float: right;">';
html += '<input type="radio" name="stockphoto_code_type" value="html" id="stockphoto_code_type_html" onchange="stockPhoto.make_html_textarea();" checked> <label for="stockphoto_code_type_html">' + stockPhoto.i18n.html + '</label> ';
html += '<input type="radio" name="stockphoto_code_type" value="bbcode" id="stockphoto_code_type_bbcode" onchange="stockPhoto.make_html_textarea();"> <label for="stockphoto_code_type_bbcode">' + stockPhoto.i18n.bbcode + '</label> ';
html += '<select id="stockphoto_html_select" onchange="stockPhoto.make_html_textarea();">';
const defChoice = stockPhoto.file.embedDefaultChoice;
if (stockPhoto.file.audio) {
html += '<option value="' + defChoice + '" selected>' + defChoice + stockPhoto.i18n.px_wide_icon + '</option>';
} else if (stockPhoto.file.videoPlayers) {
for (const v of stockPhoto.file.videoPlayers) {
html += '<option value="' + v + '">' + v + stockPhoto.i18n.px_wide + '</option>';
}
} else {
if (!stockPhoto.file.widths.size) {
html += '<option value="' + defChoice + '" selected>' + defChoice + stockPhoto.i18n.px_wide + '</option>';
} else {
for (const [v, url] of stockPhoto.file.widths) {
if (v < 1000) {
html += '<option value="' + v + '">' + v + stockPhoto.i18n.px_wide + '</option>';
}
}
}
}
html += '</select></div>';
html += '<b>' + stockPhoto.i18n.embed_this_file + '</b><textarea onclick="select()" id="stockphoto_html" readonly>';
html += '</textarea></div>';
break;
case 3:
dtitle = stockPhoto.i18n.use_this_file_wiki;
html = stockPhoto.createDialogRow(stockPhoto.i18n.thumbnail, '[[File:' + mw.config.get('wgTitle') + '|thumb|' + stockPhoto.file.title + ']]');
html += stockPhoto.createDialogRow(stockPhoto.i18n.image, '[[File:' + mw.config.get('wgTitle') + '|' + stockPhoto.file.title + ']]');
break;
}
modalLoad.done(function () {
$('<div style="display: none;"></div>').html(html).dialog({
modal: true,
width: 610,
height: 'auto',
title: dtitle,
close: function () {
$(this).remove();
}
});
$('#stockphoto_html_select').val(stockPhoto.file.embedDefaultChoice);
stockPhoto.make_html_textarea();
$('#stockphoto_attribution_html').on('change', stockPhoto.refresh_attribution);
});
},
call_download: function () {
stockPhoto.share_this(1);
},
call_web: function () {
stockPhoto.share_this(2);
},
call_wiki: function () {
stockPhoto.share_this(3);
},
i18n: {
// Download:
// - Button label
download: 'Download',
// - Button caption
all_sizes: 'all sizes',
// - Dialog title
download_this_file: 'Download this file',
// Use web:
// - Button label
use_this_file_web_short: 'Use this file',
// - Button caption
on_a_website: 'on the web',
// - Dialog title
use_this_file_web: 'Use this file on the web',
// Use wiki:
// - Button label
use_this_file_wiki_short: 'Use this file',
// - Button caption
on_a_wiki: 'on a wiki',
// - Dialog title
use_this_file_wiki: 'Use this file on a wiki',
thumbnail: 'Thumbnail',
image: 'Image',
// Email:
// - Button label
email_link_short: 'Email a link',
// - Button caption
to_this_file: 'to this file',
// Reuse:
// - Button label
information: 'Information',
// - Button caption
about_reusing: 'about reusing',
// Disable (button caption)
remove_icons: 'Remove these icons',
// Enable (button label)
reuse: 'Reuse this file',
via_wikimedia_commons: 'via Wikimedia Commons',
see_page_for_author: 'See page for author',
see_page_for_license: 'see page for license',
page_url: 'Page URL',
file_url: 'File URL',
attribution: 'Attribution',
no_attr: 'Attribution not legally required',
or: 'or',
gfdl_warning: 'Using this file might require attaching a full copy of the <a href="//en.wikipedia.org/wiki/GNU_Free_Documentation_License">GFDL</a>',
download_image_file: 'Download image file',
full_resolution: 'Full resolution',
not_available: 'not available',
share_this_file: 'Share this file',
embed_this_file: 'Embed this file',
html: 'HTML',
bbcode: 'BBCode',
px_wide_icon: 'px wide (icon)',
px_wide: 'px wide'
}
};
// Export
window.stockPhoto = stockPhoto;
var promises = [ $.ready, mw.loader.using( [ 'mediawiki.user' ] ) ];
if (mw.config.get('wgUserLanguage') !== 'en') {
var translationPromise = $.ajax({
url: mw.config.get('wgScript') + '?title=' + mw.util.wikiUrlencode('MediaWiki:Gadget-Stockphoto.js/' + mw.config.get('wgUserLanguage')) + '&action=raw&ctype=text/javascript',
dataType: 'script',
// For performance, use 'crossDomain' to trigger <script> instead of XHR.
// Browsers do cache scripts, but not XHR.
crossDomain: true,
cache: true
});
promises.push( translationPromise );
}
$.when(...promises).done(() => {
stockPhoto.init();
});
// on subpages [[MediaWiki:stockPhoto.js/langcode]]:
// stockPhoto.i18n = { ... }
}());