mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-21 09:49:14 +00:00
Bug 1168833: introduce different sizing modes to docked social chat windows and re-style text chat UI indide the Hello conversation window. r=Standard8
This commit is contained in:
parent
cba59000ab
commit
393b9d5a26
@ -34,8 +34,8 @@
|
||||
* along any dimension beyond the point at which an overflow event would
|
||||
* occur". But none of -moz-{fit,max,min}-content do what we want here. So..
|
||||
*/
|
||||
min-width: 320px;
|
||||
min-height: 280px;
|
||||
min-width: 260px;
|
||||
min-height: 315px;
|
||||
}
|
||||
|
||||
#main-window[customize-entered] {
|
||||
@ -907,8 +907,32 @@ chatbox {
|
||||
width: 260px; /* CHAT_WIDTH_OPEN in socialchat.xml */
|
||||
}
|
||||
|
||||
chatbox[large="true"] {
|
||||
width: 300px;
|
||||
chatbox[customSize] {
|
||||
width: 300px; /* CHAT_WIDTH_OPEN_ALT in socialchat.xml */
|
||||
}
|
||||
|
||||
#chat-window[customSize] {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
chatbox[customSize="loopChatEnabled"] {
|
||||
/* 325px as defined per UX */
|
||||
height: 325px;
|
||||
}
|
||||
|
||||
#chat-window[customSize="loopChatEnabled"] {
|
||||
/* 325px + 30px top bar height. */
|
||||
min-height: calc(325px + 30px);
|
||||
}
|
||||
|
||||
chatbox[customSize="loopChatMessageAppended"] {
|
||||
/* 445px as defined per UX */
|
||||
height: 445px;
|
||||
}
|
||||
|
||||
#chat-window[customSize="loopChatMessageAppended"] {
|
||||
/* 445px + 30px top bar height. */
|
||||
min-height: calc(445px + 30px);
|
||||
}
|
||||
|
||||
chatbox[minimized="true"] {
|
||||
@ -922,6 +946,15 @@ chatbar {
|
||||
max-height: 0;
|
||||
}
|
||||
|
||||
.chatbar-innerbox {
|
||||
margin: -285px 0 0;
|
||||
}
|
||||
|
||||
chatbar[customSize] > .chatbar-innerbox {
|
||||
/* 425px to make room for the maximum custom-size chatbox; currently 'loopChatMessageAppended'. */
|
||||
margin-top: -425px;
|
||||
}
|
||||
|
||||
/* Apply crisp rendering for favicons at exactly 2dppx resolution */
|
||||
@media (resolution: 2dppx) {
|
||||
#social-sidebar-favico,
|
||||
|
@ -160,8 +160,7 @@
|
||||
<parameter name="aTarget"/>
|
||||
<body><![CDATA[
|
||||
aTarget.setAttribute("label", this.contentDocument.title);
|
||||
if (this.getAttribute("dark") == "true")
|
||||
aTarget.setAttribute("dark", "true");
|
||||
|
||||
aTarget.src = this.src;
|
||||
aTarget.content.setAttribute("origin", this.content.getAttribute("origin"));
|
||||
aTarget.content.popupnotificationanchor.className = this.content.popupnotificationanchor.className;
|
||||
@ -169,6 +168,16 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="setDecorationAttributes">
|
||||
<parameter name="aTarget"/>
|
||||
<body><![CDATA[
|
||||
for (let attr of ["dark", "customSize"]) {
|
||||
if (this.hasAttribute(attr))
|
||||
aTarget.setAttribute(attr, this.getAttribute(attr));
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="onTitlebarClick">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
@ -211,6 +220,8 @@
|
||||
let chatbar = win.document.getElementById("pinnedchats");
|
||||
let origin = this.content.getAttribute("origin");
|
||||
let cb = chatbar.openChat(origin, title, "about:blank");
|
||||
this.setDecorationAttributes(cb);
|
||||
|
||||
cb.promiseChatLoaded.then(
|
||||
() => {
|
||||
this.swapDocShells(cb);
|
||||
@ -225,6 +236,12 @@
|
||||
chatbar.chatboxForURL.delete("about:blank");
|
||||
chatbar.chatboxForURL.set(this.src, Cu.getWeakReference(cb));
|
||||
|
||||
let attachEvent = new cb.contentWindow.CustomEvent("socialFrameAttached", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
cb.contentDocument.dispatchEvent(attachEvent);
|
||||
|
||||
deferred.resolve(cb);
|
||||
}
|
||||
);
|
||||
@ -457,8 +474,10 @@
|
||||
// These are from the CSS for the chatbox and must be kept in sync.
|
||||
// We can't use calcTotalWidthOf due to the transitions...
|
||||
const CHAT_WIDTH_OPEN = 260;
|
||||
const CHAT_WIDTH_OPEN_ALT = 300;
|
||||
const CHAT_WIDTH_MINIMIZED = 160;
|
||||
let openWidth = aChatbox.hasAttribute("large") ? 300 : CHAT_WIDTH_OPEN;
|
||||
let openWidth = aChatbox.hasAttribute("customSize") ?
|
||||
CHAT_WIDTH_OPEN_ALT : CHAT_WIDTH_OPEN;
|
||||
|
||||
return aChatbox.minimized ? CHAT_WIDTH_MINIMIZED : openWidth;
|
||||
]]></body>
|
||||
@ -684,18 +703,27 @@
|
||||
if (event.target != otherWin.document)
|
||||
return;
|
||||
|
||||
if (aChatbox.hasAttribute("customSize")) {
|
||||
otherWin.document.getElementById("chat-window").
|
||||
setAttribute("customSize", aChatbox.getAttribute("customSize"));
|
||||
}
|
||||
|
||||
let document = aChatbox.contentDocument;
|
||||
let detachEvent = new aChatbox.contentWindow.CustomEvent("socialFrameDetached", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
aChatbox.contentDocument.dispatchEvent(detachEvent);
|
||||
|
||||
otherWin.removeEventListener("load", _chatLoad, true);
|
||||
let otherChatbox = otherWin.document.getElementById("chatter");
|
||||
aChatbox.setDecorationAttributes(otherChatbox);
|
||||
aChatbox.swapDocShells(otherChatbox);
|
||||
aChatbox.close();
|
||||
chatbar.chatboxForURL.set(aChatbox.src, Cu.getWeakReference(otherChatbox));
|
||||
|
||||
// All processing is done, now we can fire the event.
|
||||
document.dispatchEvent(detachEvent);
|
||||
|
||||
deferred.resolve(otherChatbox);
|
||||
}, true);
|
||||
return deferred.promise;
|
||||
|
@ -718,7 +718,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "room-conversation-wrapper"},
|
||||
React.createElement(sharedViews.TextChatView, {dispatcher: this.props.dispatcher}),
|
||||
React.createElement(DesktopRoomInvitationView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
@ -761,7 +760,8 @@ loop.roomViews = (function(mozL10n) {
|
||||
savingContext: this.state.savingContext,
|
||||
mozLoop: this.props.mozLoop,
|
||||
roomData: roomData,
|
||||
show: !shouldRenderInvitationOverlay && shouldRenderContextView})
|
||||
show: !shouldRenderInvitationOverlay && shouldRenderContextView}),
|
||||
React.createElement(sharedViews.TextChatView, {dispatcher: this.props.dispatcher})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -718,7 +718,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
|
||||
return (
|
||||
<div className="room-conversation-wrapper">
|
||||
<sharedViews.TextChatView dispatcher={this.props.dispatcher} />
|
||||
<DesktopRoomInvitationView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
@ -762,6 +761,7 @@ loop.roomViews = (function(mozL10n) {
|
||||
mozLoop={this.props.mozLoop}
|
||||
roomData={roomData}
|
||||
show={!shouldRenderInvitationOverlay && shouldRenderContextView} />
|
||||
<sharedViews.TextChatView dispatcher={this.props.dispatcher} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -651,27 +651,6 @@ html, .fx-embedded, #main,
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* The .fx-embbeded .text-chat-* styles are very temporarily whilst we work on
|
||||
* text chat (bug 1108892 and dependencies).
|
||||
*/
|
||||
.fx-embedded .text-chat-view {
|
||||
height: 60px;
|
||||
color: white;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-entries {
|
||||
/* XXX Should use flex, this is just for the initial implementation. */
|
||||
height: calc(100% - 2em);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-box {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
/* We use 641px rather than 640, as min-width and max-width are inclusive */
|
||||
@media screen and (min-width:641px) {
|
||||
.standalone .conversation-toolbar {
|
||||
@ -681,10 +660,6 @@ html, .fx-embedded, #main,
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fx-embedded .local-stream {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.standalone .local-stream,
|
||||
.standalone .remote-inset-stream {
|
||||
position: absolute;
|
||||
@ -697,7 +672,7 @@ html, .fx-embedded, #main,
|
||||
}
|
||||
|
||||
/* Nested video elements */
|
||||
.conversation .media.nested {
|
||||
.standalone .conversation .media.nested {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
@ -744,7 +719,7 @@ html, .fx-embedded, #main,
|
||||
}
|
||||
|
||||
/* Nested video elements */
|
||||
.conversation .media.nested {
|
||||
.standalone .conversation .media.nested {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@ -1239,18 +1214,64 @@ html[dir="rtl"] .room-context-btn-edit {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Text chat in rooms styles */
|
||||
|
||||
.fx-embedded .room-conversation-wrapper {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.fx-embedded .video-layout-wrapper {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.text-chat-view {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-view {
|
||||
flex: 1 0 auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-entries {
|
||||
flex: 1 1 auto;
|
||||
max-height: 120px;
|
||||
min-height: 60px;
|
||||
padding: .7em .5em 0;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-box {
|
||||
flex: 0 0 auto;
|
||||
max-height: 40px;
|
||||
min-height: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-chat-entries {
|
||||
margin: auto;
|
||||
overflow: scroll;
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
.text-chat-entry {
|
||||
text-align: left;
|
||||
text-align: end;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.text-chat-entry > span {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #0095dd;
|
||||
border-radius: 10000px;
|
||||
padding: .5em 1em;
|
||||
}
|
||||
|
||||
.text-chat-entry.received {
|
||||
text-align: right;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.text-chat-entry.received > span {
|
||||
border-color: #d8d8d8;
|
||||
}
|
||||
|
||||
.text-chat-box {
|
||||
@ -1259,6 +1280,14 @@ html[dir="rtl"] .room-context-btn-edit {
|
||||
|
||||
.text-chat-box > form > input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 0 .5em .5em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-box > form > input {
|
||||
border: 0;
|
||||
border-top: 1px solid #999;
|
||||
}
|
||||
|
||||
@media screen and (max-width:640px) {
|
||||
|
@ -68,6 +68,27 @@ loop.store.TextChatStore = (function() {
|
||||
*/
|
||||
dataChannelsAvailable: function() {
|
||||
this.setStoreState({ textChatEnabled: true });
|
||||
window.dispatchEvent(new CustomEvent("LoopChatEnabled"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends a message to the store, which may be of type 'sent' or 'received'.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {sharedActions.ReceivedTextChatMessage|sharedActions.SendTextChatMessage} actionData
|
||||
*/
|
||||
_appendTextChatMessage: function(type, actionData) {
|
||||
// We create a new list to avoid updating the store's state directly,
|
||||
// which confuses the views.
|
||||
var message = {
|
||||
type: type,
|
||||
contentType: actionData.contentType,
|
||||
message: actionData.message
|
||||
};
|
||||
var newList = this._storeState.messageList.concat(message);
|
||||
this.setStoreState({ messageList: newList });
|
||||
|
||||
window.dispatchEvent(new CustomEvent("LoopChatMessageAppended"));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -81,14 +102,8 @@ loop.store.TextChatStore = (function() {
|
||||
if (actionData.contentType != CHAT_CONTENT_TYPES.TEXT) {
|
||||
return;
|
||||
}
|
||||
// We create a new list to avoid updating the store's state directly,
|
||||
// which confuses the views.
|
||||
var newList = this._storeState.messageList.concat({
|
||||
type: CHAT_MESSAGE_TYPES.RECEIVED,
|
||||
contentType: actionData.contentType,
|
||||
message: actionData.message
|
||||
});
|
||||
this.setStoreState({ messageList: newList });
|
||||
|
||||
this._appendTextChatMessage(CHAT_MESSAGE_TYPES.RECEIVED, actionData);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -97,15 +112,8 @@ loop.store.TextChatStore = (function() {
|
||||
* @param {sharedActions.SendTextChatMessage} actionData
|
||||
*/
|
||||
sendTextChatMessage: function(actionData) {
|
||||
// We create a new list to avoid updating the store's state directly,
|
||||
// which confuses the views.
|
||||
var newList = this._storeState.messageList.concat({
|
||||
type: CHAT_MESSAGE_TYPES.SENT,
|
||||
contentType: actionData.contentType,
|
||||
message: actionData.message
|
||||
});
|
||||
this._appendTextChatMessage(CHAT_MESSAGE_TYPES.SENT, actionData);
|
||||
this._sdkDriver.sendTextChatMessage(actionData);
|
||||
this.setStoreState({ messageList: newList });
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -29,7 +29,7 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: classes},
|
||||
this.props.message
|
||||
React.createElement("span", null, this.props.message)
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -49,6 +49,9 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
|
||||
componentWillUpdate: function() {
|
||||
var node = this.getDOMNode();
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
// Scroll only if we're right at the bottom of the display.
|
||||
this.shouldScroll = node.scrollHeight === node.scrollTop + node.clientHeight;
|
||||
},
|
||||
@ -64,17 +67,23 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.props.messageList.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "text-chat-entries"},
|
||||
|
||||
this.props.messageList.map(function(entry, i) {
|
||||
return (
|
||||
React.createElement(TextChatEntry, {key: i,
|
||||
message: entry.message,
|
||||
type: entry.type})
|
||||
);
|
||||
}, this)
|
||||
|
||||
React.createElement("div", {className: "text-chat-scroller"},
|
||||
|
||||
this.props.messageList.map(function(entry, i) {
|
||||
return (
|
||||
React.createElement(TextChatEntry, {key: i,
|
||||
message: entry.message,
|
||||
type: entry.type})
|
||||
);
|
||||
}, this)
|
||||
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -134,12 +143,15 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var messageList = this.state.messageList;
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "text-chat-view"},
|
||||
React.createElement(TextChatEntriesView, {messageList: this.state.messageList}),
|
||||
React.createElement(TextChatEntriesView, {messageList: messageList}),
|
||||
React.createElement("div", {className: "text-chat-box"},
|
||||
React.createElement("form", {onSubmit: this.handleFormSubmit},
|
||||
React.createElement("input", {type: "text",
|
||||
placeholder: messageList.length ? "" : mozl10n.get("chat_textbox_placeholder"),
|
||||
onKeyDown: this.handleKeyDown,
|
||||
valueLink: this.linkState("messageDetail")})
|
||||
)
|
||||
|
@ -29,7 +29,7 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
{this.props.message}
|
||||
<span>{this.props.message}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -49,6 +49,9 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
|
||||
componentWillUpdate: function() {
|
||||
var node = this.getDOMNode();
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
// Scroll only if we're right at the bottom of the display.
|
||||
this.shouldScroll = node.scrollHeight === node.scrollTop + node.clientHeight;
|
||||
},
|
||||
@ -64,17 +67,23 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.props.messageList.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-chat-entries">
|
||||
{
|
||||
this.props.messageList.map(function(entry, i) {
|
||||
return (
|
||||
<TextChatEntry key={i}
|
||||
message={entry.message}
|
||||
type={entry.type} />
|
||||
);
|
||||
}, this)
|
||||
}
|
||||
<div className="text-chat-scroller">
|
||||
{
|
||||
this.props.messageList.map(function(entry, i) {
|
||||
return (
|
||||
<TextChatEntry key={i}
|
||||
message={entry.message}
|
||||
type={entry.type} />
|
||||
);
|
||||
}, this)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -134,12 +143,15 @@ loop.shared.views.TextChatView = (function(mozl10n) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var messageList = this.state.messageList;
|
||||
|
||||
return (
|
||||
<div className="text-chat-view">
|
||||
<TextChatEntriesView messageList={this.state.messageList} />
|
||||
<TextChatEntriesView messageList={messageList} />
|
||||
<div className="text-chat-box">
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<input type="text"
|
||||
placeholder={messageList.length ? "" : mozl10n.get("chat_textbox_placeholder")}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
valueLink={this.linkState("messageDetail")} />
|
||||
</form>
|
||||
|
@ -853,27 +853,51 @@ let MozLoopServiceInternal = {
|
||||
return;
|
||||
}
|
||||
|
||||
chatbox.setAttribute("dark", true);
|
||||
chatbox.setAttribute("large", true);
|
||||
|
||||
chatbox.addEventListener("DOMContentLoaded", function loaded(event) {
|
||||
if (event.target != chatbox.contentDocument) {
|
||||
return;
|
||||
}
|
||||
chatbox.removeEventListener("DOMContentLoaded", loaded, true);
|
||||
|
||||
let chatbar = chatbox.parentNode;
|
||||
let window = chatbox.contentWindow;
|
||||
|
||||
function socialFrameChanged(eventName) {
|
||||
UITour.availableTargetsCache.clear();
|
||||
UITour.notify(eventName);
|
||||
|
||||
if (eventName == "Loop:ChatWindowDetached" || eventName == "Loop:ChatWindowAttached") {
|
||||
// After detach, re-attach of the chatbox, refresh its reference so
|
||||
// we can keep using it here.
|
||||
let ref = chatbar.chatboxForURL.get(chatbox.src);
|
||||
chatbox = ref && ref.get() || chatbox;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("socialFrameHide", socialFrameChanged.bind(null, "Loop:ChatWindowHidden"));
|
||||
window.addEventListener("socialFrameShow", socialFrameChanged.bind(null, "Loop:ChatWindowShown"));
|
||||
window.addEventListener("socialFrameDetached", socialFrameChanged.bind(null, "Loop:ChatWindowDetached"));
|
||||
window.addEventListener("socialFrameAttached", socialFrameChanged.bind(null, "Loop:ChatWindowAttached"));
|
||||
window.addEventListener("unload", socialFrameChanged.bind(null, "Loop:ChatWindowClosed"));
|
||||
|
||||
const kSizeMap = {
|
||||
LoopChatEnabled: "loopChatEnabled",
|
||||
LoopChatMessageAppended: "loopChatMessageAppended"
|
||||
};
|
||||
|
||||
function onChatEvent(event) {
|
||||
// When the chat box or messages are shown, resize the panel or window
|
||||
// to be slightly higher to accomodate them.
|
||||
let customSize = kSizeMap[event.type];
|
||||
if (customSize) {
|
||||
chatbox.setAttribute("customSize", customSize);
|
||||
chatbox.parentNode.setAttribute("customSize", customSize);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("LoopChatEnabled", onChatEvent);
|
||||
window.addEventListener("LoopChatMessageAppended", onChatEvent);
|
||||
|
||||
injectLoopAPI(window);
|
||||
|
||||
let ourID = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
@ -918,8 +942,16 @@ let MozLoopServiceInternal = {
|
||||
}.bind(this), true);
|
||||
};
|
||||
|
||||
if (!Chat.open(null, origin, "", url, undefined, undefined, callback)) {
|
||||
let chatbox = Chat.open(null, origin, "", url, undefined, undefined, callback);
|
||||
if (!chatbox) {
|
||||
return null;
|
||||
// It's common for unit tests to overload Chat.open.
|
||||
} else if (chatbox.setAttribute) {
|
||||
// Set properties that influence visual appeara nce of the chatbox right
|
||||
// away to circumvent glitches.
|
||||
chatbox.setAttribute("dark", true);
|
||||
chatbox.setAttribute("customSize", "loopDefault");
|
||||
chatbox.parentNode.setAttribute("customSize", "loopDefault");
|
||||
}
|
||||
return windowId;
|
||||
},
|
||||
|
@ -137,3 +137,7 @@ status_in_conversation=In conversation
|
||||
status_conversation_ended=Conversation ended
|
||||
status_error=Something went wrong
|
||||
support_link=Get Help
|
||||
|
||||
# Text chat strings
|
||||
|
||||
chat_textbox_placeholder=Type here…
|
||||
|
@ -25,6 +25,11 @@ describe("loop.store.TextChatStore", function () {
|
||||
store = new loop.store.TextChatStore(dispatcher, {
|
||||
sdkDriver: fakeSdkDriver
|
||||
});
|
||||
|
||||
sandbox.stub(window, "dispatchEvent");
|
||||
sandbox.stub(window, "CustomEvent", function(name) {
|
||||
this.name = name;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@ -37,6 +42,14 @@ describe("loop.store.TextChatStore", function () {
|
||||
|
||||
expect(store.getStoreState("textChatEnabled")).eql(true);
|
||||
});
|
||||
|
||||
it("should dispatch a LoopChatEnabled event", function() {
|
||||
store.dataChannelsAvailable();
|
||||
|
||||
sinon.assert.calledOnce(window.dispatchEvent);
|
||||
sinon.assert.calledWithExactly(window.dispatchEvent,
|
||||
new CustomEvent("LoopChatEnabled"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#receivedTextChatMessage", function() {
|
||||
@ -63,6 +76,17 @@ describe("loop.store.TextChatStore", function () {
|
||||
|
||||
expect(store.getStoreState("messageList").length).eql(0);
|
||||
});
|
||||
|
||||
it("should dispatch a LoopChatMessageAppended event", function() {
|
||||
store.receivedTextChatMessage({
|
||||
contentType: CHAT_CONTENT_TYPES.TEXT,
|
||||
message: "Hello!"
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(window.dispatchEvent);
|
||||
sinon.assert.calledWithExactly(window.dispatchEvent,
|
||||
new CustomEvent("LoopChatMessageAppended"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#sendTextChatMessage", function() {
|
||||
@ -92,5 +116,16 @@ describe("loop.store.TextChatStore", function () {
|
||||
message: messageData.message
|
||||
}]);
|
||||
});
|
||||
|
||||
it("should dipatch a LoopChatMessageAppended event", function() {
|
||||
store.sendTextChatMessage({
|
||||
contentType: CHAT_CONTENT_TYPES.TEXT,
|
||||
message: "Hello!"
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(window.dispatchEvent);
|
||||
sinon.assert.calledWithExactly(window.dispatchEvent,
|
||||
new CustomEvent("LoopChatMessageAppended"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -80,5 +80,32 @@ describe("loop.shared.views.TextChatView", function () {
|
||||
message: "Hello!"
|
||||
}));
|
||||
});
|
||||
|
||||
it("should not render message entries when none are sent/ received yet", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode().querySelector(".text-chat-entries")).to.eql(null);
|
||||
});
|
||||
|
||||
it("should render message entries when message were sent/ received", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
store.receivedTextChatMessage({
|
||||
contentType: CHAT_CONTENT_TYPES.TEXT,
|
||||
message: "Hello!"
|
||||
});
|
||||
store.sendTextChatMessage({
|
||||
contentType: CHAT_CONTENT_TYPES.TEXT,
|
||||
message: "Is it me you're looking for?"
|
||||
});
|
||||
|
||||
var node = view.getDOMNode();
|
||||
expect(node.querySelector(".text-chat-entries")).to.not.eql(null);
|
||||
|
||||
var entries = node.querySelectorAll(".text-chat-entry");
|
||||
expect(entries.length).to.eql(2);
|
||||
expect(entries[0].classList.contains("received")).to.eql(true);
|
||||
expect(entries[1].classList.contains("received")).to.not.eql(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -354,3 +354,7 @@ context_show_tooltip=Show Context
|
||||
context_save_label2=Save
|
||||
context_link_modified=This link was modified.
|
||||
context_learn_more_link_label=Learn more.
|
||||
|
||||
# Text chat strings
|
||||
|
||||
chat_textbox_placeholder=Type here…
|
||||
|
@ -195,7 +195,6 @@ chatbox[dark=true] > .chat-titlebar > hbox > .chat-title {
|
||||
|
||||
.chatbar-innerbox {
|
||||
background: transparent;
|
||||
margin: -285px 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user