164 lines
5.1 KiB
JavaScript
164 lines
5.1 KiB
JavaScript
const INCOMING_MESSAGE_NAME = "MessageCenter:child-to-parent";
|
|
const OUTGOING_MESSAGE_NAME = "MessageCenter:parent-to-child";
|
|
|
|
const FAKE_MESSAGES = [
|
|
{
|
|
id: "ONBOARDING_1",
|
|
template: "simple_snippet",
|
|
content: {
|
|
title: "Find it faster",
|
|
body: "Access all of your favorite search engines with a click. Search the whole Web or just one website from the search box.",
|
|
button: {
|
|
label: "Learn More",
|
|
action: "OPEN_LINK",
|
|
params: {url: "https://mozilla.org"}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "ONBOARDING_2",
|
|
template: "simple_snippet",
|
|
content: {
|
|
title: "Make Firefox your go-to-browser",
|
|
body: "It doesn't take much to get the most from Firefox. Just set Firefox as your default browser and put control, customization, and protection on autopilot."
|
|
}
|
|
},
|
|
{
|
|
id: "ONBOARDING_3",
|
|
template: "simple_snippet",
|
|
content: {
|
|
title: "Did you know?",
|
|
body: "All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood."
|
|
}
|
|
}
|
|
];
|
|
|
|
/**
|
|
* getRandomItemFromArray
|
|
*
|
|
* @param {Array} arr An array of items
|
|
* @returns one of the items in the array
|
|
*/
|
|
function getRandomItemFromArray(arr) {
|
|
const index = Math.floor(Math.random() * arr.length);
|
|
return arr[index];
|
|
}
|
|
|
|
/**
|
|
* @class _MessageCenterRouter - Keeps track of all messages, UI surfaces, and
|
|
* handles blocking, rotation, etc. Inspecting MessageCenter.state will
|
|
* tell you what the current displayed message is in all UI surfaces.
|
|
*
|
|
* Note: This is written as a constructor rather than just a plain object
|
|
* so that it can be more easily unit tested.
|
|
*/
|
|
class _MessageCenterRouter {
|
|
constructor(initialState = {}) {
|
|
this.initialized = false;
|
|
this.messageChannel = null;
|
|
this._state = Object.assign({
|
|
currentId: null,
|
|
blockList: {},
|
|
messages: {}
|
|
}, initialState);
|
|
this.onMessage = this.onMessage.bind(this);
|
|
}
|
|
|
|
get state() {
|
|
return this._state;
|
|
}
|
|
|
|
set state(value) {
|
|
throw new Error("Do not modify this.state directy. Instead, call this.setState(newState)");
|
|
}
|
|
|
|
/**
|
|
* init - Initializes the MessageRouter.
|
|
* It is ready when it has been connected to a RemotePageManager instance.
|
|
*
|
|
* @param {RemotePageManager} channel a RemotePageManager instance
|
|
* @memberof _MessageCenterRouter
|
|
*/
|
|
init(channel) {
|
|
this.messageChannel = channel;
|
|
this.messageChannel.addMessageListener(INCOMING_MESSAGE_NAME, this.onMessage);
|
|
this.initialized = true;
|
|
}
|
|
|
|
uninit() {
|
|
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "CLEAR_MESSAGE"});
|
|
this.messageChannel.removeMessageListener(INCOMING_MESSAGE_NAME, this.onMessage);
|
|
this.messageChannel = null;
|
|
this.initialized = false;
|
|
}
|
|
|
|
setState(callbackOrObj) {
|
|
const newState = (typeof callbackOrObj === "function") ? callbackOrObj(this.state) : callbackOrObj;
|
|
this._state = Object.assign({}, this.state, newState);
|
|
return new Promise(resolve => {
|
|
this._onStateChanged(this.state);
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
_onStateChanged(state) {
|
|
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: state});
|
|
}
|
|
|
|
async sendNextMessage(target, id) {
|
|
let message;
|
|
await this.setState(state => {
|
|
message = getRandomItemFromArray(state.messages.filter(item => item.id !== state.currentId && !state.blockList[item.id]));
|
|
return {currentId: message ? message.id : null};
|
|
});
|
|
if (message) {
|
|
target.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "SET_MESSAGE", data: message});
|
|
} else {
|
|
target.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "CLEAR_MESSAGE"});
|
|
}
|
|
}
|
|
|
|
async clearMessage(target, id) {
|
|
if (this.state.currentId === id) {
|
|
await this.setState({currentId: null});
|
|
}
|
|
target.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "CLEAR_MESSAGE"});
|
|
}
|
|
|
|
async onMessage({data: action, target}) {
|
|
switch (action.type) {
|
|
case "CONNECT_UI_REQUEST":
|
|
case "GET_NEXT_MESSAGE":
|
|
await this.sendNextMessage(target);
|
|
break;
|
|
case "BLOCK_MESSAGE_BY_ID":
|
|
await this.setState(state => {
|
|
const newState = Object.assign({}, state.blockList);
|
|
newState[action.data.id] = true;
|
|
return {blockList: newState};
|
|
});
|
|
await this.clearMessage(target, action.data.id);
|
|
break;
|
|
case "UNBLOCK_MESSAGE_BY_ID":
|
|
await this.setState(state => {
|
|
const newState = Object.assign({}, state.blockList);
|
|
delete newState[action.data.id];
|
|
return {blockList: newState};
|
|
});
|
|
break;
|
|
case "ADMIN_CONNECT_STATE":
|
|
target.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: this.state});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this._MessageCenterRouter = _MessageCenterRouter;
|
|
|
|
/**
|
|
* MessageCenterRouter - singleton instance of _MessageCenterRouter that controls all messages
|
|
* in the new tab page.
|
|
*/
|
|
this.MessageCenterRouter = new _MessageCenterRouter({messages: FAKE_MESSAGES});
|
|
|
|
const EXPORTED_SYMBOLS = ["_MessageCenterRouter", "MessageCenterRouter"];
|