diff --git a/package.json b/package.json
index 89ecba684..7283a9b90 100644
--- a/package.json
+++ b/package.json
@@ -100,7 +100,6 @@
"react-test-renderer": "16.2.0",
"react-tooltip": "3.8.0",
"react-virtualized": "9.20.1",
- "react-visibility-sensor": "5.0.2",
"redux": "3.7.2",
"redux-mock-store": "^1.2.3",
"redux-throttle": "0.1.1",
@@ -110,7 +109,7 @@
"scratch-l10n": "3.1.20190410143750",
"scratch-paint": "0.2.0-prerelease.20190318170811",
"scratch-render": "0.1.0-prerelease.20190326161919",
- "scratch-storage": "1.3.1",
+ "scratch-storage": "1.2.2",
"scratch-svg-renderer": "0.2.0-prerelease.20190329052730",
"scratch-vm": "0.2.0-prerelease.20190410143927",
"selenium-webdriver": "3.6.0",
diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx
index 3ae872e8a..5af6fb159 100644
--- a/src/components/library-item/library-item.jsx
+++ b/src/components/library-item/library-item.jsx
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import React from 'react';
import Box from '../box/box.jsx';
-import ScratchImage from '../scratch-image/scratch-image.jsx';
import styles from './library-item.css';
import classNames from 'classnames';
@@ -36,12 +35,10 @@ class LibraryItemComponent extends React.PureComponent {
/>
) : null}
- {this.props.iconSource ? (
-
- ) : null}
+
{this.props.insetIconURL ? (
@@ -124,9 +121,9 @@ class LibraryItemComponent extends React.PureComponent {
{/* Layers of wrapping is to prevent layout thrashing on animation */}
-
@@ -149,7 +146,7 @@ LibraryItemComponent.propTypes = {
extensionId: PropTypes.string,
featured: PropTypes.bool,
hidden: PropTypes.bool,
- iconSource: ScratchImage.ImageSourcePropType,
+ iconURL: PropTypes.string,
insetIconURL: PropTypes.string,
internetConnectionRequired: PropTypes.bool,
name: PropTypes.oneOfType([
diff --git a/src/components/library/library.jsx b/src/components/library/library.jsx
index 89e820f1b..60f65a06d 100644
--- a/src/components/library/library.jsx
+++ b/src/components/library/library.jsx
@@ -9,7 +9,6 @@ import Modal from '../../containers/modal.jsx';
import Divider from '../divider/divider.jsx';
import Filter from '../filter/filter.jsx';
import TagButton from '../../containers/tag-button.jsx';
-import storage from '../../lib/storage';
import styles from './library.css';
@@ -29,47 +28,6 @@ const messages = defineMessages({
const ALL_TAG = {tag: 'all', intlLabel: messages.allTag};
const tagListPrefix = [ALL_TAG];
-/**
- * Find the AssetType which corresponds to a particular file extension. For example, 'png' => AssetType.ImageBitmap.
- * @param {string} fileExtension - the file extension to look up.
- * @returns {AssetType} - the AssetType corresponding to the extension, if any.
- */
-const getAssetTypeForFileExtension = function (fileExtension) {
- const compareOptions = {
- sensitivity: 'accent',
- usage: 'search'
- };
- for (const assetTypeId in storage.AssetType) {
- const assetType = storage.AssetType[assetTypeId];
- if (fileExtension.localeCompare(assetType.runtimeFormat, compareOptions) === 0) {
- return assetType;
- }
- }
-};
-
-/**
- * Figure out an `imageSource` (URI or asset ID & type) for a library item's icon.
- * @param {object} item - either a library item or one of a library item's costumes.
- * @returns {object} - an `imageSource` ready to be passed to a `ScratchImage`.
- */
-const getItemImageSource = function (item) {
- if (item.rawURL) {
- return {
- uri: item.rawURL
- };
- }
-
- // TODO: adjust libraries to be more storage-friendly; don't use split() here.
- const md5 = item.md5 || item.baseLayerMD5;
- if (md5) {
- const [assetId, fileExtension] = md5.split('.');
- return {
- assetId: assetId,
- assetType: getAssetTypeForFileExtension(fileExtension)
- };
- }
-};
-
class LibraryComponent extends React.Component {
constructor (props) {
super(props);
@@ -204,10 +162,8 @@ class LibraryComponent extends React.Component {
})}
ref={this.setFilteredDataRef}
>
- {this.getFilteredData().map((dataItem, index) => {
- const iconSource = getItemImageSource(dataItem);
- const icons = dataItem.json && dataItem.json.costumes.map(getItemImageSource);
- return ( (
+ );
- })}
+ />
+ ))}
);
diff --git a/src/components/scratch-image/scratch-image.jsx b/src/components/scratch-image/scratch-image.jsx
deleted file mode 100644
index 15abe9d3f..000000000
--- a/src/components/scratch-image/scratch-image.jsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import VisibilitySensor from 'react-visibility-sensor';
-
-import storage from '../../lib/storage';
-
-class ScratchImage extends React.PureComponent {
- static init () {
- this._maxParallelism = 6;
- this._currentJobs = 0;
- this._pendingImages = new Set();
- }
-
- static loadPendingImages () {
- if (this._currentJobs >= this._maxParallelism) {
- // already busy
- return;
- }
-
- // Find the first visible image. If there aren't any, find the first non-visible image.
- let nextImage;
- for (const image of this._pendingImages) {
- if (image.isVisible) {
- nextImage = image;
- break;
- } else {
- nextImage = nextImage || image;
- }
- }
-
- // If we found an image to load:
- // 1) Remove it from the queue
- // 2) Load the image
- // 3) Pump the queue again
- if (nextImage) {
- this._pendingImages.delete(nextImage);
- const imageSource = nextImage.props.imageSource;
- ++this._currentJobs;
- storage
- .load(imageSource.assetType, imageSource.assetId)
- .then(asset => {
- if (!nextImage.wasUnmounted) {
- const dataURI = asset.encodeDataURI();
-
- nextImage.setState({
- imageURI: dataURI
- });
- }
- --this._currentJobs;
- this.loadPendingImages();
- });
- }
- }
-
- constructor (props) {
- super(props);
- this.state = {};
- Object.assign(this.state, this._loadImageSource(props.imageSource));
- }
- componentWillReceiveProps (nextProps) {
- const newState = this._loadImageSource(nextProps.imageSource);
- this.setState(newState);
- }
- componentWillUnmount () {
- this.wasUnmounted = true;
- ScratchImage._pendingImages.delete(this);
- }
- /**
- * Calculate the state changes necessary to load the image specified in the provided source info. If the component
- * is mounted, call setState() with the return value of this function. If the component has not yet mounted, use
- * the return value of this function as initial state for the component.
- *
- * @param {object} imageSource - the new source for the image, including either assetId or URI
- * @returns {object} - the new state values, if any.
- */
- _loadImageSource (imageSource) {
- if (imageSource) {
- if (imageSource.uri) {
- ScratchImage._pendingImages.delete(this);
- return {
- imageURI: imageSource.uri,
- lastRequestedAsset: null
- };
- }
- if (this.state.lastRequestedAsset !== imageSource.assetId) {
- ScratchImage._pendingImages.add(this);
- return {
- lastRequestedAsset: imageSource.assetId
- };
- }
- }
- // Nothing to do - don't change any state.
- return {};
- }
- render () {
- const {
- src: _src,
- imageSource: _imageSource,
- ...imgProps
- } = this.props;
- return (
-
- {
- ({isVisible}) => {
- this.isVisible = isVisible;
- ScratchImage.loadPendingImages();
- return (
-
- );
- }
- }
-
- );
- }
-}
-
-ScratchImage.ImageSourcePropType = PropTypes.oneOfType([
- PropTypes.shape({
- assetId: PropTypes.string.isRequired,
- assetType: PropTypes.oneOf(Object.values(storage.AssetType)).isRequired
- }),
- PropTypes.shape({
- uri: PropTypes.string.isRequired
- })
-]);
-
-ScratchImage.propTypes = {
- imageSource: ScratchImage.ImageSourcePropType.isRequired
-};
-
-ScratchImage.init();
-
-export default ScratchImage;
diff --git a/src/containers/library-item.jsx b/src/containers/library-item.jsx
index 0f770546d..6177b916f 100644
--- a/src/containers/library-item.jsx
+++ b/src/containers/library-item.jsx
@@ -75,17 +75,21 @@ class LibraryItem extends React.PureComponent {
const nextIconIndex = (this.state.iconIndex + 1) % this.props.icons.length;
this.setState({iconIndex: nextIconIndex});
}
- curIconSource () {
+ curIconMd5 () {
if (this.props.icons &&
this.state.isRotatingIcon &&
this.state.iconIndex < this.props.icons.length &&
- this.props.icons[this.state.iconIndex]) {
- return this.props.icons[this.state.iconIndex];
+ this.props.icons[this.state.iconIndex] &&
+ this.props.icons[this.state.iconIndex].baseLayerMD5) {
+ return this.props.icons[this.state.iconIndex].baseLayerMD5;
}
- return this.props.iconSource;
+ return this.props.iconMd5;
}
render () {
- const iconSource = this.curIconSource();
+ const iconMd5 = this.curIconMd5();
+ const iconURL = iconMd5 ?
+ `https://cdn.assets.scratch.mit.edu/internalapi/asset/${iconMd5}/get/` :
+ this.props.iconRawURL;
return (
{
.mouseMove(abbyElement)
.perform();
// wait for one of Abby's alternate costumes to appear
- const src1 = await abbyElement.findElement({css: 'img'}).getAttribute('src');
- await driver.sleep(300);
- const src2 = await abbyElement.findElement({css: 'img'}).getAttribute('src');
- const sourcesMatch = (src1 === src2);
- await expect(sourcesMatch).toBeFalsy(); // 'src' attribute should have changed by now
+ await findByXpath('//img[@src="https://cdn.assets.scratch.mit.edu/internalapi/asset/b6e23922f23b49ddc6f62f675e77417c.svg/get/"]');
const logs = await getLogs();
await expect(logs).toEqual([]);
});