Skip to content

Commit 40d8b4c

Browse files
authored
Merge pull request #88 from OpenRefine/58-thumbnails-for-existing-files
Merging after feedback via e-mail; will ask for improvements in new issue.
2 parents 2de6f2f + 0740e9b commit 40d8b4c

3 files changed

Lines changed: 183 additions & 0 deletions

File tree

module/MOD-INF/controller.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ function init() {
4545
]
4646
);
4747

48+
// Script files to inject into /project page
49+
ClientSideResourceManager.addPaths(
50+
"project/scripts",
51+
module,
52+
[
53+
"scripts/project/thumbnail-renderer.js"
54+
]
55+
);
56+
57+
4858
// Style files to inject into /index page
4959
ClientSideResourceManager.addPaths(
5060
"index/styles",
@@ -54,4 +64,14 @@ function init() {
5464
"externals/suggest/css/suggest-4_3.min.css"
5565
]
5666
);
67+
68+
// Style files to inject into /project page
69+
ClientSideResourceManager.addPaths(
70+
"project/styles",
71+
module,
72+
[
73+
"styles/thumbnails.less"
74+
]
75+
);
76+
5777
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
2+
/**
3+
Renders a thumbnail alongside a matched cell when the reconcilition service
4+
is associated with the MediaInfo entities of a Wikibase instance.
5+
*/
6+
class ThumbnailReconRenderer extends ReconCellRenderer {
7+
8+
constructor() {
9+
super();
10+
this.supportedExtensions = [
11+
'jpg', 'jpeg', 'png', 'gif', 'svg', 'tiff', 'ogv', 'pdf', 'djvu', 'webm'
12+
];
13+
this.siteIriToMediaWikiRootUrl = new Map();
14+
var self = this;
15+
$.ajax({
16+
url: 'command/core/get-preference?' + $.param({ name: 'wikibase.manifests' }),
17+
success: function (data) {
18+
let wikibases = JSON.parse(data.value || '[]');
19+
for (let manifest of wikibases) {
20+
try {
21+
let api = manifest.mediawiki.api;
22+
let siteIri = null;
23+
if (manifest.entity_types && manifest.entity_types.mediainfo) {
24+
if (manifest.entity_types.mediainfo.site_iri) {
25+
siteIri = manifest.entity_types.mediainfo.site_iri;
26+
} else {
27+
siteIri = manifest.wikibase.site_iri;
28+
}
29+
}
30+
if (siteIri) {
31+
self.siteIriToMediaWikiRootUrl.set(siteIri, api.substr(0, api.length - 'w/api.php'.length));
32+
}
33+
} catch(error) {
34+
console.warn('Unsupported manifest format for Wikibase instance ' + manifest.mediawiki.name);
35+
}
36+
}
37+
}});
38+
}
39+
40+
render(rowIndex, cellIndex, cell, cellUI) {
41+
var self = this;
42+
var divContent = document.createElement('div');
43+
var divContentRecon = $(divContent);
44+
var r = cell.r;
45+
if ( !r.service ) {
46+
return undefined;
47+
}
48+
49+
var service = ReconciliationManager.getServiceFromUrl(r.service);
50+
var mediaWikiRootUrl = self.siteIriToMediaWikiRootUrl.get(service.identifierSpace);
51+
// if the reconciliation service is not associated with a Wikibase, defer to recon renderer
52+
if (!mediaWikiRootUrl) {
53+
return undefined;
54+
}
55+
56+
// only display thumbnails for matched cells
57+
if (cell && 'r' in cell && cell.r.j === 'matched') {
58+
var match = cell.r.m;
59+
var a = $('<a></a>')
60+
.text(match.name)
61+
.attr("target", "_blank")
62+
.appendTo(divContentRecon);
63+
64+
var bareFileName = match.name.substr('File:'.length).replaceAll(' ', '_');
65+
var fileNameParts = bareFileName.split('.');
66+
var extension = fileNameParts[fileNameParts.length - 1];
67+
if (!self.supportedExtensions.includes(extension)) {
68+
// defer to the standard recon renderer
69+
return undefined;
70+
}
71+
72+
var imageUrl = self.getThumbnailUrl(mediaWikiRootUrl, bareFileName, 320);
73+
74+
if (service && (service.view) && (service.view.url)) {
75+
a.attr("href", encodeURI(service.view.url.replace("{{id}}", match.id)));
76+
}
77+
78+
$('<span></span>').appendTo(divContentRecon);
79+
var thumbnailDiv = $('<div></div>')
80+
.addClass('media-file-thumbnail-in-cell')
81+
.appendTo(divContentRecon);
82+
var image = $('<img />')
83+
.attr('src', imageUrl)
84+
.appendTo(thumbnailDiv);
85+
image.on('click', function(evt) {
86+
self.showFullScreenPreview(mediaWikiRootUrl, bareFileName);
87+
});
88+
$('<a></a>')
89+
.text($.i18n('core-views/choose-match'))
90+
.addClass('data-table-recon-action')
91+
.appendTo(divContentRecon)
92+
.on('click', function(evt) {
93+
self.doRematch(rowIndex, cellIndex, cell, cellUI);
94+
});
95+
96+
return divContent;
97+
}
98+
99+
}
100+
101+
showFullScreenPreview(mediaWikiRootUrl, bareFileName) {
102+
var self = this;
103+
var imageUrl = self.getThumbnailUrl(mediaWikiRootUrl, bareFileName);
104+
let div = $('<div></div>')
105+
.addClass('media-file-full-screen-preview')
106+
.appendTo($('body'));
107+
let img = $('<img />')
108+
.attr('src', self.getThumbnailUrl(mediaWikiRootUrl, bareFileName, 1920))
109+
.appendTo(div);
110+
div.on('click', function(evt) {
111+
div.remove();
112+
});
113+
}
114+
115+
/*
116+
Important: thumbnails take resources to generate, so it is worth sticking to the thumbnail sizes
117+
which are auto-generated at upload time:
118+
320, 640, 800, 1024, 1280, 1920, 2560, 2880
119+
120+
See https://www.mediawiki.org/wiki/Requests_for_comment/Standardized_thumbnails_sizes
121+
*/
122+
getThumbnailUrl(mediaWikiRootUrl, bareFileName, width) {
123+
return `${mediaWikiRootUrl}w/thumb.php?f=${encodeURIComponent(bareFileName)}&w=${width}&h=${width}`;
124+
}
125+
}
126+
127+
CellRendererRegistry.addRenderer('thumbnail', new ThumbnailReconRenderer(), 'recon');

module/styles/thumbnails.less

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.media-file-full-screen-preview {
2+
position: absolute;
3+
top: 0px;
4+
left: 0px;
5+
width: 100%;
6+
height: 100%;
7+
background: rgba(0,0,0,0.4);
8+
z-index: 1;
9+
display: flex;
10+
}
11+
12+
.media-file-full-screen-preview img {
13+
max-width: 95%;
14+
max-height: 95%;
15+
margin: auto;
16+
z-index: 100;
17+
cursor: zoom-out;
18+
}
19+
20+
.media-file-thumbnail-in-cell {
21+
background: white;
22+
margin-top: 3px;
23+
display: table; // to make it fit the image it contains
24+
width: auto;
25+
}
26+
27+
.media-file-thumbnail-in-cell img {
28+
max-width: 240px;
29+
}
30+
31+
.media-file-thumbnail-in-cell img:hover {
32+
opacity: .7;
33+
cursor: zoom-in;
34+
}
35+
36+

0 commit comments

Comments
 (0)