Bug 1164510: show a globe favicon as default when no favicon can be found for a Hello context in conversation. r=Standard8

This commit is contained in:
Mike de Boer 2015-06-10 14:10:20 +02:00
Родитель fb6be5d957
Коммит e71453a6fc
19 изменённых файлов: 103 добавлений и 46 удалений

Просмотреть файл

@ -9,6 +9,13 @@ let LoopUI;
const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const kBrowserSharingNotificationId = "loop-sharing-notification";
const kPrefBrowserSharingInfoBar = "browserSharing.showInfoBar";
// This is the default icon as provided by the favicon service when a website
// doesn't provide its own. When the icon ever changes, this data-uri will need
// to be updated as well. A unit test covers this event.
const kDefaultFavicon = "data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAArklEQVR42t2TMQ4CIRBF" +
"9xBGEw5AkBJKY7uhcHsCjfEkHkJDLOWiyDeTyWoFwcriMcD8/wMkTKWUId6DMUYrpa5Symddb1CB9/4IaM09aOHhgLpxyzlf6jxChErsibjuQQsPB1C" +
"6hKARCQ8HcHof8eMEvQHwDAX89grOuVNvADx/9AbjJ7DWPkIIh1YztPBwQErprLW+t34maOFZv8G2MlcWIcSESuyI5as3k2d6AZGetvsfEgPvAAAAAE" +
"lFTkSuQmCC";
LoopUI = {
/**
@ -548,7 +555,10 @@ let LoopUI;
}
let reader = new FileReader();
reader.onload = () => callback(null, reader.result);
reader.onload = () => {
let result = reader.result;
callback(null, result && result != kDefaultFavicon ? result : null);
};
reader.onerror = callback;
reader.readAsDataURL(xhr.response);
};

Просмотреть файл

@ -269,10 +269,6 @@ body[dir=rtl] .new-room-view > .context > .context-content > .context-preview {
float: left;
}
.new-room-view > .context > .context-content > .context-preview[src=""] {
display: none;
}
.new-room-view > .context > .context-content > .context-description {
flex: 0 1 auto;
display: block;

Просмотреть файл

@ -29,7 +29,7 @@ loop.conversationViews = (function(mozL10n) {
if (!contact.email || contact.email.length === 0) {
return { value: "" };
}
return contact.email.find(e => e.pref) || contact.email[0];
return contact.email.find(function find(e) { return e.pref; }) || contact.email[0];
}
function _getContactDisplayName(contact) {

Просмотреть файл

@ -29,7 +29,7 @@ loop.conversationViews = (function(mozL10n) {
if (!contact.email || contact.email.length === 0) {
return { value: "" };
}
return contact.email.find(e => e.pref) || contact.email[0];
return contact.email.find(function find(e) { return e.pref; }) || contact.email[0];
}
function _getContactDisplayName(contact) {

Просмотреть файл

@ -500,9 +500,8 @@ loop.panel = (function(_, mozL10n) {
return (
React.createElement("div", {className: "room-entry-context-item"},
React.createElement("a", {href: roomUrl.location, onClick: this.handleClick},
React.createElement("img", {title: roomUrl.description,
src: roomUrl.thumbnail})
React.createElement("a", {href: roomUrl.location, title: roomUrl.description, onClick: this.handleClick},
React.createElement("img", {src: roomUrl.thumbnail || "loop/shared/img/icons-16x16.svg#globe"})
)
)
);
@ -766,6 +765,7 @@ loop.panel = (function(_, mozL10n) {
hide: !hostname ||
!this.props.mozLoop.getLoopPref("contextInConversations.enabled")
});
var thumbnail = this.state.previewImage || "loop/shared/img/icons-16x16.svg#globe";
return (
React.createElement("div", {className: "new-room-view"},
@ -773,7 +773,7 @@ loop.panel = (function(_, mozL10n) {
React.createElement(Checkbox, {label: mozL10n.get("context_inroom_label"),
onChange: this.onCheckboxChange}),
React.createElement("div", {className: "context-content"},
React.createElement("img", {className: "context-preview", src: this.state.previewImage}),
React.createElement("img", {className: "context-preview", src: thumbnail}),
React.createElement("span", {className: "context-description"},
this.state.description,
React.createElement("span", {className: "context-url"}, hostname)

Просмотреть файл

@ -500,9 +500,8 @@ loop.panel = (function(_, mozL10n) {
return (
<div className="room-entry-context-item">
<a href={roomUrl.location} onClick={this.handleClick}>
<img title={roomUrl.description}
src={roomUrl.thumbnail} />
<a href={roomUrl.location} title={roomUrl.description} onClick={this.handleClick}>
<img src={roomUrl.thumbnail || "loop/shared/img/icons-16x16.svg#globe"} />
</a>
</div>
);
@ -766,6 +765,7 @@ loop.panel = (function(_, mozL10n) {
hide: !hostname ||
!this.props.mozLoop.getLoopPref("contextInConversations.enabled")
});
var thumbnail = this.state.previewImage || "loop/shared/img/icons-16x16.svg#globe";
return (
<div className="new-room-view">
@ -773,7 +773,7 @@ loop.panel = (function(_, mozL10n) {
<Checkbox label={mozL10n.get("context_inroom_label")}
onChange={this.onCheckboxChange} />
<div className="context-content">
<img className="context-preview" src={this.state.previewImage}/>
<img className="context-preview" src={thumbnail} />
<span className="context-description">
{this.state.description}
<span className="context-url">{hostname}</span>

Просмотреть файл

@ -473,7 +473,7 @@ loop.roomViews = (function(mozL10n) {
}
var url = this._getURL();
var thumbnail = url && url.thumbnail || "";
var thumbnail = url && url.thumbnail || "loop/shared/img/icons-16x16.svg#globe";
var urlDescription = url && url.description || "";
var location = url && url.location || "";
var locationData = null;

Просмотреть файл

@ -473,7 +473,7 @@ loop.roomViews = (function(mozL10n) {
}
var url = this._getURL();
var thumbnail = url && url.thumbnail || "";
var thumbnail = url && url.thumbnail || "loop/shared/img/icons-16x16.svg#globe";
var urlDescription = url && url.description || "";
var location = url && url.location || "";
var locationData = null;
@ -546,7 +546,7 @@ loop.roomViews = (function(mozL10n) {
<div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
<div className="room-context-content"
onClick={this.handleContextClick}>
<img className="room-context-thumbnail" src={thumbnail}/>
<img className="room-context-thumbnail" src={thumbnail} />
<div className="room-context-description"
title={urlDescription}>
{this._truncate(urlDescription)}

Просмотреть файл

@ -979,10 +979,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
flex: 0 1 auto;
}
.room-context-thumbnail[src=""] {
display: none;
}
.room-context > .error-display-area.error {
display: block;
background-color: rgba(215,67,69,.8);
@ -1218,9 +1214,8 @@ body[dir=rtl] .room-context-btn-edit {
.standalone-context-url > img {
margin: 1em auto;
max-width: 50%;
/* allows 20% for the description wrapper plus the margins */
max-height: calc(80% - 2em);
width: 16px;
height: 16px;
}
.standalone-context-url-description-wrapper {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 13 KiB

После

Ширина:  |  Высота:  |  Размер: 73 KiB

Просмотреть файл

@ -262,7 +262,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
return (
React.createElement("div", {className: classes},
React.createElement("img", {src: this.props.roomContextUrl.thumbnail}),
React.createElement("img", {src: this.props.roomContextUrl.thumbnail || "shared/img/icons-16x16.svg#globe"}),
React.createElement("div", {className: "standalone-context-url-description-wrapper"},
this.props.roomContextUrl.description,
React.createElement("br", null), React.createElement("a", {href: locationInfo.location,

Просмотреть файл

@ -262,7 +262,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
return (
<div className={classes}>
<img src={this.props.roomContextUrl.thumbnail} />
<img src={this.props.roomContextUrl.thumbnail || "shared/img/icons-16x16.svg#globe"} />
<div className="standalone-context-url-description-wrapper">
{this.props.roomContextUrl.description}
<br /><a href={locationInfo.location}

Просмотреть файл

@ -850,6 +850,24 @@ describe("loop.panel", function() {
expect(contextContent).to.not.equal(null);
});
it("should show a default favicon when none is available", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "https://www.example.com",
description: "fake description",
previews: [""]
});
};
var view = createTestComponent();
// Simulate being visible
view.onDocumentVisible();
var previewImage = view.getDOMNode().querySelector(".context-preview");
expect(previewImage.src).to.match(/loop\/shared\/img\/icons-16x16.svg#globe$/);
});
it("should not show context information when a URL is unavailable", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({

Просмотреть файл

@ -305,6 +305,19 @@ describe("loop.roomViews", function () {
expect(view.getDOMNode().querySelector(".room-context-url").textContent)
.eql("hostname");
});
it("should show a default favicon when none is available", function() {
fakeContextURL.thumbnail = null;
view = mountTestComponent({
showContext: true,
roomData: {
roomContextUrls: [fakeContextURL]
}
});
expect(view.getDOMNode().querySelector(".room-context-thumbnail").src)
.to.match(/loop\/shared\/img\/icons-16x16.svg#globe$/);
});
});
});

Просмотреть файл

@ -35,3 +35,16 @@ add_task(function* test_mozLoop_getSelectedTabMetadata() {
gBrowser.removeTab(tab);
});
add_task(function* test_mozLoop_getSelectedTabMetadata_defaultIcon() {
let tab = gBrowser.selectedTab = gBrowser.addTab();
yield promiseTabLoadEvent(tab, "http://example.com/");
let metadata = yield promiseGetMetadata();
Assert.strictEqual(metadata.url, "http://example.com/", "URL should match");
Assert.strictEqual(metadata.favicon, null, "Favicon should be empty");
Assert.ok(metadata.title, "Title should be set");
Assert.deepEqual(metadata.previews, [], "No previews available");
gBrowser.removeTab(tab);
});

Просмотреть файл

@ -149,6 +149,20 @@ describe("loop.standaloneRoomViews", function() {
linkInfo: "Shared URL"
}));
});
it("should display the default favicon when no thumbnail is available", function() {
var view = mountTestComponent({
roomName: "Mike's room",
roomContextUrls: [{
description: "Mark's super page",
location: "http://invalid.com",
thumbnail: ""
}]
});
expect(view.getDOMNode().querySelector(".standalone-context-url > img").src)
.to.match(/shared\/img\/icons-16x16.svg#globe$/);
});
});
describe("StandaloneRoomHeader", function() {

Просмотреть файл

@ -140,10 +140,6 @@ body {
.svg-icon {
display: inline-block;
width: 16px;
height: 16px;
margin-left: .5rem;
background-repeat: no-repeat;
background-size: 16px 16px;
background-position: center;
border: 0;
}

Просмотреть файл

@ -299,13 +299,12 @@
var SVGIcon = React.createClass({displayName: "SVGIcon",
render: function() {
var sizeUnit = this.props.size.split("x")[0] + "px";
var sizeUnit = this.props.size.split("x");
return (
React.createElement("span", {className: "svg-icon", style: {
"backgroundImage": "url(../content/shared/img/icons-" + this.props.size +
".svg#" + this.props.shapeId + ")",
"backgroundSize": sizeUnit + " " + sizeUnit
}})
React.createElement("img", {className: "svg-icon",
src: "../content/shared/img/icons-" + this.props.size + ".svg#" + this.props.shapeId,
width: sizeUnit[0],
height: sizeUnit[1]})
);
}
});
@ -327,7 +326,7 @@
],
"16x16": ["add", "add-hover", "add-active", "audio", "audio-hover", "audio-active",
"block", "block-red", "block-hover", "block-active", "contacts", "contacts-hover",
"contacts-active", "copy", "checkmark", "delete", "google", "google-hover",
"contacts-active", "copy", "checkmark", "delete", "globe", "google", "google-hover",
"google-active", "history", "history-hover", "history-active", "leave",
"precall", "precall-hover", "precall-active", "screen-white", "screenmute-white",
"settings", "settings-hover", "settings-active", "share-darkgrey", "tag",

Просмотреть файл

@ -299,13 +299,12 @@
var SVGIcon = React.createClass({
render: function() {
var sizeUnit = this.props.size.split("x")[0] + "px";
var sizeUnit = this.props.size.split("x");
return (
<span className="svg-icon" style={{
"backgroundImage": "url(../content/shared/img/icons-" + this.props.size +
".svg#" + this.props.shapeId + ")",
"backgroundSize": sizeUnit + " " + sizeUnit
}} />
<img className="svg-icon"
src={"../content/shared/img/icons-" + this.props.size + ".svg#" + this.props.shapeId}
width={sizeUnit[0]}
height={sizeUnit[1]} />
);
}
});
@ -327,7 +326,7 @@
],
"16x16": ["add", "add-hover", "add-active", "audio", "audio-hover", "audio-active",
"block", "block-red", "block-hover", "block-active", "contacts", "contacts-hover",
"contacts-active", "copy", "checkmark", "delete", "google", "google-hover",
"contacts-active", "copy", "checkmark", "delete", "globe", "google", "google-hover",
"google-active", "history", "history-hover", "history-active", "leave",
"precall", "precall-hover", "precall-active", "screen-white", "screenmute-white",
"settings", "settings-hover", "settings-active", "share-darkgrey", "tag",