зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1142687 - Show context information for current page in the rooms view. r=standard8
This commit is contained in:
Родитель
9ae3882abb
Коммит
eefcc0b4fd
|
@ -1700,9 +1700,9 @@ pref("loop.debug.websocket", false);
|
||||||
pref("loop.debug.sdk", false);
|
pref("loop.debug.sdk", false);
|
||||||
pref("loop.debug.twoWayMediaTelemetry", false);
|
pref("loop.debug.twoWayMediaTelemetry", false);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:");
|
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src *; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:");
|
||||||
#else
|
#else
|
||||||
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:");
|
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src *; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:");
|
||||||
#endif
|
#endif
|
||||||
pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
|
pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
|
||||||
pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
|
pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
|
||||||
|
|
|
@ -21,6 +21,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoopStorage",
|
||||||
"resource:///modules/loop/LoopStorage.jsm");
|
"resource:///modules/loop/LoopStorage.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose",
|
XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose",
|
||||||
"resource://gre/modules/MozSocialAPI.jsm");
|
"resource://gre/modules/MozSocialAPI.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata",
|
||||||
|
"resource://gre/modules/PageMetadata.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||||
"resource://gre/modules/PluralForm.jsm");
|
"resource://gre/modules/PluralForm.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||||
|
@ -844,6 +846,24 @@ function injectLoopAPI(targetWindow) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the metadata related to the currently selected tab in
|
||||||
|
* the most recent window.
|
||||||
|
*
|
||||||
|
* @param {Function} A callback that is passed the metadata.
|
||||||
|
*/
|
||||||
|
getSelectedTabMetadata: {
|
||||||
|
value: function(callback) {
|
||||||
|
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||||
|
win.messageManager.addMessageListener("PageMetadata:PageDataResult", function onPageDataResult(msg) {
|
||||||
|
win.messageManager.removeMessageListener("PageMetadata:PageDataResult", onPageDataResult);
|
||||||
|
let pageData = msg.json;
|
||||||
|
callback(cloneValueInto(pageData, targetWindow));
|
||||||
|
});
|
||||||
|
win.gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associates a session-id and a call-id with a window for debugging.
|
* Associates a session-id and a call-id with a window for debugging.
|
||||||
*
|
*
|
||||||
|
|
|
@ -170,25 +170,71 @@ body {
|
||||||
/* Rooms */
|
/* Rooms */
|
||||||
.rooms {
|
.rooms {
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
|
padding: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rooms > h1 {
|
.rooms > h1 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #999;
|
color: #999;
|
||||||
padding: .5rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rooms > p {
|
|
||||||
padding: .5rem 0;
|
padding: .5rem 0;
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.rooms > p > .btn {
|
.rooms > div > .context {
|
||||||
|
margin: .5rem 0 0;
|
||||||
|
background-color: #DEEFF7;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
padding: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms > div > .context > .context-enabled {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms > div > .context > .context-enabled > input {
|
||||||
|
-moz-margin-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms > div > .context > .context-preview {
|
||||||
|
float: right;
|
||||||
|
width: 100px;
|
||||||
|
max-height: 200px;
|
||||||
|
-moz-margin-start: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[dir=rtl] .rooms > div > .context > .context-preview {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms > div > .context > .context-preview[src=""] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms > div > .context > .context-description {
|
||||||
|
display: block;
|
||||||
|
color: #707070;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms > div > .context > .context-url {
|
||||||
|
display: block;
|
||||||
|
color: #59A1D7;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms > div > .btn {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto .5rem;
|
||||||
|
width: 100%;
|
||||||
padding: .5rem 1rem;
|
padding: .5rem 1rem;
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove when bug 1142671 is backed out. */
|
||||||
|
.rooms > div > :not(.context) + .btn {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.room-list {
|
.room-list {
|
||||||
|
@ -197,6 +243,8 @@ body {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
|
margin-left: -1rem;
|
||||||
|
margin-right: -1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.room-list:empty {
|
.room-list:empty {
|
||||||
|
|
|
@ -594,6 +594,7 @@ loop.panel = (function(_, mozL10n) {
|
||||||
mixins: [Backbone.Events, sharedMixins.WindowCloseMixin],
|
mixins: [Backbone.Events, sharedMixins.WindowCloseMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
mozLoop: React.PropTypes.object.isRequired,
|
||||||
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
||||||
|
@ -666,7 +667,8 @@ loop.panel = (function(_, mozL10n) {
|
||||||
);
|
);
|
||||||
}, this)
|
}, this)
|
||||||
),
|
),
|
||||||
React.createElement("p", null,
|
React.createElement("div", null,
|
||||||
|
React.createElement(ContextInfo, {mozLoop: this.props.mozLoop}),
|
||||||
React.createElement("button", {className: "btn btn-info new-room-button",
|
React.createElement("button", {className: "btn btn-info new-room-button",
|
||||||
onClick: this.handleCreateButtonClick,
|
onClick: this.handleCreateButtonClick,
|
||||||
disabled: this._hasPendingOperation()},
|
disabled: this._hasPendingOperation()},
|
||||||
|
@ -678,6 +680,60 @@ loop.panel = (function(_, mozL10n) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context info that is offered to be part of a Room.
|
||||||
|
*/
|
||||||
|
var ContextInfo = React.createClass({displayName: "ContextInfo",
|
||||||
|
propTypes: {
|
||||||
|
mozLoop: React.PropTypes.object.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [sharedMixins.DocumentVisibilityMixin],
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
previewImage: "",
|
||||||
|
description: "",
|
||||||
|
url: ""
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onDocumentVisible: function() {
|
||||||
|
this.props.mozLoop.getSelectedTabMetadata(function callback(metadata) {
|
||||||
|
var previewImage = metadata.previews.length ? metadata.previews[0] : "";
|
||||||
|
var description = metadata.description || metadata.title;
|
||||||
|
var url = metadata.url;
|
||||||
|
this.setState({previewImage: previewImage,
|
||||||
|
description: description,
|
||||||
|
url: url});
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
onDocumentHidden: function() {
|
||||||
|
this.setState({previewImage: "",
|
||||||
|
description: "",
|
||||||
|
url: ""});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
if (!this.props.mozLoop.getLoopPref("contextInConverations.enabled") ||
|
||||||
|
!this.state.url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
React.createElement("div", {className: "context"},
|
||||||
|
React.createElement("label", {className: "context-enabled"},
|
||||||
|
React.createElement("input", {type: "checkbox"}),
|
||||||
|
mozL10n.get("context_offer_label")
|
||||||
|
),
|
||||||
|
React.createElement("img", {className: "context-preview", src: this.state.previewImage}),
|
||||||
|
React.createElement("span", {className: "context-description"}, this.state.description),
|
||||||
|
React.createElement("span", {className: "context-url"}, this.state.url)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel view.
|
* Panel view.
|
||||||
*/
|
*/
|
||||||
|
@ -819,7 +875,8 @@ loop.panel = (function(_, mozL10n) {
|
||||||
React.createElement(Tab, {name: "rooms"},
|
React.createElement(Tab, {name: "rooms"},
|
||||||
React.createElement(RoomList, {dispatcher: this.props.dispatcher,
|
React.createElement(RoomList, {dispatcher: this.props.dispatcher,
|
||||||
store: this.props.roomStore,
|
store: this.props.roomStore,
|
||||||
userDisplayName: this._getUserDisplayName()}),
|
userDisplayName: this._getUserDisplayName(),
|
||||||
|
mozLoop: this.props.mozLoop}),
|
||||||
React.createElement(ToSView, null)
|
React.createElement(ToSView, null)
|
||||||
),
|
),
|
||||||
React.createElement(Tab, {name: "contacts"},
|
React.createElement(Tab, {name: "contacts"},
|
||||||
|
@ -890,6 +947,7 @@ loop.panel = (function(_, mozL10n) {
|
||||||
init: init,
|
init: init,
|
||||||
AuthLink: AuthLink,
|
AuthLink: AuthLink,
|
||||||
AvailabilityDropdown: AvailabilityDropdown,
|
AvailabilityDropdown: AvailabilityDropdown,
|
||||||
|
ContextInfo: ContextInfo,
|
||||||
GettingStartedView: GettingStartedView,
|
GettingStartedView: GettingStartedView,
|
||||||
PanelView: PanelView,
|
PanelView: PanelView,
|
||||||
RoomEntry: RoomEntry,
|
RoomEntry: RoomEntry,
|
||||||
|
|
|
@ -594,6 +594,7 @@ loop.panel = (function(_, mozL10n) {
|
||||||
mixins: [Backbone.Events, sharedMixins.WindowCloseMixin],
|
mixins: [Backbone.Events, sharedMixins.WindowCloseMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
mozLoop: React.PropTypes.object.isRequired,
|
||||||
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
||||||
|
@ -666,13 +667,68 @@ loop.panel = (function(_, mozL10n) {
|
||||||
/>;
|
/>;
|
||||||
}, this)
|
}, this)
|
||||||
}</div>
|
}</div>
|
||||||
<p>
|
<div>
|
||||||
|
<ContextInfo mozLoop={this.props.mozLoop} />
|
||||||
<button className="btn btn-info new-room-button"
|
<button className="btn btn-info new-room-button"
|
||||||
onClick={this.handleCreateButtonClick}
|
onClick={this.handleCreateButtonClick}
|
||||||
disabled={this._hasPendingOperation()}>
|
disabled={this._hasPendingOperation()}>
|
||||||
{mozL10n.get("rooms_new_room_button_label")}
|
{mozL10n.get("rooms_new_room_button_label")}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context info that is offered to be part of a Room.
|
||||||
|
*/
|
||||||
|
var ContextInfo = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
mozLoop: React.PropTypes.object.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [sharedMixins.DocumentVisibilityMixin],
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
previewImage: "",
|
||||||
|
description: "",
|
||||||
|
url: ""
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onDocumentVisible: function() {
|
||||||
|
this.props.mozLoop.getSelectedTabMetadata(function callback(metadata) {
|
||||||
|
var previewImage = metadata.previews.length ? metadata.previews[0] : "";
|
||||||
|
var description = metadata.description || metadata.title;
|
||||||
|
var url = metadata.url;
|
||||||
|
this.setState({previewImage: previewImage,
|
||||||
|
description: description,
|
||||||
|
url: url});
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
onDocumentHidden: function() {
|
||||||
|
this.setState({previewImage: "",
|
||||||
|
description: "",
|
||||||
|
url: ""});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
if (!this.props.mozLoop.getLoopPref("contextInConverations.enabled") ||
|
||||||
|
!this.state.url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="context">
|
||||||
|
<label className="context-enabled">
|
||||||
|
<input type="checkbox"/>
|
||||||
|
{mozL10n.get("context_offer_label")}
|
||||||
|
</label>
|
||||||
|
<img className="context-preview" src={this.state.previewImage}/>
|
||||||
|
<span className="context-description">{this.state.description}</span>
|
||||||
|
<span className="context-url">{this.state.url}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -819,7 +875,8 @@ loop.panel = (function(_, mozL10n) {
|
||||||
<Tab name="rooms">
|
<Tab name="rooms">
|
||||||
<RoomList dispatcher={this.props.dispatcher}
|
<RoomList dispatcher={this.props.dispatcher}
|
||||||
store={this.props.roomStore}
|
store={this.props.roomStore}
|
||||||
userDisplayName={this._getUserDisplayName()}/>
|
userDisplayName={this._getUserDisplayName()}
|
||||||
|
mozLoop={this.props.mozLoop}/>
|
||||||
<ToSView />
|
<ToSView />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab name="contacts">
|
<Tab name="contacts">
|
||||||
|
@ -890,6 +947,7 @@ loop.panel = (function(_, mozL10n) {
|
||||||
init: init,
|
init: init,
|
||||||
AuthLink: AuthLink,
|
AuthLink: AuthLink,
|
||||||
AvailabilityDropdown: AvailabilityDropdown,
|
AvailabilityDropdown: AvailabilityDropdown,
|
||||||
|
ContextInfo: ContextInfo,
|
||||||
GettingStartedView: GettingStartedView,
|
GettingStartedView: GettingStartedView,
|
||||||
PanelView: PanelView,
|
PanelView: PanelView,
|
||||||
RoomEntry: RoomEntry,
|
RoomEntry: RoomEntry,
|
||||||
|
|
|
@ -651,7 +651,8 @@ describe("loop.panel", function() {
|
||||||
React.createElement(loop.panel.RoomList, {
|
React.createElement(loop.panel.RoomList, {
|
||||||
store: roomStore,
|
store: roomStore,
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
userDisplayName: fakeEmail
|
userDisplayName: fakeEmail,
|
||||||
|
mozLoop: fakeMozLoop
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,6 +709,49 @@ describe("loop.panel", function() {
|
||||||
var buttonNode = view.getDOMNode().querySelector("button[disabled]");
|
var buttonNode = view.getDOMNode().querySelector("button[disabled]");
|
||||||
expect(buttonNode).to.not.equal(null);
|
expect(buttonNode).to.not.equal(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should show context information when a URL is available",
|
||||||
|
function() {
|
||||||
|
navigator.mozLoop.getLoopPref = function() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = TestUtils.renderIntoDocument(
|
||||||
|
React.createElement(loop.panel.ContextInfo, {
|
||||||
|
mozLoop: navigator.mozLoop
|
||||||
|
})
|
||||||
|
);
|
||||||
|
view.setState({
|
||||||
|
previews: [""],
|
||||||
|
description: "fake description",
|
||||||
|
url: "https://www.example.com"
|
||||||
|
});
|
||||||
|
|
||||||
|
var contextEnabledCheckbox = view.getDOMNode().querySelector(".context-enabled");
|
||||||
|
expect(contextEnabledCheckbox).to.not.equal(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not show context information when a URL is unavailable",
|
||||||
|
function() {
|
||||||
|
navigator.mozLoop.getLoopPref = function() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = TestUtils.renderIntoDocument(
|
||||||
|
React.createElement(loop.panel.ContextInfo, {
|
||||||
|
mozLoop: navigator.mozLoop
|
||||||
|
})
|
||||||
|
);
|
||||||
|
view.setState({
|
||||||
|
previews: [""],
|
||||||
|
description: "fake description",
|
||||||
|
url: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
var contextInfo = view.getDOMNode();
|
||||||
|
expect(contextInfo).to.equal(null);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('loop.panel.ToSView', function() {
|
describe('loop.panel.ToSView', function() {
|
||||||
|
|
|
@ -115,6 +115,7 @@ navigator.mozLoop = {
|
||||||
// Ensure we skip FTE completely.
|
// Ensure we skip FTE completely.
|
||||||
case "gettingStarted.seen":
|
case "gettingStarted.seen":
|
||||||
case "contacts.gravatars.promo":
|
case "contacts.gravatars.promo":
|
||||||
|
case "contextInConverations.enabled":
|
||||||
return true;
|
return true;
|
||||||
case "contacts.gravatars.show":
|
case "contacts.gravatars.show":
|
||||||
return false;
|
return false;
|
||||||
|
@ -127,6 +128,13 @@ navigator.mozLoop = {
|
||||||
return "http://www.gravatar.com/avatar/" + (Math.ceil(Math.random() * 3) === 2 ?
|
return "http://www.gravatar.com/avatar/" + (Math.ceil(Math.random() * 3) === 2 ?
|
||||||
"0a996f0fe2727ef1668bdb11897e4459" : "foo") + ".jpg?default=blank&s=40";
|
"0a996f0fe2727ef1668bdb11897e4459" : "foo") + ".jpg?default=blank&s=40";
|
||||||
},
|
},
|
||||||
|
getSelectedTabMetadata: function(callback) {
|
||||||
|
callback({
|
||||||
|
previews: ["chrome://branding/content/about-logo.png"],
|
||||||
|
description: "sample webpage description",
|
||||||
|
url: "https://www.example.com"
|
||||||
|
});
|
||||||
|
},
|
||||||
contacts: {
|
contacts: {
|
||||||
getAll: function(callback) {
|
getAll: function(callback) {
|
||||||
callback(null, [].concat(fakeContacts));
|
callback(null, [].concat(fakeContacts));
|
||||||
|
|
|
@ -56,6 +56,28 @@
|
||||||
|
|
||||||
function noop(){}
|
function noop(){}
|
||||||
|
|
||||||
|
// We save the visibility change listeners so that we can fake an event
|
||||||
|
// to the panel once we've loaded all the views.
|
||||||
|
var visibilityListeners = [];
|
||||||
|
var rootObject = window;
|
||||||
|
|
||||||
|
rootObject.document.addEventListener = function(eventName, func) {
|
||||||
|
if (eventName === "visibilitychange") {
|
||||||
|
visibilityListeners.push(func);
|
||||||
|
}
|
||||||
|
window.addEventListener(eventName, func);
|
||||||
|
};
|
||||||
|
|
||||||
|
rootObject.document.removeEventListener = function(eventName, func) {
|
||||||
|
if (eventName === "visibilitychange") {
|
||||||
|
var index = visibilityListeners.indexOf(func);
|
||||||
|
visibilityListeners.splice(index, 1);
|
||||||
|
}
|
||||||
|
window.removeEventListener(eventName, func);
|
||||||
|
};
|
||||||
|
|
||||||
|
loop.shared.mixins.setRootObject(rootObject);
|
||||||
|
|
||||||
// Feedback API client configured to send data to the stage input server,
|
// Feedback API client configured to send data to the stage input server,
|
||||||
// which is available at https://input.allizom.org
|
// which is available at https://input.allizom.org
|
||||||
var stageFeedbackApiClient = new loop.FeedbackAPIClient(
|
var stageFeedbackApiClient = new loop.FeedbackAPIClient(
|
||||||
|
@ -757,6 +779,10 @@
|
||||||
window.addEventListener("DOMContentLoaded", function() {
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
try {
|
try {
|
||||||
React.renderComponent(React.createElement(App, null), document.getElementById("main"));
|
React.renderComponent(React.createElement(App, null), document.getElementById("main"));
|
||||||
|
|
||||||
|
for (var listener of visibilityListeners) {
|
||||||
|
listener({target: {hidden: false}});
|
||||||
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
uncaughtError = err;
|
uncaughtError = err;
|
||||||
|
|
|
@ -56,6 +56,28 @@
|
||||||
|
|
||||||
function noop(){}
|
function noop(){}
|
||||||
|
|
||||||
|
// We save the visibility change listeners so that we can fake an event
|
||||||
|
// to the panel once we've loaded all the views.
|
||||||
|
var visibilityListeners = [];
|
||||||
|
var rootObject = window;
|
||||||
|
|
||||||
|
rootObject.document.addEventListener = function(eventName, func) {
|
||||||
|
if (eventName === "visibilitychange") {
|
||||||
|
visibilityListeners.push(func);
|
||||||
|
}
|
||||||
|
window.addEventListener(eventName, func);
|
||||||
|
};
|
||||||
|
|
||||||
|
rootObject.document.removeEventListener = function(eventName, func) {
|
||||||
|
if (eventName === "visibilitychange") {
|
||||||
|
var index = visibilityListeners.indexOf(func);
|
||||||
|
visibilityListeners.splice(index, 1);
|
||||||
|
}
|
||||||
|
window.removeEventListener(eventName, func);
|
||||||
|
};
|
||||||
|
|
||||||
|
loop.shared.mixins.setRootObject(rootObject);
|
||||||
|
|
||||||
// Feedback API client configured to send data to the stage input server,
|
// Feedback API client configured to send data to the stage input server,
|
||||||
// which is available at https://input.allizom.org
|
// which is available at https://input.allizom.org
|
||||||
var stageFeedbackApiClient = new loop.FeedbackAPIClient(
|
var stageFeedbackApiClient = new loop.FeedbackAPIClient(
|
||||||
|
@ -757,6 +779,10 @@
|
||||||
window.addEventListener("DOMContentLoaded", function() {
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
try {
|
try {
|
||||||
React.renderComponent(<App />, document.getElementById("main"));
|
React.renderComponent(<App />, document.getElementById("main"));
|
||||||
|
|
||||||
|
for (var listener of visibilityListeners) {
|
||||||
|
listener({target: {hidden: false}});
|
||||||
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
uncaughtError = err;
|
uncaughtError = err;
|
||||||
|
|
|
@ -331,3 +331,6 @@ infobar_button_gotit_label=Got it!
|
||||||
infobar_button_gotit_accesskey=G
|
infobar_button_gotit_accesskey=G
|
||||||
infobar_menuitem_dontshowagain_label=Don't show this again
|
infobar_menuitem_dontshowagain_label=Don't show this again
|
||||||
infobar_menuitem_dontshowagain_accesskey=D
|
infobar_menuitem_dontshowagain_accesskey=D
|
||||||
|
|
||||||
|
# Context in conversation strings
|
||||||
|
context_offer_label=Let's talk about this page
|
||||||
|
|
Загрузка…
Ссылка в новой задаче