This repository has been archived by the owner on Nov 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
301 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,323 @@ | ||
/** File: bookmark.js | ||
* Candy Plugin - Bookmark rooms | ||
* Candy Plugin - Bookmark Rooms | ||
* Author: Rafael Macedo <[email protected]> | ||
* Author: Ben Langfeld <[email protected]> | ||
*/ | ||
|
||
/* global Candy, jQuery, Strophe, $iq */ | ||
|
||
var CandyShop = (function(self) { return self; }(CandyShop || {})); | ||
|
||
CandyShop.Bookmark = (function(self, Candy, $) { | ||
self.init = function(){ | ||
$(Candy).on('candy:view.connection.status-5', function(){ | ||
self._createBookmarksNode(); | ||
return true; | ||
}); | ||
|
||
self.Bookmark = (function() { | ||
function Bookmark(type, args) { | ||
this.type = type; | ||
this.jid = args.jid; | ||
this.name = args.name || args.jid.split(/@/)[0]; | ||
this.id = args.room_id || args.user_id; | ||
this.term = args.term; | ||
this.to = args.to; | ||
this.opened = false; | ||
this.is_private = args.is_private; | ||
this.pending_removal = false; | ||
} | ||
|
||
Bookmark.prototype.join = function(foreground) { | ||
if (!this.opened) { | ||
if (this.type.match(/users/)) { | ||
Candy.View.Pane.PrivateRoom.open(this.jid, this.name, foreground, true); | ||
} else if (this.type.match(/rooms/)) { | ||
var data = { roomJid: this.jid, name: this.name, is_private: this.is_private, room_id: this.id }; | ||
CandyShop.JoinOnResponse.joinRoom(data, false, foreground); | ||
} else { | ||
Candy.Core.warn('Error: unknown bookmark type: ', this.type); | ||
} | ||
this.opened = true; | ||
} | ||
}; | ||
|
||
Bookmark.prototype.leave = function() { | ||
if (this.type.match(/users/)) { | ||
Candy.View.Pane.Room.close(this.jid); | ||
} else if (this.type.match(/rooms/)) { | ||
Candy.Core.Action.Jabber.Room.Leave(this.jid); | ||
} | ||
}; | ||
|
||
Bookmark.prototype.toArgs = function() { | ||
var args = {}; | ||
|
||
if (this.id) { | ||
if (this.type.match(/users/)) { | ||
args.user_id = this.id; | ||
} else if (this.type.match(/rooms/)) { | ||
args.room_id = this.id; | ||
} | ||
} else { | ||
if (this.type.match(/users/)) { | ||
args.user_jid = this.jid; | ||
} else if (this.type.match(/rooms/)) { | ||
args.room_jid = this.jid; | ||
} | ||
} | ||
|
||
return args; | ||
}; | ||
|
||
return Bookmark; | ||
})(); | ||
|
||
self.BookmarkCollection = (function() { | ||
function BookmarkCollection() { | ||
this.collection = []; | ||
this.version = undefined; | ||
} | ||
|
||
BookmarkCollection.prototype.add = function(bookmark, newlyAdded) { | ||
if (this.collection.filter(function(item) { return item.jid === bookmark; }).length === 0) { | ||
if (newlyAdded) { | ||
this.collection.unshift(bookmark); | ||
if (Candy.Core.getConnection().connected === true) { | ||
bookmark.join(); | ||
} | ||
} else { | ||
this.collection.push(bookmark); | ||
} | ||
} | ||
return this.collection; | ||
}; | ||
|
||
BookmarkCollection.prototype.joinAll = function() { | ||
this.collection.forEach(function (bookmark, position, collection) { | ||
var foreground = false; | ||
if (CandyShop.RoomAnchors.roomAnchorJid()) { | ||
// This bookmark matches the room in the URL | ||
if (CandyShop.RoomAnchors.roomAnchorJid() === bookmark.jid) { | ||
foreground = true; | ||
} | ||
} else if (position === 0) { | ||
foreground = true; | ||
} | ||
bookmark.join(foreground); | ||
}); | ||
} | ||
|
||
BookmarkCollection.prototype.jids = function() { | ||
return this.collection.map(function(bookmark) { | ||
return bookmark.jid; | ||
}); | ||
}; | ||
|
||
BookmarkCollection.prototype.pendingRemoval = function() { | ||
return this.collection.filter(function(item) { return item.pending_removal; }); | ||
}; | ||
|
||
BookmarkCollection.prototype.valid = function() { | ||
return this.collection.filter(function(item) { return !item.pending_removal; }); | ||
}; | ||
|
||
BookmarkCollection.prototype.tryRemoveByJid = function(jid) { | ||
this.collection.forEach(function (item) { | ||
if (item.jid === jid) { | ||
item.pending_removal = true; | ||
} | ||
}); | ||
}; | ||
|
||
BookmarkCollection.prototype.removeByJid = function(jid) { | ||
this.collection = this.collection.filter(function(bookmark) { | ||
return bookmark.jid !== jid; | ||
}); | ||
}; | ||
|
||
BookmarkCollection.prototype.reset = function(data) { | ||
for (var key in data) { | ||
data[key].forEach($.proxy(function(obj) { | ||
self.bookmarks.add(new self.Bookmark(key, obj)); | ||
}), this); | ||
} | ||
}; | ||
|
||
BookmarkCollection.prototype.sync = function(data) { | ||
for (var key in data) { | ||
data[key].forEach($.proxy(function(obj) { | ||
if ($.inArray(obj.jid, self.bookmarks.jids()) === -1) { | ||
self.bookmarks.add(new self.Bookmark(key, obj)); | ||
} | ||
}), this); | ||
} | ||
|
||
var jids = []; | ||
jids = jids.concat(data.connect_bookmarked_users.map(function(i) { return i.jid; })); | ||
jids = jids.concat(data.connect_bookmarked_rooms.map(function(i) { return i.jid; })); | ||
|
||
this.valid().forEach($.proxy(function(item) { | ||
if ($.inArray(item.jid, jids) === -1) { | ||
this.removeByJid(item.jid); | ||
item.leave(); | ||
} | ||
}), this); | ||
}; | ||
|
||
BookmarkCollection.prototype.setVersion = function(version) { | ||
this.version = version; | ||
}; | ||
|
||
BookmarkCollection.prototype.toArgs = function() { | ||
var args = {}; | ||
var valid = this.valid(); | ||
|
||
args.version = this.version; | ||
|
||
args.connect_bookmarked_users = | ||
valid.filter(function(bookmark) { | ||
return bookmark.type === 'connect_bookmarked_users'; | ||
}).map(function(bookmark) { return bookmark.toArgs(); }); | ||
|
||
args.connect_bookmarked_rooms = | ||
valid.filter(function(bookmark) { | ||
return bookmark.type === 'connect_bookmarked_rooms'; | ||
}).map(function(bookmark) { return bookmark.toArgs(); }); | ||
|
||
return args; | ||
}; | ||
|
||
BookmarkCollection.prototype.type = function(type) { | ||
return this.collection.filter(function(bookmark) { | ||
return bookmark.type === 'connect_bookmarked_' + type; | ||
}); | ||
}; | ||
|
||
return BookmarkCollection; | ||
})(); | ||
|
||
self.requestHandler = undefined; | ||
|
||
self.init = function() { | ||
self.bookmarks = new self.BookmarkCollection(); | ||
self._addEventListeners(); | ||
}; | ||
/** File: bookmark.js | ||
* Candy Plugin - Bookmark rooms | ||
* Author: Ben Langfeld <[email protected]> | ||
*/ | ||
|
||
var CandyShop = (function(self) { return self; }(CandyShop || {})); | ||
self._addEventListeners = function() { | ||
$(Candy) | ||
.on('candy:core.presence.error', self._removeBookmarkPresenceError) | ||
.on('candy:view.room.after-close', self._removeBookmark) | ||
.on('candy:view.room.after-add', self._onRoomOpen) | ||
.on('candy:view.connection.status-' + Strophe.Status.CONNECTED, self.joinAll) | ||
.on('candy:view.connection.status-' + Strophe.Status.ATTACHED, self.joinAll); | ||
}; | ||
|
||
CandyShop.Bookmark = (function(self, Candy, $) { | ||
/** Object: about | ||
* | ||
* Contains: | ||
* (String) name - Candy Plugin - Bookmark rooms | ||
* (Float) version - Candy Plugin - Bookmark rooms | ||
*/ | ||
self.about = { | ||
name: 'Candy Plugin - Bookmark rooms', | ||
version: '0.1' | ||
self.joinAll = function () { | ||
self.bookmarks.joinAll(); | ||
}; | ||
|
||
self.init = function(){ | ||
Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub'); | ||
$(Candy).on('candy:view.connection.status-5', self._createBookmarksNode); | ||
$(Candy).on('candy:view.connection.status-8', self._createBookmarksNode); | ||
self.fetchBookmarks = function(data) { | ||
self.bookmarks.setVersion(data.version); | ||
delete data.version; | ||
self.bookmarks.reset(data); | ||
}; | ||
|
||
/** Function: add | ||
* Adds a bookmark for the provided MUC room | ||
* | ||
* Parameters: | ||
* (String) roomJid - The JID of the room to bookmark | ||
*/ | ||
self.add = function(roomJid) { | ||
Candy.Core.getConnection().sendIQ($iq({ | ||
type: 'set' | ||
}) | ||
.c('pubsub', {xmlns: Strophe.NS.PUBSUB}) | ||
.c('publish', {node: Strophe.NS.BOOKMARKS}) | ||
.c('item', {id: roomJid}) | ||
.c('storage', {xmlns: Strophe.NS.BOOKMARKS}) | ||
.c('conference', {autojoin: 'true', jid: roomJid}) | ||
); | ||
self._onRoomOpen = function(e, args) { | ||
if (self.bookmarks) { | ||
if ($.inArray(args.roomJid, self.bookmarks.jids()) === -1) { | ||
var bookmark; | ||
var type; | ||
|
||
if (args.type === 'chat') { | ||
type = 'connect_bookmarked_users'; | ||
} else if (args.type === 'groupchat') { | ||
type = 'connect_bookmarked_rooms'; | ||
} | ||
|
||
if (type) { | ||
bookmark = new self.Bookmark(type, { jid: args.roomJid }); | ||
self.bookmarks.add(bookmark, true); | ||
self._updateBookmarks(); | ||
} | ||
} | ||
|
||
// Re-sort the order of Rooms, and One-on-One chats to match | ||
// the order of the bookmarks | ||
var chatTabs = $('#chat-tabs'); | ||
var roomsHead = $('#rooms-head').detach(); | ||
var rooms = chatTabs.find('.roomtype-groupchat').detach(); | ||
var peopleHead = $('#people-head').detach(); | ||
var people = chatTabs.find('.roomtype-chat').detach(); | ||
|
||
// TODO: DRY | ||
chatTabs.append(roomsHead); | ||
self.bookmarks.type('rooms').map(function(bookmark) { | ||
chatTabs.append(rooms.filter(function(i, room) { | ||
return $(room).attr('data-roomjid') === bookmark.jid; | ||
})); | ||
}); | ||
|
||
chatTabs.append(peopleHead); | ||
self.bookmarks.type('users').map(function(bookmark) { | ||
chatTabs.append(people.filter(function(i, user) { | ||
return $(user).attr('data-roomjid') === bookmark.jid; | ||
})); | ||
}); | ||
} | ||
}; | ||
|
||
/** Function: remove | ||
* Removes a bookmark for the provided MUC room | ||
* | ||
* Parameters: | ||
* (String) roomJid - The JID of the room to remove from bookmarks | ||
*/ | ||
self.remove = function(roomJid) { | ||
Candy.Core.getConnection().sendIQ($iq({ | ||
type: 'set' | ||
}) | ||
.c('pubsub', {xmlns: Strophe.NS.PUBSUB}) | ||
.c('retract', {node: Strophe.NS.BOOKMARKS}) | ||
.c('item', {id: roomJid}) | ||
); | ||
self._removeBookmarkPresenceError = function(e, args) { | ||
if ($(args).attr('error') && Strophe.getBareJidFromJid($(args).attr('from')) !== Strophe.getBareJidFromJid(Candy.Core.getUser().getJid())) { | ||
self._removeBookmark(e, args); | ||
} | ||
}; | ||
|
||
self._createBookmarksNode = function() { | ||
// We do this instead of using publish-options because this is not mandatory to implement according to XEP-0060 | ||
Candy.Core.getConnection().sendIQ($iq({type: 'set'}) | ||
.c('pubsub', {xmlns: Strophe.NS.PUBSUB}) | ||
.c('create', {node: 'storage:bookmarks'}).up() | ||
.c('configure') | ||
.c('x', {xmlns: 'jabber:x:data', type: 'submit'}) | ||
.c('field', {'var': 'FORM_TYPE', type: 'hidden'}) | ||
.c('value').t('http://jabber.org/protocol/pubsub#node_config').up().up() | ||
.c('field', {'var': 'pubsub#persist_items'}).c('value').t('1').up().up() | ||
.c('field', {'var': 'pubsub#access_model'}).c('value').t('whitelist') | ||
); | ||
|
||
return true; | ||
self._removeBookmark = function(e, args) { | ||
if (args.roomJid) { | ||
self.bookmarks.tryRemoveByJid(args.roomJid); | ||
window.clearTimeout(self.requestHandler); | ||
self.requestHandler = window.setTimeout(self._updateBookmarks, 300); | ||
} | ||
}; | ||
|
||
self._updateBookmarks = function() { | ||
$.ajax({ | ||
type: 'PUT', | ||
url: '/api/v1/connect/bookmarks', | ||
contentType: 'application/json', | ||
data: JSON.stringify(self.bookmarks.toArgs()), | ||
statusCode: { | ||
409: function() { | ||
CandyShop.ConnectStateData.fetch().done(function(data) { | ||
self.bookmarks.setVersion(data.bookmarks.version); | ||
delete data.bookmarks.version; | ||
self.bookmarks.sync(data.bookmarks); | ||
self._updateBookmarks(); | ||
}); | ||
} | ||
} | ||
}).done(function(data) { | ||
self.bookmarks.setVersion(data.version); | ||
delete data.version; | ||
self.bookmarks.sync(data); | ||
|
||
self.bookmarks.pendingRemoval().forEach(function (bookmark) { | ||
if (self._serverHasBookmark(bookmark.jid, data)) { | ||
// The server still has this bookmark. We need to sync again | ||
self._removeBookmark(undefined, { roomJid: bookmark.jid }); | ||
} else { | ||
// This bookmark was removed from the server. Remove it from our local collection | ||
self.bookmarks.removeByJid(bookmark.jid); | ||
} | ||
}); | ||
}); | ||
}; | ||
|
||
self._serverHasBookmark = function (jid, data) { | ||
var has = false; | ||
for (var key in data) { | ||
data[key].forEach(function (bookmark) { | ||
if (bookmark.jid == jid) { | ||
has = true; | ||
} | ||
}) | ||
} | ||
return has; | ||
} | ||
|
||
return self; | ||
}(CandyShop.Bookmark || {}, Candy, jQuery)); |