mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 21:24:59 +08:00
Cache the tinted SVGs for MFileBody as data URLs (#559)
* Use a list of callbacks for things that need tinting. Rather than gutwrenching the internals of TintableSVG inside the Tinter. * Share a data: url for the tinted download svg in MFileBody * Check image exists before tinting * Add comments * Use fetch+DomParser rather than XMLHttpRequest * Remove comment about XMLHttpRequest
This commit is contained in:
parent
218ced0276
commit
6ccc825f0d
@ -153,7 +153,25 @@ function rgbToHex(rgb) {
|
||||
return '#' + (0x1000000 + val).toString(16).slice(1)
|
||||
}
|
||||
|
||||
// List of functions to call when the tint changes.
|
||||
const tintables = [];
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Register a callback to fire when the tint changes.
|
||||
* This is used to rewrite the tintable SVGs with the new tint.
|
||||
*
|
||||
* It's not possible to unregister a tintable callback. So this can only be
|
||||
* used to register a static callback. If a set of tintables will change
|
||||
* over time then the best bet is to register a single callback for the
|
||||
* entire set.
|
||||
*
|
||||
* @param {Function} tintable Function to call when the tint changes.
|
||||
*/
|
||||
registerTintable : function(tintable) {
|
||||
tintables.push(tintable);
|
||||
},
|
||||
|
||||
tint: function(primaryColor, secondaryColor, tertiaryColor) {
|
||||
|
||||
if (!cached) {
|
||||
@ -201,12 +219,9 @@ module.exports = {
|
||||
|
||||
// tell all the SVGs to go fix themselves up
|
||||
// we don't do this as a dispatch otherwise it will visually lag
|
||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
if (TintableSvg.mounts) {
|
||||
Object.keys(TintableSvg.mounts).forEach((id) => {
|
||||
TintableSvg.mounts[id].tint();
|
||||
tintables.forEach(function(tintable) {
|
||||
tintable();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// XXX: we could just move this all into TintableSvg, but as it's so similar
|
||||
@ -265,5 +280,5 @@ module.exports = {
|
||||
svgFixup.node.setAttribute(svgFixup.attr, colors[svgFixup.index]);
|
||||
}
|
||||
if (DEBUG) console.log("applySvgFixups end");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -74,4 +74,13 @@ var TintableSvg = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
// Register with the Tinter so that we will be told if the tint changes
|
||||
Tinter.registerTintable(function() {
|
||||
if (TintableSvg.mounts) {
|
||||
Object.keys(TintableSvg.mounts).forEach((id) => {
|
||||
TintableSvg.mounts[id].tint();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = TintableSvg;
|
||||
|
@ -21,7 +21,42 @@ import filesize from 'filesize';
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import sdk from '../../../index';
|
||||
import {decryptFile} from '../../../utils/DecryptFile';
|
||||
import Tinter from '../../../Tinter';
|
||||
import 'isomorphic-fetch';
|
||||
import q from 'q';
|
||||
|
||||
// A cached tinted copy of "img/download.svg"
|
||||
var tintedDownloadImageURL;
|
||||
// Track a list of mounted MFileBody instances so that we can update
|
||||
// the "img/download.svg" when the tint changes.
|
||||
var nextMountId = 0;
|
||||
const mounts = {};
|
||||
|
||||
/**
|
||||
* Updates the tinted copy of "img/download.svg" when the tint changes.
|
||||
*/
|
||||
function updateTintedDownloadImage() {
|
||||
// Download the svg as an XML document.
|
||||
// We could cache the XML response here, but since the tint rarely changes
|
||||
// it's probably not worth it.
|
||||
q(fetch("img/download.svg")).then(function(response) {
|
||||
return response.text();
|
||||
}).then(function(svgText) {
|
||||
const svg = new DOMParser().parseFromString(svgText, "image/svg+xml");
|
||||
// Apply the fixups to the XML.
|
||||
const fixups = Tinter.calcSvgFixups([{contentDocument: svg}]);
|
||||
Tinter.applySvgFixups(fixups);
|
||||
// Encoded the fixed up SVG as a data URL.
|
||||
const svgString = new XMLSerializer().serializeToString(svg);
|
||||
tintedDownloadImageURL = "data:image/svg+xml;base64," + window.btoa(svgString);
|
||||
// Notify each mounted MFileBody that the URL has changed.
|
||||
Object.keys(mounts).forEach(function(id) {
|
||||
mounts[id].tint();
|
||||
});
|
||||
}).done();
|
||||
}
|
||||
|
||||
Tinter.registerTintable(updateTintedDownloadImage);
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MFileBody',
|
||||
@ -70,6 +105,12 @@ module.exports = React.createClass({
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
// Add this to the list of mounted components to receive notifications
|
||||
// when the tint changes.
|
||||
this.id = nextMountId++;
|
||||
mounts[this.id] = this;
|
||||
this.tint();
|
||||
// Check whether we need to decrypt the file content.
|
||||
const content = this.props.mxEvent.getContent();
|
||||
if (content.file !== undefined && this.state.decryptedUrl === null) {
|
||||
decryptFile(content.file).done((url) => {
|
||||
@ -84,12 +125,23 @@ module.exports = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
// Remove this from the list of mounted components
|
||||
delete mounts[this.id];
|
||||
},
|
||||
|
||||
tint: function() {
|
||||
// Update our tinted copy of "img/download.svg"
|
||||
if (this.refs.downloadImage) {
|
||||
this.refs.downloadImage.src = tintedDownloadImageURL;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const content = this.props.mxEvent.getContent();
|
||||
|
||||
const text = this.presentableTextForFile(content);
|
||||
|
||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
if (content.file !== undefined && this.state.decryptedUrl === null) {
|
||||
|
||||
// Need to decrypt the attachment
|
||||
@ -155,7 +207,7 @@ module.exports = React.createClass({
|
||||
<span className="mx_MFileBody">
|
||||
<div className="mx_MImageBody_download">
|
||||
<a href={contentUrl} target="_blank" rel="noopener" download={downloadAttr}>
|
||||
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
||||
<img src={tintedDownloadImageURL} width="12" height="14" ref="downloadImage"/>
|
||||
Download {text}
|
||||
</a>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user