Bug 955642 - Handle Twitter direct messages (DMs) - Pull out shared methods from TimelineConversation, r=clokep.
This commit is contained in:
Родитель
0f0bed4fa5
Коммит
13461cb1c0
|
@ -123,87 +123,13 @@ Action.prototype = {
|
||||||
get run() { return this._action.bind(this._tweet); }
|
get run() { return this._action.bind(this._tweet); }
|
||||||
};
|
};
|
||||||
|
|
||||||
function Conversation(aAccount)
|
// Properties / methods shared by both DirectMessageConversation and
|
||||||
{
|
// TimelineConversation.
|
||||||
this._init(aAccount);
|
var GenericTwitterConversation = {
|
||||||
this._ensureParticipantExists(aAccount.name);
|
|
||||||
// We need the screen names for the IDs in _friends, but _userInfo is
|
|
||||||
// indexed by name, so we build an ID -> name map.
|
|
||||||
let entries = [];
|
|
||||||
for (let [name, userInfo] of aAccount._userInfo) {
|
|
||||||
entries.push([userInfo.id_str, name]);
|
|
||||||
}
|
|
||||||
let names = new Map(entries);
|
|
||||||
for (let id_str of aAccount._friends)
|
|
||||||
this._ensureParticipantExists(names.get(id_str));
|
|
||||||
|
|
||||||
// If the user's info has already been received, update the timeline topic.
|
|
||||||
if (aAccount._userInfo.has(aAccount.name)) {
|
|
||||||
let userInfo = aAccount._userInfo.get(aAccount.name);
|
|
||||||
if ("description" in userInfo)
|
|
||||||
this.setTopic(userInfo.description, aAccount.name, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Conversation.prototype = {
|
|
||||||
__proto__: GenericConvChatPrototype,
|
|
||||||
unInit: function() {
|
|
||||||
delete this._account._timeline;
|
|
||||||
GenericConvChatPrototype.unInit.call(this);
|
|
||||||
},
|
|
||||||
inReplyToStatusId: null,
|
|
||||||
startReply: function(aTweet) {
|
|
||||||
this.inReplyToStatusId = aTweet.id_str;
|
|
||||||
let entities = aTweet.entities;
|
|
||||||
|
|
||||||
// Twitter replies go to all the users mentioned in the tweet.
|
|
||||||
let nicks = [aTweet.user.screen_name];
|
|
||||||
if ("user_mentions" in entities && Array.isArray(entities.user_mentions)) {
|
|
||||||
nicks = nicks.concat(entities.user_mentions
|
|
||||||
.map(um => um.screen_name));
|
|
||||||
}
|
|
||||||
// Ignore duplicates and the user's nick.
|
|
||||||
let prompt =
|
|
||||||
nicks.filter(function(aNick, aPos) {
|
|
||||||
return nicks.indexOf(aNick) == aPos && aNick != this._account.name;
|
|
||||||
}, this)
|
|
||||||
.map(aNick => "@" + aNick)
|
|
||||||
.join(" ") + " ";
|
|
||||||
|
|
||||||
this.notifyObservers(null, "replying-to-prompt", prompt);
|
|
||||||
this.notifyObservers(null, "status-text-changed",
|
|
||||||
_("replyingToStatusText", aTweet.text));
|
|
||||||
},
|
|
||||||
reTweet: function(aTweet) {
|
|
||||||
this._account.reTweet(aTweet, this.onSentCallback,
|
|
||||||
function(aException, aData) {
|
|
||||||
this.systemMessage(_("error.retweet", this._parseError(aData),
|
|
||||||
aTweet.text), true);
|
|
||||||
}, this);
|
|
||||||
},
|
|
||||||
getTweetLength: function (aString) {
|
getTweetLength: function (aString) {
|
||||||
// Use the Twitter library to calculate the length.
|
// Use the Twitter library to calculate the length.
|
||||||
return twttr.txt.getTweetLength(aString, this._account.config);
|
return twttr.txt.getTweetLength(aString, this._account.config);
|
||||||
},
|
},
|
||||||
sendMsg: function (aMsg) {
|
|
||||||
if (this.getTweetLength(aMsg) > kMaxMessageLength) {
|
|
||||||
this.systemMessage(_("error.tooLong"), true);
|
|
||||||
throw Cr.NS_ERROR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
this._account.tweet(aMsg, this.inReplyToStatusId, this.onSentCallback,
|
|
||||||
function(aException, aData) {
|
|
||||||
let error = this._parseError(aData);
|
|
||||||
this.systemMessage(_("error.general", error, aMsg), true);
|
|
||||||
}, this);
|
|
||||||
this.sendTyping("");
|
|
||||||
},
|
|
||||||
sendTyping: function(aString) {
|
|
||||||
if (aString.length == 0 && this.inReplyToStatusId) {
|
|
||||||
delete this.inReplyToStatusId;
|
|
||||||
this.notifyObservers(null, "status-text-changed", "");
|
|
||||||
return kMaxMessageLength;
|
|
||||||
}
|
|
||||||
return kMaxMessageLength - this.getTweetLength(aString);
|
|
||||||
},
|
|
||||||
systemMessage: function(aMessage, aIsError, aDate) {
|
systemMessage: function(aMessage, aIsError, aDate) {
|
||||||
let flags = {system: true};
|
let flags = {system: true};
|
||||||
if (aIsError)
|
if (aIsError)
|
||||||
|
@ -218,19 +144,6 @@ Conversation.prototype = {
|
||||||
throw "Wrong screen_name... Uh?";
|
throw "Wrong screen_name... Uh?";
|
||||||
this._account.displayMessages([tweet]);
|
this._account.displayMessages([tweet]);
|
||||||
},
|
},
|
||||||
_parseError: function(aData) {
|
|
||||||
let error = "";
|
|
||||||
try {
|
|
||||||
let data = JSON.parse(aData);
|
|
||||||
if ("error" in data)
|
|
||||||
error = data.error;
|
|
||||||
else if ("errors" in data)
|
|
||||||
error = data.errors[0].message;
|
|
||||||
if (error)
|
|
||||||
error = "(" + error + ")";
|
|
||||||
} catch(e) {}
|
|
||||||
return error;
|
|
||||||
},
|
|
||||||
parseTweet: function(aTweet) {
|
parseTweet: function(aTweet) {
|
||||||
let text = aTweet.text;
|
let text = aTweet.text;
|
||||||
let entities = {};
|
let entities = {};
|
||||||
|
@ -362,6 +275,98 @@ Conversation.prototype = {
|
||||||
|
|
||||||
(new Tweet(aTweet, name, text, flags)).conversation = this;
|
(new Tweet(aTweet, name, text, flags)).conversation = this;
|
||||||
},
|
},
|
||||||
|
_parseError: function(aData) {
|
||||||
|
let error = "";
|
||||||
|
try {
|
||||||
|
let data = JSON.parse(aData);
|
||||||
|
if ("error" in data)
|
||||||
|
error = data.error;
|
||||||
|
else if ("errors" in data)
|
||||||
|
error = data.errors[0].message;
|
||||||
|
if (error)
|
||||||
|
error = "(" + error + ")";
|
||||||
|
} catch(e) {}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function TimelineConversation(aAccount)
|
||||||
|
{
|
||||||
|
this._init(aAccount);
|
||||||
|
this._ensureParticipantExists(aAccount.name);
|
||||||
|
// We need the screen names for the IDs in _friends, but _userInfo is
|
||||||
|
// indexed by name, so we build an ID -> name map.
|
||||||
|
let entries = [];
|
||||||
|
for (let [name, userInfo] of aAccount._userInfo) {
|
||||||
|
entries.push([userInfo.id_str, name]);
|
||||||
|
}
|
||||||
|
let names = new Map(entries);
|
||||||
|
for (let id_str of aAccount._friends)
|
||||||
|
this._ensureParticipantExists(names.get(id_str));
|
||||||
|
|
||||||
|
// If the user's info has already been received, update the timeline topic.
|
||||||
|
if (aAccount._userInfo.has(aAccount.name)) {
|
||||||
|
let userInfo = aAccount._userInfo.get(aAccount.name);
|
||||||
|
if ("description" in userInfo)
|
||||||
|
this.setTopic(userInfo.description, aAccount.name, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TimelineConversation.prototype = {
|
||||||
|
__proto__: GenericConvChatPrototype,
|
||||||
|
unInit: function() {
|
||||||
|
delete this._account._timeline;
|
||||||
|
GenericConvChatPrototype.unInit.call(this);
|
||||||
|
},
|
||||||
|
inReplyToStatusId: null,
|
||||||
|
startReply: function(aTweet) {
|
||||||
|
this.inReplyToStatusId = aTweet.id_str;
|
||||||
|
let entities = aTweet.entities;
|
||||||
|
|
||||||
|
// Twitter replies go to all the users mentioned in the tweet.
|
||||||
|
let nicks = [aTweet.user.screen_name];
|
||||||
|
if ("user_mentions" in entities && Array.isArray(entities.user_mentions)) {
|
||||||
|
nicks = nicks.concat(entities.user_mentions
|
||||||
|
.map(um => um.screen_name));
|
||||||
|
}
|
||||||
|
// Ignore duplicates and the user's nick.
|
||||||
|
let prompt =
|
||||||
|
nicks.filter(function(aNick, aPos) {
|
||||||
|
return nicks.indexOf(aNick) == aPos && aNick != this._account.name;
|
||||||
|
}, this)
|
||||||
|
.map(aNick => "@" + aNick)
|
||||||
|
.join(" ") + " ";
|
||||||
|
|
||||||
|
this.notifyObservers(null, "replying-to-prompt", prompt);
|
||||||
|
this.notifyObservers(null, "status-text-changed",
|
||||||
|
_("replyingToStatusText", aTweet.text));
|
||||||
|
},
|
||||||
|
reTweet: function(aTweet) {
|
||||||
|
this._account.reTweet(aTweet, this.onSentCallback,
|
||||||
|
function(aException, aData) {
|
||||||
|
this.systemMessage(_("error.retweet", this._parseError(aData),
|
||||||
|
aTweet.text), true);
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
sendMsg: function (aMsg) {
|
||||||
|
if (this.getTweetLength(aMsg) > kMaxMessageLength) {
|
||||||
|
this.systemMessage(_("error.tooLong"), true);
|
||||||
|
throw Cr.NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
this._account.tweet(aMsg, this.inReplyToStatusId, this.onSentCallback,
|
||||||
|
function(aException, aData) {
|
||||||
|
let error = this._parseError(aData);
|
||||||
|
this.systemMessage(_("error.general", error, aMsg), true);
|
||||||
|
}, this);
|
||||||
|
this.sendTyping("");
|
||||||
|
},
|
||||||
|
sendTyping: function(aString) {
|
||||||
|
if (aString.length == 0 && this.inReplyToStatusId) {
|
||||||
|
delete this.inReplyToStatusId;
|
||||||
|
this.notifyObservers(null, "status-text-changed", "");
|
||||||
|
return kMaxMessageLength;
|
||||||
|
}
|
||||||
|
return kMaxMessageLength - this.getTweetLength(aString);
|
||||||
|
},
|
||||||
_ensureParticipantExists: function(aNick) {
|
_ensureParticipantExists: function(aNick) {
|
||||||
if (this._participants.has(aNick))
|
if (this._participants.has(aNick))
|
||||||
return;
|
return;
|
||||||
|
@ -382,6 +387,7 @@ Conversation.prototype = {
|
||||||
this._account.setUserDescription(aTopic);
|
this._account.setUserDescription(aTopic);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Object.assign(TimelineConversation.prototype, GenericTwitterConversation);
|
||||||
|
|
||||||
function Account(aProtocol, aImAccount)
|
function Account(aProtocol, aImAccount)
|
||||||
{
|
{
|
||||||
|
@ -621,7 +627,7 @@ Account.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get timeline() { return this._timeline || (this._timeline = new Conversation(this)); },
|
get timeline() { return this._timeline || (this._timeline = new TimelineConversation(this)); },
|
||||||
displayMessages: function(aMessages) {
|
displayMessages: function(aMessages) {
|
||||||
let lastMsgId = this._lastMsgId;
|
let lastMsgId = this._lastMsgId;
|
||||||
for (let tweet of aMessages) {
|
for (let tweet of aMessages) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче