Skip to content

Commit

Permalink
Use regular favicon URLs to be x-browser compliant
Browse files Browse the repository at this point in the history
Firefox does not have a favicon API for extensions, and it errors when
seeing the non-standard `"chrome://favicon/"` in the `"permissions"`
Array of the manifest. Replace it with the previously used `LazyImage`
so this extension will build and run in both Chrome and in Firefox.

Addresses #185

This reverts commit e7afdb7.
  • Loading branch information
ssorallen committed Apr 20, 2018
1 parent 066858f commit 5a64bbf
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 31 deletions.
1 change: 1 addition & 0 deletions app/css/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ body {
.favicon {
display: inline-block;
height: 16px;
vertical-align: middle;
width: 16px;
}

Expand Down
12 changes: 9 additions & 3 deletions app/js/ClosedTabRow.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* @flow */

import LazyImage from './LazyImage';
import React from 'react';
import TabFavicon from './TabFavicon';
import TimeAgo from 'timeago-react';
import cx from 'classnames';
import extractHostname from './extractHostname';
Expand Down Expand Up @@ -89,8 +89,14 @@ export default class ClosedTabRow extends React.PureComponent<Props, State> {
<div
className="faviconCol ReactVirtualized__Table__rowColumn"
style={{verticalAlign: 'middle'}}>
<TabFavicon className="faviconCol--hover-hidden" tab={tab} />
<i
<LazyImage
alt=""
className="faviconCol--hover-hidden favicon"
height={16}
src={tab.favIconUrl}
width={16}
/>
<span
className="faviconCol--hover-shown glyphicon glyphicon-trash"
onClick={this._handleClickRemove}
style={{cursor: 'pointer', height: 16, width: 16}}
Expand Down
1 change: 0 additions & 1 deletion app/js/CorralTab.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

.table .faviconCol {
text-align: center;
width: 21px;
}

.table-hover .ReactVirtualized__Table__row:hover {
Expand Down
32 changes: 32 additions & 0 deletions app/js/LazyImage.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.lazy-image-container {
position: relative;
vertical-align: middle;
}

/**
* Transitions for fading out LazyImage placeholders and fading in the images.
*/
.lazy-image-enter {
opacity: 0.01;
}

.lazy-image-enter.lazy-image-enter-active {
opacity: 1;
transition: opacity 250ms ease-in;
}

/**
* Position the placeholder absolutely when starting to leave so the `<img>` is in the page flow to
* maintain the height of the container and so this gray fades out on top of the `<img>`.
*/
.lazy-image-leave {
left: 0;
opacity: 1;
position: absolute;
top: 0;
}

.lazy-image-leave.lazy-image-leave-active {
opacity: 0.01;
transition: opacity 100000ms ease-in;
}
121 changes: 121 additions & 0 deletions app/js/LazyImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* @flow */

import './LazyImage.css';
import ColorHash from 'color-hash';
import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

const loadedSrcs = new Set();
const pendingLazyImages = new Set();

function checkShouldLoadLazyImages() {
for (const lazyImage of pendingLazyImages) {
lazyImage.checkShouldLoad();
}
}

// Begin the loading process a full second after initial execution to allow the popup to open
// before loading images. If images begin to load too soon after the popup opens, Chrome waits
// for them to fully load before showing the popup.
let shouldCheck = false;
setTimeout(() => {
shouldCheck = true;
checkShouldLoadLazyImages();
}, 1000);

interface Props {
className?: string;
height: number;
src: ?string;
style?: Object;
width: number;
}

interface State {
loaded: boolean;
}

const colorHash = new ColorHash();

export default class LazyImage extends React.PureComponent<Props, State> {
_img: ?Image;
_placeholder: ?HTMLDivElement;

constructor(props: Props) {
super(props);
this.state = {
loaded: this.props.src == null || loadedSrcs.has(this.props.src),
};
}

componentDidMount() {
if (!this.state.loaded) {
pendingLazyImages.add(this);
if (shouldCheck) this.checkShouldLoad();
}
}

componentWillUnmount() {
if (pendingLazyImages.has(this)) {
pendingLazyImages.delete(this);
}

// Ensure the loading image does not try to call this soon-to-be-unmounted component.
if (this._img != null) {
this._img.onload = null;
this._img = null;
}
}

checkShouldLoad() {
if (!shouldCheck) return;

const {src} = this.props;

if (src == null || !this._placeholder) return;

this._img = new Image();
this._img.onload = this.setLoaded;
this._img.src = src;
pendingLazyImages.delete(this);
}

setLoaded = () => {
this._img = null;
loadedSrcs.add(this.props.src);
this.setState({loaded: true});
};

render() {
return (
<ReactCSSTransitionGroup
className="lazy-image-container"
component="div"
transitionEnterTimeout={250}
transitionLeaveTimeout={250}
transitionName="lazy-image">
{(this.props.src != null && this.state.loaded) ?
<img
className={this.props.className}
height={this.props.height}
key="img"
src={this.props.src}
style={this.props.style}
width={this.props.width}
/> :
<div
className={this.props.className}
key="placeholder"
ref={(placeholder: ?HTMLDivElement) => { this._placeholder = placeholder; }}
style={Object.assign({}, this.props.style, {
background: colorHash.hex(this.props.src),
borderRadius: `${this.props.height / 2}px`,
height: `${this.props.height}px`,
width: `${this.props.width}px`,
})}
/>
}
</ReactCSSTransitionGroup>
);
}
}
10 changes: 8 additions & 2 deletions app/js/OpenTabRow.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* @flow */

import LazyImage from './LazyImage';
import React from 'react';
import TabFavicon from './TabFavicon';

const TW = chrome.extension.getBackgroundPage().TW;

Expand Down Expand Up @@ -98,7 +98,13 @@ export default class OpenTabRow extends React.Component<OpenTabRowProps> {
/>
</td>
<td className="text-center" style={{verticalAlign: 'middle', width: '32px'}}>
<TabFavicon tab={tab} />
<LazyImage
alt=""
height={16}
src={tab.favIconUrl}
style={{height: '16px', maxWidth: 'none'}}
width={16}
/>
</td>
<td style={{paddingBottom: '4px', paddingTop: '4px', width: '75%'}}>
<div style={{display: 'flex'}}>
Expand Down
24 changes: 0 additions & 24 deletions app/js/TabFavicon.js

This file was deleted.

1 change: 0 additions & 1 deletion app/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"page": "popup.html"
},
"permissions": [
"chrome://favicon/",
"contextMenus",
"sessions",
"storage",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
},
"dependencies": {
"classnames": "^2.2.5",
"color-hash": "^1.0.3",
"file-saver": "^1.3.3",
"lodash": "^4.17.4",
"react": "^16.3.1",
Expand Down
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1487,6 +1487,10 @@ color-convert@^1.3.0, color-convert@^1.9.0:
dependencies:
color-name "^1.1.1"

color-hash@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/color-hash/-/color-hash-1.0.3.tgz#c0e7952f06d022e548e65da239512bd67d3809ee"

color-name@^1.0.0, color-name@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
Expand Down

0 comments on commit 5a64bbf

Please sign in to comment.